--- /tmp/openlayers-2.13.1+ds2-8w72cwlij/debian/libjs-openlayers_2.13.1+ds2-8_all.deb +++ libjs-openlayers_2.13.1+ds2-8_all.deb ├── file list │ @@ -1,3 +1,3 @@ │ -rw-r--r-- 0 0 0 4 2020-04-18 18:00:46.000000 debian-binary │ -rw-r--r-- 0 0 0 3680 2020-04-18 18:00:46.000000 control.tar.xz │ --rw-r--r-- 0 0 0 711488 2020-04-18 18:00:46.000000 data.tar.xz │ +-rw-r--r-- 0 0 0 718268 2020-04-18 18:00:46.000000 data.tar.xz ├── control.tar.xz │ ├── control.tar │ │ ├── ./md5sums │ │ │ ├── ./md5sums │ │ │ │┄ Files differ ├── data.tar.xz │ ├── data.tar │ │ ├── ./usr/share/javascript/openlayers/OpenLayers.js │ │ │ ├── js-beautify {} │ │ │ │ @@ -52,37 +52,14 @@ │ │ │ │ * 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. │ │ │ │ */ │ │ │ │ /* ====================================================================== │ │ │ │ - Rico/license.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @license Apache 2 │ │ │ │ - * │ │ │ │ - * Contains portions of Rico │ │ │ │ - * │ │ │ │ - * Copyright 2005 Sabre Airline Solutions │ │ │ │ - * │ │ │ │ - * 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. │ │ │ │ - */ │ │ │ │ -/* ====================================================================== │ │ │ │ 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. */ │ │ │ │ @@ -159,14 +136,481 @@ │ │ │ │ * (code) │ │ │ │ * │ │ │ │ * (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. */ │ │ │ │ @@ -540,479 +984,592 @@ │ │ │ │ OpenLayers.Util.extend(OpenLayers.Console, console); │ │ │ │ break; │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ })(); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/BaseTypes.js │ │ │ │ + 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/SingleFile.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Header: OpenLayers Base Types │ │ │ │ - * OpenLayers custom string, number and function functions are described here. │ │ │ │ + * @requires OpenLayers/BaseTypes.js │ │ │ │ + * @requires OpenLayers/Console.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Namespace: OpenLayers.String │ │ │ │ - * Contains convenience functions for string manipulation. │ │ │ │ + * Namespace: OpenLayers.Lang │ │ │ │ + * Internationalization namespace. Contains dictionaries in various languages │ │ │ │ + * and methods to set and get the current language. │ │ │ │ */ │ │ │ │ -OpenLayers.String = { │ │ │ │ +OpenLayers.Lang = { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * Property: code │ │ │ │ + * {String} Current language code to use in OpenLayers. Use the │ │ │ │ + * method to set this value and the method to │ │ │ │ + * retrieve it. │ │ │ │ */ │ │ │ │ - startsWith: function(str, sub) { │ │ │ │ - return (str.indexOf(sub) == 0); │ │ │ │ - }, │ │ │ │ + code: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * APIProperty: defaultCode │ │ │ │ + * {String} Default language to use when a specific language can't be │ │ │ │ + * found. Default is "en". │ │ │ │ */ │ │ │ │ - contains: function(str, sub) { │ │ │ │ - return (str.indexOf(sub) != -1); │ │ │ │ - }, │ │ │ │ + defaultCode: "en", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIFunction: trim │ │ │ │ - * Removes leading and trailing whitespace characters from a string. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * str - {String} The (potentially) space padded string. This string is not │ │ │ │ - * modified. │ │ │ │ - * │ │ │ │ + * APIFunction: getCode │ │ │ │ + * Get the current language code. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {String} A trimmed version of the string with all leading and │ │ │ │ - * trailing spaces removed. │ │ │ │ + * {String} The current language code. │ │ │ │ */ │ │ │ │ - trim: function(str) { │ │ │ │ - return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); │ │ │ │ + getCode: function() { │ │ │ │ + if (!OpenLayers.Lang.code) { │ │ │ │ + OpenLayers.Lang.setCode(); │ │ │ │ + } │ │ │ │ + return OpenLayers.Lang.code; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIFunction: camelize │ │ │ │ - * Camel-case a hyphenated string. │ │ │ │ - * Ex. "chicken-head" becomes "chickenHead", and │ │ │ │ - * "-chicken-head" becomes "ChickenHead". │ │ │ │ + * APIFunction: setCode │ │ │ │ + * Set the language code for string translation. This code is used by │ │ │ │ + * the method. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * str - {String} The string to be camelized. The original is not modified. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} The string, camelized │ │ │ │ + * 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 │ │ │ │ + * dictionary exists for the code, the │ │ │ │ + * will be used. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + setCode: function(code) { │ │ │ │ + var lang; │ │ │ │ + if (!code) { │ │ │ │ + code = (OpenLayers.BROWSER_NAME == "msie") ? │ │ │ │ + navigator.userLanguage : navigator.language; │ │ │ │ } │ │ │ │ - return camelizedString; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. "${${". │ │ │ │ + * APIMethod: translate │ │ │ │ + * Looks up a key from a dictionary based on the current language string. │ │ │ │ + * The value of will be used to determine the appropriate │ │ │ │ + * dictionary. Dictionaries are stored in . │ │ │ │ * │ │ │ │ * 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. │ │ │ │ - * │ │ │ │ + * key - {String} The key for an i18n string value in the dictionary. │ │ │ │ + * context - {Object} Optional context to be used with │ │ │ │ + * . │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {String} A string with tokens replaced from the context object. │ │ │ │ + * {String} A internationalized string. │ │ │ │ */ │ │ │ │ - format: function(template, context, args) { │ │ │ │ - if (!context) { │ │ │ │ - context = window; │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ │ │ │ │ - // 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(); │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * APIMethod: OpenLayers.i18n │ │ │ │ + * Alias for . Looks up a key from a dictionary │ │ │ │ + * based on the current language string. The value of │ │ │ │ + * will be used to determine the appropriate │ │ │ │ + * dictionary. Dictionaries are stored in . │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * key - {String} The key for an i18n string value in the dictionary. │ │ │ │ + * context - {Object} Optional context to be used with │ │ │ │ + * . │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A internationalized string. │ │ │ │ + */ │ │ │ │ +OpenLayers.i18n = OpenLayers.Lang.translate; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Renderer.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - // 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; │ │ │ │ - } │ │ │ │ - }; │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - return template.replace(OpenLayers.String.tokenRegEx, replacer); │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: tokenRegEx │ │ │ │ - * Used to find tokens in a string. │ │ │ │ - * Examples: ${a}, ${a.b.c}, ${a-b}, ${5} │ │ │ │ +/** │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - tokenRegEx: /\$\{([\w.]+?)\}/g, │ │ │ │ + container: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: numberRegEx │ │ │ │ - * Used to test strings as numbers. │ │ │ │ + * Property: root │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - numberRegEx: /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/, │ │ │ │ + root: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * Property: extent │ │ │ │ + * {} │ │ │ │ */ │ │ │ │ - isNumeric: function(value) { │ │ │ │ - return OpenLayers.String.numberRegEx.test(value); │ │ │ │ - }, │ │ │ │ + extent: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + locked: false, │ │ │ │ │ │ │ │ -}; │ │ │ │ + /** │ │ │ │ + * Property: size │ │ │ │ + * {} │ │ │ │ + */ │ │ │ │ + size: null, │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Number │ │ │ │ - * Contains convenience functions for manipulating numbers. │ │ │ │ - */ │ │ │ │ -OpenLayers.Number = { │ │ │ │ + /** │ │ │ │ + * Property: resolution │ │ │ │ + * {Float} cache of current map resolution │ │ │ │ + */ │ │ │ │ + resolution: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: decimalSeparator │ │ │ │ - * Decimal separator to use when formatting numbers. │ │ │ │ + * Property: map │ │ │ │ + * {} Reference to the map -- this is set in Vector's setMap() │ │ │ │ */ │ │ │ │ - decimalSeparator: ".", │ │ │ │ + map: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: thousandsSeparator │ │ │ │ - * Thousands separator to use when formatting numbers. │ │ │ │ + * Property: featureDx │ │ │ │ + * {Number} Feature offset in x direction. Will be calculated for and │ │ │ │ + * applied to the current feature while rendering (see │ │ │ │ + * ). │ │ │ │ */ │ │ │ │ - thousandsSeparator: ",", │ │ │ │ + featureDx: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIFunction: limitSigDigs │ │ │ │ - * Limit the number of significant digits on a float. │ │ │ │ - * │ │ │ │ + * Constructor: OpenLayers.Renderer │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * num - {Float} │ │ │ │ - * sig - {Integer} │ │ │ │ + * containerID - {} │ │ │ │ + * 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: │ │ │ │ - * {Float} The number, rounded to the specified number of significant │ │ │ │ - * digits. │ │ │ │ + * {Boolean} Whether or not the browser supports the renderer class │ │ │ │ */ │ │ │ │ - limitSigDigs: function(num, sig) { │ │ │ │ - var fig = 0; │ │ │ │ - if (sig > 0) { │ │ │ │ - fig = parseFloat(num.toPrecision(sig)); │ │ │ │ - } │ │ │ │ - return fig; │ │ │ │ + supported: function() { │ │ │ │ + return false; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIFunction: format │ │ │ │ - * Formats a number for output. │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * 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 ".". │ │ │ │ + * extent - {} │ │ │ │ + * resolutionChanged - {Boolean} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} A string representing the formatted number. │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - 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)); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - │ │ │ │ - var parts = num.toString().split("."); │ │ │ │ - if (parts.length == 1 && dec == null) { │ │ │ │ - // integer where we do not want to touch the decimals │ │ │ │ - dec = 0; │ │ │ │ + if (resolutionChanged) { │ │ │ │ + this.resolution = null; │ │ │ │ } │ │ │ │ + return true; │ │ │ │ + }, │ │ │ │ │ │ │ │ - var integer = parts[0]; │ │ │ │ - if (tsep) { │ │ │ │ - var thousands = /(-?[0-9]+)([0-9]{3})/; │ │ │ │ - while (thousands.test(integer)) { │ │ │ │ - integer = integer.replace(thousands, "$1" + tsep + "$2"); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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 - {} │ │ │ │ + */ │ │ │ │ + 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 - {} │ │ │ │ + * style - {} │ │ │ │ + * │ │ │ │ + * 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 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"); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - str = integer + dsep + rem; │ │ │ │ } │ │ │ │ - return str; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: zeroPad │ │ │ │ - * Create a zero padded string optionally with a radix for casting numbers. │ │ │ │ + * 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: │ │ │ │ - * 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. │ │ │ │ + * bounds - {} Bounds of the feature │ │ │ │ + * worldBounds - {} Bounds of the world │ │ │ │ */ │ │ │ │ - zeroPad: function(num, len, radix) { │ │ │ │ - var str = num.toString(radix || 10); │ │ │ │ - while (str.length < len) { │ │ │ │ - str = "0" + str; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - 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. │ │ │ │ + /** │ │ │ │ + * Method: drawGeometry │ │ │ │ * │ │ │ │ + * Draw a geometry. This should only be called from the renderer itself. │ │ │ │ + * Use layer.drawFeature() from outside the renderer. │ │ │ │ + * virtual function │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * func - {Function} Input function. │ │ │ │ - * object - {Object} The object to bind to the input function (as this). │ │ │ │ + * geometry - {} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {} │ │ │ │ + */ │ │ │ │ + drawGeometry: function(geometry, style, featureId) {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: drawText │ │ │ │ + * Function for drawing text labels. │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Function} A closure with 'this' set to the passed in object. │ │ │ │ + * Parameters: │ │ │ │ + * featureId - {String} │ │ │ │ + * style - │ │ │ │ + * location - {} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ + drawText: function(featureId, style, location) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIFunction: bindAsEventListener │ │ │ │ - * Bind a function to an object, and configure it to receive the event │ │ │ │ - * object as first parameter when called. │ │ │ │ + * Method: removeText │ │ │ │ + * Function for removing text labels. │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * func - {Function} Input function to serve as an event listener. │ │ │ │ - * object - {Object} A reference to this. │ │ │ │ + * 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 - {} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Function} │ │ │ │ + * {String} A feature id or undefined. │ │ │ │ */ │ │ │ │ - bindAsEventListener: function(func, object) { │ │ │ │ - return function(event) { │ │ │ │ - return func.call(object, event || window.event); │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ + getFeatureIdFromEvent: function(evt) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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; │ │ │ │ + * Method: eraseFeatures │ │ │ │ + * This is called by the layer to erase features │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} │ │ │ │ + * Parameters: │ │ │ │ + * features - {Array()} │ │ │ │ */ │ │ │ │ - False: function() { │ │ │ │ - return false; │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: eraseGeometry │ │ │ │ + * Remove a geometry from the renderer (by id). │ │ │ │ + * virtual function. │ │ │ │ * │ │ │ │ - * Usage: │ │ │ │ - * document.onclick = OpenLayers.Function.True; │ │ │ │ + * Parameters: │ │ │ │ + * 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 - {} 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: │ │ │ │ - * {Boolean} │ │ │ │ + * {String} the id of the output layer. │ │ │ │ */ │ │ │ │ - True: function() { │ │ │ │ - return true; │ │ │ │ + getRenderLayerId: function() { │ │ │ │ + return this.container.id; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIFunction: Void │ │ │ │ - * A reusable function that returns ``undefined``. │ │ │ │ - * │ │ │ │ + * Method: applyDefaultSymbolizer │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * symbolizer - {Object} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {undefined} │ │ │ │ + * {Object} │ │ │ │ */ │ │ │ │ - Void: function() {} │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ │ │ │ │ /** │ │ │ │ - * Namespace: OpenLayers.Array │ │ │ │ - * Contains convenience functions for array manipulation. │ │ │ │ + * 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.Array = { │ │ │ │ +OpenLayers.Renderer.defaultSymbolizer = { │ │ │ │ + fillColor: "#000000", │ │ │ │ + strokeColor: "#000000", │ │ │ │ + strokeWidth: 2, │ │ │ │ + fillOpacity: 1, │ │ │ │ + strokeOpacity: 1, │ │ │ │ + pointRadius: 0, │ │ │ │ + labelAlign: 'cm' │ │ │ │ +}; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - } │ │ │ │ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * 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/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. │ │ │ │ @@ -1866,14 +2423,207 @@ │ │ │ │ │ │ │ │ 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. */ │ │ │ │ @@ -2327,152 +3077,14 @@ │ │ │ │ } │ │ │ │ return equals; │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Size" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - 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 │ │ │ │ - * method to set this value and the 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 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 │ │ │ │ - * dictionary exists for the code, the │ │ │ │ - * 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 will be used to determine the appropriate │ │ │ │ - * dictionary. Dictionaries are stored in . │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * key - {String} The key for an i18n string value in the dictionary. │ │ │ │ - * context - {Object} Optional context to be used with │ │ │ │ - * . │ │ │ │ - * │ │ │ │ - * 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 . Looks up a key from a dictionary │ │ │ │ - * based on the current language string. The value of │ │ │ │ - * will be used to determine the appropriate │ │ │ │ - * dictionary. Dictionaries are stored in . │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * key - {String} The key for an i18n string value in the dictionary. │ │ │ │ - * context - {Object} Optional context to be used with │ │ │ │ - * . │ │ │ │ - * │ │ │ │ - * 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. */ │ │ │ │ @@ -4256,841 +4868,14 @@ │ │ │ │ } else { │ │ │ │ str += coordinate < 0 ? OpenLayers.i18n("S") : OpenLayers.i18n("N"); │ │ │ │ } │ │ │ │ return str; │ │ │ │ }; │ │ │ │ │ │ │ │ /* ====================================================================== │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - Rico/Color.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires Rico/license.js │ │ │ │ - * @requires OpenLayers/Console.js │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ - * @requires OpenLayers/BaseTypes/Element.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ - │ │ │ │ -/* │ │ │ │ - * This file has been edited substantially from the Rico-released version by │ │ │ │ - * the OpenLayers development team. │ │ │ │ - */ │ │ │ │ - │ │ │ │ -OpenLayers.Console.warn("OpenLayers.Rico is deprecated"); │ │ │ │ - │ │ │ │ -OpenLayers.Rico = OpenLayers.Rico || {}; │ │ │ │ -OpenLayers.Rico.Color = OpenLayers.Class({ │ │ │ │ - │ │ │ │ - initialize: function(red, green, blue) { │ │ │ │ - this.rgb = { │ │ │ │ - r: red, │ │ │ │ - g: green, │ │ │ │ - b: blue │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - setRed: function(r) { │ │ │ │ - this.rgb.r = r; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - setGreen: function(g) { │ │ │ │ - this.rgb.g = g; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - setBlue: function(b) { │ │ │ │ - this.rgb.b = b; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - setHue: function(h) { │ │ │ │ - │ │ │ │ - // get an HSB model, and set the new hue... │ │ │ │ - var hsb = this.asHSB(); │ │ │ │ - hsb.h = h; │ │ │ │ - │ │ │ │ - // convert back to RGB... │ │ │ │ - this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - setSaturation: function(s) { │ │ │ │ - // get an HSB model, and set the new hue... │ │ │ │ - var hsb = this.asHSB(); │ │ │ │ - hsb.s = s; │ │ │ │ - │ │ │ │ - // convert back to RGB and set values... │ │ │ │ - this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - setBrightness: function(b) { │ │ │ │ - // get an HSB model, and set the new hue... │ │ │ │ - var hsb = this.asHSB(); │ │ │ │ - hsb.b = b; │ │ │ │ - │ │ │ │ - // convert back to RGB and set values... │ │ │ │ - this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - darken: function(percent) { │ │ │ │ - var hsb = this.asHSB(); │ │ │ │ - this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent, 0)); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - brighten: function(percent) { │ │ │ │ - var hsb = this.asHSB(); │ │ │ │ - this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent, 1)); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - blend: function(other) { │ │ │ │ - this.rgb.r = Math.floor((this.rgb.r + other.rgb.r) / 2); │ │ │ │ - this.rgb.g = Math.floor((this.rgb.g + other.rgb.g) / 2); │ │ │ │ - this.rgb.b = Math.floor((this.rgb.b + other.rgb.b) / 2); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - isBright: function() { │ │ │ │ - var hsb = this.asHSB(); │ │ │ │ - return this.asHSB().b > 0.5; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - isDark: function() { │ │ │ │ - return !this.isBright(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - asRGB: function() { │ │ │ │ - return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")"; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - asHex: function() { │ │ │ │ - return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - asHSB: function() { │ │ │ │ - return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - toString: function() { │ │ │ │ - return this.asHex(); │ │ │ │ - } │ │ │ │ - │ │ │ │ -}); │ │ │ │ - │ │ │ │ -OpenLayers.Rico.Color.createFromHex = function(hexCode) { │ │ │ │ - if (hexCode.length == 4) { │ │ │ │ - var shortHexCode = hexCode; │ │ │ │ - var hexCode = '#'; │ │ │ │ - for (var i = 1; i < 4; i++) { │ │ │ │ - hexCode += (shortHexCode.charAt(i) + │ │ │ │ - shortHexCode.charAt(i)); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (hexCode.indexOf('#') == 0) { │ │ │ │ - hexCode = hexCode.substring(1); │ │ │ │ - } │ │ │ │ - var red = hexCode.substring(0, 2); │ │ │ │ - var green = hexCode.substring(2, 4); │ │ │ │ - var blue = hexCode.substring(4, 6); │ │ │ │ - return new OpenLayers.Rico.Color(parseInt(red, 16), parseInt(green, 16), parseInt(blue, 16)); │ │ │ │ -}; │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Factory method for creating a color from the background of │ │ │ │ - * an HTML element. │ │ │ │ - */ │ │ │ │ -OpenLayers.Rico.Color.createColorFromBackground = function(elem) { │ │ │ │ - │ │ │ │ - var actualColor = │ │ │ │ - OpenLayers.Element.getStyle(OpenLayers.Util.getElement(elem), │ │ │ │ - "backgroundColor"); │ │ │ │ - │ │ │ │ - if (actualColor == "transparent" && elem.parentNode) { │ │ │ │ - return OpenLayers.Rico.Color.createColorFromBackground(elem.parentNode); │ │ │ │ - } │ │ │ │ - if (actualColor == null) { │ │ │ │ - return new OpenLayers.Rico.Color(255, 255, 255); │ │ │ │ - } │ │ │ │ - if (actualColor.indexOf("rgb(") == 0) { │ │ │ │ - var colors = actualColor.substring(4, actualColor.length - 1); │ │ │ │ - var colorArray = colors.split(","); │ │ │ │ - return new OpenLayers.Rico.Color(parseInt(colorArray[0]), │ │ │ │ - parseInt(colorArray[1]), │ │ │ │ - parseInt(colorArray[2])); │ │ │ │ - │ │ │ │ - } else if (actualColor.indexOf("#") == 0) { │ │ │ │ - return OpenLayers.Rico.Color.createFromHex(actualColor); │ │ │ │ - } else { │ │ │ │ - return new OpenLayers.Rico.Color(255, 255, 255); │ │ │ │ - } │ │ │ │ -}; │ │ │ │ - │ │ │ │ -OpenLayers.Rico.Color.HSBtoRGB = function(hue, saturation, brightness) { │ │ │ │ - │ │ │ │ - var red = 0; │ │ │ │ - var green = 0; │ │ │ │ - var blue = 0; │ │ │ │ - │ │ │ │ - if (saturation == 0) { │ │ │ │ - red = parseInt(brightness * 255.0 + 0.5); │ │ │ │ - green = red; │ │ │ │ - blue = red; │ │ │ │ - } else { │ │ │ │ - var h = (hue - Math.floor(hue)) * 6.0; │ │ │ │ - var f = h - Math.floor(h); │ │ │ │ - var p = brightness * (1.0 - saturation); │ │ │ │ - var q = brightness * (1.0 - saturation * f); │ │ │ │ - var t = brightness * (1.0 - (saturation * (1.0 - f))); │ │ │ │ - │ │ │ │ - switch (parseInt(h)) { │ │ │ │ - case 0: │ │ │ │ - red = (brightness * 255.0 + 0.5); │ │ │ │ - green = (t * 255.0 + 0.5); │ │ │ │ - blue = (p * 255.0 + 0.5); │ │ │ │ - break; │ │ │ │ - case 1: │ │ │ │ - red = (q * 255.0 + 0.5); │ │ │ │ - green = (brightness * 255.0 + 0.5); │ │ │ │ - blue = (p * 255.0 + 0.5); │ │ │ │ - break; │ │ │ │ - case 2: │ │ │ │ - red = (p * 255.0 + 0.5); │ │ │ │ - green = (brightness * 255.0 + 0.5); │ │ │ │ - blue = (t * 255.0 + 0.5); │ │ │ │ - break; │ │ │ │ - case 3: │ │ │ │ - red = (p * 255.0 + 0.5); │ │ │ │ - green = (q * 255.0 + 0.5); │ │ │ │ - blue = (brightness * 255.0 + 0.5); │ │ │ │ - break; │ │ │ │ - case 4: │ │ │ │ - red = (t * 255.0 + 0.5); │ │ │ │ - green = (p * 255.0 + 0.5); │ │ │ │ - blue = (brightness * 255.0 + 0.5); │ │ │ │ - break; │ │ │ │ - case 5: │ │ │ │ - red = (brightness * 255.0 + 0.5); │ │ │ │ - green = (p * 255.0 + 0.5); │ │ │ │ - blue = (q * 255.0 + 0.5); │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return { │ │ │ │ - r: parseInt(red), │ │ │ │ - g: parseInt(green), │ │ │ │ - b: parseInt(blue) │ │ │ │ - }; │ │ │ │ -}; │ │ │ │ - │ │ │ │ -OpenLayers.Rico.Color.RGBtoHSB = function(r, g, b) { │ │ │ │ - │ │ │ │ - var hue; │ │ │ │ - var saturation; │ │ │ │ - var brightness; │ │ │ │ - │ │ │ │ - var cmax = (r > g) ? r : g; │ │ │ │ - if (b > cmax) { │ │ │ │ - cmax = b; │ │ │ │ - } │ │ │ │ - var cmin = (r < g) ? r : g; │ │ │ │ - if (b < cmin) { │ │ │ │ - cmin = b; │ │ │ │ - } │ │ │ │ - brightness = cmax / 255.0; │ │ │ │ - if (cmax != 0) { │ │ │ │ - saturation = (cmax - cmin) / cmax; │ │ │ │ - } else { │ │ │ │ - saturation = 0; │ │ │ │ - } │ │ │ │ - if (saturation == 0) { │ │ │ │ - hue = 0; │ │ │ │ - } else { │ │ │ │ - var redc = (cmax - r) / (cmax - cmin); │ │ │ │ - var greenc = (cmax - g) / (cmax - cmin); │ │ │ │ - var bluec = (cmax - b) / (cmax - cmin); │ │ │ │ - │ │ │ │ - if (r == cmax) { │ │ │ │ - hue = bluec - greenc; │ │ │ │ - } else if (g == cmax) { │ │ │ │ - hue = 2.0 + redc - bluec; │ │ │ │ - } else { │ │ │ │ - hue = 4.0 + greenc - redc; │ │ │ │ - } │ │ │ │ - hue = hue / 6.0; │ │ │ │ - if (hue < 0) { │ │ │ │ - hue = hue + 1.0; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return { │ │ │ │ - h: hue, │ │ │ │ - s: saturation, │ │ │ │ - b: brightness │ │ │ │ - }; │ │ │ │ -}; │ │ │ │ - │ │ │ │ -/* ====================================================================== │ │ │ │ - Rico/Corner.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Console.js │ │ │ │ - * @requires Rico/Color.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ - │ │ │ │ -/* │ │ │ │ - * This file has been edited substantially from the Rico-released │ │ │ │ - * version by the OpenLayers development team. │ │ │ │ - * │ │ │ │ - * Copyright 2005 Sabre Airline Solutions │ │ │ │ - * │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ - */ │ │ │ │ - │ │ │ │ -OpenLayers.Console.warn("OpenLayers.Rico is deprecated"); │ │ │ │ - │ │ │ │ -OpenLayers.Rico = OpenLayers.Rico || {}; │ │ │ │ -OpenLayers.Rico.Corner = { │ │ │ │ - │ │ │ │ - round: function(e, options) { │ │ │ │ - e = OpenLayers.Util.getElement(e); │ │ │ │ - this._setOptions(options); │ │ │ │ - │ │ │ │ - var color = this.options.color; │ │ │ │ - if (this.options.color == "fromElement") { │ │ │ │ - color = this._background(e); │ │ │ │ - } │ │ │ │ - var bgColor = this.options.bgColor; │ │ │ │ - if (this.options.bgColor == "fromParent") { │ │ │ │ - bgColor = this._background(e.offsetParent); │ │ │ │ - } │ │ │ │ - this._roundCornersImpl(e, color, bgColor); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** This is a helper function to change the background │ │ │ │ - * color of
that has had Rico rounded corners added. │ │ │ │ - * │ │ │ │ - * It seems we cannot just set the background color for the │ │ │ │ - * outer
so each element used to create the │ │ │ │ - * corners must have its background color set individually. │ │ │ │ - * │ │ │ │ - * @param {DOM} theDiv - A child of the outer
that was │ │ │ │ - * supplied to the `round` method. │ │ │ │ - * │ │ │ │ - * @param {String} newColor - The new background color to use. │ │ │ │ - */ │ │ │ │ - changeColor: function(theDiv, newColor) { │ │ │ │ - │ │ │ │ - theDiv.style.backgroundColor = newColor; │ │ │ │ - │ │ │ │ - var spanElements = theDiv.parentNode.getElementsByTagName("span"); │ │ │ │ - │ │ │ │ - for (var currIdx = 0; currIdx < spanElements.length; currIdx++) { │ │ │ │ - spanElements[currIdx].style.backgroundColor = newColor; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** This is a helper function to change the background │ │ │ │ - * opacity of
that has had Rico rounded corners added. │ │ │ │ - * │ │ │ │ - * See changeColor (above) for algorithm explanation │ │ │ │ - * │ │ │ │ - * @param {DOM} theDiv A child of the outer
that was │ │ │ │ - * supplied to the `round` method. │ │ │ │ - * │ │ │ │ - * @param {int} newOpacity The new opacity to use (0-1). │ │ │ │ - */ │ │ │ │ - changeOpacity: function(theDiv, newOpacity) { │ │ │ │ - │ │ │ │ - var mozillaOpacity = newOpacity; │ │ │ │ - var ieOpacity = 'alpha(opacity=' + newOpacity * 100 + ')'; │ │ │ │ - │ │ │ │ - theDiv.style.opacity = mozillaOpacity; │ │ │ │ - theDiv.style.filter = ieOpacity; │ │ │ │ - │ │ │ │ - var spanElements = theDiv.parentNode.getElementsByTagName("span"); │ │ │ │ - │ │ │ │ - for (var currIdx = 0; currIdx < spanElements.length; currIdx++) { │ │ │ │ - spanElements[currIdx].style.opacity = mozillaOpacity; │ │ │ │ - spanElements[currIdx].style.filter = ieOpacity; │ │ │ │ - } │ │ │ │ - │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** this function takes care of redoing the rico cornering │ │ │ │ - * │ │ │ │ - * you can't just call updateRicoCorners() again and pass it a │ │ │ │ - * new options string. you have to first remove the divs that │ │ │ │ - * rico puts on top and below the content div. │ │ │ │ - * │ │ │ │ - * @param {DOM} theDiv - A child of the outer
that was │ │ │ │ - * supplied to the `round` method. │ │ │ │ - * │ │ │ │ - * @param {Object} options - list of options │ │ │ │ - */ │ │ │ │ - reRound: function(theDiv, options) { │ │ │ │ - │ │ │ │ - var topRico = theDiv.parentNode.childNodes[0]; │ │ │ │ - //theDiv would be theDiv.parentNode.childNodes[1] │ │ │ │ - var bottomRico = theDiv.parentNode.childNodes[2]; │ │ │ │ - │ │ │ │ - theDiv.parentNode.removeChild(topRico); │ │ │ │ - theDiv.parentNode.removeChild(bottomRico); │ │ │ │ - │ │ │ │ - this.round(theDiv.parentNode, options); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - _roundCornersImpl: function(e, color, bgColor) { │ │ │ │ - if (this.options.border) { │ │ │ │ - this._renderBorder(e, bgColor); │ │ │ │ - } │ │ │ │ - if (this._isTopRounded()) { │ │ │ │ - this._roundTopCorners(e, color, bgColor); │ │ │ │ - } │ │ │ │ - if (this._isBottomRounded()) { │ │ │ │ - this._roundBottomCorners(e, color, bgColor); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - _renderBorder: function(el, bgColor) { │ │ │ │ - var borderValue = "1px solid " + this._borderColor(bgColor); │ │ │ │ - var borderL = "border-left: " + borderValue; │ │ │ │ - var borderR = "border-right: " + borderValue; │ │ │ │ - var style = "style='" + borderL + ";" + borderR + "'"; │ │ │ │ - el.innerHTML = "
" + el.innerHTML + "
"; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - _roundTopCorners: function(el, color, bgColor) { │ │ │ │ - var corner = this._createCorner(bgColor); │ │ │ │ - for (var i = 0; i < this.options.numSlices; i++) { │ │ │ │ - corner.appendChild(this._createCornerSlice(color, bgColor, i, "top")); │ │ │ │ - } │ │ │ │ - el.style.paddingTop = 0; │ │ │ │ - el.insertBefore(corner, el.firstChild); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - _roundBottomCorners: function(el, color, bgColor) { │ │ │ │ - var corner = this._createCorner(bgColor); │ │ │ │ - for (var i = (this.options.numSlices - 1); i >= 0; i--) { │ │ │ │ - corner.appendChild(this._createCornerSlice(color, bgColor, i, "bottom")); │ │ │ │ - } │ │ │ │ - el.style.paddingBottom = 0; │ │ │ │ - el.appendChild(corner); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - _createCorner: function(bgColor) { │ │ │ │ - var corner = document.createElement("div"); │ │ │ │ - corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor); │ │ │ │ - return corner; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - _createCornerSlice: function(color, bgColor, n, position) { │ │ │ │ - var slice = document.createElement("span"); │ │ │ │ - │ │ │ │ - var inStyle = slice.style; │ │ │ │ - inStyle.backgroundColor = color; │ │ │ │ - inStyle.display = "block"; │ │ │ │ - inStyle.height = "1px"; │ │ │ │ - inStyle.overflow = "hidden"; │ │ │ │ - inStyle.fontSize = "1px"; │ │ │ │ - │ │ │ │ - var borderColor = this._borderColor(color, bgColor); │ │ │ │ - if (this.options.border && n == 0) { │ │ │ │ - inStyle.borderTopStyle = "solid"; │ │ │ │ - inStyle.borderTopWidth = "1px"; │ │ │ │ - inStyle.borderLeftWidth = "0px"; │ │ │ │ - inStyle.borderRightWidth = "0px"; │ │ │ │ - inStyle.borderBottomWidth = "0px"; │ │ │ │ - inStyle.height = "0px"; // assumes css compliant box model │ │ │ │ - inStyle.borderColor = borderColor; │ │ │ │ - } else if (borderColor) { │ │ │ │ - inStyle.borderColor = borderColor; │ │ │ │ - inStyle.borderStyle = "solid"; │ │ │ │ - inStyle.borderWidth = "0px 1px"; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (!this.options.compact && (n == (this.options.numSlices - 1))) { │ │ │ │ - inStyle.height = "2px"; │ │ │ │ - } │ │ │ │ - this._setMargin(slice, n, position); │ │ │ │ - this._setBorder(slice, n, position); │ │ │ │ - return slice; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - _setOptions: function(options) { │ │ │ │ - this.options = { │ │ │ │ - corners: "all", │ │ │ │ - color: "fromElement", │ │ │ │ - bgColor: "fromParent", │ │ │ │ - blend: true, │ │ │ │ - border: false, │ │ │ │ - compact: false │ │ │ │ - }; │ │ │ │ - OpenLayers.Util.extend(this.options, options || {}); │ │ │ │ - │ │ │ │ - this.options.numSlices = this.options.compact ? 2 : 4; │ │ │ │ - if (this._isTransparent()) { │ │ │ │ - this.options.blend = false; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - _whichSideTop: function() { │ │ │ │ - if (this._hasString(this.options.corners, "all", "top")) { │ │ │ │ - return ""; │ │ │ │ - } │ │ │ │ - if (this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0) { │ │ │ │ - return ""; │ │ │ │ - } │ │ │ │ - if (this.options.corners.indexOf("tl") >= 0) { │ │ │ │ - return "left"; │ │ │ │ - } else if (this.options.corners.indexOf("tr") >= 0) { │ │ │ │ - return "right"; │ │ │ │ - } │ │ │ │ - return ""; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - _whichSideBottom: function() { │ │ │ │ - if (this._hasString(this.options.corners, "all", "bottom")) { │ │ │ │ - return ""; │ │ │ │ - } │ │ │ │ - if (this.options.corners.indexOf("bl") >= 0 && this.options.corners.indexOf("br") >= 0) { │ │ │ │ - return ""; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.options.corners.indexOf("bl") >= 0) { │ │ │ │ - return "left"; │ │ │ │ - } else if (this.options.corners.indexOf("br") >= 0) { │ │ │ │ - return "right"; │ │ │ │ - } │ │ │ │ - return ""; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - _borderColor: function(color, bgColor) { │ │ │ │ - if (color == "transparent") { │ │ │ │ - return bgColor; │ │ │ │ - } else if (this.options.border) { │ │ │ │ - return this.options.border; │ │ │ │ - } else if (this.options.blend) { │ │ │ │ - return this._blend(bgColor, color); │ │ │ │ - } else { │ │ │ │ - return ""; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - _setMargin: function(el, n, corners) { │ │ │ │ - var marginSize = this._marginSize(n); │ │ │ │ - var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); │ │ │ │ - │ │ │ │ - if (whichSide == "left") { │ │ │ │ - el.style.marginLeft = marginSize + "px"; │ │ │ │ - el.style.marginRight = "0px"; │ │ │ │ - } else if (whichSide == "right") { │ │ │ │ - el.style.marginRight = marginSize + "px"; │ │ │ │ - el.style.marginLeft = "0px"; │ │ │ │ - } else { │ │ │ │ - el.style.marginLeft = marginSize + "px"; │ │ │ │ - el.style.marginRight = marginSize + "px"; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - _setBorder: function(el, n, corners) { │ │ │ │ - var borderSize = this._borderSize(n); │ │ │ │ - var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); │ │ │ │ - if (whichSide == "left") { │ │ │ │ - el.style.borderLeftWidth = borderSize + "px"; │ │ │ │ - el.style.borderRightWidth = "0px"; │ │ │ │ - } else if (whichSide == "right") { │ │ │ │ - el.style.borderRightWidth = borderSize + "px"; │ │ │ │ - el.style.borderLeftWidth = "0px"; │ │ │ │ - } else { │ │ │ │ - el.style.borderLeftWidth = borderSize + "px"; │ │ │ │ - el.style.borderRightWidth = borderSize + "px"; │ │ │ │ - } │ │ │ │ - if (this.options.border != false) { │ │ │ │ - el.style.borderLeftWidth = borderSize + "px"; │ │ │ │ - el.style.borderRightWidth = borderSize + "px"; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - _marginSize: function(n) { │ │ │ │ - if (this._isTransparent()) { │ │ │ │ - return 0; │ │ │ │ - } │ │ │ │ - var marginSizes = [5, 3, 2, 1]; │ │ │ │ - var blendedMarginSizes = [3, 2, 1, 0]; │ │ │ │ - var compactMarginSizes = [2, 1]; │ │ │ │ - var smBlendedMarginSizes = [1, 0]; │ │ │ │ - │ │ │ │ - if (this.options.compact && this.options.blend) { │ │ │ │ - return smBlendedMarginSizes[n]; │ │ │ │ - } else if (this.options.compact) { │ │ │ │ - return compactMarginSizes[n]; │ │ │ │ - } else if (this.options.blend) { │ │ │ │ - return blendedMarginSizes[n]; │ │ │ │ - } else { │ │ │ │ - return marginSizes[n]; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - _borderSize: function(n) { │ │ │ │ - var transparentBorderSizes = [5, 3, 2, 1]; │ │ │ │ - var blendedBorderSizes = [2, 1, 1, 1]; │ │ │ │ - var compactBorderSizes = [1, 0]; │ │ │ │ - var actualBorderSizes = [0, 2, 0, 0]; │ │ │ │ - │ │ │ │ - if (this.options.compact && (this.options.blend || this._isTransparent())) { │ │ │ │ - return 1; │ │ │ │ - } else if (this.options.compact) { │ │ │ │ - return compactBorderSizes[n]; │ │ │ │ - } else if (this.options.blend) { │ │ │ │ - return blendedBorderSizes[n]; │ │ │ │ - } else if (this.options.border) { │ │ │ │ - return actualBorderSizes[n]; │ │ │ │ - } else if (this._isTransparent()) { │ │ │ │ - return transparentBorderSizes[n]; │ │ │ │ - } │ │ │ │ - return 0; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - _hasString: function(str) { │ │ │ │ - for (var i = 1; i < arguments.length; i++) │ │ │ │ - if (str.indexOf(arguments[i]) >= 0) { │ │ │ │ - return true; │ │ │ │ - } return false; │ │ │ │ - }, │ │ │ │ - _blend: function(c1, c2) { │ │ │ │ - var cc1 = OpenLayers.Rico.Color.createFromHex(c1); │ │ │ │ - cc1.blend(OpenLayers.Rico.Color.createFromHex(c2)); │ │ │ │ - return cc1; │ │ │ │ - }, │ │ │ │ - _background: function(el) { │ │ │ │ - try { │ │ │ │ - return OpenLayers.Rico.Color.createColorFromBackground(el).asHex(); │ │ │ │ - } catch (err) { │ │ │ │ - return "#ffffff"; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - _isTransparent: function() { │ │ │ │ - return this.options.color == "transparent"; │ │ │ │ - }, │ │ │ │ - _isTopRounded: function() { │ │ │ │ - return this._hasString(this.options.corners, "all", "top", "tl", "tr"); │ │ │ │ - }, │ │ │ │ - _isBottomRounded: function() { │ │ │ │ - return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); │ │ │ │ - }, │ │ │ │ - _hasSingleTextChild: function(el) { │ │ │ │ - return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ 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. */ │ │ │ │ @@ -6279,15 +6064,15 @@ │ │ │ │ * {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/Rule.js │ │ │ │ + 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. */ │ │ │ │ │ │ │ │ @@ -6295,236 +6080,86 @@ │ │ │ │ /** │ │ │ │ * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ * @requires OpenLayers/Util.js │ │ │ │ * @requires OpenLayers/Style.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Rule │ │ │ │ - * This class represents an SLD Rule, as being used for rule-based SLD styling. │ │ │ │ + * Class: OpenLayers.Filter │ │ │ │ + * This class represents an OGC Filter. │ │ │ │ */ │ │ │ │ -OpenLayers.Rule = OpenLayers.Class({ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: id │ │ │ │ - * {String} A unique id for this session. │ │ │ │ - */ │ │ │ │ - id: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: name │ │ │ │ - * {String} name of this rule │ │ │ │ - */ │ │ │ │ - name: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: title │ │ │ │ - * {String} Title of this rule (set if included in SLD) │ │ │ │ - */ │ │ │ │ - title: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: description │ │ │ │ - * {String} Description of this rule (set if abstract is included in SLD) │ │ │ │ - */ │ │ │ │ - description: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: context │ │ │ │ - * {Object} An optional object with properties that the rule should be │ │ │ │ - * evaluated against. If no context is specified, feature.attributes will │ │ │ │ - * be used. │ │ │ │ - */ │ │ │ │ - context: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: filter │ │ │ │ - * {} Optional filter for the rule. │ │ │ │ - */ │ │ │ │ - filter: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: elseFilter │ │ │ │ - * {Boolean} Determines whether this rule is only to be applied only if │ │ │ │ - * no other rules match (ElseFilter according to the SLD specification). │ │ │ │ - * Default is false. For instances of OpenLayers.Rule, if elseFilter is │ │ │ │ - * false, the rule will always apply. For subclasses, the else property is │ │ │ │ - * ignored. │ │ │ │ - */ │ │ │ │ - elseFilter: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: symbolizer │ │ │ │ - * {Object} Symbolizer or hash of symbolizers for this rule. If hash of │ │ │ │ - * symbolizers, keys are one or more of ["Point", "Line", "Polygon"]. The │ │ │ │ - * latter if useful if it is required to style e.g. vertices of a line │ │ │ │ - * with a point symbolizer. Note, however, that this is not implemented │ │ │ │ - * yet in OpenLayers, but it is the way how symbolizers are defined in │ │ │ │ - * SLD. │ │ │ │ - */ │ │ │ │ - symbolizer: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: symbolizers │ │ │ │ - * {Array} Collection of symbolizers associated with this rule. If │ │ │ │ - * provided at construction, the symbolizers array has precedence │ │ │ │ - * over the deprecated symbolizer property. Note that multiple │ │ │ │ - * symbolizers are not currently supported by the vector renderers. │ │ │ │ - * Rules with multiple symbolizers are currently only useful for │ │ │ │ - * maintaining elements in an SLD document. │ │ │ │ - */ │ │ │ │ - symbolizers: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: minScaleDenominator │ │ │ │ - * {Number} or {String} minimum scale at which to draw the feature. │ │ │ │ - * In the case of a String, this can be a combination of text and │ │ │ │ - * propertyNames in the form "literal ${propertyName}" │ │ │ │ - */ │ │ │ │ - minScaleDenominator: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: maxScaleDenominator │ │ │ │ - * {Number} or {String} maximum scale at which to draw the feature. │ │ │ │ - * In the case of a String, this can be a combination of text and │ │ │ │ - * propertyNames in the form "literal ${propertyName}" │ │ │ │ - */ │ │ │ │ - maxScaleDenominator: null, │ │ │ │ +OpenLayers.Filter = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Rule │ │ │ │ - * Creates a Rule. │ │ │ │ + * Constructor: OpenLayers.Filter │ │ │ │ + * This class represents a generic filter. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object with properties to set on the │ │ │ │ - * rule │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {} │ │ │ │ + * {} │ │ │ │ */ │ │ │ │ initialize: function(options) { │ │ │ │ - this.symbolizer = {}; │ │ │ │ OpenLayers.Util.extend(this, options); │ │ │ │ - if (this.symbolizers) { │ │ │ │ - delete this.symbolizer; │ │ │ │ - } │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: destroy │ │ │ │ - * nullify references to prevent circular references and memory leaks │ │ │ │ + * Remove reference to anything added. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - for (var i in this.symbolizer) { │ │ │ │ - this.symbolizer[i] = null; │ │ │ │ - } │ │ │ │ - this.symbolizer = null; │ │ │ │ - delete this.symbolizers; │ │ │ │ - }, │ │ │ │ + destroy: function() {}, │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: evaluate │ │ │ │ - * evaluates this rule for a specific feature │ │ │ │ + * Evaluates this filter in a specific context. Instances or subclasses │ │ │ │ + * are supposed to override this method. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {} feature to apply the rule to. │ │ │ │ + * 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} true if the rule applies, false if it does not. │ │ │ │ - * This rule is the default rule and always returns true. │ │ │ │ + * {Boolean} The filter applies. │ │ │ │ */ │ │ │ │ - evaluate: function(feature) { │ │ │ │ - var context = this.getContext(feature); │ │ │ │ - var applies = true; │ │ │ │ - │ │ │ │ - if (this.minScaleDenominator || this.maxScaleDenominator) { │ │ │ │ - var scale = feature.layer.map.getScale(); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // check if within minScale/maxScale bounds │ │ │ │ - if (this.minScaleDenominator) { │ │ │ │ - applies = scale >= OpenLayers.Style.createLiteral( │ │ │ │ - this.minScaleDenominator, context); │ │ │ │ - } │ │ │ │ - if (applies && this.maxScaleDenominator) { │ │ │ │ - applies = scale < OpenLayers.Style.createLiteral( │ │ │ │ - this.maxScaleDenominator, context); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // check if optional filter applies │ │ │ │ - if (applies && this.filter) { │ │ │ │ - // feature id filters get the feature, others get the context │ │ │ │ - if (this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") { │ │ │ │ - applies = this.filter.evaluate(feature); │ │ │ │ - } else { │ │ │ │ - applies = this.filter.evaluate(context); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return applies; │ │ │ │ + evaluate: function(context) { │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getContext │ │ │ │ - * Gets the context for evaluating this rule │ │ │ │ + * APIMethod: clone │ │ │ │ + * Clones this filter. Should be implemented by subclasses. │ │ │ │ * │ │ │ │ - * Paramters: │ │ │ │ - * feature - {} feature to take the context from if │ │ │ │ - * none is specified. │ │ │ │ + * Returns: │ │ │ │ + * {} Clone of this filter. │ │ │ │ */ │ │ │ │ - getContext: function(feature) { │ │ │ │ - var context = this.context; │ │ │ │ - if (!context) { │ │ │ │ - context = feature.attributes || feature.data; │ │ │ │ - } │ │ │ │ - if (typeof this.context == "function") { │ │ │ │ - context = this.context(feature); │ │ │ │ - } │ │ │ │ - return context; │ │ │ │ + clone: function() { │ │ │ │ + return null; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Clones this rule. │ │ │ │ - * │ │ │ │ + * APIMethod: toString │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {} Clone of this rule. │ │ │ │ + * {String} Include in your build to get a CQL │ │ │ │ + * representation of the filter returned. Otherwise "[Object object]" │ │ │ │ + * will be returned. │ │ │ │ */ │ │ │ │ - clone: function() { │ │ │ │ - var options = OpenLayers.Util.extend({}, this); │ │ │ │ - if (this.symbolizers) { │ │ │ │ - // clone symbolizers │ │ │ │ - var len = this.symbolizers.length; │ │ │ │ - options.symbolizers = new Array(len); │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ - options.symbolizers[i] = this.symbolizers[i].clone(); │ │ │ │ - } │ │ │ │ + toString: function() { │ │ │ │ + var string; │ │ │ │ + if (OpenLayers.Format && OpenLayers.Format.CQL) { │ │ │ │ + string = OpenLayers.Format.CQL.prototype.write(this); │ │ │ │ } else { │ │ │ │ - // clone symbolizer │ │ │ │ - options.symbolizer = {}; │ │ │ │ - var value, type; │ │ │ │ - for (var key in this.symbolizer) { │ │ │ │ - value = this.symbolizer[key]; │ │ │ │ - type = typeof value; │ │ │ │ - if (type === "object") { │ │ │ │ - options.symbolizer[key] = OpenLayers.Util.extend({}, value); │ │ │ │ - } else if (type === "string") { │ │ │ │ - options.symbolizer[key] = value; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + string = Object.prototype.toString.call(this); │ │ │ │ } │ │ │ │ - // clone filter │ │ │ │ - options.filter = this.filter && this.filter.clone(); │ │ │ │ - // clone context │ │ │ │ - options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ - return new OpenLayers.Rule(options); │ │ │ │ + return string; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Rule" │ │ │ │ + CLASS_NAME: "OpenLayers.Filter" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ 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. │ │ │ │ @@ -6660,485 +6295,14 @@ │ │ │ │ │ │ │ │ // 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 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 │ │ │ │ - * . │ │ │ │ - */ │ │ │ │ - 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 . │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * id - {Number} Identifier returned from . │ │ │ │ - */ │ │ │ │ - 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 │ │ │ │ - * {(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 - {(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, │ │ │ │ - */ │ │ │ │ -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/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. */ │ │ │ │ @@ -8307,14 +7471,485 @@ │ │ │ │ │ │ │ │ OpenLayers.Event.observe(element, 'MSPointerUp', cb); │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Events" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ + 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 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 │ │ │ │ + * . │ │ │ │ + */ │ │ │ │ + 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 . │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * id - {Number} Identifier returned from . │ │ │ │ + */ │ │ │ │ + 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 │ │ │ │ + * {(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 - {(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, │ │ │ │ + */ │ │ │ │ +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. */ │ │ │ │ @@ -15820,465 +15455,514 @@ │ │ │ │ this.tileCache = null; │ │ │ │ this.tileCacheIndex = null; │ │ │ │ this._destroyed = true; │ │ │ │ } │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Strategy.js │ │ │ │ + OpenLayers/Icon.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. │ │ │ │ + * Class: OpenLayers.Icon │ │ │ │ + * │ │ │ │ + * The icon represents a graphical icon on the screen. Typically used in │ │ │ │ + * conjunction with a to represent markers on a screen. │ │ │ │ + * │ │ │ │ + * An icon has a url, size and position. It also contains an offset which │ │ │ │ + * allows the center point to be represented correctly. This can be │ │ │ │ + * provided either as a fixed offset or a function provided to calculate │ │ │ │ + * the desired offset. │ │ │ │ + * │ │ │ │ */ │ │ │ │ -OpenLayers.Strategy = OpenLayers.Class({ │ │ │ │ +OpenLayers.Icon = OpenLayers.Class({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: layer │ │ │ │ - * {} The layer this strategy belongs to. │ │ │ │ + /** │ │ │ │ + * Property: url │ │ │ │ + * {String} image url │ │ │ │ */ │ │ │ │ - layer: null, │ │ │ │ + url: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: options │ │ │ │ - * {Object} Any options sent to the constructor. │ │ │ │ + /** │ │ │ │ + * Property: size │ │ │ │ + * {|Object} An OpenLayers.Size or │ │ │ │ + * an object with a 'w' and 'h' properties. │ │ │ │ */ │ │ │ │ - options: null, │ │ │ │ + size: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: active │ │ │ │ - * {Boolean} The control is active. │ │ │ │ + * Property: offset │ │ │ │ + * {|Object} distance in pixels to offset the │ │ │ │ + * image when being rendered. An OpenLayers.Pixel or an object │ │ │ │ + * with a 'x' and 'y' properties. │ │ │ │ */ │ │ │ │ - active: null, │ │ │ │ + offset: 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. │ │ │ │ + /** │ │ │ │ + * Property: calculateOffset │ │ │ │ + * {Function} Function to calculate the offset (based on the size) │ │ │ │ */ │ │ │ │ - autoActivate: true, │ │ │ │ + calculateOffset: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: autoDestroy │ │ │ │ - * {Boolean} The creator of the strategy can set autoDestroy to false │ │ │ │ - * to fully control when the strategy is destroyed. Defaults to │ │ │ │ - * true. │ │ │ │ + /** │ │ │ │ + * Property: imageDiv │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - autoDestroy: true, │ │ │ │ + imageDiv: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Strategy │ │ │ │ - * Abstract class for vector strategies. Create instances of a subclass. │ │ │ │ + /** │ │ │ │ + * Property: px │ │ │ │ + * {|Object} An OpenLayers.Pixel or an object │ │ │ │ + * with a 'x' and 'y' properties. │ │ │ │ + */ │ │ │ │ + px: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Icon │ │ │ │ + * Creates an icon, which is an image tag in a div. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * url - {String} │ │ │ │ + * size - {|Object} An OpenLayers.Size or an │ │ │ │ + * object with a 'w' and 'h' │ │ │ │ + * properties. │ │ │ │ + * offset - {|Object} An OpenLayers.Pixel or an │ │ │ │ + * object with a 'x' and 'y' │ │ │ │ + * properties. │ │ │ │ + * calculateOffset - {Function} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + initialize: function(url, size, offset, calculateOffset) { │ │ │ │ + this.url = url; │ │ │ │ + this.size = size || { │ │ │ │ + w: 20, │ │ │ │ + h: 20 │ │ │ │ + }; │ │ │ │ + this.offset = offset || { │ │ │ │ + x: -(this.size.w / 2), │ │ │ │ + y: -(this.size.h / 2) │ │ │ │ + }; │ │ │ │ + this.calculateOffset = calculateOffset; │ │ │ │ + │ │ │ │ + var id = OpenLayers.Util.createUniqueID("OL_Icon_"); │ │ │ │ + this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Clean up the strategy. │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + * Nullify references and remove event listeners to prevent circular │ │ │ │ + * references and memory leaks │ │ │ │ */ │ │ │ │ destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - this.layer = null; │ │ │ │ - this.options = null; │ │ │ │ + // erase any drawn elements │ │ │ │ + this.erase(); │ │ │ │ + │ │ │ │ + OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild); │ │ │ │ + this.imageDiv.innerHTML = ""; │ │ │ │ + this.imageDiv = null; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clone │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {} A fresh copy of the icon. │ │ │ │ + */ │ │ │ │ + clone: function() { │ │ │ │ + return new OpenLayers.Icon(this.url, │ │ │ │ + this.size, │ │ │ │ + this.offset, │ │ │ │ + this.calculateOffset); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setLayer │ │ │ │ - * Called to set the property. │ │ │ │ - * │ │ │ │ + * Method: setSize │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * layer - {} │ │ │ │ + * size - {|Object} An OpenLayers.Size or │ │ │ │ + * an object with a 'w' and 'h' properties. │ │ │ │ */ │ │ │ │ - setLayer: function(layer) { │ │ │ │ - this.layer = layer; │ │ │ │ + setSize: function(size) { │ │ │ │ + if (size != null) { │ │ │ │ + this.size = size; │ │ │ │ + } │ │ │ │ + this.draw(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ - * │ │ │ │ + * Method: setUrl │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * url - {String} │ │ │ │ + */ │ │ │ │ + setUrl: function(url) { │ │ │ │ + if (url != null) { │ │ │ │ + this.url = url; │ │ │ │ + } │ │ │ │ + this.draw(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: draw │ │ │ │ + * Move the div to the given pixel. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * px - {|Object} An OpenLayers.Pixel or an │ │ │ │ + * object with a 'x' and 'y' properties. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ - * the strategy was already active. │ │ │ │ + * {DOMElement} A new DOM Image of this icon set at the location passed-in │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - if (!this.active) { │ │ │ │ - this.active = true; │ │ │ │ - return true; │ │ │ │ + draw: function(px) { │ │ │ │ + OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, │ │ │ │ + null, │ │ │ │ + null, │ │ │ │ + this.size, │ │ │ │ + this.url, │ │ │ │ + "absolute"); │ │ │ │ + this.moveTo(px); │ │ │ │ + return this.imageDiv; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: erase │ │ │ │ + * Erase the underlying image element. │ │ │ │ + */ │ │ │ │ + erase: function() { │ │ │ │ + if (this.imageDiv != null && this.imageDiv.parentNode != null) { │ │ │ │ + OpenLayers.Element.remove(this.imageDiv); │ │ │ │ } │ │ │ │ - return false; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setOpacity │ │ │ │ + * Change the icon's opacity │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * opacity - {float} │ │ │ │ + */ │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ + OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, │ │ │ │ + null, null, null, null, opacity); │ │ │ │ + │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ - * tear-down. │ │ │ │ + * Method: moveTo │ │ │ │ + * move icon to passed in px. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} True if the strategy was successfully deactivated or false if │ │ │ │ - * the strategy was already inactive. │ │ │ │ + * Parameters: │ │ │ │ + * px - {|Object} the pixel position to move to. │ │ │ │ + * An OpenLayers.Pixel or an object with a 'x' and 'y' properties. │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - if (this.active) { │ │ │ │ - this.active = false; │ │ │ │ - return true; │ │ │ │ + moveTo: function(px) { │ │ │ │ + //if no px passed in, use stored location │ │ │ │ + if (px != null) { │ │ │ │ + this.px = px; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.imageDiv != null) { │ │ │ │ + if (this.px == null) { │ │ │ │ + this.display(false); │ │ │ │ + } else { │ │ │ │ + if (this.calculateOffset) { │ │ │ │ + this.offset = this.calculateOffset(this.size); │ │ │ │ + } │ │ │ │ + OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, { │ │ │ │ + x: this.px.x + this.offset.x, │ │ │ │ + y: this.px.y + this.offset.y │ │ │ │ + }); │ │ │ │ + } │ │ │ │ } │ │ │ │ - return false; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ + /** │ │ │ │ + * Method: display │ │ │ │ + * Hide or show the icon │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * display - {Boolean} │ │ │ │ + */ │ │ │ │ + display: function(display) { │ │ │ │ + this.imageDiv.style.display = (display) ? "" : "none"; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: isDrawn │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the icon is drawn. │ │ │ │ + */ │ │ │ │ + isDrawn: function() { │ │ │ │ + // nodeType 11 for ie, whose nodes *always* have a parentNode │ │ │ │ + // (of type document fragment) │ │ │ │ + var isDrawn = (this.imageDiv && this.imageDiv.parentNode && │ │ │ │ + (this.imageDiv.parentNode.nodeType != 11)); │ │ │ │ + │ │ │ │ + return isDrawn; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Icon" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Handler.js │ │ │ │ + OpenLayers/Marker.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 │ │ │ │ + * @requires OpenLayers/Icon.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. │ │ │ │ + * Class: OpenLayers.Marker │ │ │ │ + * Instances of OpenLayers.Marker are a combination of a │ │ │ │ + * and an . │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Markers are generally added to a special layer called │ │ │ │ + * . │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * (code) │ │ │ │ + * var markers = new OpenLayers.Layer.Markers( "Markers" ); │ │ │ │ + * map.addLayer(markers); │ │ │ │ + * │ │ │ │ + * var size = new OpenLayers.Size(21,25); │ │ │ │ + * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h); │ │ │ │ + * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset); │ │ │ │ + * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon)); │ │ │ │ + * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone())); │ │ │ │ + * │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Note that if you pass an icon into the Marker constructor, it will take │ │ │ │ + * that icon and use it. This means that you should not share icons between │ │ │ │ + * markers -- you use them once, but you should clone() for any additional │ │ │ │ + * markers using that same icon. │ │ │ │ */ │ │ │ │ -OpenLayers.Handler = OpenLayers.Class({ │ │ │ │ +OpenLayers.Marker = OpenLayers.Class({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: id │ │ │ │ - * {String} │ │ │ │ + /** │ │ │ │ + * Property: icon │ │ │ │ + * {} The icon used by this marker. │ │ │ │ */ │ │ │ │ - id: null, │ │ │ │ + icon: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: 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. │ │ │ │ + /** │ │ │ │ + * Property: lonlat │ │ │ │ + * {} location of object │ │ │ │ */ │ │ │ │ - control: null, │ │ │ │ + lonlat: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: map │ │ │ │ - * {} │ │ │ │ + /** │ │ │ │ + * Property: events │ │ │ │ + * {} the event handler. │ │ │ │ + */ │ │ │ │ + events: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: map │ │ │ │ + * {} the map this marker is attached to │ │ │ │ */ │ │ │ │ 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 │ │ │ │ - * . 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; │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Marker │ │ │ │ * │ │ │ │ - * // handler only responds if Ctrl-Shift is down │ │ │ │ - * handler.keyMask = OpenLayers.Handler.MOD_SHIFT | │ │ │ │ - * OpenLayers.Handler.MOD_CTRL; │ │ │ │ - * (end) │ │ │ │ + * Parameters: │ │ │ │ + * lonlat - {} the position of this marker │ │ │ │ + * icon - {} the icon for this marker │ │ │ │ */ │ │ │ │ - keyMask: null, │ │ │ │ + initialize: function(lonlat, icon) { │ │ │ │ + this.lonlat = lonlat; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: active │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - active: false, │ │ │ │ + var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon(); │ │ │ │ + if (this.icon == null) { │ │ │ │ + this.icon = newIcon; │ │ │ │ + } else { │ │ │ │ + this.icon.url = newIcon.url; │ │ │ │ + this.icon.size = newIcon.size; │ │ │ │ + this.icon.offset = newIcon.offset; │ │ │ │ + this.icon.calculateOffset = newIcon.calculateOffset; │ │ │ │ + } │ │ │ │ + this.events = new OpenLayers.Events(this, this.icon.imageDiv); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Destroy the marker. You must first remove the marker from any │ │ │ │ + * layer which it has been added to, or you will get buggy behavior. │ │ │ │ + * (This can not be done within the marker since the marker does not │ │ │ │ + * know which layer it is attached to.) │ │ │ │ */ │ │ │ │ - evt: null, │ │ │ │ + destroy: function() { │ │ │ │ + // erase any drawn features │ │ │ │ + this.erase(); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + this.map = null; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Handler │ │ │ │ - * Construct a handler. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * 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; │ │ │ │ + this.events.destroy(); │ │ │ │ + this.events = null; │ │ │ │ │ │ │ │ - var map = this.map || control.map; │ │ │ │ - if (map) { │ │ │ │ - this.setMap(map); │ │ │ │ + if (this.icon != null) { │ │ │ │ + this.icon.destroy(); │ │ │ │ + this.icon = null; │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ + /** │ │ │ │ + * Method: draw │ │ │ │ + * Calls draw on the icon, and returns that output. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * px - {} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A new DOM Image with this marker's icon set at the │ │ │ │ + * location passed-in │ │ │ │ + */ │ │ │ │ + draw: function(px) { │ │ │ │ + return this.icon.draw(px); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ + /** │ │ │ │ + * Method: erase │ │ │ │ + * Erases any drawn elements for this marker. │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - this.map = map; │ │ │ │ + erase: function() { │ │ │ │ + if (this.icon != null) { │ │ │ │ + this.icon.erase(); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: checkModifiers │ │ │ │ - * Check the keyMask on the handler. If no is set, this always │ │ │ │ - * returns true. If a is set and it matches the combination │ │ │ │ - * of keys down on an event, this returns true. │ │ │ │ + * Method: moveTo │ │ │ │ + * Move the marker to the new location. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Parameters: │ │ │ │ + * px - {|Object} the pixel position to move to. │ │ │ │ + * An OpenLayers.Pixel or an object with a 'x' and 'y' properties. │ │ │ │ */ │ │ │ │ - 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]]); │ │ │ │ - } │ │ │ │ + moveTo: function(px) { │ │ │ │ + if ((px != null) && (this.icon != null)) { │ │ │ │ + this.icon.moveTo(px); │ │ │ │ } │ │ │ │ - this.active = true; │ │ │ │ - return true; │ │ │ │ + this.lonlat = this.map.getLonLatFromLayerPx(px); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Turn off the handler. Returns false if the handler was already inactive. │ │ │ │ + * APIMethod: isDrawn │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} The handler was deactivated. │ │ │ │ + * {Boolean} Whether or not the marker is drawn. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + isDrawn: function() { │ │ │ │ + var isDrawn = (this.icon && this.icon.isDrawn()); │ │ │ │ + return isDrawn; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: startTouch │ │ │ │ - * Start touch events, this method must be called by subclasses in │ │ │ │ - * "touchstart" method. When touch events are started will be │ │ │ │ - * true and all mouse related listeners will do nothing. │ │ │ │ + * Method: onScreen │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the marker is currently visible on screen. │ │ │ │ */ │ │ │ │ - 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]]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + onScreen: function() { │ │ │ │ + │ │ │ │ + var onScreen = false; │ │ │ │ + if (this.map) { │ │ │ │ + var screenBounds = this.map.getExtent(); │ │ │ │ + onScreen = screenBounds.containsLonLat(this.lonlat); │ │ │ │ } │ │ │ │ + return onScreen; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: callback │ │ │ │ - * Trigger the control's named callback with the given arguments │ │ │ │ + * Method: inflate │ │ │ │ + * Englarges the markers icon by the specified ratio. │ │ │ │ * │ │ │ │ * 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). │ │ │ │ + * inflate - {float} the ratio to enlarge the marker by (passing 2 │ │ │ │ + * will double the size). │ │ │ │ */ │ │ │ │ - callback: function(name, args) { │ │ │ │ - if (name && this.callbacks[name]) { │ │ │ │ - this.callbacks[name].apply(this.control, args); │ │ │ │ + inflate: function(inflate) { │ │ │ │ + if (this.icon) { │ │ │ │ + this.icon.setSize({ │ │ │ │ + w: this.icon.size.w * inflate, │ │ │ │ + h: this.icon.size.h * inflate │ │ │ │ + }); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 │ │ │ │ + /** │ │ │ │ + * Method: setOpacity │ │ │ │ + * Change the opacity of the marker by changin the opacity of │ │ │ │ + * its icon │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * opacity - {float} Specified as fraction (0.4, etc) │ │ │ │ */ │ │ │ │ - unregister: function(name, method) { │ │ │ │ - this.map.events.unregister(name, this, method); │ │ │ │ - this.map.events.unregister(name, this, this.setEvent); │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ + this.icon.setOpacity(opacity); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: setUrl │ │ │ │ + * Change URL of the Icon Image. │ │ │ │ + * │ │ │ │ + * url - {String} │ │ │ │ */ │ │ │ │ - setEvent: function(evt) { │ │ │ │ - this.evt = evt; │ │ │ │ - return true; │ │ │ │ + setUrl: function(url) { │ │ │ │ + this.icon.setUrl(url); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - * Deconstruct the handler. │ │ │ │ + /** │ │ │ │ + * Method: display │ │ │ │ + * Hide or show the icon │ │ │ │ + * │ │ │ │ + * display - {Boolean} │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - // unregister event listeners │ │ │ │ - this.deactivate(); │ │ │ │ - // eliminate circular references │ │ │ │ - this.control = this.map = null; │ │ │ │ + display: function(display) { │ │ │ │ + this.icon.display(display); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler" │ │ │ │ + CLASS_NAME: "OpenLayers.Marker" │ │ │ │ }); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Handler.MOD_NONE │ │ │ │ - * If set as the , returns false if any key is down. │ │ │ │ - */ │ │ │ │ -OpenLayers.Handler.MOD_NONE = 0; │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Handler.MOD_SHIFT │ │ │ │ - * If set as the , returns false if Shift is down. │ │ │ │ - */ │ │ │ │ -OpenLayers.Handler.MOD_SHIFT = 1; │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Handler.MOD_CTRL │ │ │ │ - * If set as the , returns false if Ctrl is down. │ │ │ │ - */ │ │ │ │ -OpenLayers.Handler.MOD_CTRL = 2; │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Handler.MOD_ALT │ │ │ │ - * If set as the , returns false if Alt is down. │ │ │ │ - */ │ │ │ │ -OpenLayers.Handler.MOD_ALT = 4; │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Handler.MOD_META │ │ │ │ - * If set as the , returns false if Cmd is down. │ │ │ │ + * Function: defaultIcon │ │ │ │ + * Creates a default . │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {} A default OpenLayers.Icon to use for a marker │ │ │ │ */ │ │ │ │ -OpenLayers.Handler.MOD_META = 8; │ │ │ │ +OpenLayers.Marker.defaultIcon = function() { │ │ │ │ + return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"), { │ │ │ │ + w: 21, │ │ │ │ + h: 25 │ │ │ │ + }, { │ │ │ │ + x: -10.5, │ │ │ │ + y: -25 │ │ │ │ + }); │ │ │ │ +}; │ │ │ │ │ │ │ │ │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Geometry.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ @@ -16780,642 +16464,14 @@ │ │ │ │ distance: Math.pow(x - x0, 2) + Math.pow(y - y0, 2), │ │ │ │ x: x, │ │ │ │ y: y, │ │ │ │ along: along │ │ │ │ }; │ │ │ │ }; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Icon.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.Icon │ │ │ │ - * │ │ │ │ - * The icon represents a graphical icon on the screen. Typically used in │ │ │ │ - * conjunction with a to represent markers on a screen. │ │ │ │ - * │ │ │ │ - * An icon has a url, size and position. It also contains an offset which │ │ │ │ - * allows the center point to be represented correctly. This can be │ │ │ │ - * provided either as a fixed offset or a function provided to calculate │ │ │ │ - * the desired offset. │ │ │ │ - * │ │ │ │ - */ │ │ │ │ -OpenLayers.Icon = OpenLayers.Class({ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: url │ │ │ │ - * {String} image url │ │ │ │ - */ │ │ │ │ - url: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: size │ │ │ │ - * {|Object} An OpenLayers.Size or │ │ │ │ - * an object with a 'w' and 'h' properties. │ │ │ │ - */ │ │ │ │ - size: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: offset │ │ │ │ - * {|Object} distance in pixels to offset the │ │ │ │ - * image when being rendered. An OpenLayers.Pixel or an object │ │ │ │ - * with a 'x' and 'y' properties. │ │ │ │ - */ │ │ │ │ - offset: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: calculateOffset │ │ │ │ - * {Function} Function to calculate the offset (based on the size) │ │ │ │ - */ │ │ │ │ - calculateOffset: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: imageDiv │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - imageDiv: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: px │ │ │ │ - * {|Object} An OpenLayers.Pixel or an object │ │ │ │ - * with a 'x' and 'y' properties. │ │ │ │ - */ │ │ │ │ - px: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Icon │ │ │ │ - * Creates an icon, which is an image tag in a div. │ │ │ │ - * │ │ │ │ - * url - {String} │ │ │ │ - * size - {|Object} An OpenLayers.Size or an │ │ │ │ - * object with a 'w' and 'h' │ │ │ │ - * properties. │ │ │ │ - * offset - {|Object} An OpenLayers.Pixel or an │ │ │ │ - * object with a 'x' and 'y' │ │ │ │ - * properties. │ │ │ │ - * calculateOffset - {Function} │ │ │ │ - */ │ │ │ │ - initialize: function(url, size, offset, calculateOffset) { │ │ │ │ - this.url = url; │ │ │ │ - this.size = size || { │ │ │ │ - w: 20, │ │ │ │ - h: 20 │ │ │ │ - }; │ │ │ │ - this.offset = offset || { │ │ │ │ - x: -(this.size.w / 2), │ │ │ │ - y: -(this.size.h / 2) │ │ │ │ - }; │ │ │ │ - this.calculateOffset = calculateOffset; │ │ │ │ - │ │ │ │ - var id = OpenLayers.Util.createUniqueID("OL_Icon_"); │ │ │ │ - this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - * Nullify references and remove event listeners to prevent circular │ │ │ │ - * references and memory leaks │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - // erase any drawn elements │ │ │ │ - this.erase(); │ │ │ │ - │ │ │ │ - OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild); │ │ │ │ - this.imageDiv.innerHTML = ""; │ │ │ │ - this.imageDiv = null; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: clone │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {} A fresh copy of the icon. │ │ │ │ - */ │ │ │ │ - clone: function() { │ │ │ │ - return new OpenLayers.Icon(this.url, │ │ │ │ - this.size, │ │ │ │ - this.offset, │ │ │ │ - this.calculateOffset); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setSize │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * size - {|Object} An OpenLayers.Size or │ │ │ │ - * an object with a 'w' and 'h' properties. │ │ │ │ - */ │ │ │ │ - setSize: function(size) { │ │ │ │ - if (size != null) { │ │ │ │ - this.size = size; │ │ │ │ - } │ │ │ │ - this.draw(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setUrl │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * url - {String} │ │ │ │ - */ │ │ │ │ - setUrl: function(url) { │ │ │ │ - if (url != null) { │ │ │ │ - this.url = url; │ │ │ │ - } │ │ │ │ - this.draw(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * Move the div to the given pixel. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * px - {|Object} An OpenLayers.Pixel or an │ │ │ │ - * object with a 'x' and 'y' properties. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A new DOM Image of this icon set at the location passed-in │ │ │ │ - */ │ │ │ │ - draw: function(px) { │ │ │ │ - OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, │ │ │ │ - null, │ │ │ │ - null, │ │ │ │ - this.size, │ │ │ │ - this.url, │ │ │ │ - "absolute"); │ │ │ │ - this.moveTo(px); │ │ │ │ - return this.imageDiv; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: erase │ │ │ │ - * Erase the underlying image element. │ │ │ │ - */ │ │ │ │ - erase: function() { │ │ │ │ - if (this.imageDiv != null && this.imageDiv.parentNode != null) { │ │ │ │ - OpenLayers.Element.remove(this.imageDiv); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setOpacity │ │ │ │ - * Change the icon's opacity │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * opacity - {float} │ │ │ │ - */ │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ - OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, │ │ │ │ - null, null, null, null, opacity); │ │ │ │ - │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: moveTo │ │ │ │ - * move icon to passed in px. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * px - {|Object} the pixel position to move to. │ │ │ │ - * An OpenLayers.Pixel or an object with a 'x' and 'y' properties. │ │ │ │ - */ │ │ │ │ - moveTo: function(px) { │ │ │ │ - //if no px passed in, use stored location │ │ │ │ - if (px != null) { │ │ │ │ - this.px = px; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.imageDiv != null) { │ │ │ │ - if (this.px == null) { │ │ │ │ - this.display(false); │ │ │ │ - } else { │ │ │ │ - if (this.calculateOffset) { │ │ │ │ - this.offset = this.calculateOffset(this.size); │ │ │ │ - } │ │ │ │ - OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, { │ │ │ │ - x: this.px.x + this.offset.x, │ │ │ │ - y: this.px.y + this.offset.y │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: display │ │ │ │ - * Hide or show the icon │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * display - {Boolean} │ │ │ │ - */ │ │ │ │ - display: function(display) { │ │ │ │ - this.imageDiv.style.display = (display) ? "" : "none"; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: isDrawn │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the icon is drawn. │ │ │ │ - */ │ │ │ │ - isDrawn: function() { │ │ │ │ - // nodeType 11 for ie, whose nodes *always* have a parentNode │ │ │ │ - // (of type document fragment) │ │ │ │ - var isDrawn = (this.imageDiv && this.imageDiv.parentNode && │ │ │ │ - (this.imageDiv.parentNode.nodeType != 11)); │ │ │ │ - │ │ │ │ - return isDrawn; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Icon" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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 │ │ │ │ - * {} 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 │ │ │ │ - * . │ │ │ │ - */ │ │ │ │ - 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 and │ │ │ │ - * to change control state. │ │ │ │ - */ │ │ │ │ - active: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: handlerOptions │ │ │ │ - * {Object} Used to set non-default properties on the control's handler │ │ │ │ - */ │ │ │ │ - handlerOptions: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: handler │ │ │ │ - * {} null │ │ │ │ - */ │ │ │ │ - handler: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: eventListeners │ │ │ │ - * {Object} If set as an option at construction, the eventListeners │ │ │ │ - * object will be registered with . Object │ │ │ │ - * structure must be a listeners object as shown in the example for │ │ │ │ - * the events.on method. │ │ │ │ - */ │ │ │ │ - eventListeners: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: 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 - {} │ │ │ │ - */ │ │ │ │ - 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 - {} 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 - {} │ │ │ │ - */ │ │ │ │ - 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/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. */ │ │ │ │ @@ -23776,104 +22832,14 @@ │ │ │ │ * Constant: OpenLayers.Format.WFST.DEFAULTS │ │ │ │ * {Object} Default properties for the WFST format. │ │ │ │ */ │ │ │ │ OpenLayers.Format.WFST.DEFAULTS = { │ │ │ │ "version": "1.0.0" │ │ │ │ }; │ │ │ │ /* ====================================================================== │ │ │ │ - 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: │ │ │ │ - * {} │ │ │ │ - */ │ │ │ │ - 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: │ │ │ │ - * {} Clone of this filter. │ │ │ │ - */ │ │ │ │ - clone: function() { │ │ │ │ - return null; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: toString │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} Include 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/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. */ │ │ │ │ @@ -30102,2264 +29068,137 @@ │ │ │ │ OpenLayers.Util.extend(this, options); │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.WPSProcess.ChainLink" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Spherical.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: Spherical │ │ │ │ - * The OpenLayers.Spherical namespace includes utility functions for │ │ │ │ - * calculations on the basis of a spherical earth (ignoring ellipsoidal │ │ │ │ - * effects), which is accurate enough for most purposes. │ │ │ │ - * │ │ │ │ - * Relevant links: │ │ │ │ - * * http://www.movable-type.co.uk/scripts/latlong.html │ │ │ │ - * * http://code.google.com/apis/maps/documentation/javascript/reference.html#spherical │ │ │ │ - */ │ │ │ │ - │ │ │ │ -OpenLayers.Spherical = OpenLayers.Spherical || {}; │ │ │ │ - │ │ │ │ -OpenLayers.Spherical.DEFAULT_RADIUS = 6378137; │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * APIFunction: computeDistanceBetween │ │ │ │ - * Computes the distance between two LonLats. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * from - {} or {Object} Starting point. A LonLat or │ │ │ │ - * a JavaScript literal with lon lat properties. │ │ │ │ - * to - {} or {Object} Ending point. A LonLat or a │ │ │ │ - * JavaScript literal with lon lat properties. │ │ │ │ - * radius - {Float} The radius. Optional. Defaults to 6378137 meters. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Float} The distance in meters. │ │ │ │ - */ │ │ │ │ -OpenLayers.Spherical.computeDistanceBetween = function(from, to, radius) { │ │ │ │ - var R = radius || OpenLayers.Spherical.DEFAULT_RADIUS; │ │ │ │ - var sinHalfDeltaLon = Math.sin(Math.PI * (to.lon - from.lon) / 360); │ │ │ │ - var sinHalfDeltaLat = Math.sin(Math.PI * (to.lat - from.lat) / 360); │ │ │ │ - var a = sinHalfDeltaLat * sinHalfDeltaLat + │ │ │ │ - sinHalfDeltaLon * sinHalfDeltaLon * Math.cos(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ - return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); │ │ │ │ -}; │ │ │ │ - │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * APIFunction: computeHeading │ │ │ │ - * Computes the heading from one LonLat to another LonLat. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * from - {} or {Object} Starting point. A LonLat or │ │ │ │ - * a JavaScript literal with lon lat properties. │ │ │ │ - * to - {} or {Object} Ending point. A LonLat or a │ │ │ │ - * JavaScript literal with lon lat properties. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Float} The heading in degrees. │ │ │ │ - */ │ │ │ │ -OpenLayers.Spherical.computeHeading = function(from, to) { │ │ │ │ - var y = Math.sin(Math.PI * (from.lon - to.lon) / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ - var x = Math.cos(Math.PI * from.lat / 180) * Math.sin(Math.PI * to.lat / 180) - │ │ │ │ - Math.sin(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180) * Math.cos(Math.PI * (from.lon - to.lon) / 180); │ │ │ │ - return 180 * Math.atan2(y, x) / Math.PI; │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Protocol.js │ │ │ │ + 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.Protocol │ │ │ │ - * Abstract vector layer protocol class. Not to be instantiated directly. Use │ │ │ │ - * one of the protocol subclasses instead. │ │ │ │ + * Class: OpenLayers.Strategy │ │ │ │ + * Abstract vector layer strategy class. Not to be instantiated directly. Use │ │ │ │ + * one of the strategy subclasses instead. │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol = OpenLayers.Class({ │ │ │ │ +OpenLayers.Strategy = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: format │ │ │ │ - * {} The format used by this protocol. │ │ │ │ + * Property: layer │ │ │ │ + * {} The layer this strategy belongs to. │ │ │ │ */ │ │ │ │ - format: null, │ │ │ │ + layer: 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 │ │ │ │ - * {} 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 - {} │ │ │ │ - */ │ │ │ │ - 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: │ │ │ │ - * {} An │ │ │ │ - * 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({})} or │ │ │ │ - * {} │ │ │ │ - * options - {Object} Optional object for configuring the request. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {} An │ │ │ │ - * 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({})} or │ │ │ │ - * {} │ │ │ │ - * options - {Object} Optional object for configuring the request. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {} An │ │ │ │ - * 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 - {} │ │ │ │ - * options - {Object} Optional object for configuring the request. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {} An │ │ │ │ - * 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({})} │ │ │ │ - * 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({})} An array of │ │ │ │ - * objects. │ │ │ │ - */ │ │ │ │ - commit: function() {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: abort │ │ │ │ - * Abort an ongoing request. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * 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 - {} 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({})} or {} │ │ │ │ - * 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({})} or {} │ │ │ │ - * The features provided by the user and placed in the request by the │ │ │ │ - * protocol. │ │ │ │ + /** │ │ │ │ + * Property: active │ │ │ │ + * {Boolean} The control is active. │ │ │ │ */ │ │ │ │ - reqFeatures: null, │ │ │ │ + active: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: priv │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - priv: null, │ │ │ │ + autoActivate: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: error │ │ │ │ - * {Object} The error object in case a service exception was encountered. │ │ │ │ + * Property: autoDestroy │ │ │ │ + * {Boolean} The creator of the strategy can set autoDestroy to false │ │ │ │ + * to fully control when the strategy is destroyed. Defaults to │ │ │ │ + * true. │ │ │ │ */ │ │ │ │ - error: null, │ │ │ │ + autoDestroy: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Protocol.Response │ │ │ │ + * 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); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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/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 │ │ │ │ - * {} │ │ │ │ - */ │ │ │ │ - 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 │ │ │ │ - * {} │ │ │ │ - */ │ │ │ │ - size: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: resolution │ │ │ │ - * {Float} cache of current map resolution │ │ │ │ - */ │ │ │ │ - resolution: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: 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 │ │ │ │ - * ). │ │ │ │ - */ │ │ │ │ - featureDx: 0, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Renderer │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * containerID - {} │ │ │ │ - * 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 - {} │ │ │ │ - * 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 - {} │ │ │ │ - */ │ │ │ │ - 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 - {} │ │ │ │ - * style - {} │ │ │ │ - * │ │ │ │ - * 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 - {} Bounds of the feature │ │ │ │ - * worldBounds - {} 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 - {} │ │ │ │ - * style - {Object} │ │ │ │ - * featureId - {} │ │ │ │ - */ │ │ │ │ - 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 - {} │ │ │ │ - */ │ │ │ │ - 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 - {} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A feature id or undefined. │ │ │ │ - */ │ │ │ │ - getFeatureIdFromEvent: function(evt) {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: eraseFeatures │ │ │ │ - * This is called by the layer to erase features │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * features - {Array()} │ │ │ │ - */ │ │ │ │ - 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 - {} │ │ │ │ - * 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 - {} 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/Symbolizer.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.Symbolizer │ │ │ │ - * Base class representing a symbolizer used for feature rendering. │ │ │ │ - */ │ │ │ │ -OpenLayers.Symbolizer = OpenLayers.Class({ │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: zIndex │ │ │ │ - * {Number} The zIndex determines the rendering order for a symbolizer. │ │ │ │ - * Symbolizers with larger zIndex values are rendered over symbolizers │ │ │ │ - * with smaller zIndex values. Default is 0. │ │ │ │ - */ │ │ │ │ - zIndex: 0, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Symbolizer │ │ │ │ - * Instances of this class are not useful. See one of the subclasses. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ - * construction. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * A new symbolizer. │ │ │ │ - */ │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Util.extend(this, config); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Create a copy of this symbolizer. │ │ │ │ - * │ │ │ │ - * Returns a symbolizer of the same type with the same properties. │ │ │ │ - */ │ │ │ │ - clone: function() { │ │ │ │ - var Type = eval(this.CLASS_NAME); │ │ │ │ - return new Type(OpenLayers.Util.extend({}, this)); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer" │ │ │ │ - │ │ │ │ -}); │ │ │ │ - │ │ │ │ -/* ====================================================================== │ │ │ │ - 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 {}, 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 - {} 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/Marker.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 │ │ │ │ - * @requires OpenLayers/Icon.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Marker │ │ │ │ - * Instances of OpenLayers.Marker are a combination of a │ │ │ │ - * and an . │ │ │ │ - * │ │ │ │ - * Markers are generally added to a special layer called │ │ │ │ - * . │ │ │ │ - * │ │ │ │ - * Example: │ │ │ │ - * (code) │ │ │ │ - * var markers = new OpenLayers.Layer.Markers( "Markers" ); │ │ │ │ - * map.addLayer(markers); │ │ │ │ - * │ │ │ │ - * var size = new OpenLayers.Size(21,25); │ │ │ │ - * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h); │ │ │ │ - * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset); │ │ │ │ - * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon)); │ │ │ │ - * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone())); │ │ │ │ - * │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * Note that if you pass an icon into the Marker constructor, it will take │ │ │ │ - * that icon and use it. This means that you should not share icons between │ │ │ │ - * markers -- you use them once, but you should clone() for any additional │ │ │ │ - * markers using that same icon. │ │ │ │ - */ │ │ │ │ -OpenLayers.Marker = OpenLayers.Class({ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: icon │ │ │ │ - * {} The icon used by this marker. │ │ │ │ - */ │ │ │ │ - icon: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: lonlat │ │ │ │ - * {} location of object │ │ │ │ - */ │ │ │ │ - lonlat: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: events │ │ │ │ - * {} the event handler. │ │ │ │ - */ │ │ │ │ - events: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: map │ │ │ │ - * {} the map this marker is attached to │ │ │ │ - */ │ │ │ │ - map: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Marker │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * lonlat - {} the position of this marker │ │ │ │ - * icon - {} the icon for this marker │ │ │ │ - */ │ │ │ │ - initialize: function(lonlat, icon) { │ │ │ │ - this.lonlat = lonlat; │ │ │ │ - │ │ │ │ - var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon(); │ │ │ │ - if (this.icon == null) { │ │ │ │ - this.icon = newIcon; │ │ │ │ - } else { │ │ │ │ - this.icon.url = newIcon.url; │ │ │ │ - this.icon.size = newIcon.size; │ │ │ │ - this.icon.offset = newIcon.offset; │ │ │ │ - this.icon.calculateOffset = newIcon.calculateOffset; │ │ │ │ - } │ │ │ │ - this.events = new OpenLayers.Events(this, this.icon.imageDiv); │ │ │ │ + this.options = options; │ │ │ │ + // set the active property here, so that user cannot override it │ │ │ │ + this.active = false; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: destroy │ │ │ │ - * Destroy the marker. You must first remove the marker from any │ │ │ │ - * layer which it has been added to, or you will get buggy behavior. │ │ │ │ - * (This can not be done within the marker since the marker does not │ │ │ │ - * know which layer it is attached to.) │ │ │ │ + * Clean up the strategy. │ │ │ │ */ │ │ │ │ destroy: function() { │ │ │ │ - // erase any drawn features │ │ │ │ - this.erase(); │ │ │ │ - │ │ │ │ - this.map = null; │ │ │ │ - │ │ │ │ - this.events.destroy(); │ │ │ │ - this.events = null; │ │ │ │ - │ │ │ │ - if (this.icon != null) { │ │ │ │ - this.icon.destroy(); │ │ │ │ - this.icon = null; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * Calls draw on the icon, and returns that output. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * px - {} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A new DOM Image with this marker's icon set at the │ │ │ │ - * location passed-in │ │ │ │ - */ │ │ │ │ - draw: function(px) { │ │ │ │ - return this.icon.draw(px); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: erase │ │ │ │ - * Erases any drawn elements for this marker. │ │ │ │ - */ │ │ │ │ - erase: function() { │ │ │ │ - if (this.icon != null) { │ │ │ │ - this.icon.erase(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: moveTo │ │ │ │ - * Move the marker to the new location. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * px - {|Object} the pixel position to move to. │ │ │ │ - * An OpenLayers.Pixel or an object with a 'x' and 'y' properties. │ │ │ │ - */ │ │ │ │ - moveTo: function(px) { │ │ │ │ - if ((px != null) && (this.icon != null)) { │ │ │ │ - this.icon.moveTo(px); │ │ │ │ - } │ │ │ │ - this.lonlat = this.map.getLonLatFromLayerPx(px); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: isDrawn │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the marker is drawn. │ │ │ │ - */ │ │ │ │ - isDrawn: function() { │ │ │ │ - var isDrawn = (this.icon && this.icon.isDrawn()); │ │ │ │ - return isDrawn; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: onScreen │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the marker is currently visible on screen. │ │ │ │ - */ │ │ │ │ - onScreen: function() { │ │ │ │ - │ │ │ │ - var onScreen = false; │ │ │ │ - if (this.map) { │ │ │ │ - var screenBounds = this.map.getExtent(); │ │ │ │ - onScreen = screenBounds.containsLonLat(this.lonlat); │ │ │ │ - } │ │ │ │ - return onScreen; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: inflate │ │ │ │ - * Englarges the markers icon by the specified ratio. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * inflate - {float} the ratio to enlarge the marker by (passing 2 │ │ │ │ - * will double the size). │ │ │ │ - */ │ │ │ │ - inflate: function(inflate) { │ │ │ │ - if (this.icon) { │ │ │ │ - this.icon.setSize({ │ │ │ │ - w: this.icon.size.w * inflate, │ │ │ │ - h: this.icon.size.h * inflate │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setOpacity │ │ │ │ - * Change the opacity of the marker by changin the opacity of │ │ │ │ - * its icon │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * opacity - {float} Specified as fraction (0.4, etc) │ │ │ │ - */ │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ - this.icon.setOpacity(opacity); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setUrl │ │ │ │ - * Change URL of the Icon Image. │ │ │ │ - * │ │ │ │ - * url - {String} │ │ │ │ - */ │ │ │ │ - setUrl: function(url) { │ │ │ │ - this.icon.setUrl(url); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: display │ │ │ │ - * Hide or show the icon │ │ │ │ - * │ │ │ │ - * display - {Boolean} │ │ │ │ - */ │ │ │ │ - display: function(display) { │ │ │ │ - this.icon.display(display); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Marker" │ │ │ │ -}); │ │ │ │ - │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Function: defaultIcon │ │ │ │ - * Creates a default . │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {} A default OpenLayers.Icon to use for a marker │ │ │ │ - */ │ │ │ │ -OpenLayers.Marker.defaultIcon = function() { │ │ │ │ - return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"), { │ │ │ │ - w: 21, │ │ │ │ - h: 25 │ │ │ │ - }, { │ │ │ │ - x: -10.5, │ │ │ │ - y: -25 │ │ │ │ - }); │ │ │ │ -}; │ │ │ │ - │ │ │ │ - │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Symbolizer/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/Symbolizer.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Symbolizer.Point │ │ │ │ - * A symbolizer used to render point features. │ │ │ │ - */ │ │ │ │ -OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeColor │ │ │ │ - * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ - * for red). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeOpacity │ │ │ │ - * {Number} Stroke opacity (0-1). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeWidth │ │ │ │ - * {Number} Pixel stroke width. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeLinecap │ │ │ │ - * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: strokeDashstyle │ │ │ │ - * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ - * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ - * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ - * most SLD patterns will render correctly in OpenLayers. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: fillColor │ │ │ │ - * {String} RGB hex fill color (e.g. "#ff0000" for red). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: fillOpacity │ │ │ │ - * {Number} Fill opacity (0-1). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: pointRadius │ │ │ │ - * {Number} Pixel point radius. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: externalGraphic │ │ │ │ - * {String} Url to an external graphic that will be used for rendering │ │ │ │ - * points. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: graphicWidth │ │ │ │ - * {Number} Pixel width for sizing an external graphic. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: graphicHeight │ │ │ │ - * {Number} Pixel height for sizing an external graphic. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: graphicOpacity │ │ │ │ - * {Number} Opacity (0-1) for an external graphic. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: graphicXOffset │ │ │ │ - * {Number} Pixel offset along the positive x axis for displacing an │ │ │ │ - * external graphic. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: graphicYOffset │ │ │ │ - * {Number} Pixel offset along the positive y axis for displacing an │ │ │ │ - * external graphic. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: rotation │ │ │ │ - * {Number} The rotation of a graphic in the clockwise direction about its │ │ │ │ - * center point (or any point off center as specified by │ │ │ │ - * and ). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: graphicName │ │ │ │ - * {String} Named graphic to use when rendering points. Supported values │ │ │ │ - * include "circle", "square", "star", "x", "cross", and "triangle". │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Symbolizer.Point │ │ │ │ - * Create a symbolizer for rendering points. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ - * construction. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * A new point symbolizer. │ │ │ │ - */ │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Point" │ │ │ │ - │ │ │ │ -}); │ │ │ │ - │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Symbolizer/Line.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/Symbolizer.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Symbolizer.Line │ │ │ │ - * A symbolizer used to render line features. │ │ │ │ - */ │ │ │ │ -OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeColor │ │ │ │ - * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ - * for red). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeOpacity │ │ │ │ - * {Number} Stroke opacity (0-1). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeWidth │ │ │ │ - * {Number} Pixel stroke width. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeLinecap │ │ │ │ - * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: strokeDashstyle │ │ │ │ - * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ - * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ - * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ - * most SLD patterns will render correctly in OpenLayers. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Symbolizer.Line │ │ │ │ - * Create a symbolizer for rendering lines. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ - * construction. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * A new line symbolizer. │ │ │ │ - */ │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Line" │ │ │ │ - │ │ │ │ -}); │ │ │ │ - │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Symbolizer/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/Symbolizer.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Symbolizer.Polygon │ │ │ │ - * A symbolizer used to render line features. │ │ │ │ - */ │ │ │ │ -OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeColor │ │ │ │ - * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ - * for red). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeOpacity │ │ │ │ - * {Number} Stroke opacity (0-1). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeWidth │ │ │ │ - * {Number} Pixel stroke width. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeLinecap │ │ │ │ - * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: strokeDashstyle │ │ │ │ - * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ - * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ - * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ - * most SLD patterns will render correctly in OpenLayers. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: fillColor │ │ │ │ - * {String} RGB hex fill color (e.g. "#ff0000" for red). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: fillOpacity │ │ │ │ - * {Number} Fill opacity (0-1). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Symbolizer.Polygon │ │ │ │ - * Create a symbolizer for rendering polygons. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ - * construction. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * A new polygon symbolizer. │ │ │ │ - */ │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Polygon" │ │ │ │ - │ │ │ │ -}); │ │ │ │ - │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Symbolizer/Text.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/Symbolizer.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Symbolizer.Text │ │ │ │ - * A symbolizer used to render text labels for features. │ │ │ │ - */ │ │ │ │ -OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: label │ │ │ │ - * {String} The text for the label. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: fontFamily │ │ │ │ - * {String} The font family for the label. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: fontSize │ │ │ │ - * {String} The font size for the label. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: fontWeight │ │ │ │ - * {String} The font weight for the label. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: fontStyle │ │ │ │ - * {String} The font style for the label. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Symbolizer.Text │ │ │ │ - * Create a symbolizer for rendering text labels. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ - * construction. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * A new text symbolizer. │ │ │ │ - */ │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ + this.deactivate(); │ │ │ │ + this.layer = null; │ │ │ │ + this.options = null; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Text" │ │ │ │ - │ │ │ │ -}); │ │ │ │ - │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Symbolizer/Raster.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/Symbolizer.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Symbolizer.Raster │ │ │ │ - * A symbolizer used to render raster images. │ │ │ │ - */ │ │ │ │ -OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Symbolizer.Raster │ │ │ │ - * Create a symbolizer for rendering rasters. │ │ │ │ + * Method: setLayer │ │ │ │ + * Called to set the property. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ - * construction. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * A new raster symbolizer. │ │ │ │ + * layer - {} │ │ │ │ */ │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ + setLayer: function(layer) { │ │ │ │ + this.layer = layer; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Raster" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Style2.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/Rule.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Point.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Line.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Polygon.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Text.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Raster.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Style2 │ │ │ │ - * This class represents a collection of rules for rendering features. │ │ │ │ - */ │ │ │ │ -OpenLayers.Style2 = OpenLayers.Class({ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: id │ │ │ │ - * {String} A unique id for this session. │ │ │ │ - */ │ │ │ │ - id: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: name │ │ │ │ - * {String} Style identifier. │ │ │ │ - */ │ │ │ │ - name: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: title │ │ │ │ - * {String} Title of this style. │ │ │ │ - */ │ │ │ │ - title: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: description │ │ │ │ - * {String} Description of this style. │ │ │ │ - */ │ │ │ │ - description: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: layerName │ │ │ │ - * {} 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, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: rules │ │ │ │ - * {Array()} Collection of rendering rules. │ │ │ │ - */ │ │ │ │ - rules: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Style2 │ │ │ │ - * Creates a style representing a collection of rendering rules. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ - * style. Any documented properties may be set at construction. │ │ │ │ + * Method: activate │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {} A new style object. │ │ │ │ - */ │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Util.extend(this, config); │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ - delete this.rules; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Clones this style. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {} Clone of this style. │ │ │ │ - */ │ │ │ │ - clone: function() { │ │ │ │ - var config = OpenLayers.Util.extend({}, this); │ │ │ │ - // clone rules │ │ │ │ - if (this.rules) { │ │ │ │ - config.rules = []; │ │ │ │ - for (var i = 0, len = this.rules.length; i < len; ++i) { │ │ │ │ - config.rules.push(this.rules[i].clone()); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return new OpenLayers.Style2(config); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Style2" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WPSDescribeProcess.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/OWSCommon/v1_1_0.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WPSDescribeProcess │ │ │ │ - * Read WPS DescribeProcess responses. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WPSDescribeProcess = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constant: VERSION │ │ │ │ - * {String} 1.0.0 │ │ │ │ - */ │ │ │ │ - VERSION: "1.0.0", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - wps: "http://www.opengis.net/wps/1.0.0", │ │ │ │ - ows: "http://www.opengis.net/ows/1.1", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} Schema location │ │ │ │ - */ │ │ │ │ - schemaLocation: "http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ - */ │ │ │ │ - defaultPrefix: "wps", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ - */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WPSDescribeProcess │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Parse a WPS DescribeProcess and return an object with its information. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} │ │ │ │ - */ │ │ │ │ - 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 info = {}; │ │ │ │ - this.readNode(data, info); │ │ │ │ - return info; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "wps": { │ │ │ │ - "ProcessDescriptions": function(node, obj) { │ │ │ │ - obj.processDescriptions = {}; │ │ │ │ - this.readChildNodes(node, obj.processDescriptions); │ │ │ │ - }, │ │ │ │ - "ProcessDescription": function(node, processDescriptions) { │ │ │ │ - var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); │ │ │ │ - var processDescription = { │ │ │ │ - processVersion: processVersion, │ │ │ │ - statusSupported: (node.getAttribute("statusSupported") === "true"), │ │ │ │ - storeSupported: (node.getAttribute("storeSupported") === "true") │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, processDescription); │ │ │ │ - processDescriptions[processDescription.identifier] = processDescription; │ │ │ │ - }, │ │ │ │ - "DataInputs": function(node, processDescription) { │ │ │ │ - processDescription.dataInputs = []; │ │ │ │ - this.readChildNodes(node, processDescription.dataInputs); │ │ │ │ - }, │ │ │ │ - "ProcessOutputs": function(node, processDescription) { │ │ │ │ - processDescription.processOutputs = []; │ │ │ │ - this.readChildNodes(node, processDescription.processOutputs); │ │ │ │ - }, │ │ │ │ - "Output": function(node, processOutputs) { │ │ │ │ - var output = {}; │ │ │ │ - this.readChildNodes(node, output); │ │ │ │ - processOutputs.push(output); │ │ │ │ - }, │ │ │ │ - "ComplexOutput": function(node, output) { │ │ │ │ - output.complexOutput = {}; │ │ │ │ - this.readChildNodes(node, output.complexOutput); │ │ │ │ - }, │ │ │ │ - "LiteralOutput": function(node, output) { │ │ │ │ - output.literalOutput = {}; │ │ │ │ - this.readChildNodes(node, output.literalOutput); │ │ │ │ - }, │ │ │ │ - "Input": function(node, dataInputs) { │ │ │ │ - var input = { │ │ │ │ - maxOccurs: parseInt(node.getAttribute("maxOccurs")), │ │ │ │ - minOccurs: parseInt(node.getAttribute("minOccurs")) │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, input); │ │ │ │ - dataInputs.push(input); │ │ │ │ - }, │ │ │ │ - "BoundingBoxData": function(node, input) { │ │ │ │ - input.boundingBoxData = {}; │ │ │ │ - this.readChildNodes(node, input.boundingBoxData); │ │ │ │ - }, │ │ │ │ - "CRS": function(node, obj) { │ │ │ │ - if (!obj.CRSs) { │ │ │ │ - obj.CRSs = {}; │ │ │ │ - } │ │ │ │ - obj.CRSs[this.getChildValue(node)] = true; │ │ │ │ - }, │ │ │ │ - "LiteralData": function(node, input) { │ │ │ │ - input.literalData = {}; │ │ │ │ - this.readChildNodes(node, input.literalData); │ │ │ │ - }, │ │ │ │ - "ComplexData": function(node, input) { │ │ │ │ - input.complexData = {}; │ │ │ │ - this.readChildNodes(node, input.complexData); │ │ │ │ - }, │ │ │ │ - "Default": function(node, complexData) { │ │ │ │ - complexData["default"] = {}; │ │ │ │ - this.readChildNodes(node, complexData["default"]); │ │ │ │ - }, │ │ │ │ - "Supported": function(node, complexData) { │ │ │ │ - complexData["supported"] = {}; │ │ │ │ - this.readChildNodes(node, complexData["supported"]); │ │ │ │ - }, │ │ │ │ - "Format": function(node, obj) { │ │ │ │ - var format = {}; │ │ │ │ - this.readChildNodes(node, format); │ │ │ │ - if (!obj.formats) { │ │ │ │ - obj.formats = {}; │ │ │ │ - } │ │ │ │ - obj.formats[format.mimeType] = true; │ │ │ │ - }, │ │ │ │ - "MimeType": function(node, format) { │ │ │ │ - format.mimeType = this.getChildValue(node); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WPSDescribeProcess" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/WPSClient.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/Events.js │ │ │ │ - * @requires OpenLayers/WPSProcess.js │ │ │ │ - * @requires OpenLayers/Format/WPSDescribeProcess.js │ │ │ │ - * @requires OpenLayers/Request.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.WPSClient │ │ │ │ - * High level API for interaction with Web Processing Services (WPS). │ │ │ │ - * An instance is used to create │ │ │ │ - * instances for servers known to the WPSClient. The WPSClient also caches │ │ │ │ - * DescribeProcess responses to reduce the number of requests sent to servers │ │ │ │ - * when processes are created. │ │ │ │ - */ │ │ │ │ -OpenLayers.WPSClient = OpenLayers.Class({ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: servers │ │ │ │ - * {Object} Service metadata, keyed by a local identifier. │ │ │ │ - * │ │ │ │ - * Properties: │ │ │ │ - * url - {String} the url of the server │ │ │ │ - * version - {String} WPS version of the server │ │ │ │ - * processDescription - {Object} Cache of raw DescribeProcess │ │ │ │ - * responses, keyed by process identifier. │ │ │ │ - */ │ │ │ │ - servers: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} The default WPS version to use if none is configured. Default │ │ │ │ - * is '1.0.0'. │ │ │ │ - */ │ │ │ │ - version: '1.0.0', │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: lazy │ │ │ │ - * {Boolean} Should the DescribeProcess be deferred until a process is │ │ │ │ - * fully configured? Default is false. │ │ │ │ - */ │ │ │ │ - lazy: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: events │ │ │ │ - * {} │ │ │ │ - * │ │ │ │ - * Supported event types: │ │ │ │ - * describeprocess - Fires when the process description is available. │ │ │ │ - * Listeners receive an object with a 'raw' property holding the raw │ │ │ │ - * DescribeProcess response, and an 'identifier' property holding the │ │ │ │ - * process identifier of the described process. │ │ │ │ - */ │ │ │ │ - events: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.WPSClient │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Object whose properties will be set on the instance. │ │ │ │ - * │ │ │ │ - * Avaliable options: │ │ │ │ - * servers - {Object} Mandatory. Service metadata, keyed by a local │ │ │ │ - * identifier. Can either be a string with the service url or an │ │ │ │ - * object literal with additional metadata: │ │ │ │ - * │ │ │ │ - * (code) │ │ │ │ - * servers: { │ │ │ │ - * local: '/geoserver/wps' │ │ │ │ - * }, { │ │ │ │ - * opengeo: { │ │ │ │ - * url: 'http://demo.opengeo.org/geoserver/wps', │ │ │ │ - * version: '1.0.0' │ │ │ │ - * } │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * lazy - {Boolean} Optional. Set to true if DescribeProcess should not be │ │ │ │ - * requested until a process is fully configured. Default is false. │ │ │ │ + * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ + * the strategy was already active. │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - this.events = new OpenLayers.Events(this); │ │ │ │ - this.servers = {}; │ │ │ │ - for (var s in options.servers) { │ │ │ │ - this.servers[s] = typeof options.servers[s] == 'string' ? { │ │ │ │ - url: options.servers[s], │ │ │ │ - version: this.version, │ │ │ │ - processDescription: {} │ │ │ │ - } : options.servers[s]; │ │ │ │ + activate: function() { │ │ │ │ + if (!this.active) { │ │ │ │ + this.active = true; │ │ │ │ + return true; │ │ │ │ } │ │ │ │ + return false; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: execute │ │ │ │ - * Shortcut to execute a process with a single function call. This is │ │ │ │ - * equivalent to using and then calling execute on the │ │ │ │ - * process. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Options for the execute operation. │ │ │ │ - * │ │ │ │ - * Available options: │ │ │ │ - * server - {String} Mandatory. One of the local identifiers of the │ │ │ │ - * configured servers. │ │ │ │ - * process - {String} Mandatory. A process identifier known to the │ │ │ │ - * server. │ │ │ │ - * inputs - {Object} The inputs for the process, keyed by input identifier. │ │ │ │ - * For spatial data inputs, the value of an input is usually an │ │ │ │ - * , an or an array of │ │ │ │ - * geometries or features. │ │ │ │ - * output - {String} The identifier of an output to parse. Optional. If not │ │ │ │ - * provided, the first output will be parsed. │ │ │ │ - * success - {Function} Callback to call when the process is complete. │ │ │ │ - * This function is called with an outputs object as argument, which │ │ │ │ - * will have a property with the identifier of the requested output │ │ │ │ - * (e.g. 'result'). For processes that generate spatial output, the │ │ │ │ - * value will either be a single or an │ │ │ │ - * array of features. │ │ │ │ - * scope - {Object} Optional scope for the success callback. │ │ │ │ - */ │ │ │ │ - execute: function(options) { │ │ │ │ - var process = this.getProcess(options.server, options.process); │ │ │ │ - process.execute({ │ │ │ │ - inputs: options.inputs, │ │ │ │ - success: options.success, │ │ │ │ - scope: options.scope │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: getProcess │ │ │ │ - * Creates an . │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * serverID - {String} Local identifier from the servers that this instance │ │ │ │ - * was constructed with. │ │ │ │ - * processID - {String} Process identifier known to the server. │ │ │ │ + * Method: deactivate │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ + * tear-down. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {} │ │ │ │ - */ │ │ │ │ - getProcess: function(serverID, processID) { │ │ │ │ - var process = new OpenLayers.WPSProcess({ │ │ │ │ - client: this, │ │ │ │ - server: serverID, │ │ │ │ - identifier: processID │ │ │ │ - }); │ │ │ │ - if (!this.lazy) { │ │ │ │ - process.describe(); │ │ │ │ - } │ │ │ │ - return process; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: describeProcess │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * serverID - {String} Identifier of the server │ │ │ │ - * processID - {String} Identifier of the requested process │ │ │ │ - * callback - {Function} Callback to call when the description is available │ │ │ │ - * scope - {Object} Optional execution scope for the callback function │ │ │ │ + * {Boolean} True if the strategy was successfully deactivated or false if │ │ │ │ + * the strategy was already inactive. │ │ │ │ */ │ │ │ │ - describeProcess: function(serverID, processID, callback, scope) { │ │ │ │ - var server = this.servers[serverID]; │ │ │ │ - if (!server.processDescription[processID]) { │ │ │ │ - if (!(processID in server.processDescription)) { │ │ │ │ - // set to null so we know a describeFeature request is pending │ │ │ │ - server.processDescription[processID] = null; │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ - url: server.url, │ │ │ │ - params: { │ │ │ │ - SERVICE: 'WPS', │ │ │ │ - VERSION: server.version, │ │ │ │ - REQUEST: 'DescribeProcess', │ │ │ │ - IDENTIFIER: processID │ │ │ │ - }, │ │ │ │ - success: function(response) { │ │ │ │ - server.processDescription[processID] = response.responseText; │ │ │ │ - this.events.triggerEvent('describeprocess', { │ │ │ │ - identifier: processID, │ │ │ │ - raw: response.responseText │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - // pending request │ │ │ │ - this.events.register('describeprocess', this, function describe(evt) { │ │ │ │ - if (evt.identifier === processID) { │ │ │ │ - this.events.unregister('describeprocess', this, describe); │ │ │ │ - callback.call(scope, evt.raw); │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - window.setTimeout(function() { │ │ │ │ - callback.call(scope, server.processDescription[processID]); │ │ │ │ - }, 0); │ │ │ │ + deactivate: function() { │ │ │ │ + if (this.active) { │ │ │ │ + this.active = false; │ │ │ │ + return true; │ │ │ │ } │ │ │ │ + return false; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - this.events.destroy(); │ │ │ │ - this.events = null; │ │ │ │ - this.servers = null; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: 'OpenLayers.WPSClient' │ │ │ │ - │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Popup.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ @@ -33427,14 +30266,389 @@ │ │ │ │ │ │ │ │ OpenLayers.Popup.WIDTH = 200; │ │ │ │ OpenLayers.Popup.HEIGHT = 200; │ │ │ │ OpenLayers.Popup.COLOR = "white"; │ │ │ │ OpenLayers.Popup.OPACITY = 1; │ │ │ │ OpenLayers.Popup.BORDER = "0px"; │ │ │ │ /* ====================================================================== │ │ │ │ + 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 │ │ │ │ + * {} 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 │ │ │ │ + * . │ │ │ │ + */ │ │ │ │ + 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 and │ │ │ │ + * to change control state. │ │ │ │ + */ │ │ │ │ + active: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: handlerOptions │ │ │ │ + * {Object} Used to set non-default properties on the control's handler │ │ │ │ + */ │ │ │ │ + handlerOptions: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: handler │ │ │ │ + * {} null │ │ │ │ + */ │ │ │ │ + handler: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: eventListeners │ │ │ │ + * {Object} If set as an option at construction, the eventListeners │ │ │ │ + * object will be registered with . Object │ │ │ │ + * structure must be a listeners object as shown in the example for │ │ │ │ + * the events.on method. │ │ │ │ + */ │ │ │ │ + eventListeners: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: 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 - {} │ │ │ │ + */ │ │ │ │ + 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 - {} 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 - {} │ │ │ │ + */ │ │ │ │ + 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/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. */ │ │ │ │ @@ -33615,12696 +30829,10359 @@ │ │ │ │ OpenLayers.Function.bind(timerCallback, this) │ │ │ │ ); │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Kinetic" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/Markers.js │ │ │ │ + OpenLayers/Rule.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/BaseTypes/Class.js │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ + * @requires OpenLayers/Style.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.Markers │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - │ │ │ │ + * Class: OpenLayers.Rule │ │ │ │ + * This class represents an SLD Rule, as being used for rule-based SLD styling. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.Markers = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ +OpenLayers.Rule = OpenLayers.Class({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} Markers layer is never a base layer. │ │ │ │ + /** │ │ │ │ + * Property: id │ │ │ │ + * {String} A unique id for this session. │ │ │ │ */ │ │ │ │ - isBaseLayer: false, │ │ │ │ + id: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: markers │ │ │ │ - * {Array()} internal marker list │ │ │ │ + /** │ │ │ │ + * APIProperty: name │ │ │ │ + * {String} name of this rule │ │ │ │ */ │ │ │ │ - markers: null, │ │ │ │ + name: null, │ │ │ │ │ │ │ │ + /** │ │ │ │ + * Property: title │ │ │ │ + * {String} Title of this rule (set if included in SLD) │ │ │ │ + */ │ │ │ │ + title: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: drawn │ │ │ │ - * {Boolean} internal state of drawing. This is a workaround for the fact │ │ │ │ - * that the map does not call moveTo with a zoomChanged when the map is │ │ │ │ - * first starting up. This lets us catch the case where we have *never* │ │ │ │ - * drawn the layer, and draw it even if the zoom hasn't changed. │ │ │ │ + /** │ │ │ │ + * Property: description │ │ │ │ + * {String} Description of this rule (set if abstract is included in SLD) │ │ │ │ */ │ │ │ │ - drawn: false, │ │ │ │ + description: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.Markers │ │ │ │ - * Create a Markers layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ + * Property: context │ │ │ │ + * {Object} An optional object with properties that the rule should be │ │ │ │ + * evaluated against. If no context is specified, feature.attributes will │ │ │ │ + * be used. │ │ │ │ */ │ │ │ │ - initialize: function(name, options) { │ │ │ │ - OpenLayers.Layer.prototype.initialize.apply(this, arguments); │ │ │ │ - this.markers = []; │ │ │ │ - }, │ │ │ │ + context: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ + * Property: filter │ │ │ │ + * {} Optional filter for the rule. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - this.clearMarkers(); │ │ │ │ - this.markers = null; │ │ │ │ - OpenLayers.Layer.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + filter: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setOpacity │ │ │ │ - * Sets the opacity for all the markers. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * opacity - {Float} │ │ │ │ + * Property: elseFilter │ │ │ │ + * {Boolean} Determines whether this rule is only to be applied only if │ │ │ │ + * no other rules match (ElseFilter according to the SLD specification). │ │ │ │ + * Default is false. For instances of OpenLayers.Rule, if elseFilter is │ │ │ │ + * false, the rule will always apply. For subclasses, the else property is │ │ │ │ + * ignored. │ │ │ │ */ │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ - if (opacity != this.opacity) { │ │ │ │ - this.opacity = opacity; │ │ │ │ - for (var i = 0, len = this.markers.length; i < len; i++) { │ │ │ │ - this.markers[i].setOpacity(this.opacity); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + elseFilter: false, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: moveTo │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {} │ │ │ │ - * zoomChanged - {Boolean} │ │ │ │ - * dragging - {Boolean} │ │ │ │ + /** │ │ │ │ + * Property: symbolizer │ │ │ │ + * {Object} Symbolizer or hash of symbolizers for this rule. If hash of │ │ │ │ + * symbolizers, keys are one or more of ["Point", "Line", "Polygon"]. The │ │ │ │ + * latter if useful if it is required to style e.g. vertices of a line │ │ │ │ + * with a point symbolizer. Note, however, that this is not implemented │ │ │ │ + * yet in OpenLayers, but it is the way how symbolizers are defined in │ │ │ │ + * SLD. │ │ │ │ */ │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ + symbolizer: null, │ │ │ │ │ │ │ │ - if (zoomChanged || !this.drawn) { │ │ │ │ - for (var i = 0, len = this.markers.length; i < len; i++) { │ │ │ │ - this.drawMarker(this.markers[i]); │ │ │ │ - } │ │ │ │ - this.drawn = true; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: symbolizers │ │ │ │ + * {Array} Collection of symbolizers associated with this rule. If │ │ │ │ + * provided at construction, the symbolizers array has precedence │ │ │ │ + * over the deprecated symbolizer property. Note that multiple │ │ │ │ + * symbolizers are not currently supported by the vector renderers. │ │ │ │ + * Rules with multiple symbolizers are currently only useful for │ │ │ │ + * maintaining elements in an SLD document. │ │ │ │ + */ │ │ │ │ + symbolizers: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: addMarker │ │ │ │ + * APIProperty: minScaleDenominator │ │ │ │ + * {Number} or {String} minimum scale at which to draw the feature. │ │ │ │ + * In the case of a String, this can be a combination of text and │ │ │ │ + * propertyNames in the form "literal ${propertyName}" │ │ │ │ + */ │ │ │ │ + minScaleDenominator: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: maxScaleDenominator │ │ │ │ + * {Number} or {String} maximum scale at which to draw the feature. │ │ │ │ + * In the case of a String, this can be a combination of text and │ │ │ │ + * propertyNames in the form "literal ${propertyName}" │ │ │ │ + */ │ │ │ │ + maxScaleDenominator: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Rule │ │ │ │ + * Creates a Rule. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * marker - {} │ │ │ │ + * options - {Object} An optional object with properties to set on the │ │ │ │ + * rule │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {} │ │ │ │ */ │ │ │ │ - addMarker: function(marker) { │ │ │ │ - this.markers.push(marker); │ │ │ │ - │ │ │ │ - if (this.opacity < 1) { │ │ │ │ - marker.setOpacity(this.opacity); │ │ │ │ + initialize: function(options) { │ │ │ │ + this.symbolizer = {}; │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + if (this.symbolizers) { │ │ │ │ + delete this.symbolizer; │ │ │ │ } │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (this.map && this.map.getExtent()) { │ │ │ │ - marker.map = this.map; │ │ │ │ - this.drawMarker(marker); │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + for (var i in this.symbolizer) { │ │ │ │ + this.symbolizer[i] = null; │ │ │ │ } │ │ │ │ + this.symbolizer = null; │ │ │ │ + delete this.symbolizers; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: removeMarker │ │ │ │ - * │ │ │ │ + * APIMethod: evaluate │ │ │ │ + * evaluates this rule for a specific feature │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * marker - {} │ │ │ │ + * feature - {} feature to apply the rule to. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} true if the rule applies, false if it does not. │ │ │ │ + * This rule is the default rule and always returns true. │ │ │ │ */ │ │ │ │ - removeMarker: function(marker) { │ │ │ │ - if (this.markers && this.markers.length) { │ │ │ │ - OpenLayers.Util.removeItem(this.markers, marker); │ │ │ │ - marker.erase(); │ │ │ │ + evaluate: function(feature) { │ │ │ │ + var context = this.getContext(feature); │ │ │ │ + var applies = true; │ │ │ │ + │ │ │ │ + if (this.minScaleDenominator || this.maxScaleDenominator) { │ │ │ │ + var scale = feature.layer.map.getScale(); │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: clearMarkers │ │ │ │ - * This method removes all markers from a layer. The markers are not │ │ │ │ - * destroyed by this function, but are removed from the list of markers. │ │ │ │ - */ │ │ │ │ - clearMarkers: function() { │ │ │ │ - if (this.markers != null) { │ │ │ │ - while (this.markers.length > 0) { │ │ │ │ - this.removeMarker(this.markers[0]); │ │ │ │ + // check if within minScale/maxScale bounds │ │ │ │ + if (this.minScaleDenominator) { │ │ │ │ + applies = scale >= OpenLayers.Style.createLiteral( │ │ │ │ + this.minScaleDenominator, context); │ │ │ │ + } │ │ │ │ + if (applies && this.maxScaleDenominator) { │ │ │ │ + applies = scale < OpenLayers.Style.createLiteral( │ │ │ │ + this.maxScaleDenominator, context); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // check if optional filter applies │ │ │ │ + if (applies && this.filter) { │ │ │ │ + // feature id filters get the feature, others get the context │ │ │ │ + if (this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") { │ │ │ │ + applies = this.filter.evaluate(feature); │ │ │ │ + } else { │ │ │ │ + applies = this.filter.evaluate(context); │ │ │ │ } │ │ │ │ } │ │ │ │ + │ │ │ │ + return applies; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: drawMarker │ │ │ │ - * Calculate the pixel location for the marker, create it, and │ │ │ │ - * add it to the layer's div │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * marker - {} │ │ │ │ + /** │ │ │ │ + * Method: getContext │ │ │ │ + * Gets the context for evaluating this rule │ │ │ │ + * │ │ │ │ + * Paramters: │ │ │ │ + * feature - {} feature to take the context from if │ │ │ │ + * none is specified. │ │ │ │ */ │ │ │ │ - drawMarker: function(marker) { │ │ │ │ - var px = this.map.getLayerPxFromLonLat(marker.lonlat); │ │ │ │ - if (px == null) { │ │ │ │ - marker.display(false); │ │ │ │ - } else { │ │ │ │ - if (!marker.isDrawn()) { │ │ │ │ - var markerImg = marker.draw(px); │ │ │ │ - this.div.appendChild(markerImg); │ │ │ │ - } else if (marker.icon) { │ │ │ │ - marker.icon.moveTo(px); │ │ │ │ - } │ │ │ │ + getContext: function(feature) { │ │ │ │ + var context = this.context; │ │ │ │ + if (!context) { │ │ │ │ + context = feature.attributes || feature.data; │ │ │ │ + } │ │ │ │ + if (typeof this.context == "function") { │ │ │ │ + context = this.context(feature); │ │ │ │ } │ │ │ │ + return context; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getDataExtent │ │ │ │ - * Calculates the max extent which includes all of the markers. │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * Clones this rule. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {} │ │ │ │ + * {} Clone of this rule. │ │ │ │ */ │ │ │ │ - getDataExtent: function() { │ │ │ │ - var maxExtent = null; │ │ │ │ - │ │ │ │ - if (this.markers && (this.markers.length > 0)) { │ │ │ │ - var maxExtent = new OpenLayers.Bounds(); │ │ │ │ - for (var i = 0, len = this.markers.length; i < len; i++) { │ │ │ │ - var marker = this.markers[i]; │ │ │ │ - maxExtent.extend(marker.lonlat); │ │ │ │ + clone: function() { │ │ │ │ + var options = OpenLayers.Util.extend({}, this); │ │ │ │ + if (this.symbolizers) { │ │ │ │ + // clone symbolizers │ │ │ │ + var len = this.symbolizers.length; │ │ │ │ + options.symbolizers = new Array(len); │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ + options.symbolizers[i] = this.symbolizers[i].clone(); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + // clone symbolizer │ │ │ │ + options.symbolizer = {}; │ │ │ │ + var value, type; │ │ │ │ + for (var key in this.symbolizer) { │ │ │ │ + value = this.symbolizer[key]; │ │ │ │ + type = typeof value; │ │ │ │ + if (type === "object") { │ │ │ │ + options.symbolizer[key] = OpenLayers.Util.extend({}, value); │ │ │ │ + } else if (type === "string") { │ │ │ │ + options.symbolizer[key] = value; │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ - │ │ │ │ - return maxExtent; │ │ │ │ + // clone filter │ │ │ │ + options.filter = this.filter && this.filter.clone(); │ │ │ │ + // clone context │ │ │ │ + options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ + return new OpenLayers.Rule(options); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Markers" │ │ │ │ + CLASS_NAME: "OpenLayers.Rule" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/GeoRSS.js │ │ │ │ + OpenLayers/Spherical.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/Layer/Markers.js │ │ │ │ - * @requires OpenLayers/Request/XMLHttpRequest.js │ │ │ │ + * Namespace: Spherical │ │ │ │ + * The OpenLayers.Spherical namespace includes utility functions for │ │ │ │ + * calculations on the basis of a spherical earth (ignoring ellipsoidal │ │ │ │ + * effects), which is accurate enough for most purposes. │ │ │ │ + * │ │ │ │ + * Relevant links: │ │ │ │ + * * http://www.movable-type.co.uk/scripts/latlong.html │ │ │ │ + * * http://code.google.com/apis/maps/documentation/javascript/reference.html#spherical │ │ │ │ */ │ │ │ │ │ │ │ │ +OpenLayers.Spherical = OpenLayers.Spherical || {}; │ │ │ │ + │ │ │ │ +OpenLayers.Spherical.DEFAULT_RADIUS = 6378137; │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.GeoRSS │ │ │ │ - * Add GeoRSS Point features to your map. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - │ │ │ │ + * APIFunction: computeDistanceBetween │ │ │ │ + * Computes the distance between two LonLats. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * from - {} or {Object} Starting point. A LonLat or │ │ │ │ + * a JavaScript literal with lon lat properties. │ │ │ │ + * to - {} or {Object} Ending point. A LonLat or a │ │ │ │ + * JavaScript literal with lon lat properties. │ │ │ │ + * radius - {Float} The radius. Optional. Defaults to 6378137 meters. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Float} The distance in meters. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.GeoRSS = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ +OpenLayers.Spherical.computeDistanceBetween = function(from, to, radius) { │ │ │ │ + var R = radius || OpenLayers.Spherical.DEFAULT_RADIUS; │ │ │ │ + var sinHalfDeltaLon = Math.sin(Math.PI * (to.lon - from.lon) / 360); │ │ │ │ + var sinHalfDeltaLat = Math.sin(Math.PI * (to.lat - from.lat) / 360); │ │ │ │ + var a = sinHalfDeltaLat * sinHalfDeltaLat + │ │ │ │ + sinHalfDeltaLon * sinHalfDeltaLon * Math.cos(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ + return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); │ │ │ │ +}; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: location │ │ │ │ - * {String} store url of text file │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * APIFunction: computeHeading │ │ │ │ + * Computes the heading from one LonLat to another LonLat. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * from - {} or {Object} Starting point. A LonLat or │ │ │ │ + * a JavaScript literal with lon lat properties. │ │ │ │ + * to - {} or {Object} Ending point. A LonLat or a │ │ │ │ + * JavaScript literal with lon lat properties. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Float} The heading in degrees. │ │ │ │ + */ │ │ │ │ +OpenLayers.Spherical.computeHeading = function(from, to) { │ │ │ │ + var y = Math.sin(Math.PI * (from.lon - to.lon) / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ + var x = Math.cos(Math.PI * from.lat / 180) * Math.sin(Math.PI * to.lat / 180) - │ │ │ │ + Math.sin(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180) * Math.cos(Math.PI * (from.lon - to.lon) / 180); │ │ │ │ + return 180 * Math.atan2(y, x) / Math.PI; │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + 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} │ │ │ │ */ │ │ │ │ - location: null, │ │ │ │ + id: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: features │ │ │ │ - * {Array()} │ │ │ │ + /** │ │ │ │ + * APIProperty: 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. │ │ │ │ */ │ │ │ │ - features: null, │ │ │ │ + control: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: formatOptions │ │ │ │ - * {Object} Hash of options which should be passed to the format when it is │ │ │ │ - * created. Must be passed in the constructor. │ │ │ │ + * Property: map │ │ │ │ + * {} │ │ │ │ */ │ │ │ │ - formatOptions: null, │ │ │ │ + map: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: selectedFeature │ │ │ │ - * {} │ │ │ │ + /** │ │ │ │ + * APIProperty: keyMask │ │ │ │ + * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler │ │ │ │ + * constants to construct a keyMask. The keyMask is used by │ │ │ │ + * . 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) │ │ │ │ */ │ │ │ │ - selectedFeature: null, │ │ │ │ + keyMask: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: icon │ │ │ │ - * {}. This determines the Icon to be used on the map │ │ │ │ - * for this GeoRSS layer. │ │ │ │ + /** │ │ │ │ + * Property: active │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - icon: null, │ │ │ │ + active: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: popupSize │ │ │ │ - * {} This determines the size of GeoRSS popups. If │ │ │ │ - * not provided, defaults to 250px by 120px. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - popupSize: null, │ │ │ │ + evt: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: useFeedTitle │ │ │ │ - * {Boolean} Set layer.name to the first element in the feed. Default is true. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - useFeedTitle: true, │ │ │ │ + touch: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.GeoRSS │ │ │ │ - * Create a GeoRSS Layer. │ │ │ │ + * Constructor: OpenLayers.Handler │ │ │ │ + * Construct a handler. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * location - {String} │ │ │ │ - * options - {Object} │ │ │ │ + * 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(name, location, options) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.initialize.apply(this, [name, options]); │ │ │ │ - this.location = location; │ │ │ │ - this.features = []; │ │ │ │ + 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: destroy │ │ │ │ + * Method: setMap │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - // Warning: Layer.Markers.destroy() must be called prior to calling │ │ │ │ - // clearFeatures() here, otherwise we leak memory. Indeed, if │ │ │ │ - // Layer.Markers.destroy() is called after clearFeatures(), it won't be │ │ │ │ - // able to remove the marker image elements from the layer's div since │ │ │ │ - // the markers will have been destroyed by clearFeatures(). │ │ │ │ - OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ - this.clearFeatures(); │ │ │ │ - this.features = null; │ │ │ │ + setMap: function(map) { │ │ │ │ + this.map = map; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: loadRSS │ │ │ │ - * Start the load of the RSS data. Don't do this when we first add the layer, │ │ │ │ - * since we may not be visible at any point, and it would therefore be a waste. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - loadRSS: function() { │ │ │ │ - if (!this.loaded) { │ │ │ │ - this.events.triggerEvent("loadstart"); │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ - url: this.location, │ │ │ │ - success: this.parseData, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.loaded = true; │ │ │ │ + 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); │ │ │ │ + }, │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: moveTo │ │ │ │ - * If layer is visible and RSS has not been loaded, load RSS. │ │ │ │ + * APIMethod: activate │ │ │ │ + * Turn on the handler. Returns false if the handler was already active. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {Object} │ │ │ │ - * zoomChanged - {Object} │ │ │ │ - * minor - {Object} │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The handler was activated. │ │ │ │ */ │ │ │ │ - moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ - if (this.visibility && !this.loaded) { │ │ │ │ - this.loadRSS(); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseData │ │ │ │ - * Parse the data returned from the Events call. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * ajaxRequest - {<OpenLayers.Request.XMLHttpRequest>} │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Turn off the handler. Returns false if the handler was already inactive. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The handler was deactivated. │ │ │ │ */ │ │ │ │ - parseData: function(ajaxRequest) { │ │ │ │ - var doc = ajaxRequest.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = OpenLayers.Format.XML.prototype.read(ajaxRequest.responseText); │ │ │ │ + deactivate: function() { │ │ │ │ + if (!this.active) { │ │ │ │ + return false; │ │ │ │ } │ │ │ │ - │ │ │ │ - if (this.useFeedTitle) { │ │ │ │ - var name = null; │ │ │ │ - try { │ │ │ │ - name = doc.getElementsByTagNameNS('*', 'title')[0].firstChild.nodeValue; │ │ │ │ - } catch (e) { │ │ │ │ - try { │ │ │ │ - name = doc.getElementsByTagName('title')[0].firstChild.nodeValue; │ │ │ │ - } catch (e) {} │ │ │ │ + // 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]]); │ │ │ │ } │ │ │ │ - if (name) { │ │ │ │ - this.setName(name); │ │ │ │ + } │ │ │ │ + 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]]); │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - var options = {}; │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ - options.externalProjection = this.projection; │ │ │ │ - options.internalProjection = this.map.getProjectionObject(); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ + }, │ │ │ │ │ │ │ │ - var format = new OpenLayers.Format.GeoRSS(options); │ │ │ │ - var features = format.read(doc); │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ - var data = {}; │ │ │ │ - var feature = features[i]; │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + * Deconstruct the handler. │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + // unregister event listeners │ │ │ │ + this.deactivate(); │ │ │ │ + // eliminate circular references │ │ │ │ + this.control = this.map = null; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // we don't support features with no geometry in the GeoRSS │ │ │ │ - // layer at this time. │ │ │ │ - if (!feature.geometry) { │ │ │ │ - continue; │ │ │ │ - } │ │ │ │ + CLASS_NAME: "OpenLayers.Handler" │ │ │ │ +}); │ │ │ │ │ │ │ │ - var title = feature.attributes.title ? │ │ │ │ - feature.attributes.title : "Untitled"; │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Handler.MOD_NONE │ │ │ │ + * If set as the <keyMask>, <checkModifiers> returns false if any key is down. │ │ │ │ + */ │ │ │ │ +OpenLayers.Handler.MOD_NONE = 0; │ │ │ │ │ │ │ │ - var description = feature.attributes.description ? │ │ │ │ - feature.attributes.description : "No description."; │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Handler.MOD_SHIFT │ │ │ │ + * If set as the <keyMask>, <checkModifiers> returns false if Shift is down. │ │ │ │ + */ │ │ │ │ +OpenLayers.Handler.MOD_SHIFT = 1; │ │ │ │ │ │ │ │ - var link = feature.attributes.link ? feature.attributes.link : ""; │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Handler.MOD_CTRL │ │ │ │ + * If set as the <keyMask>, <checkModifiers> returns false if Ctrl is down. │ │ │ │ + */ │ │ │ │ +OpenLayers.Handler.MOD_CTRL = 2; │ │ │ │ │ │ │ │ - var location = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ +/** │ │ │ │ + * 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; │ │ │ │ │ │ │ │ - data.icon = this.icon == null ? │ │ │ │ - OpenLayers.Marker.defaultIcon() : │ │ │ │ - this.icon.clone(); │ │ │ │ │ │ │ │ - data.popupSize = this.popupSize ? │ │ │ │ - this.popupSize.clone() : │ │ │ │ - new OpenLayers.Size(250, 120); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WPSDescribeProcess.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - if (title || description) { │ │ │ │ - // we have supplemental data, store them. │ │ │ │ - data.title = title; │ │ │ │ - data.description = description; │ │ │ │ +/* 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 contentHTML = '<div class="olLayerGeoRSSClose">[x]</div>'; │ │ │ │ - contentHTML += '<div class="olLayerGeoRSSTitle">'; │ │ │ │ - if (link) { │ │ │ │ - contentHTML += '<a class="link" href="' + link + '" target="_blank">'; │ │ │ │ - } │ │ │ │ - contentHTML += title; │ │ │ │ - if (link) { │ │ │ │ - contentHTML += '</a>'; │ │ │ │ - } │ │ │ │ - contentHTML += '</div>'; │ │ │ │ - contentHTML += '<div style="" class="olLayerGeoRSSDescription">'; │ │ │ │ - contentHTML += description; │ │ │ │ - contentHTML += '</div>'; │ │ │ │ - data['popupContentHTML'] = contentHTML; │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/XML.js │ │ │ │ + * @requires OpenLayers/Format/OWSCommon/v1_1_0.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WPSDescribeProcess │ │ │ │ + * Read WPS DescribeProcess responses. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WPSDescribeProcess = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.XML, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: VERSION │ │ │ │ + * {String} 1.0.0 │ │ │ │ + */ │ │ │ │ + VERSION: "1.0.0", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + */ │ │ │ │ + namespaces: { │ │ │ │ + wps: "http://www.opengis.net/wps/1.0.0", │ │ │ │ + ows: "http://www.opengis.net/ows/1.1", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} Schema location │ │ │ │ + */ │ │ │ │ + schemaLocation: "http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: defaultPrefix │ │ │ │ + */ │ │ │ │ + defaultPrefix: "wps", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ + */ │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WPSDescribeProcess │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Parse a WPS DescribeProcess and return an object with its information. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} │ │ │ │ + */ │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ } │ │ │ │ - var feature = new OpenLayers.Feature(this, location, data); │ │ │ │ - this.features.push(feature); │ │ │ │ - var marker = feature.createMarker(); │ │ │ │ - marker.events.register('click', feature, this.markerClick); │ │ │ │ - this.addMarker(marker); │ │ │ │ - } │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ - }, │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement; │ │ │ │ + } │ │ │ │ + var info = {}; │ │ │ │ + this.readNode(data, info); │ │ │ │ + return info; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: markerClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - */ │ │ │ │ - markerClick: function(evt) { │ │ │ │ - var sameMarkerClicked = (this == this.layer.selectedFeature); │ │ │ │ - this.layer.selectedFeature = (!sameMarkerClicked) ? this : null; │ │ │ │ - for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ - this.layer.map.removePopup(this.layer.map.popups[i]); │ │ │ │ - } │ │ │ │ - if (!sameMarkerClicked) { │ │ │ │ - var popup = this.createPopup(); │ │ │ │ - OpenLayers.Event.observe(popup.div, "click", │ │ │ │ - OpenLayers.Function.bind(function() { │ │ │ │ - for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ - this.layer.map.removePopup(this.layer.map.popups[i]); │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wps": { │ │ │ │ + "ProcessDescriptions": function(node, obj) { │ │ │ │ + obj.processDescriptions = {}; │ │ │ │ + this.readChildNodes(node, obj.processDescriptions); │ │ │ │ + }, │ │ │ │ + "ProcessDescription": function(node, processDescriptions) { │ │ │ │ + var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); │ │ │ │ + var processDescription = { │ │ │ │ + processVersion: processVersion, │ │ │ │ + statusSupported: (node.getAttribute("statusSupported") === "true"), │ │ │ │ + storeSupported: (node.getAttribute("storeSupported") === "true") │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, processDescription); │ │ │ │ + processDescriptions[processDescription.identifier] = processDescription; │ │ │ │ + }, │ │ │ │ + "DataInputs": function(node, processDescription) { │ │ │ │ + processDescription.dataInputs = []; │ │ │ │ + this.readChildNodes(node, processDescription.dataInputs); │ │ │ │ + }, │ │ │ │ + "ProcessOutputs": function(node, processDescription) { │ │ │ │ + processDescription.processOutputs = []; │ │ │ │ + this.readChildNodes(node, processDescription.processOutputs); │ │ │ │ + }, │ │ │ │ + "Output": function(node, processOutputs) { │ │ │ │ + var output = {}; │ │ │ │ + this.readChildNodes(node, output); │ │ │ │ + processOutputs.push(output); │ │ │ │ + }, │ │ │ │ + "ComplexOutput": function(node, output) { │ │ │ │ + output.complexOutput = {}; │ │ │ │ + this.readChildNodes(node, output.complexOutput); │ │ │ │ + }, │ │ │ │ + "LiteralOutput": function(node, output) { │ │ │ │ + output.literalOutput = {}; │ │ │ │ + this.readChildNodes(node, output.literalOutput); │ │ │ │ + }, │ │ │ │ + "Input": function(node, dataInputs) { │ │ │ │ + var input = { │ │ │ │ + maxOccurs: parseInt(node.getAttribute("maxOccurs")), │ │ │ │ + minOccurs: parseInt(node.getAttribute("minOccurs")) │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, input); │ │ │ │ + dataInputs.push(input); │ │ │ │ + }, │ │ │ │ + "BoundingBoxData": function(node, input) { │ │ │ │ + input.boundingBoxData = {}; │ │ │ │ + this.readChildNodes(node, input.boundingBoxData); │ │ │ │ + }, │ │ │ │ + "CRS": function(node, obj) { │ │ │ │ + if (!obj.CRSs) { │ │ │ │ + obj.CRSs = {}; │ │ │ │ } │ │ │ │ - }, this) │ │ │ │ - ); │ │ │ │ - this.layer.map.addPopup(popup); │ │ │ │ - } │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - }, │ │ │ │ + obj.CRSs[this.getChildValue(node)] = true; │ │ │ │ + }, │ │ │ │ + "LiteralData": function(node, input) { │ │ │ │ + input.literalData = {}; │ │ │ │ + this.readChildNodes(node, input.literalData); │ │ │ │ + }, │ │ │ │ + "ComplexData": function(node, input) { │ │ │ │ + input.complexData = {}; │ │ │ │ + this.readChildNodes(node, input.complexData); │ │ │ │ + }, │ │ │ │ + "Default": function(node, complexData) { │ │ │ │ + complexData["default"] = {}; │ │ │ │ + this.readChildNodes(node, complexData["default"]); │ │ │ │ + }, │ │ │ │ + "Supported": function(node, complexData) { │ │ │ │ + complexData["supported"] = {}; │ │ │ │ + this.readChildNodes(node, complexData["supported"]); │ │ │ │ + }, │ │ │ │ + "Format": function(node, obj) { │ │ │ │ + var format = {}; │ │ │ │ + this.readChildNodes(node, format); │ │ │ │ + if (!obj.formats) { │ │ │ │ + obj.formats = {}; │ │ │ │ + } │ │ │ │ + obj.formats[format.mimeType] = true; │ │ │ │ + }, │ │ │ │ + "MimeType": function(node, format) { │ │ │ │ + format.mimeType = this.getChildValue(node); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: clearFeatures │ │ │ │ - * Destroy all features in this layer. │ │ │ │ - */ │ │ │ │ - clearFeatures: function() { │ │ │ │ - if (this.features != null) { │ │ │ │ - while (this.features.length > 0) { │ │ │ │ - var feature = this.features[0]; │ │ │ │ - OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ - feature.destroy(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WPSDescribeProcess" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.GeoRSS" │ │ │ │ -}); │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/XYZ.js │ │ │ │ + OpenLayers/WPSClient.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 │ │ │ │ + * @requires OpenLayers/SingleFile.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> │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ + * @requires OpenLayers/WPSProcess.js │ │ │ │ + * @requires OpenLayers/Format/WPSDescribeProcess.js │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.WPSClient │ │ │ │ + * High level API for interaction with Web Processing Services (WPS). │ │ │ │ + * An <OpenLayers.WPSClient> instance is used to create <OpenLayers.WPSProcess> │ │ │ │ + * instances for servers known to the WPSClient. The WPSClient also caches │ │ │ │ + * DescribeProcess responses to reduce the number of requests sent to servers │ │ │ │ + * when processes are created. │ │ │ │ + */ │ │ │ │ +OpenLayers.WPSClient = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * Default is true, as this is designed to be a base tile source. │ │ │ │ + * Property: servers │ │ │ │ + * {Object} Service metadata, keyed by a local identifier. │ │ │ │ + * │ │ │ │ + * Properties: │ │ │ │ + * url - {String} the url of the server │ │ │ │ + * version - {String} WPS version of the server │ │ │ │ + * processDescription - {Object} Cache of raw DescribeProcess │ │ │ │ + * responses, keyed by process identifier. │ │ │ │ */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + servers: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: version │ │ │ │ + * {String} The default WPS version to use if none is configured. Default │ │ │ │ + * is '1.0.0'. │ │ │ │ */ │ │ │ │ - sphericalMercator: false, │ │ │ │ + version: '1.0.0', │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: lazy │ │ │ │ + * {Boolean} Should the DescribeProcess be deferred until a process is │ │ │ │ + * fully configured? Default is false. │ │ │ │ */ │ │ │ │ - zoomOffset: 0, │ │ │ │ + lazy: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: events │ │ │ │ + * {<OpenLayers.Events>} │ │ │ │ + * │ │ │ │ + * Supported event types: │ │ │ │ + * describeprocess - Fires when the process description is available. │ │ │ │ + * Listeners receive an object with a 'raw' property holding the raw │ │ │ │ + * DescribeProcess response, and an 'identifier' property holding the │ │ │ │ + * process identifier of the described process. │ │ │ │ */ │ │ │ │ - serverResolutions: null, │ │ │ │ + events: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.XYZ │ │ │ │ + * Constructor: OpenLayers.WPSClient │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * url - {String} │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ + * options - {Object} Object whose properties will be set on the instance. │ │ │ │ + * │ │ │ │ + * Avaliable options: │ │ │ │ + * servers - {Object} Mandatory. Service metadata, keyed by a local │ │ │ │ + * identifier. Can either be a string with the service url or an │ │ │ │ + * object literal with additional metadata: │ │ │ │ + * │ │ │ │ + * (code) │ │ │ │ + * servers: { │ │ │ │ + * local: '/geoserver/wps' │ │ │ │ + * }, { │ │ │ │ + * opengeo: { │ │ │ │ + * url: 'http://demo.opengeo.org/geoserver/wps', │ │ │ │ + * version: '1.0.0' │ │ │ │ + * } │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * lazy - {Boolean} Optional. Set to true if DescribeProcess should not be │ │ │ │ + * requested until a process is fully configured. Default is false. │ │ │ │ */ │ │ │ │ - initialize: function(name, url, options) { │ │ │ │ - if (options && options.sphericalMercator || this.sphericalMercator) { │ │ │ │ - options = OpenLayers.Util.extend({ │ │ │ │ - projection: "EPSG:900913", │ │ │ │ - numZoomLevels: 19 │ │ │ │ - }, options); │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + this.events = new OpenLayers.Events(this); │ │ │ │ + this.servers = {}; │ │ │ │ + for (var s in options.servers) { │ │ │ │ + this.servers[s] = typeof options.servers[s] == 'string' ? { │ │ │ │ + url: options.servers[s], │ │ │ │ + version: this.version, │ │ │ │ + processDescription: {} │ │ │ │ + } : options.servers[s]; │ │ │ │ } │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, [ │ │ │ │ - name || this.name, url || this.url, {}, │ │ │ │ - options │ │ │ │ - ]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ + * APIMethod: execute │ │ │ │ + * Shortcut to execute a process with a single function call. This is │ │ │ │ + * equivalent to using <getProcess> and then calling execute on the │ │ │ │ + * process. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * obj - {Object} Is this ever used? │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.XYZ>} An exact clone of this OpenLayers.Layer.XYZ │ │ │ │ + * options - {Object} Options for the execute operation. │ │ │ │ + * │ │ │ │ + * Available options: │ │ │ │ + * server - {String} Mandatory. One of the local identifiers of the │ │ │ │ + * configured servers. │ │ │ │ + * process - {String} Mandatory. A process identifier known to the │ │ │ │ + * server. │ │ │ │ + * inputs - {Object} The inputs for the process, keyed by input identifier. │ │ │ │ + * For spatial data inputs, the value of an input is usually an │ │ │ │ + * <OpenLayers.Geometry>, an <OpenLayers.Feature.Vector> or an array of │ │ │ │ + * geometries or features. │ │ │ │ + * output - {String} The identifier of an output to parse. Optional. If not │ │ │ │ + * provided, the first output will be parsed. │ │ │ │ + * success - {Function} Callback to call when the process is complete. │ │ │ │ + * This function is called with an outputs object as argument, which │ │ │ │ + * will have a property with the identifier of the requested output │ │ │ │ + * (e.g. 'result'). For processes that generate spatial output, the │ │ │ │ + * value will either be a single <OpenLayers.Feature.Vector> or an │ │ │ │ + * array of features. │ │ │ │ + * scope - {Object} Optional scope for the success callback. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + execute: function(options) { │ │ │ │ + var process = this.getProcess(options.server, options.process); │ │ │ │ + process.execute({ │ │ │ │ + inputs: options.inputs, │ │ │ │ + success: options.success, │ │ │ │ + scope: options.scope │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getURL │ │ │ │ + * APIMethod: getProcess │ │ │ │ + * Creates an <OpenLayers.WPSProcess>. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * serverID - {String} Local identifier from the servers that this instance │ │ │ │ + * was constructed with. │ │ │ │ + * processID - {String} Process identifier known to the server. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} A string with the layer's url and parameters and also the │ │ │ │ - * passed-in bounds and appropriate tile size specified as │ │ │ │ - * parameters │ │ │ │ + * {<OpenLayers.WPSProcess>} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + getProcess: function(serverID, processID) { │ │ │ │ + var process = new OpenLayers.WPSProcess({ │ │ │ │ + client: this, │ │ │ │ + server: serverID, │ │ │ │ + identifier: processID │ │ │ │ + }); │ │ │ │ + if (!this.lazy) { │ │ │ │ + process.describe(); │ │ │ │ } │ │ │ │ - │ │ │ │ - return OpenLayers.String.format(url, xyz); │ │ │ │ + return process; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getXYZ │ │ │ │ - * Calculates x, y and z for the given bounds. │ │ │ │ + * Method: describeProcess │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} - an object with x, y and z properties. │ │ │ │ + * serverID - {String} Identifier of the server │ │ │ │ + * processID - {String} Identifier of the requested process │ │ │ │ + * callback - {Function} Callback to call when the description is available │ │ │ │ + * scope - {Object} Optional execution scope for the callback function │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + describeProcess: function(serverID, processID, callback, scope) { │ │ │ │ + var server = this.servers[serverID]; │ │ │ │ + if (!server.processDescription[processID]) { │ │ │ │ + if (!(processID in server.processDescription)) { │ │ │ │ + // set to null so we know a describeFeature request is pending │ │ │ │ + server.processDescription[processID] = null; │ │ │ │ + OpenLayers.Request.GET({ │ │ │ │ + url: server.url, │ │ │ │ + params: { │ │ │ │ + SERVICE: 'WPS', │ │ │ │ + VERSION: server.version, │ │ │ │ + REQUEST: 'DescribeProcess', │ │ │ │ + IDENTIFIER: processID │ │ │ │ + }, │ │ │ │ + success: function(response) { │ │ │ │ + server.processDescription[processID] = response.responseText; │ │ │ │ + this.events.triggerEvent('describeprocess', { │ │ │ │ + identifier: processID, │ │ │ │ + raw: response.responseText │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + // pending request │ │ │ │ + this.events.register('describeprocess', this, function describe(evt) { │ │ │ │ + if (evt.identifier === processID) { │ │ │ │ + this.events.unregister('describeprocess', this, describe); │ │ │ │ + callback.call(scope, evt.raw); │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + window.setTimeout(function() { │ │ │ │ + callback.call(scope, server.processDescription[processID]); │ │ │ │ + }, 0); │ │ │ │ } │ │ │ │ - │ │ │ │ - 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>} │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + destroy: function() { │ │ │ │ + this.events.destroy(); │ │ │ │ + this.events = null; │ │ │ │ + this.servers = null; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.XYZ" │ │ │ │ + CLASS_NAME: 'OpenLayers.WPSClient' │ │ │ │ + │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/ArcGISCache.js │ │ │ │ + OpenLayers/Symbolizer.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 │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ */ │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Layer.ArcGISCache │ │ │ │ - * Layer for accessing cached map tiles from an ArcGIS Server style mapcache. │ │ │ │ - * Tile must already be cached for this layer to access it. This does not require │ │ │ │ - * ArcGIS Server itself. │ │ │ │ - * │ │ │ │ - * A few attempts have been made at this kind of layer before. See │ │ │ │ - * http://trac.osgeo.org/openlayers/ticket/1967 │ │ │ │ - * and │ │ │ │ - * http://trac.osgeo.org/openlayers/browser/sandbox/tschaub/arcgiscache/lib/OpenLayers/Layer/ArcGISCache.js │ │ │ │ - * │ │ │ │ - * Typically the problem encountered is that the tiles seem to "jump around". │ │ │ │ - * This is due to the fact that the actual max extent for the tiles on AGS layers │ │ │ │ - * changes at each zoom level due to the way these caches are constructed. │ │ │ │ - * We have attempted to use the resolutions, tile size, and tile origin │ │ │ │ - * from the cache meta data to make the appropriate changes to the max extent │ │ │ │ - * of the tile to compensate for this behavior. This must be done as zoom levels change │ │ │ │ - * and before tiles are requested, which is why methods from base classes are overridden. │ │ │ │ - * │ │ │ │ - * For reference, you can access mapcache meta data in two ways. For accessing a │ │ │ │ - * mapcache through ArcGIS Server, you can simply go to the landing page for the │ │ │ │ - * layer. (ie. http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer) │ │ │ │ - * For accessing it directly through HTTP, there should always be a conf.xml file │ │ │ │ - * in the root directory. │ │ │ │ - * (ie. http://serverx.esri.com/arcgiscache/DG_County_roads_yesA_backgroundDark/Layers/conf.xml) │ │ │ │ - * │ │ │ │ - *Inherits from: │ │ │ │ - * - <OpenLayers.Layer.XYZ> │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Symbolizer │ │ │ │ + * Base class representing a symbolizer used for feature rendering. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.ArcGISCache = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ +OpenLayers.Symbolizer = OpenLayers.Class({ │ │ │ │ + │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: url │ │ │ │ - * {String | Array} The base URL for the layer cache. You can also │ │ │ │ - * provide a list of URL strings for the layer if your cache is │ │ │ │ - * available from multiple origins. This must be set before the layer │ │ │ │ - * is drawn. │ │ │ │ + * APIProperty: zIndex │ │ │ │ + * {Number} The zIndex determines the rendering order for a symbolizer. │ │ │ │ + * Symbolizers with larger zIndex values are rendered over symbolizers │ │ │ │ + * with smaller zIndex values. Default is 0. │ │ │ │ */ │ │ │ │ - url: null, │ │ │ │ + zIndex: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: tileOrigin │ │ │ │ - * {<OpenLayers.LonLat>} The location of the tile origin for the cache. │ │ │ │ - * An ArcGIS cache has it's origin at the upper-left (lowest x value │ │ │ │ - * and highest y value of the coordinate system). The units for the │ │ │ │ - * tile origin should be the same as the units for the cached data. │ │ │ │ + * Constructor: OpenLayers.Symbolizer │ │ │ │ + * Instances of this class are not useful. See one of the subclasses. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ + * construction. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * A new symbolizer. │ │ │ │ */ │ │ │ │ - tileOrigin: null, │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Util.extend(this, config); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: tileSize │ │ │ │ - * {<OpenLayers.Size>} This size of each tile. Defaults to 256 by 256 pixels. │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * Create a copy of this symbolizer. │ │ │ │ + * │ │ │ │ + * Returns a symbolizer of the same type with the same properties. │ │ │ │ */ │ │ │ │ - tileSize: new OpenLayers.Size(256, 256), │ │ │ │ + clone: function() { │ │ │ │ + var Type = eval(this.CLASS_NAME); │ │ │ │ + return new Type(OpenLayers.Util.extend({}, this)); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer" │ │ │ │ + │ │ │ │ +}); │ │ │ │ + │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Symbolizer/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/Symbolizer.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Symbolizer.Point │ │ │ │ + * A symbolizer used to render point features. │ │ │ │ + */ │ │ │ │ +OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: useAGS │ │ │ │ - * {Boolean} Indicates if we are going to be accessing the ArcGIS Server (AGS) │ │ │ │ - * cache via an AGS MapServer or directly through HTTP. When accessing via │ │ │ │ - * AGS the path structure uses a standard z/y/x structure. But AGS actually │ │ │ │ - * stores the tile images on disk using a hex based folder structure that looks │ │ │ │ - * like "http://example.com/mylayer/L00/R00000000/C00000000.png". Learn more │ │ │ │ - * about this here: │ │ │ │ - * http://blogs.esri.com/Support/blogs/mappingcenter/archive/2010/08/20/Checking-Your-Local-Cache-Folders.aspx │ │ │ │ - * Defaults to true; │ │ │ │ + * APIProperty: strokeColor │ │ │ │ + * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ + * for red). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - useArcGISServer: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: type │ │ │ │ - * {String} Image type for the layer. This becomes the filename extension │ │ │ │ - * in tile requests. Default is "png" (generating a url like │ │ │ │ - * "http://example.com/mylayer/L00/R00000000/C00000000.png"). │ │ │ │ + * APIProperty: strokeOpacity │ │ │ │ + * {Number} Stroke opacity (0-1). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - type: 'png', │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: useScales │ │ │ │ - * {Boolean} Optional override to indicate that the layer should use 'scale' information │ │ │ │ - * returned from the server capabilities object instead of 'resolution' information. │ │ │ │ - * This can be important if your tile server uses an unusual DPI for the tiles. │ │ │ │ + * APIProperty: strokeWidth │ │ │ │ + * {Number} Pixel stroke width. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - useScales: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: overrideDPI │ │ │ │ - * {Boolean} Optional override to change the OpenLayers.DOTS_PER_INCH setting based │ │ │ │ - * on the tile information in the server capabilities object. This can be useful │ │ │ │ - * if your server has a non-standard DPI setting on its tiles, and you're only using │ │ │ │ - * tiles with that DPI. This value is used while OpenLayers is calculating resolution │ │ │ │ - * using scales, and is not necessary if you have resolution information. (This is │ │ │ │ - * typically the case) Regardless, this setting can be useful, but is dangerous │ │ │ │ - * because it will impact other layers while calculating resolution. Only use this │ │ │ │ - * if you know what you are doing. (See OpenLayers.Util.getResolutionFromScale) │ │ │ │ + * APIProperty: strokeLinecap │ │ │ │ + * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - overrideDPI: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.ArcGISCache │ │ │ │ - * Creates a new instance of this class │ │ │ │ + * Property: strokeDashstyle │ │ │ │ + * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ + * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ + * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ + * most SLD patterns will render correctly in OpenLayers. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * url - {String} │ │ │ │ - * options - {Object} extra layer options │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - initialize: function(name, url, options) { │ │ │ │ - OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments); │ │ │ │ - │ │ │ │ - if (this.resolutions) { │ │ │ │ - this.serverResolutions = this.resolutions; │ │ │ │ - this.maxExtent = this.getMaxExtentForResolution(this.resolutions[0]); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // this block steps through translating the values from the server layer JSON │ │ │ │ - // capabilities object into values that we can use. This is also a helpful │ │ │ │ - // reference when configuring this layer directly. │ │ │ │ - if (this.layerInfo) { │ │ │ │ - // alias the object │ │ │ │ - var info = this.layerInfo; │ │ │ │ - │ │ │ │ - // build our extents │ │ │ │ - var startingTileExtent = new OpenLayers.Bounds( │ │ │ │ - info.fullExtent.xmin, │ │ │ │ - info.fullExtent.ymin, │ │ │ │ - info.fullExtent.xmax, │ │ │ │ - info.fullExtent.ymax │ │ │ │ - ); │ │ │ │ - │ │ │ │ - // set our projection based on the given spatial reference. │ │ │ │ - // esri uses slightly different IDs, so this may not be comprehensive │ │ │ │ - this.projection = 'EPSG:' + info.spatialReference.wkid; │ │ │ │ - this.sphericalMercator = (info.spatialReference.wkid == 102100); │ │ │ │ - │ │ │ │ - // convert esri units into openlayers units (basic feet or meters only) │ │ │ │ - this.units = (info.units == "esriFeet") ? 'ft' : 'm'; │ │ │ │ - │ │ │ │ - // optional extended section based on whether or not the server returned │ │ │ │ - // specific tile information │ │ │ │ - if (!!info.tileInfo) { │ │ │ │ - // either set the tiles based on rows/columns, or specific width/height │ │ │ │ - this.tileSize = new OpenLayers.Size( │ │ │ │ - info.tileInfo.width || info.tileInfo.cols, │ │ │ │ - info.tileInfo.height || info.tileInfo.rows │ │ │ │ - ); │ │ │ │ - │ │ │ │ - // this must be set when manually configuring this layer │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat( │ │ │ │ - info.tileInfo.origin.x, │ │ │ │ - info.tileInfo.origin.y │ │ │ │ - ); │ │ │ │ - │ │ │ │ - var upperLeft = new OpenLayers.Geometry.Point( │ │ │ │ - startingTileExtent.left, │ │ │ │ - startingTileExtent.top │ │ │ │ - ); │ │ │ │ - │ │ │ │ - var bottomRight = new OpenLayers.Geometry.Point( │ │ │ │ - startingTileExtent.right, │ │ │ │ - startingTileExtent.bottom │ │ │ │ - ); │ │ │ │ - │ │ │ │ - if (this.useScales) { │ │ │ │ - this.scales = []; │ │ │ │ - } else { │ │ │ │ - this.resolutions = []; │ │ │ │ - } │ │ │ │ - │ │ │ │ - this.lods = []; │ │ │ │ - for (var key in info.tileInfo.lods) { │ │ │ │ - if (info.tileInfo.lods.hasOwnProperty(key)) { │ │ │ │ - var lod = info.tileInfo.lods[key]; │ │ │ │ - if (this.useScales) { │ │ │ │ - this.scales.push(lod.scale); │ │ │ │ - } else { │ │ │ │ - this.resolutions.push(lod.resolution); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var start = this.getContainingTileCoords(upperLeft, lod.resolution); │ │ │ │ - lod.startTileCol = start.x; │ │ │ │ - lod.startTileRow = start.y; │ │ │ │ │ │ │ │ - var end = this.getContainingTileCoords(bottomRight, lod.resolution); │ │ │ │ - lod.endTileCol = end.x; │ │ │ │ - lod.endTileRow = end.y; │ │ │ │ - this.lods.push(lod); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - this.maxExtent = this.calculateMaxExtentWithLOD(this.lods[0]); │ │ │ │ - this.serverResolutions = this.resolutions; │ │ │ │ - if (this.overrideDPI && info.tileInfo.dpi) { │ │ │ │ - // see comment above for 'overrideDPI' │ │ │ │ - OpenLayers.DOTS_PER_INCH = info.tileInfo.dpi; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getContainingTileCoords │ │ │ │ - * Calculates the x/y pixel corresponding to the position of the tile │ │ │ │ - * that contains the given point and for the for the given resolution. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * point - {<OpenLayers.Geometry.Point>} │ │ │ │ - * res - {Float} The resolution for which to compute the extent. │ │ │ │ + /** │ │ │ │ + * APIProperty: fillColor │ │ │ │ + * {String} RGB hex fill color (e.g. "#ff0000" for red). │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Pixel>} The x/y pixel corresponding to the position │ │ │ │ - * of the upper left tile for the given resolution. │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - getContainingTileCoords: function(point, res) { │ │ │ │ - return new OpenLayers.Pixel( │ │ │ │ - Math.max(Math.floor((point.x - this.tileOrigin.lon) / (this.tileSize.w * res)), 0), │ │ │ │ - Math.max(Math.floor((this.tileOrigin.lat - point.y) / (this.tileSize.h * res)), 0) │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: calculateMaxExtentWithLOD │ │ │ │ - * Given a Level of Detail object from the server, this function │ │ │ │ - * calculates the actual max extent │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * lod - {Object} a Level of Detail Object from the server capabilities object │ │ │ │ - representing a particular zoom level │ │ │ │ + /** │ │ │ │ + * APIProperty: fillOpacity │ │ │ │ + * {Number} Fill opacity (0-1). │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} The actual extent of the tiles for the given zoom level │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - calculateMaxExtentWithLOD: function(lod) { │ │ │ │ - // the max extent we're provided with just overlaps some tiles │ │ │ │ - // our real extent is the bounds of all the tiles we touch │ │ │ │ - │ │ │ │ - var numTileCols = (lod.endTileCol - lod.startTileCol) + 1; │ │ │ │ - var numTileRows = (lod.endTileRow - lod.startTileRow) + 1; │ │ │ │ - │ │ │ │ - var minX = this.tileOrigin.lon + (lod.startTileCol * this.tileSize.w * lod.resolution); │ │ │ │ - var maxX = minX + (numTileCols * this.tileSize.w * lod.resolution); │ │ │ │ - │ │ │ │ - var maxY = this.tileOrigin.lat - (lod.startTileRow * this.tileSize.h * lod.resolution); │ │ │ │ - var minY = maxY - (numTileRows * this.tileSize.h * lod.resolution); │ │ │ │ - return new OpenLayers.Bounds(minX, minY, maxX, maxY); │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: calculateMaxExtentWithExtent │ │ │ │ - * Given a 'suggested' max extent from the server, this function uses │ │ │ │ - * information about the actual tile sizes to determine the actual │ │ │ │ - * extent of the layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * extent - {<OpenLayers.Bounds>} The 'suggested' extent for the layer │ │ │ │ - * res - {Float} The resolution for which to compute the extent. │ │ │ │ + /** │ │ │ │ + * APIProperty: pointRadius │ │ │ │ + * {Number} Pixel point radius. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} The actual extent of the tiles for the given zoom level │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - calculateMaxExtentWithExtent: function(extent, res) { │ │ │ │ - var upperLeft = new OpenLayers.Geometry.Point(extent.left, extent.top); │ │ │ │ - var bottomRight = new OpenLayers.Geometry.Point(extent.right, extent.bottom); │ │ │ │ - var start = this.getContainingTileCoords(upperLeft, res); │ │ │ │ - var end = this.getContainingTileCoords(bottomRight, res); │ │ │ │ - var lod = { │ │ │ │ - resolution: res, │ │ │ │ - startTileCol: start.x, │ │ │ │ - startTileRow: start.y, │ │ │ │ - endTileCol: end.x, │ │ │ │ - endTileRow: end.y │ │ │ │ - }; │ │ │ │ - return this.calculateMaxExtentWithLOD(lod); │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getUpperLeftTileCoord │ │ │ │ - * Calculates the x/y pixel corresponding to the position │ │ │ │ - * of the upper left tile for the given resolution. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * res - {Float} The resolution for which to compute the extent. │ │ │ │ + /** │ │ │ │ + * APIProperty: externalGraphic │ │ │ │ + * {String} Url to an external graphic that will be used for rendering │ │ │ │ + * points. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Pixel>} The x/y pixel corresponding to the position │ │ │ │ - * of the upper left tile for the given resolution. │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - getUpperLeftTileCoord: function(res) { │ │ │ │ - var upperLeft = new OpenLayers.Geometry.Point( │ │ │ │ - this.maxExtent.left, │ │ │ │ - this.maxExtent.top); │ │ │ │ - return this.getContainingTileCoords(upperLeft, res); │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getLowerRightTileCoord │ │ │ │ - * Calculates the x/y pixel corresponding to the position │ │ │ │ - * of the lower right tile for the given resolution. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * res - {Float} The resolution for which to compute the extent. │ │ │ │ + /** │ │ │ │ + * APIProperty: graphicWidth │ │ │ │ + * {Number} Pixel width for sizing an external graphic. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Pixel>} The x/y pixel corresponding to the position │ │ │ │ - * of the lower right tile for the given resolution. │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - getLowerRightTileCoord: function(res) { │ │ │ │ - var bottomRight = new OpenLayers.Geometry.Point( │ │ │ │ - this.maxExtent.right, │ │ │ │ - this.maxExtent.bottom); │ │ │ │ - return this.getContainingTileCoords(bottomRight, res); │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getMaxExtentForResolution │ │ │ │ - * Since the max extent of a set of tiles can change from zoom level │ │ │ │ - * to zoom level, we need to be able to calculate that max extent │ │ │ │ - * for a given resolution. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * res - {Float} The resolution for which to compute the extent. │ │ │ │ + /** │ │ │ │ + * APIProperty: graphicHeight │ │ │ │ + * {Number} Pixel height for sizing an external graphic. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} The extent for this resolution │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - getMaxExtentForResolution: function(res) { │ │ │ │ - var start = this.getUpperLeftTileCoord(res); │ │ │ │ - var end = this.getLowerRightTileCoord(res); │ │ │ │ - │ │ │ │ - var numTileCols = (end.x - start.x) + 1; │ │ │ │ - var numTileRows = (end.y - start.y) + 1; │ │ │ │ │ │ │ │ - var minX = this.tileOrigin.lon + (start.x * this.tileSize.w * res); │ │ │ │ - var maxX = minX + (numTileCols * this.tileSize.w * res); │ │ │ │ - │ │ │ │ - var maxY = this.tileOrigin.lat - (start.y * this.tileSize.h * res); │ │ │ │ - var minY = maxY - (numTileRows * this.tileSize.h * res); │ │ │ │ - return new OpenLayers.Bounds(minX, minY, maxX, maxY); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * APIProperty: graphicOpacity │ │ │ │ + * {Number} Opacity (0-1) for an external graphic. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Returns an exact clone of this OpenLayers.Layer.ArcGISCache │ │ │ │ + /** │ │ │ │ + * APIProperty: graphicXOffset │ │ │ │ + * {Number} Pixel offset along the positive x axis for displacing an │ │ │ │ + * external graphic. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * [obj] - {Object} optional object to assign the cloned instance to. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.ArcGISCache>} clone of this instance │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.ArcGISCache(this.name, this.url, this.options); │ │ │ │ - } │ │ │ │ - return OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: initGriddedTiles │ │ │ │ + * APIProperty: graphicYOffset │ │ │ │ + * {Number} Pixel offset along the positive y axis for displacing an │ │ │ │ + * external graphic. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - initGriddedTiles: function(bounds) { │ │ │ │ - delete this._tileOrigin; │ │ │ │ - OpenLayers.Layer.XYZ.prototype.initGriddedTiles.apply(this, arguments); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getMaxExtent │ │ │ │ - * Get this layer's maximum extent. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} │ │ │ │ + * APIProperty: rotation │ │ │ │ + * {Number} The rotation of a graphic in the clockwise direction about its │ │ │ │ + * center point (or any point off center as specified by │ │ │ │ + * <graphicXOffset> and <graphicYOffset>). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - getMaxExtent: function() { │ │ │ │ - var resolution = this.map.getResolution(); │ │ │ │ - return this.maxExtent = this.getMaxExtentForResolution(resolution); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getTileOrigin │ │ │ │ - * Determine the origin for aligning the grid of tiles. │ │ │ │ - * The origin will be derived from the layer's <maxExtent> property. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.LonLat>} The tile origin. │ │ │ │ + * APIProperty: graphicName │ │ │ │ + * {String} Named graphic to use when rendering points. Supported values │ │ │ │ + * include "circle", "square", "star", "x", "cross", and "triangle". │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - getTileOrigin: function() { │ │ │ │ - if (!this._tileOrigin) { │ │ │ │ - var extent = this.getMaxExtent(); │ │ │ │ - this._tileOrigin = new OpenLayers.LonLat(extent.left, extent.bottom); │ │ │ │ - } │ │ │ │ - return this._tileOrigin; │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getURL │ │ │ │ - * Determine the URL for a tile given the tile bounds. This is should support │ │ │ │ - * urls that access tiles through an ArcGIS Server MapServer or directly through │ │ │ │ - * the hex folder structure using HTTP. Just be sure to set the useArcGISServer │ │ │ │ - * property appropriately! This is basically the same as │ │ │ │ - * 'OpenLayers.Layer.TMS.getURL', but with the addition of hex addressing, │ │ │ │ - * and tile rounding. │ │ │ │ + * Constructor: OpenLayers.Symbolizer.Point │ │ │ │ + * Create a symbolizer for rendering points. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ + * construction. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} The URL for a tile based on given bounds. │ │ │ │ + * A new point symbolizer. │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - var res = this.getResolution(); │ │ │ │ - │ │ │ │ - // tile center │ │ │ │ - var originTileX = (this.tileOrigin.lon + (res * this.tileSize.w / 2)); │ │ │ │ - var originTileY = (this.tileOrigin.lat - (res * this.tileSize.h / 2)); │ │ │ │ - │ │ │ │ - var center = bounds.getCenterLonLat(); │ │ │ │ - var point = { │ │ │ │ - x: center.lon, │ │ │ │ - y: center.lat │ │ │ │ - }; │ │ │ │ - var x = (Math.round(Math.abs((center.lon - originTileX) / (res * this.tileSize.w)))); │ │ │ │ - var y = (Math.round(Math.abs((originTileY - center.lat) / (res * this.tileSize.h)))); │ │ │ │ - var z = this.map.getZoom(); │ │ │ │ - │ │ │ │ - // this prevents us from getting pink tiles (non-existant tiles) │ │ │ │ - if (this.lods) { │ │ │ │ - var lod = this.lods[this.map.getZoom()]; │ │ │ │ - if ((x < lod.startTileCol || x > lod.endTileCol) || │ │ │ │ - (y < lod.startTileRow || y > lod.endTileRow)) { │ │ │ │ - return null; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - var start = this.getUpperLeftTileCoord(res); │ │ │ │ - var end = this.getLowerRightTileCoord(res); │ │ │ │ - if ((x < start.x || x >= end.x) || │ │ │ │ - (y < start.y || y >= end.y)) { │ │ │ │ - return null; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // Construct the url string │ │ │ │ - var url = this.url; │ │ │ │ - var s = '' + x + y + z; │ │ │ │ - │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(s, url); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // Accessing tiles through ArcGIS Server uses a different path │ │ │ │ - // structure than direct access via the folder structure. │ │ │ │ - if (this.useArcGISServer) { │ │ │ │ - // AGS MapServers have pretty url access to tiles │ │ │ │ - url = url + '/tile/${z}/${y}/${x}'; │ │ │ │ - } else { │ │ │ │ - // The tile images are stored using hex values on disk. │ │ │ │ - x = 'C' + OpenLayers.Number.zeroPad(x, 8, 16); │ │ │ │ - y = 'R' + OpenLayers.Number.zeroPad(y, 8, 16); │ │ │ │ - z = 'L' + OpenLayers.Number.zeroPad(z, 2, 10); │ │ │ │ - url = url + '/${z}/${y}/${x}.' + this.type; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // Write the values into our formatted url │ │ │ │ - url = OpenLayers.String.format(url, { │ │ │ │ - 'x': x, │ │ │ │ - 'y': y, │ │ │ │ - 'z': z │ │ │ │ - }); │ │ │ │ - │ │ │ │ - return OpenLayers.Util.urlAppend( │ │ │ │ - url, OpenLayers.Util.getParameterString(this.params) │ │ │ │ - ); │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: 'OpenLayers.Layer.ArcGISCache' │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Point" │ │ │ │ + │ │ │ │ }); │ │ │ │ + │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/Bing.js │ │ │ │ + OpenLayers/Symbolizer/Line.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 │ │ │ │ + * @requires OpenLayers/Symbolizer.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> │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Symbolizer.Line │ │ │ │ + * A symbolizer used to render line features. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ +OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: key │ │ │ │ - * {String} API key for Bing maps, get your own key │ │ │ │ - * at http://bingmapsportal.com/ . │ │ │ │ + * APIProperty: strokeColor │ │ │ │ + * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ + * for red). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - key: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: serverResolutions │ │ │ │ - * {Array} the resolutions provided by the Bing servers. │ │ │ │ + * APIProperty: strokeOpacity │ │ │ │ + * {Number} Stroke opacity (0-1). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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} │ │ │ │ + * APIProperty: strokeWidth │ │ │ │ + * {Number} Pixel stroke width. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + * APIProperty: strokeLinecap │ │ │ │ + * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - metadata: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: protocolRegex │ │ │ │ - * {RegExp} Regular expression to match and replace http: in bing urls │ │ │ │ + * Property: strokeDashstyle │ │ │ │ + * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ + * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ + * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ + * most SLD patterns will render correctly in OpenLayers. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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". │ │ │ │ + * Constructor: OpenLayers.Symbolizer.Line │ │ │ │ + * Create a symbolizer for rendering lines. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ + * construction. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * A new line symbolizer. │ │ │ │ */ │ │ │ │ - type: "Road", │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Line" │ │ │ │ + │ │ │ │ +}); │ │ │ │ + │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Symbolizer/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/Symbolizer.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Symbolizer.Polygon │ │ │ │ + * A symbolizer used to render line features. │ │ │ │ + */ │ │ │ │ +OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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". │ │ │ │ + * APIProperty: strokeColor │ │ │ │ + * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ + * for red). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + * APIProperty: strokeOpacity │ │ │ │ + * {Number} Stroke opacity (0-1). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - metadataParams: null, │ │ │ │ │ │ │ │ - /** APIProperty: tileOptions │ │ │ │ - * {Object} optional configuration options for <OpenLayers.Tile> instances │ │ │ │ - * created by this Layer. Default is │ │ │ │ - * │ │ │ │ - * (code) │ │ │ │ - * {crossOriginKeyword: 'anonymous'} │ │ │ │ - * (end) │ │ │ │ + /** │ │ │ │ + * APIProperty: strokeWidth │ │ │ │ + * {Number} Pixel stroke width. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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:'. │ │ │ │ + /** │ │ │ │ + * APIProperty: strokeLinecap │ │ │ │ + * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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. │ │ │ │ + * Property: strokeDashstyle │ │ │ │ + * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ + * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ + * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ + * most SLD patterns will render correctly in OpenLayers. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * APIProperty: fillColor │ │ │ │ + * {String} RGB hex fill color (e.g. "#ff0000" for red). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: loadMetadata │ │ │ │ + * APIProperty: fillOpacity │ │ │ │ + * {Number} Fill opacity (0-1). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + * Constructor: OpenLayers.Symbolizer.Polygon │ │ │ │ + * Create a symbolizer for rendering polygons. │ │ │ │ * │ │ │ │ - * Sets layer properties according to the metadata provided by the API │ │ │ │ + * Parameters: │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ + * construction. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * A new polygon symbolizer. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getURL │ │ │ │ - * │ │ │ │ - * Paramters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Polygon" │ │ │ │ + │ │ │ │ +}); │ │ │ │ + │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Symbolizer/Text.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/Symbolizer.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Symbolizer.Text │ │ │ │ + * A symbolizer used to render text labels for features. │ │ │ │ + */ │ │ │ │ +OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: label │ │ │ │ + * {String} The text for the label. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * APIProperty: fontFamily │ │ │ │ + * {String} The font family for the label. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: updateAttribution │ │ │ │ - * Updates the attribution according to the requirements outlined in │ │ │ │ - * http://gis.638310.n2.nabble.com/Bing-imagery-td5789168.html │ │ │ │ + /** │ │ │ │ + * APIProperty: fontSize │ │ │ │ + * {String} The font size for the label. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + /** │ │ │ │ + * APIProperty: fontWeight │ │ │ │ + * {String} The font weight for the label. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - setMap: function() { │ │ │ │ - OpenLayers.Layer.XYZ.prototype.setMap.apply(this, arguments); │ │ │ │ - this.map.events.register("moveend", this, this.updateAttribution); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * obj - {Object} │ │ │ │ + * Property: fontStyle │ │ │ │ + * {String} The font style for the label. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.Bing>} An exact clone of this <OpenLayers.Layer.Bing> │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + * Constructor: OpenLayers.Symbolizer.Text │ │ │ │ + * Create a symbolizer for rendering text labels. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ + * construction. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * A new text symbolizer. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - this.map && │ │ │ │ - this.map.events.unregister("moveend", this, this.updateAttribution); │ │ │ │ - OpenLayers.Layer.XYZ.prototype.destroy.apply(this, arguments); │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Bing" │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Text" │ │ │ │ + │ │ │ │ }); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * 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/Layer/SphericalMercator.js │ │ │ │ + OpenLayers/Symbolizer/Raster.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/Projection.js │ │ │ │ + * @requires OpenLayers/Symbolizer.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.SphericalMercator │ │ │ │ - * A mixin for layers that wraps up the pieces neccesary to have a coordinate │ │ │ │ - * conversion for working with commercial APIs which use a spherical │ │ │ │ - * mercator projection. Using this layer as a base layer, additional │ │ │ │ - * layers can be used as overlays if they are in the same projection. │ │ │ │ - * │ │ │ │ - * A layer is given properties of this object by setting the sphericalMercator │ │ │ │ - * property to true. │ │ │ │ - * │ │ │ │ - * More projection information: │ │ │ │ - * - http://spatialreference.org/ref/user/google-projection/ │ │ │ │ - * │ │ │ │ - * Proj4 Text: │ │ │ │ - * +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 │ │ │ │ - * +k=1.0 +units=m +nadgrids=@null +no_defs │ │ │ │ - * │ │ │ │ - * WKT: │ │ │ │ - * 900913=PROJCS["WGS84 / Simple Mercator", GEOGCS["WGS 84", │ │ │ │ - * DATUM["WGS_1984", SPHEROID["WGS_1984", 6378137.0, 298.257223563]], │ │ │ │ - * PRIMEM["Greenwich", 0.0], UNIT["degree", 0.017453292519943295], │ │ │ │ - * AXIS["Longitude", EAST], AXIS["Latitude", NORTH]], │ │ │ │ - * PROJECTION["Mercator_1SP_Google"], │ │ │ │ - * PARAMETER["latitude_of_origin", 0.0], PARAMETER["central_meridian", 0.0], │ │ │ │ - * PARAMETER["scale_factor", 1.0], PARAMETER["false_easting", 0.0], │ │ │ │ - * PARAMETER["false_northing", 0.0], UNIT["m", 1.0], AXIS["x", EAST], │ │ │ │ - * AXIS["y", NORTH], AUTHORITY["EPSG","900913"]] │ │ │ │ + * Class: OpenLayers.Symbolizer.Raster │ │ │ │ + * A symbolizer used to render raster images. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.SphericalMercator = { │ │ │ │ +OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getExtent │ │ │ │ - * Get the map's extent. │ │ │ │ + * Constructor: OpenLayers.Symbolizer.Raster │ │ │ │ + * Create a symbolizer for rendering rasters. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ + * construction. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} The map extent. │ │ │ │ + * A new raster symbolizer. │ │ │ │ */ │ │ │ │ - getExtent: function() { │ │ │ │ - var extent = null; │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - extent = this.map.calculateBounds(); │ │ │ │ - } else { │ │ │ │ - extent = OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this); │ │ │ │ - } │ │ │ │ - return extent; │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Raster" │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Style2.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/Rule.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Point.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Line.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Polygon.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Text.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Raster.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Style2 │ │ │ │ + * This class represents a collection of rules for rendering features. │ │ │ │ + */ │ │ │ │ +OpenLayers.Style2 = OpenLayers.Class({ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: getLonLatFromViewPortPx │ │ │ │ - * Get a map location from a pixel location │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * viewPortPx - {<OpenLayers.Pixel>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view │ │ │ │ - * port OpenLayers.Pixel, translated into lon/lat by map lib │ │ │ │ - * If the map lib is not loaded or not centered, returns null │ │ │ │ + * Property: id │ │ │ │ + * {String} A unique id for this session. │ │ │ │ */ │ │ │ │ - getLonLatFromViewPortPx: function(viewPortPx) { │ │ │ │ - return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + id: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getViewPortPxFromLonLat │ │ │ │ - * Get a pixel location from a map location │ │ │ │ + * APIProperty: name │ │ │ │ + * {String} Style identifier. │ │ │ │ + */ │ │ │ │ + name: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: title │ │ │ │ + * {String} Title of this style. │ │ │ │ + */ │ │ │ │ + title: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: description │ │ │ │ + * {String} Description of this style. │ │ │ │ + */ │ │ │ │ + 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, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: rules │ │ │ │ + * {Array(<OpenLayers.Rule>)} Collection of rendering rules. │ │ │ │ + */ │ │ │ │ + rules: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Style2 │ │ │ │ + * Creates a style representing a collection of rendering rules. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * lonlat - {<OpenLayers.LonLat>} │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ + * style. Any documented properties may be set at construction. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in │ │ │ │ - * OpenLayers.LonLat, translated into view port pixels by map lib │ │ │ │ - * If map lib is not loaded or not centered, returns null │ │ │ │ + * {<OpenLayers.Style2>} A new style object. │ │ │ │ */ │ │ │ │ - getViewPortPxFromLonLat: function(lonlat) { │ │ │ │ - return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this, arguments); │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Util.extend(this, config); │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: initMercatorParameters │ │ │ │ - * Set up the mercator parameters on the layer: resolutions, │ │ │ │ - * projection, units. │ │ │ │ + * APIMethod: destroy │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ */ │ │ │ │ - initMercatorParameters: function() { │ │ │ │ - // set up properties for Mercator - assume EPSG:900913 │ │ │ │ - this.RESOLUTIONS = []; │ │ │ │ - var maxResolution = 156543.03390625; │ │ │ │ - for (var zoom = 0; zoom <= this.MAX_ZOOM_LEVEL; ++zoom) { │ │ │ │ - this.RESOLUTIONS[zoom] = maxResolution / Math.pow(2, zoom); │ │ │ │ + destroy: function() { │ │ │ │ + for (var i = 0, len = this.rules.length; i < len; i++) { │ │ │ │ + this.rules[i].destroy(); │ │ │ │ } │ │ │ │ - this.units = "m"; │ │ │ │ - this.projection = this.projection || "EPSG:900913"; │ │ │ │ + delete this.rules; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: forwardMercator │ │ │ │ - * Given a lon,lat in EPSG:4326, return a point in Spherical Mercator. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * lon - {float} │ │ │ │ - * lat - {float} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.LonLat>} The coordinates transformed to Mercator. │ │ │ │ - */ │ │ │ │ - forwardMercator: (function() { │ │ │ │ - var gg = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ - var sm = new OpenLayers.Projection("EPSG:900913"); │ │ │ │ - return function(lon, lat) { │ │ │ │ - var point = OpenLayers.Projection.transform({ │ │ │ │ - x: lon, │ │ │ │ - y: lat │ │ │ │ - }, gg, sm); │ │ │ │ - return new OpenLayers.LonLat(point.x, point.y); │ │ │ │ - }; │ │ │ │ - })(), │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: inverseMercator │ │ │ │ - * Given a x,y in Spherical Mercator, return a point in EPSG:4326. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * x - {float} A map x in Spherical Mercator. │ │ │ │ - * y - {float} A map y in Spherical Mercator. │ │ │ │ + * APIMethod: clone │ │ │ │ + * Clones this style. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.LonLat>} The coordinates transformed to EPSG:4326. │ │ │ │ + * {<OpenLayers.Style2>} Clone of this style. │ │ │ │ */ │ │ │ │ - inverseMercator: (function() { │ │ │ │ - var gg = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ - var sm = new OpenLayers.Projection("EPSG:900913"); │ │ │ │ - return function(x, y) { │ │ │ │ - var point = OpenLayers.Projection.transform({ │ │ │ │ - x: x, │ │ │ │ - y: y │ │ │ │ - }, sm, gg); │ │ │ │ - return new OpenLayers.LonLat(point.x, point.y); │ │ │ │ - }; │ │ │ │ - })() │ │ │ │ + clone: function() { │ │ │ │ + var config = OpenLayers.Util.extend({}, this); │ │ │ │ + // clone rules │ │ │ │ + if (this.rules) { │ │ │ │ + config.rules = []; │ │ │ │ + for (var i = 0, len = this.rules.length; i < len; ++i) { │ │ │ │ + config.rules.push(this.rules[i].clone()); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return new OpenLayers.Style2(config); │ │ │ │ + }, │ │ │ │ │ │ │ │ -}; │ │ │ │ + CLASS_NAME: "OpenLayers.Style2" │ │ │ │ +}); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/EventPane.js │ │ │ │ + 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/Layer.js │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.EventPane │ │ │ │ - * Base class for 3rd party layers, providing a DOM element which isolates │ │ │ │ - * the 3rd-party layer from mouse events. │ │ │ │ - * Only used by Google layers. │ │ │ │ - * │ │ │ │ - * Automatically instantiated by the Google constructor, and not usually instantiated directly. │ │ │ │ - * │ │ │ │ - * Create a new event pane layer with the │ │ │ │ - * <OpenLayers.Layer.EventPane> constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer> │ │ │ │ + * Class: OpenLayers.Protocol │ │ │ │ + * Abstract vector layer protocol class. Not to be instantiated directly. Use │ │ │ │ + * one of the protocol subclasses instead. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.EventPane = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ +OpenLayers.Protocol = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: smoothDragPan │ │ │ │ - * {Boolean} smoothDragPan determines whether non-public/internal API │ │ │ │ - * methods are used for better performance while dragging EventPane │ │ │ │ - * layers. When not in sphericalMercator mode, the smoother dragging │ │ │ │ - * doesn't actually move north/south directly with the number of │ │ │ │ - * pixels moved, resulting in a slight offset when you drag your mouse │ │ │ │ - * north south with this option on. If this visual disparity bothers │ │ │ │ - * you, you should turn this option off, or use spherical mercator. │ │ │ │ - * Default is on. │ │ │ │ + * Property: format │ │ │ │ + * {<OpenLayers.Format>} The format used by this protocol. │ │ │ │ */ │ │ │ │ - smoothDragPan: true, │ │ │ │ + format: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: isBaseLayer │ │ │ │ - * {Boolean} EventPaned layers are always base layers, by necessity. │ │ │ │ + * Property: options │ │ │ │ + * {Object} Any options sent to the constructor. │ │ │ │ */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + options: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: isFixed │ │ │ │ - * {Boolean} EventPaned layers are fixed by default. │ │ │ │ + * Property: autoDestroy │ │ │ │ + * {Boolean} The creator of the protocol can set autoDestroy to false │ │ │ │ + * to fully control when the protocol is destroyed. Defaults to │ │ │ │ + * true. │ │ │ │ */ │ │ │ │ - isFixed: true, │ │ │ │ + autoDestroy: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: pane │ │ │ │ - * {DOMElement} A reference to the element that controls the events. │ │ │ │ + * Property: defaultFilter │ │ │ │ + * {<OpenLayers.Filter>} Optional default filter to read requests │ │ │ │ */ │ │ │ │ - pane: null, │ │ │ │ - │ │ │ │ + defaultFilter: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: mapObject │ │ │ │ - * {Object} This is the object which will be used to load the 3rd party library │ │ │ │ - * in the case of the google layer, this will be of type GMap, │ │ │ │ - * in the case of the ve layer, this will be of type VEMap │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - mapObject: null, │ │ │ │ - │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + this.options = options; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.EventPane │ │ │ │ - * Create a new event pane layer │ │ │ │ + * Method: mergeWithDefaultFilter │ │ │ │ + * Merge filter passed to the read method with the default one │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ + * filter - {<OpenLayers.Filter>} │ │ │ │ */ │ │ │ │ - initialize: function(name, options) { │ │ │ │ - OpenLayers.Layer.prototype.initialize.apply(this, arguments); │ │ │ │ - if (this.pane == null) { │ │ │ │ - this.pane = OpenLayers.Util.createDiv(this.div.id + "_EventPane"); │ │ │ │ + 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 │ │ │ │ - * Deconstruct this layer. │ │ │ │ + * Clean up the protocol. │ │ │ │ */ │ │ │ │ destroy: function() { │ │ │ │ - this.mapObject = null; │ │ │ │ - this.pane = null; │ │ │ │ - OpenLayers.Layer.prototype.destroy.apply(this, arguments); │ │ │ │ + this.options = null; │ │ │ │ + this.format = null; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: read │ │ │ │ + * Construct a request for reading new features. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.prototype.setMap.apply(this, arguments); │ │ │ │ - │ │ │ │ - this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1; │ │ │ │ - this.pane.style.display = this.div.style.display; │ │ │ │ - this.pane.style.width = "100%"; │ │ │ │ - this.pane.style.height = "100%"; │ │ │ │ - if (OpenLayers.BROWSER_NAME == "msie") { │ │ │ │ - this.pane.style.background = │ │ │ │ - "url(" + OpenLayers.Util.getImageLocation("blank.gif") + ")"; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.isFixed) { │ │ │ │ - this.map.viewPortDiv.appendChild(this.pane); │ │ │ │ - } else { │ │ │ │ - this.map.layerContainerDiv.appendChild(this.pane); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // once our layer has been added to the map, we can load it │ │ │ │ - this.loadMapObject(); │ │ │ │ - │ │ │ │ - // if map didn't load, display warning │ │ │ │ - if (this.mapObject == null) { │ │ │ │ - this.loadWarningMessage(); │ │ │ │ - } │ │ │ │ + read: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + options.filter = this.mergeWithDefaultFilter(options.filter); │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * APIMethod: removeMap │ │ │ │ - * On being removed from the map, we'll like to remove the invisible 'pane' │ │ │ │ - * div that we added to it on creation. │ │ │ │ - * │ │ │ │ + * APIMethod: create │ │ │ │ + * Construct a request for writing newly created features. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - removeMap: function(map) { │ │ │ │ - if (this.pane && this.pane.parentNode) { │ │ │ │ - this.pane.parentNode.removeChild(this.pane); │ │ │ │ - } │ │ │ │ - OpenLayers.Layer.prototype.removeMap.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + create: function() {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: loadWarningMessage │ │ │ │ - * If we can't load the map lib, then display an error message to the │ │ │ │ - * user and tell them where to go for help. │ │ │ │ - * │ │ │ │ - * This function sets up the layout for the warning message. Each 3rd │ │ │ │ - * party layer must implement its own getWarningHTML() function to │ │ │ │ - * provide the actual warning message. │ │ │ │ - */ │ │ │ │ - loadWarningMessage: function() { │ │ │ │ - │ │ │ │ - this.div.style.backgroundColor = "darkblue"; │ │ │ │ - │ │ │ │ - var viewSize = this.map.getSize(); │ │ │ │ - │ │ │ │ - var msgW = Math.min(viewSize.w, 300); │ │ │ │ - var msgH = Math.min(viewSize.h, 200); │ │ │ │ - var size = new OpenLayers.Size(msgW, msgH); │ │ │ │ - │ │ │ │ - var centerPx = new OpenLayers.Pixel(viewSize.w / 2, viewSize.h / 2); │ │ │ │ - │ │ │ │ - var topLeft = centerPx.add(-size.w / 2, -size.h / 2); │ │ │ │ - │ │ │ │ - var div = OpenLayers.Util.createDiv(this.name + "_warning", │ │ │ │ - topLeft, │ │ │ │ - size, │ │ │ │ - null, │ │ │ │ - null, │ │ │ │ - null, │ │ │ │ - "auto"); │ │ │ │ - │ │ │ │ - div.style.padding = "7px"; │ │ │ │ - div.style.backgroundColor = "yellow"; │ │ │ │ - │ │ │ │ - div.innerHTML = this.getWarningHTML(); │ │ │ │ - this.div.appendChild(div); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getWarningHTML │ │ │ │ - * To be implemented by subclasses. │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * {String} String with information on why layer is broken, how to get │ │ │ │ - * it working. │ │ │ │ + * {<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. │ │ │ │ */ │ │ │ │ - getWarningHTML: function() { │ │ │ │ - //should be implemented by subclasses │ │ │ │ - return ""; │ │ │ │ - }, │ │ │ │ + update: function() {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: display │ │ │ │ - * Set the display on the pane │ │ │ │ + * APIMethod: delete │ │ │ │ + * Construct a request deleting a removed feature. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * display - {Boolean} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - display: function(display) { │ │ │ │ - OpenLayers.Layer.prototype.display.apply(this, arguments); │ │ │ │ - this.pane.style.display = this.div.style.display; │ │ │ │ - }, │ │ │ │ + "delete": function() {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setZIndex │ │ │ │ - * Set the z-index order for the pane. │ │ │ │ - * │ │ │ │ + * APIMethod: commit │ │ │ │ + * Go over the features and for each take action │ │ │ │ + * based on the feature state. Possible actions are create, │ │ │ │ + * update and delete. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * zIndex - {int} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - setZIndex: function(zIndex) { │ │ │ │ - OpenLayers.Layer.prototype.setZIndex.apply(this, arguments); │ │ │ │ - this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1; │ │ │ │ - }, │ │ │ │ + commit: function() {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: moveByPx │ │ │ │ - * Move the layer based on pixel vector. To be implemented by subclasses. │ │ │ │ + * Method: abort │ │ │ │ + * Abort an ongoing request. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * dx - {Number} The x coord of the displacement vector. │ │ │ │ - * dy - {Number} The y coord of the displacement vector. │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} │ │ │ │ */ │ │ │ │ - moveByPx: function(dx, dy) { │ │ │ │ - OpenLayers.Layer.prototype.moveByPx.apply(this, arguments); │ │ │ │ - │ │ │ │ - if (this.dragPanMapObject) { │ │ │ │ - this.dragPanMapObject(dx, -dy); │ │ │ │ - } else { │ │ │ │ - this.moveTo(this.map.getCachedCenter()); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + abort: function(response) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: moveTo │ │ │ │ - * Handle calls to move the layer. │ │ │ │ - * │ │ │ │ + * Method: createCallback │ │ │ │ + * Returns a function that applies the given public method with resp and │ │ │ │ + * options arguments. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - * zoomChanged - {Boolean} │ │ │ │ - * dragging - {Boolean} │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ + createCallback: function(method, response, options) { │ │ │ │ + return OpenLayers.Function.bind(function() { │ │ │ │ + method.apply(this, [response, options]); │ │ │ │ + }, this); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (this.mapObject != null) { │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol" │ │ │ │ +}); │ │ │ │ │ │ │ │ - var newCenter = this.map.getCenter(); │ │ │ │ - var newZoom = this.map.getZoom(); │ │ │ │ +/** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - if (newCenter != null) { │ │ │ │ + /** │ │ │ │ + * Property: requestType │ │ │ │ + * {String} The type of request this response corresponds to. Either │ │ │ │ + * "create", "read", "update" or "delete". │ │ │ │ + */ │ │ │ │ + requestType: null, │ │ │ │ │ │ │ │ - var moOldCenter = this.getMapObjectCenter(); │ │ │ │ - var oldCenter = this.getOLLonLatFromMapObjectLonLat(moOldCenter); │ │ │ │ + /** │ │ │ │ + * Property: last │ │ │ │ + * {Boolean} - true if this is the last response expected in a commit, │ │ │ │ + * false otherwise, defaults to true. │ │ │ │ + */ │ │ │ │ + last: true, │ │ │ │ │ │ │ │ - var moOldZoom = this.getMapObjectZoom(); │ │ │ │ - var oldZoom = this.getOLZoomFromMapObjectZoom(moOldZoom); │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - if (!(newCenter.equals(oldCenter)) || newZoom != oldZoom) { │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - if (!zoomChanged && oldCenter && this.dragPanMapObject && │ │ │ │ - this.smoothDragPan) { │ │ │ │ - var oldPx = this.map.getViewPortPxFromLonLat(oldCenter); │ │ │ │ - var newPx = this.map.getViewPortPxFromLonLat(newCenter); │ │ │ │ - this.dragPanMapObject(newPx.x - oldPx.x, oldPx.y - newPx.y); │ │ │ │ - } else { │ │ │ │ - var center = this.getMapObjectLonLatFromOLLonLat(newCenter); │ │ │ │ - var zoom = this.getMapObjectZoomFromOLZoom(newZoom); │ │ │ │ - this.setMapObjectCenter(center, zoom, dragging); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - /********************************************************/ │ │ │ │ - /* */ │ │ │ │ - /* Baselayer Functions */ │ │ │ │ - /* */ │ │ │ │ - /********************************************************/ │ │ │ │ + /** │ │ │ │ + * Property: error │ │ │ │ + * {Object} The error object in case a service exception was encountered. │ │ │ │ + */ │ │ │ │ + error: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getLonLatFromViewPortPx │ │ │ │ - * Get a map location from a pixel location │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * viewPortPx - {<OpenLayers.Pixel>} │ │ │ │ + * Constructor: OpenLayers.Protocol.Response │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view │ │ │ │ - * port OpenLayers.Pixel, translated into lon/lat by map lib │ │ │ │ - * If the map lib is not loaded or not centered, returns null │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - getLonLatFromViewPortPx: function(viewPortPx) { │ │ │ │ - var lonlat = null; │ │ │ │ - if ((this.mapObject != null) && │ │ │ │ - (this.getMapObjectCenter() != null)) { │ │ │ │ - var moPixel = this.getMapObjectPixelFromOLPixel(viewPortPx); │ │ │ │ - var moLonLat = this.getMapObjectLonLatFromMapObjectPixel(moPixel); │ │ │ │ - lonlat = this.getOLLonLatFromMapObjectLonLat(moLonLat); │ │ │ │ - } │ │ │ │ - return lonlat; │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: getViewPortPxFromLonLat │ │ │ │ - * Get a pixel location from a map location │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * lonlat - {<OpenLayers.LonLat>} │ │ │ │ + * Method: success │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in │ │ │ │ - * OpenLayers.LonLat, translated into view port pixels by map lib │ │ │ │ - * If map lib is not loaded or not centered, returns null │ │ │ │ + * {Boolean} - true on success, false otherwise │ │ │ │ */ │ │ │ │ - getViewPortPxFromLonLat: function(lonlat) { │ │ │ │ - var viewPortPx = null; │ │ │ │ - if ((this.mapObject != null) && │ │ │ │ - (this.getMapObjectCenter() != null)) { │ │ │ │ + success: function() { │ │ │ │ + return this.code > 0; │ │ │ │ + }, │ │ │ │ │ │ │ │ - var moLonLat = this.getMapObjectLonLatFromOLLonLat(lonlat); │ │ │ │ - var moPixel = this.getMapObjectPixelFromMapObjectLonLat(moLonLat); │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.Response" │ │ │ │ +}); │ │ │ │ │ │ │ │ - viewPortPx = this.getOLPixelFromMapObjectPixel(moPixel); │ │ │ │ - } │ │ │ │ - return viewPortPx; │ │ │ │ - }, │ │ │ │ +OpenLayers.Protocol.Response.SUCCESS = 1; │ │ │ │ +OpenLayers.Protocol.Response.FAILURE = 0; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/StyleMap.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /********************************************************/ │ │ │ │ - /* */ │ │ │ │ - /* Translation Functions */ │ │ │ │ - /* */ │ │ │ │ - /* The following functions translate Map Object and */ │ │ │ │ - /* OL formats for Pixel, LonLat */ │ │ │ │ - /* */ │ │ │ │ - /********************************************************/ │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - // │ │ │ │ - // TRANSLATION: MapObject LatLng <-> OpenLayers.LonLat │ │ │ │ - // │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ + * @requires OpenLayers/Style.js │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.StyleMap │ │ │ │ + */ │ │ │ │ +OpenLayers.StyleMap = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getOLLonLatFromMapObjectLonLat │ │ │ │ - * Get an OL style map location from a 3rd party style map location │ │ │ │ - * │ │ │ │ - * Parameters │ │ │ │ - * moLonLat - {Object} │ │ │ │ + * 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 │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.LonLat>} An OpenLayers.LonLat, translated from the passed in │ │ │ │ - * MapObject LonLat │ │ │ │ - * Returns null if null value is passed in │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - getOLLonLatFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - var olLonLat = null; │ │ │ │ - if (moLonLat != null) { │ │ │ │ - var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); │ │ │ │ - var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); │ │ │ │ - olLonLat = new OpenLayers.LonLat(lon, lat); │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - return olLonLat; │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getMapObjectLonLatFromOLLonLat │ │ │ │ - * Get a 3rd party map location from an OL map location. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * olLonLat - {<OpenLayers.LonLat>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} A MapObject LonLat, translated from the passed in │ │ │ │ - * OpenLayers.LonLat │ │ │ │ - * Returns null if null value is passed in │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - getMapObjectLonLatFromOLLonLat: function(olLonLat) { │ │ │ │ - var moLatLng = null; │ │ │ │ - if (olLonLat != null) { │ │ │ │ - moLatLng = this.getMapObjectLonLatFromLonLat(olLonLat.lon, │ │ │ │ - olLonLat.lat); │ │ │ │ + destroy: function() { │ │ │ │ + for (var key in this.styles) { │ │ │ │ + this.styles[key].destroy(); │ │ │ │ } │ │ │ │ - return moLatLng; │ │ │ │ + this.styles = null; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ - // │ │ │ │ - // TRANSLATION: MapObject Pixel <-> OpenLayers.Pixel │ │ │ │ - // │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: getOLPixelFromMapObjectPixel │ │ │ │ - * Get an OL pixel location from a 3rd party pixel location. │ │ │ │ - * │ │ │ │ + * Method: createSymbolizer │ │ │ │ + * Creates the symbolizer for a feature for a render intent. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * moPixel - {Object} │ │ │ │ + * 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: │ │ │ │ - * {<OpenLayers.Pixel>} An OpenLayers.Pixel, translated from the passed in │ │ │ │ - * MapObject Pixel │ │ │ │ - * Returns null if null value is passed in │ │ │ │ + * {Object} symbolizer hash │ │ │ │ */ │ │ │ │ - getOLPixelFromMapObjectPixel: function(moPixel) { │ │ │ │ - var olPixel = null; │ │ │ │ - if (moPixel != null) { │ │ │ │ - var x = this.getXFromMapObjectPixel(moPixel); │ │ │ │ - var y = this.getYFromMapObjectPixel(moPixel); │ │ │ │ - olPixel = new OpenLayers.Pixel(x, y); │ │ │ │ + createSymbolizer: function(feature, intent) { │ │ │ │ + if (!feature) { │ │ │ │ + feature = new OpenLayers.Feature.Vector(); │ │ │ │ } │ │ │ │ - return olPixel; │ │ │ │ + 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: getMapObjectPixelFromOLPixel │ │ │ │ - * Get a 3rd party pixel location from an OL pixel location │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * olPixel - {<OpenLayers.Pixel>} │ │ │ │ + * 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 │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Object} A MapObject Pixel, translated from the passed in │ │ │ │ - * OpenLayers.Pixel │ │ │ │ - * Returns null if null value is passed in │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - getMapObjectPixelFromOLPixel: function(olPixel) { │ │ │ │ - var moPixel = null; │ │ │ │ - if (olPixel != null) { │ │ │ │ - moPixel = this.getMapObjectPixelFromXY(olPixel.x, olPixel.y); │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + })); │ │ │ │ } │ │ │ │ - return moPixel; │ │ │ │ + this.styles[renderIntent].addRules(rules); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.EventPane" │ │ │ │ + CLASS_NAME: "OpenLayers.StyleMap" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/FixedZoomLevels.js │ │ │ │ + OpenLayers/Tile/UTFGrid.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/Tile.js │ │ │ │ + * @requires OpenLayers/Format/JSON.js │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.FixedZoomLevels │ │ │ │ - * Some Layers will already have established zoom levels (like google │ │ │ │ - * or ve). Instead of trying to determine them and populate a resolutions[] │ │ │ │ - * Array with those values, we will hijack the resolution functionality │ │ │ │ - * here. │ │ │ │ - * │ │ │ │ - * When you subclass FixedZoomLevels: │ │ │ │ - * │ │ │ │ - * The initResolutions() call gets nullified, meaning no resolutions[] array │ │ │ │ - * is set up. Which would be a big problem getResolution() in Layer, since │ │ │ │ - * it merely takes map.zoom and indexes into resolutions[]... but.... │ │ │ │ - * │ │ │ │ - * The getResolution() call is also overridden. Instead of using the │ │ │ │ - * resolutions[] array, we simply calculate the current resolution based │ │ │ │ - * on the current extent and the current map size. But how will we be able │ │ │ │ - * to calculate the current extent without knowing the resolution...? │ │ │ │ - * │ │ │ │ - * The getExtent() function is also overridden. Instead of calculating extent │ │ │ │ - * based on the center point and the current resolution, we instead │ │ │ │ - * calculate the extent by getting the lonlats at the top-left and │ │ │ │ - * bottom-right by using the getLonLatFromViewPortPx() translation function, │ │ │ │ - * taken from the pixel locations (0,0) and the size of the map. But how │ │ │ │ - * will we be able to do lonlat-px translation without resolution....? │ │ │ │ - * │ │ │ │ - * The getZoomForResolution() method is overridden. Instead of indexing into │ │ │ │ - * the resolutions[] array, we call OpenLayers.Layer.getExent(), passing in │ │ │ │ - * the desired resolution. With this extent, we then call getZoomForExtent() │ │ │ │ - * │ │ │ │ - * │ │ │ │ - * Whenever you implement a layer using OpenLayers.Layer.FixedZoomLevels, │ │ │ │ - * it is your responsibility to provide the following three functions: │ │ │ │ - * │ │ │ │ - * - getLonLatFromViewPortPx │ │ │ │ - * - getViewPortPxFromLonLat │ │ │ │ - * - getZoomForExtent │ │ │ │ - * │ │ │ │ - * ...those three functions should generally be provided by any reasonable │ │ │ │ - * API that you might be working from. │ │ │ │ + * Class: OpenLayers.Tile.UTFGrid │ │ │ │ + * Instances of OpenLayers.Tile.UTFGrid are used to manage │ │ │ │ + * UTFGrids. This is an unusual tile type in that it doesn't have a │ │ │ │ + * rendered image; only a 'hit grid' that can be used to │ │ │ │ + * look up feature attributes. │ │ │ │ + * │ │ │ │ + * See the <OpenLayers.Tile.UTFGrid> constructor for details on constructing a │ │ │ │ + * new instance. │ │ │ │ * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Tile> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.FixedZoomLevels = OpenLayers.Class({ │ │ │ │ - │ │ │ │ - /********************************************************/ │ │ │ │ - /* */ │ │ │ │ - /* Baselayer Functions */ │ │ │ │ - /* */ │ │ │ │ - /* The following functions must all be implemented */ │ │ │ │ - /* by all base layers */ │ │ │ │ - /* */ │ │ │ │ - /********************************************************/ │ │ │ │ +OpenLayers.Tile.UTFGrid = OpenLayers.Class(OpenLayers.Tile, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.FixedZoomLevels │ │ │ │ - * Create a new fixed zoom levels layer. │ │ │ │ + /** │ │ │ │ + * Property: url │ │ │ │ + * {String} │ │ │ │ + * The URL of the UTFGrid file being requested. Provided by the <getURL> │ │ │ │ + * method. │ │ │ │ */ │ │ │ │ - initialize: function() { │ │ │ │ - //this class is only just to add the following functions... │ │ │ │ - // nothing to actually do here... but it is probably a good │ │ │ │ - // idea to have layers that use these functions call this │ │ │ │ - // inititalize() anyways, in case at some point we decide we │ │ │ │ - // do want to put some functionality or state in here. │ │ │ │ - }, │ │ │ │ + url: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: initResolutions │ │ │ │ - * Populate the resolutions array │ │ │ │ + * Property: utfgridResolution │ │ │ │ + * {Number} │ │ │ │ + * Ratio of the pixel width to the width of a UTFGrid data point. If an │ │ │ │ + * entry in the grid represents a 4x4 block of pixels, the │ │ │ │ + * utfgridResolution would be 4. Default is 2. │ │ │ │ */ │ │ │ │ - initResolutions: function() { │ │ │ │ - │ │ │ │ - var props = ['minZoomLevel', 'maxZoomLevel', 'numZoomLevels']; │ │ │ │ - │ │ │ │ - for (var i = 0, len = props.length; i < len; i++) { │ │ │ │ - var property = props[i]; │ │ │ │ - this[property] = (this.options[property] != null) ? │ │ │ │ - this.options[property] : │ │ │ │ - this.map[property]; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if ((this.minZoomLevel == null) || │ │ │ │ - (this.minZoomLevel < this.MIN_ZOOM_LEVEL)) { │ │ │ │ - this.minZoomLevel = this.MIN_ZOOM_LEVEL; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // │ │ │ │ - // At this point, we know what the minimum desired zoom level is, and │ │ │ │ - // we must calculate the total number of zoom levels. │ │ │ │ - // │ │ │ │ - // Because we allow for the setting of either the 'numZoomLevels' │ │ │ │ - // or the 'maxZoomLevel' properties... on either the layer or the │ │ │ │ - // map, we have to define some rules to see which we take into │ │ │ │ - // account first in this calculation. │ │ │ │ - // │ │ │ │ - // The following is the precedence list for these properties: │ │ │ │ - // │ │ │ │ - // (1) numZoomLevels set on layer │ │ │ │ - // (2) maxZoomLevel set on layer │ │ │ │ - // (3) numZoomLevels set on map │ │ │ │ - // (4) maxZoomLevel set on map* │ │ │ │ - // (5) none of the above* │ │ │ │ - // │ │ │ │ - // *Note that options (4) and (5) are only possible if the user │ │ │ │ - // _explicitly_ sets the 'numZoomLevels' property on the map to │ │ │ │ - // null, since it is set by default to 16. │ │ │ │ - // │ │ │ │ - │ │ │ │ - // │ │ │ │ - // Note to future: In 3.0, I think we should remove the default │ │ │ │ - // value of 16 for map.numZoomLevels. Rather, I think that value │ │ │ │ - // should be set as a default on the Layer.WMS class. If someone │ │ │ │ - // creates a 3rd party layer and does not specify any 'minZoomLevel', │ │ │ │ - // 'maxZoomLevel', or 'numZoomLevels', and has not explicitly │ │ │ │ - // specified any of those on the map object either.. then I think │ │ │ │ - // it is fair to say that s/he wants all the zoom levels available. │ │ │ │ - // │ │ │ │ - // By making map.numZoomLevels *null* by default, that will be the │ │ │ │ - // case. As it is, I don't feel comfortable changing that right now │ │ │ │ - // as it would be a glaring API change and actually would probably │ │ │ │ - // break many peoples' codes. │ │ │ │ - // │ │ │ │ - │ │ │ │ - //the number of zoom levels we'd like to have. │ │ │ │ - var desiredZoomLevels; │ │ │ │ - │ │ │ │ - //this is the maximum number of zoom levels the layer will allow, │ │ │ │ - // given the specified starting minimum zoom level. │ │ │ │ - var limitZoomLevels = this.MAX_ZOOM_LEVEL - this.minZoomLevel + 1; │ │ │ │ + utfgridResolution: 2, │ │ │ │ │ │ │ │ - if (((this.options.numZoomLevels == null) && │ │ │ │ - (this.options.maxZoomLevel != null)) // (2) │ │ │ │ - || │ │ │ │ - ((this.numZoomLevels == null) && │ │ │ │ - (this.maxZoomLevel != null)) // (4) │ │ │ │ - ) { │ │ │ │ - //calculate based on specified maxZoomLevel (on layer or map) │ │ │ │ - desiredZoomLevels = this.maxZoomLevel - this.minZoomLevel + 1; │ │ │ │ - } else { │ │ │ │ - //calculate based on specified numZoomLevels (on layer or map) │ │ │ │ - // this covers cases (1) and (3) │ │ │ │ - desiredZoomLevels = this.numZoomLevels; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: json │ │ │ │ + * {Object} │ │ │ │ + * Stores the parsed JSON tile data structure. │ │ │ │ + */ │ │ │ │ + json: null, │ │ │ │ │ │ │ │ - if (desiredZoomLevels != null) { │ │ │ │ - //Now that we know what we would *like* the number of zoom levels │ │ │ │ - // to be, based on layer or map options, we have to make sure that │ │ │ │ - // it does not conflict with the actual limit, as specified by │ │ │ │ - // the constants on the layer itself (and calculated into the │ │ │ │ - // 'limitZoomLevels' variable). │ │ │ │ - this.numZoomLevels = Math.min(desiredZoomLevels, limitZoomLevels); │ │ │ │ - } else { │ │ │ │ - // case (5) -- neither 'numZoomLevels' not 'maxZoomLevel' was │ │ │ │ - // set on either the layer or the map. So we just use the │ │ │ │ - // maximum limit as calculated by the layer's constants. │ │ │ │ - this.numZoomLevels = limitZoomLevels; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: format │ │ │ │ + * {OpenLayers.Format.JSON} │ │ │ │ + * Parser instance used to parse JSON for cross browser support. The native │ │ │ │ + * JSON.parse method will be used where available (all except IE<8). │ │ │ │ + */ │ │ │ │ + format: null, │ │ │ │ │ │ │ │ - //now that the 'numZoomLevels' is appropriately, safely set, │ │ │ │ - // we go back and re-calculate the 'maxZoomLevel'. │ │ │ │ - this.maxZoomLevel = this.minZoomLevel + this.numZoomLevels - 1; │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Tile.UTFGrid │ │ │ │ + * Constructor for a new <OpenLayers.Tile.UTFGrid> 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} │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (this.RESOLUTIONS != null) { │ │ │ │ - var resolutionsIndex = 0; │ │ │ │ - this.resolutions = []; │ │ │ │ - for (var i = this.minZoomLevel; i <= this.maxZoomLevel; i++) { │ │ │ │ - this.resolutions[resolutionsIndex++] = this.RESOLUTIONS[i]; │ │ │ │ - } │ │ │ │ - this.maxResolution = this.resolutions[0]; │ │ │ │ - this.minResolution = this.resolutions[this.resolutions.length - 1]; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Clean up. │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + this.clear(); │ │ │ │ + OpenLayers.Tile.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getResolution │ │ │ │ - * Get the current map resolution │ │ │ │ + * Method: draw │ │ │ │ + * Check that a tile should be drawn, and draw it. │ │ │ │ + * In the case of UTFGrids, "drawing" it means fetching and │ │ │ │ + * parsing the json. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Float} Map units per Pixel │ │ │ │ + * {Boolean} Was a tile drawn? │ │ │ │ */ │ │ │ │ - getResolution: function() { │ │ │ │ + draw: function() { │ │ │ │ + var drawn = OpenLayers.Tile.prototype.draw.apply(this, arguments); │ │ │ │ + if (drawn) { │ │ │ │ + if (this.isLoading) { │ │ │ │ + this.abortLoading(); │ │ │ │ + //if we're already loading, send 'reload' instead of 'loadstart'. │ │ │ │ + this.events.triggerEvent("reload"); │ │ │ │ + } else { │ │ │ │ + this.isLoading = true; │ │ │ │ + this.events.triggerEvent("loadstart"); │ │ │ │ + } │ │ │ │ + this.url = this.layer.getURL(this.bounds); │ │ │ │ │ │ │ │ - if (this.resolutions != null) { │ │ │ │ - return OpenLayers.Layer.prototype.getResolution.apply(this, arguments); │ │ │ │ + if (this.layer.useJSONP) { │ │ │ │ + // Use JSONP method to avoid xbrowser policy │ │ │ │ + var ols = new OpenLayers.Protocol.Script({ │ │ │ │ + url: this.url, │ │ │ │ + callback: function(response) { │ │ │ │ + this.isLoading = false; │ │ │ │ + this.events.triggerEvent("loadend"); │ │ │ │ + this.json = response.data; │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + ols.read(); │ │ │ │ + this.request = ols; │ │ │ │ + } else { │ │ │ │ + // Use standard XHR │ │ │ │ + this.request = OpenLayers.Request.GET({ │ │ │ │ + url: this.url, │ │ │ │ + callback: function(response) { │ │ │ │ + this.isLoading = false; │ │ │ │ + this.events.triggerEvent("loadend"); │ │ │ │ + if (response.status === 200) { │ │ │ │ + this.parseData(response.responseText); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ } else { │ │ │ │ - var resolution = null; │ │ │ │ - │ │ │ │ - var viewSize = this.map.getSize(); │ │ │ │ - var extent = this.getExtent(); │ │ │ │ + this.unload(); │ │ │ │ + } │ │ │ │ + return drawn; │ │ │ │ + }, │ │ │ │ │ │ │ │ - if ((viewSize != null) && (extent != null)) { │ │ │ │ - resolution = Math.max(extent.getWidth() / viewSize.w, │ │ │ │ - extent.getHeight() / viewSize.h); │ │ │ │ - } │ │ │ │ - return resolution; │ │ │ │ + /** │ │ │ │ + * Method: abortLoading │ │ │ │ + * Cancel a pending request. │ │ │ │ + */ │ │ │ │ + abortLoading: function() { │ │ │ │ + if (this.request) { │ │ │ │ + this.request.abort(); │ │ │ │ + delete this.request; │ │ │ │ } │ │ │ │ + this.isLoading = false; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getExtent │ │ │ │ - * Calculates using px-> lonlat translation functions on tl and br │ │ │ │ - * corners of viewport │ │ │ │ - * │ │ │ │ + * Method: getFeatureInfo │ │ │ │ + * Get feature information associated with a pixel offset. If the pixel │ │ │ │ + * offset corresponds to a feature, the returned object will have id │ │ │ │ + * and data properties. Otherwise, null will be returned. │ │ │ │ + * │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * i - {Number} X-axis pixel offset (from top left of tile) │ │ │ │ + * j - {Number} Y-axis pixel offset (from top left of tile) │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat │ │ │ │ - * bounds of the current viewPort. │ │ │ │ + * {Object} Object with feature id and data properties corresponding to the │ │ │ │ + * given pixel offset. │ │ │ │ */ │ │ │ │ - getExtent: function() { │ │ │ │ - var size = this.map.getSize(); │ │ │ │ - var tl = this.getLonLatFromViewPortPx({ │ │ │ │ - x: 0, │ │ │ │ - y: 0 │ │ │ │ - }); │ │ │ │ - var br = this.getLonLatFromViewPortPx({ │ │ │ │ - x: size.w, │ │ │ │ - y: size.h │ │ │ │ - }); │ │ │ │ - │ │ │ │ - if ((tl != null) && (br != null)) { │ │ │ │ - return new OpenLayers.Bounds(tl.lon, br.lat, br.lon, tl.lat); │ │ │ │ - } else { │ │ │ │ - return null; │ │ │ │ + getFeatureInfo: function(i, j) { │ │ │ │ + var info = null; │ │ │ │ + if (this.json) { │ │ │ │ + var id = this.getFeatureId(i, j); │ │ │ │ + if (id !== null) { │ │ │ │ + info = { │ │ │ │ + id: id, │ │ │ │ + data: this.json.data[id] │ │ │ │ + }; │ │ │ │ + } │ │ │ │ } │ │ │ │ + return info; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getZoomForResolution │ │ │ │ - * Get the zoom level for a given resolution │ │ │ │ + * Method: getFeatureId │ │ │ │ + * Get the identifier for the feature associated with a pixel offset. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * resolution - {Float} │ │ │ │ + * i - {Number} X-axis pixel offset (from top left of tile) │ │ │ │ + * j - {Number} Y-axis pixel offset (from top left of tile) │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Integer} A suitable zoom level for the specified resolution. │ │ │ │ - * If no baselayer is set, returns null. │ │ │ │ + * {Object} The feature identifier corresponding to the given pixel offset. │ │ │ │ + * Returns null if pixel doesn't correspond to a feature. │ │ │ │ */ │ │ │ │ - getZoomForResolution: function(resolution) { │ │ │ │ - │ │ │ │ - if (this.resolutions != null) { │ │ │ │ - return OpenLayers.Layer.prototype.getZoomForResolution.apply(this, arguments); │ │ │ │ - } else { │ │ │ │ - var extent = OpenLayers.Layer.prototype.getExtent.apply(this, []); │ │ │ │ - return this.getZoomForExtent(extent); │ │ │ │ + getFeatureId: function(i, j) { │ │ │ │ + var id = null; │ │ │ │ + if (this.json) { │ │ │ │ + var resolution = this.utfgridResolution; │ │ │ │ + var row = Math.floor(j / resolution); │ │ │ │ + var col = Math.floor(i / resolution); │ │ │ │ + var charCode = this.json.grid[row].charCodeAt(col); │ │ │ │ + var index = this.indexFromCharCode(charCode); │ │ │ │ + var keys = this.json.keys; │ │ │ │ + if (!isNaN(index) && (index in keys)) { │ │ │ │ + id = keys[index]; │ │ │ │ + } │ │ │ │ } │ │ │ │ + return id; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ - │ │ │ │ - │ │ │ │ - /********************************************************/ │ │ │ │ - /* */ │ │ │ │ - /* Translation Functions */ │ │ │ │ - /* */ │ │ │ │ - /* The following functions translate GMaps and OL */ │ │ │ │ - /* formats for Pixel, LonLat, Bounds, and Zoom */ │ │ │ │ - /* */ │ │ │ │ - /********************************************************/ │ │ │ │ - │ │ │ │ - │ │ │ │ - // │ │ │ │ - // TRANSLATION: MapObject Zoom <-> OpenLayers Zoom │ │ │ │ - // │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: getOLZoomFromMapObjectZoom │ │ │ │ - * Get the OL zoom index from the map object zoom level │ │ │ │ + * Method: indexFromCharCode │ │ │ │ + * Given a character code for one of the UTFGrid "grid" characters, │ │ │ │ + * resolve the integer index for the feature id in the UTFGrid "keys" │ │ │ │ + * array. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * moZoom - {Integer} │ │ │ │ - * │ │ │ │ + * charCode - {Integer} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Integer} An OpenLayers Zoom level, translated from the passed in zoom │ │ │ │ - * Returns null if null value is passed in │ │ │ │ + * {Integer} Index for the feature id from the keys array. │ │ │ │ */ │ │ │ │ - getOLZoomFromMapObjectZoom: function(moZoom) { │ │ │ │ - var zoom = null; │ │ │ │ - if (moZoom != null) { │ │ │ │ - zoom = moZoom - this.minZoomLevel; │ │ │ │ - if (this.map.baseLayer !== this) { │ │ │ │ - zoom = this.map.baseLayer.getZoomForResolution( │ │ │ │ - this.getResolutionForZoom(zoom) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + indexFromCharCode: function(charCode) { │ │ │ │ + if (charCode >= 93) { │ │ │ │ + charCode--; │ │ │ │ } │ │ │ │ - return zoom; │ │ │ │ + if (charCode >= 35) { │ │ │ │ + charCode--; │ │ │ │ + } │ │ │ │ + return charCode - 32; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getMapObjectZoomFromOLZoom │ │ │ │ - * Get the map object zoom level from the OL zoom level │ │ │ │ + * Method: parseData │ │ │ │ + * Parse the JSON from a request │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * olZoom - {Integer} │ │ │ │ + * str - {String} UTFGrid as a JSON string. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Integer} A MapObject level, translated from the passed in olZoom │ │ │ │ - * Returns null if null value is passed in │ │ │ │ + * {Object} parsed javascript data │ │ │ │ */ │ │ │ │ - getMapObjectZoomFromOLZoom: function(olZoom) { │ │ │ │ - var zoom = null; │ │ │ │ - if (olZoom != null) { │ │ │ │ - zoom = olZoom + this.minZoomLevel; │ │ │ │ - if (this.map.baseLayer !== this) { │ │ │ │ - zoom = this.getZoomForResolution( │ │ │ │ - this.map.baseLayer.getResolutionForZoom(zoom) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + parseData: function(str) { │ │ │ │ + if (!this.format) { │ │ │ │ + this.format = new OpenLayers.Format.JSON(); │ │ │ │ } │ │ │ │ - return zoom; │ │ │ │ + this.json = this.format.read(str); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.FixedZoomLevels" │ │ │ │ -}); │ │ │ │ + /** │ │ │ │ + * Method: clear │ │ │ │ + * Delete data stored with this tile. │ │ │ │ + */ │ │ │ │ + clear: function() { │ │ │ │ + this.json = null; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Tile.UTFGrid" │ │ │ │ │ │ │ │ +}); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/Google.js │ │ │ │ + OpenLayers/Tile/Image/IFrame.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/SphericalMercator.js │ │ │ │ - * @requires OpenLayers/Layer/EventPane.js │ │ │ │ - * @requires OpenLayers/Layer/FixedZoomLevels.js │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ + * @requires OpenLayers/Tile/Image.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.Google │ │ │ │ - * │ │ │ │ - * Provides a wrapper for Google's Maps API │ │ │ │ - * Normally the Terms of Use for this API do not allow wrapping, but Google │ │ │ │ - * have provided written consent to OpenLayers for this - see email in │ │ │ │ - * http://osgeo-org.1560.n6.nabble.com/Google-Maps-API-Terms-of-Use-changes-tp4910013p4911981.html │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.SphericalMercator> │ │ │ │ - * - <OpenLayers.Layer.EventPane> │ │ │ │ - * - <OpenLayers.Layer.FixedZoomLevels> │ │ │ │ + * Constant: OpenLayers.Tile.Image.IFrame │ │ │ │ + * Mixin for tiles that use form-encoded POST requests to get images from │ │ │ │ + * remote services. Images will be loaded using HTTP-POST into an IFrame. │ │ │ │ + * │ │ │ │ + * This mixin will be applied to <OpenLayers.Tile.Image> instances │ │ │ │ + * configured with <OpenLayers.Tile.Image.maxGetUrlLength> set. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.Google = OpenLayers.Class( │ │ │ │ - OpenLayers.Layer.EventPane, │ │ │ │ - OpenLayers.Layer.FixedZoomLevels, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constant: MIN_ZOOM_LEVEL │ │ │ │ - * {Integer} 0 │ │ │ │ - */ │ │ │ │ - MIN_ZOOM_LEVEL: 0, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constant: MAX_ZOOM_LEVEL │ │ │ │ - * {Integer} 21 │ │ │ │ - */ │ │ │ │ - MAX_ZOOM_LEVEL: 21, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constant: RESOLUTIONS │ │ │ │ - * {Array(Float)} Hardcode these resolutions so that they are more closely │ │ │ │ - * tied with the standard wms projection │ │ │ │ - */ │ │ │ │ - RESOLUTIONS: [ │ │ │ │ - 1.40625, │ │ │ │ - 0.703125, │ │ │ │ - 0.3515625, │ │ │ │ - 0.17578125, │ │ │ │ - 0.087890625, │ │ │ │ - 0.0439453125, │ │ │ │ - 0.02197265625, │ │ │ │ - 0.010986328125, │ │ │ │ - 0.0054931640625, │ │ │ │ - 0.00274658203125, │ │ │ │ - 0.001373291015625, │ │ │ │ - 0.0006866455078125, │ │ │ │ - 0.00034332275390625, │ │ │ │ - 0.000171661376953125, │ │ │ │ - 0.0000858306884765625, │ │ │ │ - 0.00004291534423828125, │ │ │ │ - 0.00002145767211914062, │ │ │ │ - 0.00001072883605957031, │ │ │ │ - 0.00000536441802978515, │ │ │ │ - 0.00000268220901489257, │ │ │ │ - 0.0000013411045074462891, │ │ │ │ - 0.00000067055225372314453 │ │ │ │ - ], │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: type │ │ │ │ - * {GMapType} │ │ │ │ - */ │ │ │ │ - type: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: wrapDateLine │ │ │ │ - * {Boolean} Allow user to pan forever east/west. Default is true. │ │ │ │ - * Setting this to false only restricts panning if │ │ │ │ - * <sphericalMercator> is true. │ │ │ │ - */ │ │ │ │ - wrapDateLine: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: sphericalMercator │ │ │ │ - * {Boolean} Should the map act as a mercator-projected map? This will │ │ │ │ - * cause all interactions with the map to be in the actual map │ │ │ │ - * projection, which allows support for vector drawing, overlaying │ │ │ │ - * other maps, etc. │ │ │ │ - */ │ │ │ │ - sphericalMercator: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {Number} The version of the Google Maps API │ │ │ │ - */ │ │ │ │ - version: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.Google │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} A name for the layer. │ │ │ │ - * options - {Object} An optional object whose properties will be set │ │ │ │ - * on the layer. │ │ │ │ - */ │ │ │ │ - initialize: function(name, options) { │ │ │ │ - options = options || {}; │ │ │ │ - if (!options.version) { │ │ │ │ - options.version = typeof GMap2 === "function" ? "2" : "3"; │ │ │ │ - } │ │ │ │ - var mixin = OpenLayers.Layer.Google["v" + │ │ │ │ - options.version.replace(/\./g, "_")]; │ │ │ │ - if (mixin) { │ │ │ │ - OpenLayers.Util.applyDefaults(options, mixin); │ │ │ │ - } else { │ │ │ │ - throw "Unsupported Google Maps API version: " + options.version; │ │ │ │ - } │ │ │ │ - │ │ │ │ - OpenLayers.Util.applyDefaults(options, mixin.DEFAULTS); │ │ │ │ - if (options.maxExtent) { │ │ │ │ - options.maxExtent = options.maxExtent.clone(); │ │ │ │ - } │ │ │ │ +OpenLayers.Tile.Image.IFrame = { │ │ │ │ │ │ │ │ - OpenLayers.Layer.EventPane.prototype.initialize.apply(this, │ │ │ │ - [name, options]); │ │ │ │ - OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, │ │ │ │ - [name, options]); │ │ │ │ + /** │ │ │ │ + * Property: useIFrame │ │ │ │ + * {Boolean} true if we are currently using an IFrame to render POST │ │ │ │ + * responses, false if we are using an img element to render GET responses. │ │ │ │ + */ │ │ │ │ + useIFrame: null, │ │ │ │ │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator); │ │ │ │ - this.initMercatorParameters(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: blankImageUrl │ │ │ │ + * {String} Using a data scheme url is not supported by all browsers, but │ │ │ │ + * we don't care because we either set it as css backgroundImage, or the │ │ │ │ + * image's display style is set to "none" when we use it. │ │ │ │ + */ │ │ │ │ + blankImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.Google>} An exact clone of this layer │ │ │ │ - */ │ │ │ │ - clone: function() { │ │ │ │ - /** │ │ │ │ - * This method isn't intended to be called by a subclass and it │ │ │ │ - * doesn't call the same method on the superclass. We don't call │ │ │ │ - * the super's clone because we don't want properties that are set │ │ │ │ - * on this layer after initialize (i.e. this.mapObject etc.). │ │ │ │ - */ │ │ │ │ - return new OpenLayers.Layer.Google( │ │ │ │ - this.name, this.getOptions() │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Method: draw │ │ │ │ + * Set useIFrame in the instance, and operate the image/iframe switch. │ │ │ │ + * Then call Tile.Image.draw. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} │ │ │ │ + */ │ │ │ │ + draw: function() { │ │ │ │ + var draw = OpenLayers.Tile.Image.prototype.shouldDraw.call(this); │ │ │ │ + if (draw) { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: setVisibility │ │ │ │ - * Set the visibility flag for the layer and hide/show & redraw │ │ │ │ - * accordingly. Fire event unless otherwise specified │ │ │ │ - * │ │ │ │ - * Note that visibility is no longer simply whether or not the layer's │ │ │ │ - * style.display is set to "block". Now we store a 'visibility' state │ │ │ │ - * property on the layer class, this allows us to remember whether or │ │ │ │ - * not we *desire* for a layer to be visible. In the case where the │ │ │ │ - * map's resolution is out of the layer's range, this desire may be │ │ │ │ - * subverted. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * visible - {Boolean} Display the layer (if in range) │ │ │ │ - */ │ │ │ │ - setVisibility: function(visible) { │ │ │ │ - // sharing a map container, opacity has to be set per layer │ │ │ │ - var opacity = this.opacity == null ? 1 : this.opacity; │ │ │ │ - OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this, arguments); │ │ │ │ - this.setOpacity(opacity); │ │ │ │ - }, │ │ │ │ + // this.url isn't set to the currect value yet, so we call getURL │ │ │ │ + // on the layer and store the result in a local variable │ │ │ │ + var url = this.layer.getURL(this.bounds); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: display │ │ │ │ - * Hide or show the Layer │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * visible - {Boolean} │ │ │ │ - */ │ │ │ │ - display: function(visible) { │ │ │ │ - if (!this._dragging) { │ │ │ │ - this.setGMapVisibility(visible); │ │ │ │ - } │ │ │ │ - OpenLayers.Layer.EventPane.prototype.display.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + var usedIFrame = this.useIFrame; │ │ │ │ + this.useIFrame = this.maxGetUrlLength !== null && │ │ │ │ + !this.layer.async && │ │ │ │ + url.length > this.maxGetUrlLength; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: moveTo │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to │ │ │ │ - * do some init work in that case. │ │ │ │ - * dragging - {Boolean} │ │ │ │ - */ │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - this._dragging = dragging; │ │ │ │ - OpenLayers.Layer.EventPane.prototype.moveTo.apply(this, arguments); │ │ │ │ - delete this._dragging; │ │ │ │ - }, │ │ │ │ + var fromIFrame = usedIFrame && !this.useIFrame; │ │ │ │ + var toIFrame = !usedIFrame && this.useIFrame; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: setOpacity │ │ │ │ - * Sets the opacity for the entire layer (all images) │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * opacity - {Float} │ │ │ │ - */ │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ - if (opacity !== this.opacity) { │ │ │ │ - if (this.map != null) { │ │ │ │ - this.map.events.triggerEvent("changelayer", { │ │ │ │ - layer: this, │ │ │ │ - property: "opacity" │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - this.opacity = opacity; │ │ │ │ - } │ │ │ │ - // Though this layer's opacity may not change, we're sharing a container │ │ │ │ - // and need to update the opacity for the entire container. │ │ │ │ - if (this.getVisibility()) { │ │ │ │ - var container = this.getMapContainer(); │ │ │ │ - OpenLayers.Util.modifyDOMElement( │ │ │ │ - container, null, null, null, null, null, null, opacity │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + if (fromIFrame || toIFrame) { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Clean up this layer. │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - /** │ │ │ │ - * We have to override this method because the event pane destroy │ │ │ │ - * deletes the mapObject reference before removing this layer from │ │ │ │ - * the map. │ │ │ │ - */ │ │ │ │ - if (this.map) { │ │ │ │ - this.setGMapVisibility(false); │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache && cache.count <= 1) { │ │ │ │ - this.removeGMapElements(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - OpenLayers.Layer.EventPane.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + // Switching between GET (image) and POST (iframe). │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: removeGMapElements │ │ │ │ - * Remove all elements added to the dom. This should only be called if │ │ │ │ - * this is the last of the Google layers for the given map. │ │ │ │ - */ │ │ │ │ - removeGMapElements: function() { │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - // remove shared elements from dom │ │ │ │ - var container = this.mapObject && this.getMapContainer(); │ │ │ │ - if (container && container.parentNode) { │ │ │ │ - container.parentNode.removeChild(container); │ │ │ │ - } │ │ │ │ - var termsOfUse = cache.termsOfUse; │ │ │ │ - if (termsOfUse && termsOfUse.parentNode) { │ │ │ │ - termsOfUse.parentNode.removeChild(termsOfUse); │ │ │ │ - } │ │ │ │ - var poweredBy = cache.poweredBy; │ │ │ │ - if (poweredBy && poweredBy.parentNode) { │ │ │ │ - poweredBy.parentNode.removeChild(poweredBy); │ │ │ │ - } │ │ │ │ - if (this.mapObject && window.google && google.maps && │ │ │ │ - google.maps.event && google.maps.event.clearListeners) { │ │ │ │ - google.maps.event.clearListeners(this.mapObject, 'tilesloaded'); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + // We remove the imgDiv (really either an image or an iframe) │ │ │ │ + // from the frame and set it to null to make sure initImage │ │ │ │ + // will call getImage. │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: removeMap │ │ │ │ - * On being removed from the map, also remove termsOfUse and poweredBy divs │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ - */ │ │ │ │ - removeMap: function(map) { │ │ │ │ - // hide layer before removing │ │ │ │ - if (this.visibility && this.mapObject) { │ │ │ │ - this.setGMapVisibility(false); │ │ │ │ - } │ │ │ │ - // check to see if last Google layer in this map │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[map.id]; │ │ │ │ - if (cache) { │ │ │ │ - if (cache.count <= 1) { │ │ │ │ - this.removeGMapElements(); │ │ │ │ - delete OpenLayers.Layer.Google.cache[map.id]; │ │ │ │ - } else { │ │ │ │ - // decrement the layer count │ │ │ │ - --cache.count; │ │ │ │ + if (this.imgDiv && this.imgDiv.parentNode === this.frame) { │ │ │ │ + this.frame.removeChild(this.imgDiv); │ │ │ │ } │ │ │ │ - } │ │ │ │ - // remove references to gmap elements │ │ │ │ - delete this.termsOfUse; │ │ │ │ - delete this.poweredBy; │ │ │ │ - delete this.mapObject; │ │ │ │ - delete this.dragObject; │ │ │ │ - OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + this.imgDiv = null; │ │ │ │ │ │ │ │ - // │ │ │ │ - // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ - // │ │ │ │ + // And if we had an iframe we also remove the event pane. │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getOLBoundsFromMapObjectBounds │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moBounds - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} An <OpenLayers.Bounds>, translated from the │ │ │ │ - * passed-in MapObject Bounds. │ │ │ │ - * Returns null if null value is passed in. │ │ │ │ - */ │ │ │ │ - getOLBoundsFromMapObjectBounds: function(moBounds) { │ │ │ │ - var olBounds = null; │ │ │ │ - if (moBounds != null) { │ │ │ │ - var sw = moBounds.getSouthWest(); │ │ │ │ - var ne = moBounds.getNorthEast(); │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - sw = this.forwardMercator(sw.lng(), sw.lat()); │ │ │ │ - ne = this.forwardMercator(ne.lng(), ne.lat()); │ │ │ │ - } else { │ │ │ │ - sw = new OpenLayers.LonLat(sw.lng(), sw.lat()); │ │ │ │ - ne = new OpenLayers.LonLat(ne.lng(), ne.lat()); │ │ │ │ + if (fromIFrame) { │ │ │ │ + this.frame.removeChild(this.frame.firstChild); │ │ │ │ } │ │ │ │ - olBounds = new OpenLayers.Bounds(sw.lon, │ │ │ │ - sw.lat, │ │ │ │ - ne.lon, │ │ │ │ - ne.lat); │ │ │ │ } │ │ │ │ - return olBounds; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: getWarningHTML │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} String with information on why layer is broken, how to get │ │ │ │ - * it working. │ │ │ │ - */ │ │ │ │ - getWarningHTML: function() { │ │ │ │ - return OpenLayers.i18n("googleWarning"); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Interface Controls * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ - │ │ │ │ - │ │ │ │ - // Get&Set Center, Zoom │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectCenter │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} The mapObject's current center in Map Object format │ │ │ │ - */ │ │ │ │ - getMapObjectCenter: function() { │ │ │ │ - return this.mapObject.getCenter(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectZoom │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} The mapObject's current zoom, in Map Object format │ │ │ │ - */ │ │ │ │ - getMapObjectZoom: function() { │ │ │ │ - return this.mapObject.getZoom(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Primitives * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ - │ │ │ │ - │ │ │ │ - // LonLat │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: getLongitudeFromMapObjectLonLat │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moLonLat - {Object} MapObject LonLat format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Float} Longitude of the given MapObject LonLat │ │ │ │ - */ │ │ │ │ - getLongitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - return this.sphericalMercator ? │ │ │ │ - this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon : │ │ │ │ - moLonLat.lng(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: getLatitudeFromMapObjectLonLat │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moLonLat - {Object} MapObject LonLat format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Float} Latitude of the given MapObject LonLat │ │ │ │ - */ │ │ │ │ - getLatitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - var lat = this.sphericalMercator ? │ │ │ │ - this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat : │ │ │ │ - moLonLat.lat(); │ │ │ │ - return lat; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - // Pixel │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: getXFromMapObjectPixel │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moPixel - {Object} MapObject Pixel format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} X value of the MapObject Pixel │ │ │ │ - */ │ │ │ │ - getXFromMapObjectPixel: function(moPixel) { │ │ │ │ - return moPixel.x; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: getYFromMapObjectPixel │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moPixel - {Object} MapObject Pixel format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} Y value of the MapObject Pixel │ │ │ │ - */ │ │ │ │ - getYFromMapObjectPixel: function(moPixel) { │ │ │ │ - return moPixel.y; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Google" │ │ │ │ - }); │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Property: OpenLayers.Layer.Google.cache │ │ │ │ - * {Object} Cache for elements that should only be created once per map. │ │ │ │ - */ │ │ │ │ -OpenLayers.Layer.Google.cache = {}; │ │ │ │ - │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Layer.Google.v2 │ │ │ │ - * │ │ │ │ - * Mixin providing functionality specific to the Google Maps API v2. │ │ │ │ - * │ │ │ │ - * This API has been deprecated by Google. │ │ │ │ - * Developers are encouraged to migrate to v3 of the API; support for this │ │ │ │ - * is provided by <OpenLayers.Layer.Google.v3> │ │ │ │ - */ │ │ │ │ -OpenLayers.Layer.Google.v2 = { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: termsOfUse │ │ │ │ - * {DOMElement} Div for Google's copyright and terms of use link │ │ │ │ - */ │ │ │ │ - termsOfUse: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: poweredBy │ │ │ │ - * {DOMElement} Div for Google's powered by logo and link │ │ │ │ - */ │ │ │ │ - poweredBy: null, │ │ │ │ + } │ │ │ │ + return OpenLayers.Tile.Image.prototype.draw.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: dragObject │ │ │ │ - * {GDraggableObject} Since 2.93, Google has exposed the ability to get │ │ │ │ - * the maps GDraggableObject. We can now use this for smooth panning │ │ │ │ - */ │ │ │ │ - dragObject: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: loadMapObject │ │ │ │ - * Load the GMap and register appropriate event listeners. If we can't │ │ │ │ - * load GMap2, then display a warning message. │ │ │ │ + * Method: getImage │ │ │ │ + * Creates the content for the frame on the tile. │ │ │ │ */ │ │ │ │ - loadMapObject: function() { │ │ │ │ - if (!this.type) { │ │ │ │ - this.type = G_NORMAL_MAP; │ │ │ │ - } │ │ │ │ - var mapObject, termsOfUse, poweredBy; │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - // there are already Google layers added to this map │ │ │ │ - mapObject = cache.mapObject; │ │ │ │ - termsOfUse = cache.termsOfUse; │ │ │ │ - poweredBy = cache.poweredBy; │ │ │ │ - // increment the layer count │ │ │ │ - ++cache.count; │ │ │ │ - } else { │ │ │ │ - // this is the first Google layer for this map │ │ │ │ - │ │ │ │ - var container = this.map.viewPortDiv; │ │ │ │ - var div = document.createElement("div"); │ │ │ │ - div.id = this.map.id + "_GMap2Container"; │ │ │ │ - div.style.position = "absolute"; │ │ │ │ - div.style.width = "100%"; │ │ │ │ - div.style.height = "100%"; │ │ │ │ - container.appendChild(div); │ │ │ │ - │ │ │ │ - // create GMap and shuffle elements │ │ │ │ - try { │ │ │ │ - mapObject = new GMap2(div); │ │ │ │ + getImage: function() { │ │ │ │ + if (this.useIFrame === true) { │ │ │ │ + if (!this.frame.childNodes.length) { │ │ │ │ + var eventPane = document.createElement("div"), │ │ │ │ + style = eventPane.style; │ │ │ │ + style.position = "absolute"; │ │ │ │ + style.width = "100%"; │ │ │ │ + style.height = "100%"; │ │ │ │ + style.zIndex = 1; │ │ │ │ + style.backgroundImage = "url(" + this.blankImageUrl + ")"; │ │ │ │ + this.frame.appendChild(eventPane); │ │ │ │ + } │ │ │ │ │ │ │ │ - // move the ToS and branding stuff up to the container div │ │ │ │ - termsOfUse = div.lastChild; │ │ │ │ - container.appendChild(termsOfUse); │ │ │ │ - termsOfUse.style.zIndex = "1100"; │ │ │ │ - termsOfUse.style.right = ""; │ │ │ │ - termsOfUse.style.bottom = ""; │ │ │ │ - termsOfUse.className = "olLayerGoogleCopyright"; │ │ │ │ + var id = this.id + '_iFrame', │ │ │ │ + iframe; │ │ │ │ + if (parseFloat(navigator.appVersion.split("MSIE")[1]) < 9) { │ │ │ │ + // Older IE versions do not set the name attribute of an iFrame │ │ │ │ + // properly via DOM manipulation, so we need to do it on our own with │ │ │ │ + // this hack. │ │ │ │ + iframe = document.createElement('<iframe name="' + id + '">'); │ │ │ │ │ │ │ │ - poweredBy = div.lastChild; │ │ │ │ - container.appendChild(poweredBy); │ │ │ │ - poweredBy.style.zIndex = "1100"; │ │ │ │ - poweredBy.style.right = ""; │ │ │ │ - poweredBy.style.bottom = ""; │ │ │ │ - poweredBy.className = "olLayerGooglePoweredBy gmnoprint"; │ │ │ │ + // IFrames in older IE versions are not transparent, if you set │ │ │ │ + // the backgroundColor transparent. This is a workaround to get │ │ │ │ + // transparent iframes. │ │ │ │ + iframe.style.backgroundColor = '#FFFFFF'; │ │ │ │ + iframe.style.filter = 'chroma(color=#FFFFFF)'; │ │ │ │ + } else { │ │ │ │ + iframe = document.createElement('iframe'); │ │ │ │ + iframe.style.backgroundColor = 'transparent'; │ │ │ │ │ │ │ │ - } catch (e) { │ │ │ │ - throw (e); │ │ │ │ + // iframe.name needs to be an unique id, otherwise it │ │ │ │ + // could happen that other iframes are overwritten. │ │ │ │ + iframe.name = id; │ │ │ │ } │ │ │ │ - // cache elements for use by any other google layers added to │ │ │ │ - // this same map │ │ │ │ - OpenLayers.Layer.Google.cache[this.map.id] = { │ │ │ │ - mapObject: mapObject, │ │ │ │ - termsOfUse: termsOfUse, │ │ │ │ - poweredBy: poweredBy, │ │ │ │ - count: 1 │ │ │ │ - }; │ │ │ │ - } │ │ │ │ │ │ │ │ - this.mapObject = mapObject; │ │ │ │ - this.termsOfUse = termsOfUse; │ │ │ │ - this.poweredBy = poweredBy; │ │ │ │ + // some special properties to avoid scaling the images and scrollbars │ │ │ │ + // in the iframe │ │ │ │ + iframe.scrolling = 'no'; │ │ │ │ + iframe.marginWidth = '0px'; │ │ │ │ + iframe.marginHeight = '0px'; │ │ │ │ + iframe.frameBorder = '0'; │ │ │ │ │ │ │ │ - // ensure this layer type is one of the mapObject types │ │ │ │ - if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(), │ │ │ │ - this.type) === -1) { │ │ │ │ - this.mapObject.addMapType(this.type); │ │ │ │ - } │ │ │ │ + iframe.style.position = "absolute"; │ │ │ │ + iframe.style.width = "100%"; │ │ │ │ + iframe.style.height = "100%"; │ │ │ │ │ │ │ │ - //since v 2.93 getDragObject is now available. │ │ │ │ - if (typeof mapObject.getDragObject == "function") { │ │ │ │ - this.dragObject = mapObject.getDragObject(); │ │ │ │ + if (this.layer.opacity < 1) { │ │ │ │ + OpenLayers.Util.modifyDOMElement(iframe, null, null, null, │ │ │ │ + null, null, null, this.layer.opacity); │ │ │ │ + } │ │ │ │ + this.frame.appendChild(iframe); │ │ │ │ + this.imgDiv = iframe; │ │ │ │ + return iframe; │ │ │ │ } else { │ │ │ │ - this.dragPanMapObject = null; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.isBaseLayer === false) { │ │ │ │ - this.setGMapVisibility(this.div.style.display !== "none"); │ │ │ │ + return OpenLayers.Tile.Image.prototype.getImage.apply(this, arguments); │ │ │ │ } │ │ │ │ - │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: onMapResize │ │ │ │ + * Method: createRequestForm │ │ │ │ + * Create the html <form> element with width, height, bbox and all │ │ │ │ + * parameters specified in the layer params. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} The form element which sends the HTTP-POST request to the │ │ │ │ + * WMS. │ │ │ │ */ │ │ │ │ - onMapResize: function() { │ │ │ │ - // workaround for resizing of invisible or not yet fully loaded layers │ │ │ │ - // where GMap2.checkResize() does not work. We need to load the GMap │ │ │ │ - // for the old div size, then checkResize(), and then call │ │ │ │ - // layer.moveTo() to trigger GMap.setCenter() (which will finish │ │ │ │ - // the GMap initialization). │ │ │ │ - if (this.visibility && this.mapObject.isLoaded()) { │ │ │ │ - this.mapObject.checkResize(); │ │ │ │ - } else { │ │ │ │ - if (!this._resized) { │ │ │ │ - var layer = this; │ │ │ │ - var handle = GEvent.addListener(this.mapObject, "load", function() { │ │ │ │ - GEvent.removeListener(handle); │ │ │ │ - delete layer._resized; │ │ │ │ - layer.mapObject.checkResize(); │ │ │ │ - layer.moveTo(layer.map.getCenter(), layer.map.getZoom()); │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - this._resized = true; │ │ │ │ + createRequestForm: function() { │ │ │ │ + // creation of the form element │ │ │ │ + var form = document.createElement('form'); │ │ │ │ + form.method = 'POST'; │ │ │ │ + var cacheId = this.layer.params["_OLSALT"]; │ │ │ │ + cacheId = (cacheId ? cacheId + "_" : "") + this.bounds.toBBOX(); │ │ │ │ + form.action = OpenLayers.Util.urlAppend(this.layer.url, cacheId); │ │ │ │ + form.target = this.id + '_iFrame'; │ │ │ │ + │ │ │ │ + // adding all parameters in layer params as hidden fields to the html │ │ │ │ + // form element │ │ │ │ + var imageSize = this.layer.getImageSize(), │ │ │ │ + params = OpenLayers.Util.getParameters(this.url), │ │ │ │ + field; │ │ │ │ + │ │ │ │ + for (var par in params) { │ │ │ │ + field = document.createElement('input'); │ │ │ │ + field.type = 'hidden'; │ │ │ │ + field.name = par; │ │ │ │ + field.value = params[par]; │ │ │ │ + form.appendChild(field); │ │ │ │ } │ │ │ │ + │ │ │ │ + return form; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setGMapVisibility │ │ │ │ - * Display the GMap container and associated elements. │ │ │ │ - * │ │ │ │ + * Method: setImgSrc │ │ │ │ + * Sets the source for the tile image │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * visible - {Boolean} Display the GMap elements. │ │ │ │ + * url - {String} │ │ │ │ */ │ │ │ │ - setGMapVisibility: function(visible) { │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - var container = this.mapObject.getContainer(); │ │ │ │ - if (visible === true) { │ │ │ │ - this.mapObject.setMapType(this.type); │ │ │ │ - container.style.display = ""; │ │ │ │ - this.termsOfUse.style.left = ""; │ │ │ │ - this.termsOfUse.style.display = ""; │ │ │ │ - this.poweredBy.style.display = ""; │ │ │ │ - cache.displayed = this.id; │ │ │ │ - } else { │ │ │ │ - if (cache.displayed === this.id) { │ │ │ │ - delete cache.displayed; │ │ │ │ - } │ │ │ │ - if (!cache.displayed) { │ │ │ │ - container.style.display = "none"; │ │ │ │ - this.termsOfUse.style.display = "none"; │ │ │ │ - // move ToU far to the left in addition to setting display │ │ │ │ - // to "none", because at the end of the GMap2 load │ │ │ │ - // sequence, display: none will be unset and ToU would be │ │ │ │ - // visible after loading a map with a google layer that is │ │ │ │ - // initially hidden. │ │ │ │ - this.termsOfUse.style.left = "-9999px"; │ │ │ │ - this.poweredBy.style.display = "none"; │ │ │ │ - } │ │ │ │ + setImgSrc: function(url) { │ │ │ │ + if (this.useIFrame === true) { │ │ │ │ + if (url) { │ │ │ │ + var form = this.createRequestForm(); │ │ │ │ + this.frame.appendChild(form); │ │ │ │ + form.submit(); │ │ │ │ + this.frame.removeChild(form); │ │ │ │ + } else if (this.imgDiv.parentNode === this.frame) { │ │ │ │ + // we don't reuse iframes to avoid caching issues │ │ │ │ + this.frame.removeChild(this.imgDiv); │ │ │ │ + this.imgDiv = null; │ │ │ │ } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Tile.Image.prototype.setImgSrc.apply(this, arguments); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getMapContainer │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} the GMap container's div │ │ │ │ + * Method: onImageLoad │ │ │ │ + * Handler for the image onload event │ │ │ │ */ │ │ │ │ - getMapContainer: function() { │ │ │ │ - return this.mapObject.getContainer(); │ │ │ │ + onImageLoad: function() { │ │ │ │ + //TODO de-uglify opacity handling │ │ │ │ + OpenLayers.Tile.Image.prototype.onImageLoad.apply(this, arguments); │ │ │ │ + if (this.useIFrame === true) { │ │ │ │ + this.imgDiv.style.opacity = 1; │ │ │ │ + this.frame.style.opacity = this.layer.opacity; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - // │ │ │ │ - // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ - // │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectBoundsFromOLBounds │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * olBounds - {<OpenLayers.Bounds>} │ │ │ │ - * │ │ │ │ + * Method: createBackBuffer │ │ │ │ + * Override createBackBuffer to do nothing when we use an iframe. Moving an │ │ │ │ + * iframe from one element to another makes it necessary to reload the iframe │ │ │ │ + * because its content is lost. So we just give up. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} A MapObject Bounds, translated from olBounds │ │ │ │ - * Returns null if null value is passed in │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ - var moBounds = null; │ │ │ │ - if (olBounds != null) { │ │ │ │ - var sw = this.sphericalMercator ? │ │ │ │ - this.inverseMercator(olBounds.bottom, olBounds.left) : │ │ │ │ - new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ - var ne = this.sphericalMercator ? │ │ │ │ - this.inverseMercator(olBounds.top, olBounds.right) : │ │ │ │ - new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ - moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon), │ │ │ │ - new GLatLng(ne.lat, ne.lon)); │ │ │ │ + createBackBuffer: function() { │ │ │ │ + var backBuffer; │ │ │ │ + if (this.useIFrame === false) { │ │ │ │ + backBuffer = OpenLayers.Tile.Image.prototype.createBackBuffer.call(this); │ │ │ │ } │ │ │ │ - return moBounds; │ │ │ │ - }, │ │ │ │ + return backBuffer; │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Marker/Box.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. */ │ │ │ │ │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Interface Controls * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Marker.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - // Get&Set Center, Zoom │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Marker.Box │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Marker> │ │ │ │ + */ │ │ │ │ +OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setMapObjectCenter │ │ │ │ - * Set the mapObject to the specified center and zoom │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * center - {Object} MapObject LonLat format │ │ │ │ - * zoom - {int} MapObject zoom format │ │ │ │ + * Property: bounds │ │ │ │ + * {<OpenLayers.Bounds>} │ │ │ │ */ │ │ │ │ - setMapObjectCenter: function(center, zoom) { │ │ │ │ - this.mapObject.setCenter(center, zoom); │ │ │ │ - }, │ │ │ │ + bounds: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: dragPanMapObject │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Property: div │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + div: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Marker.Box │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * dX - {Integer} │ │ │ │ - * dY - {Integer} │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * borderColor - {String} │ │ │ │ + * borderWidth - {int} │ │ │ │ */ │ │ │ │ - dragPanMapObject: function(dX, dY) { │ │ │ │ - this.dragObject.moveBy(new GSize(-dX, dY)); │ │ │ │ + initialize: function(bounds, borderColor, borderWidth) { │ │ │ │ + this.bounds = bounds; │ │ │ │ + this.div = OpenLayers.Util.createDiv(); │ │ │ │ + this.div.style.overflow = 'hidden'; │ │ │ │ + this.events = new OpenLayers.Events(this, this.div); │ │ │ │ + this.setBorder(borderColor, borderWidth); │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ - // LonLat - Pixel Translation │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectLonLatFromMapObjectPixel │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moPixel - {Object} MapObject Pixel format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject LonLat translated from MapObject Pixel │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ - return this.mapObject.fromContainerPixelToLatLng(moPixel); │ │ │ │ + destroy: function() { │ │ │ │ + │ │ │ │ + this.bounds = null; │ │ │ │ + this.div = null; │ │ │ │ + │ │ │ │ + OpenLayers.Marker.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectPixelFromMapObjectLonLat │ │ │ │ + /** │ │ │ │ + * Method: setBorder │ │ │ │ + * Allow the user to change the box's color and border width │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * moLonLat - {Object} MapObject LonLat format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject Pixel transtlated from MapObject LonLat │ │ │ │ + * color - {String} Default is "red" │ │ │ │ + * width - {int} Default is 2 │ │ │ │ */ │ │ │ │ - getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - return this.mapObject.fromLatLngToContainerPixel(moLonLat); │ │ │ │ + setBorder: function(color, width) { │ │ │ │ + if (!color) { │ │ │ │ + color = "red"; │ │ │ │ + } │ │ │ │ + if (!width) { │ │ │ │ + width = 2; │ │ │ │ + } │ │ │ │ + this.div.style.border = width + "px solid " + color; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ - // Bounds │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectZoomFromMapObjectBounds │ │ │ │ + * Method: draw │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * moBounds - {Object} MapObject Bounds format │ │ │ │ + * px - {<OpenLayers.Pixel>} │ │ │ │ + * sz - {<OpenLayers.Size>} │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject Zoom for specified MapObject Bounds │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A new DOM Image with this marker's icon set at the │ │ │ │ + * location passed-in │ │ │ │ */ │ │ │ │ - getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ - return this.mapObject.getBoundsZoomLevel(moBounds); │ │ │ │ + draw: function(px, sz) { │ │ │ │ + OpenLayers.Util.modifyDOMElement(this.div, null, px, sz); │ │ │ │ + return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Primitives * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ - │ │ │ │ - │ │ │ │ - // LonLat │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectLonLatFromLonLat │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * lon - {Float} │ │ │ │ - * lat - {Float} │ │ │ │ + * Method: onScreen │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject LonLat built from lon and lat params │ │ │ │ + * Rreturn: │ │ │ │ + * {Boolean} Whether or not the marker is currently visible on screen. │ │ │ │ */ │ │ │ │ - getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ - var gLatLng; │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - var lonlat = this.inverseMercator(lon, lat); │ │ │ │ - gLatLng = new GLatLng(lonlat.lat, lonlat.lon); │ │ │ │ - } else { │ │ │ │ - gLatLng = new GLatLng(lat, lon); │ │ │ │ + onScreen: function() { │ │ │ │ + var onScreen = false; │ │ │ │ + if (this.map) { │ │ │ │ + var screenBounds = this.map.getExtent(); │ │ │ │ + onScreen = screenBounds.containsBounds(this.bounds, true, true); │ │ │ │ } │ │ │ │ - return gLatLng; │ │ │ │ + return onScreen; │ │ │ │ }, │ │ │ │ │ │ │ │ - // Pixel │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectPixelFromXY │ │ │ │ + * Method: display │ │ │ │ + * Hide or show the icon │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * x - {Integer} │ │ │ │ - * y - {Integer} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject Pixel from x and y parameters │ │ │ │ + * display - {Boolean} │ │ │ │ */ │ │ │ │ - getMapObjectPixelFromXY: function(x, y) { │ │ │ │ - return new GPoint(x, y); │ │ │ │ - } │ │ │ │ + display: function(display) { │ │ │ │ + this.div.style.display = (display) ? "" : "none"; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Marker.Box" │ │ │ │ +}); │ │ │ │ │ │ │ │ -}; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/WorldWind.js │ │ │ │ + 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/Layer/Grid.js │ │ │ │ + * @requires OpenLayers/Renderer.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.WorldWind │ │ │ │ + * Class: OpenLayers.Renderer.Canvas │ │ │ │ + * A renderer based on the 2D 'canvas' drawing element. │ │ │ │ * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * Inherits: │ │ │ │ + * - <OpenLayers.Renderer> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.WorldWind = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - │ │ │ │ - DEFAULT_PARAMS: {}, │ │ │ │ +OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} WorldWind layer is a base layer by default. │ │ │ │ + * APIProperty: hitDetection │ │ │ │ + * {Boolean} Allow for hit detection of features. Default is true. │ │ │ │ */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + hitDetection: true, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: lzd │ │ │ │ - * {Float} LevelZeroTileSizeDegrees │ │ │ │ + /** │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - lzd: null, │ │ │ │ + hitOverflow: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: zoomLevels │ │ │ │ - * {Integer} Number of zoom levels. │ │ │ │ + * Property: canvas │ │ │ │ + * {Canvas} The canvas context object. │ │ │ │ */ │ │ │ │ - zoomLevels: null, │ │ │ │ + canvas: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.WorldWind │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} Name of Layer │ │ │ │ - * url - {String} Base URL │ │ │ │ - * lzd - {Float} Level zero tile size degrees │ │ │ │ - * zoomLevels - {Integer} number of zoom levels │ │ │ │ - * params - {Object} additional parameters │ │ │ │ - * options - {Object} additional options │ │ │ │ + * Property: features │ │ │ │ + * {Object} Internal object of feature/style pairs for use in redrawing the layer. │ │ │ │ */ │ │ │ │ - initialize: function(name, url, lzd, zoomLevels, params, options) { │ │ │ │ - this.lzd = lzd; │ │ │ │ - this.zoomLevels = zoomLevels; │ │ │ │ - var newArguments = []; │ │ │ │ - newArguments.push(name, url, params, options); │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments); │ │ │ │ - this.params = OpenLayers.Util.applyDefaults( │ │ │ │ - this.params, this.DEFAULT_PARAMS │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ + features: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getZoom │ │ │ │ - * Convert map zoom to WW zoom. │ │ │ │ + * Property: pendingRedraw │ │ │ │ + * {Boolean} The renderer needs a redraw call to render features added while │ │ │ │ + * the renderer was locked. │ │ │ │ */ │ │ │ │ - getZoom: function() { │ │ │ │ - var zoom = this.map.getZoom(); │ │ │ │ - var extent = this.map.getMaxExtent(); │ │ │ │ - zoom = zoom - Math.log(this.maxResolution / (this.lzd / 512)) / Math.log(2); │ │ │ │ - return zoom; │ │ │ │ + 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: getURL │ │ │ │ + * Method: setExtent │ │ │ │ + * Set the visible part of the layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * extent - {<OpenLayers.Bounds>} │ │ │ │ + * resolutionChanged - {Boolean} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} A string with the layer's url and parameters and also the │ │ │ │ - * passed-in bounds and appropriate tile size specified as │ │ │ │ - * parameters │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var zoom = this.getZoom(); │ │ │ │ - var extent = this.map.getMaxExtent(); │ │ │ │ - var deg = this.lzd / Math.pow(2, this.getZoom()); │ │ │ │ - var x = Math.floor((bounds.left - extent.left) / deg); │ │ │ │ - var y = Math.floor((bounds.bottom - extent.bottom) / deg); │ │ │ │ - if (this.map.getResolution() <= (this.lzd / 512) && │ │ │ │ - this.getZoom() <= this.zoomLevels) { │ │ │ │ - return this.getFullRequestString({ │ │ │ │ - L: zoom, │ │ │ │ - X: x, │ │ │ │ - Y: y │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - return OpenLayers.Util.getImageLocation("blank.gif"); │ │ │ │ - } │ │ │ │ - │ │ │ │ + setExtent: function() { │ │ │ │ + OpenLayers.Renderer.prototype.setExtent.apply(this, arguments); │ │ │ │ + // always redraw features │ │ │ │ + return false; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.WorldWind" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Layer/TileCache.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.TileCache │ │ │ │ - * A read only TileCache layer. Used to requests tiles cached by TileCache in │ │ │ │ - * a web accessible cache. This means that you have to pre-populate your │ │ │ │ - * cache before this layer can be used. It is meant only to read tiles │ │ │ │ - * created by TileCache, and not to make calls to TileCache for tile │ │ │ │ - * creation. Create a new instance with the │ │ │ │ - * <OpenLayers.Layer.TileCache> constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ - */ │ │ │ │ -OpenLayers.Layer.TileCache = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} Treat this layer as a base layer. Default is true. │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + eraseGeometry: function(geometry, featureId) { │ │ │ │ + this.eraseFeatures(this.features[featureId][0]); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: format │ │ │ │ - * {String} Mime type of the images returned. Default is image/png. │ │ │ │ + /** │ │ │ │ + * APIMethod: supported │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the browser supports the renderer class │ │ │ │ */ │ │ │ │ - format: 'image/png', │ │ │ │ + supported: function() { │ │ │ │ + return OpenLayers.CANVAS_SUPPORTED; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. (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. │ │ │ │ + * Method: setSize │ │ │ │ + * Sets the size of the drawing surface. │ │ │ │ + * │ │ │ │ + * Once the size is updated, redraw the canvas. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * size - {<OpenLayers.Size>} │ │ │ │ */ │ │ │ │ - serverResolutions: null, │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.TileCache │ │ │ │ - * Create a new read only TileCache layer. │ │ │ │ + * Method: drawFeature │ │ │ │ + * Draw the feature. Stores the feature in the features list, │ │ │ │ + * then redraws the layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} Name of the layer displayed in the interface │ │ │ │ - * url - {String} Location of the web accessible cache (not the location of │ │ │ │ - * your tilecache script!) │ │ │ │ - * layername - {String} Layer name as defined in the TileCache │ │ │ │ - * configuration │ │ │ │ - * options - {Object} Optional object with properties to be set on the │ │ │ │ - * layer. Note that you should speficy your resolutions to match │ │ │ │ - * your TileCache configuration. This can be done by setting │ │ │ │ - * the resolutions array directly (here or on the map), by setting │ │ │ │ - * maxResolution and numZoomLevels, or by using scale based properties. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - initialize: function(name, url, layername, options) { │ │ │ │ - this.layername = layername; │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, │ │ │ │ - [name, url, {}, options]); │ │ │ │ - this.extension = this.format.split('/')[1].toLowerCase(); │ │ │ │ - this.extension = (this.extension == 'jpg') ? 'jpeg' : this.extension; │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * obj - {Object} │ │ │ │ + * Method: drawExternalGraphic │ │ │ │ + * Called to draw External graphics. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.TileCache>} An exact clone of this │ │ │ │ - * <OpenLayers.Layer.TileCache> │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ + drawExternalGraphic: function(geometry, style, featureId) { │ │ │ │ + var img = new Image(); │ │ │ │ │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.TileCache(this.name, │ │ │ │ - this.url, │ │ │ │ - this.layername, │ │ │ │ - this.getOptions()); │ │ │ │ + var title = style.title || style.graphicTitle; │ │ │ │ + if (title) { │ │ │ │ + img.title = title; │ │ │ │ } │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + 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); │ │ │ │ │ │ │ │ - // copy/set any non-init, non-simple values here │ │ │ │ + var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ │ │ │ │ - return obj; │ │ │ │ + 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: getURL │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * Method: drawNamedSymbol │ │ │ │ + * Called to draw Well Known Graphic Symbol Name. │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {String} A string with the layer's url and parameters and also the │ │ │ │ - * passed-in bounds and appropriate tile size specified as parameters. │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var bbox = this.maxExtent; │ │ │ │ - var size = this.tileSize; │ │ │ │ - var tileX = Math.round((bounds.left - bbox.left) / (res * size.w)); │ │ │ │ - var tileY = Math.round((bounds.bottom - bbox.bottom) / (res * size.h)); │ │ │ │ - var tileZ = this.serverResolutions != null ? │ │ │ │ - OpenLayers.Util.indexOf(this.serverResolutions, res) : │ │ │ │ - this.map.getZoom(); │ │ │ │ + drawNamedSymbol: function(geometry, style, featureId) { │ │ │ │ + var x, y, cx, cy, i, symbolBounds, scaling, angle; │ │ │ │ + var unscaledStrokeWidth; │ │ │ │ + var deg2rad = Math.PI / 180.0; │ │ │ │ │ │ │ │ - var components = [ │ │ │ │ - this.layername, │ │ │ │ - OpenLayers.Number.zeroPad(tileZ, 2), │ │ │ │ - OpenLayers.Number.zeroPad(parseInt(tileX / 1000000), 3), │ │ │ │ - OpenLayers.Number.zeroPad((parseInt(tileX / 1000) % 1000), 3), │ │ │ │ - OpenLayers.Number.zeroPad((parseInt(tileX) % 1000), 3), │ │ │ │ - OpenLayers.Number.zeroPad(parseInt(tileY / 1000000), 3), │ │ │ │ - OpenLayers.Number.zeroPad((parseInt(tileY / 1000) % 1000), 3), │ │ │ │ - OpenLayers.Number.zeroPad((parseInt(tileY) % 1000), 3) + '.' + this.extension │ │ │ │ - ]; │ │ │ │ - var path = components.join('/'); │ │ │ │ - var url = this.url; │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(path, url); │ │ │ │ + var symbol = OpenLayers.Renderer.symbol[style.graphicName]; │ │ │ │ + │ │ │ │ + if (!symbol) { │ │ │ │ + throw new Error(style.graphicName + ' is not a valid symbol name'); │ │ │ │ } │ │ │ │ - url = (url.charAt(url.length - 1) == '/') ? url : url + '/'; │ │ │ │ - return url + path; │ │ │ │ - }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.TileCache" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/Text.js │ │ │ │ - ====================================================================== */ │ │ │ │ + if (!symbol.length || symbol.length < 2) return; │ │ │ │ │ │ │ │ -/* 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 pt = this.getLocalXY(geometry); │ │ │ │ + var p0 = pt[0]; │ │ │ │ + var p1 = pt[1]; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Feature/Vector.js │ │ │ │ - * @requires OpenLayers/Geometry/Point.js │ │ │ │ - */ │ │ │ │ + if (isNaN(p0) || isNaN(p1)) return; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.Text │ │ │ │ - * Read Text format. Create a new instance with the <OpenLayers.Format.Text> │ │ │ │ - * constructor. This reads text which is formatted like CSV text, using │ │ │ │ - * tabs as the seperator by default. It provides parsing of data originally │ │ │ │ - * used in the MapViewerService, described on the wiki. This Format is used │ │ │ │ - * by the <OpenLayers.Layer.Text> class. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.Text = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ + // Use rounded line caps │ │ │ │ + this.canvas.lineCap = "round"; │ │ │ │ + this.canvas.lineJoin = "round"; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: defaultStyle │ │ │ │ - * defaultStyle allows one to control the default styling of the features. │ │ │ │ - * It should be a symbolizer hash. By default, this is set to match the │ │ │ │ - * Layer.Text behavior, which is to use the default OpenLayers Icon. │ │ │ │ - */ │ │ │ │ - defaultStyle: null, │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.lineCap = "round"; │ │ │ │ + this.hitContext.lineJoin = "round"; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: extractStyles │ │ │ │ - * set to true to extract styles from the TSV files, using information │ │ │ │ - * from the image or icon, iconSize and iconOffset fields. This will result │ │ │ │ - * in features with a symbolizer (style) property set, using the │ │ │ │ - * default symbolizer specified in <defaultStyle>. Set to false if you │ │ │ │ - * wish to use a styleMap or OpenLayers.Style options to style your │ │ │ │ - * layer instead. │ │ │ │ - */ │ │ │ │ - extractStyles: true, │ │ │ │ + // 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; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.Text │ │ │ │ - * Create a new parser for TSV Text. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ + // 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(); │ │ │ │ + } │ │ │ │ │ │ │ │ - if (options.extractStyles !== false) { │ │ │ │ - options.defaultStyle = { │ │ │ │ - 'externalGraphic': OpenLayers.Util.getImageLocation("marker.png"), │ │ │ │ - 'graphicWidth': 21, │ │ │ │ - 'graphicHeight': 25, │ │ │ │ - 'graphicXOffset': -10.5, │ │ │ │ - 'graphicYOffset': -12.5 │ │ │ │ - }; │ │ │ │ + // Step 3: place symbol at the desired location │ │ │ │ + this.canvas.translate(p0, p1); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.translate(p0, p1); │ │ │ │ } │ │ │ │ │ │ │ │ - OpenLayers.Format.prototype.initialize.apply(this, [options]); │ │ │ │ - }, │ │ │ │ + // 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Return a list of features from a Tab Seperated Values text string. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * text - {String} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ - */ │ │ │ │ - read: function(text) { │ │ │ │ - var lines = text.split('\n'); │ │ │ │ - var columns; │ │ │ │ - var features = []; │ │ │ │ - // length - 1 to allow for trailing new line │ │ │ │ - for (var lcv = 0; lcv < (lines.length - 1); lcv++) { │ │ │ │ - var currLine = lines[lcv].replace(/^\s*/, '').replace(/\s*$/, ''); │ │ │ │ + // // 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); │ │ │ │ + } │ │ │ │ │ │ │ │ - if (currLine.charAt(0) != '#') { │ │ │ │ - /* not a comment */ │ │ │ │ + // 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); │ │ │ │ + } │ │ │ │ │ │ │ │ - if (!columns) { │ │ │ │ - //First line is columns │ │ │ │ - columns = currLine.split('\t'); │ │ │ │ - } else { │ │ │ │ - var vals = currLine.split('\t'); │ │ │ │ - var geometry = new OpenLayers.Geometry.Point(0, 0); │ │ │ │ - var attributes = {}; │ │ │ │ - var style = this.defaultStyle ? │ │ │ │ - OpenLayers.Util.applyDefaults({}, this.defaultStyle) : │ │ │ │ - null; │ │ │ │ - var icon, iconSize, iconOffset, overflow; │ │ │ │ - var set = false; │ │ │ │ - for (var valIndex = 0; valIndex < vals.length; valIndex++) { │ │ │ │ - if (vals[valIndex]) { │ │ │ │ - if (columns[valIndex] == 'point') { │ │ │ │ - var coords = vals[valIndex].split(','); │ │ │ │ - geometry.y = parseFloat(coords[0]); │ │ │ │ - geometry.x = parseFloat(coords[1]); │ │ │ │ - set = true; │ │ │ │ - } else if (columns[valIndex] == 'lat') { │ │ │ │ - geometry.y = parseFloat(vals[valIndex]); │ │ │ │ - set = true; │ │ │ │ - } else if (columns[valIndex] == 'lon') { │ │ │ │ - geometry.x = parseFloat(vals[valIndex]); │ │ │ │ - set = true; │ │ │ │ - } else if (columns[valIndex] == 'title') │ │ │ │ - attributes['title'] = vals[valIndex]; │ │ │ │ - else if (columns[valIndex] == 'image' || │ │ │ │ - columns[valIndex] == 'icon' && style) { │ │ │ │ - style['externalGraphic'] = vals[valIndex]; │ │ │ │ - } else if (columns[valIndex] == 'iconSize' && style) { │ │ │ │ - var size = vals[valIndex].split(','); │ │ │ │ - style['graphicWidth'] = parseFloat(size[0]); │ │ │ │ - style['graphicHeight'] = parseFloat(size[1]); │ │ │ │ - } else if (columns[valIndex] == 'iconOffset' && style) { │ │ │ │ - var offset = vals[valIndex].split(','); │ │ │ │ - style['graphicXOffset'] = parseFloat(offset[0]); │ │ │ │ - style['graphicYOffset'] = parseFloat(offset[1]); │ │ │ │ - } else if (columns[valIndex] == 'description') { │ │ │ │ - attributes['description'] = vals[valIndex]; │ │ │ │ - } else if (columns[valIndex] == 'overflow') { │ │ │ │ - attributes['overflow'] = vals[valIndex]; │ │ │ │ - } else { │ │ │ │ - // For StyleMap filtering, allow additional │ │ │ │ - // columns to be stored as attributes. │ │ │ │ - attributes[columns[valIndex]] = vals[valIndex]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (set) { │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - geometry.transform(this.externalProjection, │ │ │ │ - this.internalProjection); │ │ │ │ - } │ │ │ │ - var feature = new OpenLayers.Feature.Vector(geometry, attributes, style); │ │ │ │ - features.push(feature); │ │ │ │ - } │ │ │ │ + // 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(); │ │ │ │ } │ │ │ │ } │ │ │ │ - return features; │ │ │ │ - }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.Text" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Layer/Text.js │ │ │ │ - ====================================================================== */ │ │ │ │ + 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(); │ │ │ │ │ │ │ │ -/* 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. */ │ │ │ │ │ │ │ │ + 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(); │ │ │ │ + } │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Layer/Markers.js │ │ │ │ - * @requires OpenLayers/Format/Text.js │ │ │ │ - * @requires OpenLayers/Request/XMLHttpRequest.js │ │ │ │ - */ │ │ │ │ + } │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Layer.Text │ │ │ │ - * This layer creates markers given data in a text file. The <location> │ │ │ │ - * property of the layer (specified as a property of the options argument │ │ │ │ - * in the <OpenLayers.Layer.Text> constructor) points to a tab delimited │ │ │ │ - * file with data used to create markers. │ │ │ │ - * │ │ │ │ - * The first row of the data file should be a header line with the column names │ │ │ │ - * of the data. Each column should be delimited by a tab space. The │ │ │ │ - * possible columns are: │ │ │ │ - * - *point* lat,lon of the point where a marker is to be placed │ │ │ │ - * - *lat* Latitude of the point where a marker is to be placed │ │ │ │ - * - *lon* Longitude of the point where a marker is to be placed │ │ │ │ - * - *icon* or *image* URL of marker icon to use. │ │ │ │ - * - *iconSize* Size of Icon to use. │ │ │ │ - * - *iconOffset* Where the top-left corner of the icon is to be placed │ │ │ │ - * relative to the latitude and longitude of the point. │ │ │ │ - * - *title* The text of the 'title' is placed inside an 'h2' marker │ │ │ │ - * inside a popup, which opens when the marker is clicked. │ │ │ │ - * - *description* The text of the 'description' is placed below the h2 │ │ │ │ - * in the popup. this can be plain text or HTML. │ │ │ │ - * │ │ │ │ - * Example text file: │ │ │ │ - * (code) │ │ │ │ - * lat lon title description iconSize iconOffset icon │ │ │ │ - * 10 20 title description 21,25 -10,-25 http://www.openlayers.org/dev/img/marker.png │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Markers> │ │ │ │ - */ │ │ │ │ -OpenLayers.Layer.Text = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ + style.strokeWidth = unscaledStrokeWidth; │ │ │ │ + this.canvas.restore(); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.restore(); │ │ │ │ + } │ │ │ │ + this.setCanvasStyle("reset"); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: location │ │ │ │ - * {String} URL of text file. Must be specified in the "options" argument │ │ │ │ - * of the constructor. Can not be changed once passed in. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - location: null, │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: features │ │ │ │ - * {Array(<OpenLayers.Feature>)} │ │ │ │ + /** │ │ │ │ + * Method: featureIdToHex │ │ │ │ + * Convert a feature ID string into an RGB hex string. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * featureId - {String} Feature id │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} RGB hex string. │ │ │ │ */ │ │ │ │ - features: null, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: formatOptions │ │ │ │ - * {Object} Hash of options which should be passed to the format when it is │ │ │ │ - * created. Must be passed in the constructor. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - formatOptions: null, │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: selectedFeature │ │ │ │ - * {<OpenLayers.Feature>} │ │ │ │ + /** │ │ │ │ + * Method: drawPoint │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - selectedFeature: null, │ │ │ │ + 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"); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.Text │ │ │ │ - * Create a text layer. │ │ │ │ + * Method: drawLineString │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * options - {Object} Object with properties to be set on the layer. │ │ │ │ - * Must include <location> property. │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - initialize: function(name, options) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.initialize.apply(this, arguments); │ │ │ │ - this.features = []; │ │ │ │ + drawLineString: function(geometry, style, featureId) { │ │ │ │ + style = OpenLayers.Util.applyDefaults({ │ │ │ │ + fill: false │ │ │ │ + }, style); │ │ │ │ + this.drawLinearRing(geometry, style, featureId); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ + * Method: drawLinearRing │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - // Warning: Layer.Markers.destroy() must be called prior to calling │ │ │ │ - // clearFeatures() here, otherwise we leak memory. Indeed, if │ │ │ │ - // Layer.Markers.destroy() is called after clearFeatures(), it won't be │ │ │ │ - // able to remove the marker image elements from the layer's div since │ │ │ │ - // the markers will have been destroyed by clearFeatures(). │ │ │ │ - OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ - this.clearFeatures(); │ │ │ │ - this.features = null; │ │ │ │ + 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: loadText │ │ │ │ - * Start the load of the Text data. Don't do this when we first add the layer, │ │ │ │ - * since we may not be visible at any point, and it would therefore be a waste. │ │ │ │ + * Method: renderPath │ │ │ │ + * Render a path with stroke and optional fill. │ │ │ │ */ │ │ │ │ - loadText: function() { │ │ │ │ - if (!this.loaded) { │ │ │ │ - if (this.location != null) { │ │ │ │ - │ │ │ │ - var onFail = function(e) { │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ - }; │ │ │ │ - │ │ │ │ - this.events.triggerEvent("loadstart"); │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ - url: this.location, │ │ │ │ - success: this.parseData, │ │ │ │ - failure: onFail, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.loaded = true; │ │ │ │ + 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: moveTo │ │ │ │ - * If layer is visible and Text has not been loaded, load Text. │ │ │ │ + * Method: drawPolygon │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {Object} │ │ │ │ - * zoomChanged - {Object} │ │ │ │ - * minor - {Object} │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ - if (this.visibility && !this.loaded) { │ │ │ │ - this.loadText(); │ │ │ │ + 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: parseData │ │ │ │ + * Method: drawText │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * ajaxRequest - {<OpenLayers.Request.XMLHttpRequest>} │ │ │ │ + * location - {<OpenLayers.Point>} │ │ │ │ + * style - {Object} │ │ │ │ */ │ │ │ │ - parseData: function(ajaxRequest) { │ │ │ │ - var text = ajaxRequest.responseText; │ │ │ │ - │ │ │ │ - var options = {}; │ │ │ │ - │ │ │ │ - OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ - │ │ │ │ - if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ - options.externalProjection = this.projection; │ │ │ │ - options.internalProjection = this.map.getProjectionObject(); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var parser = new OpenLayers.Format.Text(options); │ │ │ │ - var features = parser.read(text); │ │ │ │ - for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ - var data = {}; │ │ │ │ - var feature = features[i]; │ │ │ │ - var location; │ │ │ │ - var iconSize, iconOffset; │ │ │ │ - │ │ │ │ - location = new OpenLayers.LonLat(feature.geometry.x, │ │ │ │ - feature.geometry.y); │ │ │ │ - │ │ │ │ - if (feature.style.graphicWidth && │ │ │ │ - feature.style.graphicHeight) { │ │ │ │ - iconSize = new OpenLayers.Size( │ │ │ │ - feature.style.graphicWidth, │ │ │ │ - feature.style.graphicHeight); │ │ │ │ - } │ │ │ │ + drawText: function(location, style) { │ │ │ │ + var pt = this.getLocalXY(location); │ │ │ │ │ │ │ │ - // FIXME: At the moment, we only use this if we have an │ │ │ │ - // externalGraphic, because icon has no setOffset API Method. │ │ │ │ - /** │ │ │ │ - * FIXME FIRST!! │ │ │ │ - * The Text format does all sorts of parseFloating │ │ │ │ - * The result of a parseFloat for a bogus string is NaN. That │ │ │ │ - * means the three possible values here are undefined, NaN, or a │ │ │ │ - * number. The previous check was an identity check for null. This │ │ │ │ - * means it was failing for all undefined or NaN. A slightly better │ │ │ │ - * check is for undefined. An even better check is to see if the │ │ │ │ - * value is a number (see #1441). │ │ │ │ - */ │ │ │ │ - if (feature.style.graphicXOffset !== undefined && │ │ │ │ - feature.style.graphicYOffset !== undefined) { │ │ │ │ - iconOffset = new OpenLayers.Pixel( │ │ │ │ - feature.style.graphicXOffset, │ │ │ │ - feature.style.graphicYOffset); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - │ │ │ │ - if (feature.style.externalGraphic != null) { │ │ │ │ - data.icon = new OpenLayers.Icon(feature.style.externalGraphic, │ │ │ │ - iconSize, │ │ │ │ - iconOffset); │ │ │ │ - } else { │ │ │ │ - data.icon = OpenLayers.Marker.defaultIcon(); │ │ │ │ - │ │ │ │ - //allows for the case where the image url is not │ │ │ │ - // specified but the size is. use a default icon │ │ │ │ - // but change the size │ │ │ │ - if (iconSize != null) { │ │ │ │ - data.icon.setSize(iconSize); │ │ │ │ + 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)); │ │ │ │ } │ │ │ │ - │ │ │ │ - if ((feature.attributes.title != null) && │ │ │ │ - (feature.attributes.description != null)) { │ │ │ │ - data['popupContentHTML'] = │ │ │ │ - '<h2>' + feature.attributes.title + '</h2>' + │ │ │ │ - '<p>' + feature.attributes.description + '</p>'; │ │ │ │ + } 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; │ │ │ │ } │ │ │ │ - │ │ │ │ - data['overflow'] = feature.attributes.overflow || "auto"; │ │ │ │ - │ │ │ │ - var markerFeature = new OpenLayers.Feature(this, location, data); │ │ │ │ - this.features.push(markerFeature); │ │ │ │ - var marker = markerFeature.createMarker(); │ │ │ │ - if ((feature.attributes.title != null) && │ │ │ │ - (feature.attributes.description != null)) { │ │ │ │ - marker.events.register('click', markerFeature, this.markerClick); │ │ │ │ + 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.addMarker(marker); │ │ │ │ } │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ + this.setCanvasStyle("reset"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: markerClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * Method: getLocalXY │ │ │ │ + * transform geographic xy into pixel xy │ │ │ │ * │ │ │ │ - * Context: │ │ │ │ - * - {<OpenLayers.Feature>} │ │ │ │ + * Parameters: │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} │ │ │ │ */ │ │ │ │ - markerClick: function(evt) { │ │ │ │ - var sameMarkerClicked = (this == this.layer.selectedFeature); │ │ │ │ - this.layer.selectedFeature = (!sameMarkerClicked) ? this : null; │ │ │ │ - for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ - this.layer.map.removePopup(this.layer.map.popups[i]); │ │ │ │ - } │ │ │ │ - if (!sameMarkerClicked) { │ │ │ │ - this.layer.map.addPopup(this.createPopup()); │ │ │ │ - } │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ + 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: clearFeatures │ │ │ │ + * Method: clear │ │ │ │ + * Clear all vectors from the renderer. │ │ │ │ */ │ │ │ │ - clearFeatures: function() { │ │ │ │ - if (this.features != null) { │ │ │ │ - while (this.features.length > 0) { │ │ │ │ - var feature = this.features[0]; │ │ │ │ - OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ - feature.destroy(); │ │ │ │ - } │ │ │ │ + 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); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Text" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Layer/Boxes.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/Layer/Markers.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Layer.Boxes │ │ │ │ - * Draw divs as 'boxes' on the layer. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Markers> │ │ │ │ - */ │ │ │ │ -OpenLayers.Layer.Boxes = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.Boxes │ │ │ │ - * │ │ │ │ + * Method: getFeatureIdFromEvent │ │ │ │ + * Returns a feature id from an event on the renderer. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: drawMarker │ │ │ │ - * Calculate the pixel location for the marker, create it, and │ │ │ │ - * add it to the layer's div │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * marker - {<OpenLayers.Marker.Box>} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - drawMarker: function(marker) { │ │ │ │ - var topleft = this.map.getLayerPxFromLonLat({ │ │ │ │ - lon: marker.bounds.left, │ │ │ │ - lat: marker.bounds.top │ │ │ │ - }); │ │ │ │ - var botright = this.map.getLayerPxFromLonLat({ │ │ │ │ - lon: marker.bounds.right, │ │ │ │ - lat: marker.bounds.bottom │ │ │ │ - }); │ │ │ │ - if (botright == null || topleft == null) { │ │ │ │ - marker.display(false); │ │ │ │ - } else { │ │ │ │ - var markerDiv = marker.draw(topleft, { │ │ │ │ - w: Math.max(1, botright.x - topleft.x), │ │ │ │ - h: Math.max(1, botright.y - topleft.y) │ │ │ │ - }); │ │ │ │ - if (!marker.drawn) { │ │ │ │ - this.div.appendChild(markerDiv); │ │ │ │ - marker.drawn = true; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: removeMarker │ │ │ │ + * Method: eraseFeatures │ │ │ │ + * This is called by the layer to erase features; removes the feature from │ │ │ │ + * the list, then redraws the layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * marker - {<OpenLayers.Marker.Box>} │ │ │ │ + * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ */ │ │ │ │ - removeMarker: function(marker) { │ │ │ │ - OpenLayers.Util.removeItem(this.markers, marker); │ │ │ │ - if ((marker.div != null) && │ │ │ │ - (marker.div.parentNode == this.div)) { │ │ │ │ - this.div.removeChild(marker.div); │ │ │ │ + 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(); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Boxes" │ │ │ │ + /** │ │ │ │ + * 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/Layer/Vector.js │ │ │ │ + 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/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> │ │ │ │ + * 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.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, │ │ │ │ +OpenLayers.ElementsIndexer = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: styleMap │ │ │ │ - * {<OpenLayers.StyleMap>} │ │ │ │ + * Property: maxZIndex │ │ │ │ + * {Integer} This is the largest-most z-index value for a node │ │ │ │ + * contained within the indexer. │ │ │ │ */ │ │ │ │ - styleMap: null, │ │ │ │ + maxZIndex: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: strategies │ │ │ │ - * {Array(<OpenLayers.Strategy>})} Optional list of strategies for the layer. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - strategies: null, │ │ │ │ + order: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: protocol │ │ │ │ - * {<OpenLayers.Protocol>} Optional protocol for the layer. │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - protocol: null, │ │ │ │ + indices: 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>} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - renderer: null, │ │ │ │ + compare: 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. │ │ │ │ + * APIMethod: initialize │ │ │ │ + * Create a new indexer with │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * yOrdering - {Boolean} Whether to use y-ordering. │ │ │ │ */ │ │ │ │ - geometryType: null, │ │ │ │ + initialize: function(yOrdering) { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: drawn │ │ │ │ - * {Boolean} Whether the Vector Layer features have been drawn yet. │ │ │ │ - */ │ │ │ │ - drawn: false, │ │ │ │ + this.compare = yOrdering ? │ │ │ │ + OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER : │ │ │ │ + OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + this.clear(); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.Vector │ │ │ │ - * Create a new vector layer │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * 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 │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ │ │ │ │ - // if no valid renderer found, display error │ │ │ │ - if (!this.renderer || !this.renderer.supported()) { │ │ │ │ - this.renderer = null; │ │ │ │ - this.displayError(); │ │ │ │ - } │ │ │ │ + var nodeId = newNode.id; │ │ │ │ │ │ │ │ - if (!this.styleMap) { │ │ │ │ - this.styleMap = new OpenLayers.StyleMap(); │ │ │ │ - } │ │ │ │ + this.determineZIndex(newNode); │ │ │ │ │ │ │ │ - this.features = []; │ │ │ │ - this.selectedFeatures = []; │ │ │ │ - this.unrenderedFeatures = {}; │ │ │ │ + var leftIndex = -1; │ │ │ │ + var rightIndex = this.order.length; │ │ │ │ + var middle; │ │ │ │ │ │ │ │ - // Allow for custom layer behavior │ │ │ │ - if (this.strategies) { │ │ │ │ - for (var i = 0, len = this.strategies.length; i < len; i++) { │ │ │ │ - this.strategies[i].setLayer(this); │ │ │ │ + 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: destroy │ │ │ │ - * Destroy this layer │ │ │ │ + * APIMethod: remove │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} The node to be removed. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - 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 │ │ │ │ + * APIMethod: clear │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + clear: function() { │ │ │ │ + this.order = []; │ │ │ │ + this.indices = {}; │ │ │ │ + this.maxZIndex = 0; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: refresh │ │ │ │ - * Ask the layer to request features again and redraw them. Triggers │ │ │ │ - * the refresh event if the layer is in range and visible. │ │ │ │ + * APIMethod: exists │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * node - {DOMElement} The node to test for existence. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the node exists in the indexer? │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + exists: function(node) { │ │ │ │ + return (this.indices[node.id] != null); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: displayError │ │ │ │ - * Let the user know their browser isn't supported. │ │ │ │ + /** │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - displayError: function() { │ │ │ │ - if (this.reportError) { │ │ │ │ - OpenLayers.Console.userError(OpenLayers.i18n("browserNotSupported", { │ │ │ │ - renderers: this.renderers.join('\n') │ │ │ │ - })); │ │ │ │ - } │ │ │ │ + getZIndex: function(node) { │ │ │ │ + return node._style.graphicZIndex; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * 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: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * node - {DOMElement} │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.prototype.setMap.apply(this, arguments); │ │ │ │ - │ │ │ │ - if (!this.renderer) { │ │ │ │ - this.map.removeLayer(this); │ │ │ │ - } else { │ │ │ │ - this.renderer.map = this.map; │ │ │ │ + determineZIndex: function(node) { │ │ │ │ + var zIndex = node._style.graphicZIndex; │ │ │ │ │ │ │ │ - var newSize = this.map.getSize(); │ │ │ │ - newSize.w = newSize.w * this.ratio; │ │ │ │ - newSize.h = newSize.h * this.ratio; │ │ │ │ - this.renderer.setSize(newSize); │ │ │ │ + // 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; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ + 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: removeMap │ │ │ │ - * The layer has been removed from the map. │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * indexer - {<OpenLayers.ElementsIndexer>} │ │ │ │ + * newNode - {DOMElement} │ │ │ │ + * nextNode - {DOMElement} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onMapResize │ │ │ │ - * Notify the renderer of the change in size. │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - onMapResize: function() { │ │ │ │ - OpenLayers.Layer.prototype.onMapResize.apply(this, arguments); │ │ │ │ + Z_ORDER_DRAWING_ORDER: function(indexer, newNode, nextNode) { │ │ │ │ + var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER( │ │ │ │ + indexer, │ │ │ │ + newNode, │ │ │ │ + nextNode │ │ │ │ + ); │ │ │ │ │ │ │ │ - var newSize = this.map.getSize(); │ │ │ │ - newSize.w = newSize.w * this.ratio; │ │ │ │ - newSize.h = newSize.h * this.ratio; │ │ │ │ - this.renderer.setSize(newSize); │ │ │ │ + // 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - * zoomChanged - {Boolean} │ │ │ │ - * dragging - {Boolean} │ │ │ │ + * indexer - {<OpenLayers.ElementsIndexer>} │ │ │ │ + * newNode - {DOMElement} │ │ │ │ + * nextNode - {DOMElement} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + Z_ORDER_Y_ORDER: function(indexer, newNode, nextNode) { │ │ │ │ + var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER( │ │ │ │ + indexer, │ │ │ │ + newNode, │ │ │ │ + nextNode │ │ │ │ + ); │ │ │ │ │ │ │ │ - this.renderer.root.style.visibility = 'visible'; │ │ │ │ + if (nextNode && returnVal === 0) { │ │ │ │ + var result = nextNode._boundsBottom - newNode._boundsBottom; │ │ │ │ + returnVal = (result === 0) ? 1 : result; │ │ │ │ + } │ │ │ │ │ │ │ │ - // 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; │ │ │ │ - } │ │ │ │ + return returnVal; │ │ │ │ + } │ │ │ │ +}; │ │ │ │ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * 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, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: display │ │ │ │ - * Hide or show the Layer │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * display - {Boolean} │ │ │ │ + /** │ │ │ │ + * Property: rendererRoot │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + rendererRoot: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: addFeatures │ │ │ │ - * Add Features to the layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ - * options - {Object} │ │ │ │ + * Property: root │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + root: null, │ │ │ │ │ │ │ │ - // 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]; │ │ │ │ + /** │ │ │ │ + * Property: vectorRoot │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + vectorRoot: null, │ │ │ │ │ │ │ │ - if (this.geometryType && │ │ │ │ - !(feature.geometry instanceof this.geometryType)) { │ │ │ │ - throw new TypeError('addFeatures: component should be an ' + │ │ │ │ - this.geometryType.prototype.CLASS_NAME); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: textRoot │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + textRoot: null, │ │ │ │ │ │ │ │ - //give feature reference to its layer │ │ │ │ - feature.layer = this; │ │ │ │ + /** │ │ │ │ + * Property: xmlns │ │ │ │ + * {String} │ │ │ │ + */ │ │ │ │ + xmlns: null, │ │ │ │ │ │ │ │ - if (!feature.style && this.style) { │ │ │ │ - feature.style = OpenLayers.Util.extend({}, this.style); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - if (notify) { │ │ │ │ - if (this.events.triggerEvent("beforefeatureadded", { │ │ │ │ - feature: feature │ │ │ │ - }) === false) { │ │ │ │ - continue; │ │ │ │ - } │ │ │ │ - this.preFeatureInsert(feature); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ + */ │ │ │ │ │ │ │ │ - featuresAdded.push(feature); │ │ │ │ - this.features.push(feature); │ │ │ │ - this.drawFeature(feature); │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - if (notify) { │ │ │ │ - this.events.triggerEvent("featureadded", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - this.onFeatureInsert(feature); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Constant: BACKGROUND_ID_SUFFIX │ │ │ │ + * {String} │ │ │ │ + */ │ │ │ │ + BACKGROUND_ID_SUFFIX: "_background", │ │ │ │ │ │ │ │ - if (notify) { │ │ │ │ - this.events.triggerEvent("featuresadded", { │ │ │ │ - features: featuresAdded │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Constant: LABEL_ID_SUFFIX │ │ │ │ + * {String} │ │ │ │ + */ │ │ │ │ + LABEL_ID_SUFFIX: "_label", │ │ │ │ │ │ │ │ + /** │ │ │ │ + * Constant: LABEL_OUTLINE_SUFFIX │ │ │ │ + * {String} │ │ │ │ + */ │ │ │ │ + LABEL_OUTLINE_SUFFIX: "_outline", │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Constructor: OpenLayers.Renderer.Elements │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} List of features to be │ │ │ │ - * removed. │ │ │ │ - * options - {Object} Optional properties for changing behavior of the │ │ │ │ - * removal. │ │ │ │ + * containerID - {String} │ │ │ │ + * options - {Object} options for this renderer. │ │ │ │ * │ │ │ │ - * Valid options: │ │ │ │ - * silent - {Boolean} Supress event triggering. Default is false. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + initialize: function(containerID, options) { │ │ │ │ + OpenLayers.Renderer.prototype.initialize.apply(this, arguments); │ │ │ │ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + this.rendererRoot = this.createRenderRoot(); │ │ │ │ + this.root = this.createRoot("_root"); │ │ │ │ + this.vectorRoot = this.createRoot("_vroot"); │ │ │ │ + this.textRoot = this.createRoot("_troot"); │ │ │ │ │ │ │ │ - var feature = features[i]; │ │ │ │ - delete this.unrenderedFeatures[feature.id]; │ │ │ │ + this.root.appendChild(this.vectorRoot); │ │ │ │ + this.root.appendChild(this.textRoot); │ │ │ │ │ │ │ │ - if (notify) { │ │ │ │ - this.events.triggerEvent("beforefeatureremoved", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - } │ │ │ │ + this.rendererRoot.appendChild(this.root); │ │ │ │ + this.container.appendChild(this.rendererRoot); │ │ │ │ │ │ │ │ - this.features = OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ - // feature has no layer at this point │ │ │ │ - feature.layer = null; │ │ │ │ + if (options && (options.zIndexing || options.yOrdering)) { │ │ │ │ + this.indexer = new OpenLayers.ElementsIndexer(options.yOrdering); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (feature.geometry) { │ │ │ │ - this.renderer.eraseFeatures(feature); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ │ │ │ │ - //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); │ │ │ │ - } │ │ │ │ + this.clear(); │ │ │ │ │ │ │ │ - if (notify) { │ │ │ │ - this.events.triggerEvent("featureremoved", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + this.rendererRoot = null; │ │ │ │ + this.root = null; │ │ │ │ + this.xmlns = null; │ │ │ │ │ │ │ │ - if (notify) { │ │ │ │ - this.events.triggerEvent("featuresremoved", { │ │ │ │ - features: features │ │ │ │ - }); │ │ │ │ - } │ │ │ │ + OpenLayers.Renderer.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * Method: clear │ │ │ │ + * Remove all the elements from the root │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + clear: function() { │ │ │ │ + var child; │ │ │ │ + var root = this.vectorRoot; │ │ │ │ + if (root) { │ │ │ │ + while (child = root.firstChild) { │ │ │ │ + root.removeChild(child); │ │ │ │ } │ │ │ │ - feature.layer = null; │ │ │ │ - if (notify) { │ │ │ │ - this.events.triggerEvent("featureremoved", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ + } │ │ │ │ + root = this.textRoot; │ │ │ │ + if (root) { │ │ │ │ + while (child = root.firstChild) { │ │ │ │ + root.removeChild(child); │ │ │ │ } │ │ │ │ } │ │ │ │ - this.renderer.clear(); │ │ │ │ - this.features = []; │ │ │ │ - this.unrenderedFeatures = {}; │ │ │ │ - this.selectedFeatures = []; │ │ │ │ - if (notify) { │ │ │ │ - this.events.triggerEvent("featuresremoved", { │ │ │ │ - features: features │ │ │ │ - }); │ │ │ │ + if (this.indexer) { │ │ │ │ + this.indexer.clear(); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroyFeatures │ │ │ │ - * Erase and destroy features on the layer. │ │ │ │ + * Method: setExtent │ │ │ │ + * Set the visible part of 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. │ │ │ │ + * extent - {<OpenLayers.Bounds>} │ │ │ │ + * resolutionChanged - {Boolean} │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - * style - {String | Object} Named render intent or full symbolizer object. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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"; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - var renderIntent = style || feature.renderIntent; │ │ │ │ - style = feature.style || this.style; │ │ │ │ - if (!style) { │ │ │ │ - style = this.styleMap.createSymbolizer(feature, renderIntent); │ │ │ │ + if (rightOfDateLine !== this.rightOfDateLine || resolutionChanged) { │ │ │ │ + coordSysUnchanged = false; │ │ │ │ + this.xOffset = rightOfDateLine === true ? │ │ │ │ + world.getWidth() / resolution : 0; │ │ │ │ } │ │ │ │ + this.rightOfDateLine = rightOfDateLine; │ │ │ │ } │ │ │ │ - │ │ │ │ - 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]; │ │ │ │ - } │ │ │ │ + return coordSysUnchanged; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: eraseFeatures │ │ │ │ - * Erase features from the layer. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * 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: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} The corresponding node type for the specified geometry │ │ │ │ */ │ │ │ │ - eraseFeatures: function(features) { │ │ │ │ - this.renderer.eraseFeatures(features); │ │ │ │ - }, │ │ │ │ + getNodeType: function(geometry, style) {}, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getFeatureFromEvent │ │ │ │ - * Given an event, return a feature if the event occurred over one. │ │ │ │ - * Otherwise, return null. │ │ │ │ + /** │ │ │ │ + * 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: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} A feature if one was under the event. │ │ │ │ + * {Boolean} true if the geometry has been drawn completely; null if │ │ │ │ + * incomplete; false otherwise │ │ │ │ */ │ │ │ │ - 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.'); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - var feature = null; │ │ │ │ - var featureId = this.renderer.getFeatureIdFromEvent(evt); │ │ │ │ - if (featureId) { │ │ │ │ - if (typeof featureId === "string") { │ │ │ │ - feature = this.getFeatureById(featureId); │ │ │ │ + │ │ │ │ + rendered = false; │ │ │ │ + var removeBackground = false; │ │ │ │ + if (style.display != "none") { │ │ │ │ + if (style.backgroundGraphic) { │ │ │ │ + this.redrawBackgroundNode(geometry.id, geometry, style, │ │ │ │ + featureId); │ │ │ │ } else { │ │ │ │ - feature = featureId; │ │ │ │ + removeBackground = true; │ │ │ │ } │ │ │ │ + rendered = this.redrawNode(geometry.id, geometry, style, │ │ │ │ + featureId); │ │ │ │ } │ │ │ │ - return feature; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getFeatureBy │ │ │ │ - * Given a property value, return the feature if it exists in the features array │ │ │ │ - * │ │ │ │ + * Method: redrawNode │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * property - {String} │ │ │ │ - * value - {String} │ │ │ │ - * │ │ │ │ + * id - {String} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} A feature corresponding to the given │ │ │ │ - * property value or null if there is no such feature. │ │ │ │ + * {Boolean} true if the complete geometry could be drawn, null if parts of │ │ │ │ + * the geometry could not be drawn, false otherwise │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ } │ │ │ │ - return feature; │ │ │ │ + │ │ │ │ + this.postDraw(node); │ │ │ │ + │ │ │ │ + return drawResult.complete; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getFeatureById │ │ │ │ - * Given a feature id, return the feature if it exists in the features array │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * {<OpenLayers.Feature.Vector>} A feature corresponding to the given │ │ │ │ - * featureId or null if there is no such feature. │ │ │ │ + * {Boolean} true if the complete geometry could be drawn, null if parts of │ │ │ │ + * the geometry could not be drawn, false otherwise │ │ │ │ */ │ │ │ │ - getFeatureById: function(featureId) { │ │ │ │ - return this.getFeatureBy('id', featureId); │ │ │ │ - }, │ │ │ │ + redrawBackgroundNode: function(id, geometry, style, featureId) { │ │ │ │ + var backgroundStyle = OpenLayers.Util.extend({}, style); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + // 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 │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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: │ │ │ │ - * attrName - {String} │ │ │ │ - * attrValue - {Mixed} │ │ │ │ - * │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * Array({<OpenLayers.Feature.Vector>}) An array of features that have the │ │ │ │ - * passed named attribute set to the given value. │ │ │ │ + * {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) │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - return foundFeatures; │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Unselect the selected features │ │ │ │ - * i.e. clears the featureSelection array │ │ │ │ - * change the style back │ │ │ │ - clearSelection: function() { │ │ │ │ + node._options = options; │ │ │ │ │ │ │ │ - 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); │ │ │ │ + //set style │ │ │ │ + //TBD simplify this │ │ │ │ + if (drawn != false) { │ │ │ │ + return { │ │ │ │ + node: this.setStyle(node, style, options, geometry), │ │ │ │ + complete: drawn │ │ │ │ + }; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ } │ │ │ │ - this.map.featureSelection = []; │ │ │ │ }, │ │ │ │ - */ │ │ │ │ │ │ │ │ + /** │ │ │ │ + * 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) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: onFeatureInsert │ │ │ │ - * method called after a feature is inserted. │ │ │ │ - * Does nothing by default. Override this if you │ │ │ │ - * need to do something on feature updates. │ │ │ │ - * │ │ │ │ + * Method: drawPoint │ │ │ │ + * Virtual function for drawing Point Geometry. │ │ │ │ + * Should be implemented by subclasses. │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} or false if the renderer could not draw the point │ │ │ │ */ │ │ │ │ - onFeatureInsert: function(feature) {}, │ │ │ │ + drawPoint: function(node, geometry) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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>} │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - preFeatureInsert: function(feature) {}, │ │ │ │ + drawLineString: function(node, geometry) {}, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getDataExtent │ │ │ │ - * Calculates the max extent which includes all of the features. │ │ │ │ + /** │ │ │ │ + * 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: │ │ │ │ - * {<OpenLayers.Bounds>} or null if the layer has no features with │ │ │ │ - * geometries. │ │ │ │ + * {DOMElement} or null if the renderer could not draw all components │ │ │ │ + * of the linear ring, or false if nothing could be drawn │ │ │ │ */ │ │ │ │ - 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/PointTrack.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.PointTrack │ │ │ │ - * Vector layer to display ordered point features as a line, creating one │ │ │ │ - * LineString feature for each pair of two points. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Vector> │ │ │ │ - */ │ │ │ │ -OpenLayers.Layer.PointTrack = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ + drawLinearRing: function(node, geometry) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: dataFrom │ │ │ │ - * {<OpenLayers.Layer.PointTrack.TARGET_NODE>} or │ │ │ │ - * {<OpenLayers.Layer.PointTrack.SOURCE_NODE>} optional. If the lines │ │ │ │ - * should get the data/attributes from one of the two points it is │ │ │ │ - * composed of, which one should it be? │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - dataFrom: null, │ │ │ │ + drawPolygon: function(node, geometry) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: styleFrom │ │ │ │ - * {<OpenLayers.Layer.PointTrack.TARGET_NODE>} or │ │ │ │ - * {<OpenLayers.Layer.PointTrack.SOURCE_NODE>} optional. If the lines │ │ │ │ - * should get the style from one of the two points it is composed of, │ │ │ │ - * which one should it be? │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - styleFrom: null, │ │ │ │ + drawRectangle: function(node, geometry) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.PointTrack │ │ │ │ - * Constructor for a new OpenLayers.PointTrack instance. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} name of the layer │ │ │ │ - * options - {Object} Optional object with properties to tag onto the │ │ │ │ - * instance. │ │ │ │ + * 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) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: addNodes │ │ │ │ - * Adds point features that will be used to create lines from, using point │ │ │ │ - * pairs. The first point of a pair will be the source node, the second │ │ │ │ - * will be the target node. │ │ │ │ + * Method: removeText │ │ │ │ + * Removes a label │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * pointFeatures - {Array(<OpenLayers.Feature>)} │ │ │ │ - * options - {Object} │ │ │ │ - * │ │ │ │ - * Supported options: │ │ │ │ - * silent - {Boolean} true to suppress (before)feature(s)added events │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - addNodes: function(pointFeatures, options) { │ │ │ │ - if (pointFeatures.length < 2) { │ │ │ │ - throw new Error("At least two point features have to be added to " + │ │ │ │ - "create a line from"); │ │ │ │ + removeText: function(featureId) { │ │ │ │ + var label = document.getElementById(featureId + this.LABEL_ID_SUFFIX); │ │ │ │ + if (label) { │ │ │ │ + this.textRoot.removeChild(label); │ │ │ │ } │ │ │ │ - │ │ │ │ - var lines = new Array(pointFeatures.length - 1); │ │ │ │ - │ │ │ │ - var pointFeature, startPoint, endPoint; │ │ │ │ - for (var i = 0, len = pointFeatures.length; i < len; i++) { │ │ │ │ - pointFeature = pointFeatures[i]; │ │ │ │ - endPoint = pointFeature.geometry; │ │ │ │ - │ │ │ │ - if (!endPoint) { │ │ │ │ - var lonlat = pointFeature.lonlat; │ │ │ │ - endPoint = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat); │ │ │ │ - } else if (endPoint.CLASS_NAME != "OpenLayers.Geometry.Point") { │ │ │ │ - throw new TypeError("Only features with point geometries are supported."); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (i > 0) { │ │ │ │ - var attributes = (this.dataFrom != null) ? │ │ │ │ - (pointFeatures[i + this.dataFrom].data || │ │ │ │ - pointFeatures[i + this.dataFrom].attributes) : │ │ │ │ - null; │ │ │ │ - var style = (this.styleFrom != null) ? │ │ │ │ - (pointFeatures[i + this.styleFrom].style) : │ │ │ │ - null; │ │ │ │ - var line = new OpenLayers.Geometry.LineString([startPoint, │ │ │ │ - endPoint │ │ │ │ - ]); │ │ │ │ - │ │ │ │ - lines[i - 1] = new OpenLayers.Feature.Vector(line, attributes, │ │ │ │ - style); │ │ │ │ - } │ │ │ │ - │ │ │ │ - startPoint = endPoint; │ │ │ │ + var outline = document.getElementById(featureId + this.LABEL_OUTLINE_SUFFIX); │ │ │ │ + if (outline) { │ │ │ │ + this.textRoot.removeChild(outline); │ │ │ │ } │ │ │ │ - │ │ │ │ - this.addFeatures(lines, options); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.PointTrack" │ │ │ │ -}); │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Layer.PointTrack.SOURCE_NODE │ │ │ │ - * {Number} value for <OpenLayers.Layer.PointTrack.dataFrom> and │ │ │ │ - * <OpenLayers.Layer.PointTrack.styleFrom> │ │ │ │ - */ │ │ │ │ -OpenLayers.Layer.PointTrack.SOURCE_NODE = -1; │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Layer.PointTrack.TARGET_NODE │ │ │ │ - * {Number} value for <OpenLayers.Layer.PointTrack.dataFrom> and │ │ │ │ - * <OpenLayers.Layer.PointTrack.styleFrom> │ │ │ │ - */ │ │ │ │ -OpenLayers.Layer.PointTrack.TARGET_NODE = 0; │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Layer.PointTrack.dataFrom │ │ │ │ - * {Object} with the following keys - *deprecated* │ │ │ │ - * - SOURCE_NODE: take data/attributes from the source node of the line │ │ │ │ - * - TARGET_NODE: take data/attributes from the target node of the line │ │ │ │ - */ │ │ │ │ -OpenLayers.Layer.PointTrack.dataFrom = { │ │ │ │ - 'SOURCE_NODE': -1, │ │ │ │ - 'TARGET_NODE': 0 │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Tile/UTFGrid.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/Format/JSON.js │ │ │ │ - * @requires OpenLayers/Request.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Tile.UTFGrid │ │ │ │ - * Instances of OpenLayers.Tile.UTFGrid are used to manage │ │ │ │ - * UTFGrids. This is an unusual tile type in that it doesn't have a │ │ │ │ - * rendered image; only a 'hit grid' that can be used to │ │ │ │ - * look up feature attributes. │ │ │ │ - * │ │ │ │ - * See the <OpenLayers.Tile.UTFGrid> constructor for details on constructing a │ │ │ │ - * new instance. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Tile> │ │ │ │ - */ │ │ │ │ -OpenLayers.Tile.UTFGrid = OpenLayers.Class(OpenLayers.Tile, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: url │ │ │ │ - * {String} │ │ │ │ - * The URL of the UTFGrid file being requested. Provided by the <getURL> │ │ │ │ - * method. │ │ │ │ - */ │ │ │ │ - url: null, │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Property: utfgridResolution │ │ │ │ - * {Number} │ │ │ │ - * Ratio of the pixel width to the width of a UTFGrid data point. If an │ │ │ │ - * entry in the grid represents a 4x4 block of pixels, the │ │ │ │ - * utfgridResolution would be 4. Default is 2. │ │ │ │ - */ │ │ │ │ - utfgridResolution: 2, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: json │ │ │ │ - * {Object} │ │ │ │ - * Stores the parsed JSON tile data structure. │ │ │ │ - */ │ │ │ │ - json: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: format │ │ │ │ - * {OpenLayers.Format.JSON} │ │ │ │ - * Parser instance used to parse JSON for cross browser support. The native │ │ │ │ - * JSON.parse method will be used where available (all except IE<8). │ │ │ │ - */ │ │ │ │ - format: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Tile.UTFGrid │ │ │ │ - * Constructor for a new <OpenLayers.Tile.UTFGrid> instance. │ │ │ │ + * Method: getFeatureIdFromEvent │ │ │ │ * │ │ │ │ * 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} │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Clean up. │ │ │ │ + * evt - {Object} An <OpenLayers.Event> object │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A feature id or undefined. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - this.clear(); │ │ │ │ - OpenLayers.Tile.prototype.destroy.apply(this, arguments); │ │ │ │ + getFeatureIdFromEvent: function(evt) { │ │ │ │ + var target = evt.target; │ │ │ │ + var useElement = target && target.correspondingUseElement; │ │ │ │ + var node = useElement ? useElement : (target || evt.srcElement); │ │ │ │ + return node._featureId; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * Check that a tile should be drawn, and draw it. │ │ │ │ - * In the case of UTFGrids, "drawing" it means fetching and │ │ │ │ - * parsing the json. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Was a tile drawn? │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - draw: function() { │ │ │ │ - var drawn = OpenLayers.Tile.prototype.draw.apply(this, arguments); │ │ │ │ - if (drawn) { │ │ │ │ - if (this.isLoading) { │ │ │ │ - this.abortLoading(); │ │ │ │ - //if we're already loading, send 'reload' instead of 'loadstart'. │ │ │ │ - this.events.triggerEvent("reload"); │ │ │ │ - } else { │ │ │ │ - this.isLoading = true; │ │ │ │ - this.events.triggerEvent("loadstart"); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - this.url = this.layer.getURL(this.bounds); │ │ │ │ + } 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.layer.useJSONP) { │ │ │ │ - // Use JSONP method to avoid xbrowser policy │ │ │ │ - var ols = new OpenLayers.Protocol.Script({ │ │ │ │ - url: this.url, │ │ │ │ - callback: function(response) { │ │ │ │ - this.isLoading = false; │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ - this.json = response.data; │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - ols.read(); │ │ │ │ - this.request = ols; │ │ │ │ - } else { │ │ │ │ - // Use standard XHR │ │ │ │ - this.request = OpenLayers.Request.GET({ │ │ │ │ - url: this.url, │ │ │ │ - callback: function(response) { │ │ │ │ - this.isLoading = false; │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ - if (response.status === 200) { │ │ │ │ - this.parseData(response.responseText); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - this.unload(); │ │ │ │ } │ │ │ │ - return drawn; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: abortLoading │ │ │ │ - * Cancel a pending request. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - abortLoading: function() { │ │ │ │ - if (this.request) { │ │ │ │ - this.request.abort(); │ │ │ │ - delete this.request; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - this.isLoading = false; │ │ │ │ + return node; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getFeatureInfo │ │ │ │ - * Get feature information associated with a pixel offset. If the pixel │ │ │ │ - * offset corresponds to a feature, the returned object will have id │ │ │ │ - * and data properties. Otherwise, null will be returned. │ │ │ │ - * │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: nodeTypeCompare │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * i - {Number} X-axis pixel offset (from top left of tile) │ │ │ │ - * j - {Number} Y-axis pixel offset (from top left of tile) │ │ │ │ - * │ │ │ │ + * node - {DOMElement} │ │ │ │ + * type - {String} Kind of node │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} Object with feature id and data properties corresponding to the │ │ │ │ - * given pixel offset. │ │ │ │ + * {Boolean} Whether or not the specified node is of the specified type │ │ │ │ + * This function must be overridden by subclasses. │ │ │ │ */ │ │ │ │ - getFeatureInfo: function(i, j) { │ │ │ │ - var info = null; │ │ │ │ - if (this.json) { │ │ │ │ - var id = this.getFeatureId(i, j); │ │ │ │ - if (id !== null) { │ │ │ │ - info = { │ │ │ │ - id: id, │ │ │ │ - data: this.json.data[id] │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return info; │ │ │ │ - }, │ │ │ │ + nodeTypeCompare: function(node, type) {}, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getFeatureId │ │ │ │ - * Get the identifier for the feature associated with a pixel offset. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: createNode │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * i - {Number} X-axis pixel offset (from top left of tile) │ │ │ │ - * j - {Number} Y-axis pixel offset (from top left of tile) │ │ │ │ - * │ │ │ │ + * type - {String} Kind of node to draw. │ │ │ │ + * id - {String} Id for node. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} The feature identifier corresponding to the given pixel offset. │ │ │ │ - * Returns null if pixel doesn't correspond to a feature. │ │ │ │ + * {DOMElement} A new node of the given type and id. │ │ │ │ + * This function must be overridden by subclasses. │ │ │ │ */ │ │ │ │ - getFeatureId: function(i, j) { │ │ │ │ - var id = null; │ │ │ │ - if (this.json) { │ │ │ │ - var resolution = this.utfgridResolution; │ │ │ │ - var row = Math.floor(j / resolution); │ │ │ │ - var col = Math.floor(i / resolution); │ │ │ │ - var charCode = this.json.grid[row].charCodeAt(col); │ │ │ │ - var index = this.indexFromCharCode(charCode); │ │ │ │ - var keys = this.json.keys; │ │ │ │ - if (!isNaN(index) && (index in keys)) { │ │ │ │ - id = keys[index]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return id; │ │ │ │ - }, │ │ │ │ + createNode: function(type, id) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: indexFromCharCode │ │ │ │ - * Given a character code for one of the UTFGrid "grid" characters, │ │ │ │ - * resolve the integer index for the feature id in the UTFGrid "keys" │ │ │ │ - * array. │ │ │ │ - * │ │ │ │ + * Method: moveRoot │ │ │ │ + * moves this renderer's root to a different renderer. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * charCode - {Integer} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} Index for the feature id from the keys array. │ │ │ │ + * renderer - {<OpenLayers.Renderer>} target renderer for the moved root │ │ │ │ */ │ │ │ │ - indexFromCharCode: function(charCode) { │ │ │ │ - if (charCode >= 93) { │ │ │ │ - charCode--; │ │ │ │ - } │ │ │ │ - if (charCode >= 35) { │ │ │ │ - charCode--; │ │ │ │ + moveRoot: function(renderer) { │ │ │ │ + var root = this.root; │ │ │ │ + if (renderer.root.parentNode == this.rendererRoot) { │ │ │ │ + root = renderer.root; │ │ │ │ } │ │ │ │ - return charCode - 32; │ │ │ │ + root.parentNode.removeChild(root); │ │ │ │ + renderer.rendererRoot.appendChild(root); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseData │ │ │ │ - * Parse the JSON from a request │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * str - {String} UTFGrid as a JSON string. │ │ │ │ + * 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: │ │ │ │ - * {Object} parsed javascript data │ │ │ │ + * {String} the id of the output layer. │ │ │ │ */ │ │ │ │ - parseData: function(str) { │ │ │ │ - if (!this.format) { │ │ │ │ - this.format = new OpenLayers.Format.JSON(); │ │ │ │ - } │ │ │ │ - this.json = this.format.read(str); │ │ │ │ + getRenderLayerId: function() { │ │ │ │ + return this.root.parentNode.parentNode.id; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: clear │ │ │ │ - * Delete data stored with this tile. │ │ │ │ + /** │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - clear: function() { │ │ │ │ - this.json = null; │ │ │ │ + isComplexSymbol: function(graphicName) { │ │ │ │ + return (graphicName != "circle") && !!graphicName; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Tile.UTFGrid" │ │ │ │ - │ │ │ │ + CLASS_NAME: "OpenLayers.Renderer.Elements" │ │ │ │ }); │ │ │ │ + │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/UTFGrid.js │ │ │ │ + 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/Layer/XYZ.js │ │ │ │ - * @requires OpenLayers/Tile/UTFGrid.js │ │ │ │ + * @requires OpenLayers/Renderer/Elements.js │ │ │ │ */ │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Layer.UTFGrid │ │ │ │ - * This Layer reads from UTFGrid tiled data sources. Since UTFGrids are │ │ │ │ - * essentially JSON-based ASCII art with attached attributes, they are not │ │ │ │ - * visibly rendered. In order to use them in the map, you must add a │ │ │ │ - * <OpenLayers.Control.UTFGrid> control as well. │ │ │ │ - * │ │ │ │ - * Example: │ │ │ │ - * │ │ │ │ - * (start code) │ │ │ │ - * var world_utfgrid = new OpenLayers.Layer.UTFGrid({ │ │ │ │ - * url: "/tiles/world_utfgrid/${z}/${x}/${y}.json", │ │ │ │ - * utfgridResolution: 4, │ │ │ │ - * displayInLayerSwitcher: false │ │ │ │ - * ); │ │ │ │ - * map.addLayer(world_utfgrid); │ │ │ │ - * │ │ │ │ - * var control = new OpenLayers.Control.UTFGrid({ │ │ │ │ - * layers: [world_utfgrid], │ │ │ │ - * handlerMode: 'move', │ │ │ │ - * callback: function(dataLookup) { │ │ │ │ - * // do something with returned data │ │ │ │ - * } │ │ │ │ - * }) │ │ │ │ - * (end code) │ │ │ │ - * │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Renderer.SVG │ │ │ │ * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.XYZ> │ │ │ │ + * Inherits: │ │ │ │ + * - <OpenLayers.Renderer.Elements> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.UTFGrid = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ +OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: xmlns │ │ │ │ + * {String} │ │ │ │ + */ │ │ │ │ + xmlns: "http://www.w3.org/2000/svg", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * Default is false, as UTFGrids are designed to be a transparent overlay layer. │ │ │ │ + * Property: xlinkns │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - isBaseLayer: false, │ │ │ │ + xlinkns: "http://www.w3.org/1999/xlink", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: projection │ │ │ │ - * {<OpenLayers.Projection>} │ │ │ │ - * Source projection for the UTFGrids. Default is "EPSG:900913". │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - projection: new OpenLayers.Projection("EPSG:900913"), │ │ │ │ + MAX_PIXEL: 15000, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: useJSONP │ │ │ │ - * {Boolean} │ │ │ │ - * Should we use a JSONP script approach instead of a standard AJAX call? │ │ │ │ - * │ │ │ │ - * Set to true for using utfgrids from another server. │ │ │ │ - * Avoids same-domain policy restrictions. │ │ │ │ - * Note that this only works if the server accepts │ │ │ │ - * the callback GET parameter and dynamically │ │ │ │ - * wraps the returned json in a function call. │ │ │ │ - * │ │ │ │ - * Default is false │ │ │ │ + * Property: translationParameters │ │ │ │ + * {Object} Hash with "x" and "y" properties │ │ │ │ */ │ │ │ │ - useJSONP: false, │ │ │ │ + translationParameters: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: url │ │ │ │ - * {String} │ │ │ │ - * URL tempate for UTFGrid tiles. Include x, y, and z parameters. │ │ │ │ - * E.g. "/tiles/${z}/${x}/${y}.json" │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: utfgridResolution │ │ │ │ - * {Number} │ │ │ │ - * Ratio of the pixel width to the width of a UTFGrid data point. If an │ │ │ │ - * entry in the grid represents a 4x4 block of pixels, the │ │ │ │ - * utfgridResolution would be 4. Default is 2 (specified in │ │ │ │ - * <OpenLayers.Tile.UTFGrid>). │ │ │ │ + * 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 = {}; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: tileClass │ │ │ │ - * {<OpenLayers.Tile>} The tile class to use for this layer. │ │ │ │ - * Defaults is <OpenLayers.Tile.UTFGrid>. │ │ │ │ + * APIMethod: supported │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the browser supports the SVG renderer │ │ │ │ */ │ │ │ │ - tileClass: OpenLayers.Tile.UTFGrid, │ │ │ │ + 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"))); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.UTFGrid │ │ │ │ - * Create a new UTFGrid layer. │ │ │ │ + * Method: inValidRange │ │ │ │ + * See #669 for more information │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * config - {Object} Configuration properties for the layer. │ │ │ │ - * │ │ │ │ - * Required configuration properties: │ │ │ │ - * url - {String} The url template for UTFGrid tiles. See the <url> property. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply( │ │ │ │ - this, [options.name, options.url, {}, options] │ │ │ │ - ); │ │ │ │ - this.tileOptions = OpenLayers.Util.extend({ │ │ │ │ - utfgridResolution: this.utfgridResolution │ │ │ │ - }, this.tileOptions); │ │ │ │ + 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: createBackBuffer │ │ │ │ - * The UTFGrid cannot create a back buffer, so this method is overriden. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - createBackBuffer: function() {}, │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ - * │ │ │ │ + * Method: translate │ │ │ │ + * Transforms the SVG coordinate system │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * obj - {Object} Only used by a subclass of this layer. │ │ │ │ + * x - {Float} │ │ │ │ + * y - {Float} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Layer.UTFGrid>} An exact clone of this OpenLayers.Layer.UTFGrid │ │ │ │ + * {Boolean} true if the translation parameters are in the valid coordinates │ │ │ │ + * range, false otherwise. │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.UTFGrid(this.getOptions()); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - // get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ │ │ │ │ - return obj; │ │ │ │ + this.rendererRoot.setAttributeNS(null, "width", this.size.w); │ │ │ │ + this.rendererRoot.setAttributeNS(null, "height", this.size.h); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: getFeatureInfo │ │ │ │ - * Get details about a feature associated with a map location. The object │ │ │ │ - * returned will have id and data properties. If the given location │ │ │ │ - * doesn't correspond to a feature, null will be returned. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: getNodeType │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * location - {<OpenLayers.LonLat>} map location │ │ │ │ - * │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} Object representing the feature id and UTFGrid data │ │ │ │ - * corresponding to the given map location. Returns null if the given │ │ │ │ - * location doesn't hit a feature. │ │ │ │ + * {String} The corresponding node type for the specified geometry │ │ │ │ */ │ │ │ │ - getFeatureInfo: function(location) { │ │ │ │ - var info = null; │ │ │ │ - var tileInfo = this.getTileData(location); │ │ │ │ - if (tileInfo && tileInfo.tile) { │ │ │ │ - info = tileInfo.tile.getFeatureInfo(tileInfo.i, tileInfo.j); │ │ │ │ + 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 info; │ │ │ │ + return nodeType; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getFeatureId │ │ │ │ - * Get the identifier for the feature associated with a map location. │ │ │ │ + /** │ │ │ │ + * 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: │ │ │ │ - * location - {<OpenLayers.LonLat>} map location │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} The feature identifier corresponding to the given map location. │ │ │ │ - * Returns null if the location doesn't hit a feature. │ │ │ │ + * node - {SVGDomElement} An SVG element to decorate │ │ │ │ + * style - {Object} │ │ │ │ + * options - {Object} Currently supported options include │ │ │ │ + * 'isFilled' {Boolean} and │ │ │ │ + * 'isStroked' {Boolean} │ │ │ │ */ │ │ │ │ - getFeatureId: function(location) { │ │ │ │ - var id = null; │ │ │ │ - var info = this.getTileData(location); │ │ │ │ - if (info.tile) { │ │ │ │ - id = info.tile.getFeatureId(info.i, info.j); │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ } │ │ │ │ - return id; │ │ │ │ - }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.UTFGrid" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Layer/PointGrid.js │ │ │ │ - ====================================================================== */ │ │ │ │ + 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); │ │ │ │ │ │ │ │ -/* 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 opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Layer/Vector.js │ │ │ │ - * @requires OpenLayers/Geometry/Polygon.js │ │ │ │ - */ │ │ │ │ + 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; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Layer.PointGrid │ │ │ │ - * A point grid layer dynamically generates a regularly spaced grid of point │ │ │ │ - * features. This is a specialty layer for cases where an application needs │ │ │ │ - * a regular grid of points. It can be used, for example, in an editing │ │ │ │ - * environment to snap to a grid. │ │ │ │ - * │ │ │ │ - * Create a new vector layer with the <OpenLayers.Layer.PointGrid> constructor. │ │ │ │ - * (code) │ │ │ │ - * // create a grid with points spaced at 10 map units │ │ │ │ - * var points = new OpenLayers.Layer.PointGrid({dx: 10, dy: 10}); │ │ │ │ - * │ │ │ │ - * // create a grid with different x/y spacing rotated 15 degrees clockwise. │ │ │ │ - * var points = new OpenLayers.Layer.PointGrid({dx: 5, dy: 10, rotation: 15}); │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Vector> │ │ │ │ - */ │ │ │ │ -OpenLayers.Layer.PointGrid = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ + // 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); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: dx │ │ │ │ - * {Number} Point grid spacing in the x-axis direction (map units). │ │ │ │ - * Read-only. Use the <setSpacing> method to modify this value. │ │ │ │ - */ │ │ │ │ - dx: null, │ │ │ │ + // 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")); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: dy │ │ │ │ - * {Number} Point grid spacing in the y-axis direction (map units). │ │ │ │ - * Read-only. Use the <setSpacing> method to modify this value. │ │ │ │ - */ │ │ │ │ - dy: null, │ │ │ │ + node.setAttributeNS(null, "width", size); │ │ │ │ + node.setAttributeNS(null, "height", size); │ │ │ │ + node.setAttributeNS(null, "x", pos.x - offset); │ │ │ │ + node.setAttributeNS(null, "y", pos.y - offset); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: ratio │ │ │ │ - * {Number} Ratio of the desired grid size to the map viewport size. │ │ │ │ - * Default is 1.5. Larger ratios mean the grid is recalculated less often │ │ │ │ - * while panning. The <maxFeatures> setting has precedence when determining │ │ │ │ - * grid size. Read-only. Use the <setRatio> method to modify this value. │ │ │ │ - */ │ │ │ │ - ratio: 1.5, │ │ │ │ + // 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); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: maxFeatures │ │ │ │ - * {Number} The maximum number of points to generate in the grid. Default │ │ │ │ - * is 250. Read-only. Use the <setMaxFeatures> method to modify this value. │ │ │ │ - */ │ │ │ │ - maxFeatures: 250, │ │ │ │ + var rotation = style.rotation; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: rotation │ │ │ │ - * {Number} Grid rotation (in degrees clockwise from the positive x-axis). │ │ │ │ - * Default is 0. Read-only. Use the <setRotation> method to modify this │ │ │ │ - * value. │ │ │ │ - */ │ │ │ │ - rotation: 0, │ │ │ │ + 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] + ")"); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: origin │ │ │ │ - * {<OpenLayers.LonLat>} Grid origin. The grid lattice will be aligned with │ │ │ │ - * the origin. If not set at construction, the center of the map's maximum │ │ │ │ - * extent is used. Read-only. Use the <setOrigin> method to modify this │ │ │ │ - * value. │ │ │ │ - */ │ │ │ │ - origin: null, │ │ │ │ + if (options.isFilled) { │ │ │ │ + node.setAttributeNS(null, "fill", style.fillColor); │ │ │ │ + node.setAttributeNS(null, "fill-opacity", style.fillOpacity); │ │ │ │ + } else { │ │ │ │ + node.setAttributeNS(null, "fill", "none"); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: gridBounds │ │ │ │ - * {<OpenLayers.Bounds>} Internally cached grid bounds (with optional │ │ │ │ - * rotation applied). │ │ │ │ - */ │ │ │ │ - gridBounds: null, │ │ │ │ + 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"); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.PointGrid │ │ │ │ - * Creates a new point grid layer. │ │ │ │ - * │ │ │ │ + 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: │ │ │ │ - * config - {Object} An object containing all configuration properties for │ │ │ │ - * the layer. The <dx> and <dy> properties are required to be set at │ │ │ │ - * construction. Any other layer properties may be set in this object. │ │ │ │ + * style - {Object} │ │ │ │ + * widthFactor - {Number} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A SVG compliant 'stroke-dasharray' value │ │ │ │ */ │ │ │ │ - initialize: function(config) { │ │ │ │ - config = config || {}; │ │ │ │ - OpenLayers.Layer.Vector.prototype.initialize.apply(this, [config.name, config]); │ │ │ │ + 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: setMap │ │ │ │ - * The layer has been added to the map. │ │ │ │ + * Method: createNode │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * type - {String} Kind of node to draw │ │ │ │ + * id - {String} Id for node │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A new node of the given type and id │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ - map.events.register("moveend", this, this.onMoveEnd); │ │ │ │ + createNode: function(type, id) { │ │ │ │ + var node = document.createElementNS(this.xmlns, type); │ │ │ │ + if (id) { │ │ │ │ + node.setAttributeNS(null, "id", id); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: removeMap │ │ │ │ - * The layer has been removed from the map. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: nodeTypeCompare │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * node - {SVGDomElement} An SVG element │ │ │ │ + * type - {String} Kind of node │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the specified node is of the specified type │ │ │ │ */ │ │ │ │ - removeMap: function(map) { │ │ │ │ - map.events.unregister("moveend", this, this.onMoveEnd); │ │ │ │ - OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments); │ │ │ │ + nodeTypeCompare: function(node, type) { │ │ │ │ + return (type == node.nodeName); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setRatio │ │ │ │ - * Set the grid <ratio> property and update the grid. Can only be called │ │ │ │ - * after the layer has been added to a map with a center/extent. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * ratio - {Number} │ │ │ │ + * Method: createRenderRoot │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} The specific render engine's root element │ │ │ │ */ │ │ │ │ - setRatio: function(ratio) { │ │ │ │ - this.ratio = ratio; │ │ │ │ - this.updateGrid(true); │ │ │ │ + createRenderRoot: function() { │ │ │ │ + var svg = this.nodeFactory(this.container.id + "_svgRoot", "svg"); │ │ │ │ + svg.style.display = "block"; │ │ │ │ + return svg; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setMaxFeatures │ │ │ │ - * Set the grid <maxFeatures> property and update the grid. Can only be │ │ │ │ - * called after the layer has been added to a map with a center/extent. │ │ │ │ - * │ │ │ │ + * Method: createRoot │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * maxFeatures - {Number} │ │ │ │ + * suffix - {String} suffix to append to the id │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - setMaxFeatures: function(maxFeatures) { │ │ │ │ - this.maxFeatures = maxFeatures; │ │ │ │ - this.updateGrid(true); │ │ │ │ + createRoot: function(suffix) { │ │ │ │ + return this.nodeFactory(this.container.id + suffix, "g"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setSpacing │ │ │ │ - * Set the grid <dx> and <dy> properties and update the grid. If only one │ │ │ │ - * argument is provided, it will be set as <dx> and <dy>. Can only be │ │ │ │ - * called after the layer has been added to a map with a center/extent. │ │ │ │ + * Method: createDefs │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * dx - {Number} │ │ │ │ - * dy - {Number} │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} The element to which we'll add the symbol definitions │ │ │ │ */ │ │ │ │ - setSpacing: function(dx, dy) { │ │ │ │ - this.dx = dx; │ │ │ │ - this.dy = dy || dx; │ │ │ │ - this.updateGrid(true); │ │ │ │ + createDefs: function() { │ │ │ │ + var defs = this.nodeFactory(this.container.id + "_defs", "defs"); │ │ │ │ + this.rendererRoot.appendChild(defs); │ │ │ │ + return defs; │ │ │ │ }, │ │ │ │ │ │ │ │ + /************************************** │ │ │ │ + * * │ │ │ │ + * GEOMETRY DRAWING FUNCTIONS * │ │ │ │ + * * │ │ │ │ + **************************************/ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * APIMethod: setOrigin │ │ │ │ - * Set the grid <origin> property and update the grid. Can only be called │ │ │ │ - * after the layer has been added to a map with a center/extent. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * origin - {<OpenLayers.LonLat>} │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - setOrigin: function(origin) { │ │ │ │ - this.origin = origin; │ │ │ │ - this.updateGrid(true); │ │ │ │ + drawPoint: function(node, geometry) { │ │ │ │ + return this.drawCircle(node, geometry, 1); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getOrigin │ │ │ │ - * Get the grid <origin> property. │ │ │ │ - * │ │ │ │ + * Method: drawCircle │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * radius - {Float} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.LonLat>} The grid origin. │ │ │ │ + * {DOMElement} or false if the renderer could not draw the circle │ │ │ │ */ │ │ │ │ - getOrigin: function() { │ │ │ │ - if (!this.origin) { │ │ │ │ - this.origin = this.map.getExtent().getCenterLonLat(); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - return this.origin; │ │ │ │ + │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setRotation │ │ │ │ - * Set the grid <rotation> property and update the grid. Rotation values │ │ │ │ - * are in degrees clockwise from the positive x-axis (negative values │ │ │ │ - * for counter-clockwise rotation). Can only be called after the layer │ │ │ │ - * has been added to a map with a center/extent. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * rotation - {Number} Degrees clockwise from the positive x-axis. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - setRotation: function(rotation) { │ │ │ │ - this.rotation = rotation; │ │ │ │ - this.updateGrid(true); │ │ │ │ + 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: onMoveEnd │ │ │ │ - * Listener for map "moveend" events. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - onMoveEnd: function() { │ │ │ │ - this.updateGrid(); │ │ │ │ + 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: getViewBounds │ │ │ │ - * Gets the (potentially rotated) view bounds for grid calculations. │ │ │ │ - * │ │ │ │ + * Method: drawPolygon │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} │ │ │ │ + * {DOMElement} or null if the renderer could not draw all components │ │ │ │ + * of the polygon, or false if nothing could be drawn │ │ │ │ */ │ │ │ │ - getViewBounds: function() { │ │ │ │ - var bounds = this.map.getExtent(); │ │ │ │ - if (this.rotation) { │ │ │ │ - var origin = this.getOrigin(); │ │ │ │ - var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); │ │ │ │ - var rect = bounds.toGeometry(); │ │ │ │ - rect.rotate(-this.rotation, rotationOrigin); │ │ │ │ - bounds = rect.getBounds(); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - return bounds; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: updateGrid │ │ │ │ - * Update the grid. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * force - {Boolean} Update the grid even if the previous bounds are still │ │ │ │ - * valid. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - updateGrid: function(force) { │ │ │ │ - if (force || this.invalidBounds()) { │ │ │ │ - var viewBounds = this.getViewBounds(); │ │ │ │ - var origin = this.getOrigin(); │ │ │ │ - var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); │ │ │ │ - var viewBoundsWidth = viewBounds.getWidth(); │ │ │ │ - var viewBoundsHeight = viewBounds.getHeight(); │ │ │ │ - var aspectRatio = viewBoundsWidth / viewBoundsHeight; │ │ │ │ - var maxHeight = Math.sqrt(this.dx * this.dy * this.maxFeatures / aspectRatio); │ │ │ │ - var maxWidth = maxHeight * aspectRatio; │ │ │ │ - var gridWidth = Math.min(viewBoundsWidth * this.ratio, maxWidth); │ │ │ │ - var gridHeight = Math.min(viewBoundsHeight * this.ratio, maxHeight); │ │ │ │ - var center = viewBounds.getCenterLonLat(); │ │ │ │ - this.gridBounds = new OpenLayers.Bounds( │ │ │ │ - center.lon - (gridWidth / 2), │ │ │ │ - center.lat - (gridHeight / 2), │ │ │ │ - center.lon + (gridWidth / 2), │ │ │ │ - center.lat + (gridHeight / 2) │ │ │ │ - ); │ │ │ │ - var rows = Math.floor(gridHeight / this.dy); │ │ │ │ - var cols = Math.floor(gridWidth / this.dx); │ │ │ │ - var gridLeft = origin.lon + (this.dx * Math.ceil((this.gridBounds.left - origin.lon) / this.dx)); │ │ │ │ - var gridBottom = origin.lat + (this.dy * Math.ceil((this.gridBounds.bottom - origin.lat) / this.dy)); │ │ │ │ - var features = new Array(rows * cols); │ │ │ │ - var x, y, point; │ │ │ │ - for (var i = 0; i < cols; ++i) { │ │ │ │ - x = gridLeft + (i * this.dx); │ │ │ │ - for (var j = 0; j < rows; ++j) { │ │ │ │ - y = gridBottom + (j * this.dy); │ │ │ │ - point = new OpenLayers.Geometry.Point(x, y); │ │ │ │ - if (this.rotation) { │ │ │ │ - point.rotate(this.rotation, rotationOrigin); │ │ │ │ - } │ │ │ │ - features[(i * rows) + j] = new OpenLayers.Feature.Vector(point); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.destroyFeatures(this.features, { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ - this.addFeatures(features, { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ + 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: invalidBounds │ │ │ │ - * Determine whether the previously generated point grid is invalid. │ │ │ │ - * This occurs when the map bounds extends beyond the previously │ │ │ │ - * generated grid bounds. │ │ │ │ + * Method: drawText │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} │ │ │ │ + * Parameters: │ │ │ │ + * featureId - {String} │ │ │ │ + * style - │ │ │ │ + * location - {<OpenLayers.Geometry.Point>} │ │ │ │ */ │ │ │ │ - invalidBounds: function() { │ │ │ │ - return !this.gridBounds || !this.gridBounds.containsBounds(this.getViewBounds()); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.PointGrid" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Layer/Zoomify.js │ │ │ │ - ====================================================================== */ │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ │ │ │ │ -/* 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 resolution = this.getResolution(); │ │ │ │ │ │ │ │ -/* │ │ │ │ - * Development supported by a R&D grant DC08P02OUK006 - Old Maps Online │ │ │ │ - * (www.oldmapsonline.org) from Ministry of Culture of the Czech Republic. │ │ │ │ - */ │ │ │ │ + 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"); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ - */ │ │ │ │ + label.setAttributeNS(null, "x", x); │ │ │ │ + label.setAttributeNS(null, "y", -y); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Layer.Zoomify │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ - */ │ │ │ │ -OpenLayers.Layer.Zoomify = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + 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"); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: size │ │ │ │ - * {<OpenLayers.Size>} The Zoomify image size in pixels. │ │ │ │ - */ │ │ │ │ - size: null, │ │ │ │ + if (OpenLayers.IS_GECKO === true) { │ │ │ │ + label.setAttributeNS(null, "dominant-baseline", │ │ │ │ + OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]] || "central"); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: standardTileSize │ │ │ │ - * {Integer} The size of a standard (non-border) square tile in pixels. │ │ │ │ - */ │ │ │ │ - standardTileSize: 256, │ │ │ │ + if (!label.parentNode) { │ │ │ │ + this.textRoot.appendChild(label); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: tileOriginCorner │ │ │ │ - * {String} This layer uses top-left as tile origin │ │ │ │ - **/ │ │ │ │ - tileOriginCorner: "tl", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: numberOfTiers │ │ │ │ - * {Integer} Depth of the Zoomify pyramid, number of tiers (zoom levels) │ │ │ │ - * - filled during Zoomify pyramid initialization. │ │ │ │ - */ │ │ │ │ - numberOfTiers: 0, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: tileCountUpToTier │ │ │ │ - * {Array(Integer)} Number of tiles up to the given tier of pyramid. │ │ │ │ - * - filled during Zoomify pyramid initialization. │ │ │ │ - */ │ │ │ │ - tileCountUpToTier: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: tierSizeInTiles │ │ │ │ - * {Array(<OpenLayers.Size>)} Size (in tiles) for each tier of pyramid. │ │ │ │ - * - filled during Zoomify pyramid initialization. │ │ │ │ - */ │ │ │ │ - tierSizeInTiles: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: tierImageSize │ │ │ │ - * {Array(<OpenLayers.Size>)} Image size in pixels for each pyramid tier. │ │ │ │ - * - filled during Zoomify pyramid initialization. │ │ │ │ - */ │ │ │ │ - tierImageSize: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.Zoomify │ │ │ │ - * │ │ │ │ + * Method: getComponentString │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} A name for the layer. │ │ │ │ - * url - {String} - Relative or absolute path to the image or more │ │ │ │ - * precisly to the TileGroup[X] directories root. │ │ │ │ - * Flash plugin use the variable name "zoomifyImagePath" for this. │ │ │ │ - * size - {<OpenLayers.Size>} The size (in pixels) of the image. │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ + * 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) │ │ │ │ */ │ │ │ │ - initialize: function(name, url, size, options) { │ │ │ │ - │ │ │ │ - // initilize the Zoomify pyramid for given size │ │ │ │ - this.initializeZoomify(size); │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, [ │ │ │ │ - name, url, size, {}, │ │ │ │ - options │ │ │ │ - ]); │ │ │ │ + return { │ │ │ │ + path: strings.join(separator || ","), │ │ │ │ + complete: complete │ │ │ │ + }; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: initializeZoomify │ │ │ │ - * It generates constants for all tiers of the Zoomify pyramid │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * size - {<OpenLayers.Size>} The size of the image in pixels │ │ │ │ - * │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - initializeZoomify: function(size) { │ │ │ │ - │ │ │ │ - var imageSize = size.clone(); │ │ │ │ - this.size = size.clone(); │ │ │ │ - var tiles = new OpenLayers.Size( │ │ │ │ - Math.ceil(imageSize.w / this.standardTileSize), │ │ │ │ - Math.ceil(imageSize.h / this.standardTileSize) │ │ │ │ - ); │ │ │ │ - │ │ │ │ - this.tierSizeInTiles = [tiles]; │ │ │ │ - this.tierImageSize = [imageSize]; │ │ │ │ - │ │ │ │ - while (imageSize.w > this.standardTileSize || │ │ │ │ - imageSize.h > this.standardTileSize) { │ │ │ │ - │ │ │ │ - imageSize = new OpenLayers.Size( │ │ │ │ - Math.floor(imageSize.w / 2), │ │ │ │ - Math.floor(imageSize.h / 2) │ │ │ │ - ); │ │ │ │ - tiles = new OpenLayers.Size( │ │ │ │ - Math.ceil(imageSize.w / this.standardTileSize), │ │ │ │ - Math.ceil(imageSize.h / this.standardTileSize) │ │ │ │ - ); │ │ │ │ - this.tierSizeInTiles.push(tiles); │ │ │ │ - this.tierImageSize.push(imageSize); │ │ │ │ + clipLine: function(badComponent, goodComponent) { │ │ │ │ + if (goodComponent.equals(badComponent)) { │ │ │ │ + return ""; │ │ │ │ } │ │ │ │ - │ │ │ │ - this.tierSizeInTiles.reverse(); │ │ │ │ - this.tierImageSize.reverse(); │ │ │ │ - │ │ │ │ - this.numberOfTiers = this.tierSizeInTiles.length; │ │ │ │ - var resolutions = [1]; │ │ │ │ - this.tileCountUpToTier = [0]; │ │ │ │ - for (var i = 1; i < this.numberOfTiers; i++) { │ │ │ │ - resolutions.unshift(Math.pow(2, i)); │ │ │ │ - this.tileCountUpToTier.push( │ │ │ │ - this.tierSizeInTiles[i - 1].w * this.tierSizeInTiles[i - 1].h + │ │ │ │ - this.tileCountUpToTier[i - 1] │ │ │ │ - ); │ │ │ │ + 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 (!this.serverResolutions) { │ │ │ │ - this.serverResolutions = resolutions; │ │ │ │ + if (y2 < -maxY || y2 > maxY) { │ │ │ │ + k = (x2 - x1) / (y2 - y1); │ │ │ │ + y2 = y2 < 0 ? -maxY : maxY; │ │ │ │ + x2 = x1 + (y2 - y1) * k; │ │ │ │ } │ │ │ │ + return x2 + "," + y2; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod:destroy │ │ │ │ + /** │ │ │ │ + * Method: getShortString │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} or false if point is outside the valid range │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - // for now, nothing special to do here. │ │ │ │ - OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments); │ │ │ │ - │ │ │ │ - // Remove from memory the Zoomify pyramid - is that enough? │ │ │ │ - this.tileCountUpToTier.length = 0; │ │ │ │ - this.tierSizeInTiles.length = 0; │ │ │ │ - this.tierImageSize.length = 0; │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * │ │ │ │ + * Method: getPosition │ │ │ │ + * Finds the position of an svg node. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * obj - {Object} │ │ │ │ - * │ │ │ │ + * node - {DOMElement} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Layer.Zoomify>} An exact clone of this <OpenLayers.Layer.Zoomify> │ │ │ │ + * {Object} hash with x and y properties, representing the coordinates │ │ │ │ + * within the svg coordinate system │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.Zoomify(this.name, │ │ │ │ - this.url, │ │ │ │ - this.size, │ │ │ │ - this.options); │ │ │ │ - } │ │ │ │ - │ │ │ │ - //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; │ │ │ │ + getPosition: function(node) { │ │ │ │ + return ({ │ │ │ │ + x: parseFloat(node.getAttributeNS(null, "cx")), │ │ │ │ + y: parseFloat(node.getAttributeNS(null, "cy")) │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getURL │ │ │ │ - * │ │ │ │ + * Method: importSymbol │ │ │ │ + * add a new symbol definition from the rendererer's symbol hash │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - * │ │ │ │ + * graphicName - {String} name of the symbol to import │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {String} A string with the layer's url and parameters and also the │ │ │ │ - * passed-in bounds and appropriate tile size specified as │ │ │ │ - * parameters │ │ │ │ + * {DOMElement} - the imported symbol │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ - var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ - var z = this.getZoomForResolution(res); │ │ │ │ + importSymbol: function(graphicName) { │ │ │ │ + if (!this.defs) { │ │ │ │ + // create svg defs tag │ │ │ │ + this.defs = this.createDefs(); │ │ │ │ + } │ │ │ │ + var id = this.container.id + "-" + graphicName; │ │ │ │ │ │ │ │ - var tileIndex = x + y * this.tierSizeInTiles[z].w + this.tileCountUpToTier[z]; │ │ │ │ - var path = "TileGroup" + Math.floor((tileIndex) / 256) + │ │ │ │ - "/" + z + "-" + x + "-" + y + ".jpg"; │ │ │ │ - var url = this.url; │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(path, url); │ │ │ │ + // check if symbol already exists in the defs │ │ │ │ + var existing = document.getElementById(id); │ │ │ │ + if (existing != null) { │ │ │ │ + return existing; │ │ │ │ } │ │ │ │ - return url + path; │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getImageSize │ │ │ │ - * getImageSize returns size for a particular tile. If bounds are given as │ │ │ │ - * first argument, size is calculated (bottom-right tiles are non square). │ │ │ │ - * │ │ │ │ - */ │ │ │ │ - getImageSize: function() { │ │ │ │ - if (arguments.length > 0) { │ │ │ │ - var bounds = this.adjustBounds(arguments[0]); │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ - var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ - var z = this.getZoomForResolution(res); │ │ │ │ - var w = this.standardTileSize; │ │ │ │ - var h = this.standardTileSize; │ │ │ │ - if (x == this.tierSizeInTiles[z].w - 1) { │ │ │ │ - var w = this.tierImageSize[z].w % this.standardTileSize; │ │ │ │ - } │ │ │ │ - if (y == this.tierSizeInTiles[z].h - 1) { │ │ │ │ - var h = this.tierImageSize[z].h % this.standardTileSize; │ │ │ │ - } │ │ │ │ - return (new OpenLayers.Size(w, h)); │ │ │ │ - } else { │ │ │ │ - return this.tileSize; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setMap │ │ │ │ - * When the layer is added to a map, then we can fetch our origin │ │ │ │ - * (if we don't have one.) │ │ │ │ - * │ │ │ │ + * Method: getFeatureIdFromEvent │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * evt - {Object} An <OpenLayers.Event> object │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A feature id or undefined. │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left, │ │ │ │ - this.map.maxExtent.top); │ │ │ │ + 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.Layer.Zoomify" │ │ │ │ + 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/Layer/TMS.js │ │ │ │ + OpenLayers/Renderer/VML.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 │ │ │ │ + * @requires OpenLayers/Renderer/Elements.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.TMS │ │ │ │ - * Create a layer for accessing tiles from services that conform with the │ │ │ │ - * Tile Map Service Specification │ │ │ │ - * (http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification). │ │ │ │ - * │ │ │ │ - * Example: │ │ │ │ - * (code) │ │ │ │ - * var layer = new OpenLayers.Layer.TMS( │ │ │ │ - * "My Layer", // name for display in LayerSwitcher │ │ │ │ - * "http://tilecache.osgeo.org/wms-c/Basic.py/", // service endpoint │ │ │ │ - * {layername: "basic", type: "png"} // required properties │ │ │ │ - * ); │ │ │ │ - * (end) │ │ │ │ + * Class: OpenLayers.Renderer.VML │ │ │ │ + * Render vector features in browsers with VML capability. Construct a new │ │ │ │ + * VML renderer with the <OpenLayers.Renderer.VML> constructor. │ │ │ │ * │ │ │ │ + * Note that for all calculations in this class, we use (num | 0) to truncate a │ │ │ │ + * float value to an integer. This is done because it seems that VML doesn't │ │ │ │ + * support float values. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * - <OpenLayers.Renderer.Elements> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.TMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: serviceVersion │ │ │ │ - * {String} Service version for tile requests. Default is "1.0.0". │ │ │ │ - */ │ │ │ │ - serviceVersion: "1.0.0", │ │ │ │ +OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layername │ │ │ │ - * {String} The identifier for the <TileMap> as advertised by the service. │ │ │ │ - * For example, if the service advertises a <TileMap> with │ │ │ │ - * 'href="http://tms.osgeo.org/1.0.0/vmap0"', the <layername> property │ │ │ │ - * would be set to "vmap0". │ │ │ │ + * Property: xmlns │ │ │ │ + * {String} XML Namespace URN │ │ │ │ */ │ │ │ │ - layername: null, │ │ │ │ + xmlns: "urn:schemas-microsoft-com:vml", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: type │ │ │ │ - * {String} The format extension corresponding to the requested tile image │ │ │ │ - * type. This is advertised in a <TileFormat> element as the │ │ │ │ - * "extension" attribute. For example, if the service advertises a │ │ │ │ - * <TileMap> with <TileFormat width="256" height="256" mime-type="image/jpeg" extension="jpg" />, │ │ │ │ - * the <type> property would be set to "jpg". │ │ │ │ + * Property: symbolCache │ │ │ │ + * {DOMElement} node holding symbols. This hash is keyed by symbol name, │ │ │ │ + * and each value is a hash with a "path" and an "extent" property. │ │ │ │ */ │ │ │ │ - type: null, │ │ │ │ + symbolCache: {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} Make this layer a base layer. Default is true. Set false to │ │ │ │ - * use the layer as an overlay. │ │ │ │ + * Property: offset │ │ │ │ + * {Object} Hash with "x" and "y" properties │ │ │ │ */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + offset: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 bottom-left │ │ │ │ - * corner of the map's <maxExtent>. Default is ``null``. │ │ │ │ + * Constructor: OpenLayers.Renderer.VML │ │ │ │ + * Create a new VML renderer. │ │ │ │ * │ │ │ │ - * Example: │ │ │ │ - * (code) │ │ │ │ - * var layer = new OpenLayers.Layer.TMS( │ │ │ │ - * "My Layer", │ │ │ │ - * "http://tilecache.osgeo.org/wms-c/Basic.py/", │ │ │ │ - * { │ │ │ │ - * layername: "basic", │ │ │ │ - * type: "png", │ │ │ │ - * // set if different than the bottom left of map.maxExtent │ │ │ │ - * tileOrigin: new OpenLayers.LonLat(-180, -90) │ │ │ │ - * } │ │ │ │ - * ); │ │ │ │ - * (end) │ │ │ │ + * Parameters: │ │ │ │ + * containerID - {String} The id for the element that contains the renderer │ │ │ │ */ │ │ │ │ - tileOrigin: null, │ │ │ │ + initialize: function(containerID) { │ │ │ │ + if (!this.supported()) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + if (!document.namespaces.olv) { │ │ │ │ + document.namespaces.add("olv", this.xmlns); │ │ │ │ + var style = document.createStyleSheet(); │ │ │ │ + var shapes = ['shape', 'rect', 'oval', 'fill', 'stroke', 'imagedata', 'group', 'textbox']; │ │ │ │ + for (var i = 0, len = shapes.length; i < len; i++) { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + style.addRule('olv\\:' + shapes[i], "behavior: url(#default#VML); " + │ │ │ │ + "position: absolute; display: inline-block;"); │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + OpenLayers.Renderer.Elements.prototype.initialize.apply(this, │ │ │ │ + arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.TMS │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} Title to be displayed in a <OpenLayers.Control.LayerSwitcher> │ │ │ │ - * url - {String} Service endpoint (without the version number). E.g. │ │ │ │ - * "http://tms.osgeo.org/". │ │ │ │ - * options - {Object} Additional properties to be set on the layer. The │ │ │ │ - * <layername> and <type> properties must be set here. │ │ │ │ + * APIMethod: supported │ │ │ │ + * Determine whether a browser supports this renderer. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The browser supports the VML renderer │ │ │ │ */ │ │ │ │ - initialize: function(name, url, options) { │ │ │ │ - var newArguments = []; │ │ │ │ - newArguments.push(name, url, {}, options); │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments); │ │ │ │ + supported: function() { │ │ │ │ + return !!(document.namespaces); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Create a complete copy of this layer. │ │ │ │ + * Method: setExtent │ │ │ │ + * Set the renderer's extent │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * obj - {Object} Should only be provided by subclasses that call this │ │ │ │ - * method. │ │ │ │ + * extent - {<OpenLayers.Bounds>} │ │ │ │ + * resolutionChanged - {Boolean} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Layer.TMS>} An exact clone of this <OpenLayers.Layer.TMS> │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ + setExtent: function(extent, resolutionChanged) { │ │ │ │ + var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.TMS(this.name, │ │ │ │ - this.url, │ │ │ │ - this.getOptions()); │ │ │ │ + var left = (extent.left / resolution) | 0; │ │ │ │ + var top = (extent.top / resolution - this.size.h) | 0; │ │ │ │ + if (resolutionChanged || !this.offset) { │ │ │ │ + this.offset = { │ │ │ │ + x: left, │ │ │ │ + y: top │ │ │ │ + }; │ │ │ │ + left = 0; │ │ │ │ + top = 0; │ │ │ │ + } else { │ │ │ │ + left = left - this.offset.x; │ │ │ │ + top = top - this.offset.y; │ │ │ │ } │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ │ │ │ │ - // copy/set any non-init, non-simple values here │ │ │ │ + var org = (left - this.xOffset) + " " + top; │ │ │ │ + this.root.coordorigin = org; │ │ │ │ + var roots = [this.root, this.vectorRoot, this.textRoot]; │ │ │ │ + var root; │ │ │ │ + for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ + root = roots[i]; │ │ │ │ │ │ │ │ - return obj; │ │ │ │ + var size = this.size.w + " " + this.size.h; │ │ │ │ + root.coordsize = size; │ │ │ │ + │ │ │ │ + } │ │ │ │ + // flip the VML display Y axis upside down so it │ │ │ │ + // matches the display Y axis of the map │ │ │ │ + this.root.style.flip = "y"; │ │ │ │ + │ │ │ │ + return coordSysUnchanged; │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: getURL │ │ │ │ - * │ │ │ │ + * Method: setSize │ │ │ │ + * Set the size of the drawing surface │ │ │ │ + * │ │ │ │ * 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 │ │ │ │ + * size - {<OpenLayers.Size>} the size of the drawing surface │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ - var y = Math.round((bounds.bottom - this.tileOrigin.lat) / (res * this.tileSize.h)); │ │ │ │ - var z = this.getServerZoom(); │ │ │ │ - var path = this.serviceVersion + "/" + this.layername + "/" + z + "/" + x + "/" + y + "." + this.type; │ │ │ │ - var url = this.url; │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(path, url); │ │ │ │ + setSize: function(size) { │ │ │ │ + OpenLayers.Renderer.prototype.setSize.apply(this, arguments); │ │ │ │ + │ │ │ │ + // setting width and height on all roots to avoid flicker which we │ │ │ │ + // would get with 100% width and height on child roots │ │ │ │ + var roots = [ │ │ │ │ + this.rendererRoot, │ │ │ │ + this.root, │ │ │ │ + this.vectorRoot, │ │ │ │ + this.textRoot │ │ │ │ + ]; │ │ │ │ + var w = this.size.w + "px"; │ │ │ │ + var h = this.size.h + "px"; │ │ │ │ + var root; │ │ │ │ + for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ + root = roots[i]; │ │ │ │ + root.style.width = w; │ │ │ │ + root.style.height = h; │ │ │ │ } │ │ │ │ - return url + path; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * When the layer is added to a map, then we can fetch our origin │ │ │ │ - * (if we don't have one.) │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: getNodeType │ │ │ │ + * Get the node type for a geometry and style │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} The corresponding node type for the specified geometry │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); │ │ │ │ - if (!this.tileOrigin) { │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left, │ │ │ │ - this.map.maxExtent.bottom); │ │ │ │ + getNodeType: function(geometry, style) { │ │ │ │ + var nodeType = null; │ │ │ │ + switch (geometry.CLASS_NAME) { │ │ │ │ + case "OpenLayers.Geometry.Point": │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + nodeType = "olv:rect"; │ │ │ │ + } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ + nodeType = "olv:shape"; │ │ │ │ + } else { │ │ │ │ + nodeType = "olv:oval"; │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case "OpenLayers.Geometry.Rectangle": │ │ │ │ + nodeType = "olv:rect"; │ │ │ │ + break; │ │ │ │ + case "OpenLayers.Geometry.LineString": │ │ │ │ + case "OpenLayers.Geometry.LinearRing": │ │ │ │ + case "OpenLayers.Geometry.Polygon": │ │ │ │ + case "OpenLayers.Geometry.Curve": │ │ │ │ + nodeType = "olv:shape"; │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + break; │ │ │ │ } │ │ │ │ + return nodeType; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.TMS" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Layer/WMS.js │ │ │ │ - ====================================================================== */ │ │ │ │ + /** │ │ │ │ + * Method: setStyle │ │ │ │ + * Use to set all the style attributes to a VML node. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} An VML element to decorate │ │ │ │ + * style - {Object} │ │ │ │ + * options - {Object} Currently supported options include │ │ │ │ + * 'isFilled' {Boolean} and │ │ │ │ + * 'isStroked' {Boolean} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + */ │ │ │ │ + setStyle: function(node, style, options, geometry) { │ │ │ │ + style = style || node._style; │ │ │ │ + options = options || node._options; │ │ │ │ + var fillColor = style.fillColor; │ │ │ │ │ │ │ │ -/* 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 title = style.title || style.graphicTitle; │ │ │ │ + if (title) { │ │ │ │ + node.title = title; │ │ │ │ + } │ │ │ │ │ │ │ │ + if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + options.isFilled = true; │ │ │ │ + var width = style.graphicWidth || style.graphicHeight; │ │ │ │ + var height = style.graphicHeight || style.graphicWidth; │ │ │ │ + width = width ? width : style.pointRadius * 2; │ │ │ │ + height = height ? height : style.pointRadius * 2; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ - */ │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var xOffset = (style.graphicXOffset != undefined) ? │ │ │ │ + style.graphicXOffset : -(0.5 * width); │ │ │ │ + var yOffset = (style.graphicYOffset != undefined) ? │ │ │ │ + style.graphicYOffset : -(0.5 * height); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * 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, { │ │ │ │ + node.style.left = ((((geometry.x - this.featureDx) / resolution - this.offset.x) + xOffset) | 0) + "px"; │ │ │ │ + node.style.top = (((geometry.y / resolution - this.offset.y) - (yOffset + height)) | 0) + "px"; │ │ │ │ + node.style.width = width + "px"; │ │ │ │ + node.style.height = height + "px"; │ │ │ │ + node.style.flip = "y"; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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" │ │ │ │ - }, │ │ │ │ + // modify fillColor and options for stroke styling below │ │ │ │ + fillColor = "none"; │ │ │ │ + options.isStroked = false; │ │ │ │ + } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ + var cache = this.importSymbol(style.graphicName); │ │ │ │ + node.path = cache.path; │ │ │ │ + node.coordorigin = cache.left + "," + cache.bottom; │ │ │ │ + var size = cache.size; │ │ │ │ + node.coordsize = size + "," + size; │ │ │ │ + this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ + node.style.flip = "y"; │ │ │ │ + } else { │ │ │ │ + this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} Default is true for WMS layer │ │ │ │ - */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + // fill │ │ │ │ + if (options.isFilled) { │ │ │ │ + node.fillcolor = fillColor; │ │ │ │ + } else { │ │ │ │ + node.filled = "false"; │ │ │ │ + } │ │ │ │ + var fills = node.getElementsByTagName("fill"); │ │ │ │ + var fill = (fills.length == 0) ? null : fills[0]; │ │ │ │ + if (!options.isFilled) { │ │ │ │ + if (fill) { │ │ │ │ + node.removeChild(fill); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (!fill) { │ │ │ │ + fill = this.createNode('olv:fill', node.id + "_fill"); │ │ │ │ + } │ │ │ │ + fill.opacity = style.fillOpacity; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + if (node._geometryClass === "OpenLayers.Geometry.Point" && │ │ │ │ + style.externalGraphic) { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + // override fillOpacity │ │ │ │ + if (style.graphicOpacity) { │ │ │ │ + fill.opacity = style.graphicOpacity; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: {}, │ │ │ │ + fill.src = style.externalGraphic; │ │ │ │ + fill.type = "frame"; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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"; │ │ │ │ + if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ + fill.aspect = "atmost"; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (fill.parentNode != node) { │ │ │ │ + node.appendChild(fill); │ │ │ │ + } │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + // additional rendering for rotated graphics or symbols │ │ │ │ + var rotation = style.rotation; │ │ │ │ + if ((rotation !== undefined || node._rotation !== undefined)) { │ │ │ │ + node._rotation = rotation; │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ + // make the fill fully transparent, because we now have │ │ │ │ + // the graphic as imagedata element. We cannot just remove │ │ │ │ + // the fill, because this is part of the hack described │ │ │ │ + // in graphicRotate │ │ │ │ + fill.opacity = 0; │ │ │ │ + } else if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ + node.style.rotation = rotation || 0; │ │ │ │ } │ │ │ │ + } │ │ │ │ │ │ │ │ - // 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"; │ │ │ │ + // stroke │ │ │ │ + var strokes = node.getElementsByTagName("stroke"); │ │ │ │ + var stroke = (strokes.length == 0) ? null : strokes[0]; │ │ │ │ + if (!options.isStroked) { │ │ │ │ + node.stroked = false; │ │ │ │ + if (stroke) { │ │ │ │ + stroke.on = false; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (!stroke) { │ │ │ │ + stroke = this.createNode('olv:stroke', node.id + "_stroke"); │ │ │ │ + node.appendChild(stroke); │ │ │ │ + } │ │ │ │ + stroke.on = true; │ │ │ │ + stroke.color = style.strokeColor; │ │ │ │ + stroke.weight = style.strokeWidth + "px"; │ │ │ │ + stroke.opacity = style.strokeOpacity; │ │ │ │ + stroke.endcap = style.strokeLinecap == 'butt' ? 'flat' : │ │ │ │ + (style.strokeLinecap || 'round'); │ │ │ │ + if (style.strokeDashstyle) { │ │ │ │ + stroke.dashstyle = this.dashStyle(style); │ │ │ │ } │ │ │ │ } │ │ │ │ │ │ │ │ + if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ + node.style.cursor = style.cursor; │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.WMS>} An exact clone of this layer │ │ │ │ + * Method: graphicRotate │ │ │ │ + * If a point is to be styled with externalGraphic and rotation, VML fills │ │ │ │ + * cannot be used to display the graphic, because rotation of graphic │ │ │ │ + * fills is not supported by the VML implementation of Internet Explorer. │ │ │ │ + * This method creates a olv:imagedata element inside the VML node, │ │ │ │ + * DXImageTransform.Matrix and BasicImage filters for rotation and │ │ │ │ + * opacity, and a 3-step hack to remove rendering artefacts from the │ │ │ │ + * graphic and preserve the ability of graphics to trigger events. │ │ │ │ + * Finally, OpenLayers methods are used to determine the correct │ │ │ │ + * insertion point of the rotated image, because DXImageTransform.Matrix │ │ │ │ + * does the rotation without the ability to specify a rotation center │ │ │ │ + * point. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * xOffset - {Number} rotation center relative to image, x coordinate │ │ │ │ + * yOffset - {Number} rotation center relative to image, y coordinate │ │ │ │ + * style - {Object} │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ + graphicRotate: function(node, xOffset, yOffset, style) { │ │ │ │ + var style = style || node._style; │ │ │ │ + var rotation = style.rotation || 0; │ │ │ │ │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.WMS(this.name, │ │ │ │ - this.url, │ │ │ │ - this.params, │ │ │ │ - this.getOptions()); │ │ │ │ + var aspectRatio, size; │ │ │ │ + if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ + // load the image to determine its size │ │ │ │ + var img = new Image(); │ │ │ │ + img.onreadystatechange = OpenLayers.Function.bind(function() { │ │ │ │ + if (img.readyState == "complete" || │ │ │ │ + img.readyState == "interactive") { │ │ │ │ + aspectRatio = img.width / img.height; │ │ │ │ + size = Math.max(style.pointRadius * 2, │ │ │ │ + style.graphicWidth || 0, │ │ │ │ + style.graphicHeight || 0); │ │ │ │ + xOffset = xOffset * aspectRatio; │ │ │ │ + style.graphicWidth = size * aspectRatio; │ │ │ │ + style.graphicHeight = size; │ │ │ │ + this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ + } │ │ │ │ + }, this); │ │ │ │ + img.src = style.externalGraphic; │ │ │ │ + │ │ │ │ + // will be called again by the onreadystate handler │ │ │ │ + return; │ │ │ │ + } else { │ │ │ │ + size = Math.max(style.graphicWidth, style.graphicHeight); │ │ │ │ + aspectRatio = style.graphicWidth / style.graphicHeight; │ │ │ │ } │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + var width = Math.round(style.graphicWidth || size * aspectRatio); │ │ │ │ + var height = Math.round(style.graphicHeight || size); │ │ │ │ + node.style.width = width + "px"; │ │ │ │ + node.style.height = height + "px"; │ │ │ │ │ │ │ │ - // copy/set any non-init, non-simple values here │ │ │ │ + // Three steps are required to remove artefacts for images with │ │ │ │ + // transparent backgrounds (resulting from using DXImageTransform │ │ │ │ + // filters on svg objects), while preserving awareness for browser │ │ │ │ + // events on images: │ │ │ │ + // - Use the fill as usual (like for unrotated images) to handle │ │ │ │ + // events │ │ │ │ + // - specify an imagedata element with the same src as the fill │ │ │ │ + // - style the imagedata element with an AlphaImageLoader filter │ │ │ │ + // with empty src │ │ │ │ + var image = document.getElementById(node.id + "_image"); │ │ │ │ + if (!image) { │ │ │ │ + image = this.createNode("olv:imagedata", node.id + "_image"); │ │ │ │ + node.appendChild(image); │ │ │ │ + } │ │ │ │ + image.style.width = width + "px"; │ │ │ │ + image.style.height = height + "px"; │ │ │ │ + image.src = style.externalGraphic; │ │ │ │ + image.style.filter = │ │ │ │ + "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + │ │ │ │ + "src='', sizingMethod='scale')"; │ │ │ │ │ │ │ │ - return obj; │ │ │ │ + var rot = rotation * Math.PI / 180; │ │ │ │ + var sintheta = Math.sin(rot); │ │ │ │ + var costheta = Math.cos(rot); │ │ │ │ + │ │ │ │ + // do the rotation on the image │ │ │ │ + var filter = │ │ │ │ + "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta + │ │ │ │ + ",M12=" + (-sintheta) + ",M21=" + sintheta + ",M22=" + costheta + │ │ │ │ + ",SizingMethod='auto expand')\n"; │ │ │ │ + │ │ │ │ + // set the opacity (needed for the imagedata) │ │ │ │ + var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ + if (opacity && opacity != 1) { │ │ │ │ + filter += │ │ │ │ + "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + │ │ │ │ + opacity + ")\n"; │ │ │ │ + } │ │ │ │ + node.style.filter = filter; │ │ │ │ + │ │ │ │ + // do the rotation again on a box, so we know the insertion point │ │ │ │ + var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset); │ │ │ │ + var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry(); │ │ │ │ + imgBox.rotate(style.rotation, centerPoint); │ │ │ │ + var imgBounds = imgBox.getBounds(); │ │ │ │ + │ │ │ │ + node.style.left = Math.round( │ │ │ │ + parseInt(node.style.left) + imgBounds.left) + "px"; │ │ │ │ + node.style.top = Math.round( │ │ │ │ + parseInt(node.style.top) - imgBounds.bottom) + "px"; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: reverseAxisOrder │ │ │ │ - * Returns true if the axis order is reversed for the WMS version and │ │ │ │ - * projection of the layer. │ │ │ │ + * Method: postDraw │ │ │ │ + * Does some node postprocessing to work around browser issues: │ │ │ │ + * - Some versions of Internet Explorer seem to be unable to set fillcolor │ │ │ │ + * and strokecolor to "none" correctly before the fill node is appended │ │ │ │ + * to a visible vml node. This method takes care of that and sets │ │ │ │ + * fillcolor and strokecolor again if needed. │ │ │ │ + * - In some cases, a node won't become visible after being drawn. Setting │ │ │ │ + * style.visibility to "visible" works around that. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} true if the axis order is reversed, false otherwise. │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ */ │ │ │ │ - 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)); │ │ │ │ + postDraw: function(node) { │ │ │ │ + node.style.visibility = "visible"; │ │ │ │ + var fillColor = node._style.fillColor; │ │ │ │ + var strokeColor = node._style.strokeColor; │ │ │ │ + if (fillColor == "none" && │ │ │ │ + node.fillcolor != fillColor) { │ │ │ │ + node.fillcolor = fillColor; │ │ │ │ + } │ │ │ │ + if (strokeColor == "none" && │ │ │ │ + node.strokecolor != strokeColor) { │ │ │ │ + node.strokecolor = strokeColor; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: getURL │ │ │ │ - * Return a GetMap query string for this layer │ │ │ │ - * │ │ │ │ + * Method: setNodeDimension │ │ │ │ + * Get the geometry's bounds, convert it to our vml coordinate system, │ │ │ │ + * then set the node's position, size, and local coordinate system. │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ + setNodeDimension: function(node, geometry) { │ │ │ │ │ │ │ │ - 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; │ │ │ │ - }, │ │ │ │ + var bbox = geometry.getBounds(); │ │ │ │ + if (bbox) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + var scaledBox = │ │ │ │ + new OpenLayers.Bounds(((bbox.left - this.featureDx) / resolution - this.offset.x) | 0, │ │ │ │ + (bbox.bottom / resolution - this.offset.y) | 0, │ │ │ │ + ((bbox.right - this.featureDx) / resolution - this.offset.x) | 0, │ │ │ │ + (bbox.top / resolution - this.offset.y) | 0); │ │ │ │ + │ │ │ │ + // Set the internal coordinate system to draw the path │ │ │ │ + node.style.left = scaledBox.left + "px"; │ │ │ │ + node.style.top = scaledBox.top + "px"; │ │ │ │ + node.style.width = scaledBox.getWidth() + "px"; │ │ │ │ + node.style.height = scaledBox.getHeight() + "px"; │ │ │ │ + │ │ │ │ + node.coordorigin = scaledBox.left + " " + scaledBox.top; │ │ │ │ + node.coordsize = scaledBox.getWidth() + " " + scaledBox.getHeight(); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + * Method: dashStyle │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * newParams - {Object} │ │ │ │ - * altUrl - {String} Use this as the url instead of the layer's url │ │ │ │ + * style - {Object} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} │ │ │ │ + * {String} A VML compliant 'stroke-dasharray' value │ │ │ │ */ │ │ │ │ - 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"; │ │ │ │ + dashStyle: function(style) { │ │ │ │ + var dash = style.strokeDashstyle; │ │ │ │ + switch (dash) { │ │ │ │ + case 'solid': │ │ │ │ + case 'dot': │ │ │ │ + case 'dash': │ │ │ │ + case 'dashdot': │ │ │ │ + case 'longdash': │ │ │ │ + case 'longdashdot': │ │ │ │ + return dash; │ │ │ │ + default: │ │ │ │ + // very basic guessing of dash style patterns │ │ │ │ + var parts = dash.split(/[ ,]/); │ │ │ │ + if (parts.length == 2) { │ │ │ │ + if (1 * parts[0] >= 2 * parts[1]) { │ │ │ │ + return "longdash"; │ │ │ │ + } │ │ │ │ + return (parts[0] == 1 || parts[1] == 1) ? "dot" : "dash"; │ │ │ │ + } else if (parts.length == 4) { │ │ │ │ + return (1 * parts[0] >= 2 * parts[1]) ? "longdashdot" : │ │ │ │ + "dashdot"; │ │ │ │ + } │ │ │ │ + return "solid"; │ │ │ │ } │ │ │ │ - │ │ │ │ - return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply( │ │ │ │ - this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.WMS" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/ArcXML.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/Geometry/Polygon.js │ │ │ │ - * @requires OpenLayers/Geometry/Point.js │ │ │ │ - * @requires OpenLayers/Geometry/MultiPolygon.js │ │ │ │ - * @requires OpenLayers/Geometry/LinearRing.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.ArcXML │ │ │ │ - * Read/Write ArcXML. Create a new instance with the <OpenLayers.Format.ArcXML> │ │ │ │ - * constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.ArcXML = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Property: fontStyleKeys │ │ │ │ - * {Array} List of keys used in font styling. │ │ │ │ + * Method: createNode │ │ │ │ + * Create a new node │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * type - {String} Kind of node to draw │ │ │ │ + * id - {String} Id for node │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A new node of the given type and id │ │ │ │ */ │ │ │ │ - fontStyleKeys: [ │ │ │ │ - 'antialiasing', 'blockout', 'font', 'fontcolor', 'fontsize', 'fontstyle', │ │ │ │ - 'glowing', 'interval', 'outline', 'printmode', 'shadow', 'transparency' │ │ │ │ - ], │ │ │ │ + createNode: function(type, id) { │ │ │ │ + var node = document.createElement(type); │ │ │ │ + if (id) { │ │ │ │ + node.id = id; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: request │ │ │ │ - * A get_image request destined for an ArcIMS server. │ │ │ │ - */ │ │ │ │ - request: null, │ │ │ │ + // IE hack to make elements unselectable, to prevent 'blue flash' │ │ │ │ + // while dragging vectors; #1410 │ │ │ │ + node.unselectable = 'on'; │ │ │ │ + node.onselectstart = OpenLayers.Function.False; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: response │ │ │ │ - * A parsed response from an ArcIMS server. │ │ │ │ - */ │ │ │ │ - response: null, │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.ArcXML │ │ │ │ - * Create a new parser/writer for ArcXML. Create an instance of this class │ │ │ │ - * to begin authoring a request to an ArcIMS service. This is used │ │ │ │ - * primarily by the ArcIMS layer, but could be used to do other wild │ │ │ │ - * stuff, like geocoding. │ │ │ │ + * Method: nodeTypeCompare │ │ │ │ + * Determine whether a node is of a given type │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * node - {DOMElement} An VML element │ │ │ │ + * type - {String} Kind of node │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the specified node is of the specified type │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - this.request = new OpenLayers.Format.ArcXML.Request(); │ │ │ │ - this.response = new OpenLayers.Format.ArcXML.Response(); │ │ │ │ - │ │ │ │ - if (options) { │ │ │ │ - if (options.requesttype == "feature") { │ │ │ │ - this.request.get_image = null; │ │ │ │ - │ │ │ │ - var qry = this.request.get_feature.query; │ │ │ │ - this.addCoordSys(qry.featurecoordsys, options.featureCoordSys); │ │ │ │ - this.addCoordSys(qry.filtercoordsys, options.filterCoordSys); │ │ │ │ - │ │ │ │ - if (options.polygon) { │ │ │ │ - qry.isspatial = true; │ │ │ │ - qry.spatialfilter.polygon = options.polygon; │ │ │ │ - } else if (options.envelope) { │ │ │ │ - qry.isspatial = true; │ │ │ │ - qry.spatialfilter.envelope = { │ │ │ │ - minx: 0, │ │ │ │ - miny: 0, │ │ │ │ - maxx: 0, │ │ │ │ - maxy: 0 │ │ │ │ - }; │ │ │ │ - this.parseEnvelope(qry.spatialfilter.envelope, options.envelope); │ │ │ │ - } │ │ │ │ - } else if (options.requesttype == "image") { │ │ │ │ - this.request.get_feature = null; │ │ │ │ + nodeTypeCompare: function(node, type) { │ │ │ │ │ │ │ │ - var props = this.request.get_image.properties; │ │ │ │ - this.parseEnvelope(props.envelope, options.envelope); │ │ │ │ + //split type │ │ │ │ + var subType = type; │ │ │ │ + var splitIndex = subType.indexOf(":"); │ │ │ │ + if (splitIndex != -1) { │ │ │ │ + subType = subType.substr(splitIndex + 1); │ │ │ │ + } │ │ │ │ │ │ │ │ - this.addLayers(props.layerlist, options.layers); │ │ │ │ - this.addImageSize(props.imagesize, options.tileSize); │ │ │ │ - this.addCoordSys(props.featurecoordsys, options.featureCoordSys); │ │ │ │ - this.addCoordSys(props.filtercoordsys, options.filterCoordSys); │ │ │ │ - } else { │ │ │ │ - // if an arcxml object is being created with no request type, it is │ │ │ │ - // probably going to consume a response, so do not throw an error if │ │ │ │ - // the requesttype is not defined │ │ │ │ - this.request = null; │ │ │ │ - } │ │ │ │ + //split nodeName │ │ │ │ + var nodeName = node.nodeName; │ │ │ │ + splitIndex = nodeName.indexOf(":"); │ │ │ │ + if (splitIndex != -1) { │ │ │ │ + nodeName = nodeName.substr(splitIndex + 1); │ │ │ │ } │ │ │ │ │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ + return (subType == nodeName); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseEnvelope │ │ │ │ - * Parse an array of coordinates into an ArcXML envelope structure. │ │ │ │ + * Method: createRenderRoot │ │ │ │ + * Create the renderer root │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * env - {Object} An envelope object that will contain the parsed coordinates. │ │ │ │ - * arr - {Array(double)} An array of coordinates in the order: [ minx, miny, maxx, maxy ] │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} The specific render engine's root element │ │ │ │ */ │ │ │ │ - parseEnvelope: function(env, arr) { │ │ │ │ - if (arr && arr.length == 4) { │ │ │ │ - env.minx = arr[0]; │ │ │ │ - env.miny = arr[1]; │ │ │ │ - env.maxx = arr[2]; │ │ │ │ - env.maxy = arr[3]; │ │ │ │ - } │ │ │ │ + createRenderRoot: function() { │ │ │ │ + return this.nodeFactory(this.container.id + "_vmlRoot", "div"); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: addLayers │ │ │ │ - * Add a collection of layers to another collection of layers. Each layer in the list is tuple of │ │ │ │ - * { id, visible }. These layer collections represent the │ │ │ │ - * /ARCXML/REQUEST/get_image/PROPERTIES/LAYERLIST/LAYERDEF items in ArcXML │ │ │ │ - * │ │ │ │ - * TODO: Add support for dynamic layer rendering. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: createRoot │ │ │ │ + * Create the main root element │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * ll - {Array({id,visible})} A list of layer definitions. │ │ │ │ - * lyrs - {Array({id,visible})} A list of layer definitions. │ │ │ │ + * suffix - {String} suffix to append to the id │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - addLayers: function(ll, lyrs) { │ │ │ │ - for (var lind = 0, len = lyrs.length; lind < len; lind++) { │ │ │ │ - ll.push(lyrs[lind]); │ │ │ │ - } │ │ │ │ + createRoot: function(suffix) { │ │ │ │ + return this.nodeFactory(this.container.id + suffix, "olv:group"); │ │ │ │ }, │ │ │ │ │ │ │ │ + /************************************** │ │ │ │ + * * │ │ │ │ + * GEOMETRY DRAWING FUNCTIONS * │ │ │ │ + * * │ │ │ │ + **************************************/ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: addImageSize │ │ │ │ - * Set the size of the requested image. │ │ │ │ - * │ │ │ │ + * Method: drawPoint │ │ │ │ + * Render a point │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * imsize - {Object} An ArcXML imagesize object. │ │ │ │ - * olsize - {<OpenLayers.Size>} The image size to set. │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} or false if the point could not be drawn │ │ │ │ */ │ │ │ │ - addImageSize: function(imsize, olsize) { │ │ │ │ - if (olsize !== null) { │ │ │ │ - imsize.width = olsize.w; │ │ │ │ - imsize.height = olsize.h; │ │ │ │ - imsize.printwidth = olsize.w; │ │ │ │ - imsize.printheight = olsize.h; │ │ │ │ - } │ │ │ │ + drawPoint: function(node, geometry) { │ │ │ │ + return this.drawCircle(node, geometry, 1); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: addCoordSys │ │ │ │ - * Add the coordinate system information to an object. The object may be │ │ │ │ - * │ │ │ │ + * Method: drawCircle │ │ │ │ + * Render a circle. │ │ │ │ + * Size and Center a circle given geometry (x,y center) and radius │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * featOrFilt - {Object} A featurecoordsys or filtercoordsys ArcXML structure. │ │ │ │ - * fsys - {String} or {<OpenLayers.Projection>} or {filtercoordsys} or │ │ │ │ - * {featurecoordsys} A projection representation. If it's a {String}, │ │ │ │ - * the value is assumed to be the SRID. If it's a {OpenLayers.Projection} │ │ │ │ - * AND Proj4js is available, the projection number and name are extracted │ │ │ │ - * from there. If it's a filter or feature ArcXML structure, it is copied. │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * radius - {float} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} or false if the circle could not ne drawn │ │ │ │ */ │ │ │ │ - addCoordSys: function(featOrFilt, fsys) { │ │ │ │ - if (typeof fsys == "string") { │ │ │ │ - featOrFilt.id = parseInt(fsys); │ │ │ │ - featOrFilt.string = fsys; │ │ │ │ - } │ │ │ │ - // is this a proj4js instance? │ │ │ │ - else if (typeof fsys == "object" && fsys.proj !== null) { │ │ │ │ - featOrFilt.id = fsys.proj.srsProjNumber; │ │ │ │ - featOrFilt.string = fsys.proj.srsCode; │ │ │ │ - } else { │ │ │ │ - featOrFilt = fsys; │ │ │ │ + drawCircle: function(node, geometry, radius) { │ │ │ │ + if (!isNaN(geometry.x) && !isNaN(geometry.y)) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + │ │ │ │ + node.style.left = ((((geometry.x - this.featureDx) / resolution - this.offset.x) | 0) - radius) + "px"; │ │ │ │ + node.style.top = (((geometry.y / resolution - this.offset.y) | 0) - radius) + "px"; │ │ │ │ + │ │ │ │ + var diameter = radius * 2; │ │ │ │ + │ │ │ │ + node.style.width = diameter + "px"; │ │ │ │ + node.style.height = diameter + "px"; │ │ │ │ + return node; │ │ │ │ } │ │ │ │ + return false; │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * APIMethod: iserror │ │ │ │ - * Check to see if the response from the server was an error. │ │ │ │ - * │ │ │ │ + * Method: drawLineString │ │ │ │ + * Render a linestring. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. If nothing is supplied, │ │ │ │ - * the current response is examined. │ │ │ │ - * │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} true if the response was an error. │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - iserror: function(data) { │ │ │ │ - var ret = null; │ │ │ │ - │ │ │ │ - if (!data) { │ │ │ │ - ret = (this.response.error !== ''); │ │ │ │ - } else { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - var errorNodes = data.documentElement.getElementsByTagName("ERROR"); │ │ │ │ - ret = (errorNodes !== null && errorNodes.length > 0); │ │ │ │ - } │ │ │ │ - │ │ │ │ - return ret; │ │ │ │ + drawLineString: function(node, geometry) { │ │ │ │ + return this.drawLine(node, geometry, false); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read data from a string, and return an response. │ │ │ │ + * Method: drawLinearRing │ │ │ │ + * Render a linearring │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Format.ArcXML.Response>} An ArcXML response. Note that this response │ │ │ │ - * data may change in the future. │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var arcNode = null; │ │ │ │ - if (data && data.documentElement) { │ │ │ │ - if (data.documentElement.nodeName == "ARCXML") { │ │ │ │ - arcNode = data.documentElement; │ │ │ │ - } else { │ │ │ │ - arcNode = data.documentElement.getElementsByTagName("ARCXML")[0]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // in Safari, arcNode will be there but will have a child named │ │ │ │ - // parsererror │ │ │ │ - if (!arcNode || arcNode.firstChild.nodeName === 'parsererror') { │ │ │ │ - var error, source; │ │ │ │ - try { │ │ │ │ - error = data.firstChild.nodeValue; │ │ │ │ - source = data.firstChild.childNodes[1].firstChild.nodeValue; │ │ │ │ - } catch (err) { │ │ │ │ - // pass │ │ │ │ - } │ │ │ │ - throw { │ │ │ │ - message: "Error parsing the ArcXML request", │ │ │ │ - error: error, │ │ │ │ - source: source │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var response = this.parseResponse(arcNode); │ │ │ │ - return response; │ │ │ │ + drawLinearRing: function(node, geometry) { │ │ │ │ + return this.drawLine(node, geometry, true); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Generate an ArcXml document string for sending to an ArcIMS server. │ │ │ │ + * Method: DrawLine │ │ │ │ + * Render a line. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * closeLine - {Boolean} Close the line? (make it a ring?) │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} A string representing the ArcXML document request. │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - write: function(request) { │ │ │ │ - if (!request) { │ │ │ │ - request = this.request; │ │ │ │ - } │ │ │ │ - var root = this.createElementNS("", "ARCXML"); │ │ │ │ - root.setAttribute("version", "1.1"); │ │ │ │ - │ │ │ │ - var reqElem = this.createElementNS("", "REQUEST"); │ │ │ │ - │ │ │ │ - if (request.get_image != null) { │ │ │ │ - var getElem = this.createElementNS("", "GET_IMAGE"); │ │ │ │ - reqElem.appendChild(getElem); │ │ │ │ - │ │ │ │ - var propElem = this.createElementNS("", "PROPERTIES"); │ │ │ │ - getElem.appendChild(propElem); │ │ │ │ - │ │ │ │ - var props = request.get_image.properties; │ │ │ │ - if (props.featurecoordsys != null) { │ │ │ │ - var feat = this.createElementNS("", "FEATURECOORDSYS"); │ │ │ │ - propElem.appendChild(feat); │ │ │ │ - │ │ │ │ - if (props.featurecoordsys.id === 0) { │ │ │ │ - feat.setAttribute("string", props.featurecoordsys['string']); │ │ │ │ - } else { │ │ │ │ - feat.setAttribute("id", props.featurecoordsys.id); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (props.filtercoordsys != null) { │ │ │ │ - var filt = this.createElementNS("", "FILTERCOORDSYS"); │ │ │ │ - propElem.appendChild(filt); │ │ │ │ - │ │ │ │ - if (props.filtercoordsys.id === 0) { │ │ │ │ - filt.setAttribute("string", props.filtercoordsys.string); │ │ │ │ - } else { │ │ │ │ - filt.setAttribute("id", props.filtercoordsys.id); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (props.envelope != null) { │ │ │ │ - var env = this.createElementNS("", "ENVELOPE"); │ │ │ │ - propElem.appendChild(env); │ │ │ │ - │ │ │ │ - env.setAttribute("minx", props.envelope.minx); │ │ │ │ - env.setAttribute("miny", props.envelope.miny); │ │ │ │ - env.setAttribute("maxx", props.envelope.maxx); │ │ │ │ - env.setAttribute("maxy", props.envelope.maxy); │ │ │ │ - } │ │ │ │ + drawLine: function(node, geometry, closeLine) { │ │ │ │ │ │ │ │ - var imagesz = this.createElementNS("", "IMAGESIZE"); │ │ │ │ - propElem.appendChild(imagesz); │ │ │ │ + this.setNodeDimension(node, geometry); │ │ │ │ │ │ │ │ - imagesz.setAttribute("height", props.imagesize.height); │ │ │ │ - imagesz.setAttribute("width", props.imagesize.width); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var numComponents = geometry.components.length; │ │ │ │ + var parts = new Array(numComponents); │ │ │ │ │ │ │ │ - if (props.imagesize.height != props.imagesize.printheight || │ │ │ │ - props.imagesize.width != props.imagesize.printwidth) { │ │ │ │ - imagesz.setAttribute("printheight", props.imagesize.printheight); │ │ │ │ - imagesz.setArrtibute("printwidth", props.imagesize.printwidth); │ │ │ │ - } │ │ │ │ + var comp, x, y; │ │ │ │ + for (var i = 0; i < numComponents; i++) { │ │ │ │ + comp = geometry.components[i]; │ │ │ │ + x = ((comp.x - this.featureDx) / resolution - this.offset.x) | 0; │ │ │ │ + y = (comp.y / resolution - this.offset.y) | 0; │ │ │ │ + parts[i] = " " + x + "," + y + " l "; │ │ │ │ + } │ │ │ │ + var end = (closeLine) ? " x e" : " e"; │ │ │ │ + node.path = "m" + parts.join("") + end; │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (props.background != null) { │ │ │ │ - var backgrnd = this.createElementNS("", "BACKGROUND"); │ │ │ │ - propElem.appendChild(backgrnd); │ │ │ │ + /** │ │ │ │ + * Method: drawPolygon │ │ │ │ + * Render a polygon │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + drawPolygon: function(node, geometry) { │ │ │ │ + this.setNodeDimension(node, geometry); │ │ │ │ │ │ │ │ - backgrnd.setAttribute("color", │ │ │ │ - props.background.color.r + "," + │ │ │ │ - props.background.color.g + "," + │ │ │ │ - props.background.color.b); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ │ │ │ │ - if (props.background.transcolor !== null) { │ │ │ │ - backgrnd.setAttribute("transcolor", │ │ │ │ - props.background.transcolor.r + "," + │ │ │ │ - props.background.transcolor.g + "," + │ │ │ │ - props.background.transcolor.b); │ │ │ │ + var path = []; │ │ │ │ + var j, jj, points, area, first, second, i, ii, comp, pathComp, x, y; │ │ │ │ + for (j = 0, jj = geometry.components.length; j < jj; j++) { │ │ │ │ + path.push("m"); │ │ │ │ + points = geometry.components[j].components; │ │ │ │ + // we only close paths of interior rings with area │ │ │ │ + area = (j === 0); │ │ │ │ + first = null; │ │ │ │ + second = null; │ │ │ │ + for (i = 0, ii = points.length; i < ii; i++) { │ │ │ │ + comp = points[i]; │ │ │ │ + x = ((comp.x - this.featureDx) / resolution - this.offset.x) | 0; │ │ │ │ + y = (comp.y / resolution - this.offset.y) | 0; │ │ │ │ + pathComp = " " + x + "," + y; │ │ │ │ + path.push(pathComp); │ │ │ │ + if (i == 0) { │ │ │ │ + path.push(" l"); │ │ │ │ } │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (props.layerlist != null && props.layerlist.length > 0) { │ │ │ │ - var layerlst = this.createElementNS("", "LAYERLIST"); │ │ │ │ - propElem.appendChild(layerlst); │ │ │ │ - │ │ │ │ - for (var ld = 0; ld < props.layerlist.length; ld++) { │ │ │ │ - var ldef = this.createElementNS("", "LAYERDEF"); │ │ │ │ - layerlst.appendChild(ldef); │ │ │ │ - │ │ │ │ - ldef.setAttribute("id", props.layerlist[ld].id); │ │ │ │ - ldef.setAttribute("visible", props.layerlist[ld].visible); │ │ │ │ - │ │ │ │ - if (typeof props.layerlist[ld].query == "object") { │ │ │ │ - var query = props.layerlist[ld].query; │ │ │ │ - │ │ │ │ - if (query.where.length < 0) { │ │ │ │ - continue; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var queryElem = null; │ │ │ │ - if (typeof query.spatialfilter == "boolean" && query.spatialfilter) { │ │ │ │ - // handle spatial filter madness │ │ │ │ - queryElem = this.createElementNS("", "SPATIALQUERY"); │ │ │ │ - } else { │ │ │ │ - queryElem = this.createElementNS("", "QUERY"); │ │ │ │ - } │ │ │ │ - │ │ │ │ - queryElem.setAttribute("where", query.where); │ │ │ │ - │ │ │ │ - if (typeof query.accuracy == "number" && query.accuracy > 0) { │ │ │ │ - queryElem.setAttribute("accuracy", query.accuracy); │ │ │ │ - } │ │ │ │ - if (typeof query.featurelimit == "number" && query.featurelimit < 2000) { │ │ │ │ - queryElem.setAttribute("featurelimit", query.featurelimit); │ │ │ │ - } │ │ │ │ - if (typeof query.subfields == "string" && query.subfields != "#ALL#") { │ │ │ │ - queryElem.setAttribute("subfields", query.subfields); │ │ │ │ - } │ │ │ │ - if (typeof query.joinexpression == "string" && query.joinexpression.length > 0) { │ │ │ │ - queryElem.setAttribute("joinexpression", query.joinexpression); │ │ │ │ - } │ │ │ │ - if (typeof query.jointables == "string" && query.jointables.length > 0) { │ │ │ │ - queryElem.setAttribute("jointables", query.jointables); │ │ │ │ + if (!area) { │ │ │ │ + // IE improperly renders sub-paths that have no area. │ │ │ │ + // Instead of checking the area of every ring, we confirm │ │ │ │ + // the ring has at least three distinct points. This does │ │ │ │ + // not catch all non-zero area cases, but it greatly improves │ │ │ │ + // interior ring digitizing and is a minor performance hit │ │ │ │ + // when rendering rings with many points. │ │ │ │ + if (!first) { │ │ │ │ + first = pathComp; │ │ │ │ + } else if (first != pathComp) { │ │ │ │ + if (!second) { │ │ │ │ + second = pathComp; │ │ │ │ + } else if (second != pathComp) { │ │ │ │ + // stop looking │ │ │ │ + area = true; │ │ │ │ } │ │ │ │ - │ │ │ │ - ldef.appendChild(queryElem); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (typeof props.layerlist[ld].renderer == "object") { │ │ │ │ - this.addRenderer(ldef, props.layerlist[ld].renderer); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else if (request.get_feature != null) { │ │ │ │ - var getElem = this.createElementNS("", "GET_FEATURES"); │ │ │ │ - getElem.setAttribute("outputmode", "newxml"); │ │ │ │ - getElem.setAttribute("checkesc", "true"); │ │ │ │ - │ │ │ │ - if (request.get_feature.geometry) { │ │ │ │ - getElem.setAttribute("geometry", request.get_feature.geometry); │ │ │ │ - } else { │ │ │ │ - getElem.setAttribute("geometry", "false"); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (request.get_feature.compact) { │ │ │ │ - getElem.setAttribute("compact", request.get_feature.compact); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (request.get_feature.featurelimit == "number") { │ │ │ │ - getElem.setAttribute("featurelimit", request.get_feature.featurelimit); │ │ │ │ - } │ │ │ │ - │ │ │ │ - getElem.setAttribute("globalenvelope", "true"); │ │ │ │ - reqElem.appendChild(getElem); │ │ │ │ - │ │ │ │ - if (request.get_feature.layer != null && request.get_feature.layer.length > 0) { │ │ │ │ - var lyrElem = this.createElementNS("", "LAYER"); │ │ │ │ - lyrElem.setAttribute("id", request.get_feature.layer); │ │ │ │ - getElem.appendChild(lyrElem); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var fquery = request.get_feature.query; │ │ │ │ - if (fquery != null) { │ │ │ │ - var qElem = null; │ │ │ │ - if (fquery.isspatial) { │ │ │ │ - qElem = this.createElementNS("", "SPATIALQUERY"); │ │ │ │ - } else { │ │ │ │ - qElem = this.createElementNS("", "QUERY"); │ │ │ │ - } │ │ │ │ - getElem.appendChild(qElem); │ │ │ │ - │ │ │ │ - if (typeof fquery.accuracy == "number") { │ │ │ │ - qElem.setAttribute("accuracy", fquery.accuracy); │ │ │ │ - } │ │ │ │ - //qElem.setAttribute("featurelimit", "5"); │ │ │ │ - │ │ │ │ - if (fquery.featurecoordsys != null) { │ │ │ │ - var fcsElem1 = this.createElementNS("", "FEATURECOORDSYS"); │ │ │ │ - │ │ │ │ - if (fquery.featurecoordsys.id == 0) { │ │ │ │ - fcsElem1.setAttribute("string", fquery.featurecoordsys.string); │ │ │ │ - } else { │ │ │ │ - fcsElem1.setAttribute("id", fquery.featurecoordsys.id); │ │ │ │ - } │ │ │ │ - qElem.appendChild(fcsElem1); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (fquery.filtercoordsys != null) { │ │ │ │ - var fcsElem2 = this.createElementNS("", "FILTERCOORDSYS"); │ │ │ │ - │ │ │ │ - if (fquery.filtercoordsys.id === 0) { │ │ │ │ - fcsElem2.setAttribute("string", fquery.filtercoordsys.string); │ │ │ │ - } else { │ │ │ │ - fcsElem2.setAttribute("id", fquery.filtercoordsys.id); │ │ │ │ - } │ │ │ │ - qElem.appendChild(fcsElem2); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (fquery.buffer > 0) { │ │ │ │ - var bufElem = this.createElementNS("", "BUFFER"); │ │ │ │ - bufElem.setAttribute("distance", fquery.buffer); │ │ │ │ - qElem.appendChild(bufElem); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (fquery.isspatial) { │ │ │ │ - var spfElem = this.createElementNS("", "SPATIALFILTER"); │ │ │ │ - spfElem.setAttribute("relation", fquery.spatialfilter.relation); │ │ │ │ - qElem.appendChild(spfElem); │ │ │ │ - │ │ │ │ - if (fquery.spatialfilter.envelope) { │ │ │ │ - var envElem = this.createElementNS("", "ENVELOPE"); │ │ │ │ - envElem.setAttribute("minx", fquery.spatialfilter.envelope.minx); │ │ │ │ - envElem.setAttribute("miny", fquery.spatialfilter.envelope.miny); │ │ │ │ - envElem.setAttribute("maxx", fquery.spatialfilter.envelope.maxx); │ │ │ │ - envElem.setAttribute("maxy", fquery.spatialfilter.envelope.maxy); │ │ │ │ - spfElem.appendChild(envElem); │ │ │ │ - } else if (typeof fquery.spatialfilter.polygon == "object") { │ │ │ │ - spfElem.appendChild(this.writePolygonGeometry(fquery.spatialfilter.polygon)); │ │ │ │ } │ │ │ │ } │ │ │ │ - │ │ │ │ - if (fquery.where != null && fquery.where.length > 0) { │ │ │ │ - qElem.setAttribute("where", fquery.where); │ │ │ │ - } │ │ │ │ } │ │ │ │ + path.push(area ? " x " : " "); │ │ │ │ } │ │ │ │ - │ │ │ │ - root.appendChild(reqElem); │ │ │ │ - │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [root]); │ │ │ │ + path.push("e"); │ │ │ │ + node.path = path.join(""); │ │ │ │ + return node; │ │ │ │ }, │ │ │ │ │ │ │ │ + /** │ │ │ │ + * Method: drawRectangle │ │ │ │ + * Render a rectangle │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + drawRectangle: function(node, geometry) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ │ │ │ │ - addGroupRenderer: function(ldef, toprenderer) { │ │ │ │ - var topRelem = this.createElementNS("", "GROUPRENDERER"); │ │ │ │ - ldef.appendChild(topRelem); │ │ │ │ + node.style.left = (((geometry.x - this.featureDx) / resolution - this.offset.x) | 0) + "px"; │ │ │ │ + node.style.top = ((geometry.y / resolution - this.offset.y) | 0) + "px"; │ │ │ │ + node.style.width = ((geometry.width / resolution) | 0) + "px"; │ │ │ │ + node.style.height = ((geometry.height / resolution) | 0) + "px"; │ │ │ │ │ │ │ │ - for (var rind = 0; rind < toprenderer.length; rind++) { │ │ │ │ - var renderer = toprenderer[rind]; │ │ │ │ - this.addRenderer(topRelem, renderer); │ │ │ │ - } │ │ │ │ + return node; │ │ │ │ }, │ │ │ │ │ │ │ │ + /** │ │ │ │ + * 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 label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect"); │ │ │ │ + var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox"); │ │ │ │ │ │ │ │ - addRenderer: function(topRelem, renderer) { │ │ │ │ - if (OpenLayers.Util.isArray(renderer)) { │ │ │ │ - this.addGroupRenderer(topRelem, renderer); │ │ │ │ - } else { │ │ │ │ - var renderElem = this.createElementNS("", renderer.type.toUpperCase() + "RENDERER"); │ │ │ │ - topRelem.appendChild(renderElem); │ │ │ │ - │ │ │ │ - if (renderElem.tagName == "VALUEMAPRENDERER") { │ │ │ │ - this.addValueMapRenderer(renderElem, renderer); │ │ │ │ - } else if (renderElem.tagName == "VALUEMAPLABELRENDERER") { │ │ │ │ - this.addValueMapLabelRenderer(renderElem, renderer); │ │ │ │ - } else if (renderElem.tagName == "SIMPLELABELRENDERER") { │ │ │ │ - this.addSimpleLabelRenderer(renderElem, renderer); │ │ │ │ - } else if (renderElem.tagName == "SCALEDEPENDENTRENDERER") { │ │ │ │ - this.addScaleDependentRenderer(renderElem, renderer); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + label.style.left = (((location.x - this.featureDx) / resolution - this.offset.x) | 0) + "px"; │ │ │ │ + label.style.top = ((location.y / resolution - this.offset.y) | 0) + "px"; │ │ │ │ + label.style.flip = "y"; │ │ │ │ │ │ │ │ + textbox.innerText = style.label; │ │ │ │ │ │ │ │ - addScaleDependentRenderer: function(renderElem, renderer) { │ │ │ │ - if (typeof renderer.lower == "string" || typeof renderer.lower == "number") { │ │ │ │ - renderElem.setAttribute("lower", renderer.lower); │ │ │ │ + if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ + textbox.style.cursor = style.cursor; │ │ │ │ } │ │ │ │ - if (typeof renderer.upper == "string" || typeof renderer.upper == "number") { │ │ │ │ - renderElem.setAttribute("upper", renderer.upper); │ │ │ │ + if (style.fontColor) { │ │ │ │ + textbox.style.color = style.fontColor; │ │ │ │ } │ │ │ │ - │ │ │ │ - this.addRenderer(renderElem, renderer.renderer); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - addValueMapLabelRenderer: function(renderElem, renderer) { │ │ │ │ - renderElem.setAttribute("lookupfield", renderer.lookupfield); │ │ │ │ - renderElem.setAttribute("labelfield", renderer.labelfield); │ │ │ │ - │ │ │ │ - if (typeof renderer.exacts == "object") { │ │ │ │ - for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) { │ │ │ │ - var exact = renderer.exacts[ext]; │ │ │ │ - │ │ │ │ - var eelem = this.createElementNS("", "EXACT"); │ │ │ │ - │ │ │ │ - if (typeof exact.value == "string") { │ │ │ │ - eelem.setAttribute("value", exact.value); │ │ │ │ - } │ │ │ │ - if (typeof exact.label == "string") { │ │ │ │ - eelem.setAttribute("label", exact.label); │ │ │ │ - } │ │ │ │ - if (typeof exact.method == "string") { │ │ │ │ - eelem.setAttribute("method", exact.method); │ │ │ │ - } │ │ │ │ - │ │ │ │ - renderElem.appendChild(eelem); │ │ │ │ - │ │ │ │ - if (typeof exact.symbol == "object") { │ │ │ │ - var selem = null; │ │ │ │ - │ │ │ │ - if (exact.symbol.type == "text") { │ │ │ │ - selem = this.createElementNS("", "TEXTSYMBOL"); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (selem != null) { │ │ │ │ - var keys = this.fontStyleKeys; │ │ │ │ - for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ - var key = keys[i]; │ │ │ │ - if (exact.symbol[key]) { │ │ │ │ - selem.setAttribute(key, exact.symbol[key]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - eelem.appendChild(selem); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } // for each exact │ │ │ │ + if (style.fontOpacity) { │ │ │ │ + textbox.style.filter = 'alpha(opacity=' + (style.fontOpacity * 100) + ')'; │ │ │ │ } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - addValueMapRenderer: function(renderElem, renderer) { │ │ │ │ - renderElem.setAttribute("lookupfield", renderer.lookupfield); │ │ │ │ - │ │ │ │ - if (typeof renderer.ranges == "object") { │ │ │ │ - for (var rng = 0, rnglen = renderer.ranges.length; rng < rnglen; rng++) { │ │ │ │ - var range = renderer.ranges[rng]; │ │ │ │ - │ │ │ │ - var relem = this.createElementNS("", "RANGE"); │ │ │ │ - relem.setAttribute("lower", range.lower); │ │ │ │ - relem.setAttribute("upper", range.upper); │ │ │ │ - │ │ │ │ - renderElem.appendChild(relem); │ │ │ │ - │ │ │ │ - if (typeof range.symbol == "object") { │ │ │ │ - var selem = null; │ │ │ │ - │ │ │ │ - if (range.symbol.type == "simplepolygon") { │ │ │ │ - selem = this.createElementNS("", "SIMPLEPOLYGONSYMBOL"); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (selem != null) { │ │ │ │ - if (typeof range.symbol.boundarycolor == "string") { │ │ │ │ - selem.setAttribute("boundarycolor", range.symbol.boundarycolor); │ │ │ │ - } │ │ │ │ - if (typeof range.symbol.fillcolor == "string") { │ │ │ │ - selem.setAttribute("fillcolor", range.symbol.fillcolor); │ │ │ │ - } │ │ │ │ - if (typeof range.symbol.filltransparency == "number") { │ │ │ │ - selem.setAttribute("filltransparency", range.symbol.filltransparency); │ │ │ │ - } │ │ │ │ - relem.appendChild(selem); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } // for each range │ │ │ │ - } else if (typeof renderer.exacts == "object") { │ │ │ │ - for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) { │ │ │ │ - var exact = renderer.exacts[ext]; │ │ │ │ - │ │ │ │ - var eelem = this.createElementNS("", "EXACT"); │ │ │ │ - if (typeof exact.value == "string") { │ │ │ │ - eelem.setAttribute("value", exact.value); │ │ │ │ - } │ │ │ │ - if (typeof exact.label == "string") { │ │ │ │ - eelem.setAttribute("label", exact.label); │ │ │ │ - } │ │ │ │ - if (typeof exact.method == "string") { │ │ │ │ - eelem.setAttribute("method", exact.method); │ │ │ │ - } │ │ │ │ - │ │ │ │ - renderElem.appendChild(eelem); │ │ │ │ - │ │ │ │ - if (typeof exact.symbol == "object") { │ │ │ │ - var selem = null; │ │ │ │ - │ │ │ │ - if (exact.symbol.type == "simplemarker") { │ │ │ │ - selem = this.createElementNS("", "SIMPLEMARKERSYMBOL"); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (selem != null) { │ │ │ │ - if (typeof exact.symbol.antialiasing == "string") { │ │ │ │ - selem.setAttribute("antialiasing", exact.symbol.antialiasing); │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.color == "string") { │ │ │ │ - selem.setAttribute("color", exact.symbol.color); │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.outline == "string") { │ │ │ │ - selem.setAttribute("outline", exact.symbol.outline); │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.overlap == "string") { │ │ │ │ - selem.setAttribute("overlap", exact.symbol.overlap); │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.shadow == "string") { │ │ │ │ - selem.setAttribute("shadow", exact.symbol.shadow); │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.transparency == "number") { │ │ │ │ - selem.setAttribute("transparency", exact.symbol.transparency); │ │ │ │ - } │ │ │ │ - //if (typeof exact.symbol.type == "string") │ │ │ │ - // selem.setAttribute("type", exact.symbol.type); │ │ │ │ - if (typeof exact.symbol.usecentroid == "string") { │ │ │ │ - selem.setAttribute("usecentroid", exact.symbol.usecentroid); │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.width == "number") { │ │ │ │ - selem.setAttribute("width", exact.symbol.width); │ │ │ │ - } │ │ │ │ - │ │ │ │ - eelem.appendChild(selem); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } // for each exact │ │ │ │ + if (style.fontFamily) { │ │ │ │ + textbox.style.fontFamily = style.fontFamily; │ │ │ │ } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - addSimpleLabelRenderer: function(renderElem, renderer) { │ │ │ │ - renderElem.setAttribute("field", renderer.field); │ │ │ │ - var keys = ['featureweight', 'howmanylabels', 'labelbufferratio', │ │ │ │ - 'labelpriorities', 'labelweight', 'linelabelposition', │ │ │ │ - 'rotationalangles' │ │ │ │ - ]; │ │ │ │ - for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ - var key = keys[i]; │ │ │ │ - if (renderer[key]) { │ │ │ │ - renderElem.setAttribute(key, renderer[key]); │ │ │ │ - } │ │ │ │ + if (style.fontSize) { │ │ │ │ + textbox.style.fontSize = style.fontSize; │ │ │ │ } │ │ │ │ - │ │ │ │ - if (renderer.symbol.type == "text") { │ │ │ │ - var symbol = renderer.symbol; │ │ │ │ - var selem = this.createElementNS("", "TEXTSYMBOL"); │ │ │ │ - renderElem.appendChild(selem); │ │ │ │ - │ │ │ │ - var keys = this.fontStyleKeys; │ │ │ │ - for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ - var key = keys[i]; │ │ │ │ - if (symbol[key]) { │ │ │ │ - selem.setAttribute(key, renderer[key]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + if (style.fontWeight) { │ │ │ │ + textbox.style.fontWeight = style.fontWeight; │ │ │ │ } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - writePolygonGeometry: function(polygon) { │ │ │ │ - if (!(polygon instanceof OpenLayers.Geometry.Polygon)) { │ │ │ │ - throw { │ │ │ │ - message: 'Cannot write polygon geometry to ArcXML with an ' + │ │ │ │ - polygon.CLASS_NAME + ' object.', │ │ │ │ - geometry: polygon │ │ │ │ - }; │ │ │ │ + if (style.fontStyle) { │ │ │ │ + textbox.style.fontStyle = style.fontStyle; │ │ │ │ } │ │ │ │ - │ │ │ │ - var polyElem = this.createElementNS("", "POLYGON"); │ │ │ │ - │ │ │ │ - for (var ln = 0, lnlen = polygon.components.length; ln < lnlen; ln++) { │ │ │ │ - var ring = polygon.components[ln]; │ │ │ │ - var ringElem = this.createElementNS("", "RING"); │ │ │ │ - │ │ │ │ - for (var rn = 0, rnlen = ring.components.length; rn < rnlen; rn++) { │ │ │ │ - var point = ring.components[rn]; │ │ │ │ - var pointElem = this.createElementNS("", "POINT"); │ │ │ │ - │ │ │ │ - pointElem.setAttribute("x", point.x); │ │ │ │ - pointElem.setAttribute("y", point.y); │ │ │ │ - │ │ │ │ - ringElem.appendChild(pointElem); │ │ │ │ - } │ │ │ │ - │ │ │ │ - polyElem.appendChild(ringElem); │ │ │ │ + if (style.labelSelect === true) { │ │ │ │ + label._featureId = featureId; │ │ │ │ + textbox._featureId = featureId; │ │ │ │ + textbox._geometry = location; │ │ │ │ + textbox._geometryClass = location.CLASS_NAME; │ │ │ │ } │ │ │ │ + textbox.style.whiteSpace = "nowrap"; │ │ │ │ + // fun with IE: IE7 in standards compliant mode does not display any │ │ │ │ + // text with a left inset of 0. So we set this to 1px and subtract one │ │ │ │ + // pixel later when we set label.style.left │ │ │ │ + textbox.inset = "1px,0px,0px,0px"; │ │ │ │ │ │ │ │ - return polyElem; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: parseResponse │ │ │ │ - * Take an ArcXML response, and parse in into this object's internal properties. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} The ArcXML response, as either a string or the │ │ │ │ - * top level DOMElement of the response. │ │ │ │ - */ │ │ │ │ - parseResponse: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - var newData = new OpenLayers.Format.XML(); │ │ │ │ - data = newData.read(data); │ │ │ │ + if (!label.parentNode) { │ │ │ │ + label.appendChild(textbox); │ │ │ │ + this.textRoot.appendChild(label); │ │ │ │ } │ │ │ │ - var response = new OpenLayers.Format.ArcXML.Response(); │ │ │ │ - │ │ │ │ - var errorNode = data.getElementsByTagName("ERROR"); │ │ │ │ - │ │ │ │ - if (errorNode != null && errorNode.length > 0) { │ │ │ │ - response.error = this.getChildValue(errorNode, "Unknown error."); │ │ │ │ - } else { │ │ │ │ - var responseNode = data.getElementsByTagName("RESPONSE"); │ │ │ │ - │ │ │ │ - if (responseNode == null || responseNode.length == 0) { │ │ │ │ - response.error = "No RESPONSE tag found in ArcXML response."; │ │ │ │ - return response; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var rtype = responseNode[0].firstChild.nodeName; │ │ │ │ - if (rtype == "#text") { │ │ │ │ - rtype = responseNode[0].firstChild.nextSibling.nodeName; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (rtype == "IMAGE") { │ │ │ │ - var envelopeNode = data.getElementsByTagName("ENVELOPE"); │ │ │ │ - var outputNode = data.getElementsByTagName("OUTPUT"); │ │ │ │ - │ │ │ │ - if (envelopeNode == null || envelopeNode.length == 0) { │ │ │ │ - response.error = "No ENVELOPE tag found in ArcXML response."; │ │ │ │ - } else if (outputNode == null || outputNode.length == 0) { │ │ │ │ - response.error = "No OUTPUT tag found in ArcXML response."; │ │ │ │ - } else { │ │ │ │ - var envAttr = this.parseAttributes(envelopeNode[0]); │ │ │ │ - var outputAttr = this.parseAttributes(outputNode[0]); │ │ │ │ - │ │ │ │ - if (typeof outputAttr.type == "string") { │ │ │ │ - response.image = { │ │ │ │ - envelope: envAttr, │ │ │ │ - output: { │ │ │ │ - type: outputAttr.type, │ │ │ │ - data: this.getChildValue(outputNode[0]) │ │ │ │ - } │ │ │ │ - }; │ │ │ │ - } else { │ │ │ │ - response.image = { │ │ │ │ - envelope: envAttr, │ │ │ │ - output: outputAttr │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else if (rtype == "FEATURES") { │ │ │ │ - var features = responseNode[0].getElementsByTagName("FEATURES"); │ │ │ │ - │ │ │ │ - // get the feature count │ │ │ │ - var featureCount = features[0].getElementsByTagName("FEATURECOUNT"); │ │ │ │ - response.features.featurecount = featureCount[0].getAttribute("count"); │ │ │ │ - │ │ │ │ - if (response.features.featurecount > 0) { │ │ │ │ - // get the feature envelope │ │ │ │ - var envelope = features[0].getElementsByTagName("ENVELOPE"); │ │ │ │ - response.features.envelope = this.parseAttributes(envelope[0], typeof(0)); │ │ │ │ - │ │ │ │ - // get the field values per feature │ │ │ │ - var featureList = features[0].getElementsByTagName("FEATURE"); │ │ │ │ - for (var fn = 0; fn < featureList.length; fn++) { │ │ │ │ - var feature = new OpenLayers.Feature.Vector(); │ │ │ │ - var fields = featureList[fn].getElementsByTagName("FIELD"); │ │ │ │ - │ │ │ │ - for (var fdn = 0; fdn < fields.length; fdn++) { │ │ │ │ - var fieldName = fields[fdn].getAttribute("name"); │ │ │ │ - var fieldValue = fields[fdn].getAttribute("value"); │ │ │ │ - feature.attributes[fieldName] = fieldValue; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var geom = featureList[fn].getElementsByTagName("POLYGON"); │ │ │ │ - │ │ │ │ - if (geom.length > 0) { │ │ │ │ - // if there is a polygon, create an openlayers polygon, and assign │ │ │ │ - // it to the .geometry property of the feature │ │ │ │ - var ring = geom[0].getElementsByTagName("RING"); │ │ │ │ - │ │ │ │ - var polys = []; │ │ │ │ - for (var rn = 0; rn < ring.length; rn++) { │ │ │ │ - var linearRings = []; │ │ │ │ - linearRings.push(this.parsePointGeometry(ring[rn])); │ │ │ │ - │ │ │ │ - var holes = ring[rn].getElementsByTagName("HOLE"); │ │ │ │ - for (var hn = 0; hn < holes.length; hn++) { │ │ │ │ - linearRings.push(this.parsePointGeometry(holes[hn])); │ │ │ │ - } │ │ │ │ - holes = null; │ │ │ │ - polys.push(new OpenLayers.Geometry.Polygon(linearRings)); │ │ │ │ - linearRings = null; │ │ │ │ - } │ │ │ │ - ring = null; │ │ │ │ - │ │ │ │ - if (polys.length == 1) { │ │ │ │ - feature.geometry = polys[0]; │ │ │ │ - } else { │ │ │ │ - feature.geometry = new OpenLayers.Geometry.MultiPolygon(polys); │ │ │ │ - } │ │ │ │ - } │ │ │ │ │ │ │ │ - response.features.feature.push(feature); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - response.error = "Unidentified response type."; │ │ │ │ - } │ │ │ │ + var align = style.labelAlign || "cm"; │ │ │ │ + if (align.length == 1) { │ │ │ │ + align += "m"; │ │ │ │ } │ │ │ │ - return response; │ │ │ │ - }, │ │ │ │ + var xshift = textbox.clientWidth * │ │ │ │ + (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0, 1)]); │ │ │ │ + var yshift = textbox.clientHeight * │ │ │ │ + (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1, 1)]); │ │ │ │ + label.style.left = parseInt(label.style.left) - xshift - 1 + "px"; │ │ │ │ + label.style.top = parseInt(label.style.top) + yshift + "px"; │ │ │ │ │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseAttributes │ │ │ │ - * │ │ │ │ + * Method: moveRoot │ │ │ │ + * moves this renderer's root to a different renderer. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * node - {<DOMElement>} An element to parse attributes from. │ │ │ │ - * │ │ │ │ + * renderer - {<OpenLayers.Renderer>} target renderer for the moved root │ │ │ │ + * root - {DOMElement} optional root node. To be used when this renderer │ │ │ │ + * holds roots from multiple layers to tell this method which one to │ │ │ │ + * detach │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} An attributes object, with properties set to attribute values. │ │ │ │ + * {Boolean} true if successful, false otherwise │ │ │ │ */ │ │ │ │ - parseAttributes: function(node, type) { │ │ │ │ - var attributes = {}; │ │ │ │ - for (var attr = 0; attr < node.attributes.length; attr++) { │ │ │ │ - if (type == "number") { │ │ │ │ - attributes[node.attributes[attr].nodeName] = parseFloat(node.attributes[attr].nodeValue); │ │ │ │ - } else { │ │ │ │ - attributes[node.attributes[attr].nodeName] = node.attributes[attr].nodeValue; │ │ │ │ - } │ │ │ │ + moveRoot: function(renderer) { │ │ │ │ + var layer = this.map.getLayer(renderer.container.id); │ │ │ │ + if (layer instanceof OpenLayers.Layer.Vector.RootContainer) { │ │ │ │ + layer = this.map.getLayer(this.container.id); │ │ │ │ } │ │ │ │ - return attributes; │ │ │ │ + layer && layer.renderer.clear(); │ │ │ │ + OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments); │ │ │ │ + layer && layer.redraw(); │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: parsePointGeometry │ │ │ │ - * │ │ │ │ + * Method: importSymbol │ │ │ │ + * add a new symbol definition from the rendererer's symbol hash │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * node - {<DOMElement>} An element to parse <COORDS> or <POINT> arcxml data from. │ │ │ │ - * │ │ │ │ + * graphicName - {String} name of the symbol to import │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Geometry.LinearRing>} A linear ring represented by the node's points. │ │ │ │ + * {Object} - hash of {DOMElement} "symbol" and {Number} "size" │ │ │ │ */ │ │ │ │ - parsePointGeometry: function(node) { │ │ │ │ - var ringPoints = []; │ │ │ │ - var coords = node.getElementsByTagName("COORDS"); │ │ │ │ + importSymbol: function(graphicName) { │ │ │ │ + var id = this.container.id + "-" + graphicName; │ │ │ │ │ │ │ │ - if (coords.length > 0) { │ │ │ │ - // if coords is present, it's the only coords item │ │ │ │ - var coordArr = this.getChildValue(coords[0]); │ │ │ │ - coordArr = coordArr.split(/;/); │ │ │ │ - for (var cn = 0; cn < coordArr.length; cn++) { │ │ │ │ - var coordItems = coordArr[cn].split(/ /); │ │ │ │ - ringPoints.push(new OpenLayers.Geometry.Point(coordItems[0], coordItems[1])); │ │ │ │ - } │ │ │ │ - coords = null; │ │ │ │ - } else { │ │ │ │ - var point = node.getElementsByTagName("POINT"); │ │ │ │ - if (point.length > 0) { │ │ │ │ - for (var pn = 0; pn < point.length; pn++) { │ │ │ │ - ringPoints.push( │ │ │ │ - new OpenLayers.Geometry.Point( │ │ │ │ - parseFloat(point[pn].getAttribute("x")), │ │ │ │ - parseFloat(point[pn].getAttribute("y")) │ │ │ │ - ) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - point = null; │ │ │ │ + // check if symbol already exists in the cache │ │ │ │ + var cache = this.symbolCache[id]; │ │ │ │ + if (cache) { │ │ │ │ + return cache; │ │ │ │ } │ │ │ │ │ │ │ │ - return new OpenLayers.Geometry.LinearRing(ringPoints); │ │ │ │ - }, │ │ │ │ + var symbol = OpenLayers.Renderer.symbol[graphicName]; │ │ │ │ + if (!symbol) { │ │ │ │ + throw new Error(graphicName + ' is not a valid symbol name'); │ │ │ │ + } │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.ArcXML" │ │ │ │ -}); │ │ │ │ + var symbolExtent = new OpenLayers.Bounds( │ │ │ │ + Number.MAX_VALUE, Number.MAX_VALUE, 0, 0); │ │ │ │ │ │ │ │ -OpenLayers.Format.ArcXML.Request = OpenLayers.Class({ │ │ │ │ - initialize: function(params) { │ │ │ │ - var defaults = { │ │ │ │ - get_image: { │ │ │ │ - properties: { │ │ │ │ - background: null, │ │ │ │ - /*{ │ │ │ │ - color: { r:255, g:255, b:255 }, │ │ │ │ - transcolor: null │ │ │ │ - },*/ │ │ │ │ - draw: true, │ │ │ │ - envelope: { │ │ │ │ - minx: 0, │ │ │ │ - miny: 0, │ │ │ │ - maxx: 0, │ │ │ │ - maxy: 0 │ │ │ │ - }, │ │ │ │ - featurecoordsys: { │ │ │ │ - id: 0, │ │ │ │ - string: "", │ │ │ │ - datumtransformid: 0, │ │ │ │ - datumtransformstring: "" │ │ │ │ - }, │ │ │ │ - filtercoordsys: { │ │ │ │ - id: 0, │ │ │ │ - string: "", │ │ │ │ - datumtransformid: 0, │ │ │ │ - datumtransformstring: "" │ │ │ │ - }, │ │ │ │ - imagesize: { │ │ │ │ - height: 0, │ │ │ │ - width: 0, │ │ │ │ - dpi: 96, │ │ │ │ - printheight: 0, │ │ │ │ - printwidth: 0, │ │ │ │ - scalesymbols: false │ │ │ │ - }, │ │ │ │ - layerlist: [], │ │ │ │ - /* no support for legends */ │ │ │ │ - output: { │ │ │ │ - baseurl: "", │ │ │ │ - legendbaseurl: "", │ │ │ │ - legendname: "", │ │ │ │ - legendpath: "", │ │ │ │ - legendurl: "", │ │ │ │ - name: "", │ │ │ │ - path: "", │ │ │ │ - type: "jpg", │ │ │ │ - url: "" │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + var pathitems = ["m"]; │ │ │ │ + for (var i = 0; i < symbol.length; i = i + 2) { │ │ │ │ + var x = symbol[i]; │ │ │ │ + var 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); │ │ │ │ │ │ │ │ - get_feature: { │ │ │ │ - layer: "", │ │ │ │ - query: { │ │ │ │ - isspatial: false, │ │ │ │ - featurecoordsys: { │ │ │ │ - id: 0, │ │ │ │ - string: "", │ │ │ │ - datumtransformid: 0, │ │ │ │ - datumtransformstring: "" │ │ │ │ - }, │ │ │ │ - filtercoordsys: { │ │ │ │ - id: 0, │ │ │ │ - string: "", │ │ │ │ - datumtransformid: 0, │ │ │ │ - datumtransformstring: "" │ │ │ │ - }, │ │ │ │ - buffer: 0, │ │ │ │ - where: "", │ │ │ │ - spatialfilter: { │ │ │ │ - relation: "envelope_intersection", │ │ │ │ - envelope: null │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + pathitems.push(x); │ │ │ │ + pathitems.push(y); │ │ │ │ + if (i == 0) { │ │ │ │ + pathitems.push("l"); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + pathitems.push("x e"); │ │ │ │ + var path = pathitems.join(" "); │ │ │ │ │ │ │ │ - environment: { │ │ │ │ - separators: { │ │ │ │ - cs: " ", │ │ │ │ - ts: ";" │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2; │ │ │ │ + if (diff > 0) { │ │ │ │ + symbolExtent.bottom = symbolExtent.bottom - diff; │ │ │ │ + symbolExtent.top = symbolExtent.top + diff; │ │ │ │ + } else { │ │ │ │ + symbolExtent.left = symbolExtent.left + diff; │ │ │ │ + symbolExtent.right = symbolExtent.right - diff; │ │ │ │ + } │ │ │ │ │ │ │ │ - layer: [], │ │ │ │ - workspaces: [] │ │ │ │ + cache = { │ │ │ │ + path: path, │ │ │ │ + size: symbolExtent.getWidth(), // equals getHeight() now │ │ │ │ + left: symbolExtent.left, │ │ │ │ + bottom: symbolExtent.bottom │ │ │ │ }; │ │ │ │ + this.symbolCache[id] = cache; │ │ │ │ │ │ │ │ - return OpenLayers.Util.extend(this, defaults); │ │ │ │ + return cache; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.ArcXML.Request" │ │ │ │ + CLASS_NAME: "OpenLayers.Renderer.VML" │ │ │ │ }); │ │ │ │ │ │ │ │ -OpenLayers.Format.ArcXML.Response = OpenLayers.Class({ │ │ │ │ - initialize: function(params) { │ │ │ │ - var defaults = { │ │ │ │ - image: { │ │ │ │ - envelope: null, │ │ │ │ - output: '' │ │ │ │ - }, │ │ │ │ - │ │ │ │ - features: { │ │ │ │ - featurecount: 0, │ │ │ │ - envelope: null, │ │ │ │ - feature: [] │ │ │ │ - }, │ │ │ │ - │ │ │ │ - error: '' │ │ │ │ - }; │ │ │ │ - │ │ │ │ - return OpenLayers.Util.extend(this, defaults); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.ArcXML.Response" │ │ │ │ -}); │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Renderer.VML.LABEL_SHIFT │ │ │ │ + * {Object} │ │ │ │ + */ │ │ │ │ +OpenLayers.Renderer.VML.LABEL_SHIFT = { │ │ │ │ + "l": 0, │ │ │ │ + "c": .5, │ │ │ │ + "r": 1, │ │ │ │ + "t": 0, │ │ │ │ + "m": .5, │ │ │ │ + "b": 1 │ │ │ │ +}; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/ArcIMS.js │ │ │ │ + OpenLayers/Strategy/Cluster.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 │ │ │ │ - * @requires OpenLayers/Format/ArcXML.js │ │ │ │ - * @requires OpenLayers/Request.js │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.ArcIMS │ │ │ │ - * Instances of OpenLayers.Layer.ArcIMS are used to display data from ESRI ArcIMS │ │ │ │ - * Mapping Services. Create a new ArcIMS layer with the <OpenLayers.Layer.ArcIMS> │ │ │ │ - * constructor. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Strategy.Cluster │ │ │ │ + * Strategy for vector feature clustering. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * - <OpenLayers.Strategy> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.ArcIMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ +OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: DEFAULT_PARAMS │ │ │ │ - * {Object} Default query string parameters. │ │ │ │ + * APIProperty: distance │ │ │ │ + * {Integer} Pixel distance between features that should be considered a │ │ │ │ + * single cluster. Default is 20 pixels. │ │ │ │ */ │ │ │ │ - DEFAULT_PARAMS: { │ │ │ │ - ClientVersion: "9.2", │ │ │ │ - ServiceName: '' │ │ │ │ - }, │ │ │ │ + distance: 20, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: featureCoordSys │ │ │ │ - * {String} Code for feature coordinate system. Default is "4326". │ │ │ │ + * APIProperty: threshold │ │ │ │ + * {Integer} Optional threshold below which original features will be │ │ │ │ + * added to the layer instead of clusters. For example, a threshold │ │ │ │ + * of 3 would mean that any time there are 2 or fewer features in │ │ │ │ + * a cluster, those features will be added directly to the layer instead │ │ │ │ + * of a cluster representing those features. Default is null (which is │ │ │ │ + * equivalent to 1 - meaning that clusters may contain just one feature). │ │ │ │ */ │ │ │ │ - featureCoordSys: "4326", │ │ │ │ + threshold: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: filterCoordSys │ │ │ │ - * {String} Code for filter coordinate system. Default is "4326". │ │ │ │ + * Property: features │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} Cached features. │ │ │ │ */ │ │ │ │ - filterCoordSys: "4326", │ │ │ │ + features: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layers │ │ │ │ - * {Array} An array of objects with layer properties. │ │ │ │ + * Property: clusters │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} Calculated clusters. │ │ │ │ */ │ │ │ │ - layers: null, │ │ │ │ + clusters: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: async │ │ │ │ - * {Boolean} Request images asynchronously. Default is true. │ │ │ │ + * Property: clustering │ │ │ │ + * {Boolean} The strategy is currently clustering features. │ │ │ │ */ │ │ │ │ - async: true, │ │ │ │ + clustering: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: name │ │ │ │ - * {String} Layer name. Default is "ArcIMS". │ │ │ │ + * Property: resolution │ │ │ │ + * {Float} The resolution (map units per pixel) of the current cluster set. │ │ │ │ */ │ │ │ │ - name: "ArcIMS", │ │ │ │ + resolution: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} The layer is a base layer. Default is true. │ │ │ │ + * Constructor: OpenLayers.Strategy.Cluster │ │ │ │ + * Create a new clustering strategy. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - isBaseLayer: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: DEFAULT_OPTIONS │ │ │ │ - * {Object} Default layers properties. │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The strategy was successfully activated. │ │ │ │ */ │ │ │ │ - DEFAULT_OPTIONS: { │ │ │ │ - tileSize: new OpenLayers.Size(512, 512), │ │ │ │ - featureCoordSys: "4326", │ │ │ │ - filterCoordSys: "4326", │ │ │ │ - layers: null, │ │ │ │ - isBaseLayer: true, │ │ │ │ - async: true, │ │ │ │ - name: "ArcIMS" │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + "beforefeaturesadded": this.cacheFeatures, │ │ │ │ + "featuresremoved": this.clearCache, │ │ │ │ + "moveend": this.cluster, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.ArcIMS │ │ │ │ - * Create a new ArcIMS layer object. │ │ │ │ - * │ │ │ │ - * Example: │ │ │ │ - * (code) │ │ │ │ - * var arcims = new OpenLayers.Layer.ArcIMS( │ │ │ │ - * "Global Sample", │ │ │ │ - * "http://sample.avencia.com/servlet/com.esri.esrimap.Esrimap", │ │ │ │ - * { │ │ │ │ - * service: "OpenLayers_Sample", │ │ │ │ - * layers: [ │ │ │ │ - * // layers to manipulate │ │ │ │ - * {id: "1", visible: true} │ │ │ │ - * ] │ │ │ │ - * } │ │ │ │ - * ); │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} A name for the layer │ │ │ │ - * url - {String} Base url for the ArcIMS server │ │ │ │ - * options - {Object} Optional object with properties to be set on the │ │ │ │ - * layer. │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ + * tear-down. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ */ │ │ │ │ - initialize: function(name, url, options) { │ │ │ │ - │ │ │ │ - this.tileSize = new OpenLayers.Size(512, 512); │ │ │ │ - │ │ │ │ - // parameters │ │ │ │ - this.params = OpenLayers.Util.applyDefaults({ │ │ │ │ - ServiceName: options.serviceName │ │ │ │ - }, │ │ │ │ - this.DEFAULT_PARAMS │ │ │ │ - ); │ │ │ │ - this.options = OpenLayers.Util.applyDefaults( │ │ │ │ - options, this.DEFAULT_OPTIONS │ │ │ │ - ); │ │ │ │ - │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply( │ │ │ │ - this, [name, url, this.params, options] │ │ │ │ - ); │ │ │ │ - │ │ │ │ - //layer is transparent │ │ │ │ - if (this.transparent) { │ │ │ │ - │ │ │ │ - // unless explicitly set in options, make layer an overlay │ │ │ │ - if (!this.isBaseLayer) { │ │ │ │ - this.isBaseLayer = false; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // jpegs can never be transparent, so intelligently switch the │ │ │ │ - // format, depending on the browser's capabilities │ │ │ │ - if (this.format == "image/jpeg") { │ │ │ │ - this.format = OpenLayers.Util.alphaHack() ? "image/gif" : "image/png"; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // create an empty layer list if no layers specified in the options │ │ │ │ - if (this.options.layers === null) { │ │ │ │ - this.options.layers = []; │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.clearCache(); │ │ │ │ + this.layer.events.un({ │ │ │ │ + "beforefeaturesadded": this.cacheFeatures, │ │ │ │ + "featuresremoved": this.clearCache, │ │ │ │ + "moveend": this.cluster, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ } │ │ │ │ + return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getURL │ │ │ │ - * Return an image url this layer. │ │ │ │ + * Method: cacheFeatures │ │ │ │ + * Cache features before they are added to the layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the │ │ │ │ - * request. │ │ │ │ - * │ │ │ │ + * event - {Object} The event that this was listening for. This will come │ │ │ │ + * with a batch of features to be clustered. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {String} A string with the map image's url. │ │ │ │ + * {Boolean} False to stop features from being added to the layer. │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - var url = ""; │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - │ │ │ │ - // create an arcxml request to generate the image │ │ │ │ - var axlReq = new OpenLayers.Format.ArcXML( │ │ │ │ - OpenLayers.Util.extend(this.options, { │ │ │ │ - requesttype: "image", │ │ │ │ - envelope: bounds.toArray(), │ │ │ │ - tileSize: this.tileSize │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - │ │ │ │ - // create a synchronous ajax request to get an arcims image │ │ │ │ - var req = new OpenLayers.Request.POST({ │ │ │ │ - url: this.getFullRequestString(), │ │ │ │ - data: axlReq.write(), │ │ │ │ - async: false │ │ │ │ - }); │ │ │ │ - │ │ │ │ - // if the response exists │ │ │ │ - if (req != null) { │ │ │ │ - var doc = req.responseXML; │ │ │ │ - │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = req.responseText; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // create a new arcxml format to read the response │ │ │ │ - var axlResp = new OpenLayers.Format.ArcXML(); │ │ │ │ - var arcxml = axlResp.read(doc); │ │ │ │ - url = this.getUrlOrImage(arcxml.image.output); │ │ │ │ + cacheFeatures: function(event) { │ │ │ │ + var propagate = true; │ │ │ │ + if (!this.clustering) { │ │ │ │ + this.clearCache(); │ │ │ │ + this.features = event.features; │ │ │ │ + this.cluster(); │ │ │ │ + propagate = false; │ │ │ │ } │ │ │ │ - │ │ │ │ - return url; │ │ │ │ + return propagate; │ │ │ │ }, │ │ │ │ │ │ │ │ + /** │ │ │ │ + * Method: clearCache │ │ │ │ + * Clear out the cached features. │ │ │ │ + */ │ │ │ │ + clearCache: function() { │ │ │ │ + if (!this.clustering) { │ │ │ │ + this.features = null; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getURLasync │ │ │ │ - * Get an image url this layer asynchronously, and execute a callback │ │ │ │ - * when the image url is generated. │ │ │ │ + * Method: cluster │ │ │ │ + * Cluster features based on some threshold distance. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the │ │ │ │ - * request. │ │ │ │ - * callback - {Function} Function to call when image url is retrieved. │ │ │ │ - * scope - {Object} The scope of the callback method. │ │ │ │ + * event - {Object} The event received when cluster is called as a │ │ │ │ + * result of a moveend event. │ │ │ │ */ │ │ │ │ - getURLasync: function(bounds, callback, scope) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - │ │ │ │ - // create an arcxml request to generate the image │ │ │ │ - var axlReq = new OpenLayers.Format.ArcXML( │ │ │ │ - OpenLayers.Util.extend(this.options, { │ │ │ │ - requesttype: "image", │ │ │ │ - envelope: bounds.toArray(), │ │ │ │ - tileSize: this.tileSize │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - │ │ │ │ - // create an asynchronous ajax request to get an arcims image │ │ │ │ - OpenLayers.Request.POST({ │ │ │ │ - url: this.getFullRequestString(), │ │ │ │ - async: true, │ │ │ │ - data: axlReq.write(), │ │ │ │ - callback: function(req) { │ │ │ │ - // process the response from ArcIMS, and call the callback function │ │ │ │ - // to set the image URL │ │ │ │ - var doc = req.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = req.responseText; │ │ │ │ + cluster: function(event) { │ │ │ │ + if ((!event || event.zoomChanged) && this.features) { │ │ │ │ + var resolution = this.layer.map.getResolution(); │ │ │ │ + if (resolution != this.resolution || !this.clustersExist()) { │ │ │ │ + this.resolution = resolution; │ │ │ │ + var clusters = []; │ │ │ │ + var feature, clustered, cluster; │ │ │ │ + for (var i = 0; i < this.features.length; ++i) { │ │ │ │ + feature = this.features[i]; │ │ │ │ + if (feature.geometry) { │ │ │ │ + clustered = false; │ │ │ │ + for (var j = clusters.length - 1; j >= 0; --j) { │ │ │ │ + cluster = clusters[j]; │ │ │ │ + if (this.shouldCluster(cluster, feature)) { │ │ │ │ + this.addToCluster(cluster, feature); │ │ │ │ + clustered = true; │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (!clustered) { │ │ │ │ + clusters.push(this.createCluster(this.features[i])); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - │ │ │ │ - // create a new arcxml format to read the response │ │ │ │ - var axlResp = new OpenLayers.Format.ArcXML(); │ │ │ │ - var arcxml = axlResp.read(doc); │ │ │ │ - │ │ │ │ - callback.call(scope, this.getUrlOrImage(arcxml.image.output)); │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ + this.clustering = true; │ │ │ │ + this.layer.removeAllFeatures(); │ │ │ │ + this.clustering = false; │ │ │ │ + if (clusters.length > 0) { │ │ │ │ + if (this.threshold > 1) { │ │ │ │ + var clone = clusters.slice(); │ │ │ │ + clusters = []; │ │ │ │ + var candidate; │ │ │ │ + for (var i = 0, len = clone.length; i < len; ++i) { │ │ │ │ + candidate = clone[i]; │ │ │ │ + if (candidate.attributes.count < this.threshold) { │ │ │ │ + Array.prototype.push.apply(clusters, candidate.cluster); │ │ │ │ + } else { │ │ │ │ + clusters.push(candidate); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.clustering = true; │ │ │ │ + // A legitimate feature addition could occur during this │ │ │ │ + // addFeatures call. For clustering to behave well, features │ │ │ │ + // should be removed from a layer before requesting a new batch. │ │ │ │ + this.layer.addFeatures(clusters); │ │ │ │ + this.clustering = false; │ │ │ │ + } │ │ │ │ + this.clusters = clusters; │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getUrlOrImage │ │ │ │ - * Extract a url or image from the ArcXML image output. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * output - {Object} The image.output property of the object returned from │ │ │ │ - * the ArcXML format read method. │ │ │ │ + * Method: clustersExist │ │ │ │ + * Determine whether calculated clusters are already on the layer. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} A URL for an image (potentially with the data protocol). │ │ │ │ + * {Boolean} The calculated clusters are already on the layer. │ │ │ │ */ │ │ │ │ - getUrlOrImage: function(output) { │ │ │ │ - var ret = ""; │ │ │ │ - if (output.url) { │ │ │ │ - // If the image response output url is a string, then the image │ │ │ │ - // data is not inline. │ │ │ │ - ret = output.url; │ │ │ │ - } else if (output.data) { │ │ │ │ - // The image data is inline and base64 encoded, create a data │ │ │ │ - // url for the image. This will only work for small images, │ │ │ │ - // due to browser url length limits. │ │ │ │ - ret = "data:image/" + output.type + │ │ │ │ - ";base64," + output.data; │ │ │ │ + clustersExist: function() { │ │ │ │ + var exist = false; │ │ │ │ + if (this.clusters && this.clusters.length > 0 && │ │ │ │ + this.clusters.length == this.layer.features.length) { │ │ │ │ + exist = true; │ │ │ │ + for (var i = 0; i < this.clusters.length; ++i) { │ │ │ │ + if (this.clusters[i] != this.layer.features[i]) { │ │ │ │ + exist = false; │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - return ret; │ │ │ │ + return exist; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setLayerQuery │ │ │ │ - * Set the query definition on this layer. Query definitions are used to │ │ │ │ - * render parts of the spatial data in an image, and can be used to │ │ │ │ - * filter features or layers in the ArcIMS service. │ │ │ │ + * Method: shouldCluster │ │ │ │ + * Determine whether to include a feature in a given cluster. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * id - {String} The ArcIMS layer ID. │ │ │ │ - * querydef - {Object} The query definition to apply to this layer. │ │ │ │ + * cluster - {<OpenLayers.Feature.Vector>} A cluster. │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} A feature. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The feature should be included in the cluster. │ │ │ │ */ │ │ │ │ - setLayerQuery: function(id, querydef) { │ │ │ │ - // find the matching layer, if it exists │ │ │ │ - for (var lyr = 0; lyr < this.options.layers.length; lyr++) { │ │ │ │ - if (id == this.options.layers[lyr].id) { │ │ │ │ - // replace this layer definition │ │ │ │ - this.options.layers[lyr].query = querydef; │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // no layer found, create a new definition │ │ │ │ - this.options.layers.push({ │ │ │ │ - id: id, │ │ │ │ - visible: true, │ │ │ │ - query: querydef │ │ │ │ - }); │ │ │ │ + shouldCluster: function(cluster, feature) { │ │ │ │ + var cc = cluster.geometry.getBounds().getCenterLonLat(); │ │ │ │ + var fc = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ + var distance = ( │ │ │ │ + Math.sqrt( │ │ │ │ + Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2) │ │ │ │ + ) / this.resolution │ │ │ │ + ); │ │ │ │ + return (distance <= this.distance); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getFeatureInfo │ │ │ │ - * Get feature information from ArcIMS. Using the applied geometry, apply │ │ │ │ - * the options to the query (buffer, area/envelope intersection), and │ │ │ │ - * query the ArcIMS service. │ │ │ │ - * │ │ │ │ - * A note about accuracy: │ │ │ │ - * ArcIMS interprets the accuracy attribute in feature requests to be │ │ │ │ - * something like the 'modulus' operator on feature coordinates, │ │ │ │ - * applied to the database geometry of the feature. It doesn't round, │ │ │ │ - * so your feature coordinates may be up to (1 x accuracy) offset from │ │ │ │ - * the actual feature coordinates. If the accuracy of the layer is not │ │ │ │ - * specified, the accuracy will be computed to be approximately 1 │ │ │ │ - * feature coordinate per screen pixel. │ │ │ │ + * Method: addToCluster │ │ │ │ + * Add a feature to a cluster. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * geometry - {<OpenLayers.LonLat>} or {<OpenLayers.Geometry.Polygon>} The │ │ │ │ - * geometry to use when making the query. This should be a closed │ │ │ │ - * polygon for behavior approximating a free selection. │ │ │ │ - * layer - {Object} The ArcIMS layer definition. This is an anonymous object │ │ │ │ - * that looks like: │ │ │ │ - * (code) │ │ │ │ - * { │ │ │ │ - * id: "ArcXML layer ID", // the ArcXML layer ID │ │ │ │ - * query: { │ │ │ │ - * where: "STATE = 'PA'", // the where clause of the query │ │ │ │ - * accuracy: 100 // the accuracy of the returned feature │ │ │ │ - * } │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ - * options - {Object} Object with non-default properties to set on the layer. │ │ │ │ - * Supported properties are buffer, callback, scope, and any other │ │ │ │ - * properties applicable to the ArcXML format. Set the 'callback' and │ │ │ │ - * 'scope' for an object and function to recieve the parsed features │ │ │ │ - * from ArcIMS. │ │ │ │ + * cluster - {<OpenLayers.Feature.Vector>} A cluster. │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} A feature. │ │ │ │ */ │ │ │ │ - getFeatureInfo: function(geometry, layer, options) { │ │ │ │ - // set the buffer to 1 unit (dd/m/ft?) by default │ │ │ │ - var buffer = options.buffer || 1; │ │ │ │ - // empty callback by default │ │ │ │ - var callback = options.callback || function() {}; │ │ │ │ - // default scope is window (global) │ │ │ │ - var scope = options.scope || window; │ │ │ │ - │ │ │ │ - // apply these option to the request options │ │ │ │ - var requestOptions = {}; │ │ │ │ - OpenLayers.Util.extend(requestOptions, this.options); │ │ │ │ - │ │ │ │ - // this is a feature request │ │ │ │ - requestOptions.requesttype = "feature"; │ │ │ │ - │ │ │ │ - if (geometry instanceof OpenLayers.LonLat) { │ │ │ │ - // create an envelope if the geometry is really a lon/lat │ │ │ │ - requestOptions.polygon = null; │ │ │ │ - requestOptions.envelope = [ │ │ │ │ - geometry.lon - buffer, │ │ │ │ - geometry.lat - buffer, │ │ │ │ - geometry.lon + buffer, │ │ │ │ - geometry.lat + buffer │ │ │ │ - ]; │ │ │ │ - } else if (geometry instanceof OpenLayers.Geometry.Polygon) { │ │ │ │ - // use the polygon assigned, and empty the envelope │ │ │ │ - requestOptions.envelope = null; │ │ │ │ - requestOptions.polygon = geometry; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // create an arcxml request to get feature requests │ │ │ │ - var arcxml = new OpenLayers.Format.ArcXML(requestOptions); │ │ │ │ - │ │ │ │ - // apply any get feature options to the arcxml request │ │ │ │ - OpenLayers.Util.extend(arcxml.request.get_feature, options); │ │ │ │ - │ │ │ │ - arcxml.request.get_feature.layer = layer.id; │ │ │ │ - if (typeof layer.query.accuracy == "number") { │ │ │ │ - // set the accuracy if it was specified │ │ │ │ - arcxml.request.get_feature.query.accuracy = layer.query.accuracy; │ │ │ │ - } else { │ │ │ │ - // guess that the accuracy is 1 per screen pixel │ │ │ │ - var mapCenter = this.map.getCenter(); │ │ │ │ - var viewPx = this.map.getViewPortPxFromLonLat(mapCenter); │ │ │ │ - viewPx.x++; │ │ │ │ - var mapOffCenter = this.map.getLonLatFromPixel(viewPx); │ │ │ │ - arcxml.request.get_feature.query.accuracy = mapOffCenter.lon - mapCenter.lon; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // set the get_feature query to be the same as the layer passed in │ │ │ │ - arcxml.request.get_feature.query.where = layer.query.where; │ │ │ │ - │ │ │ │ - // use area_intersection │ │ │ │ - arcxml.request.get_feature.query.spatialfilter.relation = "area_intersection"; │ │ │ │ - │ │ │ │ - // create a new asynchronous request to get the feature info │ │ │ │ - OpenLayers.Request.POST({ │ │ │ │ - url: this.getFullRequestString({ │ │ │ │ - 'CustomService': 'Query' │ │ │ │ - }), │ │ │ │ - data: arcxml.write(), │ │ │ │ - callback: function(request) { │ │ │ │ - // parse the arcxml response │ │ │ │ - var response = arcxml.parseResponse(request.responseText); │ │ │ │ - │ │ │ │ - if (!arcxml.iserror()) { │ │ │ │ - // if the arcxml is not an error, call the callback with the features parsed │ │ │ │ - callback.call(scope, response.features); │ │ │ │ - } else { │ │ │ │ - // if the arcxml is an error, return null features selected │ │ │ │ - callback.call(scope, null); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }); │ │ │ │ + addToCluster: function(cluster, feature) { │ │ │ │ + cluster.cluster.push(feature); │ │ │ │ + cluster.attributes.count += 1; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ + * Method: createCluster │ │ │ │ + * Given a feature, create a cluster. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Layer.ArcIMS>} An exact clone of this layer │ │ │ │ + * {<OpenLayers.Feature.Vector>} A cluster. │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.ArcIMS(this.name, │ │ │ │ - this.url, │ │ │ │ - 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; │ │ │ │ + createCluster: function(feature) { │ │ │ │ + var center = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ + var cluster = new OpenLayers.Feature.Vector( │ │ │ │ + new OpenLayers.Geometry.Point(center.lon, center.lat), { │ │ │ │ + count: 1 │ │ │ │ + } │ │ │ │ + ); │ │ │ │ + cluster.cluster = [feature]; │ │ │ │ + return cluster; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.ArcIMS" │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Cluster" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/ArcGIS93Rest.js │ │ │ │ + OpenLayers/Strategy/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/Layer/Grid.js │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ + * @requires OpenLayers/Filter.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.ArcGIS93Rest │ │ │ │ - * Instances of OpenLayers.Layer.ArcGIS93Rest are used to display data from │ │ │ │ - * ESRI ArcGIS Server 9.3 (and up?) Mapping Services using the REST API. │ │ │ │ - * Create a new ArcGIS93Rest layer with the <OpenLayers.Layer.ArcGIS93Rest> │ │ │ │ - * constructor. More detail on the REST API is available at │ │ │ │ - * http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/index.html ; │ │ │ │ - * specifically, the URL provided to this layer should be an export service │ │ │ │ - * URL: http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/export.html │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Strategy.Filter │ │ │ │ + * Strategy for limiting features that get added to a layer by │ │ │ │ + * evaluating a filter. The strategy maintains a cache of │ │ │ │ + * all features until removeFeatures is called on the layer. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * - <OpenLayers.Strategy> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.ArcGIS93Rest = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ +OpenLayers.Strategy.Filter = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: DEFAULT_PARAMS │ │ │ │ - * {Object} Hashtable of default parameter key/value pairs │ │ │ │ + * APIProperty: filter │ │ │ │ + * {<OpenLayers.Filter>} Filter for limiting features sent to the layer. │ │ │ │ + * Use the <setFilter> method to update this filter after construction. │ │ │ │ */ │ │ │ │ - DEFAULT_PARAMS: { │ │ │ │ - format: "png" │ │ │ │ - }, │ │ │ │ + filter: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} Default is true for ArcGIS93Rest layer │ │ │ │ + * Property: cache │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} List of currently cached │ │ │ │ + * features. │ │ │ │ */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + cache: null, │ │ │ │ │ │ │ │ + /** │ │ │ │ + * Property: caching │ │ │ │ + * {Boolean} The filter is currently caching features. │ │ │ │ + */ │ │ │ │ + caching: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.ArcGIS93Rest │ │ │ │ - * Create a new ArcGIS93Rest layer object. │ │ │ │ - * │ │ │ │ - * Example: │ │ │ │ - * (code) │ │ │ │ - * var arcims = new OpenLayers.Layer.ArcGIS93Rest("MyName", │ │ │ │ - * "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/export", │ │ │ │ - * { │ │ │ │ - * layers: "0,1,2" │ │ │ │ - * }); │ │ │ │ - * (end) │ │ │ │ + * Constructor: OpenLayers.Strategy.Filter │ │ │ │ + * Create a new filter strategy. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} A name for the layer │ │ │ │ - * url - {String} Base url for the ArcGIS server REST service │ │ │ │ - * options - {Object} An object with key/value pairs representing the │ │ │ │ - * options and option values. │ │ │ │ - * │ │ │ │ - * Valid Options: │ │ │ │ - * format - {String} MIME type of desired image type. │ │ │ │ - * layers - {String} Comma-separated list of layers to display. │ │ │ │ - * srs - {String} Projection ID. │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - var newArguments = []; │ │ │ │ - //uppercase params │ │ │ │ - params = OpenLayers.Util.upperCaseObject(params); │ │ │ │ - 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.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 == "jpg") { │ │ │ │ - this.params.FORMAT = OpenLayers.Util.alphaHack() ? "gif" : │ │ │ │ - "png"; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ + * By default, this strategy automatically activates itself when a layer │ │ │ │ + * is added to a map. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Layer.ArcGIS93Rest>} An exact clone of this layer │ │ │ │ + * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ + * the strategy was already active. │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.ArcGIS93Rest(this.name, │ │ │ │ - this.url, │ │ │ │ - this.params, │ │ │ │ - this.getOptions()); │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments); │ │ │ │ + if (activated) { │ │ │ │ + this.cache = []; │ │ │ │ + this.layer.events.on({ │ │ │ │ + "beforefeaturesadded": this.handleAdd, │ │ │ │ + "beforefeaturesremoved": this.handleRemove, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ } │ │ │ │ - │ │ │ │ - //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; │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: getURL │ │ │ │ - * Return an image url this layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the │ │ │ │ - * request. │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the strategy. Clear the feature cache. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} A string with the map image's url. │ │ │ │ + * {Boolean} True if the strategy was successfully deactivated or false if │ │ │ │ + * the strategy was already inactive. │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - │ │ │ │ - // ArcGIS Server only wants the numeric portion of the projection ID. │ │ │ │ - var projWords = this.projection.getCode().split(":"); │ │ │ │ - var srid = projWords[projWords.length - 1]; │ │ │ │ - │ │ │ │ - var imageSize = this.getImageSize(); │ │ │ │ - var newParams = { │ │ │ │ - 'BBOX': bounds.toBBOX(), │ │ │ │ - 'SIZE': imageSize.w + "," + imageSize.h, │ │ │ │ - // We always want image, the other options were json, image with a whole lotta html around it, etc. │ │ │ │ - 'F': "image", │ │ │ │ - 'BBOXSR': srid, │ │ │ │ - 'IMAGESR': srid │ │ │ │ - }; │ │ │ │ + deactivate: function() { │ │ │ │ + this.cache = null; │ │ │ │ + if (this.layer && this.layer.events) { │ │ │ │ + this.layer.events.un({ │ │ │ │ + "beforefeaturesadded": this.handleAdd, │ │ │ │ + "beforefeaturesremoved": this.handleRemove, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + return OpenLayers.Strategy.prototype.deactivate.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ - // Now add the filter parameters. │ │ │ │ - if (this.layerDefs) { │ │ │ │ - var layerDefStrList = []; │ │ │ │ - var layerID; │ │ │ │ - for (layerID in this.layerDefs) { │ │ │ │ - if (this.layerDefs.hasOwnProperty(layerID)) { │ │ │ │ - if (this.layerDefs[layerID]) { │ │ │ │ - layerDefStrList.push(layerID); │ │ │ │ - layerDefStrList.push(":"); │ │ │ │ - layerDefStrList.push(this.layerDefs[layerID]); │ │ │ │ - layerDefStrList.push(";"); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Method: handleAdd │ │ │ │ + */ │ │ │ │ + handleAdd: function(event) { │ │ │ │ + if (!this.caching && this.filter) { │ │ │ │ + var features = event.features; │ │ │ │ + event.features = []; │ │ │ │ + var feature; │ │ │ │ + for (var i = 0, ii = features.length; i < ii; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + if (this.filter.evaluate(feature)) { │ │ │ │ + event.features.push(feature); │ │ │ │ + } else { │ │ │ │ + this.cache.push(feature); │ │ │ │ } │ │ │ │ } │ │ │ │ - if (layerDefStrList.length > 0) { │ │ │ │ - newParams['LAYERDEFS'] = layerDefStrList.join(""); │ │ │ │ - } │ │ │ │ } │ │ │ │ - var requestString = this.getFullRequestString(newParams); │ │ │ │ - return requestString; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setLayerFilter │ │ │ │ - * addTile creates a tile, initializes it, and adds it to the layer div. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * id - {String} The id of the layer to which the filter applies. │ │ │ │ - * queryDef - {String} A sql-ish query filter, for more detail see the ESRI │ │ │ │ - * documentation at http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/export.html │ │ │ │ + * Method: handleRemove │ │ │ │ */ │ │ │ │ - setLayerFilter: function(id, queryDef) { │ │ │ │ - if (!this.layerDefs) { │ │ │ │ - this.layerDefs = {}; │ │ │ │ - } │ │ │ │ - if (queryDef) { │ │ │ │ - this.layerDefs[id] = queryDef; │ │ │ │ - } else { │ │ │ │ - delete this.layerDefs[id]; │ │ │ │ + handleRemove: function(event) { │ │ │ │ + if (!this.caching) { │ │ │ │ + this.cache = []; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: clearLayerFilter │ │ │ │ - * Clears layer filters, either from a specific layer, │ │ │ │ - * or all of them. │ │ │ │ + /** │ │ │ │ + * APIMethod: setFilter │ │ │ │ + * Update the filter for this strategy. This will re-evaluate │ │ │ │ + * any features on the layer and in the cache. Only features │ │ │ │ + * for which filter.evalute(feature) returns true will be │ │ │ │ + * added to the layer. Others will be cached by the strategy. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * id - {String} The id of the layer from which to remove any │ │ │ │ - * filter. If unspecified/blank, all filters │ │ │ │ - * will be removed. │ │ │ │ + * filter - {<OpenLayers.Filter>} A filter for evaluating features. │ │ │ │ */ │ │ │ │ - clearLayerFilter: function(id) { │ │ │ │ - if (id) { │ │ │ │ - delete this.layerDefs[id]; │ │ │ │ - } else { │ │ │ │ - delete this.layerDefs; │ │ │ │ + setFilter: function(filter) { │ │ │ │ + this.filter = filter; │ │ │ │ + var previousCache = this.cache; │ │ │ │ + this.cache = []; │ │ │ │ + // look through layer for features to remove from layer │ │ │ │ + this.handleAdd({ │ │ │ │ + features: this.layer.features │ │ │ │ + }); │ │ │ │ + // cache now contains features to remove from layer │ │ │ │ + if (this.cache.length > 0) { │ │ │ │ + this.caching = true; │ │ │ │ + this.layer.removeFeatures(this.cache.slice()); │ │ │ │ + this.caching = false; │ │ │ │ + } │ │ │ │ + // now look through previous cache for features to add to layer │ │ │ │ + if (previousCache.length > 0) { │ │ │ │ + var event = { │ │ │ │ + features: previousCache │ │ │ │ + }; │ │ │ │ + this.handleAdd(event); │ │ │ │ + if (event.features.length > 0) { │ │ │ │ + // event has features to add to layer │ │ │ │ + this.caching = true; │ │ │ │ + this.layer.addFeatures(event.features); │ │ │ │ + this.caching = false; │ │ │ │ + } │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Filter" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.ArcGIS93Rest" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/OSM.js │ │ │ │ + OpenLayers/Strategy/Refresh.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 │ │ │ │ + * @requires OpenLayers/Strategy.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) │ │ │ │ + * Class: OpenLayers.Strategy.Refresh │ │ │ │ + * A strategy that refreshes the layer. By default the strategy waits for a │ │ │ │ + * call to <refresh> before refreshing. By configuring the strategy with │ │ │ │ + * the <interval> option, refreshing can take place automatically. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.XYZ> │ │ │ │ + * - <OpenLayers.Strategy> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ +OpenLayers.Strategy.Refresh = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: name │ │ │ │ - * {String} The layer name. Defaults to "OpenStreetMap" if the first │ │ │ │ - * argument to the constructor is null or undefined. │ │ │ │ + * Property: force │ │ │ │ + * {Boolean} Force a refresh on the layer. Default is false. │ │ │ │ */ │ │ │ │ - name: "OpenStreetMap", │ │ │ │ + force: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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) │ │ │ │ + * Property: interval │ │ │ │ + * {Number} Auto-refresh. Default is 0. If > 0, layer will be refreshed │ │ │ │ + * every N milliseconds. │ │ │ │ */ │ │ │ │ - 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' │ │ │ │ - ], │ │ │ │ + interval: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: attribution │ │ │ │ - * {String} The layer attribution. │ │ │ │ + * Property: timer │ │ │ │ + * {Number} The id of the timer. │ │ │ │ */ │ │ │ │ - attribution: "© <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors", │ │ │ │ + timer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: sphericalMercator │ │ │ │ - * {Boolean} │ │ │ │ + * Constructor: OpenLayers.Strategy.Refresh │ │ │ │ + * Create a new Refresh strategy. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - sphericalMercator: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: wrapDateLine │ │ │ │ - * {Boolean} │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} True if the strategy was successfully activated. │ │ │ │ */ │ │ │ │ - wrapDateLine: true, │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + if (this.layer.visibility === true) { │ │ │ │ + this.start(); │ │ │ │ + } │ │ │ │ + this.layer.events.on({ │ │ │ │ + "visibilitychanged": this.reset, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + return activated; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** 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. │ │ │ │ + /** │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ + * tear-down. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} True if the strategy was successfully deactivated. │ │ │ │ */ │ │ │ │ - tileOptions: null, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.stop(); │ │ │ │ + this.layer.events.un({ │ │ │ │ + "visibilitychanged": this.reset, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + return deactivated; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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>). │ │ │ │ + * Method: reset │ │ │ │ + * Start or cancel the refresh interval depending on the visibility of │ │ │ │ + * the layer. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + reset: function() { │ │ │ │ + if (this.layer.visibility === true) { │ │ │ │ + this.start(); │ │ │ │ + } else { │ │ │ │ + this.stop(); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clone │ │ │ │ + * Method: start │ │ │ │ + * Start the refresh interval. │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.OSM( │ │ │ │ - this.name, this.url, this.getOptions()); │ │ │ │ + start: function() { │ │ │ │ + if (this.interval && typeof this.interval === "number" && │ │ │ │ + this.interval > 0) { │ │ │ │ + │ │ │ │ + this.timer = window.setInterval( │ │ │ │ + OpenLayers.Function.bind(this.refresh, this), │ │ │ │ + this.interval); │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.OSM" │ │ │ │ + /** │ │ │ │ + * APIMethod: refresh │ │ │ │ + * Tell the strategy to refresh which will refresh the layer. │ │ │ │ + */ │ │ │ │ + refresh: function() { │ │ │ │ + if (this.layer && this.layer.refresh && │ │ │ │ + typeof this.layer.refresh == "function") { │ │ │ │ + │ │ │ │ + this.layer.refresh({ │ │ │ │ + force: this.force │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: stop │ │ │ │ + * Cancels the refresh interval. │ │ │ │ + */ │ │ │ │ + stop: function() { │ │ │ │ + if (this.timer !== null) { │ │ │ │ + window.clearInterval(this.timer); │ │ │ │ + this.timer = null; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Refresh" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/MapServer.js │ │ │ │ + OpenLayers/Strategy/Paging.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 │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.MapServer │ │ │ │ - * Instances of OpenLayers.Layer.MapServer are used to display │ │ │ │ - * data from a MapServer CGI instance. │ │ │ │ + * Class: OpenLayers.Strategy.Paging │ │ │ │ + * Strategy for vector feature paging │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * - <OpenLayers.Strategy> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.MapServer = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ +OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: DEFAULT_PARAMS │ │ │ │ - * {Object} Hashtable of default parameter key/value pairs │ │ │ │ + * Property: features │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} Cached features. │ │ │ │ */ │ │ │ │ - DEFAULT_PARAMS: { │ │ │ │ - mode: "map", │ │ │ │ - map_imagetype: "png" │ │ │ │ - }, │ │ │ │ + features: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.MapServer │ │ │ │ - * Create a new MapServer layer object │ │ │ │ + * Property: length │ │ │ │ + * {Integer} Number of features per page. Default is 10. │ │ │ │ + */ │ │ │ │ + length: 10, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: num │ │ │ │ + * {Integer} The currently displayed page number. │ │ │ │ + */ │ │ │ │ + num: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: paging │ │ │ │ + * {Boolean} The strategy is currently changing pages. │ │ │ │ + */ │ │ │ │ + paging: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Strategy.Paging │ │ │ │ + * Create a new paging strategy. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} A name for the layer │ │ │ │ - * url - {String} Base url for the MapServer CGI │ │ │ │ - * (e.g. http://www2.dmsolutions.ca/cgi-bin/mapserv) │ │ │ │ - * 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 │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ │ │ │ │ - this.params = OpenLayers.Util.applyDefaults( │ │ │ │ - this.params, this.DEFAULT_PARAMS │ │ │ │ - ); │ │ │ │ - │ │ │ │ - // unless explicitly set in options, if the layer is transparent, │ │ │ │ - // it will be an overlay │ │ │ │ - if (options == null || options.isBaseLayer == null) { │ │ │ │ - this.isBaseLayer = ((this.params.transparent != "true") && │ │ │ │ - (this.params.transparent != true)); │ │ │ │ + /** │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The strategy was successfully activated. │ │ │ │ + */ │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + "beforefeaturesadded": this.cacheFeatures, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ } │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ - * │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ + * tear-down. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Layer.MapServer>} An exact clone of this layer │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.MapServer(this.name, │ │ │ │ - this.url, │ │ │ │ - this.params, │ │ │ │ - this.getOptions()); │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.clearCache(); │ │ │ │ + this.layer.events.un({ │ │ │ │ + "beforefeaturesadded": this.cacheFeatures, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ } │ │ │ │ - //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; │ │ │ │ + return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getURL │ │ │ │ - * Return a query string for this layer │ │ │ │ + * Method: cacheFeatures │ │ │ │ + * Cache features before they are added to the 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. │ │ │ │ + * event - {Object} The event that this was listening for. This will come │ │ │ │ + * with a batch of features to be paged. │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - // Make a list, so that getFullRequestString uses literal "," │ │ │ │ - var extent = [bounds.left, bounds.bottom, bounds.right, bounds.top]; │ │ │ │ + cacheFeatures: function(event) { │ │ │ │ + if (!this.paging) { │ │ │ │ + this.clearCache(); │ │ │ │ + this.features = event.features; │ │ │ │ + this.pageNext(event); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - var imageSize = this.getImageSize(); │ │ │ │ + /** │ │ │ │ + * Method: clearCache │ │ │ │ + * Clear out the cached features. This destroys features, assuming │ │ │ │ + * nothing else has a reference. │ │ │ │ + */ │ │ │ │ + clearCache: function() { │ │ │ │ + if (this.features) { │ │ │ │ + for (var i = 0; i < this.features.length; ++i) { │ │ │ │ + this.features[i].destroy(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.features = null; │ │ │ │ + this.num = null; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // make lists, so that literal ','s are used │ │ │ │ - var url = this.getFullRequestString({ │ │ │ │ - mapext: extent, │ │ │ │ - imgext: extent, │ │ │ │ - map_size: [imageSize.w, imageSize.h], │ │ │ │ - imgx: imageSize.w / 2, │ │ │ │ - imgy: imageSize.h / 2, │ │ │ │ - imgxy: [imageSize.w, imageSize.h] │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * APIMethod: pageCount │ │ │ │ + * Get the total count of pages given the current cache of features. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} The page count. │ │ │ │ + */ │ │ │ │ + pageCount: function() { │ │ │ │ + var numFeatures = this.features ? this.features.length : 0; │ │ │ │ + return Math.ceil(numFeatures / this.length); │ │ │ │ + }, │ │ │ │ │ │ │ │ - return url; │ │ │ │ + /** │ │ │ │ + * APIMethod: pageNum │ │ │ │ + * Get the zero based page number. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} The current page number being displayed. │ │ │ │ + */ │ │ │ │ + pageNum: function() { │ │ │ │ + return this.num; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getFullRequestString │ │ │ │ - * combine the layer's url with its params and these newParams. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * APIMethod: pageLength │ │ │ │ + * Gets or sets page length. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * newParams - {Object} New parameters that should be added to the │ │ │ │ - * request string. │ │ │ │ - * altUrl - {String} (optional) Replace the URL in the full request │ │ │ │ - * string with the provided URL. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A string with the layer's url and parameters embedded in it. │ │ │ │ + * newLength - {Integer} Optional length to be set. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} The length of a page (number of features per page). │ │ │ │ */ │ │ │ │ - getFullRequestString: function(newParams, altUrl) { │ │ │ │ - // use layer's url unless altUrl passed in │ │ │ │ - var url = (altUrl == null) ? this.url : altUrl; │ │ │ │ - │ │ │ │ - // 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); │ │ │ │ + pageLength: function(newLength) { │ │ │ │ + if (newLength && newLength > 0) { │ │ │ │ + this.length = newLength; │ │ │ │ } │ │ │ │ + return this.length; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // 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]; │ │ │ │ + /** │ │ │ │ + * APIMethod: pageNext │ │ │ │ + * Display the next page of features. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} A new page was displayed. │ │ │ │ + */ │ │ │ │ + pageNext: function(event) { │ │ │ │ + var changed = false; │ │ │ │ + if (this.features) { │ │ │ │ + if (this.num === null) { │ │ │ │ + this.num = -1; │ │ │ │ } │ │ │ │ + var start = (this.num + 1) * this.length; │ │ │ │ + changed = this.page(start, event); │ │ │ │ } │ │ │ │ - paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ - │ │ │ │ - // requestString always starts with url │ │ │ │ - var requestString = url; │ │ │ │ + return changed; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // MapServer needs '+' seperating things like bounds/height/width. │ │ │ │ - // Since typically this is URL encoded, we use a slight hack: we │ │ │ │ - // depend on the list-like functionality of getParameterString to │ │ │ │ - // leave ',' only in the case of list items (since otherwise it is │ │ │ │ - // encoded) then do a regular expression replace on the , characters │ │ │ │ - // to '+' │ │ │ │ - // │ │ │ │ - paramsString = paramsString.replace(/,/g, "+"); │ │ │ │ + /** │ │ │ │ + * APIMethod: pagePrevious │ │ │ │ + * Display the previous page of features. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} A new page was displayed. │ │ │ │ + */ │ │ │ │ + pagePrevious: function() { │ │ │ │ + var changed = false; │ │ │ │ + if (this.features) { │ │ │ │ + if (this.num === null) { │ │ │ │ + this.num = this.pageCount(); │ │ │ │ + } │ │ │ │ + var start = (this.num - 1) * this.length; │ │ │ │ + changed = this.page(start); │ │ │ │ + } │ │ │ │ + return changed; │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (paramsString != "") { │ │ │ │ - var lastServerChar = url.charAt(url.length - 1); │ │ │ │ - if ((lastServerChar == "&") || (lastServerChar == "?")) { │ │ │ │ - requestString += paramsString; │ │ │ │ - } else { │ │ │ │ - if (url.indexOf('?') == -1) { │ │ │ │ - //serverPath has no ? -- add one │ │ │ │ - requestString += '?' + paramsString; │ │ │ │ - } else { │ │ │ │ - //serverPath contains ?, so must already have paramsString at the end │ │ │ │ - requestString += '&' + paramsString; │ │ │ │ + /** │ │ │ │ + * Method: page │ │ │ │ + * Display the page starting at the given index from the cache. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} A new page was displayed. │ │ │ │ + */ │ │ │ │ + page: function(start, event) { │ │ │ │ + var changed = false; │ │ │ │ + if (this.features) { │ │ │ │ + if (start >= 0 && start < this.features.length) { │ │ │ │ + var num = Math.floor(start / this.length); │ │ │ │ + if (num != this.num) { │ │ │ │ + this.paging = true; │ │ │ │ + var features = this.features.slice(start, start + this.length); │ │ │ │ + this.layer.removeFeatures(this.layer.features); │ │ │ │ + this.num = num; │ │ │ │ + // modify the event if any │ │ │ │ + if (event && event.features) { │ │ │ │ + // this.was called by an event listener │ │ │ │ + event.features = features; │ │ │ │ + } else { │ │ │ │ + // this was called directly on the strategy │ │ │ │ + this.layer.addFeatures(features); │ │ │ │ + } │ │ │ │ + this.paging = false; │ │ │ │ + changed = true; │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ - return requestString; │ │ │ │ + return changed; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.MapServer" │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Paging" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/KaMap.js │ │ │ │ + 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/Layer/Grid.js │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.KaMap │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Strategy.Fixed │ │ │ │ + * A simple strategy that requests features once and never requests new data. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * - <OpenLayers.Strategy> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.KaMap = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} KaMap Layer is always a base layer │ │ │ │ - */ │ │ │ │ - isBaseLayer: true, │ │ │ │ +OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: DEFAULT_PARAMS │ │ │ │ - * {Object} parameters set by default. The default parameters set │ │ │ │ - * the format via the 'i' parameter to 'jpeg'. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - DEFAULT_PARAMS: { │ │ │ │ - i: 'jpeg', │ │ │ │ - map: '' │ │ │ │ - }, │ │ │ │ + preload: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.KaMap │ │ │ │ - * │ │ │ │ + * Constructor: OpenLayers.Strategy.Fixed │ │ │ │ + * Create a new Fixed strategy. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * url - {String} │ │ │ │ - * params - {Object} Parameters to be sent to the HTTP server in the │ │ │ │ - * query string for the tile. The format can be set via the 'i' │ │ │ │ - * parameter (defaults to jpg) , and the map should be set via │ │ │ │ - * the 'map' parameter. It has been reported that ka-Map may behave │ │ │ │ - * inconsistently if your format parameter does not match the format │ │ │ │ - * parameter configured in your config.php. (See ticket #327 for more │ │ │ │ - * information.) │ │ │ │ - * options - {Object} Additional options for the layer. Any of the │ │ │ │ - * APIProperties listed on this layer, and any layer types it │ │ │ │ - * extends, can be overridden through the options parameter. │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ - this.params = OpenLayers.Util.applyDefaults( │ │ │ │ - this.params, this.DEFAULT_PARAMS │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getURL │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - * │ │ │ │ + * Method: activate │ │ │ │ + * Activate the strategy: load data or add listener to load when visible │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {String} A string with the layer's url and parameters and also the │ │ │ │ - * passed-in bounds and appropriate tile size specified as │ │ │ │ - * parameters │ │ │ │ + * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ + * the strategy was already active. │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ - var scale = Math.round((this.map.getScale() * 10000)) / 10000; │ │ │ │ - var pX = Math.round(bounds.left / mapRes); │ │ │ │ - var pY = -Math.round(bounds.top / mapRes); │ │ │ │ - return this.getFullRequestString({ │ │ │ │ - t: pY, │ │ │ │ - l: pX, │ │ │ │ - s: scale │ │ │ │ - }); │ │ │ │ + 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: calculateGridLayout │ │ │ │ - * ka-Map uses the center point of the map as an origin for │ │ │ │ - * its tiles. Override calculateGridLayout to center tiles │ │ │ │ - * correctly for this case. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bound>} │ │ │ │ - * origin - {<OpenLayers.LonLat>} │ │ │ │ - * resolution - {Number} │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: deactivate │ │ │ │ + * Deactivate the strategy. Undo what is done in <activate>. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} Object containing properties tilelon, tilelat, startcol, │ │ │ │ - * startrow │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ */ │ │ │ │ - calculateGridLayout: function(bounds, origin, resolution) { │ │ │ │ - var tilelon = resolution * this.tileSize.w; │ │ │ │ - var tilelat = resolution * this.tileSize.h; │ │ │ │ - │ │ │ │ - var offsetlon = bounds.left; │ │ │ │ - var tilecol = Math.floor(offsetlon / tilelon) - this.buffer; │ │ │ │ - │ │ │ │ - var offsetlat = bounds.top; │ │ │ │ - var tilerow = Math.floor(offsetlat / tilelat) + this.buffer; │ │ │ │ - │ │ │ │ - return { │ │ │ │ - tilelon: tilelon, │ │ │ │ - tilelat: tilelat, │ │ │ │ - startcol: tilecol, │ │ │ │ - startrow: tilerow │ │ │ │ - }; │ │ │ │ + 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: getTileBoundsForGridIndex │ │ │ │ + * Method: load │ │ │ │ + * Tells protocol to load data and unhooks the visibilitychanged event │ │ │ │ * │ │ │ │ * 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 minX = (tileLayout.startcol + col) * tilelon; │ │ │ │ - var minY = (tileLayout.startrow - row) * tilelat; │ │ │ │ - return new OpenLayers.Bounds( │ │ │ │ - minX, minY, │ │ │ │ - minX + tilelon, minY + tilelat │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * obj - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.Kamap>} An exact clone of this OpenLayers.Layer.KaMap │ │ │ │ + * options - {Object} options to pass to protocol read. │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.KaMap(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 │ │ │ │ - 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 = []; │ │ │ │ - │ │ │ │ - return obj; │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getTileBounds │ │ │ │ - * Returns The tile bounds for a layer given a pixel location. │ │ │ │ + * 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: │ │ │ │ - * viewPortPx - {<OpenLayers.Pixel>} The location in the viewport. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} Bounds of the tile at the given pixel location. │ │ │ │ + * resp - {<OpenLayers.Protocol.Response>} The response object passed │ │ │ │ + * by the protocol. │ │ │ │ */ │ │ │ │ - getTileBounds: function(viewPortPx) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var tileMapWidth = resolution * this.tileSize.w; │ │ │ │ - var tileMapHeight = resolution * this.tileSize.h; │ │ │ │ - var mapPoint = this.getLonLatFromViewPortPx(viewPortPx); │ │ │ │ - var tileLeft = tileMapWidth * Math.floor(mapPoint.lon / tileMapWidth); │ │ │ │ - var tileBottom = tileMapHeight * Math.floor(mapPoint.lat / tileMapHeight); │ │ │ │ - return new OpenLayers.Bounds(tileLeft, tileBottom, │ │ │ │ - tileLeft + tileMapWidth, │ │ │ │ - tileBottom + tileMapHeight); │ │ │ │ + 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.Layer.KaMap" │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Fixed" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/KaMapCache.js │ │ │ │ + OpenLayers/Strategy/Save.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 │ │ │ │ - * @requires OpenLayers/Layer/KaMap.js │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.KaMapCache │ │ │ │ - * │ │ │ │ - * This class is designed to talk directly to a web-accessible ka-Map │ │ │ │ - * cache generated by the precache2.php script. │ │ │ │ - * │ │ │ │ - * To create a a new KaMapCache layer, you must indicate also the "i" parameter │ │ │ │ - * (that will be used to calculate the file extension), and another special │ │ │ │ - * parameter, object names "metaTileSize", with "h" (height) and "w" (width) │ │ │ │ - * properties. │ │ │ │ - * │ │ │ │ - * // Create a new kaMapCache layer. │ │ │ │ - * var kamap_base = new OpenLayers.Layer.KaMapCache( │ │ │ │ - * "Satellite", │ │ │ │ - * "http://www.example.org/web/acessible/cache", │ │ │ │ - * {g: "satellite", map: "world", i: 'png24', metaTileSize: {w: 5, h: 5} } │ │ │ │ - * ); │ │ │ │ - * │ │ │ │ - * // Create an kaMapCache overlay layer (using "isBaseLayer: false"). │ │ │ │ - * // Forces the output to be a "gif", using the "i" parameter. │ │ │ │ - * var kamap_overlay = new OpenLayers.Layer.KaMapCache( │ │ │ │ - * "Streets", │ │ │ │ - * "http://www.example.org/web/acessible/cache", │ │ │ │ - * {g: "streets", map: "world", i: "gif", metaTileSize: {w: 5, h: 5} }, │ │ │ │ - * {isBaseLayer: false} │ │ │ │ - * ); │ │ │ │ - * │ │ │ │ - * The cache URLs must look like: │ │ │ │ - * var/cache/World/50000/Group_Name/def/t-440320/l20480 │ │ │ │ - * │ │ │ │ - * This means that the cache generated via tile.php will *not* work with │ │ │ │ - * this class, and should instead use the KaMap layer. │ │ │ │ + * Class: OpenLayers.Strategy.Save │ │ │ │ + * A strategy that commits newly created or modified features. By default │ │ │ │ + * the strategy waits for a call to <save> before persisting changes. By │ │ │ │ + * configuring the strategy with the <auto> option, changes can be saved │ │ │ │ + * automatically. │ │ │ │ * │ │ │ │ - * More information is available in Ticket #1518. │ │ │ │ - * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.KaMap> │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * - <OpenLayers.Strategy> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.KaMapCache = OpenLayers.Class(OpenLayers.Layer.KaMap, { │ │ │ │ +OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: IMAGE_EXTENSIONS │ │ │ │ - * {Object} Simple hash map to convert format to extension. │ │ │ │ + * APIProperty: events │ │ │ │ + * {<OpenLayers.Events>} An events object that handles all │ │ │ │ + * events on the strategy object. │ │ │ │ + * │ │ │ │ + * Register a listener for a particular event with the following syntax: │ │ │ │ + * (code) │ │ │ │ + * strategy.events.register(type, obj, listener); │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Supported event types: │ │ │ │ + * start - Triggered before saving │ │ │ │ + * success - Triggered after a successful transaction │ │ │ │ + * fail - Triggered after a failed transaction │ │ │ │ + * │ │ │ │ */ │ │ │ │ - IMAGE_EXTENSIONS: { │ │ │ │ - 'jpeg': 'jpg', │ │ │ │ - 'gif': 'gif', │ │ │ │ - 'png': 'png', │ │ │ │ - 'png8': 'png', │ │ │ │ - 'png24': 'png', │ │ │ │ - 'dithered': 'png' │ │ │ │ - }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: events │ │ │ │ + * {<OpenLayers.Events>} Events instance for triggering this protocol │ │ │ │ + * events. │ │ │ │ + */ │ │ │ │ + events: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: DEFAULT_FORMAT │ │ │ │ - * {Object} Simple hash map to convert format to extension. │ │ │ │ + * APIProperty: auto │ │ │ │ + * {Boolean | Number} Auto-save. Default is false. If true, features will be │ │ │ │ + * saved immediately after being added to the layer and with each │ │ │ │ + * modification or deletion. If auto is a number, features will be │ │ │ │ + * saved on an interval provided by the value (in seconds). │ │ │ │ */ │ │ │ │ - DEFAULT_FORMAT: 'jpeg', │ │ │ │ + auto: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.KaMapCache │ │ │ │ - * │ │ │ │ + * Property: timer │ │ │ │ + * {Number} The id of the timer. │ │ │ │ + */ │ │ │ │ + timer: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Strategy.Save │ │ │ │ + * Create a new Save strategy. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * url - {String} │ │ │ │ - * params - {Object} Parameters to be sent to the HTTP server in the │ │ │ │ - * query string for the tile. The format can be set via the 'i' │ │ │ │ - * parameter (defaults to jpg) , and the map should be set via │ │ │ │ - * the 'map' parameter. It has been reported that ka-Map may behave │ │ │ │ - * inconsistently if your format parameter does not match the format │ │ │ │ - * parameter configured in your config.php. (See ticket #327 for more │ │ │ │ - * information.) │ │ │ │ - * options - {Object} Additional options for the layer. Any of the │ │ │ │ - * APIProperties listed on this layer, and any layer types it │ │ │ │ - * extends, can be overridden through the options parameter. │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - OpenLayers.Layer.KaMap.prototype.initialize.apply(this, arguments); │ │ │ │ - this.extension = this.IMAGE_EXTENSIONS[this.params.i.toLowerCase() || this.DEFAULT_FORMAT]; │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Strategy.prototype.initialize.apply(this, [options]); │ │ │ │ + this.events = new OpenLayers.Events(this); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getURL │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The strategy was successfully activated. │ │ │ │ + */ │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + if (this.auto) { │ │ │ │ + if (typeof this.auto === "number") { │ │ │ │ + this.timer = window.setInterval( │ │ │ │ + OpenLayers.Function.bind(this.save, this), │ │ │ │ + this.auto * 1000 │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + this.layer.events.on({ │ │ │ │ + "featureadded": this.triggerSave, │ │ │ │ + "afterfeaturemodified": this.triggerSave, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return activated; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ + * tear-down. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} A string with the layer's url and parameters and also the │ │ │ │ - * passed-in bounds and appropriate tile size specified as │ │ │ │ - * parameters │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ - var scale = Math.round((this.map.getScale() * 10000)) / 10000; │ │ │ │ - var pX = Math.round(bounds.left / mapRes); │ │ │ │ - var pY = -Math.round(bounds.top / mapRes); │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + if (this.auto) { │ │ │ │ + if (typeof this.auto === "number") { │ │ │ │ + window.clearInterval(this.timer); │ │ │ │ + } else { │ │ │ │ + this.layer.events.un({ │ │ │ │ + "featureadded": this.triggerSave, │ │ │ │ + "afterfeaturemodified": this.triggerSave, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return deactivated; │ │ │ │ + }, │ │ │ │ │ │ │ │ - var metaX = Math.floor(pX / this.tileSize.w / this.params.metaTileSize.w) * this.tileSize.w * this.params.metaTileSize.w; │ │ │ │ - var metaY = Math.floor(pY / this.tileSize.h / this.params.metaTileSize.h) * this.tileSize.h * this.params.metaTileSize.h; │ │ │ │ + /** │ │ │ │ + * Method: triggerSave │ │ │ │ + * Registered as a listener. Calls save if a feature has insert, update, │ │ │ │ + * or delete state. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * event - {Object} The event this function is listening for. │ │ │ │ + */ │ │ │ │ + triggerSave: function(event) { │ │ │ │ + var feature = event.feature; │ │ │ │ + if (feature.state === OpenLayers.State.INSERT || │ │ │ │ + feature.state === OpenLayers.State.UPDATE || │ │ │ │ + feature.state === OpenLayers.State.DELETE) { │ │ │ │ + this.save([event.feature]); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - var components = [ │ │ │ │ - "/", │ │ │ │ - this.params.map, │ │ │ │ - "/", │ │ │ │ - scale, │ │ │ │ - "/", │ │ │ │ - this.params.g.replace(/\s/g, '_'), │ │ │ │ - "/def/t", │ │ │ │ - metaY, │ │ │ │ - "/l", │ │ │ │ - metaX, │ │ │ │ - "/t", │ │ │ │ - pY, │ │ │ │ - "l", │ │ │ │ - pX, │ │ │ │ - ".", │ │ │ │ - this.extension │ │ │ │ - ]; │ │ │ │ + /** │ │ │ │ + * APIMethod: save │ │ │ │ + * Tell the layer protocol to commit unsaved features. If the layer │ │ │ │ + * projection differs from the map projection, features will be │ │ │ │ + * transformed into the layer projection before being committed. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * features - {Array} Features to be saved. If null, then default is all │ │ │ │ + * features in the layer. Features are assumed to be in the map │ │ │ │ + * projection. │ │ │ │ + */ │ │ │ │ + save: function(features) { │ │ │ │ + if (!features) { │ │ │ │ + features = this.layer.features; │ │ │ │ + } │ │ │ │ + this.events.triggerEvent("start", { │ │ │ │ + features: features │ │ │ │ + }); │ │ │ │ + var remote = this.layer.projection; │ │ │ │ + var local = this.layer.map.getProjectionObject(); │ │ │ │ + if (!local.equals(remote)) { │ │ │ │ + var len = features.length; │ │ │ │ + var clones = new Array(len); │ │ │ │ + var orig, clone; │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ + orig = features[i]; │ │ │ │ + clone = orig.clone(); │ │ │ │ + clone.fid = orig.fid; │ │ │ │ + clone.state = orig.state; │ │ │ │ + if (orig.url) { │ │ │ │ + clone.url = orig.url; │ │ │ │ + } │ │ │ │ + clone._original = orig; │ │ │ │ + clone.geometry.transform(local, remote); │ │ │ │ + clones[i] = clone; │ │ │ │ + } │ │ │ │ + features = clones; │ │ │ │ + } │ │ │ │ + this.layer.protocol.commit(features, { │ │ │ │ + callback: this.onCommit, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ │ │ │ │ - var url = this.url; │ │ │ │ + /** │ │ │ │ + * Method: onCommit │ │ │ │ + * Called after protocol commit. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} A response object. │ │ │ │ + */ │ │ │ │ + onCommit: function(response) { │ │ │ │ + var evt = { │ │ │ │ + "response": response │ │ │ │ + }; │ │ │ │ + if (response.success()) { │ │ │ │ + var features = response.reqFeatures; │ │ │ │ + // deal with inserts, updates, and deletes │ │ │ │ + var state, feature; │ │ │ │ + var destroys = []; │ │ │ │ + var insertIds = response.insertIds || []; │ │ │ │ + var j = 0; │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + // if projection was different, we may be dealing with clones │ │ │ │ + feature = feature._original || feature; │ │ │ │ + state = feature.state; │ │ │ │ + if (state) { │ │ │ │ + if (state == OpenLayers.State.DELETE) { │ │ │ │ + destroys.push(feature); │ │ │ │ + } else if (state == OpenLayers.State.INSERT) { │ │ │ │ + feature.fid = insertIds[j]; │ │ │ │ + ++j; │ │ │ │ + } │ │ │ │ + feature.state = null; │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(components.join(''), url); │ │ │ │ + if (destroys.length > 0) { │ │ │ │ + this.layer.destroyFeatures(destroys); │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.events.triggerEvent("success", evt); │ │ │ │ + │ │ │ │ + } else { │ │ │ │ + this.events.triggerEvent("fail", evt); │ │ │ │ } │ │ │ │ - return url + components.join(""); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.KaMapCache" │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Save" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/Image.js │ │ │ │ + OpenLayers/Strategy/BBOX.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/Tile/Image.js │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ + * @requires OpenLayers/Filter/Spatial.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.Image │ │ │ │ - * Instances of OpenLayers.Layer.Image are used to display data from a web │ │ │ │ - * accessible image as a map layer. Create a new image layer with the │ │ │ │ - * <OpenLayers.Layer.Image> constructor. │ │ │ │ + * Class: OpenLayers.Strategy.BBOX │ │ │ │ + * A simple strategy that reads new features when the viewport invalidates │ │ │ │ + * some bounds. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Layer> │ │ │ │ + * - <OpenLayers.Strategy> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.Image = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: isBaseLayer │ │ │ │ - * {Boolean} The layer is a base layer. Default is true. Set this property │ │ │ │ - * in the layer options │ │ │ │ - */ │ │ │ │ - isBaseLayer: true, │ │ │ │ +OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: url │ │ │ │ - * {String} URL of the image to use │ │ │ │ + * Property: bounds │ │ │ │ + * {<OpenLayers.Bounds>} The current data bounds (in the same projection │ │ │ │ + * as the layer - not always the same projection as the map). │ │ │ │ */ │ │ │ │ - url: null, │ │ │ │ + bounds: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: extent │ │ │ │ - * {<OpenLayers.Bounds>} The image bounds in map units. This extent will │ │ │ │ - * also be used as the default maxExtent for the layer. If you wish │ │ │ │ - * to have a maxExtent that is different than the image extent, set the │ │ │ │ - * maxExtent property of the options argument (as with any other layer). │ │ │ │ + /** │ │ │ │ + * Property: resolution │ │ │ │ + * {Float} The current data resolution. │ │ │ │ */ │ │ │ │ - extent: null, │ │ │ │ + resolution: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: size │ │ │ │ - * {<OpenLayers.Size>} The image size in pixels │ │ │ │ + * APIProperty: ratio │ │ │ │ + * {Float} The ratio of the data bounds to the viewport bounds (in each │ │ │ │ + * dimension). Default is 2. │ │ │ │ */ │ │ │ │ - size: null, │ │ │ │ + ratio: 2, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: tile │ │ │ │ - * {<OpenLayers.Tile.Image>} │ │ │ │ + /** │ │ │ │ + * Property: resFactor │ │ │ │ + * {Float} Optional factor used to determine when previously requested │ │ │ │ + * features are invalid. If set, the resFactor will be compared to the │ │ │ │ + * resolution of the previous request to the current map resolution. │ │ │ │ + * If resFactor > (old / new) and 1/resFactor < (old / new). If you │ │ │ │ + * set a resFactor of 1, data will be requested every time the │ │ │ │ + * resolution changes. If you set a resFactor of 3, data will be │ │ │ │ + * requested if the old resolution is 3 times the new, or if the new is │ │ │ │ + * 3 times the old. If the old bounds do not contain the new bounds │ │ │ │ + * new data will always be requested (with or without considering │ │ │ │ + * resFactor). │ │ │ │ */ │ │ │ │ - tile: null, │ │ │ │ + resFactor: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: aspectRatio │ │ │ │ - * {Float} The ratio of height/width represented by a single pixel in the │ │ │ │ - * graphic │ │ │ │ + * Property: response │ │ │ │ + * {<OpenLayers.Protocol.Response>} The protocol response object returned │ │ │ │ + * by the layer protocol. │ │ │ │ */ │ │ │ │ - aspectRatio: null, │ │ │ │ + response: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.Image │ │ │ │ - * Create a new image layer │ │ │ │ + * Constructor: OpenLayers.Strategy.BBOX │ │ │ │ + * Create a new BBOX strategy. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} A name for the layer. │ │ │ │ - * url - {String} Relative or absolute path to the image │ │ │ │ - * extent - {<OpenLayers.Bounds>} The extent represented by the image │ │ │ │ - * size - {<OpenLayers.Size>} The size (in pixels) of the image │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - initialize: function(name, url, extent, size, options) { │ │ │ │ - this.url = url; │ │ │ │ - this.extent = extent; │ │ │ │ - this.maxExtent = extent; │ │ │ │ - this.size = size; │ │ │ │ - OpenLayers.Layer.prototype.initialize.apply(this, [name, options]); │ │ │ │ │ │ │ │ - this.aspectRatio = (this.extent.getHeight() / this.size.h) / │ │ │ │ - (this.extent.getWidth() / this.size.w); │ │ │ │ + /** │ │ │ │ + * Method: activate │ │ │ │ + * Set up strategy with regard to reading new batches of remote data. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The strategy was successfully activated. │ │ │ │ + */ │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + "moveend": this.update, │ │ │ │ + "refresh": this.update, │ │ │ │ + "visibilitychanged": this.update, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.update(); │ │ │ │ + } │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroy │ │ │ │ - * Destroy this layer │ │ │ │ + * Method: deactivate │ │ │ │ + * Tear down strategy with regard to reading new batches of remote data. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.tile) { │ │ │ │ - this.removeTileMonitoringHooks(this.tile); │ │ │ │ - this.tile.destroy(); │ │ │ │ - this.tile = null; │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.layer.events.un({ │ │ │ │ + "moveend": this.update, │ │ │ │ + "refresh": this.update, │ │ │ │ + "visibilitychanged": this.update, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ } │ │ │ │ - OpenLayers.Layer.prototype.destroy.apply(this, arguments); │ │ │ │ + return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ + * Method: update │ │ │ │ + * Callback function called on "moveend" or "refresh" layer events. │ │ │ │ * │ │ │ │ - * Paramters: │ │ │ │ - * obj - {Object} An optional layer (is this ever used?) │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} Optional object whose properties will determine │ │ │ │ + * the behaviour of this Strategy │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.Image>} An exact copy of this layer │ │ │ │ + * Valid options include: │ │ │ │ + * force - {Boolean} if true, new data must be unconditionally read. │ │ │ │ + * noAbort - {Boolean} if true, do not abort previous requests. │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.Image(this.name, │ │ │ │ - this.url, │ │ │ │ - this.extent, │ │ │ │ - this.size, │ │ │ │ - this.getOptions()); │ │ │ │ + update: function(options) { │ │ │ │ + var mapBounds = this.getMapBounds(); │ │ │ │ + if (mapBounds !== null && ((options && options.force) || │ │ │ │ + (this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds)))) { │ │ │ │ + this.calculateBounds(mapBounds); │ │ │ │ + this.resolution = this.layer.map.getResolution(); │ │ │ │ + this.triggerRead(options); │ │ │ │ } │ │ │ │ - │ │ │ │ - //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: setMap │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * Method: getMapBounds │ │ │ │ + * Get the map bounds expressed in the same projection as this layer. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} Map bounds in the projection of the layer. │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - /** │ │ │ │ - * If nothing to do with resolutions has been set, assume a single │ │ │ │ - * resolution determined by ratio*extent/size - if an image has a │ │ │ │ - * pixel aspect ratio different than one (as calculated above), the │ │ │ │ - * image will be stretched in one dimension only. │ │ │ │ - */ │ │ │ │ - if (this.options.maxResolution == null) { │ │ │ │ - this.options.maxResolution = this.aspectRatio * │ │ │ │ - this.extent.getWidth() / │ │ │ │ - this.size.w; │ │ │ │ + getMapBounds: function() { │ │ │ │ + if (this.layer.map === null) { │ │ │ │ + return null; │ │ │ │ } │ │ │ │ - OpenLayers.Layer.prototype.setMap.apply(this, arguments); │ │ │ │ + var bounds = this.layer.map.getExtent(); │ │ │ │ + if (bounds && !this.layer.projection.equals( │ │ │ │ + this.layer.map.getProjectionObject())) { │ │ │ │ + bounds = bounds.clone().transform( │ │ │ │ + this.layer.map.getProjectionObject(), this.layer.projection │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return bounds; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: moveTo │ │ │ │ - * Create the tile for the image or resize it for the new resolution │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: invalidBounds │ │ │ │ + * Determine whether the previously requested set of features is invalid. │ │ │ │ + * This occurs when the new map bounds do not contain the previously │ │ │ │ + * requested bounds. In addition, if <resFactor> is set, it will be │ │ │ │ + * considered. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - * zoomChanged - {Boolean} │ │ │ │ - * dragging - {Boolean} │ │ │ │ + * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be │ │ │ │ + * retrieved from the map object if not provided │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ - │ │ │ │ - var firstRendering = (this.tile == null); │ │ │ │ - │ │ │ │ - if (zoomChanged || firstRendering) { │ │ │ │ - │ │ │ │ - //determine new tile size │ │ │ │ - this.setTileSize(); │ │ │ │ - │ │ │ │ - //determine new position (upper left corner of new bounds) │ │ │ │ - var ulPx = this.map.getLayerPxFromLonLat({ │ │ │ │ - lon: this.extent.left, │ │ │ │ - lat: this.extent.top │ │ │ │ - }); │ │ │ │ - │ │ │ │ - if (firstRendering) { │ │ │ │ - //create the new tile │ │ │ │ - this.tile = new OpenLayers.Tile.Image(this, ulPx, this.extent, │ │ │ │ - null, this.tileSize); │ │ │ │ - this.addTileMonitoringHooks(this.tile); │ │ │ │ - } else { │ │ │ │ - //just resize the tile and set it's new position │ │ │ │ - this.tile.size = this.tileSize.clone(); │ │ │ │ - this.tile.position = ulPx.clone(); │ │ │ │ - } │ │ │ │ - this.tile.draw(); │ │ │ │ + invalidBounds: function(mapBounds) { │ │ │ │ + if (!mapBounds) { │ │ │ │ + mapBounds = this.getMapBounds(); │ │ │ │ + } │ │ │ │ + var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds); │ │ │ │ + if (!invalid && this.resFactor) { │ │ │ │ + var ratio = this.resolution / this.layer.map.getResolution(); │ │ │ │ + invalid = (ratio >= this.resFactor || ratio <= (1 / this.resFactor)); │ │ │ │ } │ │ │ │ + return invalid; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Set the tile size based on the map size. │ │ │ │ + * Method: calculateBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be │ │ │ │ + * retrieved from the map object if not provided │ │ │ │ */ │ │ │ │ - setTileSize: function() { │ │ │ │ - var tileWidth = this.extent.getWidth() / this.map.getResolution(); │ │ │ │ - var tileHeight = this.extent.getHeight() / this.map.getResolution(); │ │ │ │ - this.tileSize = new OpenLayers.Size(tileWidth, tileHeight); │ │ │ │ + calculateBounds: function(mapBounds) { │ │ │ │ + if (!mapBounds) { │ │ │ │ + mapBounds = this.getMapBounds(); │ │ │ │ + } │ │ │ │ + var center = mapBounds.getCenterLonLat(); │ │ │ │ + var dataWidth = mapBounds.getWidth() * this.ratio; │ │ │ │ + var dataHeight = mapBounds.getHeight() * this.ratio; │ │ │ │ + this.bounds = new OpenLayers.Bounds( │ │ │ │ + center.lon - (dataWidth / 2), │ │ │ │ + center.lat - (dataHeight / 2), │ │ │ │ + center.lon + (dataWidth / 2), │ │ │ │ + center.lat + (dataHeight / 2) │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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>} │ │ │ │ + /** │ │ │ │ + * Method: triggerRead │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} Additional options for the protocol's read method │ │ │ │ + * (optional) │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Protocol.Response>} The protocol response object │ │ │ │ + * returned by the layer protocol. │ │ │ │ */ │ │ │ │ - addTileMonitoringHooks: function(tile) { │ │ │ │ - tile.onLoadStart = function() { │ │ │ │ - this.events.triggerEvent("loadstart"); │ │ │ │ - }; │ │ │ │ - tile.events.register("loadstart", this, tile.onLoadStart); │ │ │ │ - │ │ │ │ - tile.onLoadEnd = function() { │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ + triggerRead: function(options) { │ │ │ │ + if (this.response && !(options && options.noAbort === true)) { │ │ │ │ + this.layer.protocol.abort(this.response); │ │ │ │ + this.layer.events.triggerEvent("loadend"); │ │ │ │ + } │ │ │ │ + var evt = { │ │ │ │ + filter: this.createFilter() │ │ │ │ }; │ │ │ │ - tile.events.register("loadend", this, tile.onLoadEnd); │ │ │ │ - tile.events.register("unload", this, tile.onLoadEnd); │ │ │ │ + this.layer.events.triggerEvent("loadstart", evt); │ │ │ │ + this.response = this.layer.protocol.read( │ │ │ │ + OpenLayers.Util.applyDefaults({ │ │ │ │ + filter: evt.filter, │ │ │ │ + callback: this.merge, │ │ │ │ + scope: this │ │ │ │ + }, options)); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: removeTileMonitoringHooks │ │ │ │ - * This function takes a tile as input and removes the tile hooks │ │ │ │ - * that were added in <addTileMonitoringHooks>. │ │ │ │ + /** │ │ │ │ + * Method: createFilter │ │ │ │ + * Creates a spatial BBOX filter. If the layer that this strategy belongs │ │ │ │ + * to has a filter property, this filter will be combined with the BBOX │ │ │ │ + * filter. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * tile - {<OpenLayers.Tile>} │ │ │ │ + * Returns │ │ │ │ + * {<OpenLayers.Filter>} The filter object. │ │ │ │ */ │ │ │ │ - removeTileMonitoringHooks: function(tile) { │ │ │ │ - tile.unload(); │ │ │ │ - tile.events.un({ │ │ │ │ - "loadstart": tile.onLoadStart, │ │ │ │ - "loadend": tile.onLoadEnd, │ │ │ │ - "unload": tile.onLoadEnd, │ │ │ │ - scope: this │ │ │ │ + createFilter: function() { │ │ │ │ + var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ + value: this.bounds, │ │ │ │ + projection: this.layer.projection │ │ │ │ }); │ │ │ │ + if (this.layer.filter) { │ │ │ │ + filter = new OpenLayers.Filter.Logical({ │ │ │ │ + type: OpenLayers.Filter.Logical.AND, │ │ │ │ + filters: [this.layer.filter, filter] │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + return filter; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setUrl │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * newUrl - {String} │ │ │ │ - */ │ │ │ │ - setUrl: function(newUrl) { │ │ │ │ - this.url = newUrl; │ │ │ │ - this.tile.draw(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: getURL │ │ │ │ - * The url we return is always the same (the image itself never changes) │ │ │ │ - * so we can ignore the bounds parameter (it will always be the same, │ │ │ │ - * anyways) │ │ │ │ - * │ │ │ │ + * Method: merge │ │ │ │ + * Given a list of features, determine which ones to add 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: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * resp - {<OpenLayers.Protocol.Response>} The response object passed │ │ │ │ + * by the protocol. │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - return this.url; │ │ │ │ + merge: function(resp) { │ │ │ │ + this.layer.destroyFeatures(); │ │ │ │ + if (resp.success()) { │ │ │ │ + var features = resp.features; │ │ │ │ + if (features && features.length > 0) { │ │ │ │ + var remote = this.layer.projection; │ │ │ │ + var local = this.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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.layer.addFeatures(features); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.bounds = null; │ │ │ │ + } │ │ │ │ + this.response = null; │ │ │ │ + this.layer.events.triggerEvent("loadend", { │ │ │ │ + response: resp │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Image" │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.BBOX" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/WMTS.js │ │ │ │ + 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/Layer/Grid.js │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ + * @requires OpenLayers/Geometry/Point.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.WMTS │ │ │ │ - * Instances of the WMTS class allow viewing of tiles from a service that │ │ │ │ - * implements the OGC WMTS specification version 1.0.0. │ │ │ │ + * 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.Layer.Grid> │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.WMTS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ +OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} The layer will be considered a base layer. Default is true. │ │ │ │ + * Property: point │ │ │ │ + * {<OpenLayers.Feature.Vector>} The currently drawn point │ │ │ │ */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + point: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: version │ │ │ │ - * {String} WMTS version. Default is "1.0.0". │ │ │ │ + * Property: layer │ │ │ │ + * {<OpenLayers.Layer.Vector>} The temporary drawing layer │ │ │ │ */ │ │ │ │ - version: "1.0.0", │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: requestEncoding │ │ │ │ - * {String} Request encoding. Can be "REST" or "KVP". Default is "KVP". │ │ │ │ + * APIProperty: multi │ │ │ │ + * {Boolean} Cast features to multi-part geometries before passing to the │ │ │ │ + * layer. Default is false. │ │ │ │ */ │ │ │ │ - requestEncoding: "KVP", │ │ │ │ + multi: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: url │ │ │ │ - * {String|Array(String)} The base URL or request URL template for the WMTS │ │ │ │ - * service. Must be provided. Array is only supported for base URLs, not │ │ │ │ - * for request URL templates. URL templates are only supported for │ │ │ │ - * REST <requestEncoding>. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - url: null, │ │ │ │ + citeCompliant: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layer │ │ │ │ - * {String} The layer identifier advertised by the WMTS service. Must be │ │ │ │ - * provided. │ │ │ │ + * Property: mouseDown │ │ │ │ + * {Boolean} The mouse is down │ │ │ │ */ │ │ │ │ - layer: null, │ │ │ │ + mouseDown: false, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: matrixSet │ │ │ │ - * {String} One of the advertised matrix set identifiers. Must be provided. │ │ │ │ + /** │ │ │ │ + * Property: stoppedDown │ │ │ │ + * {Boolean} Indicate whether the last mousedown stopped the event │ │ │ │ + * propagation. │ │ │ │ */ │ │ │ │ - matrixSet: null, │ │ │ │ + stoppedDown: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: style │ │ │ │ - * {String} One of the advertised layer styles. Must be provided. │ │ │ │ + /** │ │ │ │ + * Property: lastDown │ │ │ │ + * {<OpenLayers.Pixel>} Location of the last mouse down │ │ │ │ */ │ │ │ │ - style: null, │ │ │ │ + lastDown: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: format │ │ │ │ - * {String} The image MIME type. Default is "image/jpeg". │ │ │ │ + /** │ │ │ │ + * Property: lastUp │ │ │ │ + * {<OpenLayers.Pixel>} │ │ │ │ */ │ │ │ │ - format: "image/jpeg", │ │ │ │ + lastUp: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: tileOrigin │ │ │ │ - * {<OpenLayers.LonLat>} The top-left corner of the tile matrix in map │ │ │ │ - * units. If the tile origin for each matrix in a set is different, │ │ │ │ - * the <matrixIds> should include a topLeftCorner property. If │ │ │ │ - * not provided, the tile origin will default to the top left corner │ │ │ │ - * of the layer <maxExtent>. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - tileOrigin: null, │ │ │ │ + persist: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: tileFullExtent │ │ │ │ - * {<OpenLayers.Bounds>} The full extent of the tile set. If not supplied, │ │ │ │ - * the layer's <maxExtent> property will be used. │ │ │ │ + * APIProperty: stopDown │ │ │ │ + * {Boolean} Stop event propagation on mousedown. Must be false to │ │ │ │ + * allow "pan while drawing". Defaults to false. │ │ │ │ */ │ │ │ │ - tileFullExtent: null, │ │ │ │ + stopDown: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: formatSuffix │ │ │ │ - * {String} For REST request encoding, an image format suffix must be │ │ │ │ - * included in the request. If not provided, the suffix will be derived │ │ │ │ - * from the <format> property. │ │ │ │ + * APIPropery: stopUp │ │ │ │ + * {Boolean} Stop event propagation on mouse. Must be false to │ │ │ │ + * allow "pan while dragging". Defaults to fase. │ │ │ │ */ │ │ │ │ - formatSuffix: null, │ │ │ │ + stopUp: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: matrixIds │ │ │ │ - * {Array} A list of tile matrix identifiers. If not provided, the matrix │ │ │ │ - * identifiers will be assumed to be integers corresponding to the │ │ │ │ - * map zoom level. If a list of strings is provided, each item should │ │ │ │ - * be the matrix identifier that corresponds to the map zoom level. │ │ │ │ - * Additionally, a list of objects can be provided. Each object should │ │ │ │ - * describe the matrix as presented in the WMTS capabilities. These │ │ │ │ - * objects should have the propertes shown below. │ │ │ │ - * │ │ │ │ - * Matrix properties: │ │ │ │ - * identifier - {String} The matrix identifier (required). │ │ │ │ - * scaleDenominator - {Number} The matrix scale denominator. │ │ │ │ - * topLeftCorner - {<OpenLayers.LonLat>} The top left corner of the │ │ │ │ - * matrix. Must be provided if different than the layer <tileOrigin>. │ │ │ │ - * tileWidth - {Number} The tile width for the matrix. Must be provided │ │ │ │ - * if different than the width given in the layer <tileSize>. │ │ │ │ - * tileHeight - {Number} The tile height for the matrix. Must be provided │ │ │ │ - * if different than the height given in the layer <tileSize>. │ │ │ │ + * Property: layerOptions │ │ │ │ + * {Object} Any optional properties to be set on the sketch layer. │ │ │ │ */ │ │ │ │ - matrixIds: null, │ │ │ │ + layerOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: dimensions │ │ │ │ - * {Array} For RESTful request encoding, extra dimensions may be specified. │ │ │ │ - * Items in this list should be property names in the <params> object. │ │ │ │ - * Values of extra dimensions will be determined from the corresponding │ │ │ │ - * values in the <params> object. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - dimensions: null, │ │ │ │ + pixelTolerance: 5, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: params │ │ │ │ - * {Object} Extra parameters to include in tile requests. For KVP │ │ │ │ - * <requestEncoding>, these properties will be encoded in the request │ │ │ │ - * query string. For REST <requestEncoding>, these properties will │ │ │ │ - * become part of the request path, with order determined by the │ │ │ │ - * <dimensions> list. │ │ │ │ + * Property: lastTouchPx │ │ │ │ + * {<OpenLayers.Pixel>} The last pixel used to know the distance between │ │ │ │ + * two touches (for double touch). │ │ │ │ */ │ │ │ │ - params: null, │ │ │ │ + lastTouchPx: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: zoomOffset │ │ │ │ - * {Number} If your cache has more 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). Additionally, if this layer is to be used │ │ │ │ - * as an overlay and the cache has fewer zoom levels than the base │ │ │ │ - * layer, you can supply a negative zoomOffset. For example, if a │ │ │ │ - * map zoom level of 1 corresponds to your cache level zero, you would │ │ │ │ - * supply a -1 zoomOffset (and set the maxResolution of the layer │ │ │ │ - * appropriately). The zoomOffset value has no effect if complete │ │ │ │ - * matrix definitions (including scaleDenominator) are supplied in │ │ │ │ - * the <matrixIds> property. Defaults to 0 (no zoom offset). │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - zoomOffset: 0, │ │ │ │ + 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); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: activate │ │ │ │ + * turn on the handler │ │ │ │ */ │ │ │ │ - serverResolutions: null, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: formatSuffixMap │ │ │ │ - * {Object} a map between WMTS 'format' request parameter and tile image file suffix │ │ │ │ + * Method: createFeature │ │ │ │ + * Add temporary features │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * pixel - {<OpenLayers.Pixel>} A pixel location on the map. │ │ │ │ */ │ │ │ │ - formatSuffixMap: { │ │ │ │ - "image/png": "png", │ │ │ │ - "image/png8": "png", │ │ │ │ - "image/png24": "png", │ │ │ │ - "image/png32": "png", │ │ │ │ - "png": "png", │ │ │ │ - "image/jpeg": "jpg", │ │ │ │ - "image/jpg": "jpg", │ │ │ │ - "jpeg": "jpg", │ │ │ │ - "jpg": "jpg" │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: matrix │ │ │ │ - * {Object} Matrix definition for the current map resolution. Updated by │ │ │ │ - * the <updateMatrixProperties> method. │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * turn off the handler │ │ │ │ */ │ │ │ │ - matrix: null, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.WMTS │ │ │ │ - * Create a new WMTS layer. │ │ │ │ - * │ │ │ │ - * Example: │ │ │ │ - * (code) │ │ │ │ - * var wmts = new OpenLayers.Layer.WMTS({ │ │ │ │ - * name: "My WMTS Layer", │ │ │ │ - * url: "http://example.com/wmts", │ │ │ │ - * layer: "layer_id", │ │ │ │ - * style: "default", │ │ │ │ - * matrixSet: "matrix_id" │ │ │ │ - * }); │ │ │ │ - * (end) │ │ │ │ + * Method: destroyFeature │ │ │ │ + * Destroy the temporary geometries │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * config - {Object} Configuration properties for the layer. │ │ │ │ - * │ │ │ │ - * Required configuration properties: │ │ │ │ - * url - {String} The base url for the service. See the <url> property. │ │ │ │ - * layer - {String} The layer identifier. See the <layer> property. │ │ │ │ - * style - {String} The layer style identifier. See the <style> property. │ │ │ │ - * matrixSet - {String} The tile matrix set identifier. See the <matrixSet> │ │ │ │ - * property. │ │ │ │ - * │ │ │ │ - * Any other documented layer properties can be provided in the config object. │ │ │ │ + * force - {Boolean} Destroy even if persist is true. │ │ │ │ */ │ │ │ │ - initialize: function(config) { │ │ │ │ - │ │ │ │ - // confirm required properties are supplied │ │ │ │ - var required = { │ │ │ │ - url: true, │ │ │ │ - layer: true, │ │ │ │ - style: true, │ │ │ │ - matrixSet: true │ │ │ │ - }; │ │ │ │ - for (var prop in required) { │ │ │ │ - if (!(prop in config)) { │ │ │ │ - throw new Error("Missing property '" + prop + "' in layer configuration."); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - config.params = OpenLayers.Util.upperCaseObject(config.params); │ │ │ │ - var args = [config.name, config.url, config.params, config]; │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, args); │ │ │ │ - │ │ │ │ - │ │ │ │ - // determine format suffix (for REST) │ │ │ │ - if (!this.formatSuffix) { │ │ │ │ - this.formatSuffix = this.formatSuffixMap[this.format] || this.format.split("/").pop(); │ │ │ │ + destroyFeature: function(force) { │ │ │ │ + if (this.layer && (force || !this.persist)) { │ │ │ │ + this.layer.destroyFeatures(); │ │ │ │ } │ │ │ │ + this.point = null; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // expand matrixIds (may be array of string or array of object) │ │ │ │ - if (this.matrixIds) { │ │ │ │ - var len = this.matrixIds.length; │ │ │ │ - if (len && typeof this.matrixIds[0] === "string") { │ │ │ │ - var ids = this.matrixIds; │ │ │ │ - this.matrixIds = new Array(len); │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ - this.matrixIds[i] = { │ │ │ │ - identifier: ids[i] │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Method: destroyPersistedFeature │ │ │ │ + * Destroy the persisted feature. │ │ │ │ + */ │ │ │ │ + destroyPersistedFeature: function() { │ │ │ │ + var layer = this.layer; │ │ │ │ + if (layer && layer.features.length > 1) { │ │ │ │ + this.layer.features[0].destroy(); │ │ │ │ } │ │ │ │ - │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setMap │ │ │ │ + * Method: finalize │ │ │ │ + * Finish the geometry and call the "done" callback. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * cancel - {Boolean} Call cancel instead of done callback. Default │ │ │ │ + * is false. │ │ │ │ */ │ │ │ │ - setMap: function() { │ │ │ │ - OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); │ │ │ │ + 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); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: updateMatrixProperties │ │ │ │ - * Called when map resolution changes to update matrix related properties. │ │ │ │ + * APIMethod: cancel │ │ │ │ + * Finish the geometry and call the "cancel" callback. │ │ │ │ */ │ │ │ │ - updateMatrixProperties: function() { │ │ │ │ - this.matrix = this.getMatrix(); │ │ │ │ - if (this.matrix) { │ │ │ │ - if (this.matrix.topLeftCorner) { │ │ │ │ - this.tileOrigin = this.matrix.topLeftCorner; │ │ │ │ - } │ │ │ │ - if (this.matrix.tileWidth && this.matrix.tileHeight) { │ │ │ │ - this.tileSize = new OpenLayers.Size( │ │ │ │ - this.matrix.tileWidth, this.matrix.tileHeight │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (!this.tileOrigin) { │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat( │ │ │ │ - this.maxExtent.left, this.maxExtent.top │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (!this.tileFullExtent) { │ │ │ │ - this.tileFullExtent = this.maxExtent; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + cancel: function() { │ │ │ │ + this.finalize(true); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: moveTo │ │ │ │ + * Method: click │ │ │ │ + * Handle clicks. Clicks are stopped from propagating to other listeners │ │ │ │ + * on map.events or other dom elements. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to │ │ │ │ - * do some init work in that case. │ │ │ │ - * dragging - {Boolean} │ │ │ │ + * evt - {Event} The browser event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ */ │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - if (zoomChanged || !this.matrix) { │ │ │ │ - this.updateMatrixProperties(); │ │ │ │ - } │ │ │ │ - return OpenLayers.Layer.Grid.prototype.moveTo.apply(this, arguments); │ │ │ │ + click: function(evt) { │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ + return false; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ + * Method: dblclick │ │ │ │ + * Handle double-clicks. Double-clicks are stopped from propagating to other │ │ │ │ + * listeners on map.events or other dom elements. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * obj - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.WMTS>} An exact clone of this <OpenLayers.Layer.WMTS> │ │ │ │ + * evt - {Event} The browser event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.WMTS(this.options); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - //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; │ │ │ │ + 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: getIdentifier │ │ │ │ - * Get the current index in the matrixIds array. │ │ │ │ + * Method: drawFeature │ │ │ │ + * Render features on the temporary layer. │ │ │ │ */ │ │ │ │ - getIdentifier: function() { │ │ │ │ - return this.getServerZoom(); │ │ │ │ + drawFeature: function() { │ │ │ │ + this.layer.drawFeature(this.point, this.style); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getMatrix │ │ │ │ - * Get the appropriate matrix definition for the current map resolution. │ │ │ │ + * Method: getGeometry │ │ │ │ + * Return the sketch geometry. If <multi> is true, this will return │ │ │ │ + * a multi-part geometry. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Geometry.Point>} │ │ │ │ */ │ │ │ │ - getMatrix: function() { │ │ │ │ - var matrix; │ │ │ │ - if (!this.matrixIds || this.matrixIds.length === 0) { │ │ │ │ - matrix = { │ │ │ │ - identifier: this.getIdentifier() │ │ │ │ - }; │ │ │ │ - } else { │ │ │ │ - // get appropriate matrix given the map scale if possible │ │ │ │ - if ("scaleDenominator" in this.matrixIds[0]) { │ │ │ │ - // scale denominator calculation based on WMTS spec │ │ │ │ - var denom = │ │ │ │ - OpenLayers.METERS_PER_INCH * │ │ │ │ - OpenLayers.INCHES_PER_UNIT[this.units] * │ │ │ │ - this.getServerResolution() / 0.28E-3; │ │ │ │ - var diff = Number.POSITIVE_INFINITY; │ │ │ │ - var delta; │ │ │ │ - for (var i = 0, ii = this.matrixIds.length; i < ii; ++i) { │ │ │ │ - delta = Math.abs(1 - (this.matrixIds[i].scaleDenominator / denom)); │ │ │ │ - if (delta < diff) { │ │ │ │ - diff = delta; │ │ │ │ - matrix = this.matrixIds[i]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - // fall back on zoom as index │ │ │ │ - matrix = this.matrixIds[this.getIdentifier()]; │ │ │ │ - } │ │ │ │ + getGeometry: function() { │ │ │ │ + var geometry = this.point && this.point.geometry; │ │ │ │ + if (geometry && this.multi) { │ │ │ │ + geometry = new OpenLayers.Geometry.MultiPoint([geometry]); │ │ │ │ } │ │ │ │ - return matrix; │ │ │ │ + return geometry; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getTileInfo │ │ │ │ - * Get tile information for a given location at the current map resolution. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * loc - {<OpenLayers.LonLat} A location in map coordinates. │ │ │ │ + /** │ │ │ │ + * Method: geometryClone │ │ │ │ + * Return a clone of the relevant geometry. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} An object with "col", "row", "i", and "j" properties. The col │ │ │ │ - * and row values are zero based tile indexes from the top left. The │ │ │ │ - * i and j values are the number of pixels to the left and top │ │ │ │ - * (respectively) of the given location within the target tile. │ │ │ │ + * {<OpenLayers.Geometry>} │ │ │ │ */ │ │ │ │ - getTileInfo: function(loc) { │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - │ │ │ │ - var fx = (loc.lon - this.tileOrigin.lon) / (res * this.tileSize.w); │ │ │ │ - var fy = (this.tileOrigin.lat - loc.lat) / (res * this.tileSize.h); │ │ │ │ - │ │ │ │ - var col = Math.floor(fx); │ │ │ │ - var row = Math.floor(fy); │ │ │ │ - │ │ │ │ - return { │ │ │ │ - col: col, │ │ │ │ - row: row, │ │ │ │ - i: Math.floor((fx - col) * this.tileSize.w), │ │ │ │ - j: Math.floor((fy - row) * this.tileSize.h) │ │ │ │ - }; │ │ │ │ + geometryClone: function() { │ │ │ │ + var geom = this.getGeometry(); │ │ │ │ + return geom && geom.clone(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getURL │ │ │ │ + * Method: mousedown │ │ │ │ + * Handle mousedown. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * evt - {Event} The browser event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ + */ │ │ │ │ + mousedown: function(evt) { │ │ │ │ + return this.down(evt); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: touchstart │ │ │ │ + * Handle touchstart. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {String} A URL for the tile corresponding to the given bounds. │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} The browser event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var url = ""; │ │ │ │ - if (!this.tileFullExtent || this.tileFullExtent.intersectsBounds(bounds)) { │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + this.lastTouchPx = evt.xy; │ │ │ │ + return this.down(evt); │ │ │ │ + }, │ │ │ │ │ │ │ │ - var center = bounds.getCenterLonLat(); │ │ │ │ - var info = this.getTileInfo(center); │ │ │ │ - var matrixId = this.matrix.identifier; │ │ │ │ - var dimensions = this.dimensions, │ │ │ │ - params; │ │ │ │ + /** │ │ │ │ + * Method: mousemove │ │ │ │ + * Handle mousemove. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} The browser event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ + */ │ │ │ │ + mousemove: function(evt) { │ │ │ │ + return this.move(evt); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (OpenLayers.Util.isArray(this.url)) { │ │ │ │ - url = this.selectUrl([ │ │ │ │ - this.version, this.style, this.matrixSet, │ │ │ │ - this.matrix.identifier, info.row, info.col │ │ │ │ - ].join(","), this.url); │ │ │ │ - } else { │ │ │ │ - url = this.url; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (this.requestEncoding.toUpperCase() === "REST") { │ │ │ │ - params = this.params; │ │ │ │ - if (url.indexOf("{") !== -1) { │ │ │ │ - var template = url.replace(/\{/g, "${"); │ │ │ │ - var context = { │ │ │ │ - // spec does not make clear if capital S or not │ │ │ │ - style: this.style, │ │ │ │ - Style: this.style, │ │ │ │ - TileMatrixSet: this.matrixSet, │ │ │ │ - TileMatrix: this.matrix.identifier, │ │ │ │ - TileRow: info.row, │ │ │ │ - TileCol: info.col │ │ │ │ - }; │ │ │ │ - if (dimensions) { │ │ │ │ - var dimension, i; │ │ │ │ - for (i = dimensions.length - 1; i >= 0; --i) { │ │ │ │ - dimension = dimensions[i]; │ │ │ │ - context[dimension] = params[dimension.toUpperCase()]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - url = OpenLayers.String.format(template, context); │ │ │ │ - } else { │ │ │ │ - // include 'version', 'layer' and 'style' in tile resource url │ │ │ │ - var path = this.version + "/" + this.layer + "/" + this.style + "/"; │ │ │ │ + /** │ │ │ │ + * Method: mouseup │ │ │ │ + * Handle mouseup. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} The browser event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ + */ │ │ │ │ + mouseup: function(evt) { │ │ │ │ + return this.up(evt); │ │ │ │ + }, │ │ │ │ │ │ │ │ - // append optional dimension path elements │ │ │ │ - if (dimensions) { │ │ │ │ - for (var i = 0; i < dimensions.length; i++) { │ │ │ │ - if (params[dimensions[i]]) { │ │ │ │ - path = path + params[dimensions[i]] + "/"; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ + }, │ │ │ │ │ │ │ │ - // append other required path elements │ │ │ │ - path = path + this.matrixSet + "/" + this.matrix.identifier + │ │ │ │ - "/" + info.row + "/" + info.col + "." + this.formatSuffix; │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (!url.match(/\/$/)) { │ │ │ │ - url = url + "/"; │ │ │ │ - } │ │ │ │ - url = url + path; │ │ │ │ - } │ │ │ │ - } else if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // assemble all required parameters │ │ │ │ - params = { │ │ │ │ - SERVICE: "WMTS", │ │ │ │ - REQUEST: "GetTile", │ │ │ │ - VERSION: this.version, │ │ │ │ - LAYER: this.layer, │ │ │ │ - STYLE: this.style, │ │ │ │ - TILEMATRIXSET: this.matrixSet, │ │ │ │ - TILEMATRIX: this.matrix.identifier, │ │ │ │ - TILEROW: info.row, │ │ │ │ - TILECOL: info.col, │ │ │ │ - FORMAT: this.format │ │ │ │ - }; │ │ │ │ - url = OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this, [params]); │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ } │ │ │ │ - return url; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: mergeNewParams │ │ │ │ - * Extend the existing layer <params> with new properties. Tiles will be │ │ │ │ - * reloaded with updated params in the request. │ │ │ │ - * │ │ │ │ + * Method: mouseout │ │ │ │ + * Handle mouse out. For better user experience reset mouseDown │ │ │ │ + * and stoppedDown when the mouse leaves the map viewport. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * newParams - {Object} Properties to extend to existing <params>. │ │ │ │ + * evt - {Event} The browser event │ │ │ │ */ │ │ │ │ - mergeNewParams: function(newParams) { │ │ │ │ - if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ - return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply( │ │ │ │ - this, [OpenLayers.Util.upperCaseObject(newParams)] │ │ │ │ - ); │ │ │ │ + mouseout: function(evt) { │ │ │ │ + if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ + this.stoppedDown = this.stopDown; │ │ │ │ + this.mouseDown = false; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.WMTS" │ │ │ │ + /** │ │ │ │ + * 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/Layer/MapGuide.js │ │ │ │ + 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/Request/XMLHttpRequest.js │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ + * @requires OpenLayers/Handler/Point.js │ │ │ │ + * @requires OpenLayers/Geometry/Point.js │ │ │ │ + * @requires OpenLayers/Geometry/LineString.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.MapGuide │ │ │ │ - * Instances of OpenLayers.Layer.MapGuide are used to display │ │ │ │ - * data from a MapGuide OS instance. │ │ │ │ + * 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.Layer.Grid> │ │ │ │ + * - <OpenLayers.Handler.Point> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} Treat this layer as a base layer. Default is true. │ │ │ │ - **/ │ │ │ │ - isBaseLayer: true, │ │ │ │ +OpenLayers.Handler.Path = OpenLayers.Class(OpenLayers.Handler.Point, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: useHttpTile │ │ │ │ - * {Boolean} use a tile cache exposed directly via a webserver rather than the │ │ │ │ - * via mapguide server. This does require extra configuration on the Mapguide Server, │ │ │ │ - * and will only work when singleTile is false. The url for the layer must be set to the │ │ │ │ - * webserver path rather than the Mapguide mapagent. │ │ │ │ - * See http://trac.osgeo.org/mapguide/wiki/CodeSamples/Tiles/ServingTilesViaHttp │ │ │ │ - **/ │ │ │ │ - useHttpTile: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: singleTile │ │ │ │ - * {Boolean} use tile server or request single tile image. │ │ │ │ - **/ │ │ │ │ - singleTile: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: useOverlay │ │ │ │ - * {Boolean} flag to indicate if the layer should be retrieved using │ │ │ │ - * GETMAPIMAGE (default) or using GETDYNAMICOVERLAY requests. │ │ │ │ - **/ │ │ │ │ - useOverlay: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: useAsyncOverlay │ │ │ │ - * {Boolean} indicates if the MapGuide site supports the asynchronous │ │ │ │ - * GETDYNAMICOVERLAY requests which is available in MapGuide Enterprise 2010 │ │ │ │ - * and MapGuide Open Source v2.0.3 or higher. The newer versions of MG │ │ │ │ - * is called asynchronously, allows selections to be drawn separately from │ │ │ │ - * the map and offers styling options. │ │ │ │ - * │ │ │ │ - * With older versions of MapGuide, set useAsyncOverlay=false. Note that in │ │ │ │ - * this case a synchronous AJAX call is issued and the mapname and session │ │ │ │ - * parameters must be used to initialize the layer, not the mapdefinition │ │ │ │ - * parameter. Also note that this will issue a synchronous AJAX request │ │ │ │ - * before the image request can be issued so the users browser may lock │ │ │ │ - * up if the MG Web tier does not respond in a timely fashion. │ │ │ │ - **/ │ │ │ │ - useAsyncOverlay: true, │ │ │ │ + * Property: line │ │ │ │ + * {<OpenLayers.Feature.Vector>} │ │ │ │ + */ │ │ │ │ + line: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: TILE_PARAMS │ │ │ │ - * {Object} Hashtable of default parameter key/value pairs for tiled layer │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - TILE_PARAMS: { │ │ │ │ - operation: 'GETTILEIMAGE', │ │ │ │ - version: '1.2.0' │ │ │ │ - }, │ │ │ │ + maxVertices: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: SINGLE_TILE_PARAMS │ │ │ │ - * {Object} Hashtable of default parameter key/value pairs for untiled layer │ │ │ │ + * Property: doubleTouchTolerance │ │ │ │ + * {Number} Maximum number of pixels between two touches for │ │ │ │ + * the gesture to be considered a "finalize feature" action. │ │ │ │ + * Default is 20. │ │ │ │ */ │ │ │ │ - SINGLE_TILE_PARAMS: { │ │ │ │ - operation: 'GETMAPIMAGE', │ │ │ │ - format: 'PNG', │ │ │ │ - locale: 'en', │ │ │ │ - clip: '1', │ │ │ │ - version: '1.0.0' │ │ │ │ - }, │ │ │ │ + doubleTouchTolerance: 20, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OVERLAY_PARAMS │ │ │ │ - * {Object} Hashtable of default parameter key/value pairs for untiled layer │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - OVERLAY_PARAMS: { │ │ │ │ - operation: 'GETDYNAMICMAPOVERLAYIMAGE', │ │ │ │ - format: 'PNG', │ │ │ │ - locale: 'en', │ │ │ │ - clip: '1', │ │ │ │ - version: '2.0.0' │ │ │ │ - }, │ │ │ │ + freehand: false, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: FOLDER_PARAMS │ │ │ │ - * {Object} Hashtable of parameter key/value pairs which describe │ │ │ │ - * the folder structure for tiles as configured in the mapguide │ │ │ │ - * serverconfig.ini section [TileServiceProperties] │ │ │ │ + /** │ │ │ │ + * 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'. │ │ │ │ */ │ │ │ │ - FOLDER_PARAMS: { │ │ │ │ - tileColumnsPerFolder: 30, │ │ │ │ - tileRowsPerFolder: 30, │ │ │ │ - format: 'png', │ │ │ │ - querystring: null │ │ │ │ - }, │ │ │ │ + freehandToggle: 'shiftKey', │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: defaultSize │ │ │ │ - * {<OpenLayers.Size>} Tile size as produced by MapGuide server │ │ │ │ - **/ │ │ │ │ - defaultSize: new OpenLayers.Size(300, 300), │ │ │ │ + /** │ │ │ │ + * Property: timerId │ │ │ │ + * {Integer} The timer used to test the double touch. │ │ │ │ + */ │ │ │ │ + timerId: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: tileOriginCorner │ │ │ │ - * {String} MapGuide tile server uses top-left as tile origin │ │ │ │ - **/ │ │ │ │ - tileOriginCorner: "tl", │ │ │ │ + /** │ │ │ │ + * Property: redoStack │ │ │ │ + * {Array} Stack containing points removed with <undo>. │ │ │ │ + */ │ │ │ │ + redoStack: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.MapGuide │ │ │ │ - * Create a new Mapguide layer, either tiled or untiled. │ │ │ │ - * │ │ │ │ - * For tiled layers, the 'groupName' and 'mapDefinition' values │ │ │ │ - * must be specified as parameters in the constructor. │ │ │ │ - * │ │ │ │ - * For untiled base layers, specify either combination of 'mapName' and │ │ │ │ - * 'session', or 'mapDefinition' and 'locale'. │ │ │ │ + * Constructor: OpenLayers.Handler.Path │ │ │ │ + * Create a new path hander │ │ │ │ * │ │ │ │ - * For older versions of MapGuide and overlay layers, set useAsyncOverlay │ │ │ │ - * to false and in this case mapName and session are required parameters │ │ │ │ - * for the constructor. │ │ │ │ + * 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 │ │ │ │ * │ │ │ │ - * NOTE: MapGuide OS uses a DPI value and degrees to meters conversion │ │ │ │ - * factor that are different than the defaults used in OpenLayers, │ │ │ │ - * so these must be adjusted accordingly in your application. │ │ │ │ - * See the MapGuide example for how to set these values for MGOS. │ │ │ │ + * 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: │ │ │ │ - * name - {String} Name of the layer displayed in the interface │ │ │ │ - * url - {String} Location of the MapGuide mapagent executable │ │ │ │ - * (e.g. http://localhost:8008/mapguide/mapagent/mapagent.fcgi) │ │ │ │ - * params - {Object} hashtable of additional parameters to use. Some │ │ │ │ - * parameters may require additional code on the server. The ones that │ │ │ │ - * you may want to use are: │ │ │ │ - * - mapDefinition - {String} The MapGuide resource definition │ │ │ │ - * (e.g. Library://Samples/Gmap/Maps/gmapTiled.MapDefinition) │ │ │ │ - * - locale - Locale setting │ │ │ │ - * (for untiled overlays layers only) │ │ │ │ - * - mapName - {String} Name of the map as stored in the MapGuide session. │ │ │ │ - * (for untiled layers with a session parameter only) │ │ │ │ - * - session - { String} MapGuide session ID │ │ │ │ - * (for untiled overlays layers only) │ │ │ │ - * - basemaplayergroupname - {String} GroupName for tiled MapGuide layers only │ │ │ │ - * - format - Image format to be returned (for untiled overlay layers only) │ │ │ │ - * - showLayers - {String} A comma separated list of GUID's for the │ │ │ │ - * layers to display eg: 'cvc-xcv34,453-345-345sdf'. │ │ │ │ - * - hideLayers - {String} A comma separated list of GUID's for the │ │ │ │ - * layers to hide eg: 'cvc-xcv34,453-345-345sdf'. │ │ │ │ - * - showGroups - {String} A comma separated list of GUID's for the │ │ │ │ - * groups to display eg: 'cvc-xcv34,453-345-345sdf'. │ │ │ │ - * - hideGroups - {String} A comma separated list of GUID's for the │ │ │ │ - * groups to hide eg: 'cvc-xcv34,453-345-345sdf' │ │ │ │ - * - selectionXml - {String} A selection xml string Some server plumbing │ │ │ │ - * is required to read such a value. │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer; │ │ │ │ - * will vary depending if tiled or untiled maps are being requested │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new │ │ │ │ + * feature. │ │ │ │ */ │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ │ │ │ │ - // unless explicitly set in options, if the layer is transparent, │ │ │ │ - // it will be an overlay │ │ │ │ - if (options == null || options.isBaseLayer == null) { │ │ │ │ - this.isBaseLayer = ((this.transparent != "true") && │ │ │ │ - (this.transparent != 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (options && options.useOverlay != null) { │ │ │ │ - this.useOverlay = options.useOverlay; │ │ │ │ + /** │ │ │ │ + * Method: destroyPersistedFeature │ │ │ │ + * Destroy the persisted feature. │ │ │ │ + */ │ │ │ │ + destroyPersistedFeature: function() { │ │ │ │ + var layer = this.layer; │ │ │ │ + if (layer && layer.features.length > 2) { │ │ │ │ + this.layer.features[0].destroy(); │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - //initialize for untiled layers │ │ │ │ - if (this.singleTile) { │ │ │ │ - if (this.useOverlay) { │ │ │ │ - OpenLayers.Util.applyDefaults( │ │ │ │ - this.params, │ │ │ │ - this.OVERLAY_PARAMS │ │ │ │ - ); │ │ │ │ - if (!this.useAsyncOverlay) { │ │ │ │ - this.params.version = "1.0.0"; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Util.applyDefaults( │ │ │ │ - this.params, │ │ │ │ - this.SINGLE_TILE_PARAMS │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - //initialize for tiled layers │ │ │ │ - if (this.useHttpTile) { │ │ │ │ - OpenLayers.Util.applyDefaults( │ │ │ │ - this.params, │ │ │ │ - this.FOLDER_PARAMS │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - OpenLayers.Util.applyDefaults( │ │ │ │ - this.params, │ │ │ │ - this.TILE_PARAMS │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - this.setTileSize(this.defaultSize); │ │ │ │ + /** │ │ │ │ + * Method: removePoint │ │ │ │ + * Destroy the temporary point. │ │ │ │ + */ │ │ │ │ + removePoint: function() { │ │ │ │ + if (this.point) { │ │ │ │ + this.layer.removeFeatures([this.point]); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ + * Method: addPoint │ │ │ │ + * Add point to geometry. Send the point index to override │ │ │ │ + * the behavior of LinearRing that disregards adding duplicate points. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.MapGuide>} An exact clone of this layer │ │ │ │ + * Parameters: │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The pixel location for the new point. │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.MapGuide(this.name, │ │ │ │ - this.url, │ │ │ │ - this.params, │ │ │ │ - this.getOptions()); │ │ │ │ - } │ │ │ │ - //get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - │ │ │ │ - return obj; │ │ │ │ + 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: getURL │ │ │ │ - * Return a query string for this layer │ │ │ │ + * 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: │ │ │ │ - * 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. │ │ │ │ + * x - {Number} The x-coordinate of the point. │ │ │ │ + * y - {Number} The y-coordinate of the point. │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - var url; │ │ │ │ - var center = bounds.getCenterLonLat(); │ │ │ │ - var mapSize = this.map.getSize(); │ │ │ │ - │ │ │ │ - if (this.singleTile) { │ │ │ │ - //set up the call for GETMAPIMAGE or GETDYNAMICMAPOVERLAY with │ │ │ │ - //dynamic map parameters │ │ │ │ - var params = { │ │ │ │ - setdisplaydpi: OpenLayers.DOTS_PER_INCH, │ │ │ │ - setdisplayheight: mapSize.h * this.ratio, │ │ │ │ - setdisplaywidth: mapSize.w * this.ratio, │ │ │ │ - setviewcenterx: center.lon, │ │ │ │ - setviewcentery: center.lat, │ │ │ │ - setviewscale: this.map.getScale() │ │ │ │ - }; │ │ │ │ - │ │ │ │ - if (this.useOverlay && !this.useAsyncOverlay) { │ │ │ │ - //first we need to call GETVISIBLEMAPEXTENT to set the extent │ │ │ │ - var getVisParams = {}; │ │ │ │ - getVisParams = OpenLayers.Util.extend(getVisParams, params); │ │ │ │ - getVisParams.operation = "GETVISIBLEMAPEXTENT"; │ │ │ │ - getVisParams.version = "1.0.0"; │ │ │ │ - getVisParams.session = this.params.session; │ │ │ │ - getVisParams.mapName = this.params.mapName; │ │ │ │ - getVisParams.format = 'text/xml'; │ │ │ │ - url = this.getFullRequestString(getVisParams); │ │ │ │ - │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ - url: url, │ │ │ │ - async: false │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - //construct the full URL │ │ │ │ - url = this.getFullRequestString(params); │ │ │ │ - } else { │ │ │ │ - │ │ │ │ - //tiled version │ │ │ │ - var currentRes = this.map.getResolution(); │ │ │ │ - var colidx = Math.floor((bounds.left - this.maxExtent.left) / currentRes); │ │ │ │ - colidx = Math.round(colidx / this.tileSize.w); │ │ │ │ - var rowidx = Math.floor((this.maxExtent.top - bounds.top) / currentRes); │ │ │ │ - rowidx = Math.round(rowidx / this.tileSize.h); │ │ │ │ - │ │ │ │ - if (this.useHttpTile) { │ │ │ │ - url = this.getImageFilePath({ │ │ │ │ - tilecol: colidx, │ │ │ │ - tilerow: rowidx, │ │ │ │ - scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ - }); │ │ │ │ - │ │ │ │ - } else { │ │ │ │ - url = this.getFullRequestString({ │ │ │ │ - tilecol: colidx, │ │ │ │ - tilerow: rowidx, │ │ │ │ - scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return url; │ │ │ │ + insertXY: function(x, y) { │ │ │ │ + this.line.geometry.addComponent( │ │ │ │ + new OpenLayers.Geometry.Point(x, y), │ │ │ │ + this.getCurrentPointIndex() │ │ │ │ + ); │ │ │ │ + this.drawFeature(); │ │ │ │ + delete this.redoStack; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getFullRequestString │ │ │ │ - * getFullRequestString on MapGuide layers is special, because we │ │ │ │ - * do a regular expression replace on ',' in parameters to '+'. │ │ │ │ - * This is why it is subclassed here. │ │ │ │ + * Method: insertDeltaXY │ │ │ │ + * Insert a point given offsets from the previously inserted point. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * altUrl - {String} Alternative base URL to use. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A string with the layer's url appropriately encoded for MapGuide │ │ │ │ + * dx - {Number} The x-coordinate offset of the point. │ │ │ │ + * dy - {Number} The y-coordinate offset of the point. │ │ │ │ */ │ │ │ │ - getFullRequestString: function(newParams, altUrl) { │ │ │ │ - // use layer's url unless altUrl passed in │ │ │ │ - var url = (altUrl == null) ? this.url : altUrl; │ │ │ │ - │ │ │ │ - // if url is not a string, it should be an array of strings, │ │ │ │ - // in which case we will randomly select one of them in order │ │ │ │ - // to evenly distribute requests to different urls. │ │ │ │ - if (typeof url == "object") { │ │ │ │ - url = url[Math.floor(Math.random() * url.length)]; │ │ │ │ - } │ │ │ │ - // requestString always starts with url │ │ │ │ - var requestString = 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); │ │ │ │ - // 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]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ - │ │ │ │ - /* MapGuide needs '+' seperating things like bounds/height/width. │ │ │ │ - Since typically this is URL encoded, we use a slight hack: we │ │ │ │ - depend on the list-like functionality of getParameterString to │ │ │ │ - leave ',' only in the case of list items (since otherwise it is │ │ │ │ - encoded) then do a regular expression replace on the , characters │ │ │ │ - to '+' */ │ │ │ │ - paramsString = paramsString.replace(/,/g, "+"); │ │ │ │ - │ │ │ │ - if (paramsString != "") { │ │ │ │ - var lastServerChar = url.charAt(url.length - 1); │ │ │ │ - if ((lastServerChar == "&") || (lastServerChar == "?")) { │ │ │ │ - requestString += paramsString; │ │ │ │ - } else { │ │ │ │ - if (url.indexOf('?') == -1) { │ │ │ │ - //serverPath has no ? -- add one │ │ │ │ - requestString += '?' + paramsString; │ │ │ │ - } else { │ │ │ │ - //serverPath contains ?, so must already have paramsString at the end │ │ │ │ - requestString += '&' + paramsString; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - return requestString; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getImageFilePath │ │ │ │ - * special handler to request mapguide tiles from an http exposed tilecache │ │ │ │ + /** │ │ │ │ + * Method: insertDirectionLength │ │ │ │ + * Insert a point in the current sketch given a direction and a length. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * altUrl - {String} Alternative base URL to use. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A string with the url for the tile image │ │ │ │ + * direction - {Number} Degrees clockwise from the positive x-axis. │ │ │ │ + * length - {Number} Distance from the previously drawn point. │ │ │ │ */ │ │ │ │ - getImageFilePath: function(newParams, altUrl) { │ │ │ │ - // use layer's url unless altUrl passed in │ │ │ │ - var url = (altUrl == null) ? this.url : altUrl; │ │ │ │ - │ │ │ │ - // if url is not a string, it should be an array of strings, │ │ │ │ - // in which case we will randomly select one of them in order │ │ │ │ - // to evenly distribute requests to different urls. │ │ │ │ - if (typeof url == "object") { │ │ │ │ - url = url[Math.floor(Math.random() * url.length)]; │ │ │ │ - } │ │ │ │ - // requestString always starts with url │ │ │ │ - var requestString = url; │ │ │ │ - │ │ │ │ - var tileRowGroup = ""; │ │ │ │ - var tileColGroup = ""; │ │ │ │ + insertDirectionLength: function(direction, length) { │ │ │ │ + direction *= Math.PI / 180; │ │ │ │ + var dx = length * Math.cos(direction); │ │ │ │ + var dy = length * Math.sin(direction); │ │ │ │ + this.insertDeltaXY(dx, dy); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (newParams.tilerow < 0) { │ │ │ │ - tileRowGroup = '-'; │ │ │ │ + /** │ │ │ │ + * 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 │ │ │ │ + ); │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (newParams.tilerow == 0) { │ │ │ │ - tileRowGroup += '0'; │ │ │ │ - } else { │ │ │ │ - tileRowGroup += Math.floor(Math.abs(newParams.tilerow / this.params.tileRowsPerFolder)) * this.params.tileRowsPerFolder; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Method: getCurrentPointIndex │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Number} The index of the most recently drawn point. │ │ │ │ + */ │ │ │ │ + getCurrentPointIndex: function() { │ │ │ │ + return this.line.geometry.components.length - 1; │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (newParams.tilecol < 0) { │ │ │ │ - tileColGroup = '-'; │ │ │ │ - } │ │ │ │ │ │ │ │ - if (newParams.tilecol == 0) { │ │ │ │ - tileColGroup += '0'; │ │ │ │ - } else { │ │ │ │ - tileColGroup += Math.floor(Math.abs(newParams.tilecol / this.params.tileColumnsPerFolder)) * this.params.tileColumnsPerFolder; │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - var tilePath = '/S' + Math.floor(newParams.scaleindex) + │ │ │ │ - '/' + this.params.basemaplayergroupname + │ │ │ │ - '/R' + tileRowGroup + │ │ │ │ - '/C' + tileColGroup + │ │ │ │ - '/' + (newParams.tilerow % this.params.tileRowsPerFolder) + │ │ │ │ - '_' + (newParams.tilecol % this.params.tileColumnsPerFolder) + │ │ │ │ - '.' + this.params.format; │ │ │ │ - │ │ │ │ - if (this.params.querystring) { │ │ │ │ - tilePath += "?" + this.params.querystring; │ │ │ │ + /** │ │ │ │ + * 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(); │ │ │ │ } │ │ │ │ - │ │ │ │ - requestString += tilePath; │ │ │ │ - return requestString; │ │ │ │ + return !!target; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.MapGuide" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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, { │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: displayInLayerSwitcher │ │ │ │ - * Set to false for this layer type │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - displayInLayerSwitcher: false, │ │ │ │ + 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(); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layers │ │ │ │ - * Layers that are attached to this container. Required config option. │ │ │ │ + * Method: drawFeature │ │ │ │ + * Render geometries on the temporary layer. │ │ │ │ */ │ │ │ │ - layers: null, │ │ │ │ + drawFeature: function() { │ │ │ │ + this.layer.drawFeature(this.line, this.style); │ │ │ │ + this.layer.drawFeature(this.point, this.style); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Method: getSketch │ │ │ │ + * Return the sketch feature. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Layer.Vector.RootContainer>} A new vector layer root │ │ │ │ - * container │ │ │ │ + * {<OpenLayers.Feature.Vector>} │ │ │ │ */ │ │ │ │ + getSketch: function() { │ │ │ │ + return this.line; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: display │ │ │ │ + * Method: getGeometry │ │ │ │ + * Return the sketch geometry. If <multi> is true, this will return │ │ │ │ + * a multi-part geometry. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Geometry.LineString>} │ │ │ │ */ │ │ │ │ - display: function() {}, │ │ │ │ + getGeometry: function() { │ │ │ │ + var geometry = this.line && this.line.geometry; │ │ │ │ + if (geometry && this.multi) { │ │ │ │ + geometry = new OpenLayers.Geometry.MultiLineString([geometry]); │ │ │ │ + } │ │ │ │ + return geometry; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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>} │ │ │ │ + * method: touchstart │ │ │ │ + * handle touchstart. │ │ │ │ + * │ │ │ │ + * parameters: │ │ │ │ + * evt - {event} the browser event │ │ │ │ + * │ │ │ │ + * returns: │ │ │ │ + * {boolean} allow event propagation │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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: setMap │ │ │ │ + * 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: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * evt - {Event} The browser event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ - this.collectRoots(); │ │ │ │ - map.events.register("changelayer", this, this.handleChangeLayer); │ │ │ │ + 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: removeMap │ │ │ │ + * Method: move │ │ │ │ + * Handle mousemove and touchmove. Adjust the geometry and redraw. │ │ │ │ + * Return determines whether to propagate the event on the map. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * evt - {Event} The browser event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ */ │ │ │ │ - removeMap: function(map) { │ │ │ │ - map.events.unregister("changelayer", this, this.handleChangeLayer); │ │ │ │ - this.resetRoots(); │ │ │ │ - OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments); │ │ │ │ + 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: collectRoots │ │ │ │ - * Collects the root nodes of all layers this control is configured with │ │ │ │ - * and moveswien the nodes to this control's layer │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: resetRoots │ │ │ │ - * Resets the root nodes back into the layers they belong to. │ │ │ │ + * APIMethod: finishGeometry │ │ │ │ + * Finish the geometry and send it back to the control. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + finishGeometry: function() { │ │ │ │ + var index = this.line.geometry.components.length - 1; │ │ │ │ + this.line.geometry.removeComponent(this.line.geometry.components[index]); │ │ │ │ + this.removePoint(); │ │ │ │ + this.finalize(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: dblclick │ │ │ │ + * Handle double-clicks. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Object} │ │ │ │ + * evt - {Event} The browser event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ */ │ │ │ │ - handleChangeLayer: function(evt) { │ │ │ │ - var layer = evt.layer; │ │ │ │ - if (evt.property == "order" && │ │ │ │ - OpenLayers.Util.indexOf(this.layers, layer) != -1) { │ │ │ │ - this.resetRoots(); │ │ │ │ - this.collectRoots(); │ │ │ │ + dblclick: function(evt) { │ │ │ │ + if (!this.freehandMode(evt)) { │ │ │ │ + this.finishGeometry(); │ │ │ │ } │ │ │ │ + return false; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Vector.RootContainer" │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Path" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/Google/v3.js │ │ │ │ + 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/Layer/Google.js │ │ │ │ + * @requires OpenLayers/Handler/Path.js │ │ │ │ + * @requires OpenLayers/Geometry/Polygon.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Layer.Google.v3 │ │ │ │ - * │ │ │ │ - * Mixin providing functionality specific to the Google Maps API v3. │ │ │ │ - * │ │ │ │ - * To use this layer, you must include the GMaps v3 API in your html. │ │ │ │ - * │ │ │ │ - * Note that this layer configures the google.maps.map object with the │ │ │ │ - * "disableDefaultUI" option set to true. Using UI controls that the Google │ │ │ │ - * Maps API provides is not supported by the OpenLayers API. │ │ │ │ + * 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.Layer.Google.v3 = { │ │ │ │ +OpenLayers.Handler.Polygon = OpenLayers.Class(OpenLayers.Handler.Path, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: DEFAULTS │ │ │ │ - * {Object} It is not recommended to change the properties set here. Note │ │ │ │ - * that Google.v3 layers only work when sphericalMercator is set to true. │ │ │ │ - * │ │ │ │ - * (code) │ │ │ │ - * { │ │ │ │ - * sphericalMercator: true, │ │ │ │ - * projection: "EPSG:900913" │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - DEFAULTS: { │ │ │ │ - sphericalMercator: true, │ │ │ │ - projection: "EPSG:900913" │ │ │ │ - }, │ │ │ │ + holeModifier: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: animationEnabled │ │ │ │ - * {Boolean} If set to true, the transition between zoom levels will be │ │ │ │ - * animated (if supported by the GMaps API for the device used). Set to │ │ │ │ - * false to match the zooming experience of other layer types. Default │ │ │ │ - * is true. Note that the GMaps API does not give us control over zoom │ │ │ │ - * animation, so if set to false, when zooming, this will make the │ │ │ │ - * layer temporarily invisible, wait until GMaps reports the map being │ │ │ │ - * idle, and make it visible again. The result will be a blank layer │ │ │ │ - * for a few moments while zooming. │ │ │ │ + * Property: drawingHole │ │ │ │ + * {Boolean} Currently drawing an interior ring. │ │ │ │ */ │ │ │ │ - animationEnabled: true, │ │ │ │ + drawingHole: false, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: loadMapObject │ │ │ │ - * Load the GMap and register appropriate event listeners. │ │ │ │ + /** │ │ │ │ + * Property: polygon │ │ │ │ + * {<OpenLayers.Feature.Vector>} │ │ │ │ */ │ │ │ │ - loadMapObject: function() { │ │ │ │ - if (!this.type) { │ │ │ │ - this.type = google.maps.MapTypeId.ROADMAP; │ │ │ │ - } │ │ │ │ - var mapObject; │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - // there are already Google layers added to this map │ │ │ │ - mapObject = cache.mapObject; │ │ │ │ - // increment the layer count │ │ │ │ - ++cache.count; │ │ │ │ - } else { │ │ │ │ - // this is the first Google layer for this map │ │ │ │ - // create GMap │ │ │ │ - var center = this.map.getCenter(); │ │ │ │ - var container = document.createElement('div'); │ │ │ │ - container.className = "olForeignContainer"; │ │ │ │ - container.style.width = '100%'; │ │ │ │ - container.style.height = '100%'; │ │ │ │ - mapObject = new google.maps.Map(container, { │ │ │ │ - center: center ? │ │ │ │ - new google.maps.LatLng(center.lat, center.lon) : new google.maps.LatLng(0, 0), │ │ │ │ - zoom: this.map.getZoom() || 0, │ │ │ │ - mapTypeId: this.type, │ │ │ │ - disableDefaultUI: true, │ │ │ │ - keyboardShortcuts: false, │ │ │ │ - draggable: false, │ │ │ │ - disableDoubleClickZoom: true, │ │ │ │ - scrollwheel: false, │ │ │ │ - streetViewControl: false │ │ │ │ - }); │ │ │ │ - var googleControl = document.createElement('div'); │ │ │ │ - googleControl.style.width = '100%'; │ │ │ │ - googleControl.style.height = '100%'; │ │ │ │ - mapObject.controls[google.maps.ControlPosition.TOP_LEFT].push(googleControl); │ │ │ │ + polygon: null, │ │ │ │ │ │ │ │ - // cache elements for use by any other google layers added to │ │ │ │ - // this same map │ │ │ │ - cache = { │ │ │ │ - googleControl: googleControl, │ │ │ │ - mapObject: mapObject, │ │ │ │ - count: 1 │ │ │ │ - }; │ │ │ │ - OpenLayers.Layer.Google.cache[this.map.id] = cache; │ │ │ │ - } │ │ │ │ - this.mapObject = mapObject; │ │ │ │ - this.setGMapVisibility(this.visibility); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: onMapResize │ │ │ │ + * Method: createFeature │ │ │ │ + * Add temporary geometries │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new │ │ │ │ + * feature. │ │ │ │ */ │ │ │ │ - onMapResize: function() { │ │ │ │ - if (this.visibility) { │ │ │ │ - google.maps.event.trigger(this.mapObject, "resize"); │ │ │ │ - } │ │ │ │ + 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: setGMapVisibility │ │ │ │ - * Display the GMap container and associated elements. │ │ │ │ - * │ │ │ │ + * Method: addPoint │ │ │ │ + * Add point to geometry. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * visible - {Boolean} Display the GMap elements. │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The pixel location for the new point. │ │ │ │ */ │ │ │ │ - setGMapVisibility: function(visible) { │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - var map = this.map; │ │ │ │ - if (cache) { │ │ │ │ - var type = this.type; │ │ │ │ - var layers = map.layers; │ │ │ │ - var layer; │ │ │ │ - for (var i = layers.length - 1; i >= 0; --i) { │ │ │ │ - layer = layers[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.Google && │ │ │ │ - layer.visibility === true && layer.inRange === true) { │ │ │ │ - type = layer.type; │ │ │ │ - visible = true; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ } │ │ │ │ - var container = this.mapObject.getDiv(); │ │ │ │ - if (visible === true) { │ │ │ │ - if (container.parentNode !== map.div) { │ │ │ │ - if (!cache.rendered) { │ │ │ │ - var me = this; │ │ │ │ - google.maps.event.addListenerOnce(this.mapObject, 'tilesloaded', function() { │ │ │ │ - cache.rendered = true; │ │ │ │ - me.setGMapVisibility(me.getVisibility()); │ │ │ │ - me.moveTo(me.map.getCenter()); │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - map.div.appendChild(container); │ │ │ │ - cache.googleControl.appendChild(map.viewPortDiv); │ │ │ │ - google.maps.event.trigger(this.mapObject, 'resize'); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.mapObject.setMapTypeId(type); │ │ │ │ - } else if (cache.googleControl.hasChildNodes()) { │ │ │ │ - map.div.appendChild(map.viewPortDiv); │ │ │ │ - map.div.removeChild(container); │ │ │ │ - } │ │ │ │ } │ │ │ │ + OpenLayers.Handler.Path.prototype.addPoint.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getMapContainer │ │ │ │ + * Method: getCurrentPointIndex │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} the GMap container's div │ │ │ │ + * {Number} The index of the most recently drawn point. │ │ │ │ */ │ │ │ │ - getMapContainer: function() { │ │ │ │ - return this.mapObject.getDiv(); │ │ │ │ + getCurrentPointIndex: function() { │ │ │ │ + return this.line.geometry.components.length - 2; │ │ │ │ }, │ │ │ │ │ │ │ │ - // │ │ │ │ - // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ - // │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectBoundsFromOLBounds │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * olBounds - {<OpenLayers.Bounds>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} A MapObject Bounds, translated from olBounds │ │ │ │ - * Returns null if null value is passed in │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ - var moBounds = null; │ │ │ │ - if (olBounds != null) { │ │ │ │ - var sw = this.sphericalMercator ? │ │ │ │ - this.inverseMercator(olBounds.bottom, olBounds.left) : │ │ │ │ - new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ - var ne = this.sphericalMercator ? │ │ │ │ - this.inverseMercator(olBounds.top, olBounds.right) : │ │ │ │ - new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ - moBounds = new google.maps.LatLngBounds( │ │ │ │ - new google.maps.LatLng(sw.lat, sw.lon), │ │ │ │ - new google.maps.LatLng(ne.lat, ne.lon) │ │ │ │ - ); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - return moBounds; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Interface Controls * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ - │ │ │ │ - │ │ │ │ - // LonLat - Pixel Translation │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectLonLatFromMapObjectPixel │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moPixel - {Object} MapObject Pixel format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject LonLat translated from MapObject Pixel │ │ │ │ + * Method: finishGeometry │ │ │ │ + * Finish the geometry and send it back to the control. │ │ │ │ */ │ │ │ │ - getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ - var size = this.map.getSize(); │ │ │ │ - var lon = this.getLongitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ - var lat = this.getLatitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - │ │ │ │ - var delta_x = moPixel.x - (size.w / 2); │ │ │ │ - var delta_y = moPixel.y - (size.h / 2); │ │ │ │ - │ │ │ │ - var lonlat = new OpenLayers.LonLat( │ │ │ │ - lon + delta_x * res, │ │ │ │ - lat - delta_y * res │ │ │ │ - ); │ │ │ │ + finishGeometry: function() { │ │ │ │ + var index = this.line.geometry.components.length - 2; │ │ │ │ + this.line.geometry.removeComponent(this.line.geometry.components[index]); │ │ │ │ + this.removePoint(); │ │ │ │ + this.finalize(); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (this.wrapDateLine) { │ │ │ │ - lonlat = lonlat.wrapDateLine(this.maxExtent); │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - return this.getMapObjectLonLatFromLonLat(lonlat.lon, lonlat.lat); │ │ │ │ + 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: getMapObjectPixelFromMapObjectLonLat │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moLonLat - {Object} MapObject LonLat format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject Pixel transtlated from MapObject LonLat │ │ │ │ + * APIMethod: cancel │ │ │ │ + * Finish the geometry and call the "cancel" callback. │ │ │ │ */ │ │ │ │ - getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); │ │ │ │ - var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - var extent = this.map.getExtent(); │ │ │ │ - return this.getMapObjectPixelFromXY((1 / res * (lon - extent.left)), │ │ │ │ - (1 / res * (extent.top - lat))); │ │ │ │ + cancel: function() { │ │ │ │ + if (this.drawingHole) { │ │ │ │ + this.polygon.geometry.removeComponent(this.line.geometry); │ │ │ │ + this.restoreFeature(true); │ │ │ │ + } │ │ │ │ + return OpenLayers.Handler.Path.prototype.cancel.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: setMapObjectCenter │ │ │ │ - * Set the mapObject to the specified center and zoom │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * center - {Object} MapObject LonLat format │ │ │ │ - * zoom - {int} MapObject zoom format │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - setMapObjectCenter: function(center, zoom) { │ │ │ │ - if (this.animationEnabled === false && zoom != this.mapObject.zoom) { │ │ │ │ - var mapContainer = this.getMapContainer(); │ │ │ │ - google.maps.event.addListenerOnce( │ │ │ │ - this.mapObject, │ │ │ │ - "idle", │ │ │ │ - function() { │ │ │ │ - mapContainer.style.visibility = ""; │ │ │ │ + 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 │ │ │ │ } │ │ │ │ ); │ │ │ │ - mapContainer.style.visibility = "hidden"; │ │ │ │ } │ │ │ │ - this.mapObject.setOptions({ │ │ │ │ - center: center, │ │ │ │ - zoom: zoom │ │ │ │ - }); │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ - // Bounds │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectZoomFromMapObjectBounds │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: destroyFeature │ │ │ │ + * Destroy temporary geometries │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * moBounds - {Object} MapObject Bounds format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject Zoom for specified MapObject Bounds │ │ │ │ + * force - {Boolean} Destroy even if persist is true. │ │ │ │ */ │ │ │ │ - getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ - return this.mapObject.getBoundsZoomLevel(moBounds); │ │ │ │ + destroyFeature: function(force) { │ │ │ │ + OpenLayers.Handler.Path.prototype.destroyFeature.call( │ │ │ │ + this, force); │ │ │ │ + this.polygon = null; │ │ │ │ }, │ │ │ │ │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Primitives * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ - │ │ │ │ - │ │ │ │ - // LonLat │ │ │ │ + /** │ │ │ │ + * Method: drawFeature │ │ │ │ + * Render geometries on the temporary layer. │ │ │ │ + */ │ │ │ │ + drawFeature: function() { │ │ │ │ + this.layer.drawFeature(this.polygon, this.style); │ │ │ │ + this.layer.drawFeature(this.point, this.style); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectLonLatFromLonLat │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * lon - {Float} │ │ │ │ - * lat - {Float} │ │ │ │ - * │ │ │ │ + * Method: getSketch │ │ │ │ + * Return the sketch feature. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} MapObject LonLat built from lon and lat params │ │ │ │ + * {<OpenLayers.Feature.Vector>} │ │ │ │ */ │ │ │ │ - getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ - var gLatLng; │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - var lonlat = this.inverseMercator(lon, lat); │ │ │ │ - gLatLng = new google.maps.LatLng(lonlat.lat, lonlat.lon); │ │ │ │ - } else { │ │ │ │ - gLatLng = new google.maps.LatLng(lat, lon); │ │ │ │ - } │ │ │ │ - return gLatLng; │ │ │ │ + getSketch: function() { │ │ │ │ + return this.polygon; │ │ │ │ }, │ │ │ │ │ │ │ │ - // Pixel │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectPixelFromXY │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * x - {Integer} │ │ │ │ - * y - {Integer} │ │ │ │ - * │ │ │ │ + * Method: getGeometry │ │ │ │ + * Return the sketch geometry. If <multi> is true, this will return │ │ │ │ + * a multi-part geometry. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} MapObject Pixel from x and y parameters │ │ │ │ + * {<OpenLayers.Geometry.Polygon>} │ │ │ │ */ │ │ │ │ - getMapObjectPixelFromXY: function(x, y) { │ │ │ │ - return new google.maps.Point(x, y); │ │ │ │ - } │ │ │ │ + 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/Events/buttonclick.js │ │ │ │ + OpenLayers/Handler/Hover.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/Handler.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. │ │ │ │ + * Class: OpenLayers.Handler.Hover │ │ │ │ + * The hover handler is to be used to emulate mouseovers on objects │ │ │ │ + * on the map that aren't DOM elements. For example one can use │ │ │ │ + * this handler to send WMS/GetFeatureInfo requests as the user │ │ │ │ + * moves the mouve over the map. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -OpenLayers.Events.buttonclick = OpenLayers.Class({ │ │ │ │ +OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: target │ │ │ │ - * {<OpenLayers.Events>} The events instance that the buttonclick event will │ │ │ │ - * be triggered on. │ │ │ │ + * APIProperty: delay │ │ │ │ + * {Integer} - Number of milliseconds between mousemoves before │ │ │ │ + * the event is considered a hover. Default is 500. │ │ │ │ */ │ │ │ │ - target: null, │ │ │ │ + delay: 500, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: events │ │ │ │ - * {Array} Events to observe and conditionally stop from propagating when │ │ │ │ - * an element with the olButton class (or its olAlphaImg child) is │ │ │ │ - * clicked. │ │ │ │ + * APIProperty: pixelTolerance │ │ │ │ + * {Integer} - Maximum number of pixels between mousemoves for │ │ │ │ + * an event to be considered a hover. Default is null. │ │ │ │ */ │ │ │ │ - events: [ │ │ │ │ - 'mousedown', 'mouseup', 'click', 'dblclick', │ │ │ │ - 'touchstart', 'touchmove', 'touchend', 'keydown' │ │ │ │ - ], │ │ │ │ + pixelTolerance: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: startRegEx │ │ │ │ - * {RegExp} Regular expression to test Event.type for events that start │ │ │ │ - * a buttonclick sequence. │ │ │ │ + * APIProperty: stopMove │ │ │ │ + * {Boolean} - Stop other listeners from being notified on mousemoves. │ │ │ │ + * Default is false. │ │ │ │ */ │ │ │ │ - startRegEx: /^mousedown|touchstart$/, │ │ │ │ + stopMove: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: cancelRegEx │ │ │ │ - * {RegExp} Regular expression to test Event.type for events that cancel │ │ │ │ - * a buttonclick sequence. │ │ │ │ + * Property: px │ │ │ │ + * {<OpenLayers.Pixel>} - The location of the last mousemove, expressed │ │ │ │ + * in pixels. │ │ │ │ */ │ │ │ │ - cancelRegEx: /^touchmove$/, │ │ │ │ + px: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: completeRegEx │ │ │ │ - * {RegExp} Regular expression to test Event.type for events that complete │ │ │ │ - * a buttonclick sequence. │ │ │ │ + * Property: timerId │ │ │ │ + * {Number} - The id of the timer. │ │ │ │ */ │ │ │ │ - completeRegEx: /^mouseup|touchend$/, │ │ │ │ + timerId: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: startEvt │ │ │ │ - * {Event} The event that started the click sequence │ │ │ │ + * Constructor: OpenLayers.Handler.Hover │ │ │ │ + * Construct a hover 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. │ │ │ │ + * callbacks - {Object} An object with keys corresponding to callbacks │ │ │ │ + * that will be called by the handler. The callbacks should │ │ │ │ + * expect to receive a single argument, the event. Callbacks for │ │ │ │ + * 'move', the mouse is moving, and 'pause', the mouse is pausing, │ │ │ │ + * are supported. │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * the handler. │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: mousemove │ │ │ │ + * Called when the mouse moves on the map. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * target - {<OpenLayers.Events>} The events instance that the buttonclick │ │ │ │ - * event will be triggered on. │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Continue propagating this event. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + mousemove: function(evt) { │ │ │ │ + if (this.passesTolerance(evt.xy)) { │ │ │ │ + this.clearTimer(); │ │ │ │ + this.callback('move', [evt]); │ │ │ │ + this.px = evt.xy; │ │ │ │ + // clone the evt so original properties can be accessed even │ │ │ │ + // if the browser deletes them during the delay │ │ │ │ + evt = OpenLayers.Util.extend({}, evt); │ │ │ │ + this.timerId = window.setTimeout( │ │ │ │ + OpenLayers.Function.bind(this.delayedCall, this, evt), │ │ │ │ + this.delay │ │ │ │ + ); │ │ │ │ } │ │ │ │ + return !this.stopMove; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroy │ │ │ │ + * Method: mouseout │ │ │ │ + * Called when the mouse goes out of the map. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Continue propagating this event. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - for (var i = this.events.length - 1; i >= 0; --i) { │ │ │ │ - this.target.unregister(this.events[i], this, this.buttonClick); │ │ │ │ + mouseout: function(evt) { │ │ │ │ + if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ + this.clearTimer(); │ │ │ │ + this.callback('move', [evt]); │ │ │ │ } │ │ │ │ - delete this.target; │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getPressedButton │ │ │ │ - * Get the pressed button, if any. Returns undefined if no button │ │ │ │ - * was pressed. │ │ │ │ + * Method: passesTolerance │ │ │ │ + * Determine whether the mouse move is within the optional pixel tolerance. │ │ │ │ * │ │ │ │ - * Arguments: │ │ │ │ - * element - {DOMElement} The event target. │ │ │ │ + * Parameters: │ │ │ │ + * px - {<OpenLayers.Pixel>} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} The button element, or undefined. │ │ │ │ + * {Boolean} The mouse move is within the pixel tolerance. │ │ │ │ */ │ │ │ │ - getPressedButton: function(element) { │ │ │ │ - var depth = 3, // limit the search depth │ │ │ │ - button; │ │ │ │ - do { │ │ │ │ - if (OpenLayers.Element.hasClass(element, "olButton")) { │ │ │ │ - // hit! │ │ │ │ - button = element; │ │ │ │ - break; │ │ │ │ + passesTolerance: function(px) { │ │ │ │ + var passes = true; │ │ │ │ + if (this.pixelTolerance && this.px) { │ │ │ │ + var dpx = Math.sqrt( │ │ │ │ + Math.pow(this.px.x - px.x, 2) + │ │ │ │ + Math.pow(this.px.y - px.y, 2) │ │ │ │ + ); │ │ │ │ + if (dpx < this.pixelTolerance) { │ │ │ │ + passes = false; │ │ │ │ } │ │ │ │ - element = element.parentNode; │ │ │ │ - } while (--depth > 0 && element); │ │ │ │ - return button; │ │ │ │ + } │ │ │ │ + return passes; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: ignore │ │ │ │ - * Check for event target elements that should be ignored by OpenLayers. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * element - {DOMElement} The event target. │ │ │ │ + * Method: clearTimer │ │ │ │ + * Clear the timer and set <timerId> to null. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + clearTimer: function() { │ │ │ │ + if (this.timerId != null) { │ │ │ │ + window.clearTimeout(this.timerId); │ │ │ │ + this.timerId = null; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: buttonClick │ │ │ │ - * Check if a button was clicked, and fire the buttonclick event │ │ │ │ + * Method: delayedCall │ │ │ │ + * Triggers pause callback. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * evt - {<OpenLayers.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; │ │ │ │ + delayedCall: function(evt) { │ │ │ │ + this.callback('pause', [evt]); │ │ │ │ + }, │ │ │ │ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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(); │ │ │ │ + deactivated = true; │ │ │ │ } │ │ │ │ - return propagate; │ │ │ │ - } │ │ │ │ + return deactivated; │ │ │ │ + }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Hover" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Panel.js │ │ │ │ + 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/Control.js │ │ │ │ - * @requires OpenLayers/Events/buttonclick.js │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Panel │ │ │ │ - * The Panel control is a container for other controls. With it toolbars │ │ │ │ - * may be composed. │ │ │ │ + * 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.Control> │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.Panel = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - /** │ │ │ │ - * Property: controls │ │ │ │ - * {Array(<OpenLayers.Control>)} │ │ │ │ +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. │ │ │ │ */ │ │ │ │ - controls: null, │ │ │ │ + started: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ + * Property: stopDown │ │ │ │ + * {Boolean} Stop propagation of mousedown events from getting to listeners │ │ │ │ + * on the same element. Default is true. │ │ │ │ */ │ │ │ │ - autoActivate: true, │ │ │ │ + stopDown: 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. │ │ │ │ + * Property: dragging │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - defaultControl: null, │ │ │ │ + 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: lastMoveEvt │ │ │ │ + * {Object} The last mousemove event that occurred. Used to │ │ │ │ + * position the map correctly when our "delay drag" │ │ │ │ + * timeout expired. │ │ │ │ */ │ │ │ │ - saveState: false, │ │ │ │ + lastMoveEvt: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: oldOnselectstart │ │ │ │ + * {Function} │ │ │ │ */ │ │ │ │ - allowDepress: false, │ │ │ │ + oldOnselectstart: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: activeState │ │ │ │ - * {Object} stores the active state of this panel's controls. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - activeState: null, │ │ │ │ + interval: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: timeoutId │ │ │ │ + * {String} The id of the timeout used for the mousedown interval. │ │ │ │ + * This is "private", and should be left alone. │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.controls = []; │ │ │ │ - this.activeState = {}; │ │ │ │ - }, │ │ │ │ + timeoutId: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - }, │ │ │ │ + documentDrag: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: activate │ │ │ │ + * Property: documentEvents │ │ │ │ + * {Boolean} Are we currently observing document events? │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + documentEvents: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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: draw │ │ │ │ + * Method: dragstart │ │ │ │ + * This private method is factorized from mousedown and touchstart methods │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} The event │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (this.outsideViewport) { │ │ │ │ - this.events.attachToElement(this.div); │ │ │ │ - this.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ + 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.map.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ + this.started = false; │ │ │ │ + this.start = null; │ │ │ │ + this.last = null; │ │ │ │ } │ │ │ │ - this.addControlsToMap(this.controls); │ │ │ │ - return this.div; │ │ │ │ + return propagate; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: redraw │ │ │ │ + * Method: dragmove │ │ │ │ + * This private method is factorized from mousemove and touchmove methods │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} The event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: activateControl │ │ │ │ - * This method is called when the user click on the icon representing a │ │ │ │ - * control in the panel. │ │ │ │ + * Method: dragend │ │ │ │ + * This private method is factorized from mouseup and touchend methods │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * control - {<OpenLayers.Control>} │ │ │ │ + * evt - {Event} The event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ + dragend: function(evt) { │ │ │ │ + if (this.started) { │ │ │ │ + if (this.documentDrag === true && this.documentEvents) { │ │ │ │ + this.adjustXY(evt); │ │ │ │ + this.removeDocumentEvents(); │ │ │ │ } │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ + 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]); │ │ │ │ } │ │ │ │ - control.activate(); │ │ │ │ + document.onselectstart = this.oldOnselectstart; │ │ │ │ } │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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: │ │ │ │ - * controls - {<OpenLayers.Control>} Controls to add in the panel. │ │ │ │ + * evt - {Event} The mouse down event │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + down: function(evt) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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) │ │ │ │ + * Method: move │ │ │ │ + * This method is called during the handling of the mouse move event. │ │ │ │ + * Subclasses can do their own processing here. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * control - {<OpenLayers.Control>} The control to create the HTML │ │ │ │ - * markup for. │ │ │ │ + * evt - {Event} The mouse move event │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} The markup. │ │ │ │ */ │ │ │ │ - createControlMarkup: function(control) { │ │ │ │ - return document.createElement("div"); │ │ │ │ - }, │ │ │ │ + move: function(evt) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: addControlsToMap │ │ │ │ - * Only for internal use in draw() and addControls() methods. │ │ │ │ + * Method: up │ │ │ │ + * This method is called during the handling of the mouse up event. │ │ │ │ + * Subclasses can do their own processing here. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * controls - {Array(<OpenLayers.Control>)} Controls to add into map. │ │ │ │ + * evt - {Event} The mouse up event │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + up: function(evt) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: iconOn │ │ │ │ - * Internal use, for use only with "controls[i].events.on/un". │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ - }, │ │ │ │ + out: function(evt) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: iconOff │ │ │ │ - * Internal use, for use only with "controls[i].events.on/un". │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + * Method: mousedown │ │ │ │ + * Handle mousedown events │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * evt - {Event} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + mousedown: function(evt) { │ │ │ │ + return this.dragstart(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getControlsBy │ │ │ │ - * Get a list of controls with properties matching the given criteria. │ │ │ │ + * Method: touchstart │ │ │ │ + * Handle touchstart events │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Array(<OpenLayers.Control>)} A list of controls matching the given criteria. │ │ │ │ - * An empty array is returned if no matches are found. │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + return this.dragstart(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getControlsByName │ │ │ │ - * Get a list of contorls with names matching the given name. │ │ │ │ + * Method: mousemove │ │ │ │ + * Handle mousemove events │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Array(<OpenLayers.Control>)} A list of controls matching the given name. │ │ │ │ - * An empty array is returned if no matches are found. │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - getControlsByName: function(match) { │ │ │ │ - return this.getControlsBy("name", match); │ │ │ │ + mousemove: function(evt) { │ │ │ │ + return this.dragmove(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getControlsByClass │ │ │ │ - * Get a list of controls of a given type (CLASS_NAME). │ │ │ │ + * Method: touchmove │ │ │ │ + * Handle touchmove events │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Array(<OpenLayers.Control>)} A list of controls matching the given type. │ │ │ │ - * An empty array is returned if no matches are found. │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - getControlsByClass: function(match) { │ │ │ │ - return this.getControlsBy("CLASS_NAME", match); │ │ │ │ + touchmove: function(evt) { │ │ │ │ + return this.dragmove(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Panel" │ │ │ │ -}); │ │ │ │ - │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/Snapping.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/Layer/Vector.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.Snapping │ │ │ │ - * Acts as a snapping agent while editing vector features. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.Snapping = 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>): │ │ │ │ - * beforesnap - Triggered before a snap occurs. Listeners receive an │ │ │ │ - * event object with *point*, *x*, *y*, *distance*, *layer*, and │ │ │ │ - * *snapType* properties. The point property will be original point │ │ │ │ - * geometry considered for snapping. The x and y properties represent │ │ │ │ - * coordinates the point will receive. The distance is the distance │ │ │ │ - * of the snap. The layer is the target layer. The snapType property │ │ │ │ - * will be one of "node", "vertex", or "edge". Return false to stop │ │ │ │ - * snapping from occurring. │ │ │ │ - * snap - Triggered when a snap occurs. Listeners receive an event with │ │ │ │ - * *point*, *snapType*, *layer*, and *distance* properties. The point │ │ │ │ - * will be the location snapped to. The snapType will be one of "node", │ │ │ │ - * "vertex", or "edge". The layer will be the target layer. The │ │ │ │ - * distance will be the distance of the snap in map units. │ │ │ │ - * unsnap - Triggered when a vertex is unsnapped. Listeners receive an │ │ │ │ - * event with a *point* property. │ │ │ │ - */ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * CONSTANT: DEFAULTS │ │ │ │ - * Default target properties. │ │ │ │ + * Method: removeTimeout │ │ │ │ + * Private. Called by mousemove() to remove the drag timeout. │ │ │ │ */ │ │ │ │ - DEFAULTS: { │ │ │ │ - tolerance: 10, │ │ │ │ - node: true, │ │ │ │ - edge: true, │ │ │ │ - vertex: true │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: greedy │ │ │ │ - * {Boolean} Snap to closest feature in first layer with an eligible │ │ │ │ - * feature. Default is true. │ │ │ │ + * Method: mouseup │ │ │ │ + * Handle mouseup events │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - greedy: true, │ │ │ │ + mouseup: function(evt) { │ │ │ │ + return this.dragend(evt); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: precedence │ │ │ │ - * {Array} List representing precedence of different snapping types. │ │ │ │ - * Default is "node", "vertex", "edge". │ │ │ │ + * Method: touchend │ │ │ │ + * Handle touchend events │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - precedence: ["node", "vertex", "edge"], │ │ │ │ + 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); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: resolution │ │ │ │ - * {Float} The map resolution for the previously considered snap. │ │ │ │ + * Method: mouseout │ │ │ │ + * Handle mouseout events │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - resolution: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: geoToleranceCache │ │ │ │ - * {Object} A cache of geo-tolerances. Tolerance values (in map units) are │ │ │ │ - * calculated when the map resolution changes. │ │ │ │ - */ │ │ │ │ - geoToleranceCache: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: layer │ │ │ │ - * {<OpenLayers.Layer.Vector>} The current editable layer. Set at │ │ │ │ - * construction or after construction with <setLayer>. │ │ │ │ - */ │ │ │ │ - layer: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: feature │ │ │ │ - * {<OpenLayers.Feature.Vector>} The current editable feature. │ │ │ │ - */ │ │ │ │ - feature: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: point │ │ │ │ - * {<OpenLayers.Geometry.Point>} The currently snapped vertex. │ │ │ │ - */ │ │ │ │ - point: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.Snapping │ │ │ │ - * Creates a new snapping control. A control is constructed with an editable │ │ │ │ - * layer and a set of configuration objects for target layers. While the │ │ │ │ - * control is active, dragging vertices while drawing new features or │ │ │ │ - * modifying existing features on the editable layer will engage │ │ │ │ - * snapping to features on the target layers. Whether a vertex snaps to │ │ │ │ - * a feature on a target layer depends on the target layer configuration. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An object containing all configuration properties for │ │ │ │ - * the control. │ │ │ │ - * │ │ │ │ - * Valid options: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} The editable layer. Features from this │ │ │ │ - * layer that are digitized or modified may have vertices snapped to │ │ │ │ - * features from any of the target layers. │ │ │ │ - * targets - {Array(Object | OpenLayers.Layer.Vector)} A list of objects for │ │ │ │ - * configuring target layers. See valid properties of the target │ │ │ │ - * objects below. If the items in the targets list are vector layers │ │ │ │ - * (instead of configuration objects), the defaults from the <defaults> │ │ │ │ - * property will apply. The editable layer itself may be a target │ │ │ │ - * layer, allowing newly created or edited features to be snapped to │ │ │ │ - * existing features from the same layer. If no targets are provided │ │ │ │ - * the layer given in the constructor (as <layer>) will become the │ │ │ │ - * initial target. │ │ │ │ - * defaults - {Object} An object with default properties to be applied │ │ │ │ - * to all target objects. │ │ │ │ - * greedy - {Boolean} Snap to closest feature in first target layer that │ │ │ │ - * applies. Default is true. If false, all features in all target │ │ │ │ - * layers will be checked and the closest feature in all target layers │ │ │ │ - * will be chosen. The greedy property determines if the order of the │ │ │ │ - * target layers is significant. By default, the order of the target │ │ │ │ - * layers is significant where layers earlier in the target layer list │ │ │ │ - * have precedence over layers later in the list. Within a single │ │ │ │ - * layer, the closest feature is always chosen for snapping. This │ │ │ │ - * property only determines whether the search for a closer feature │ │ │ │ - * continues after an eligible feature is found in a target layer. │ │ │ │ - * │ │ │ │ - * Valid target properties: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} A target layer. Features from this │ │ │ │ - * layer will be eligible to act as snapping target for the editable │ │ │ │ - * layer. │ │ │ │ - * tolerance - {Float} The distance (in pixels) at which snapping may occur. │ │ │ │ - * Default is 10. │ │ │ │ - * node - {Boolean} Snap to nodes (first or last point in a geometry) in │ │ │ │ - * target layer. Default is true. │ │ │ │ - * nodeTolerance - {Float} Optional distance at which snapping may occur │ │ │ │ - * for nodes specifically. If none is provided, <tolerance> will be │ │ │ │ - * used. │ │ │ │ - * vertex - {Boolean} Snap to vertices in target layer. Default is true. │ │ │ │ - * vertexTolerance - {Float} Optional distance at which snapping may occur │ │ │ │ - * for vertices specifically. If none is provided, <tolerance> will be │ │ │ │ - * used. │ │ │ │ - * edge - {Boolean} Snap to edges in target layer. Default is true. │ │ │ │ - * edgeTolerance - {Float} Optional distance at which snapping may occur │ │ │ │ - * for edges specifically. If none is provided, <tolerance> will be │ │ │ │ - * used. │ │ │ │ - * filter - {<OpenLayers.Filter>} Optional filter to evaluate to determine if │ │ │ │ - * feature is eligible for snapping. If filter evaluates to true for a │ │ │ │ - * target feature a vertex may be snapped to the feature. │ │ │ │ - * minResolution - {Number} If a minResolution is provided, snapping to this │ │ │ │ - * target will only be considered if the map resolution is greater than │ │ │ │ - * or equal to this value (the minResolution is inclusive). Default is │ │ │ │ - * no minimum resolution limit. │ │ │ │ - * maxResolution - {Number} If a maxResolution is provided, snapping to this │ │ │ │ - * target will only be considered if the map resolution is strictly │ │ │ │ - * less than this value (the maxResolution is exclusive). Default is │ │ │ │ - * no maximum resolution limit. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.options = options || {}; // TODO: this could be done by the super │ │ │ │ - │ │ │ │ - // set the editable layer if provided │ │ │ │ - if (this.options.layer) { │ │ │ │ - this.setLayer(this.options.layer); │ │ │ │ - } │ │ │ │ - // configure target layers │ │ │ │ - var defaults = OpenLayers.Util.extend({}, this.options.defaults); │ │ │ │ - this.defaults = OpenLayers.Util.applyDefaults(defaults, this.DEFAULTS); │ │ │ │ - this.setTargets(this.options.targets); │ │ │ │ - if (this.targets.length === 0 && this.layer) { │ │ │ │ - this.addTargetLayer(this.layer); │ │ │ │ - } │ │ │ │ - │ │ │ │ - this.geoToleranceCache = {}; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: setLayer │ │ │ │ - * Set the editable layer. Call the setLayer method if the editable layer │ │ │ │ - * changes and the same control should be used on a new editable layer. │ │ │ │ - * If the control is already active, it will be active after the new │ │ │ │ - * layer is set. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} The new editable layer. │ │ │ │ - */ │ │ │ │ - setLayer: function(layer) { │ │ │ │ - if (this.active) { │ │ │ │ - this.deactivate(); │ │ │ │ - this.layer = layer; │ │ │ │ - this.activate(); │ │ │ │ - } else { │ │ │ │ - this.layer = layer; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setTargets │ │ │ │ - * Set the targets for the snapping agent. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * targets - {Array} An array of target configs or target layers. │ │ │ │ - */ │ │ │ │ - setTargets: function(targets) { │ │ │ │ - this.targets = []; │ │ │ │ - if (targets && targets.length) { │ │ │ │ - var target; │ │ │ │ - for (var i = 0, len = targets.length; i < len; ++i) { │ │ │ │ - target = targets[i]; │ │ │ │ - if (target instanceof OpenLayers.Layer.Vector) { │ │ │ │ - this.addTargetLayer(target); │ │ │ │ - } else { │ │ │ │ - this.addTarget(target); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: addTargetLayer │ │ │ │ - * Add a target layer with the default target config. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} A target layer. │ │ │ │ - */ │ │ │ │ - addTargetLayer: function(layer) { │ │ │ │ - this.addTarget({ │ │ │ │ - layer: layer │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: addTarget │ │ │ │ - * Add a configured target layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * target - {Object} A target config. │ │ │ │ - */ │ │ │ │ - addTarget: function(target) { │ │ │ │ - target = OpenLayers.Util.applyDefaults(target, this.defaults); │ │ │ │ - target.nodeTolerance = target.nodeTolerance || target.tolerance; │ │ │ │ - target.vertexTolerance = target.vertexTolerance || target.tolerance; │ │ │ │ - target.edgeTolerance = target.edgeTolerance || target.tolerance; │ │ │ │ - this.targets.push(target); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: removeTargetLayer │ │ │ │ - * Remove a target layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} The target layer to remove. │ │ │ │ - */ │ │ │ │ - removeTargetLayer: function(layer) { │ │ │ │ - var target; │ │ │ │ - for (var i = this.targets.length - 1; i >= 0; --i) { │ │ │ │ - target = this.targets[i]; │ │ │ │ - if (target.layer === layer) { │ │ │ │ - this.removeTarget(target); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: removeTarget │ │ │ │ - * Remove a target. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * target - {Object} A target config. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} The targets array. │ │ │ │ - */ │ │ │ │ - removeTarget: function(target) { │ │ │ │ - return OpenLayers.Util.removeItem(this.targets, target); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the control. Activating the control registers listeners for │ │ │ │ - * editing related events so that during feature creation and │ │ │ │ - * modification, moving vertices will trigger snapping. │ │ │ │ - */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - if (this.layer && this.layer.events) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - sketchstarted: this.onSketchModified, │ │ │ │ - sketchmodified: this.onSketchModified, │ │ │ │ - vertexmodified: this.onVertexModified, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return activated; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the control. Deactivating the control unregisters listeners │ │ │ │ - * so feature editing may proceed without engaging the snapping agent. │ │ │ │ - */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - if (this.layer && this.layer.events) { │ │ │ │ - this.layer.events.un({ │ │ │ │ - sketchstarted: this.onSketchModified, │ │ │ │ - sketchmodified: this.onSketchModified, │ │ │ │ - vertexmodified: this.onVertexModified, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.feature = null; │ │ │ │ - this.point = null; │ │ │ │ - return deactivated; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: onSketchModified │ │ │ │ - * Registered as a listener for the sketchmodified event on the editable │ │ │ │ - * layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * event - {Object} The sketch modified event. │ │ │ │ - */ │ │ │ │ - onSketchModified: function(event) { │ │ │ │ - this.feature = event.feature; │ │ │ │ - this.considerSnapping(event.vertex, event.vertex); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: onVertexModified │ │ │ │ - * Registered as a listener for the vertexmodified event on the editable │ │ │ │ - * layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * event - {Object} The vertex modified event. │ │ │ │ - */ │ │ │ │ - onVertexModified: function(event) { │ │ │ │ - this.feature = event.feature; │ │ │ │ - var loc = this.layer.map.getLonLatFromViewPortPx(event.pixel); │ │ │ │ - this.considerSnapping( │ │ │ │ - event.vertex, new OpenLayers.Geometry.Point(loc.lon, loc.lat) │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: considerSnapping │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * point - {<OpenLayers.Geometry.Point>} The vertex to be snapped (or │ │ │ │ - * unsnapped). │ │ │ │ - * loc - {<OpenLayers.Geometry.Point>} The location of the mouse in map │ │ │ │ - * coords. │ │ │ │ - */ │ │ │ │ - considerSnapping: function(point, loc) { │ │ │ │ - var best = { │ │ │ │ - rank: Number.POSITIVE_INFINITY, │ │ │ │ - dist: Number.POSITIVE_INFINITY, │ │ │ │ - x: null, │ │ │ │ - y: null │ │ │ │ - }; │ │ │ │ - var snapped = false; │ │ │ │ - var result, target; │ │ │ │ - for (var i = 0, len = this.targets.length; i < len; ++i) { │ │ │ │ - target = this.targets[i]; │ │ │ │ - result = this.testTarget(target, loc); │ │ │ │ - if (result) { │ │ │ │ - if (this.greedy) { │ │ │ │ - best = result; │ │ │ │ - best.target = target; │ │ │ │ - snapped = true; │ │ │ │ - break; │ │ │ │ - } else { │ │ │ │ - if ((result.rank < best.rank) || │ │ │ │ - (result.rank === best.rank && result.dist < best.dist)) { │ │ │ │ - best = result; │ │ │ │ - best.target = target; │ │ │ │ - snapped = true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (snapped) { │ │ │ │ - var proceed = this.events.triggerEvent("beforesnap", { │ │ │ │ - point: point, │ │ │ │ - x: best.x, │ │ │ │ - y: best.y, │ │ │ │ - distance: best.dist, │ │ │ │ - layer: best.target.layer, │ │ │ │ - snapType: this.precedence[best.rank] │ │ │ │ - }); │ │ │ │ - if (proceed !== false) { │ │ │ │ - point.x = best.x; │ │ │ │ - point.y = best.y; │ │ │ │ - this.point = point; │ │ │ │ - this.events.triggerEvent("snap", { │ │ │ │ - point: point, │ │ │ │ - snapType: this.precedence[best.rank], │ │ │ │ - layer: best.target.layer, │ │ │ │ - distance: best.dist │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - snapped = false; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.point && !snapped) { │ │ │ │ - point.x = loc.x; │ │ │ │ - point.y = loc.y; │ │ │ │ - this.point = null; │ │ │ │ - this.events.triggerEvent("unsnap", { │ │ │ │ - point: point │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: testTarget │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * target - {Object} Object with target layer configuration. │ │ │ │ - * loc - {<OpenLayers.Geometry.Point>} The location of the mouse in map │ │ │ │ - * coords. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} A result object with rank, dist, x, and y properties. │ │ │ │ - * Returns null if candidate is not eligible for snapping. │ │ │ │ - */ │ │ │ │ - testTarget: function(target, loc) { │ │ │ │ - var resolution = this.layer.map.getResolution(); │ │ │ │ - if ("minResolution" in target) { │ │ │ │ - if (resolution < target.minResolution) { │ │ │ │ - return null; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if ("maxResolution" in target) { │ │ │ │ - if (resolution >= target.maxResolution) { │ │ │ │ - return null; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var tolerance = { │ │ │ │ - node: this.getGeoTolerance(target.nodeTolerance, resolution), │ │ │ │ - vertex: this.getGeoTolerance(target.vertexTolerance, resolution), │ │ │ │ - edge: this.getGeoTolerance(target.edgeTolerance, resolution) │ │ │ │ - }; │ │ │ │ - // this could be cached if we don't support setting tolerance values directly │ │ │ │ - var maxTolerance = Math.max( │ │ │ │ - tolerance.node, tolerance.vertex, tolerance.edge │ │ │ │ - ); │ │ │ │ - var result = { │ │ │ │ - rank: Number.POSITIVE_INFINITY, │ │ │ │ - dist: Number.POSITIVE_INFINITY │ │ │ │ - }; │ │ │ │ - var eligible = false; │ │ │ │ - var features = target.layer.features; │ │ │ │ - var feature, type, vertices, vertex, closest, dist, found; │ │ │ │ - var numTypes = this.precedence.length; │ │ │ │ - var ll = new OpenLayers.LonLat(loc.x, loc.y); │ │ │ │ - for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - if (feature !== this.feature && !feature._sketch && │ │ │ │ - feature.state !== OpenLayers.State.DELETE && │ │ │ │ - (!target.filter || target.filter.evaluate(feature))) { │ │ │ │ - if (feature.atPoint(ll, maxTolerance, maxTolerance)) { │ │ │ │ - for (var j = 0, stop = Math.min(result.rank + 1, numTypes); j < stop; ++j) { │ │ │ │ - type = this.precedence[j]; │ │ │ │ - if (target[type]) { │ │ │ │ - if (type === "edge") { │ │ │ │ - closest = feature.geometry.distanceTo(loc, { │ │ │ │ - details: true │ │ │ │ - }); │ │ │ │ - dist = closest.distance; │ │ │ │ - if (dist <= tolerance[type] && dist < result.dist) { │ │ │ │ - result = { │ │ │ │ - rank: j, │ │ │ │ - dist: dist, │ │ │ │ - x: closest.x0, │ │ │ │ - y: closest.y0 // closest coords on feature │ │ │ │ - }; │ │ │ │ - eligible = true; │ │ │ │ - // don't look for lower precedence types for this feature │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - // look for nodes or vertices │ │ │ │ - vertices = feature.geometry.getVertices(type === "node"); │ │ │ │ - found = false; │ │ │ │ - for (var k = 0, klen = vertices.length; k < klen; ++k) { │ │ │ │ - vertex = vertices[k]; │ │ │ │ - dist = vertex.distanceTo(loc); │ │ │ │ - if (dist <= tolerance[type] && │ │ │ │ - (j < result.rank || (j === result.rank && dist < result.dist))) { │ │ │ │ - result = { │ │ │ │ - rank: j, │ │ │ │ - dist: dist, │ │ │ │ - x: vertex.x, │ │ │ │ - y: vertex.y │ │ │ │ - }; │ │ │ │ - eligible = true; │ │ │ │ - found = true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (found) { │ │ │ │ - // don't look for lower precedence types for this feature │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return eligible ? result : null; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getGeoTolerance │ │ │ │ - * Calculate a tolerance in map units given a tolerance in pixels. This │ │ │ │ - * takes advantage of the <geoToleranceCache> when the map resolution │ │ │ │ - * has not changed. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * tolerance - {Number} A tolerance value in pixels. │ │ │ │ - * resolution - {Number} Map resolution. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Number} A tolerance value in map units. │ │ │ │ - */ │ │ │ │ - getGeoTolerance: function(tolerance, resolution) { │ │ │ │ - if (resolution !== this.resolution) { │ │ │ │ - this.resolution = resolution; │ │ │ │ - this.geoToleranceCache = {}; │ │ │ │ - } │ │ │ │ - var geoTolerance = this.geoToleranceCache[tolerance]; │ │ │ │ - if (geoTolerance === undefined) { │ │ │ │ - geoTolerance = tolerance * resolution; │ │ │ │ - this.geoToleranceCache[tolerance] = geoTolerance; │ │ │ │ - } │ │ │ │ - return geoTolerance; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - * Clean up the control. │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.active) { │ │ │ │ - this.deactivate(); // TODO: this should be handled by the super │ │ │ │ - } │ │ │ │ - delete this.layer; │ │ │ │ - delete this.targets; │ │ │ │ - OpenLayers.Control.prototype.destroy.call(this); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Snapping" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/CacheWrite.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/Request.js │ │ │ │ - * @requires OpenLayers/Console.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.CacheWrite │ │ │ │ - * A control for caching image tiles in the browser's local storage. The │ │ │ │ - * <OpenLayers.Control.CacheRead> control is used to fetch and use the cached │ │ │ │ - * tile images. │ │ │ │ - * │ │ │ │ - * Note: Before using this control on any layer that is not your own, make sure │ │ │ │ - * that the terms of service of the tile provider allow local storage of tiles. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: events │ │ │ │ - * {<OpenLayers.Events>} Events instance for listeners and triggering │ │ │ │ - * control specific events. │ │ │ │ - * │ │ │ │ - * To register events in the constructor, configure <eventListeners>. │ │ │ │ - * │ │ │ │ - * 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>): │ │ │ │ - * cachefull - Triggered when the cache is full. Listeners receive an │ │ │ │ - * object with a tile property as first argument. The tile references │ │ │ │ - * the tile that couldn't be cached. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: eventListeners │ │ │ │ - * {Object} Object with event listeners, keyed by event name. An optional │ │ │ │ - * scope property defines the scope that listeners will be executed in. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: layers │ │ │ │ - * {Array(<OpenLayers.Layer.Grid>)}. Optional. If provided, caching │ │ │ │ - * will be enabled for these layers only, otherwise for all cacheable │ │ │ │ - * layers. │ │ │ │ - */ │ │ │ │ - layers: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: imageFormat │ │ │ │ - * {String} The image format used for caching. The default is "image/png". │ │ │ │ - * Supported formats depend on the user agent. If an unsupported │ │ │ │ - * <imageFormat> is provided, "image/png" will be used. For aerial │ │ │ │ - * imagery, "image/jpeg" is recommended. │ │ │ │ - */ │ │ │ │ - imageFormat: "image/png", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: quotaRegEx │ │ │ │ - * {RegExp} │ │ │ │ - */ │ │ │ │ - quotaRegEx: (/quota/i), │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.CacheWrite │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Object with API properties for this control. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * Set the map property for the control. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ - */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - var i, layers = this.layers || map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.addLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - if (!this.layers) { │ │ │ │ - map.events.on({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: addLayer │ │ │ │ - * Adds a layer to the control. Once added, tiles requested for this layer │ │ │ │ - * will be cached. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} Object with a layer property referencing an │ │ │ │ - * <OpenLayers.Layer> instance │ │ │ │ - */ │ │ │ │ - addLayer: function(evt) { │ │ │ │ - evt.layer.events.on({ │ │ │ │ - tileloadstart: this.makeSameOrigin, │ │ │ │ - tileloaded: this.onTileLoaded, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: removeLayer │ │ │ │ - * Removes a layer from the control. Once removed, tiles requested for this │ │ │ │ - * layer will no longer be cached. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} Object with a layer property referencing an │ │ │ │ - * <OpenLayers.Layer> instance │ │ │ │ - */ │ │ │ │ - removeLayer: function(evt) { │ │ │ │ - evt.layer.events.un({ │ │ │ │ - tileloadstart: this.makeSameOrigin, │ │ │ │ - tileloaded: this.onTileLoaded, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: makeSameOrigin │ │ │ │ - * If the tile does not have CORS image loading enabled and is from a │ │ │ │ - * different origin, use OpenLayers.ProxyHost to make it a same origin url. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ - */ │ │ │ │ - makeSameOrigin: function(evt) { │ │ │ │ - if (this.active) { │ │ │ │ - var tile = evt.tile; │ │ │ │ - if (tile instanceof OpenLayers.Tile.Image && │ │ │ │ - !tile.crossOriginKeyword && │ │ │ │ - tile.url.substr(0, 5) !== "data:") { │ │ │ │ - var sameOriginUrl = OpenLayers.Request.makeSameOrigin( │ │ │ │ - tile.url, OpenLayers.ProxyHost │ │ │ │ - ); │ │ │ │ - OpenLayers.Control.CacheWrite.urlMap[sameOriginUrl] = tile.url; │ │ │ │ - tile.url = sameOriginUrl; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: onTileLoaded │ │ │ │ - * Decides whether a tile can be cached and calls the cache method. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - */ │ │ │ │ - onTileLoaded: function(evt) { │ │ │ │ - if (this.active && !evt.aborted && │ │ │ │ - evt.tile instanceof OpenLayers.Tile.Image && │ │ │ │ - evt.tile.url.substr(0, 5) !== 'data:') { │ │ │ │ - this.cache({ │ │ │ │ - tile: evt.tile │ │ │ │ - }); │ │ │ │ - delete OpenLayers.Control.CacheWrite.urlMap[evt.tile.url]; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: cache │ │ │ │ - * Adds a tile to the cache. When the cache is full, the "cachefull" event │ │ │ │ - * is triggered. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * obj - {Object} Object with a tile property, tile being the │ │ │ │ - * <OpenLayers.Tile.Image> with the data to add to the cache │ │ │ │ - */ │ │ │ │ - cache: function(obj) { │ │ │ │ - if (window.localStorage) { │ │ │ │ - var tile = obj.tile; │ │ │ │ - try { │ │ │ │ - var canvasContext = tile.getCanvasContext(); │ │ │ │ - if (canvasContext) { │ │ │ │ - var urlMap = OpenLayers.Control.CacheWrite.urlMap; │ │ │ │ - var url = urlMap[tile.url] || tile.url; │ │ │ │ - window.localStorage.setItem( │ │ │ │ - "olCache_" + url, │ │ │ │ - canvasContext.canvas.toDataURL(this.imageFormat) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } catch (e) { │ │ │ │ - // local storage full or CORS violation │ │ │ │ - var reason = e.name || e.message; │ │ │ │ - if (reason && this.quotaRegEx.test(reason)) { │ │ │ │ - this.events.triggerEvent("cachefull", { │ │ │ │ - tile: tile │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - OpenLayers.Console.error(e.toString()); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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.layers || this.map) { │ │ │ │ - var i, layers = this.layers || this.map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.removeLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.un({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.CacheWrite" │ │ │ │ -}); │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * APIFunction: OpenLayers.Control.CacheWrite.clearCache │ │ │ │ - * Clears all tiles cached with <OpenLayers.Control.CacheWrite> from the cache. │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.CacheWrite.clearCache = function() { │ │ │ │ - if (!window.localStorage) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - var i, key; │ │ │ │ - for (i = window.localStorage.length - 1; i >= 0; --i) { │ │ │ │ - key = window.localStorage.key(i); │ │ │ │ - if (key.substr(0, 8) === "olCache_") { │ │ │ │ - window.localStorage.removeItem(key); │ │ │ │ - } │ │ │ │ - } │ │ │ │ -}; │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Property: OpenLayers.Control.CacheWrite.urlMap │ │ │ │ - * {Object} Mapping of same origin urls to cache url keys. Entries will be │ │ │ │ - * deleted as soon as a tile was cached. │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.CacheWrite.urlMap = {}; │ │ │ │ - │ │ │ │ - │ │ │ │ -/* ====================================================================== │ │ │ │ - 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; │ │ │ │ - }, │ │ │ │ + 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. │ │ │ │ * │ │ │ │ @@ -46395,841 +41272,14 @@ │ │ │ │ OpenLayers.Event.stopObserving(document, "mousemove", this._docMove); │ │ │ │ OpenLayers.Event.stopObserving(document, "mouseup", this._docUp); │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Handler.Drag" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - 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/Control/DragFeature.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/Feature.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.DragFeature │ │ │ │ - * The DragFeature control moves a feature with a drag of the mouse. Create a │ │ │ │ - * new control with the <OpenLayers.Control.DragFeature> constructor. │ │ │ │ - * │ │ │ │ - * Inherits From: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.DragFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: geometryTypes │ │ │ │ - * {Array(String)} To restrict dragging to a limited set of geometry types, │ │ │ │ - * send a list of strings corresponding to the geometry class names. │ │ │ │ - */ │ │ │ │ - geometryTypes: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: onStart │ │ │ │ - * {Function} Define this function if you want to know when a drag starts. │ │ │ │ - * The function should expect to receive two arguments: the feature │ │ │ │ - * that is about to be dragged and the pixel location of the mouse. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature that is about to be │ │ │ │ - * dragged. │ │ │ │ - * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. │ │ │ │ - */ │ │ │ │ - onStart: function(feature, pixel) {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: onDrag │ │ │ │ - * {Function} Define this function if you want to know about each move of a │ │ │ │ - * feature. The function should expect to receive two arguments: the │ │ │ │ - * feature that is being dragged and the pixel location of the mouse. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. │ │ │ │ - * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. │ │ │ │ - */ │ │ │ │ - onDrag: function(feature, pixel) {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: onComplete │ │ │ │ - * {Function} Define this function if you want to know when a feature is │ │ │ │ - * done dragging. The function should expect to receive two arguments: │ │ │ │ - * the feature that is being dragged and the pixel location of the │ │ │ │ - * mouse. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. │ │ │ │ - * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. │ │ │ │ - */ │ │ │ │ - onComplete: function(feature, pixel) {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: onEnter │ │ │ │ - * {Function} Define this function if you want to know when the mouse │ │ │ │ - * goes over a feature and thereby makes this feature a candidate │ │ │ │ - * for dragging. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature that is ready │ │ │ │ - * to be dragged. │ │ │ │ - */ │ │ │ │ - onEnter: function(feature) {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: onLeave │ │ │ │ - * {Function} Define this function if you want to know when the mouse │ │ │ │ - * goes out of the feature that was dragged. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. │ │ │ │ - */ │ │ │ │ - onLeave: function(feature) {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: layer │ │ │ │ - * {<OpenLayers.Layer.Vector>} │ │ │ │ - */ │ │ │ │ - layer: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: feature │ │ │ │ - * {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - feature: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: dragCallbacks │ │ │ │ - * {Object} The functions that are sent to the drag handler for callback. │ │ │ │ - */ │ │ │ │ - dragCallbacks: {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: featureCallbacks │ │ │ │ - * {Object} The functions that are sent to the feature handler for callback. │ │ │ │ - */ │ │ │ │ - featureCallbacks: {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: lastPixel │ │ │ │ - * {<OpenLayers.Pixel>} │ │ │ │ - */ │ │ │ │ - lastPixel: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.DragFeature │ │ │ │ - * Create a new control to drag features. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} The layer containing features to be │ │ │ │ - * dragged. │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * control. │ │ │ │ - */ │ │ │ │ - initialize: function(layer, options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.layer = layer; │ │ │ │ - this.handlers = { │ │ │ │ - drag: new OpenLayers.Handler.Drag( │ │ │ │ - this, OpenLayers.Util.extend({ │ │ │ │ - down: this.downFeature, │ │ │ │ - move: this.moveFeature, │ │ │ │ - up: this.upFeature, │ │ │ │ - out: this.cancel, │ │ │ │ - done: this.doneDragging │ │ │ │ - }, this.dragCallbacks), { │ │ │ │ - documentDrag: this.documentDrag │ │ │ │ - } │ │ │ │ - ), │ │ │ │ - feature: new OpenLayers.Handler.Feature( │ │ │ │ - this, this.layer, OpenLayers.Util.extend({ │ │ │ │ - // 'click' and 'clickout' callback are for the mobile │ │ │ │ - // support: no 'over' or 'out' in touch based browsers. │ │ │ │ - click: this.clickFeature, │ │ │ │ - clickout: this.clickoutFeature, │ │ │ │ - over: this.overFeature, │ │ │ │ - out: this.outFeature │ │ │ │ - }, this.featureCallbacks), { │ │ │ │ - geometryTypes: this.geometryTypes │ │ │ │ - } │ │ │ │ - ) │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: clickFeature │ │ │ │ - * Called when the feature handler detects a click-in on a feature. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - clickFeature: function(feature) { │ │ │ │ - if (this.handlers.feature.touch && !this.over && this.overFeature(feature)) { │ │ │ │ - this.handlers.drag.dragstart(this.handlers.feature.evt); │ │ │ │ - // to let the events propagate to the feature handler (click callback) │ │ │ │ - this.handlers.drag.stopDown = false; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: clickoutFeature │ │ │ │ - * Called when the feature handler detects a click-out on a feature. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - clickoutFeature: function(feature) { │ │ │ │ - if (this.handlers.feature.touch && this.over) { │ │ │ │ - this.outFeature(feature); │ │ │ │ - this.handlers.drag.stopDown = true; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Take care of things that are not handled in superclass │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - this.layer = null; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, []); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the control and the feature handler. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Successfully activated the control and feature handler. │ │ │ │ - */ │ │ │ │ - activate: function() { │ │ │ │ - return (this.handlers.feature.activate() && │ │ │ │ - OpenLayers.Control.prototype.activate.apply(this, arguments)); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the control and all handlers. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Successfully deactivated the control. │ │ │ │ - */ │ │ │ │ - deactivate: function() { │ │ │ │ - // the return from the handlers is unimportant in this case │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ - this.handlers.feature.deactivate(); │ │ │ │ - this.feature = null; │ │ │ │ - this.dragging = false; │ │ │ │ - this.lastPixel = null; │ │ │ │ - OpenLayers.Element.removeClass( │ │ │ │ - this.map.viewPortDiv, this.displayClass + "Over" │ │ │ │ - ); │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: overFeature │ │ │ │ - * Called when the feature handler detects a mouse-over on a feature. │ │ │ │ - * This activates the drag handler. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The selected feature. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Successfully activated the drag handler. │ │ │ │ - */ │ │ │ │ - overFeature: function(feature) { │ │ │ │ - var activated = false; │ │ │ │ - if (!this.handlers.drag.dragging) { │ │ │ │ - this.feature = feature; │ │ │ │ - this.handlers.drag.activate(); │ │ │ │ - activated = true; │ │ │ │ - this.over = true; │ │ │ │ - OpenLayers.Element.addClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ - this.onEnter(feature); │ │ │ │ - } else { │ │ │ │ - if (this.feature.id == feature.id) { │ │ │ │ - this.over = true; │ │ │ │ - } else { │ │ │ │ - this.over = false; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return activated; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: downFeature │ │ │ │ - * Called when the drag handler detects a mouse-down. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * pixel - {<OpenLayers.Pixel>} Location of the mouse event. │ │ │ │ - */ │ │ │ │ - downFeature: function(pixel) { │ │ │ │ - this.lastPixel = pixel; │ │ │ │ - this.onStart(this.feature, pixel); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: moveFeature │ │ │ │ - * Called when the drag handler detects a mouse-move. Also calls the │ │ │ │ - * optional onDrag method. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * pixel - {<OpenLayers.Pixel>} Location of the mouse event. │ │ │ │ - */ │ │ │ │ - moveFeature: function(pixel) { │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - this.feature.geometry.move(res * (pixel.x - this.lastPixel.x), │ │ │ │ - res * (this.lastPixel.y - pixel.y)); │ │ │ │ - this.layer.drawFeature(this.feature); │ │ │ │ - this.lastPixel = pixel; │ │ │ │ - this.onDrag(this.feature, pixel); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: upFeature │ │ │ │ - * Called when the drag handler detects a mouse-up. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * pixel - {<OpenLayers.Pixel>} Location of the mouse event. │ │ │ │ - */ │ │ │ │ - upFeature: function(pixel) { │ │ │ │ - if (!this.over) { │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: doneDragging │ │ │ │ - * Called when the drag handler is done dragging. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * pixel - {<OpenLayers.Pixel>} The last event pixel location. If this event │ │ │ │ - * came from a mouseout, this may not be in the map viewport. │ │ │ │ - */ │ │ │ │ - doneDragging: function(pixel) { │ │ │ │ - this.onComplete(this.feature, pixel); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: outFeature │ │ │ │ - * Called when the feature handler detects a mouse-out on a feature. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature that the mouse left. │ │ │ │ - */ │ │ │ │ - outFeature: function(feature) { │ │ │ │ - if (!this.handlers.drag.dragging) { │ │ │ │ - this.over = false; │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ - OpenLayers.Element.removeClass( │ │ │ │ - this.map.viewPortDiv, this.displayClass + "Over" │ │ │ │ - ); │ │ │ │ - this.onLeave(feature); │ │ │ │ - this.feature = null; │ │ │ │ - } else { │ │ │ │ - if (this.feature.id == feature.id) { │ │ │ │ - this.over = false; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: cancel │ │ │ │ - * Called when the drag handler detects a mouse-out (from the map viewport). │ │ │ │ - */ │ │ │ │ - cancel: function() { │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ - this.over = false; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - this.handlers.feature.setMap(map); │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.DragFeature" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ OpenLayers/Handler/RegularPolygon.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. */ │ │ │ │ @@ -47657,1443 +41707,468 @@ │ │ │ │ this.clear(); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Handler.RegularPolygon" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Handler/Point.js │ │ │ │ + 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 │ │ │ │ - * @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. │ │ │ │ - * │ │ │ │ + * 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.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 │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ +OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * turn off the handler │ │ │ │ + * Property: EVENTMAP │ │ │ │ + * {Object} A object mapping the browser events to objects with callback │ │ │ │ + * keys for in and out. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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' │ │ │ │ } │ │ │ │ - this.layer = null; │ │ │ │ - return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroyFeature │ │ │ │ - * Destroy the temporary geometries │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * force - {Boolean} Destroy even if persist is true. │ │ │ │ + * Property: feature │ │ │ │ + * {<OpenLayers.Feature.Vector>} The last feature that was hovered. │ │ │ │ */ │ │ │ │ - destroyFeature: function(force) { │ │ │ │ - if (this.layer && (force || !this.persist)) { │ │ │ │ - this.layer.destroyFeatures(); │ │ │ │ - } │ │ │ │ - this.point = null; │ │ │ │ - }, │ │ │ │ + feature: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroyPersistedFeature │ │ │ │ - * Destroy the persisted feature. │ │ │ │ + * Property: lastFeature │ │ │ │ + * {<OpenLayers.Feature.Vector>} The last feature that was handled. │ │ │ │ */ │ │ │ │ - destroyPersistedFeature: function() { │ │ │ │ - var layer = this.layer; │ │ │ │ - if (layer && layer.features.length > 1) { │ │ │ │ - this.layer.features[0].destroy(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + lastFeature: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: finalize │ │ │ │ - * Finish the geometry and call the "done" callback. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * cancel - {Boolean} Call cancel instead of done callback. Default │ │ │ │ - * is false. │ │ │ │ + * Property: down │ │ │ │ + * {<OpenLayers.Pixel>} The location of the last mousedown. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - }, │ │ │ │ + down: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: cancel │ │ │ │ - * Finish the geometry and call the "cancel" callback. │ │ │ │ + * Property: up │ │ │ │ + * {<OpenLayers.Pixel>} The location of the last mouseup. │ │ │ │ */ │ │ │ │ - cancel: function() { │ │ │ │ - this.finalize(true); │ │ │ │ - }, │ │ │ │ + up: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - click: function(evt) { │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - return false; │ │ │ │ - }, │ │ │ │ + clickTolerance: 4, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: dblclick │ │ │ │ - * Handle double-clicks. Double-clicks are stopped from propagating to other │ │ │ │ - * listeners on map.events or other dom elements. │ │ │ │ + * Property: geometryTypes │ │ │ │ + * To restrict dragging to a limited set of geometry types, send a list │ │ │ │ + * of strings corresponding to the geometry class names. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} The browser event │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow event propagation │ │ │ │ + * @type Array(String) │ │ │ │ */ │ │ │ │ - dblclick: function(evt) { │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - return false; │ │ │ │ - }, │ │ │ │ + geometryTypes: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: modifyFeature │ │ │ │ - * Modify the existing geometry given a pixel location. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * pixel - {<OpenLayers.Pixel>} A pixel location on the map. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - }, │ │ │ │ + stopClick: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawFeature │ │ │ │ - * Render features on the temporary layer. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - drawFeature: function() { │ │ │ │ - this.layer.drawFeature(this.point, this.style); │ │ │ │ - }, │ │ │ │ + stopDown: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getGeometry │ │ │ │ - * Return the sketch geometry. If <multi> is true, this will return │ │ │ │ - * a multi-part geometry. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Geometry.Point>} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - getGeometry: function() { │ │ │ │ - var geometry = this.point && this.point.geometry; │ │ │ │ - if (geometry && this.multi) { │ │ │ │ - geometry = new OpenLayers.Geometry.MultiPoint([geometry]); │ │ │ │ - } │ │ │ │ - return geometry; │ │ │ │ - }, │ │ │ │ + stopUp: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: geometryClone │ │ │ │ - * Return a clone of the relevant geometry. │ │ │ │ + * Constructor: OpenLayers.Handler.Feature │ │ │ │ * │ │ │ │ - * 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 │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - mousedown: function(evt) { │ │ │ │ - return this.down(evt); │ │ │ │ + initialize: function(control, layer, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ + this.layer = layer; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * Method: touchstart │ │ │ │ - * Handle touchstart. │ │ │ │ - * │ │ │ │ + * Handle touchstart events │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} The browser event │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow event propagation │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ 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); │ │ │ │ + return OpenLayers.Event.isMultiTouch(evt) ? │ │ │ │ + true : this.mousedown(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * Method: touchmove │ │ │ │ - * Handle touchmove. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} The browser event │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow event propagation │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ touchmove: function(evt) { │ │ │ │ - this.lastTouchPx = evt.xy; │ │ │ │ - return this.move(evt); │ │ │ │ + OpenLayers.Event.preventDefault(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: mouseup │ │ │ │ - * Handle mouseup. │ │ │ │ + * Method: mousedown │ │ │ │ + * Handle mouse down. Stop propagation if a feature is targeted by this │ │ │ │ + * event (stops map dragging during feature selection). │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} The browser event │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow event propagation │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - mouseup: function(evt) { │ │ │ │ - return this.up(evt); │ │ │ │ + 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: touchend │ │ │ │ - * Handle touchend. │ │ │ │ + * Method: mouseup │ │ │ │ + * Handle mouse up. Stop propagation if a feature is targeted by this │ │ │ │ + * event. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} The browser event │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow event propagation │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - touchend: function(evt) { │ │ │ │ - evt.xy = this.lastTouchPx; │ │ │ │ - return this.up(evt); │ │ │ │ + mouseup: function(evt) { │ │ │ │ + this.up = evt.xy; │ │ │ │ + return this.handle(evt) ? !this.stopUp : true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: down │ │ │ │ - * Handle mousedown and touchstart. Adjust the geometry and redraw. │ │ │ │ - * Return determines whether to propagate the event on the map. │ │ │ │ + * 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} The browser event │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow event propagation │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + click: function(evt) { │ │ │ │ + return this.handle(evt) ? !this.stopClick : true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: move │ │ │ │ - * Handle mousemove and touchmove. Adjust the geometry and redraw. │ │ │ │ - * Return determines whether to propagate the event on the map. │ │ │ │ + * 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} 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 │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow event propagation │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - 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 { │ │ │ │ + mousemove: function(evt) { │ │ │ │ + if (!this.callbacks['over'] && !this.callbacks['out']) { │ │ │ │ return true; │ │ │ │ } │ │ │ │ + this.handle(evt); │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: mouseout │ │ │ │ - * Handle mouse out. For better user experience reset mouseDown │ │ │ │ - * and stoppedDown when the mouse leaves the map viewport. │ │ │ │ + * Method: dblclick │ │ │ │ + * Handle dblclick. Call the "dblclick" callback if dblclick on a feature. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - insertDirectionLength: function(direction, length) { │ │ │ │ - direction *= Math.PI / 180; │ │ │ │ - var dx = length * Math.cos(direction); │ │ │ │ - var dy = length * Math.sin(direction); │ │ │ │ - this.insertDeltaXY(dx, dy); │ │ │ │ + dblclick: function(evt) { │ │ │ │ + return !this.handle(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: geometryTypeMatches │ │ │ │ + * Return true if the geometry type of the passed feature matches │ │ │ │ + * one of the geometry types in the geometryTypes array. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * feature - {<OpenLayers.Vector.Feature>} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ * {Boolean} │ │ │ │ */ │ │ │ │ - freehandMode: function(evt) { │ │ │ │ - return (this.freehandToggle && evt[this.freehandToggle]) ? │ │ │ │ - !this.freehand : this.freehand; │ │ │ │ + geometryTypeMatches: function(feature) { │ │ │ │ + return this.geometryTypes == null || │ │ │ │ + OpenLayers.Util.indexOf(this.geometryTypes, │ │ │ │ + feature.geometry.CLASS_NAME) > -1; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: modifyFeature │ │ │ │ - * Modify the existing geometry given the new point │ │ │ │ + * Method: handle │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ * 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 │ │ │ │ + * {Boolean} The event occurred over a relevant feature. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + handle: function(evt) { │ │ │ │ + if (this.feature && !this.feature.layer) { │ │ │ │ + // feature has been destroyed │ │ │ │ + this.feature = null; │ │ │ │ } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - } │ │ │ │ + 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.touch && (!this.lastDown || │ │ │ │ - !this.passesTolerance(this.lastDown, evt.xy, │ │ │ │ - this.pixelTolerance))) { │ │ │ │ - this.modifyFeature(evt.xy, !!this.lastUp); │ │ │ │ + if (this.lastFeature && !this.lastFeature.layer) { │ │ │ │ + // last feature has been destroyed │ │ │ │ + this.lastFeature = null; │ │ │ │ } │ │ │ │ - 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); │ │ │ │ + if (this.feature) { │ │ │ │ + if (type === "touchstart") { │ │ │ │ + // stop the event to prevent Android Webkit from │ │ │ │ + // "flashing" the map div │ │ │ │ + OpenLayers.Event.preventDefault(evt); │ │ │ │ } │ │ │ │ - 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(); │ │ │ │ + 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.removePoint(); │ │ │ │ - this.finalize(); │ │ │ │ + this.lastFeature = this.feature; │ │ │ │ + handled = true; │ │ │ │ } 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(); │ │ │ │ - } │ │ │ │ + // 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]); │ │ │ │ } │ │ │ │ - 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/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 │ │ │ │ - }); │ │ │ │ + return handled; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: addPoint │ │ │ │ - * Add point to geometry. │ │ │ │ + * Method: triggerCallback │ │ │ │ + * Call the callback keyed in the event map with the supplied arguments. │ │ │ │ + * For click and clickout, the <clickTolerance> is checked first. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * pixel - {<OpenLayers.Pixel>} The pixel location for the new point. │ │ │ │ + * type - {String} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ } │ │ │ │ - OpenLayers.Handler.Path.prototype.addPoint.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getCurrentPointIndex │ │ │ │ - * │ │ │ │ + * Method: activate │ │ │ │ + * Turn on the handler. Returns false if the handler was already active. │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - cancel: function() { │ │ │ │ - if (this.drawingHole) { │ │ │ │ - this.polygon.geometry.removeComponent(this.line.geometry); │ │ │ │ - this.restoreFeature(true); │ │ │ │ + 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 OpenLayers.Handler.Path.prototype.cancel.apply(this, arguments); │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: restoreFeature │ │ │ │ - * Move the feature from the sketch layer to the target layer. │ │ │ │ + * Method: deactivate │ │ │ │ + * Turn off the handler. Returns false if the handler was already active. │ │ │ │ * │ │ │ │ - * Properties: │ │ │ │ - * cancel - {Boolean} Cancel drawing. If falsey, the "sketchcomplete" event │ │ │ │ - * will be fired. │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - ); │ │ │ │ + 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: destroyFeature │ │ │ │ - * Destroy temporary geometries │ │ │ │ - * │ │ │ │ + * Method: handleMapEvents │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * force - {Boolean} Destroy even if persist is true. │ │ │ │ + * evt - {Object} │ │ │ │ */ │ │ │ │ - destroyFeature: function(force) { │ │ │ │ - OpenLayers.Handler.Path.prototype.destroyFeature.call( │ │ │ │ - this, force); │ │ │ │ - this.polygon = null; │ │ │ │ + handleMapEvents: function(evt) { │ │ │ │ + if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ + this.moveLayerToTop(); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawFeature │ │ │ │ - * Render geometries on the temporary layer. │ │ │ │ + * Method: moveLayerToTop │ │ │ │ + * Moves the layer for this handler to the top, so mouse events can reach │ │ │ │ + * it. │ │ │ │ */ │ │ │ │ - drawFeature: function() { │ │ │ │ - this.layer.drawFeature(this.polygon, this.style); │ │ │ │ - this.layer.drawFeature(this.point, this.style); │ │ │ │ - }, │ │ │ │ + moveLayerToTop: function() { │ │ │ │ + var index = Math.max(this.map.Z_INDEX_BASE['Feature'] - 1, │ │ │ │ + this.layer.getZIndex()) + 1; │ │ │ │ + this.layer.setZIndex(index); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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>} │ │ │ │ + * Method: moveLayerBack │ │ │ │ + * Moves the layer back to the position determined by the map's layers │ │ │ │ + * array. │ │ │ │ */ │ │ │ │ - getGeometry: function() { │ │ │ │ - var geometry = this.polygon && this.polygon.geometry; │ │ │ │ - if (geometry && this.multi) { │ │ │ │ - geometry = new OpenLayers.Geometry.MultiPolygon([geometry]); │ │ │ │ + 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)); │ │ │ │ } │ │ │ │ - return geometry; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Polygon" │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Feature" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ 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. │ │ │ │ @@ -49597,4277 +42672,14634 @@ │ │ │ │ } │ │ │ │ return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Handler.Click" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/SLD.js │ │ │ │ + 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/Format/XML/VersionedOGC.js │ │ │ │ - * @requires OpenLayers/Style.js │ │ │ │ - * @requires OpenLayers/Rule.js │ │ │ │ - * @requires OpenLayers/Filter/FeatureId.js │ │ │ │ - * @requires OpenLayers/Filter/Logical.js │ │ │ │ - * @requires OpenLayers/Filter/Comparison.js │ │ │ │ - * @requires OpenLayers/Filter/Spatial.js │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.SLD │ │ │ │ - * Read/Write SLD. Create a new instance with the <OpenLayers.Format.SLD> │ │ │ │ - * constructor. │ │ │ │ + * Class: OpenLayers.handler.Keyboard │ │ │ │ + * A handler for keyboard events. Create a new instance with the │ │ │ │ + * <OpenLayers.Handler.Keyboard> constructor. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.SLD = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ +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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: profile │ │ │ │ - * {String} If provided, use a custom profile. │ │ │ │ - * │ │ │ │ - * Currently supported profiles: │ │ │ │ - * - GeoServer - parses GeoServer vendor specific capabilities for SLD. │ │ │ │ + * Property: observeElement │ │ │ │ + * {DOMElement|String} The DOM element on which we listen for │ │ │ │ + * key events. Default to the document. │ │ │ │ */ │ │ │ │ - profile: null, │ │ │ │ + observeElement: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "1.0.0". │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - defaultVersion: "1.0.0", │ │ │ │ + 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 │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: stringifyOutput │ │ │ │ - * {Boolean} If true, write will return a string otherwise a DOMElement. │ │ │ │ - * Default is true. │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - stringifyOutput: true, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + this.eventListener = null; │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: namedLayersAsArray │ │ │ │ - * {Boolean} Generate a namedLayers array. If false, the namedLayers │ │ │ │ - * property value will be an object keyed by layer name. Default is │ │ │ │ - * false. │ │ │ │ + * Method: activate │ │ │ │ */ │ │ │ │ - namedLayersAsArray: false, │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Write a SLD document given a list of styles. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * sld - {Object} An object representing the SLD. │ │ │ │ - * options - {Object} Optional configuration object. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} An SLD document string. │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read and SLD doc and return an object representing the SLD. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String | DOMElement} Data to read. │ │ │ │ - * options - {Object} Options for the reader. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An object representing the SLD. │ │ │ │ + * Method: handleKeyEvent │ │ │ │ */ │ │ │ │ + handleKeyEvent: function(evt) { │ │ │ │ + if (this.checkModifiers(evt)) { │ │ │ │ + this.callback(evt.type, [evt]); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SLD" │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Keyboard" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/GML/v2.js │ │ │ │ + OpenLayers/Handler/Box.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 │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ + * @requires OpenLayers/Handler/Drag.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.GML.v2 │ │ │ │ - * Parses GML version 2. │ │ │ │ + * Class: OpenLayers.Handler.Box │ │ │ │ + * Handler for dragging a rectangle across the map. Box is displayed │ │ │ │ + * on mouse down, moves on mouse move, and is finished on mouse up. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.GML.Base> │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, { │ │ │ │ +OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: dragHandler │ │ │ │ + * {<OpenLayers.Handler.Drag>} │ │ │ │ + */ │ │ │ │ + dragHandler: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} Schema location for a particular minor version. │ │ │ │ + * APIProperty: boxDivClassName │ │ │ │ + * {String} The CSS class to use for drawing the box. Default is │ │ │ │ + * olHandlerBoxZoomBox │ │ │ │ */ │ │ │ │ - schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd", │ │ │ │ + boxDivClassName: 'olHandlerBoxZoomBox', │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.GML.v2 │ │ │ │ - * Create a parser for GML v2. │ │ │ │ + * Property: boxOffsets │ │ │ │ + * {Object} Caches box offsets from css. This is used by the getBoxOffsets │ │ │ │ + * method. │ │ │ │ + */ │ │ │ │ + boxOffsets: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Handler.Box │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * control - {<OpenLayers.Control>} │ │ │ │ + * callbacks - {Object} An object with a properties whose values are │ │ │ │ + * functions. Various callbacks described below. │ │ │ │ + * options - {Object} │ │ │ │ * │ │ │ │ - * Valid options properties: │ │ │ │ - * featureType - {String} Local (without prefix) feature typeName (required). │ │ │ │ - * featureNS - {String} Feature namespace (required). │ │ │ │ - * geometryName - {String} Geometry element name. │ │ │ │ + * Named callbacks: │ │ │ │ + * start - Called when the box drag operation starts. │ │ │ │ + * done - Called when the box drag operation is finished. │ │ │ │ + * The callback should expect to receive a single argument, the box │ │ │ │ + * bounds or a pixel. If the box dragging didn't span more than a 5 │ │ │ │ + * pixel distance, a pixel will be returned instead of a bounds object. │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]); │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ + this.dragHandler = new OpenLayers.Handler.Drag( │ │ │ │ + this, { │ │ │ │ + down: this.startBox, │ │ │ │ + move: this.moveBox, │ │ │ │ + out: this.removeBox, │ │ │ │ + up: this.endBox │ │ │ │ + }, { │ │ │ │ + keyMask: this.keyMask │ │ │ │ + } │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - 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"] │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ + if (this.dragHandler) { │ │ │ │ + this.dragHandler.destroy(); │ │ │ │ + this.dragHandler = null; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: write │ │ │ │ + * Method: setMap │ │ │ │ + */ │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Handler.prototype.setMap.apply(this, arguments); │ │ │ │ + if (this.dragHandler) { │ │ │ │ + this.dragHandler.setMap(map); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: startBox │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * xy - {<OpenLayers.Pixel>} │ │ │ │ */ │ │ │ │ - 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"; │ │ │ │ + startBox: function(xy) { │ │ │ │ + this.callback("start", []); │ │ │ │ + this.zoomBox = OpenLayers.Util.createDiv('zoomBox', { │ │ │ │ + x: -9999, │ │ │ │ + y: -9999 │ │ │ │ + }); │ │ │ │ + this.zoomBox.className = this.boxDivClassName; │ │ │ │ + this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1; │ │ │ │ + │ │ │ │ + this.map.viewPortDiv.appendChild(this.zoomBox); │ │ │ │ + │ │ │ │ + OpenLayers.Element.addClass( │ │ │ │ + this.map.viewPortDiv, "olDrawBox" │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveBox │ │ │ │ + */ │ │ │ │ + moveBox: function(xy) { │ │ │ │ + var startX = this.dragHandler.start.x; │ │ │ │ + var startY = this.dragHandler.start.y; │ │ │ │ + var deltaX = Math.abs(startX - xy.x); │ │ │ │ + var deltaY = Math.abs(startY - xy.y); │ │ │ │ + │ │ │ │ + var offset = this.getBoxOffsets(); │ │ │ │ + this.zoomBox.style.width = (deltaX + offset.width + 1) + "px"; │ │ │ │ + this.zoomBox.style.height = (deltaY + offset.height + 1) + "px"; │ │ │ │ + this.zoomBox.style.left = (xy.x < startX ? │ │ │ │ + startX - deltaX - offset.left : startX - offset.left) + "px"; │ │ │ │ + this.zoomBox.style.top = (xy.y < startY ? │ │ │ │ + startY - deltaY - offset.top : startY - offset.top) + "px"; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: endBox │ │ │ │ + */ │ │ │ │ + endBox: function(end) { │ │ │ │ + var result; │ │ │ │ + if (Math.abs(this.dragHandler.start.x - end.x) > 5 || │ │ │ │ + Math.abs(this.dragHandler.start.y - end.y) > 5) { │ │ │ │ + var start = this.dragHandler.start; │ │ │ │ + var top = Math.min(start.y, end.y); │ │ │ │ + var bottom = Math.max(start.y, end.y); │ │ │ │ + var left = Math.min(start.x, end.x); │ │ │ │ + var right = Math.max(start.x, end.x); │ │ │ │ + result = new OpenLayers.Bounds(left, bottom, right, top); │ │ │ │ } else { │ │ │ │ - name = "gml:featureMember"; │ │ │ │ + result = this.dragHandler.start.clone(); // i.e. OL.Pixel │ │ │ │ } │ │ │ │ - var root = this.writeNode(name, features); │ │ │ │ - this.setAttributeNS( │ │ │ │ - root, this.namespaces["xsi"], │ │ │ │ - "xsi:schemaLocation", this.schemaLocation │ │ │ │ + this.removeBox(); │ │ │ │ + │ │ │ │ + this.callback("done", [result]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: removeBox │ │ │ │ + * Remove the zoombox from the screen and nullify our reference to it. │ │ │ │ + */ │ │ │ │ + removeBox: function() { │ │ │ │ + this.map.viewPortDiv.removeChild(this.zoomBox); │ │ │ │ + this.zoomBox = null; │ │ │ │ + this.boxOffsets = null; │ │ │ │ + OpenLayers.Element.removeClass( │ │ │ │ + this.map.viewPortDiv, "olDrawBox" │ │ │ │ ); │ │ │ │ │ │ │ │ - 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. │ │ │ │ + * Method: activate │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + activate: function() { │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.dragHandler.activate(); │ │ │ │ + return true; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: deactivate │ │ │ │ + */ │ │ │ │ + deactivate: function() { │ │ │ │ + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + if (this.dragHandler.deactivate()) { │ │ │ │ + if (this.zoomBox) { │ │ │ │ + this.removeBox(); │ │ │ │ } │ │ │ │ - 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"] │ │ │ │ + return true; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.GML.v2" │ │ │ │ + /** │ │ │ │ + * Method: getBoxOffsets │ │ │ │ + * Determines border offsets for a box, according to the box model. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} an object with the following offsets: │ │ │ │ + * - left │ │ │ │ + * - right │ │ │ │ + * - top │ │ │ │ + * - bottom │ │ │ │ + * - width │ │ │ │ + * - height │ │ │ │ + */ │ │ │ │ + getBoxOffsets: function() { │ │ │ │ + if (!this.boxOffsets) { │ │ │ │ + // Determine the box model. If the testDiv's clientWidth is 3, then │ │ │ │ + // the borders are outside and we are dealing with the w3c box │ │ │ │ + // model. Otherwise, the browser uses the traditional box model and │ │ │ │ + // the borders are inside the box bounds, leaving us with a │ │ │ │ + // clientWidth of 1. │ │ │ │ + var testDiv = document.createElement("div"); │ │ │ │ + //testDiv.style.visibility = "hidden"; │ │ │ │ + testDiv.style.position = "absolute"; │ │ │ │ + testDiv.style.border = "1px solid black"; │ │ │ │ + testDiv.style.width = "3px"; │ │ │ │ + document.body.appendChild(testDiv); │ │ │ │ + var w3cBoxModel = testDiv.clientWidth == 3; │ │ │ │ + document.body.removeChild(testDiv); │ │ │ │ + │ │ │ │ + var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ + "border-left-width")); │ │ │ │ + var right = parseInt(OpenLayers.Element.getStyle( │ │ │ │ + this.zoomBox, "border-right-width")); │ │ │ │ + var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ + "border-top-width")); │ │ │ │ + var bottom = parseInt(OpenLayers.Element.getStyle( │ │ │ │ + this.zoomBox, "border-bottom-width")); │ │ │ │ + this.boxOffsets = { │ │ │ │ + left: left, │ │ │ │ + right: right, │ │ │ │ + top: top, │ │ │ │ + bottom: bottom, │ │ │ │ + width: w3cBoxModel === false ? left + right : 0, │ │ │ │ + height: w3cBoxModel === false ? top + bottom : 0 │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + return this.boxOffsets; │ │ │ │ + }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Box" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ + OpenLayers/Handler/MouseWheel.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 │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.Filter.v1_0_0 │ │ │ │ - * Write ogc:Filter version 1.0.0. │ │ │ │ + * Class: OpenLayers.Handler.MouseWheel │ │ │ │ + * Handler for wheel up/down events. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.GML.v2> │ │ │ │ - * - <OpenLayers.Format.Filter.v1> │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.Filter.v1_0_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.GML.v2, OpenLayers.Format.Filter.v1, { │ │ │ │ +OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + /** │ │ │ │ + * Property: wheelListener │ │ │ │ + * {function} │ │ │ │ + */ │ │ │ │ + wheelListener: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: VERSION │ │ │ │ - * {String} 1.0.0 │ │ │ │ - */ │ │ │ │ - VERSION: "1.0.0", │ │ │ │ + /** │ │ │ │ + * Property: interval │ │ │ │ + * {Integer} In order to increase server performance, an interval (in │ │ │ │ + * milliseconds) can be set to reduce the number of up/down events │ │ │ │ + * called. If set, a new up/down event will not be set until the │ │ │ │ + * interval has passed. │ │ │ │ + * Defaults to 0, meaning no interval. │ │ │ │ + */ │ │ │ │ + interval: 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", │ │ │ │ + /** │ │ │ │ + * Property: maxDelta │ │ │ │ + * {Integer} Maximum delta to collect before breaking from the current │ │ │ │ + * interval. In cumulative mode, this also limits the maximum delta │ │ │ │ + * returned from the handler. Default is Number.POSITIVE_INFINITY. │ │ │ │ + */ │ │ │ │ + maxDelta: Number.POSITIVE_INFINITY, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: delta │ │ │ │ + * {Integer} When interval is set, delta collects the mousewheel z-deltas │ │ │ │ + * of the events that occur within the interval. │ │ │ │ + * See also the cumulative option │ │ │ │ + */ │ │ │ │ + delta: 0, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + /** │ │ │ │ + * Property: cumulative │ │ │ │ + * {Boolean} When interval is set: true to collect all the mousewheel │ │ │ │ + * z-deltas, false to only record the delta direction (positive or │ │ │ │ + * negative) │ │ │ │ + */ │ │ │ │ + cumulative: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Handler.MouseWheel │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * control - {<OpenLayers.Control>} │ │ │ │ + * 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 point geometry. │ │ │ │ + * options - {Object} │ │ │ │ + */ │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ + this.wheelListener = OpenLayers.Function.bindAsEventListener( │ │ │ │ + this.onWheelEvent, this │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ + this.wheelListener = null; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/ │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: onWheelEvent │ │ │ │ + * Catch the wheel event and handle it xbrowserly │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * e - {Event} │ │ │ │ + */ │ │ │ │ + onWheelEvent: function(e) { │ │ │ │ + │ │ │ │ + // make sure we have a map and check keyboard modifiers │ │ │ │ + if (!this.map || !this.checkModifiers(e)) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // Ride up the element's DOM hierarchy to determine if it or any of │ │ │ │ + // its ancestors was: │ │ │ │ + // * specifically marked as scrollable (CSS overflow property) │ │ │ │ + // * one of our layer divs or a div marked as scrollable │ │ │ │ + // ('olScrollable' CSS class) │ │ │ │ + // * the map div │ │ │ │ + // │ │ │ │ + var overScrollableDiv = false; │ │ │ │ + var allowScroll = false; │ │ │ │ + var overMapDiv = false; │ │ │ │ + │ │ │ │ + var elem = OpenLayers.Event.element(e); │ │ │ │ + while ((elem != null) && !overMapDiv && !overScrollableDiv) { │ │ │ │ + │ │ │ │ + if (!overScrollableDiv) { │ │ │ │ + try { │ │ │ │ + var overflow; │ │ │ │ + if (elem.currentStyle) { │ │ │ │ + overflow = elem.currentStyle["overflow"]; │ │ │ │ + } else { │ │ │ │ + var style = │ │ │ │ + document.defaultView.getComputedStyle(elem, null); │ │ │ │ + overflow = style.getPropertyValue("overflow"); │ │ │ │ + } │ │ │ │ + overScrollableDiv = (overflow && │ │ │ │ + (overflow == "auto") || (overflow == "scroll")); │ │ │ │ + } catch (err) { │ │ │ │ + //sometimes when scrolling in a popup, this causes │ │ │ │ + // obscure browser error │ │ │ │ } │ │ │ │ - }, 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: "!" │ │ │ │ + if (!allowScroll) { │ │ │ │ + allowScroll = OpenLayers.Element.hasClass(elem, 'olScrollable'); │ │ │ │ + if (!allowScroll) { │ │ │ │ + for (var i = 0, len = this.map.layers.length; i < len; i++) { │ │ │ │ + // Are we in the layer div? Note that we have two cases │ │ │ │ + // here: one is to catch EventPane layers, which have a │ │ │ │ + // pane above the layer (layer.pane) │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + if (elem == layer.div || elem == layer.pane) { │ │ │ │ + allowScroll = true; │ │ │ │ + break; │ │ │ │ } │ │ │ │ - }); │ │ │ │ - // 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"] │ │ │ │ - }, │ │ │ │ + } │ │ │ │ + overMapDiv = (elem == this.map.div); │ │ │ │ + │ │ │ │ + elem = elem.parentNode; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // Logic below is the following: │ │ │ │ + // │ │ │ │ + // If we are over a scrollable div or not over the map div: │ │ │ │ + // * do nothing (let the browser handle scrolling) │ │ │ │ + // │ │ │ │ + // otherwise │ │ │ │ + // │ │ │ │ + // If we are over the layer div or a 'olScrollable' div: │ │ │ │ + // * zoom/in out │ │ │ │ + // then │ │ │ │ + // * kill event (so as not to also scroll the page after zooming) │ │ │ │ + // │ │ │ │ + // otherwise │ │ │ │ + // │ │ │ │ + // Kill the event (dont scroll the page if we wheel over the │ │ │ │ + // layerswitcher or the pan/zoom control) │ │ │ │ + // │ │ │ │ + if (!overScrollableDiv && overMapDiv) { │ │ │ │ + if (allowScroll) { │ │ │ │ + var delta = 0; │ │ │ │ + │ │ │ │ + if (e.wheelDelta) { │ │ │ │ + delta = e.wheelDelta; │ │ │ │ + if (delta % 160 === 0) { │ │ │ │ + // opera have steps of 160 instead of 120 │ │ │ │ + delta = delta * 0.75; │ │ │ │ + } │ │ │ │ + delta = delta / 120; │ │ │ │ + } else if (e.detail) { │ │ │ │ + // detail in Firefox on OS X is 1/3 of Windows │ │ │ │ + // so force delta 1 / -1 │ │ │ │ + delta = -(e.detail / Math.abs(e.detail)); │ │ │ │ + } │ │ │ │ + this.delta += delta; │ │ │ │ + │ │ │ │ + window.clearTimeout(this._timeoutId); │ │ │ │ + if (this.interval && Math.abs(this.delta) < this.maxDelta) { │ │ │ │ + // store e because window.event might change during delay │ │ │ │ + var evt = OpenLayers.Util.extend({}, e); │ │ │ │ + this._timeoutId = window.setTimeout( │ │ │ │ + OpenLayers.Function.bind(function() { │ │ │ │ + this.wheelZoom(evt); │ │ │ │ + }, this), │ │ │ │ + this.interval │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + this.wheelZoom(e); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: wheelZoom │ │ │ │ + * Given the wheel event, we carry out the appropriate zooming in or out, │ │ │ │ + * based on the 'wheelDelta' or 'detail' property of the event. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * e - {Event} │ │ │ │ + */ │ │ │ │ + wheelZoom: function(e) { │ │ │ │ + var delta = this.delta; │ │ │ │ + this.delta = 0; │ │ │ │ + │ │ │ │ + if (delta) { │ │ │ │ + e.xy = this.map.events.getMousePosition(e); │ │ │ │ + if (delta < 0) { │ │ │ │ + this.callback("down", │ │ │ │ + [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]); │ │ │ │ + } else { │ │ │ │ + this.callback("up", │ │ │ │ + [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: activate │ │ │ │ + */ │ │ │ │ + activate: function(evt) { │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + //register mousewheel events specifically on the window and document │ │ │ │ + var wheelListener = this.wheelListener; │ │ │ │ + OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener); │ │ │ │ + OpenLayers.Event.observe(window, "mousewheel", wheelListener); │ │ │ │ + OpenLayers.Event.observe(document, "mousewheel", wheelListener); │ │ │ │ + return true; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: deactivate │ │ │ │ + */ │ │ │ │ + deactivate: function(evt) { │ │ │ │ + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + // unregister mousewheel events specifically on the window and document │ │ │ │ + var wheelListener = this.wheelListener; │ │ │ │ + OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener); │ │ │ │ + OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener); │ │ │ │ + OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener); │ │ │ │ + return true; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.MouseWheel" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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/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/UTFGrid.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 │ │ │ │ + * @requires OpenLayers/Tile/UTFGrid.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.UTFGrid │ │ │ │ + * This Layer reads from UTFGrid tiled data sources. Since UTFGrids are │ │ │ │ + * essentially JSON-based ASCII art with attached attributes, they are not │ │ │ │ + * visibly rendered. In order to use them in the map, you must add a │ │ │ │ + * <OpenLayers.Control.UTFGrid> control as well. │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * │ │ │ │ + * (start code) │ │ │ │ + * var world_utfgrid = new OpenLayers.Layer.UTFGrid({ │ │ │ │ + * url: "/tiles/world_utfgrid/${z}/${x}/${y}.json", │ │ │ │ + * utfgridResolution: 4, │ │ │ │ + * displayInLayerSwitcher: false │ │ │ │ + * ); │ │ │ │ + * map.addLayer(world_utfgrid); │ │ │ │ + * │ │ │ │ + * var control = new OpenLayers.Control.UTFGrid({ │ │ │ │ + * layers: [world_utfgrid], │ │ │ │ + * handlerMode: 'move', │ │ │ │ + * callback: function(dataLookup) { │ │ │ │ + * // do something with returned data │ │ │ │ + * } │ │ │ │ + * }) │ │ │ │ + * (end code) │ │ │ │ + * │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.XYZ> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.UTFGrid = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * Default is false, as UTFGrids are designed to be a transparent overlay layer. │ │ │ │ + */ │ │ │ │ + isBaseLayer: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: projection │ │ │ │ + * {<OpenLayers.Projection>} │ │ │ │ + * Source projection for the UTFGrids. Default is "EPSG:900913". │ │ │ │ + */ │ │ │ │ + projection: new OpenLayers.Projection("EPSG:900913"), │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: useJSONP │ │ │ │ + * {Boolean} │ │ │ │ + * Should we use a JSONP script approach instead of a standard AJAX call? │ │ │ │ + * │ │ │ │ + * Set to true for using utfgrids from another server. │ │ │ │ + * Avoids same-domain policy restrictions. │ │ │ │ + * Note that this only works if the server accepts │ │ │ │ + * the callback GET parameter and dynamically │ │ │ │ + * wraps the returned json in a function call. │ │ │ │ + * │ │ │ │ + * Default is false │ │ │ │ + */ │ │ │ │ + useJSONP: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: url │ │ │ │ + * {String} │ │ │ │ + * URL tempate for UTFGrid tiles. Include x, y, and z parameters. │ │ │ │ + * E.g. "/tiles/${z}/${x}/${y}.json" │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: utfgridResolution │ │ │ │ + * {Number} │ │ │ │ + * Ratio of the pixel width to the width of a UTFGrid data point. If an │ │ │ │ + * entry in the grid represents a 4x4 block of pixels, the │ │ │ │ + * utfgridResolution would be 4. Default is 2 (specified in │ │ │ │ + * <OpenLayers.Tile.UTFGrid>). │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: tileClass │ │ │ │ + * {<OpenLayers.Tile>} The tile class to use for this layer. │ │ │ │ + * Defaults is <OpenLayers.Tile.UTFGrid>. │ │ │ │ + */ │ │ │ │ + tileClass: OpenLayers.Tile.UTFGrid, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.UTFGrid │ │ │ │ + * Create a new UTFGrid layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * config - {Object} Configuration properties for the layer. │ │ │ │ + * │ │ │ │ + * Required configuration properties: │ │ │ │ + * url - {String} The url template for UTFGrid tiles. See the <url> property. │ │ │ │ + */ │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply( │ │ │ │ + this, [options.name, options.url, {}, options] │ │ │ │ + ); │ │ │ │ + this.tileOptions = OpenLayers.Util.extend({ │ │ │ │ + utfgridResolution: this.utfgridResolution │ │ │ │ + }, this.tileOptions); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: createBackBuffer │ │ │ │ + * The UTFGrid cannot create a back buffer, so this method is overriden. │ │ │ │ + */ │ │ │ │ + createBackBuffer: function() {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {Object} Only used by a subclass of this layer. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.UTFGrid>} An exact clone of this OpenLayers.Layer.UTFGrid │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.UTFGrid(this.getOptions()); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // get all additions from superclasses │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + │ │ │ │ + return obj; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: getFeatureInfo │ │ │ │ + * Get details about a feature associated with a map location. The object │ │ │ │ + * returned will have id and data properties. If the given location │ │ │ │ + * doesn't correspond to a feature, null will be returned. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * location - {<OpenLayers.LonLat>} map location │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} Object representing the feature id and UTFGrid data │ │ │ │ + * corresponding to the given map location. Returns null if the given │ │ │ │ + * location doesn't hit a feature. │ │ │ │ + */ │ │ │ │ + getFeatureInfo: function(location) { │ │ │ │ + var info = null; │ │ │ │ + var tileInfo = this.getTileData(location); │ │ │ │ + if (tileInfo && tileInfo.tile) { │ │ │ │ + info = tileInfo.tile.getFeatureInfo(tileInfo.i, tileInfo.j); │ │ │ │ + } │ │ │ │ + return info; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getFeatureId │ │ │ │ + * Get the identifier for the feature associated with a map location. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * location - {<OpenLayers.LonLat>} map location │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} The feature identifier corresponding to the given map location. │ │ │ │ + * Returns null if the location doesn't hit a feature. │ │ │ │ + */ │ │ │ │ + getFeatureId: function(location) { │ │ │ │ + var id = null; │ │ │ │ + var info = this.getTileData(location); │ │ │ │ + if (info.tile) { │ │ │ │ + id = info.tile.getFeatureId(info.i, info.j); │ │ │ │ + } │ │ │ │ + return id; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.UTFGrid" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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/Layer/FixedZoomLevels.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.FixedZoomLevels │ │ │ │ + * Some Layers will already have established zoom levels (like google │ │ │ │ + * or ve). Instead of trying to determine them and populate a resolutions[] │ │ │ │ + * Array with those values, we will hijack the resolution functionality │ │ │ │ + * here. │ │ │ │ + * │ │ │ │ + * When you subclass FixedZoomLevels: │ │ │ │ + * │ │ │ │ + * The initResolutions() call gets nullified, meaning no resolutions[] array │ │ │ │ + * is set up. Which would be a big problem getResolution() in Layer, since │ │ │ │ + * it merely takes map.zoom and indexes into resolutions[]... but.... │ │ │ │ + * │ │ │ │ + * The getResolution() call is also overridden. Instead of using the │ │ │ │ + * resolutions[] array, we simply calculate the current resolution based │ │ │ │ + * on the current extent and the current map size. But how will we be able │ │ │ │ + * to calculate the current extent without knowing the resolution...? │ │ │ │ + * │ │ │ │ + * The getExtent() function is also overridden. Instead of calculating extent │ │ │ │ + * based on the center point and the current resolution, we instead │ │ │ │ + * calculate the extent by getting the lonlats at the top-left and │ │ │ │ + * bottom-right by using the getLonLatFromViewPortPx() translation function, │ │ │ │ + * taken from the pixel locations (0,0) and the size of the map. But how │ │ │ │ + * will we be able to do lonlat-px translation without resolution....? │ │ │ │ + * │ │ │ │ + * The getZoomForResolution() method is overridden. Instead of indexing into │ │ │ │ + * the resolutions[] array, we call OpenLayers.Layer.getExent(), passing in │ │ │ │ + * the desired resolution. With this extent, we then call getZoomForExtent() │ │ │ │ + * │ │ │ │ + * │ │ │ │ + * Whenever you implement a layer using OpenLayers.Layer.FixedZoomLevels, │ │ │ │ + * it is your responsibility to provide the following three functions: │ │ │ │ + * │ │ │ │ + * - getLonLatFromViewPortPx │ │ │ │ + * - getViewPortPxFromLonLat │ │ │ │ + * - getZoomForExtent │ │ │ │ + * │ │ │ │ + * ...those three functions should generally be provided by any reasonable │ │ │ │ + * API that you might be working from. │ │ │ │ + * │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.FixedZoomLevels = OpenLayers.Class({ │ │ │ │ + │ │ │ │ + /********************************************************/ │ │ │ │ + /* */ │ │ │ │ + /* Baselayer Functions */ │ │ │ │ + /* */ │ │ │ │ + /* The following functions must all be implemented */ │ │ │ │ + /* by all base layers */ │ │ │ │ + /* */ │ │ │ │ + /********************************************************/ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.FixedZoomLevels │ │ │ │ + * Create a new fixed zoom levels layer. │ │ │ │ + */ │ │ │ │ + initialize: function() { │ │ │ │ + //this class is only just to add the following functions... │ │ │ │ + // nothing to actually do here... but it is probably a good │ │ │ │ + // idea to have layers that use these functions call this │ │ │ │ + // inititalize() anyways, in case at some point we decide we │ │ │ │ + // do want to put some functionality or state in here. │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: initResolutions │ │ │ │ + * Populate the resolutions array │ │ │ │ + */ │ │ │ │ + initResolutions: function() { │ │ │ │ + │ │ │ │ + var props = ['minZoomLevel', 'maxZoomLevel', 'numZoomLevels']; │ │ │ │ + │ │ │ │ + for (var i = 0, len = props.length; i < len; i++) { │ │ │ │ + var property = props[i]; │ │ │ │ + this[property] = (this.options[property] != null) ? │ │ │ │ + this.options[property] : │ │ │ │ + this.map[property]; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if ((this.minZoomLevel == null) || │ │ │ │ + (this.minZoomLevel < this.MIN_ZOOM_LEVEL)) { │ │ │ │ + this.minZoomLevel = this.MIN_ZOOM_LEVEL; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // │ │ │ │ + // At this point, we know what the minimum desired zoom level is, and │ │ │ │ + // we must calculate the total number of zoom levels. │ │ │ │ + // │ │ │ │ + // Because we allow for the setting of either the 'numZoomLevels' │ │ │ │ + // or the 'maxZoomLevel' properties... on either the layer or the │ │ │ │ + // map, we have to define some rules to see which we take into │ │ │ │ + // account first in this calculation. │ │ │ │ + // │ │ │ │ + // The following is the precedence list for these properties: │ │ │ │ + // │ │ │ │ + // (1) numZoomLevels set on layer │ │ │ │ + // (2) maxZoomLevel set on layer │ │ │ │ + // (3) numZoomLevels set on map │ │ │ │ + // (4) maxZoomLevel set on map* │ │ │ │ + // (5) none of the above* │ │ │ │ + // │ │ │ │ + // *Note that options (4) and (5) are only possible if the user │ │ │ │ + // _explicitly_ sets the 'numZoomLevels' property on the map to │ │ │ │ + // null, since it is set by default to 16. │ │ │ │ + // │ │ │ │ + │ │ │ │ + // │ │ │ │ + // Note to future: In 3.0, I think we should remove the default │ │ │ │ + // value of 16 for map.numZoomLevels. Rather, I think that value │ │ │ │ + // should be set as a default on the Layer.WMS class. If someone │ │ │ │ + // creates a 3rd party layer and does not specify any 'minZoomLevel', │ │ │ │ + // 'maxZoomLevel', or 'numZoomLevels', and has not explicitly │ │ │ │ + // specified any of those on the map object either.. then I think │ │ │ │ + // it is fair to say that s/he wants all the zoom levels available. │ │ │ │ + // │ │ │ │ + // By making map.numZoomLevels *null* by default, that will be the │ │ │ │ + // case. As it is, I don't feel comfortable changing that right now │ │ │ │ + // as it would be a glaring API change and actually would probably │ │ │ │ + // break many peoples' codes. │ │ │ │ + // │ │ │ │ + │ │ │ │ + //the number of zoom levels we'd like to have. │ │ │ │ + var desiredZoomLevels; │ │ │ │ + │ │ │ │ + //this is the maximum number of zoom levels the layer will allow, │ │ │ │ + // given the specified starting minimum zoom level. │ │ │ │ + var limitZoomLevels = this.MAX_ZOOM_LEVEL - this.minZoomLevel + 1; │ │ │ │ + │ │ │ │ + if (((this.options.numZoomLevels == null) && │ │ │ │ + (this.options.maxZoomLevel != null)) // (2) │ │ │ │ + || │ │ │ │ + ((this.numZoomLevels == null) && │ │ │ │ + (this.maxZoomLevel != null)) // (4) │ │ │ │ + ) { │ │ │ │ + //calculate based on specified maxZoomLevel (on layer or map) │ │ │ │ + desiredZoomLevels = this.maxZoomLevel - this.minZoomLevel + 1; │ │ │ │ + } else { │ │ │ │ + //calculate based on specified numZoomLevels (on layer or map) │ │ │ │ + // this covers cases (1) and (3) │ │ │ │ + desiredZoomLevels = this.numZoomLevels; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (desiredZoomLevels != null) { │ │ │ │ + //Now that we know what we would *like* the number of zoom levels │ │ │ │ + // to be, based on layer or map options, we have to make sure that │ │ │ │ + // it does not conflict with the actual limit, as specified by │ │ │ │ + // the constants on the layer itself (and calculated into the │ │ │ │ + // 'limitZoomLevels' variable). │ │ │ │ + this.numZoomLevels = Math.min(desiredZoomLevels, limitZoomLevels); │ │ │ │ + } else { │ │ │ │ + // case (5) -- neither 'numZoomLevels' not 'maxZoomLevel' was │ │ │ │ + // set on either the layer or the map. So we just use the │ │ │ │ + // maximum limit as calculated by the layer's constants. │ │ │ │ + this.numZoomLevels = limitZoomLevels; │ │ │ │ + } │ │ │ │ + │ │ │ │ + //now that the 'numZoomLevels' is appropriately, safely set, │ │ │ │ + // we go back and re-calculate the 'maxZoomLevel'. │ │ │ │ + this.maxZoomLevel = this.minZoomLevel + this.numZoomLevels - 1; │ │ │ │ + │ │ │ │ + if (this.RESOLUTIONS != null) { │ │ │ │ + var resolutionsIndex = 0; │ │ │ │ + this.resolutions = []; │ │ │ │ + for (var i = this.minZoomLevel; i <= this.maxZoomLevel; i++) { │ │ │ │ + this.resolutions[resolutionsIndex++] = this.RESOLUTIONS[i]; │ │ │ │ + } │ │ │ │ + this.maxResolution = this.resolutions[0]; │ │ │ │ + this.minResolution = this.resolutions[this.resolutions.length - 1]; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getResolution │ │ │ │ + * Get the current map resolution │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Float} Map units per Pixel │ │ │ │ + */ │ │ │ │ + getResolution: function() { │ │ │ │ + │ │ │ │ + if (this.resolutions != null) { │ │ │ │ + return OpenLayers.Layer.prototype.getResolution.apply(this, arguments); │ │ │ │ + } else { │ │ │ │ + var resolution = null; │ │ │ │ + │ │ │ │ + var viewSize = this.map.getSize(); │ │ │ │ + var extent = this.getExtent(); │ │ │ │ + │ │ │ │ + if ((viewSize != null) && (extent != null)) { │ │ │ │ + resolution = Math.max(extent.getWidth() / viewSize.w, │ │ │ │ + extent.getHeight() / viewSize.h); │ │ │ │ + } │ │ │ │ + return resolution; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getExtent │ │ │ │ + * Calculates using px-> lonlat translation functions on tl and br │ │ │ │ + * corners of viewport │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat │ │ │ │ + * bounds of the current viewPort. │ │ │ │ + */ │ │ │ │ + getExtent: function() { │ │ │ │ + var size = this.map.getSize(); │ │ │ │ + var tl = this.getLonLatFromViewPortPx({ │ │ │ │ + x: 0, │ │ │ │ + y: 0 │ │ │ │ + }); │ │ │ │ + var br = this.getLonLatFromViewPortPx({ │ │ │ │ + x: size.w, │ │ │ │ + y: size.h │ │ │ │ + }); │ │ │ │ + │ │ │ │ + if ((tl != null) && (br != null)) { │ │ │ │ + return new OpenLayers.Bounds(tl.lon, br.lat, br.lon, tl.lat); │ │ │ │ + } else { │ │ │ │ + return null; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getZoomForResolution │ │ │ │ + * Get the zoom level for a given resolution │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * resolution - {Float} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} A suitable zoom level for the specified resolution. │ │ │ │ + * If no baselayer is set, returns null. │ │ │ │ + */ │ │ │ │ + getZoomForResolution: function(resolution) { │ │ │ │ + │ │ │ │ + if (this.resolutions != null) { │ │ │ │ + return OpenLayers.Layer.prototype.getZoomForResolution.apply(this, arguments); │ │ │ │ + } else { │ │ │ │ + var extent = OpenLayers.Layer.prototype.getExtent.apply(this, []); │ │ │ │ + return this.getZoomForExtent(extent); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + /********************************************************/ │ │ │ │ + /* */ │ │ │ │ + /* Translation Functions */ │ │ │ │ + /* */ │ │ │ │ + /* The following functions translate GMaps and OL */ │ │ │ │ + /* formats for Pixel, LonLat, Bounds, and Zoom */ │ │ │ │ + /* */ │ │ │ │ + /********************************************************/ │ │ │ │ + │ │ │ │ + │ │ │ │ + // │ │ │ │ + // TRANSLATION: MapObject Zoom <-> OpenLayers Zoom │ │ │ │ + // │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getOLZoomFromMapObjectZoom │ │ │ │ + * Get the OL zoom index from the map object zoom level │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moZoom - {Integer} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} An OpenLayers Zoom level, translated from the passed in zoom │ │ │ │ + * Returns null if null value is passed in │ │ │ │ + */ │ │ │ │ + getOLZoomFromMapObjectZoom: function(moZoom) { │ │ │ │ + var zoom = null; │ │ │ │ + if (moZoom != null) { │ │ │ │ + zoom = moZoom - this.minZoomLevel; │ │ │ │ + if (this.map.baseLayer !== this) { │ │ │ │ + zoom = this.map.baseLayer.getZoomForResolution( │ │ │ │ + this.getResolutionForZoom(zoom) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return zoom; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getMapObjectZoomFromOLZoom │ │ │ │ + * Get the map object zoom level from the OL zoom level │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * olZoom - {Integer} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} A MapObject level, translated from the passed in olZoom │ │ │ │ + * Returns null if null value is passed in │ │ │ │ + */ │ │ │ │ + getMapObjectZoomFromOLZoom: function(olZoom) { │ │ │ │ + var zoom = null; │ │ │ │ + if (olZoom != null) { │ │ │ │ + zoom = olZoom + this.minZoomLevel; │ │ │ │ + if (this.map.baseLayer !== this) { │ │ │ │ + zoom = this.getZoomForResolution( │ │ │ │ + this.map.baseLayer.getResolutionForZoom(zoom) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return zoom; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.FixedZoomLevels" │ │ │ │ +}); │ │ │ │ + │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/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/Layer.js │ │ │ │ + * @requires OpenLayers/Tile/Image.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.Image │ │ │ │ + * Instances of OpenLayers.Layer.Image are used to display data from a web │ │ │ │ + * accessible image as a map layer. Create a new image layer with the │ │ │ │ + * <OpenLayers.Layer.Image> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Image = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: isBaseLayer │ │ │ │ + * {Boolean} The layer is a base layer. Default is true. Set this property │ │ │ │ + * in the layer options │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: url │ │ │ │ + * {String} URL of the image to use │ │ │ │ + */ │ │ │ │ + url: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: extent │ │ │ │ + * {<OpenLayers.Bounds>} The image bounds in map units. This extent will │ │ │ │ + * also be used as the default maxExtent for the layer. If you wish │ │ │ │ + * to have a maxExtent that is different than the image extent, set the │ │ │ │ + * maxExtent property of the options argument (as with any other layer). │ │ │ │ + */ │ │ │ │ + extent: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: size │ │ │ │ + * {<OpenLayers.Size>} The image size in pixels │ │ │ │ + */ │ │ │ │ + size: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: tile │ │ │ │ + * {<OpenLayers.Tile.Image>} │ │ │ │ + */ │ │ │ │ + tile: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: aspectRatio │ │ │ │ + * {Float} The ratio of height/width represented by a single pixel in the │ │ │ │ + * graphic │ │ │ │ + */ │ │ │ │ + aspectRatio: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.Image │ │ │ │ + * Create a new image layer │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} A name for the layer. │ │ │ │ + * url - {String} Relative or absolute path to the image │ │ │ │ + * extent - {<OpenLayers.Bounds>} The extent represented by the image │ │ │ │ + * size - {<OpenLayers.Size>} The size (in pixels) of the image │ │ │ │ + * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, extent, size, options) { │ │ │ │ + this.url = url; │ │ │ │ + this.extent = extent; │ │ │ │ + this.maxExtent = extent; │ │ │ │ + this.size = size; │ │ │ │ + OpenLayers.Layer.prototype.initialize.apply(this, [name, options]); │ │ │ │ + │ │ │ │ + this.aspectRatio = (this.extent.getHeight() / this.size.h) / │ │ │ │ + (this.extent.getWidth() / this.size.w); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + * Destroy this layer │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + if (this.tile) { │ │ │ │ + this.removeTileMonitoringHooks(this.tile); │ │ │ │ + this.tile.destroy(); │ │ │ │ + this.tile = null; │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ + * Paramters: │ │ │ │ + * obj - {Object} An optional layer (is this ever used?) │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.Image>} An exact copy of this layer │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.Image(this.name, │ │ │ │ + this.url, │ │ │ │ + this.extent, │ │ │ │ + this.size, │ │ │ │ + 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: setMap │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + setMap: function(map) { │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * If nothing to do with resolutions has been set, assume a single │ │ │ │ + * resolution determined by ratio*extent/size - if an image has a │ │ │ │ + * pixel aspect ratio different than one (as calculated above), the │ │ │ │ + * image will be stretched in one dimension only. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + if (this.options.maxResolution == null) { │ │ │ │ + this.options.maxResolution = this.aspectRatio * │ │ │ │ + this.extent.getWidth() / │ │ │ │ + this.size.w; │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.prototype.setMap.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveTo │ │ │ │ + * Create the tile for the image or resize it for the new resolution │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * zoomChanged - {Boolean} │ │ │ │ + * dragging - {Boolean} │ │ │ │ + */ │ │ │ │ + moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ + OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ + │ │ │ │ + var firstRendering = (this.tile == null); │ │ │ │ + │ │ │ │ + if (zoomChanged || firstRendering) { │ │ │ │ + │ │ │ │ + //determine new tile size │ │ │ │ + this.setTileSize(); │ │ │ │ + │ │ │ │ + //determine new position (upper left corner of new bounds) │ │ │ │ + var ulPx = this.map.getLayerPxFromLonLat({ │ │ │ │ + lon: this.extent.left, │ │ │ │ + lat: this.extent.top │ │ │ │ + }); │ │ │ │ + │ │ │ │ + if (firstRendering) { │ │ │ │ + //create the new tile │ │ │ │ + this.tile = new OpenLayers.Tile.Image(this, ulPx, this.extent, │ │ │ │ + null, this.tileSize); │ │ │ │ + this.addTileMonitoringHooks(this.tile); │ │ │ │ } else { │ │ │ │ - var child; │ │ │ │ - if (filter.value instanceof OpenLayers.Geometry) { │ │ │ │ - child = this.writeNode("feature:_geometry", filter.value).firstChild; │ │ │ │ + //just resize the tile and set it's new position │ │ │ │ + this.tile.size = this.tileSize.clone(); │ │ │ │ + this.tile.position = ulPx.clone(); │ │ │ │ + } │ │ │ │ + this.tile.draw(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Set the tile size based on the map size. │ │ │ │ + */ │ │ │ │ + setTileSize: function() { │ │ │ │ + var tileWidth = this.extent.getWidth() / this.map.getResolution(); │ │ │ │ + var tileHeight = this.extent.getHeight() / this.map.getResolution(); │ │ │ │ + this.tileSize = new OpenLayers.Size(tileWidth, tileHeight); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ + tile.onLoadStart = function() { │ │ │ │ + this.events.triggerEvent("loadstart"); │ │ │ │ + }; │ │ │ │ + tile.events.register("loadstart", this, tile.onLoadStart); │ │ │ │ + │ │ │ │ + tile.onLoadEnd = function() { │ │ │ │ + this.events.triggerEvent("loadend"); │ │ │ │ + }; │ │ │ │ + tile.events.register("loadend", this, tile.onLoadEnd); │ │ │ │ + tile.events.register("unload", this, tile.onLoadEnd); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setUrl │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * newUrl - {String} │ │ │ │ + */ │ │ │ │ + setUrl: function(newUrl) { │ │ │ │ + this.url = newUrl; │ │ │ │ + this.tile.draw(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getURL │ │ │ │ + * The url we return is always the same (the image itself never changes) │ │ │ │ + * so we can ignore the bounds parameter (it will always be the same, │ │ │ │ + * anyways) │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + */ │ │ │ │ + getURL: function(bounds) { │ │ │ │ + return this.url; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Image" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/KaMap.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.KaMap │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.KaMap = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} KaMap Layer is always a base layer │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: DEFAULT_PARAMS │ │ │ │ + * {Object} parameters set by default. The default parameters set │ │ │ │ + * the format via the 'i' parameter to 'jpeg'. │ │ │ │ + */ │ │ │ │ + DEFAULT_PARAMS: { │ │ │ │ + i: 'jpeg', │ │ │ │ + map: '' │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.KaMap │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} │ │ │ │ + * url - {String} │ │ │ │ + * params - {Object} Parameters to be sent to the HTTP server in the │ │ │ │ + * query string for the tile. The format can be set via the 'i' │ │ │ │ + * parameter (defaults to jpg) , and the map should be set via │ │ │ │ + * the 'map' parameter. It has been reported that ka-Map may behave │ │ │ │ + * inconsistently if your format parameter does not match the format │ │ │ │ + * parameter configured in your config.php. (See ticket #327 for more │ │ │ │ + * information.) │ │ │ │ + * options - {Object} Additional options for the layer. Any of the │ │ │ │ + * APIProperties listed on this layer, and any layer types it │ │ │ │ + * extends, can be overridden through the options parameter. │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ + this.params = OpenLayers.Util.applyDefaults( │ │ │ │ + this.params, this.DEFAULT_PARAMS │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ + var scale = Math.round((this.map.getScale() * 10000)) / 10000; │ │ │ │ + var pX = Math.round(bounds.left / mapRes); │ │ │ │ + var pY = -Math.round(bounds.top / mapRes); │ │ │ │ + return this.getFullRequestString({ │ │ │ │ + t: pY, │ │ │ │ + l: pX, │ │ │ │ + s: scale │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: calculateGridLayout │ │ │ │ + * ka-Map uses the center point of the map as an origin for │ │ │ │ + * its tiles. Override calculateGridLayout to center tiles │ │ │ │ + * correctly for this case. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bound>} │ │ │ │ + * origin - {<OpenLayers.LonLat>} │ │ │ │ + * 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; │ │ │ │ + var tilecol = Math.floor(offsetlon / tilelon) - this.buffer; │ │ │ │ + │ │ │ │ + var offsetlat = bounds.top; │ │ │ │ + var tilerow = Math.floor(offsetlat / tilelat) + this.buffer; │ │ │ │ + │ │ │ │ + return { │ │ │ │ + tilelon: tilelon, │ │ │ │ + tilelat: tilelat, │ │ │ │ + startcol: tilecol, │ │ │ │ + startrow: tilerow │ │ │ │ + }; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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 minX = (tileLayout.startcol + col) * tilelon; │ │ │ │ + var minY = (tileLayout.startrow - row) * tilelat; │ │ │ │ + return new OpenLayers.Bounds( │ │ │ │ + minX, minY, │ │ │ │ + minX + tilelon, minY + tilelat │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.Kamap>} An exact clone of this OpenLayers.Layer.KaMap │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.KaMap(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 │ │ │ │ + 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 = []; │ │ │ │ + │ │ │ │ + return obj; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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 resolution = this.getResolution(); │ │ │ │ + var tileMapWidth = resolution * this.tileSize.w; │ │ │ │ + var tileMapHeight = resolution * this.tileSize.h; │ │ │ │ + var mapPoint = this.getLonLatFromViewPortPx(viewPortPx); │ │ │ │ + var tileLeft = tileMapWidth * Math.floor(mapPoint.lon / tileMapWidth); │ │ │ │ + var tileBottom = tileMapHeight * Math.floor(mapPoint.lat / tileMapHeight); │ │ │ │ + return new OpenLayers.Bounds(tileLeft, tileBottom, │ │ │ │ + tileLeft + tileMapWidth, │ │ │ │ + tileBottom + tileMapHeight); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.KaMap" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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/PointGrid.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 │ │ │ │ + * @requires OpenLayers/Geometry/Polygon.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.PointGrid │ │ │ │ + * A point grid layer dynamically generates a regularly spaced grid of point │ │ │ │ + * features. This is a specialty layer for cases where an application needs │ │ │ │ + * a regular grid of points. It can be used, for example, in an editing │ │ │ │ + * environment to snap to a grid. │ │ │ │ + * │ │ │ │ + * Create a new vector layer with the <OpenLayers.Layer.PointGrid> constructor. │ │ │ │ + * (code) │ │ │ │ + * // create a grid with points spaced at 10 map units │ │ │ │ + * var points = new OpenLayers.Layer.PointGrid({dx: 10, dy: 10}); │ │ │ │ + * │ │ │ │ + * // create a grid with different x/y spacing rotated 15 degrees clockwise. │ │ │ │ + * var points = new OpenLayers.Layer.PointGrid({dx: 5, dy: 10, rotation: 15}); │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Vector> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.PointGrid = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: dx │ │ │ │ + * {Number} Point grid spacing in the x-axis direction (map units). │ │ │ │ + * Read-only. Use the <setSpacing> method to modify this value. │ │ │ │ + */ │ │ │ │ + dx: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: dy │ │ │ │ + * {Number} Point grid spacing in the y-axis direction (map units). │ │ │ │ + * Read-only. Use the <setSpacing> method to modify this value. │ │ │ │ + */ │ │ │ │ + dy: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: ratio │ │ │ │ + * {Number} Ratio of the desired grid size to the map viewport size. │ │ │ │ + * Default is 1.5. Larger ratios mean the grid is recalculated less often │ │ │ │ + * while panning. The <maxFeatures> setting has precedence when determining │ │ │ │ + * grid size. Read-only. Use the <setRatio> method to modify this value. │ │ │ │ + */ │ │ │ │ + ratio: 1.5, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: maxFeatures │ │ │ │ + * {Number} The maximum number of points to generate in the grid. Default │ │ │ │ + * is 250. Read-only. Use the <setMaxFeatures> method to modify this value. │ │ │ │ + */ │ │ │ │ + maxFeatures: 250, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: rotation │ │ │ │ + * {Number} Grid rotation (in degrees clockwise from the positive x-axis). │ │ │ │ + * Default is 0. Read-only. Use the <setRotation> method to modify this │ │ │ │ + * value. │ │ │ │ + */ │ │ │ │ + rotation: 0, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: origin │ │ │ │ + * {<OpenLayers.LonLat>} Grid origin. The grid lattice will be aligned with │ │ │ │ + * the origin. If not set at construction, the center of the map's maximum │ │ │ │ + * extent is used. Read-only. Use the <setOrigin> method to modify this │ │ │ │ + * value. │ │ │ │ + */ │ │ │ │ + origin: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: gridBounds │ │ │ │ + * {<OpenLayers.Bounds>} Internally cached grid bounds (with optional │ │ │ │ + * rotation applied). │ │ │ │ + */ │ │ │ │ + gridBounds: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.PointGrid │ │ │ │ + * Creates a new point grid layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * config - {Object} An object containing all configuration properties for │ │ │ │ + * the layer. The <dx> and <dy> properties are required to be set at │ │ │ │ + * construction. Any other layer properties may be set in this object. │ │ │ │ + */ │ │ │ │ + initialize: function(config) { │ │ │ │ + config = config || {}; │ │ │ │ + OpenLayers.Layer.Vector.prototype.initialize.apply(this, [config.name, config]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ + * The layer has been added to the map. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ + map.events.register("moveend", this, this.onMoveEnd); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: removeMap │ │ │ │ + * The layer has been removed from the map. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + removeMap: function(map) { │ │ │ │ + map.events.unregister("moveend", this, this.onMoveEnd); │ │ │ │ + OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setRatio │ │ │ │ + * Set the grid <ratio> property and update the grid. Can only be called │ │ │ │ + * after the layer has been added to a map with a center/extent. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * ratio - {Number} │ │ │ │ + */ │ │ │ │ + setRatio: function(ratio) { │ │ │ │ + this.ratio = ratio; │ │ │ │ + this.updateGrid(true); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setMaxFeatures │ │ │ │ + * Set the grid <maxFeatures> property and update the grid. Can only be │ │ │ │ + * called after the layer has been added to a map with a center/extent. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * maxFeatures - {Number} │ │ │ │ + */ │ │ │ │ + setMaxFeatures: function(maxFeatures) { │ │ │ │ + this.maxFeatures = maxFeatures; │ │ │ │ + this.updateGrid(true); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setSpacing │ │ │ │ + * Set the grid <dx> and <dy> properties and update the grid. If only one │ │ │ │ + * argument is provided, it will be set as <dx> and <dy>. Can only be │ │ │ │ + * called after the layer has been added to a map with a center/extent. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * dx - {Number} │ │ │ │ + * dy - {Number} │ │ │ │ + */ │ │ │ │ + setSpacing: function(dx, dy) { │ │ │ │ + this.dx = dx; │ │ │ │ + this.dy = dy || dx; │ │ │ │ + this.updateGrid(true); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setOrigin │ │ │ │ + * Set the grid <origin> property and update the grid. Can only be called │ │ │ │ + * after the layer has been added to a map with a center/extent. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * origin - {<OpenLayers.LonLat>} │ │ │ │ + */ │ │ │ │ + setOrigin: function(origin) { │ │ │ │ + this.origin = origin; │ │ │ │ + this.updateGrid(true); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getOrigin │ │ │ │ + * Get the grid <origin> property. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.LonLat>} The grid origin. │ │ │ │ + */ │ │ │ │ + getOrigin: function() { │ │ │ │ + if (!this.origin) { │ │ │ │ + this.origin = this.map.getExtent().getCenterLonLat(); │ │ │ │ + } │ │ │ │ + return this.origin; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setRotation │ │ │ │ + * Set the grid <rotation> property and update the grid. Rotation values │ │ │ │ + * are in degrees clockwise from the positive x-axis (negative values │ │ │ │ + * for counter-clockwise rotation). Can only be called after the layer │ │ │ │ + * has been added to a map with a center/extent. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * rotation - {Number} Degrees clockwise from the positive x-axis. │ │ │ │ + */ │ │ │ │ + setRotation: function(rotation) { │ │ │ │ + this.rotation = rotation; │ │ │ │ + this.updateGrid(true); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: onMoveEnd │ │ │ │ + * Listener for map "moveend" events. │ │ │ │ + */ │ │ │ │ + onMoveEnd: function() { │ │ │ │ + this.updateGrid(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getViewBounds │ │ │ │ + * Gets the (potentially rotated) view bounds for grid calculations. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} │ │ │ │ + */ │ │ │ │ + getViewBounds: function() { │ │ │ │ + var bounds = this.map.getExtent(); │ │ │ │ + if (this.rotation) { │ │ │ │ + var origin = this.getOrigin(); │ │ │ │ + var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); │ │ │ │ + var rect = bounds.toGeometry(); │ │ │ │ + rect.rotate(-this.rotation, rotationOrigin); │ │ │ │ + bounds = rect.getBounds(); │ │ │ │ + } │ │ │ │ + return bounds; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: updateGrid │ │ │ │ + * Update the grid. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * force - {Boolean} Update the grid even if the previous bounds are still │ │ │ │ + * valid. │ │ │ │ + */ │ │ │ │ + updateGrid: function(force) { │ │ │ │ + if (force || this.invalidBounds()) { │ │ │ │ + var viewBounds = this.getViewBounds(); │ │ │ │ + var origin = this.getOrigin(); │ │ │ │ + var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); │ │ │ │ + var viewBoundsWidth = viewBounds.getWidth(); │ │ │ │ + var viewBoundsHeight = viewBounds.getHeight(); │ │ │ │ + var aspectRatio = viewBoundsWidth / viewBoundsHeight; │ │ │ │ + var maxHeight = Math.sqrt(this.dx * this.dy * this.maxFeatures / aspectRatio); │ │ │ │ + var maxWidth = maxHeight * aspectRatio; │ │ │ │ + var gridWidth = Math.min(viewBoundsWidth * this.ratio, maxWidth); │ │ │ │ + var gridHeight = Math.min(viewBoundsHeight * this.ratio, maxHeight); │ │ │ │ + var center = viewBounds.getCenterLonLat(); │ │ │ │ + this.gridBounds = new OpenLayers.Bounds( │ │ │ │ + center.lon - (gridWidth / 2), │ │ │ │ + center.lat - (gridHeight / 2), │ │ │ │ + center.lon + (gridWidth / 2), │ │ │ │ + center.lat + (gridHeight / 2) │ │ │ │ + ); │ │ │ │ + var rows = Math.floor(gridHeight / this.dy); │ │ │ │ + var cols = Math.floor(gridWidth / this.dx); │ │ │ │ + var gridLeft = origin.lon + (this.dx * Math.ceil((this.gridBounds.left - origin.lon) / this.dx)); │ │ │ │ + var gridBottom = origin.lat + (this.dy * Math.ceil((this.gridBounds.bottom - origin.lat) / this.dy)); │ │ │ │ + var features = new Array(rows * cols); │ │ │ │ + var x, y, point; │ │ │ │ + for (var i = 0; i < cols; ++i) { │ │ │ │ + x = gridLeft + (i * this.dx); │ │ │ │ + for (var j = 0; j < rows; ++j) { │ │ │ │ + y = gridBottom + (j * this.dy); │ │ │ │ + point = new OpenLayers.Geometry.Point(x, y); │ │ │ │ + if (this.rotation) { │ │ │ │ + point.rotate(this.rotation, rotationOrigin); │ │ │ │ + } │ │ │ │ + features[(i * rows) + j] = new OpenLayers.Feature.Vector(point); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.destroyFeatures(this.features, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + this.addFeatures(features, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: invalidBounds │ │ │ │ + * Determine whether the previously generated point grid is invalid. │ │ │ │ + * This occurs when the map bounds extends beyond the previously │ │ │ │ + * generated grid bounds. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} │ │ │ │ + */ │ │ │ │ + invalidBounds: function() { │ │ │ │ + return !this.gridBounds || !this.gridBounds.containsBounds(this.getViewBounds()); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.PointGrid" │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/ArcGISCache.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.ArcGISCache │ │ │ │ + * Layer for accessing cached map tiles from an ArcGIS Server style mapcache. │ │ │ │ + * Tile must already be cached for this layer to access it. This does not require │ │ │ │ + * ArcGIS Server itself. │ │ │ │ + * │ │ │ │ + * A few attempts have been made at this kind of layer before. See │ │ │ │ + * http://trac.osgeo.org/openlayers/ticket/1967 │ │ │ │ + * and │ │ │ │ + * http://trac.osgeo.org/openlayers/browser/sandbox/tschaub/arcgiscache/lib/OpenLayers/Layer/ArcGISCache.js │ │ │ │ + * │ │ │ │ + * Typically the problem encountered is that the tiles seem to "jump around". │ │ │ │ + * This is due to the fact that the actual max extent for the tiles on AGS layers │ │ │ │ + * changes at each zoom level due to the way these caches are constructed. │ │ │ │ + * We have attempted to use the resolutions, tile size, and tile origin │ │ │ │ + * from the cache meta data to make the appropriate changes to the max extent │ │ │ │ + * of the tile to compensate for this behavior. This must be done as zoom levels change │ │ │ │ + * and before tiles are requested, which is why methods from base classes are overridden. │ │ │ │ + * │ │ │ │ + * For reference, you can access mapcache meta data in two ways. For accessing a │ │ │ │ + * mapcache through ArcGIS Server, you can simply go to the landing page for the │ │ │ │ + * layer. (ie. http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer) │ │ │ │ + * For accessing it directly through HTTP, there should always be a conf.xml file │ │ │ │ + * in the root directory. │ │ │ │ + * (ie. http://serverx.esri.com/arcgiscache/DG_County_roads_yesA_backgroundDark/Layers/conf.xml) │ │ │ │ + * │ │ │ │ + *Inherits from: │ │ │ │ + * - <OpenLayers.Layer.XYZ> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.ArcGISCache = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: url │ │ │ │ + * {String | Array} The base URL for the layer cache. You can also │ │ │ │ + * provide a list of URL strings for the layer if your cache is │ │ │ │ + * available from multiple origins. This must be set before the layer │ │ │ │ + * is drawn. │ │ │ │ + */ │ │ │ │ + url: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: tileOrigin │ │ │ │ + * {<OpenLayers.LonLat>} The location of the tile origin for the cache. │ │ │ │ + * An ArcGIS cache has it's origin at the upper-left (lowest x value │ │ │ │ + * and highest y value of the coordinate system). The units for the │ │ │ │ + * tile origin should be the same as the units for the cached data. │ │ │ │ + */ │ │ │ │ + tileOrigin: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: tileSize │ │ │ │ + * {<OpenLayers.Size>} This size of each tile. Defaults to 256 by 256 pixels. │ │ │ │ + */ │ │ │ │ + tileSize: new OpenLayers.Size(256, 256), │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: useAGS │ │ │ │ + * {Boolean} Indicates if we are going to be accessing the ArcGIS Server (AGS) │ │ │ │ + * cache via an AGS MapServer or directly through HTTP. When accessing via │ │ │ │ + * AGS the path structure uses a standard z/y/x structure. But AGS actually │ │ │ │ + * stores the tile images on disk using a hex based folder structure that looks │ │ │ │ + * like "http://example.com/mylayer/L00/R00000000/C00000000.png". Learn more │ │ │ │ + * about this here: │ │ │ │ + * http://blogs.esri.com/Support/blogs/mappingcenter/archive/2010/08/20/Checking-Your-Local-Cache-Folders.aspx │ │ │ │ + * Defaults to true; │ │ │ │ + */ │ │ │ │ + useArcGISServer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: type │ │ │ │ + * {String} Image type for the layer. This becomes the filename extension │ │ │ │ + * in tile requests. Default is "png" (generating a url like │ │ │ │ + * "http://example.com/mylayer/L00/R00000000/C00000000.png"). │ │ │ │ + */ │ │ │ │ + type: 'png', │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: useScales │ │ │ │ + * {Boolean} Optional override to indicate that the layer should use 'scale' information │ │ │ │ + * returned from the server capabilities object instead of 'resolution' information. │ │ │ │ + * This can be important if your tile server uses an unusual DPI for the tiles. │ │ │ │ + */ │ │ │ │ + useScales: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: overrideDPI │ │ │ │ + * {Boolean} Optional override to change the OpenLayers.DOTS_PER_INCH setting based │ │ │ │ + * on the tile information in the server capabilities object. This can be useful │ │ │ │ + * if your server has a non-standard DPI setting on its tiles, and you're only using │ │ │ │ + * tiles with that DPI. This value is used while OpenLayers is calculating resolution │ │ │ │ + * using scales, and is not necessary if you have resolution information. (This is │ │ │ │ + * typically the case) Regardless, this setting can be useful, but is dangerous │ │ │ │ + * because it will impact other layers while calculating resolution. Only use this │ │ │ │ + * if you know what you are doing. (See OpenLayers.Util.getResolutionFromScale) │ │ │ │ + */ │ │ │ │ + overrideDPI: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.ArcGISCache │ │ │ │ + * Creates a new instance of this class │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} │ │ │ │ + * url - {String} │ │ │ │ + * options - {Object} extra layer options │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, options) { │ │ │ │ + OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments); │ │ │ │ + │ │ │ │ + if (this.resolutions) { │ │ │ │ + this.serverResolutions = this.resolutions; │ │ │ │ + this.maxExtent = this.getMaxExtentForResolution(this.resolutions[0]); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // this block steps through translating the values from the server layer JSON │ │ │ │ + // capabilities object into values that we can use. This is also a helpful │ │ │ │ + // reference when configuring this layer directly. │ │ │ │ + if (this.layerInfo) { │ │ │ │ + // alias the object │ │ │ │ + var info = this.layerInfo; │ │ │ │ + │ │ │ │ + // build our extents │ │ │ │ + var startingTileExtent = new OpenLayers.Bounds( │ │ │ │ + info.fullExtent.xmin, │ │ │ │ + info.fullExtent.ymin, │ │ │ │ + info.fullExtent.xmax, │ │ │ │ + info.fullExtent.ymax │ │ │ │ + ); │ │ │ │ + │ │ │ │ + // set our projection based on the given spatial reference. │ │ │ │ + // esri uses slightly different IDs, so this may not be comprehensive │ │ │ │ + this.projection = 'EPSG:' + info.spatialReference.wkid; │ │ │ │ + this.sphericalMercator = (info.spatialReference.wkid == 102100); │ │ │ │ + │ │ │ │ + // convert esri units into openlayers units (basic feet or meters only) │ │ │ │ + this.units = (info.units == "esriFeet") ? 'ft' : 'm'; │ │ │ │ + │ │ │ │ + // optional extended section based on whether or not the server returned │ │ │ │ + // specific tile information │ │ │ │ + if (!!info.tileInfo) { │ │ │ │ + // either set the tiles based on rows/columns, or specific width/height │ │ │ │ + this.tileSize = new OpenLayers.Size( │ │ │ │ + info.tileInfo.width || info.tileInfo.cols, │ │ │ │ + info.tileInfo.height || info.tileInfo.rows │ │ │ │ + ); │ │ │ │ + │ │ │ │ + // this must be set when manually configuring this layer │ │ │ │ + this.tileOrigin = new OpenLayers.LonLat( │ │ │ │ + info.tileInfo.origin.x, │ │ │ │ + info.tileInfo.origin.y │ │ │ │ + ); │ │ │ │ + │ │ │ │ + var upperLeft = new OpenLayers.Geometry.Point( │ │ │ │ + startingTileExtent.left, │ │ │ │ + startingTileExtent.top │ │ │ │ + ); │ │ │ │ + │ │ │ │ + var bottomRight = new OpenLayers.Geometry.Point( │ │ │ │ + startingTileExtent.right, │ │ │ │ + startingTileExtent.bottom │ │ │ │ + ); │ │ │ │ + │ │ │ │ + if (this.useScales) { │ │ │ │ + this.scales = []; │ │ │ │ } else { │ │ │ │ - child = this.writeNode("gml:Box", filter.value); │ │ │ │ + this.resolutions = []; │ │ │ │ } │ │ │ │ - if (filter.projection) { │ │ │ │ - child.setAttribute("srsName", filter.projection); │ │ │ │ + │ │ │ │ + this.lods = []; │ │ │ │ + for (var key in info.tileInfo.lods) { │ │ │ │ + if (info.tileInfo.lods.hasOwnProperty(key)) { │ │ │ │ + var lod = info.tileInfo.lods[key]; │ │ │ │ + if (this.useScales) { │ │ │ │ + this.scales.push(lod.scale); │ │ │ │ + } else { │ │ │ │ + this.resolutions.push(lod.resolution); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var start = this.getContainingTileCoords(upperLeft, lod.resolution); │ │ │ │ + lod.startTileCol = start.x; │ │ │ │ + lod.startTileRow = start.y; │ │ │ │ + │ │ │ │ + var end = this.getContainingTileCoords(bottomRight, lod.resolution); │ │ │ │ + lod.endTileCol = end.x; │ │ │ │ + lod.endTileRow = end.y; │ │ │ │ + this.lods.push(lod); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.maxExtent = this.calculateMaxExtentWithLOD(this.lods[0]); │ │ │ │ + this.serverResolutions = this.resolutions; │ │ │ │ + if (this.overrideDPI && info.tileInfo.dpi) { │ │ │ │ + // see comment above for 'overrideDPI' │ │ │ │ + OpenLayers.DOTS_PER_INCH = info.tileInfo.dpi; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getContainingTileCoords │ │ │ │ + * Calculates the x/y pixel corresponding to the position of the tile │ │ │ │ + * that contains the given point and for the for the given resolution. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} │ │ │ │ + * res - {Float} The resolution for which to compute the extent. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Pixel>} The x/y pixel corresponding to the position │ │ │ │ + * of the upper left tile for the given resolution. │ │ │ │ + */ │ │ │ │ + getContainingTileCoords: function(point, res) { │ │ │ │ + return new OpenLayers.Pixel( │ │ │ │ + Math.max(Math.floor((point.x - this.tileOrigin.lon) / (this.tileSize.w * res)), 0), │ │ │ │ + Math.max(Math.floor((this.tileOrigin.lat - point.y) / (this.tileSize.h * res)), 0) │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: calculateMaxExtentWithLOD │ │ │ │ + * Given a Level of Detail object from the server, this function │ │ │ │ + * calculates the actual max extent │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * lod - {Object} a Level of Detail Object from the server capabilities object │ │ │ │ + representing a particular zoom level │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} The actual extent of the tiles for the given zoom level │ │ │ │ + */ │ │ │ │ + calculateMaxExtentWithLOD: function(lod) { │ │ │ │ + // the max extent we're provided with just overlaps some tiles │ │ │ │ + // our real extent is the bounds of all the tiles we touch │ │ │ │ + │ │ │ │ + var numTileCols = (lod.endTileCol - lod.startTileCol) + 1; │ │ │ │ + var numTileRows = (lod.endTileRow - lod.startTileRow) + 1; │ │ │ │ + │ │ │ │ + var minX = this.tileOrigin.lon + (lod.startTileCol * this.tileSize.w * lod.resolution); │ │ │ │ + var maxX = minX + (numTileCols * this.tileSize.w * lod.resolution); │ │ │ │ + │ │ │ │ + var maxY = this.tileOrigin.lat - (lod.startTileRow * this.tileSize.h * lod.resolution); │ │ │ │ + var minY = maxY - (numTileRows * this.tileSize.h * lod.resolution); │ │ │ │ + return new OpenLayers.Bounds(minX, minY, maxX, maxY); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: calculateMaxExtentWithExtent │ │ │ │ + * Given a 'suggested' max extent from the server, this function uses │ │ │ │ + * information about the actual tile sizes to determine the actual │ │ │ │ + * extent of the layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * extent - {<OpenLayers.Bounds>} The 'suggested' extent for the layer │ │ │ │ + * res - {Float} The resolution for which to compute the extent. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} The actual extent of the tiles for the given zoom level │ │ │ │ + */ │ │ │ │ + calculateMaxExtentWithExtent: function(extent, res) { │ │ │ │ + var upperLeft = new OpenLayers.Geometry.Point(extent.left, extent.top); │ │ │ │ + var bottomRight = new OpenLayers.Geometry.Point(extent.right, extent.bottom); │ │ │ │ + var start = this.getContainingTileCoords(upperLeft, res); │ │ │ │ + var end = this.getContainingTileCoords(bottomRight, res); │ │ │ │ + var lod = { │ │ │ │ + resolution: res, │ │ │ │ + startTileCol: start.x, │ │ │ │ + startTileRow: start.y, │ │ │ │ + endTileCol: end.x, │ │ │ │ + endTileRow: end.y │ │ │ │ + }; │ │ │ │ + return this.calculateMaxExtentWithLOD(lod); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getUpperLeftTileCoord │ │ │ │ + * Calculates the x/y pixel corresponding to the position │ │ │ │ + * of the upper left tile for the given resolution. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * res - {Float} The resolution for which to compute the extent. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Pixel>} The x/y pixel corresponding to the position │ │ │ │ + * of the upper left tile for the given resolution. │ │ │ │ + */ │ │ │ │ + getUpperLeftTileCoord: function(res) { │ │ │ │ + var upperLeft = new OpenLayers.Geometry.Point( │ │ │ │ + this.maxExtent.left, │ │ │ │ + this.maxExtent.top); │ │ │ │ + return this.getContainingTileCoords(upperLeft, res); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getLowerRightTileCoord │ │ │ │ + * Calculates the x/y pixel corresponding to the position │ │ │ │ + * of the lower right tile for the given resolution. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * res - {Float} The resolution for which to compute the extent. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Pixel>} The x/y pixel corresponding to the position │ │ │ │ + * of the lower right tile for the given resolution. │ │ │ │ + */ │ │ │ │ + getLowerRightTileCoord: function(res) { │ │ │ │ + var bottomRight = new OpenLayers.Geometry.Point( │ │ │ │ + this.maxExtent.right, │ │ │ │ + this.maxExtent.bottom); │ │ │ │ + return this.getContainingTileCoords(bottomRight, res); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getMaxExtentForResolution │ │ │ │ + * Since the max extent of a set of tiles can change from zoom level │ │ │ │ + * to zoom level, we need to be able to calculate that max extent │ │ │ │ + * for a given resolution. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * res - {Float} The resolution for which to compute the extent. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} The extent for this resolution │ │ │ │ + */ │ │ │ │ + getMaxExtentForResolution: function(res) { │ │ │ │ + var start = this.getUpperLeftTileCoord(res); │ │ │ │ + var end = this.getLowerRightTileCoord(res); │ │ │ │ + │ │ │ │ + var numTileCols = (end.x - start.x) + 1; │ │ │ │ + var numTileRows = (end.y - start.y) + 1; │ │ │ │ + │ │ │ │ + var minX = this.tileOrigin.lon + (start.x * this.tileSize.w * res); │ │ │ │ + var maxX = minX + (numTileCols * this.tileSize.w * res); │ │ │ │ + │ │ │ │ + var maxY = this.tileOrigin.lat - (start.y * this.tileSize.h * res); │ │ │ │ + var minY = maxY - (numTileRows * this.tileSize.h * res); │ │ │ │ + return new OpenLayers.Bounds(minX, minY, maxX, maxY); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * Returns an exact clone of this OpenLayers.Layer.ArcGISCache │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * [obj] - {Object} optional object to assign the cloned instance to. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.ArcGISCache>} clone of this instance │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.ArcGISCache(this.name, this.url, this.options); │ │ │ │ + } │ │ │ │ + return OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: initGriddedTiles │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + */ │ │ │ │ + initGriddedTiles: function(bounds) { │ │ │ │ + delete this._tileOrigin; │ │ │ │ + OpenLayers.Layer.XYZ.prototype.initGriddedTiles.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getMaxExtent │ │ │ │ + * Get this layer's maximum extent. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} │ │ │ │ + */ │ │ │ │ + getMaxExtent: function() { │ │ │ │ + var resolution = this.map.getResolution(); │ │ │ │ + return this.maxExtent = this.getMaxExtentForResolution(resolution); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getTileOrigin │ │ │ │ + * Determine the origin for aligning the grid of tiles. │ │ │ │ + * The origin will be derived from the layer's <maxExtent> property. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.LonLat>} The tile origin. │ │ │ │ + */ │ │ │ │ + getTileOrigin: function() { │ │ │ │ + if (!this._tileOrigin) { │ │ │ │ + var extent = this.getMaxExtent(); │ │ │ │ + this._tileOrigin = new OpenLayers.LonLat(extent.left, extent.bottom); │ │ │ │ + } │ │ │ │ + return this._tileOrigin; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getURL │ │ │ │ + * Determine the URL for a tile given the tile bounds. This is should support │ │ │ │ + * urls that access tiles through an ArcGIS Server MapServer or directly through │ │ │ │ + * the hex folder structure using HTTP. Just be sure to set the useArcGISServer │ │ │ │ + * property appropriately! This is basically the same as │ │ │ │ + * 'OpenLayers.Layer.TMS.getURL', but with the addition of hex addressing, │ │ │ │ + * and tile rounding. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} The URL for a tile based on given bounds. │ │ │ │ + */ │ │ │ │ + getURL: function(bounds) { │ │ │ │ + var res = this.getResolution(); │ │ │ │ + │ │ │ │ + // tile center │ │ │ │ + var originTileX = (this.tileOrigin.lon + (res * this.tileSize.w / 2)); │ │ │ │ + var originTileY = (this.tileOrigin.lat - (res * this.tileSize.h / 2)); │ │ │ │ + │ │ │ │ + var center = bounds.getCenterLonLat(); │ │ │ │ + var point = { │ │ │ │ + x: center.lon, │ │ │ │ + y: center.lat │ │ │ │ + }; │ │ │ │ + var x = (Math.round(Math.abs((center.lon - originTileX) / (res * this.tileSize.w)))); │ │ │ │ + var y = (Math.round(Math.abs((originTileY - center.lat) / (res * this.tileSize.h)))); │ │ │ │ + var z = this.map.getZoom(); │ │ │ │ + │ │ │ │ + // this prevents us from getting pink tiles (non-existant tiles) │ │ │ │ + if (this.lods) { │ │ │ │ + var lod = this.lods[this.map.getZoom()]; │ │ │ │ + if ((x < lod.startTileCol || x > lod.endTileCol) || │ │ │ │ + (y < lod.startTileRow || y > lod.endTileRow)) { │ │ │ │ + return null; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + var start = this.getUpperLeftTileCoord(res); │ │ │ │ + var end = this.getLowerRightTileCoord(res); │ │ │ │ + if ((x < start.x || x >= end.x) || │ │ │ │ + (y < start.y || y >= end.y)) { │ │ │ │ + return null; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // Construct the url string │ │ │ │ + var url = this.url; │ │ │ │ + var s = '' + x + y + z; │ │ │ │ + │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(s, url); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // Accessing tiles through ArcGIS Server uses a different path │ │ │ │ + // structure than direct access via the folder structure. │ │ │ │ + if (this.useArcGISServer) { │ │ │ │ + // AGS MapServers have pretty url access to tiles │ │ │ │ + url = url + '/tile/${z}/${y}/${x}'; │ │ │ │ + } else { │ │ │ │ + // The tile images are stored using hex values on disk. │ │ │ │ + x = 'C' + OpenLayers.Number.zeroPad(x, 8, 16); │ │ │ │ + y = 'R' + OpenLayers.Number.zeroPad(y, 8, 16); │ │ │ │ + z = 'L' + OpenLayers.Number.zeroPad(z, 2, 10); │ │ │ │ + url = url + '/${z}/${y}/${x}.' + this.type; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // Write the values into our formatted url │ │ │ │ + url = OpenLayers.String.format(url, { │ │ │ │ + 'x': x, │ │ │ │ + 'y': y, │ │ │ │ + 'z': z │ │ │ │ + }); │ │ │ │ + │ │ │ │ + return OpenLayers.Util.urlAppend( │ │ │ │ + url, OpenLayers.Util.getParameterString(this.params) │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: 'OpenLayers.Layer.ArcGISCache' │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/SphericalMercator.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/Projection.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.SphericalMercator │ │ │ │ + * A mixin for layers that wraps up the pieces neccesary to have a coordinate │ │ │ │ + * conversion for working with commercial APIs which use a spherical │ │ │ │ + * mercator projection. Using this layer as a base layer, additional │ │ │ │ + * layers can be used as overlays if they are in the same projection. │ │ │ │ + * │ │ │ │ + * A layer is given properties of this object by setting the sphericalMercator │ │ │ │ + * property to true. │ │ │ │ + * │ │ │ │ + * More projection information: │ │ │ │ + * - http://spatialreference.org/ref/user/google-projection/ │ │ │ │ + * │ │ │ │ + * Proj4 Text: │ │ │ │ + * +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 │ │ │ │ + * +k=1.0 +units=m +nadgrids=@null +no_defs │ │ │ │ + * │ │ │ │ + * WKT: │ │ │ │ + * 900913=PROJCS["WGS84 / Simple Mercator", GEOGCS["WGS 84", │ │ │ │ + * DATUM["WGS_1984", SPHEROID["WGS_1984", 6378137.0, 298.257223563]], │ │ │ │ + * PRIMEM["Greenwich", 0.0], UNIT["degree", 0.017453292519943295], │ │ │ │ + * AXIS["Longitude", EAST], AXIS["Latitude", NORTH]], │ │ │ │ + * PROJECTION["Mercator_1SP_Google"], │ │ │ │ + * PARAMETER["latitude_of_origin", 0.0], PARAMETER["central_meridian", 0.0], │ │ │ │ + * PARAMETER["scale_factor", 1.0], PARAMETER["false_easting", 0.0], │ │ │ │ + * PARAMETER["false_northing", 0.0], UNIT["m", 1.0], AXIS["x", EAST], │ │ │ │ + * AXIS["y", NORTH], AUTHORITY["EPSG","900913"]] │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.SphericalMercator = { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getExtent │ │ │ │ + * Get the map's extent. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} The map extent. │ │ │ │ + */ │ │ │ │ + getExtent: function() { │ │ │ │ + var extent = null; │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + extent = this.map.calculateBounds(); │ │ │ │ + } else { │ │ │ │ + extent = OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this); │ │ │ │ + } │ │ │ │ + return extent; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getLonLatFromViewPortPx │ │ │ │ + * Get a map location from a pixel location │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * viewPortPx - {<OpenLayers.Pixel>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view │ │ │ │ + * port OpenLayers.Pixel, translated into lon/lat by map lib │ │ │ │ + * If the map lib is not loaded or not centered, returns null │ │ │ │ + */ │ │ │ │ + getLonLatFromViewPortPx: function(viewPortPx) { │ │ │ │ + return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getViewPortPxFromLonLat │ │ │ │ + * Get a pixel location from a map location │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * lonlat - {<OpenLayers.LonLat>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in │ │ │ │ + * OpenLayers.LonLat, translated into view port pixels by map lib │ │ │ │ + * If map lib is not loaded or not centered, returns null │ │ │ │ + */ │ │ │ │ + getViewPortPxFromLonLat: function(lonlat) { │ │ │ │ + return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: initMercatorParameters │ │ │ │ + * Set up the mercator parameters on the layer: resolutions, │ │ │ │ + * projection, units. │ │ │ │ + */ │ │ │ │ + initMercatorParameters: function() { │ │ │ │ + // set up properties for Mercator - assume EPSG:900913 │ │ │ │ + this.RESOLUTIONS = []; │ │ │ │ + var maxResolution = 156543.03390625; │ │ │ │ + for (var zoom = 0; zoom <= this.MAX_ZOOM_LEVEL; ++zoom) { │ │ │ │ + this.RESOLUTIONS[zoom] = maxResolution / Math.pow(2, zoom); │ │ │ │ + } │ │ │ │ + this.units = "m"; │ │ │ │ + this.projection = this.projection || "EPSG:900913"; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: forwardMercator │ │ │ │ + * Given a lon,lat in EPSG:4326, return a point in Spherical Mercator. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * lon - {float} │ │ │ │ + * lat - {float} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.LonLat>} The coordinates transformed to Mercator. │ │ │ │ + */ │ │ │ │ + forwardMercator: (function() { │ │ │ │ + var gg = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ + var sm = new OpenLayers.Projection("EPSG:900913"); │ │ │ │ + return function(lon, lat) { │ │ │ │ + var point = OpenLayers.Projection.transform({ │ │ │ │ + x: lon, │ │ │ │ + y: lat │ │ │ │ + }, gg, sm); │ │ │ │ + return new OpenLayers.LonLat(point.x, point.y); │ │ │ │ + }; │ │ │ │ + })(), │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: inverseMercator │ │ │ │ + * Given a x,y in Spherical Mercator, return a point in EPSG:4326. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * x - {float} A map x in Spherical Mercator. │ │ │ │ + * y - {float} A map y in Spherical Mercator. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.LonLat>} The coordinates transformed to EPSG:4326. │ │ │ │ + */ │ │ │ │ + inverseMercator: (function() { │ │ │ │ + var gg = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ + var sm = new OpenLayers.Projection("EPSG:900913"); │ │ │ │ + return function(x, y) { │ │ │ │ + var point = OpenLayers.Projection.transform({ │ │ │ │ + x: x, │ │ │ │ + y: y │ │ │ │ + }, sm, gg); │ │ │ │ + return new OpenLayers.LonLat(point.x, point.y); │ │ │ │ + }; │ │ │ │ + })() │ │ │ │ + │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/EventPane.js │ │ │ │ + ====================================================================== */ │ │ │ │ + │ │ │ │ +/* Copyright (c) 2006-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/Util.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.EventPane │ │ │ │ + * Base class for 3rd party layers, providing a DOM element which isolates │ │ │ │ + * the 3rd-party layer from mouse events. │ │ │ │ + * Only used by Google layers. │ │ │ │ + * │ │ │ │ + * Automatically instantiated by the Google constructor, and not usually instantiated directly. │ │ │ │ + * │ │ │ │ + * Create a new event pane layer with the │ │ │ │ + * <OpenLayers.Layer.EventPane> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.EventPane = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: smoothDragPan │ │ │ │ + * {Boolean} smoothDragPan determines whether non-public/internal API │ │ │ │ + * methods are used for better performance while dragging EventPane │ │ │ │ + * layers. When not in sphericalMercator mode, the smoother dragging │ │ │ │ + * doesn't actually move north/south directly with the number of │ │ │ │ + * pixels moved, resulting in a slight offset when you drag your mouse │ │ │ │ + * north south with this option on. If this visual disparity bothers │ │ │ │ + * you, you should turn this option off, or use spherical mercator. │ │ │ │ + * Default is on. │ │ │ │ + */ │ │ │ │ + smoothDragPan: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: isBaseLayer │ │ │ │ + * {Boolean} EventPaned layers are always base layers, by necessity. │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isFixed │ │ │ │ + * {Boolean} EventPaned layers are fixed by default. │ │ │ │ + */ │ │ │ │ + isFixed: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: pane │ │ │ │ + * {DOMElement} A reference to the element that controls the events. │ │ │ │ + */ │ │ │ │ + pane: null, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: mapObject │ │ │ │ + * {Object} This is the object which will be used to load the 3rd party library │ │ │ │ + * in the case of the google layer, this will be of type GMap, │ │ │ │ + * in the case of the ve layer, this will be of type VEMap │ │ │ │ + */ │ │ │ │ + mapObject: null, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.EventPane │ │ │ │ + * Create a new event pane layer │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} │ │ │ │ + * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ + */ │ │ │ │ + initialize: function(name, options) { │ │ │ │ + OpenLayers.Layer.prototype.initialize.apply(this, arguments); │ │ │ │ + if (this.pane == null) { │ │ │ │ + this.pane = OpenLayers.Util.createDiv(this.div.id + "_EventPane"); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Deconstruct this layer. │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + this.mapObject = null; │ │ │ │ + this.pane = null; │ │ │ │ + OpenLayers.Layer.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ + * Set the map property for the layer. This is done through an accessor │ │ │ │ + * so that subclasses can override this and take special action once │ │ │ │ + * they have their map variable set. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Layer.prototype.setMap.apply(this, arguments); │ │ │ │ + │ │ │ │ + this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1; │ │ │ │ + this.pane.style.display = this.div.style.display; │ │ │ │ + this.pane.style.width = "100%"; │ │ │ │ + this.pane.style.height = "100%"; │ │ │ │ + if (OpenLayers.BROWSER_NAME == "msie") { │ │ │ │ + this.pane.style.background = │ │ │ │ + "url(" + OpenLayers.Util.getImageLocation("blank.gif") + ")"; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.isFixed) { │ │ │ │ + this.map.viewPortDiv.appendChild(this.pane); │ │ │ │ + } else { │ │ │ │ + this.map.layerContainerDiv.appendChild(this.pane); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // once our layer has been added to the map, we can load it │ │ │ │ + this.loadMapObject(); │ │ │ │ + │ │ │ │ + // if map didn't load, display warning │ │ │ │ + if (this.mapObject == null) { │ │ │ │ + this.loadWarningMessage(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: removeMap │ │ │ │ + * On being removed from the map, we'll like to remove the invisible 'pane' │ │ │ │ + * div that we added to it on creation. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + removeMap: function(map) { │ │ │ │ + if (this.pane && this.pane.parentNode) { │ │ │ │ + this.pane.parentNode.removeChild(this.pane); │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.prototype.removeMap.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: loadWarningMessage │ │ │ │ + * If we can't load the map lib, then display an error message to the │ │ │ │ + * user and tell them where to go for help. │ │ │ │ + * │ │ │ │ + * This function sets up the layout for the warning message. Each 3rd │ │ │ │ + * party layer must implement its own getWarningHTML() function to │ │ │ │ + * provide the actual warning message. │ │ │ │ + */ │ │ │ │ + loadWarningMessage: function() { │ │ │ │ + │ │ │ │ + this.div.style.backgroundColor = "darkblue"; │ │ │ │ + │ │ │ │ + var viewSize = this.map.getSize(); │ │ │ │ + │ │ │ │ + var msgW = Math.min(viewSize.w, 300); │ │ │ │ + var msgH = Math.min(viewSize.h, 200); │ │ │ │ + var size = new OpenLayers.Size(msgW, msgH); │ │ │ │ + │ │ │ │ + var centerPx = new OpenLayers.Pixel(viewSize.w / 2, viewSize.h / 2); │ │ │ │ + │ │ │ │ + var topLeft = centerPx.add(-size.w / 2, -size.h / 2); │ │ │ │ + │ │ │ │ + var div = OpenLayers.Util.createDiv(this.name + "_warning", │ │ │ │ + topLeft, │ │ │ │ + size, │ │ │ │ + null, │ │ │ │ + null, │ │ │ │ + null, │ │ │ │ + "auto"); │ │ │ │ + │ │ │ │ + div.style.padding = "7px"; │ │ │ │ + div.style.backgroundColor = "yellow"; │ │ │ │ + │ │ │ │ + div.innerHTML = this.getWarningHTML(); │ │ │ │ + this.div.appendChild(div); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getWarningHTML │ │ │ │ + * To be implemented by subclasses. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} String with information on why layer is broken, how to get │ │ │ │ + * it working. │ │ │ │ + */ │ │ │ │ + getWarningHTML: function() { │ │ │ │ + //should be implemented by subclasses │ │ │ │ + return ""; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: display │ │ │ │ + * Set the display on the pane │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * display - {Boolean} │ │ │ │ + */ │ │ │ │ + display: function(display) { │ │ │ │ + OpenLayers.Layer.prototype.display.apply(this, arguments); │ │ │ │ + this.pane.style.display = this.div.style.display; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setZIndex │ │ │ │ + * Set the z-index order for the pane. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * zIndex - {int} │ │ │ │ + */ │ │ │ │ + setZIndex: function(zIndex) { │ │ │ │ + OpenLayers.Layer.prototype.setZIndex.apply(this, arguments); │ │ │ │ + this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveByPx │ │ │ │ + * Move the layer based on pixel vector. To be implemented by subclasses. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * dx - {Number} The x coord of the displacement vector. │ │ │ │ + * dy - {Number} The y coord of the displacement vector. │ │ │ │ + */ │ │ │ │ + moveByPx: function(dx, dy) { │ │ │ │ + OpenLayers.Layer.prototype.moveByPx.apply(this, arguments); │ │ │ │ + │ │ │ │ + if (this.dragPanMapObject) { │ │ │ │ + this.dragPanMapObject(dx, -dy); │ │ │ │ + } else { │ │ │ │ + this.moveTo(this.map.getCachedCenter()); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveTo │ │ │ │ + * Handle calls to move the layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * zoomChanged - {Boolean} │ │ │ │ + * dragging - {Boolean} │ │ │ │ + */ │ │ │ │ + moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ + OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ + │ │ │ │ + if (this.mapObject != null) { │ │ │ │ + │ │ │ │ + var newCenter = this.map.getCenter(); │ │ │ │ + var newZoom = this.map.getZoom(); │ │ │ │ + │ │ │ │ + if (newCenter != null) { │ │ │ │ + │ │ │ │ + var moOldCenter = this.getMapObjectCenter(); │ │ │ │ + var oldCenter = this.getOLLonLatFromMapObjectLonLat(moOldCenter); │ │ │ │ + │ │ │ │ + var moOldZoom = this.getMapObjectZoom(); │ │ │ │ + var oldZoom = this.getOLZoomFromMapObjectZoom(moOldZoom); │ │ │ │ + │ │ │ │ + if (!(newCenter.equals(oldCenter)) || newZoom != oldZoom) { │ │ │ │ + │ │ │ │ + if (!zoomChanged && oldCenter && this.dragPanMapObject && │ │ │ │ + this.smoothDragPan) { │ │ │ │ + var oldPx = this.map.getViewPortPxFromLonLat(oldCenter); │ │ │ │ + var newPx = this.map.getViewPortPxFromLonLat(newCenter); │ │ │ │ + this.dragPanMapObject(newPx.x - oldPx.x, oldPx.y - newPx.y); │ │ │ │ + } else { │ │ │ │ + var center = this.getMapObjectLonLatFromOLLonLat(newCenter); │ │ │ │ + var zoom = this.getMapObjectZoomFromOLZoom(newZoom); │ │ │ │ + this.setMapObjectCenter(center, zoom, dragging); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /********************************************************/ │ │ │ │ + /* */ │ │ │ │ + /* Baselayer Functions */ │ │ │ │ + /* */ │ │ │ │ + /********************************************************/ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getLonLatFromViewPortPx │ │ │ │ + * Get a map location from a pixel location │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * viewPortPx - {<OpenLayers.Pixel>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view │ │ │ │ + * port OpenLayers.Pixel, translated into lon/lat by map lib │ │ │ │ + * If the map lib is not loaded or not centered, returns null │ │ │ │ + */ │ │ │ │ + getLonLatFromViewPortPx: function(viewPortPx) { │ │ │ │ + var lonlat = null; │ │ │ │ + if ((this.mapObject != null) && │ │ │ │ + (this.getMapObjectCenter() != null)) { │ │ │ │ + var moPixel = this.getMapObjectPixelFromOLPixel(viewPortPx); │ │ │ │ + var moLonLat = this.getMapObjectLonLatFromMapObjectPixel(moPixel); │ │ │ │ + lonlat = this.getOLLonLatFromMapObjectLonLat(moLonLat); │ │ │ │ + } │ │ │ │ + return lonlat; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getViewPortPxFromLonLat │ │ │ │ + * Get a pixel location from a map location │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * lonlat - {<OpenLayers.LonLat>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in │ │ │ │ + * OpenLayers.LonLat, translated into view port pixels by map lib │ │ │ │ + * If map lib is not loaded or not centered, returns null │ │ │ │ + */ │ │ │ │ + getViewPortPxFromLonLat: function(lonlat) { │ │ │ │ + var viewPortPx = null; │ │ │ │ + if ((this.mapObject != null) && │ │ │ │ + (this.getMapObjectCenter() != null)) { │ │ │ │ + │ │ │ │ + var moLonLat = this.getMapObjectLonLatFromOLLonLat(lonlat); │ │ │ │ + var moPixel = this.getMapObjectPixelFromMapObjectLonLat(moLonLat); │ │ │ │ + │ │ │ │ + viewPortPx = this.getOLPixelFromMapObjectPixel(moPixel); │ │ │ │ + } │ │ │ │ + return viewPortPx; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /********************************************************/ │ │ │ │ + /* */ │ │ │ │ + /* Translation Functions */ │ │ │ │ + /* */ │ │ │ │ + /* The following functions translate Map Object and */ │ │ │ │ + /* OL formats for Pixel, LonLat */ │ │ │ │ + /* */ │ │ │ │ + /********************************************************/ │ │ │ │ + │ │ │ │ + // │ │ │ │ + // TRANSLATION: MapObject LatLng <-> OpenLayers.LonLat │ │ │ │ + // │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getOLLonLatFromMapObjectLonLat │ │ │ │ + * Get an OL style map location from a 3rd party style map location │ │ │ │ + * │ │ │ │ + * Parameters │ │ │ │ + * moLonLat - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.LonLat>} An OpenLayers.LonLat, translated from the passed in │ │ │ │ + * MapObject LonLat │ │ │ │ + * Returns null if null value is passed in │ │ │ │ + */ │ │ │ │ + getOLLonLatFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + var olLonLat = null; │ │ │ │ + if (moLonLat != null) { │ │ │ │ + var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); │ │ │ │ + var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); │ │ │ │ + olLonLat = new OpenLayers.LonLat(lon, lat); │ │ │ │ + } │ │ │ │ + return olLonLat; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getMapObjectLonLatFromOLLonLat │ │ │ │ + * Get a 3rd party map location from an OL map location. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * olLonLat - {<OpenLayers.LonLat>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} A MapObject LonLat, translated from the passed in │ │ │ │ + * OpenLayers.LonLat │ │ │ │ + * Returns null if null value is passed in │ │ │ │ + */ │ │ │ │ + getMapObjectLonLatFromOLLonLat: function(olLonLat) { │ │ │ │ + var moLatLng = null; │ │ │ │ + if (olLonLat != null) { │ │ │ │ + moLatLng = this.getMapObjectLonLatFromLonLat(olLonLat.lon, │ │ │ │ + olLonLat.lat); │ │ │ │ + } │ │ │ │ + return moLatLng; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + // │ │ │ │ + // TRANSLATION: MapObject Pixel <-> OpenLayers.Pixel │ │ │ │ + // │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getOLPixelFromMapObjectPixel │ │ │ │ + * Get an OL pixel location from a 3rd party pixel location. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moPixel - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Pixel>} An OpenLayers.Pixel, translated from the passed in │ │ │ │ + * MapObject Pixel │ │ │ │ + * Returns null if null value is passed in │ │ │ │ + */ │ │ │ │ + getOLPixelFromMapObjectPixel: function(moPixel) { │ │ │ │ + var olPixel = null; │ │ │ │ + if (moPixel != null) { │ │ │ │ + var x = this.getXFromMapObjectPixel(moPixel); │ │ │ │ + var y = this.getYFromMapObjectPixel(moPixel); │ │ │ │ + olPixel = new OpenLayers.Pixel(x, y); │ │ │ │ + } │ │ │ │ + return olPixel; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getMapObjectPixelFromOLPixel │ │ │ │ + * Get a 3rd party pixel location from an OL pixel location │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * olPixel - {<OpenLayers.Pixel>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} A MapObject Pixel, translated from the passed in │ │ │ │ + * OpenLayers.Pixel │ │ │ │ + * Returns null if null value is passed in │ │ │ │ + */ │ │ │ │ + getMapObjectPixelFromOLPixel: function(olPixel) { │ │ │ │ + var moPixel = null; │ │ │ │ + if (olPixel != null) { │ │ │ │ + moPixel = this.getMapObjectPixelFromXY(olPixel.x, olPixel.y); │ │ │ │ + } │ │ │ │ + return moPixel; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.EventPane" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/Google.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/SphericalMercator.js │ │ │ │ + * @requires OpenLayers/Layer/EventPane.js │ │ │ │ + * @requires OpenLayers/Layer/FixedZoomLevels.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.Google │ │ │ │ + * │ │ │ │ + * Provides a wrapper for Google's Maps API │ │ │ │ + * Normally the Terms of Use for this API do not allow wrapping, but Google │ │ │ │ + * have provided written consent to OpenLayers for this - see email in │ │ │ │ + * http://osgeo-org.1560.n6.nabble.com/Google-Maps-API-Terms-of-Use-changes-tp4910013p4911981.html │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.SphericalMercator> │ │ │ │ + * - <OpenLayers.Layer.EventPane> │ │ │ │ + * - <OpenLayers.Layer.FixedZoomLevels> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Google = OpenLayers.Class( │ │ │ │ + OpenLayers.Layer.EventPane, │ │ │ │ + OpenLayers.Layer.FixedZoomLevels, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: MIN_ZOOM_LEVEL │ │ │ │ + * {Integer} 0 │ │ │ │ + */ │ │ │ │ + MIN_ZOOM_LEVEL: 0, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: MAX_ZOOM_LEVEL │ │ │ │ + * {Integer} 21 │ │ │ │ + */ │ │ │ │ + MAX_ZOOM_LEVEL: 21, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: RESOLUTIONS │ │ │ │ + * {Array(Float)} Hardcode these resolutions so that they are more closely │ │ │ │ + * tied with the standard wms projection │ │ │ │ + */ │ │ │ │ + RESOLUTIONS: [ │ │ │ │ + 1.40625, │ │ │ │ + 0.703125, │ │ │ │ + 0.3515625, │ │ │ │ + 0.17578125, │ │ │ │ + 0.087890625, │ │ │ │ + 0.0439453125, │ │ │ │ + 0.02197265625, │ │ │ │ + 0.010986328125, │ │ │ │ + 0.0054931640625, │ │ │ │ + 0.00274658203125, │ │ │ │ + 0.001373291015625, │ │ │ │ + 0.0006866455078125, │ │ │ │ + 0.00034332275390625, │ │ │ │ + 0.000171661376953125, │ │ │ │ + 0.0000858306884765625, │ │ │ │ + 0.00004291534423828125, │ │ │ │ + 0.00002145767211914062, │ │ │ │ + 0.00001072883605957031, │ │ │ │ + 0.00000536441802978515, │ │ │ │ + 0.00000268220901489257, │ │ │ │ + 0.0000013411045074462891, │ │ │ │ + 0.00000067055225372314453 │ │ │ │ + ], │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: type │ │ │ │ + * {GMapType} │ │ │ │ + */ │ │ │ │ + type: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: wrapDateLine │ │ │ │ + * {Boolean} Allow user to pan forever east/west. Default is true. │ │ │ │ + * Setting this to false only restricts panning if │ │ │ │ + * <sphericalMercator> is true. │ │ │ │ + */ │ │ │ │ + wrapDateLine: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: sphericalMercator │ │ │ │ + * {Boolean} Should the map act as a mercator-projected map? This will │ │ │ │ + * cause all interactions with the map to be in the actual map │ │ │ │ + * projection, which allows support for vector drawing, overlaying │ │ │ │ + * other maps, etc. │ │ │ │ + */ │ │ │ │ + sphericalMercator: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {Number} The version of the Google Maps API │ │ │ │ + */ │ │ │ │ + version: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.Google │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} A name for the layer. │ │ │ │ + * options - {Object} An optional object whose properties will be set │ │ │ │ + * on the layer. │ │ │ │ + */ │ │ │ │ + initialize: function(name, options) { │ │ │ │ + options = options || {}; │ │ │ │ + if (!options.version) { │ │ │ │ + options.version = typeof GMap2 === "function" ? "2" : "3"; │ │ │ │ + } │ │ │ │ + var mixin = OpenLayers.Layer.Google["v" + │ │ │ │ + options.version.replace(/\./g, "_")]; │ │ │ │ + if (mixin) { │ │ │ │ + OpenLayers.Util.applyDefaults(options, mixin); │ │ │ │ + } else { │ │ │ │ + throw "Unsupported Google Maps API version: " + options.version; │ │ │ │ + } │ │ │ │ + │ │ │ │ + OpenLayers.Util.applyDefaults(options, mixin.DEFAULTS); │ │ │ │ + if (options.maxExtent) { │ │ │ │ + options.maxExtent = options.maxExtent.clone(); │ │ │ │ + } │ │ │ │ + │ │ │ │ + OpenLayers.Layer.EventPane.prototype.initialize.apply(this, │ │ │ │ + [name, options]); │ │ │ │ + OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, │ │ │ │ + [name, options]); │ │ │ │ + │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator); │ │ │ │ + this.initMercatorParameters(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.Google>} An exact clone of this layer │ │ │ │ + */ │ │ │ │ + clone: function() { │ │ │ │ + /** │ │ │ │ + * This method isn't intended to be called by a subclass and it │ │ │ │ + * doesn't call the same method on the superclass. We don't call │ │ │ │ + * the super's clone because we don't want properties that are set │ │ │ │ + * on this layer after initialize (i.e. this.mapObject etc.). │ │ │ │ + */ │ │ │ │ + return new OpenLayers.Layer.Google( │ │ │ │ + this.name, this.getOptions() │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setVisibility │ │ │ │ + * Set the visibility flag for the layer and hide/show & redraw │ │ │ │ + * accordingly. Fire event unless otherwise specified │ │ │ │ + * │ │ │ │ + * Note that visibility is no longer simply whether or not the layer's │ │ │ │ + * style.display is set to "block". Now we store a 'visibility' state │ │ │ │ + * property on the layer class, this allows us to remember whether or │ │ │ │ + * not we *desire* for a layer to be visible. In the case where the │ │ │ │ + * map's resolution is out of the layer's range, this desire may be │ │ │ │ + * subverted. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * visible - {Boolean} Display the layer (if in range) │ │ │ │ + */ │ │ │ │ + setVisibility: function(visible) { │ │ │ │ + // sharing a map container, opacity has to be set per layer │ │ │ │ + var opacity = this.opacity == null ? 1 : this.opacity; │ │ │ │ + OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this, arguments); │ │ │ │ + this.setOpacity(opacity); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: display │ │ │ │ + * Hide or show the Layer │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * visible - {Boolean} │ │ │ │ + */ │ │ │ │ + display: function(visible) { │ │ │ │ + if (!this._dragging) { │ │ │ │ + this.setGMapVisibility(visible); │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.EventPane.prototype.display.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveTo │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to │ │ │ │ + * do some init work in that case. │ │ │ │ + * dragging - {Boolean} │ │ │ │ + */ │ │ │ │ + moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ + this._dragging = dragging; │ │ │ │ + OpenLayers.Layer.EventPane.prototype.moveTo.apply(this, arguments); │ │ │ │ + delete this._dragging; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setOpacity │ │ │ │ + * Sets the opacity for the entire layer (all images) │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * opacity - {Float} │ │ │ │ + */ │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ + if (opacity !== this.opacity) { │ │ │ │ + if (this.map != null) { │ │ │ │ + this.map.events.triggerEvent("changelayer", { │ │ │ │ + layer: this, │ │ │ │ + property: "opacity" │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + this.opacity = opacity; │ │ │ │ + } │ │ │ │ + // Though this layer's opacity may not change, we're sharing a container │ │ │ │ + // and need to update the opacity for the entire container. │ │ │ │ + if (this.getVisibility()) { │ │ │ │ + var container = this.getMapContainer(); │ │ │ │ + OpenLayers.Util.modifyDOMElement( │ │ │ │ + container, null, null, null, null, null, null, opacity │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Clean up this layer. │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + /** │ │ │ │ + * We have to override this method because the event pane destroy │ │ │ │ + * deletes the mapObject reference before removing this layer from │ │ │ │ + * the map. │ │ │ │ + */ │ │ │ │ + if (this.map) { │ │ │ │ + this.setGMapVisibility(false); │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache && cache.count <= 1) { │ │ │ │ + this.removeGMapElements(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.EventPane.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: removeGMapElements │ │ │ │ + * Remove all elements added to the dom. This should only be called if │ │ │ │ + * this is the last of the Google layers for the given map. │ │ │ │ + */ │ │ │ │ + removeGMapElements: function() { │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + // remove shared elements from dom │ │ │ │ + var container = this.mapObject && this.getMapContainer(); │ │ │ │ + if (container && container.parentNode) { │ │ │ │ + container.parentNode.removeChild(container); │ │ │ │ + } │ │ │ │ + var termsOfUse = cache.termsOfUse; │ │ │ │ + if (termsOfUse && termsOfUse.parentNode) { │ │ │ │ + termsOfUse.parentNode.removeChild(termsOfUse); │ │ │ │ + } │ │ │ │ + var poweredBy = cache.poweredBy; │ │ │ │ + if (poweredBy && poweredBy.parentNode) { │ │ │ │ + poweredBy.parentNode.removeChild(poweredBy); │ │ │ │ + } │ │ │ │ + if (this.mapObject && window.google && google.maps && │ │ │ │ + google.maps.event && google.maps.event.clearListeners) { │ │ │ │ + google.maps.event.clearListeners(this.mapObject, 'tilesloaded'); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: removeMap │ │ │ │ + * On being removed from the map, also remove termsOfUse and poweredBy divs │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + removeMap: function(map) { │ │ │ │ + // hide layer before removing │ │ │ │ + if (this.visibility && this.mapObject) { │ │ │ │ + this.setGMapVisibility(false); │ │ │ │ + } │ │ │ │ + // check to see if last Google layer in this map │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[map.id]; │ │ │ │ + if (cache) { │ │ │ │ + if (cache.count <= 1) { │ │ │ │ + this.removeGMapElements(); │ │ │ │ + delete OpenLayers.Layer.Google.cache[map.id]; │ │ │ │ + } else { │ │ │ │ + // decrement the layer count │ │ │ │ + --cache.count; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + // remove references to gmap elements │ │ │ │ + delete this.termsOfUse; │ │ │ │ + delete this.poweredBy; │ │ │ │ + delete this.mapObject; │ │ │ │ + delete this.dragObject; │ │ │ │ + OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + // │ │ │ │ + // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ + // │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getOLBoundsFromMapObjectBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moBounds - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} An <OpenLayers.Bounds>, translated from the │ │ │ │ + * passed-in MapObject Bounds. │ │ │ │ + * Returns null if null value is passed in. │ │ │ │ + */ │ │ │ │ + getOLBoundsFromMapObjectBounds: function(moBounds) { │ │ │ │ + var olBounds = null; │ │ │ │ + if (moBounds != null) { │ │ │ │ + var sw = moBounds.getSouthWest(); │ │ │ │ + var ne = moBounds.getNorthEast(); │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + sw = this.forwardMercator(sw.lng(), sw.lat()); │ │ │ │ + ne = this.forwardMercator(ne.lng(), ne.lat()); │ │ │ │ + } else { │ │ │ │ + sw = new OpenLayers.LonLat(sw.lng(), sw.lat()); │ │ │ │ + ne = new OpenLayers.LonLat(ne.lng(), ne.lat()); │ │ │ │ + } │ │ │ │ + olBounds = new OpenLayers.Bounds(sw.lon, │ │ │ │ + sw.lat, │ │ │ │ + ne.lon, │ │ │ │ + ne.lat); │ │ │ │ + } │ │ │ │ + return olBounds; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getWarningHTML │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} String with information on why layer is broken, how to get │ │ │ │ + * it working. │ │ │ │ + */ │ │ │ │ + getWarningHTML: function() { │ │ │ │ + return OpenLayers.i18n("googleWarning"); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Interface Controls * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ + │ │ │ │ + │ │ │ │ + // Get&Set Center, Zoom │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectCenter │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} The mapObject's current center in Map Object format │ │ │ │ + */ │ │ │ │ + getMapObjectCenter: function() { │ │ │ │ + return this.mapObject.getCenter(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectZoom │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} The mapObject's current zoom, in Map Object format │ │ │ │ + */ │ │ │ │ + getMapObjectZoom: function() { │ │ │ │ + return this.mapObject.getZoom(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Primitives * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ + │ │ │ │ + │ │ │ │ + // LonLat │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getLongitudeFromMapObjectLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moLonLat - {Object} MapObject LonLat format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Float} Longitude of the given MapObject LonLat │ │ │ │ + */ │ │ │ │ + getLongitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + return this.sphericalMercator ? │ │ │ │ + this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon : │ │ │ │ + moLonLat.lng(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getLatitudeFromMapObjectLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moLonLat - {Object} MapObject LonLat format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Float} Latitude of the given MapObject LonLat │ │ │ │ + */ │ │ │ │ + getLatitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + var lat = this.sphericalMercator ? │ │ │ │ + this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat : │ │ │ │ + moLonLat.lat(); │ │ │ │ + return lat; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + // Pixel │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getXFromMapObjectPixel │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moPixel - {Object} MapObject Pixel format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} X value of the MapObject Pixel │ │ │ │ + */ │ │ │ │ + getXFromMapObjectPixel: function(moPixel) { │ │ │ │ + return moPixel.x; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getYFromMapObjectPixel │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moPixel - {Object} MapObject Pixel format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} Y value of the MapObject Pixel │ │ │ │ + */ │ │ │ │ + getYFromMapObjectPixel: function(moPixel) { │ │ │ │ + return moPixel.y; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Google" │ │ │ │ + }); │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Property: OpenLayers.Layer.Google.cache │ │ │ │ + * {Object} Cache for elements that should only be created once per map. │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Google.cache = {}; │ │ │ │ + │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Layer.Google.v2 │ │ │ │ + * │ │ │ │ + * Mixin providing functionality specific to the Google Maps API v2. │ │ │ │ + * │ │ │ │ + * This API has been deprecated by Google. │ │ │ │ + * Developers are encouraged to migrate to v3 of the API; support for this │ │ │ │ + * is provided by <OpenLayers.Layer.Google.v3> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Google.v2 = { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: termsOfUse │ │ │ │ + * {DOMElement} Div for Google's copyright and terms of use link │ │ │ │ + */ │ │ │ │ + termsOfUse: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: poweredBy │ │ │ │ + * {DOMElement} Div for Google's powered by logo and link │ │ │ │ + */ │ │ │ │ + poweredBy: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: dragObject │ │ │ │ + * {GDraggableObject} Since 2.93, Google has exposed the ability to get │ │ │ │ + * the maps GDraggableObject. We can now use this for smooth panning │ │ │ │ + */ │ │ │ │ + dragObject: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: loadMapObject │ │ │ │ + * Load the GMap and register appropriate event listeners. If we can't │ │ │ │ + * load GMap2, then display a warning message. │ │ │ │ + */ │ │ │ │ + loadMapObject: function() { │ │ │ │ + if (!this.type) { │ │ │ │ + this.type = G_NORMAL_MAP; │ │ │ │ + } │ │ │ │ + var mapObject, termsOfUse, poweredBy; │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + // there are already Google layers added to this map │ │ │ │ + mapObject = cache.mapObject; │ │ │ │ + termsOfUse = cache.termsOfUse; │ │ │ │ + poweredBy = cache.poweredBy; │ │ │ │ + // increment the layer count │ │ │ │ + ++cache.count; │ │ │ │ + } else { │ │ │ │ + // this is the first Google layer for this map │ │ │ │ + │ │ │ │ + var container = this.map.viewPortDiv; │ │ │ │ + var div = document.createElement("div"); │ │ │ │ + div.id = this.map.id + "_GMap2Container"; │ │ │ │ + div.style.position = "absolute"; │ │ │ │ + div.style.width = "100%"; │ │ │ │ + div.style.height = "100%"; │ │ │ │ + container.appendChild(div); │ │ │ │ + │ │ │ │ + // create GMap and shuffle elements │ │ │ │ + try { │ │ │ │ + mapObject = new GMap2(div); │ │ │ │ + │ │ │ │ + // move the ToS and branding stuff up to the container div │ │ │ │ + termsOfUse = div.lastChild; │ │ │ │ + container.appendChild(termsOfUse); │ │ │ │ + termsOfUse.style.zIndex = "1100"; │ │ │ │ + termsOfUse.style.right = ""; │ │ │ │ + termsOfUse.style.bottom = ""; │ │ │ │ + termsOfUse.className = "olLayerGoogleCopyright"; │ │ │ │ + │ │ │ │ + poweredBy = div.lastChild; │ │ │ │ + container.appendChild(poweredBy); │ │ │ │ + poweredBy.style.zIndex = "1100"; │ │ │ │ + poweredBy.style.right = ""; │ │ │ │ + poweredBy.style.bottom = ""; │ │ │ │ + poweredBy.className = "olLayerGooglePoweredBy gmnoprint"; │ │ │ │ + │ │ │ │ + } catch (e) { │ │ │ │ + throw (e); │ │ │ │ + } │ │ │ │ + // cache elements for use by any other google layers added to │ │ │ │ + // this same map │ │ │ │ + OpenLayers.Layer.Google.cache[this.map.id] = { │ │ │ │ + mapObject: mapObject, │ │ │ │ + termsOfUse: termsOfUse, │ │ │ │ + poweredBy: poweredBy, │ │ │ │ + count: 1 │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.mapObject = mapObject; │ │ │ │ + this.termsOfUse = termsOfUse; │ │ │ │ + this.poweredBy = poweredBy; │ │ │ │ + │ │ │ │ + // ensure this layer type is one of the mapObject types │ │ │ │ + if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(), │ │ │ │ + this.type) === -1) { │ │ │ │ + this.mapObject.addMapType(this.type); │ │ │ │ + } │ │ │ │ + │ │ │ │ + //since v 2.93 getDragObject is now available. │ │ │ │ + if (typeof mapObject.getDragObject == "function") { │ │ │ │ + this.dragObject = mapObject.getDragObject(); │ │ │ │ + } else { │ │ │ │ + this.dragPanMapObject = null; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.isBaseLayer === false) { │ │ │ │ + this.setGMapVisibility(this.div.style.display !== "none"); │ │ │ │ + } │ │ │ │ + │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: onMapResize │ │ │ │ + */ │ │ │ │ + onMapResize: function() { │ │ │ │ + // workaround for resizing of invisible or not yet fully loaded layers │ │ │ │ + // where GMap2.checkResize() does not work. We need to load the GMap │ │ │ │ + // for the old div size, then checkResize(), and then call │ │ │ │ + // layer.moveTo() to trigger GMap.setCenter() (which will finish │ │ │ │ + // the GMap initialization). │ │ │ │ + if (this.visibility && this.mapObject.isLoaded()) { │ │ │ │ + this.mapObject.checkResize(); │ │ │ │ + } else { │ │ │ │ + if (!this._resized) { │ │ │ │ + var layer = this; │ │ │ │ + var handle = GEvent.addListener(this.mapObject, "load", function() { │ │ │ │ + GEvent.removeListener(handle); │ │ │ │ + delete layer._resized; │ │ │ │ + layer.mapObject.checkResize(); │ │ │ │ + layer.moveTo(layer.map.getCenter(), layer.map.getZoom()); │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + this._resized = true; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setGMapVisibility │ │ │ │ + * Display the GMap container and associated elements. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * visible - {Boolean} Display the GMap elements. │ │ │ │ + */ │ │ │ │ + setGMapVisibility: function(visible) { │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + var container = this.mapObject.getContainer(); │ │ │ │ + if (visible === true) { │ │ │ │ + this.mapObject.setMapType(this.type); │ │ │ │ + container.style.display = ""; │ │ │ │ + this.termsOfUse.style.left = ""; │ │ │ │ + this.termsOfUse.style.display = ""; │ │ │ │ + this.poweredBy.style.display = ""; │ │ │ │ + cache.displayed = this.id; │ │ │ │ + } else { │ │ │ │ + if (cache.displayed === this.id) { │ │ │ │ + delete cache.displayed; │ │ │ │ + } │ │ │ │ + if (!cache.displayed) { │ │ │ │ + container.style.display = "none"; │ │ │ │ + this.termsOfUse.style.display = "none"; │ │ │ │ + // move ToU far to the left in addition to setting display │ │ │ │ + // to "none", because at the end of the GMap2 load │ │ │ │ + // sequence, display: none will be unset and ToU would be │ │ │ │ + // visible after loading a map with a google layer that is │ │ │ │ + // initially hidden. │ │ │ │ + this.termsOfUse.style.left = "-9999px"; │ │ │ │ + this.poweredBy.style.display = "none"; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getMapContainer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} the GMap container's div │ │ │ │ + */ │ │ │ │ + getMapContainer: function() { │ │ │ │ + return this.mapObject.getContainer(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + // │ │ │ │ + // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ + // │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectBoundsFromOLBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * olBounds - {<OpenLayers.Bounds>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} A MapObject Bounds, translated from olBounds │ │ │ │ + * Returns null if null value is passed in │ │ │ │ + */ │ │ │ │ + getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ + var moBounds = null; │ │ │ │ + if (olBounds != null) { │ │ │ │ + var sw = this.sphericalMercator ? │ │ │ │ + this.inverseMercator(olBounds.bottom, olBounds.left) : │ │ │ │ + new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ + var ne = this.sphericalMercator ? │ │ │ │ + this.inverseMercator(olBounds.top, olBounds.right) : │ │ │ │ + new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ + moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon), │ │ │ │ + new GLatLng(ne.lat, ne.lon)); │ │ │ │ + } │ │ │ │ + return moBounds; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Interface Controls * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ + │ │ │ │ + │ │ │ │ + // Get&Set Center, Zoom │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setMapObjectCenter │ │ │ │ + * Set the mapObject to the specified center and zoom │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * center - {Object} MapObject LonLat format │ │ │ │ + * zoom - {int} MapObject zoom format │ │ │ │ + */ │ │ │ │ + setMapObjectCenter: function(center, zoom) { │ │ │ │ + this.mapObject.setCenter(center, zoom); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: dragPanMapObject │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * dX - {Integer} │ │ │ │ + * dY - {Integer} │ │ │ │ + */ │ │ │ │ + dragPanMapObject: function(dX, dY) { │ │ │ │ + this.dragObject.moveBy(new GSize(-dX, dY)); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + // LonLat - Pixel Translation │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectLonLatFromMapObjectPixel │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moPixel - {Object} MapObject Pixel format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject LonLat translated from MapObject Pixel │ │ │ │ + */ │ │ │ │ + getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ + return this.mapObject.fromContainerPixelToLatLng(moPixel); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectPixelFromMapObjectLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moLonLat - {Object} MapObject LonLat format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Pixel transtlated from MapObject LonLat │ │ │ │ + */ │ │ │ │ + getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + return this.mapObject.fromLatLngToContainerPixel(moLonLat); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + // Bounds │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectZoomFromMapObjectBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moBounds - {Object} MapObject Bounds format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Zoom for specified MapObject Bounds │ │ │ │ + */ │ │ │ │ + getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ + return this.mapObject.getBoundsZoomLevel(moBounds); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Primitives * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ + │ │ │ │ + │ │ │ │ + // LonLat │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectLonLatFromLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * lon - {Float} │ │ │ │ + * lat - {Float} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject LonLat built from lon and lat params │ │ │ │ + */ │ │ │ │ + getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ + var gLatLng; │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + var lonlat = this.inverseMercator(lon, lat); │ │ │ │ + gLatLng = new GLatLng(lonlat.lat, lonlat.lon); │ │ │ │ + } else { │ │ │ │ + gLatLng = new GLatLng(lat, lon); │ │ │ │ + } │ │ │ │ + return gLatLng; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + // Pixel │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectPixelFromXY │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * x - {Integer} │ │ │ │ + * y - {Integer} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Pixel from x and y parameters │ │ │ │ + */ │ │ │ │ + getMapObjectPixelFromXY: function(x, y) { │ │ │ │ + return new GPoint(x, y); │ │ │ │ + } │ │ │ │ + │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/MapServer.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.MapServer │ │ │ │ + * Instances of OpenLayers.Layer.MapServer are used to display │ │ │ │ + * data from a MapServer CGI instance. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.MapServer = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: DEFAULT_PARAMS │ │ │ │ + * {Object} Hashtable of default parameter key/value pairs │ │ │ │ + */ │ │ │ │ + DEFAULT_PARAMS: { │ │ │ │ + mode: "map", │ │ │ │ + map_imagetype: "png" │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.MapServer │ │ │ │ + * Create a new MapServer layer object │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} A name for the layer │ │ │ │ + * url - {String} Base url for the MapServer CGI │ │ │ │ + * (e.g. http://www2.dmsolutions.ca/cgi-bin/mapserv) │ │ │ │ + * 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 │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ + │ │ │ │ + this.params = OpenLayers.Util.applyDefaults( │ │ │ │ + this.params, this.DEFAULT_PARAMS │ │ │ │ + ); │ │ │ │ + │ │ │ │ + // unless explicitly set in options, if the layer is transparent, │ │ │ │ + // it will be an overlay │ │ │ │ + if (options == null || options.isBaseLayer == null) { │ │ │ │ + this.isBaseLayer = ((this.params.transparent != "true") && │ │ │ │ + (this.params.transparent != true)); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.MapServer>} An exact clone of this layer │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.MapServer(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; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getURL │ │ │ │ + * Return a 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); │ │ │ │ + // Make a list, so that getFullRequestString uses literal "," │ │ │ │ + var extent = [bounds.left, bounds.bottom, bounds.right, bounds.top]; │ │ │ │ + │ │ │ │ + var imageSize = this.getImageSize(); │ │ │ │ + │ │ │ │ + // make lists, so that literal ','s are used │ │ │ │ + var url = this.getFullRequestString({ │ │ │ │ + mapext: extent, │ │ │ │ + imgext: extent, │ │ │ │ + map_size: [imageSize.w, imageSize.h], │ │ │ │ + imgx: imageSize.w / 2, │ │ │ │ + imgy: imageSize.h / 2, │ │ │ │ + imgxy: [imageSize.w, imageSize.h] │ │ │ │ + }); │ │ │ │ + │ │ │ │ + return url; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getFullRequestString │ │ │ │ + * combine the layer's url with its params and these newParams. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * newParams - {Object} New parameters that should be added to the │ │ │ │ + * request string. │ │ │ │ + * altUrl - {String} (optional) Replace the URL in the full request │ │ │ │ + * string with the provided URL. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A string with the layer's url and parameters embedded in it. │ │ │ │ + */ │ │ │ │ + getFullRequestString: function(newParams, altUrl) { │ │ │ │ + // use layer's url unless altUrl passed in │ │ │ │ + var url = (altUrl == null) ? this.url : altUrl; │ │ │ │ + │ │ │ │ + // 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); │ │ │ │ + │ │ │ │ + // requestString always starts with url │ │ │ │ + var requestString = url; │ │ │ │ + │ │ │ │ + // MapServer needs '+' seperating things like bounds/height/width. │ │ │ │ + // Since typically this is URL encoded, we use a slight hack: we │ │ │ │ + // depend on the list-like functionality of getParameterString to │ │ │ │ + // leave ',' only in the case of list items (since otherwise it is │ │ │ │ + // encoded) then do a regular expression replace on the , characters │ │ │ │ + // to '+' │ │ │ │ + // │ │ │ │ + paramsString = paramsString.replace(/,/g, "+"); │ │ │ │ + │ │ │ │ + if (paramsString != "") { │ │ │ │ + var lastServerChar = url.charAt(url.length - 1); │ │ │ │ + if ((lastServerChar == "&") || (lastServerChar == "?")) { │ │ │ │ + requestString += paramsString; │ │ │ │ + } else { │ │ │ │ + if (url.indexOf('?') == -1) { │ │ │ │ + //serverPath has no ? -- add one │ │ │ │ + requestString += '?' + paramsString; │ │ │ │ + } else { │ │ │ │ + //serverPath contains ?, so must already have paramsString at the end │ │ │ │ + requestString += '&' + paramsString; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return requestString; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.MapServer" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/ArcXML.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/Geometry/Polygon.js │ │ │ │ + * @requires OpenLayers/Geometry/Point.js │ │ │ │ + * @requires OpenLayers/Geometry/MultiPolygon.js │ │ │ │ + * @requires OpenLayers/Geometry/LinearRing.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.ArcXML │ │ │ │ + * Read/Write ArcXML. Create a new instance with the <OpenLayers.Format.ArcXML> │ │ │ │ + * constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.ArcXML = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: fontStyleKeys │ │ │ │ + * {Array} List of keys used in font styling. │ │ │ │ + */ │ │ │ │ + fontStyleKeys: [ │ │ │ │ + 'antialiasing', 'blockout', 'font', 'fontcolor', 'fontsize', 'fontstyle', │ │ │ │ + 'glowing', 'interval', 'outline', 'printmode', 'shadow', 'transparency' │ │ │ │ + ], │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: request │ │ │ │ + * A get_image request destined for an ArcIMS server. │ │ │ │ + */ │ │ │ │ + request: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: response │ │ │ │ + * A parsed response from an ArcIMS server. │ │ │ │ + */ │ │ │ │ + response: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.ArcXML │ │ │ │ + * Create a new parser/writer for ArcXML. Create an instance of this class │ │ │ │ + * to begin authoring a request to an ArcIMS service. This is used │ │ │ │ + * primarily by the ArcIMS layer, but could be used to do other wild │ │ │ │ + * stuff, like geocoding. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + initialize: function(options) { │ │ │ │ + this.request = new OpenLayers.Format.ArcXML.Request(); │ │ │ │ + this.response = new OpenLayers.Format.ArcXML.Response(); │ │ │ │ + │ │ │ │ + if (options) { │ │ │ │ + if (options.requesttype == "feature") { │ │ │ │ + this.request.get_image = null; │ │ │ │ + │ │ │ │ + var qry = this.request.get_feature.query; │ │ │ │ + this.addCoordSys(qry.featurecoordsys, options.featureCoordSys); │ │ │ │ + this.addCoordSys(qry.filtercoordsys, options.filterCoordSys); │ │ │ │ + │ │ │ │ + if (options.polygon) { │ │ │ │ + qry.isspatial = true; │ │ │ │ + qry.spatialfilter.polygon = options.polygon; │ │ │ │ + } else if (options.envelope) { │ │ │ │ + qry.isspatial = true; │ │ │ │ + qry.spatialfilter.envelope = { │ │ │ │ + minx: 0, │ │ │ │ + miny: 0, │ │ │ │ + maxx: 0, │ │ │ │ + maxy: 0 │ │ │ │ + }; │ │ │ │ + this.parseEnvelope(qry.spatialfilter.envelope, options.envelope); │ │ │ │ + } │ │ │ │ + } else if (options.requesttype == "image") { │ │ │ │ + this.request.get_feature = null; │ │ │ │ + │ │ │ │ + var props = this.request.get_image.properties; │ │ │ │ + this.parseEnvelope(props.envelope, options.envelope); │ │ │ │ + │ │ │ │ + this.addLayers(props.layerlist, options.layers); │ │ │ │ + this.addImageSize(props.imagesize, options.tileSize); │ │ │ │ + this.addCoordSys(props.featurecoordsys, options.featureCoordSys); │ │ │ │ + this.addCoordSys(props.filtercoordsys, options.filterCoordSys); │ │ │ │ + } else { │ │ │ │ + // if an arcxml object is being created with no request type, it is │ │ │ │ + // probably going to consume a response, so do not throw an error if │ │ │ │ + // the requesttype is not defined │ │ │ │ + this.request = null; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseEnvelope │ │ │ │ + * Parse an array of coordinates into an ArcXML envelope structure. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * env - {Object} An envelope object that will contain the parsed coordinates. │ │ │ │ + * arr - {Array(double)} An array of coordinates in the order: [ minx, miny, maxx, maxy ] │ │ │ │ + */ │ │ │ │ + parseEnvelope: function(env, arr) { │ │ │ │ + if (arr && arr.length == 4) { │ │ │ │ + env.minx = arr[0]; │ │ │ │ + env.miny = arr[1]; │ │ │ │ + env.maxx = arr[2]; │ │ │ │ + env.maxy = arr[3]; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: addLayers │ │ │ │ + * Add a collection of layers to another collection of layers. Each layer in the list is tuple of │ │ │ │ + * { id, visible }. These layer collections represent the │ │ │ │ + * /ARCXML/REQUEST/get_image/PROPERTIES/LAYERLIST/LAYERDEF items in ArcXML │ │ │ │ + * │ │ │ │ + * TODO: Add support for dynamic layer rendering. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * ll - {Array({id,visible})} A list of layer definitions. │ │ │ │ + * lyrs - {Array({id,visible})} A list of layer definitions. │ │ │ │ + */ │ │ │ │ + addLayers: function(ll, lyrs) { │ │ │ │ + for (var lind = 0, len = lyrs.length; lind < len; lind++) { │ │ │ │ + ll.push(lyrs[lind]); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: addImageSize │ │ │ │ + * Set the size of the requested image. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * imsize - {Object} An ArcXML imagesize object. │ │ │ │ + * olsize - {<OpenLayers.Size>} The image size to set. │ │ │ │ + */ │ │ │ │ + addImageSize: function(imsize, olsize) { │ │ │ │ + if (olsize !== null) { │ │ │ │ + imsize.width = olsize.w; │ │ │ │ + imsize.height = olsize.h; │ │ │ │ + imsize.printwidth = olsize.w; │ │ │ │ + imsize.printheight = olsize.h; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: addCoordSys │ │ │ │ + * Add the coordinate system information to an object. The object may be │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * featOrFilt - {Object} A featurecoordsys or filtercoordsys ArcXML structure. │ │ │ │ + * fsys - {String} or {<OpenLayers.Projection>} or {filtercoordsys} or │ │ │ │ + * {featurecoordsys} A projection representation. If it's a {String}, │ │ │ │ + * the value is assumed to be the SRID. If it's a {OpenLayers.Projection} │ │ │ │ + * AND Proj4js is available, the projection number and name are extracted │ │ │ │ + * from there. If it's a filter or feature ArcXML structure, it is copied. │ │ │ │ + */ │ │ │ │ + addCoordSys: function(featOrFilt, fsys) { │ │ │ │ + if (typeof fsys == "string") { │ │ │ │ + featOrFilt.id = parseInt(fsys); │ │ │ │ + featOrFilt.string = fsys; │ │ │ │ + } │ │ │ │ + // is this a proj4js instance? │ │ │ │ + else if (typeof fsys == "object" && fsys.proj !== null) { │ │ │ │ + featOrFilt.id = fsys.proj.srsProjNumber; │ │ │ │ + featOrFilt.string = fsys.proj.srsCode; │ │ │ │ + } else { │ │ │ │ + featOrFilt = fsys; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: iserror │ │ │ │ + * Check to see if the response from the server was an error. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. If nothing is supplied, │ │ │ │ + * the current response is examined. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} true if the response was an error. │ │ │ │ + */ │ │ │ │ + iserror: function(data) { │ │ │ │ + var ret = null; │ │ │ │ + │ │ │ │ + if (!data) { │ │ │ │ + ret = (this.response.error !== ''); │ │ │ │ + } else { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ + var errorNodes = data.documentElement.getElementsByTagName("ERROR"); │ │ │ │ + ret = (errorNodes !== null && errorNodes.length > 0); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return ret; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read data from a string, and return an response. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Format.ArcXML.Response>} An ArcXML response. Note that this response │ │ │ │ + * data may change in the future. │ │ │ │ + */ │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var arcNode = null; │ │ │ │ + if (data && data.documentElement) { │ │ │ │ + if (data.documentElement.nodeName == "ARCXML") { │ │ │ │ + arcNode = data.documentElement; │ │ │ │ + } else { │ │ │ │ + arcNode = data.documentElement.getElementsByTagName("ARCXML")[0]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // in Safari, arcNode will be there but will have a child named │ │ │ │ + // parsererror │ │ │ │ + if (!arcNode || arcNode.firstChild.nodeName === 'parsererror') { │ │ │ │ + var error, source; │ │ │ │ + try { │ │ │ │ + error = data.firstChild.nodeValue; │ │ │ │ + source = data.firstChild.childNodes[1].firstChild.nodeValue; │ │ │ │ + } catch (err) { │ │ │ │ + // pass │ │ │ │ + } │ │ │ │ + throw { │ │ │ │ + message: "Error parsing the ArcXML request", │ │ │ │ + error: error, │ │ │ │ + source: source │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var response = this.parseResponse(arcNode); │ │ │ │ + return response; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: write │ │ │ │ + * Generate an ArcXml document string for sending to an ArcIMS server. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A string representing the ArcXML document request. │ │ │ │ + */ │ │ │ │ + write: function(request) { │ │ │ │ + if (!request) { │ │ │ │ + request = this.request; │ │ │ │ + } │ │ │ │ + var root = this.createElementNS("", "ARCXML"); │ │ │ │ + root.setAttribute("version", "1.1"); │ │ │ │ + │ │ │ │ + var reqElem = this.createElementNS("", "REQUEST"); │ │ │ │ + │ │ │ │ + if (request.get_image != null) { │ │ │ │ + var getElem = this.createElementNS("", "GET_IMAGE"); │ │ │ │ + reqElem.appendChild(getElem); │ │ │ │ + │ │ │ │ + var propElem = this.createElementNS("", "PROPERTIES"); │ │ │ │ + getElem.appendChild(propElem); │ │ │ │ + │ │ │ │ + var props = request.get_image.properties; │ │ │ │ + if (props.featurecoordsys != null) { │ │ │ │ + var feat = this.createElementNS("", "FEATURECOORDSYS"); │ │ │ │ + propElem.appendChild(feat); │ │ │ │ + │ │ │ │ + if (props.featurecoordsys.id === 0) { │ │ │ │ + feat.setAttribute("string", props.featurecoordsys['string']); │ │ │ │ + } else { │ │ │ │ + feat.setAttribute("id", props.featurecoordsys.id); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (props.filtercoordsys != null) { │ │ │ │ + var filt = this.createElementNS("", "FILTERCOORDSYS"); │ │ │ │ + propElem.appendChild(filt); │ │ │ │ + │ │ │ │ + if (props.filtercoordsys.id === 0) { │ │ │ │ + filt.setAttribute("string", props.filtercoordsys.string); │ │ │ │ + } else { │ │ │ │ + filt.setAttribute("id", props.filtercoordsys.id); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (props.envelope != null) { │ │ │ │ + var env = this.createElementNS("", "ENVELOPE"); │ │ │ │ + propElem.appendChild(env); │ │ │ │ + │ │ │ │ + env.setAttribute("minx", props.envelope.minx); │ │ │ │ + env.setAttribute("miny", props.envelope.miny); │ │ │ │ + env.setAttribute("maxx", props.envelope.maxx); │ │ │ │ + env.setAttribute("maxy", props.envelope.maxy); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var imagesz = this.createElementNS("", "IMAGESIZE"); │ │ │ │ + propElem.appendChild(imagesz); │ │ │ │ + │ │ │ │ + imagesz.setAttribute("height", props.imagesize.height); │ │ │ │ + imagesz.setAttribute("width", props.imagesize.width); │ │ │ │ + │ │ │ │ + if (props.imagesize.height != props.imagesize.printheight || │ │ │ │ + props.imagesize.width != props.imagesize.printwidth) { │ │ │ │ + imagesz.setAttribute("printheight", props.imagesize.printheight); │ │ │ │ + imagesz.setArrtibute("printwidth", props.imagesize.printwidth); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (props.background != null) { │ │ │ │ + var backgrnd = this.createElementNS("", "BACKGROUND"); │ │ │ │ + propElem.appendChild(backgrnd); │ │ │ │ + │ │ │ │ + backgrnd.setAttribute("color", │ │ │ │ + props.background.color.r + "," + │ │ │ │ + props.background.color.g + "," + │ │ │ │ + props.background.color.b); │ │ │ │ + │ │ │ │ + if (props.background.transcolor !== null) { │ │ │ │ + backgrnd.setAttribute("transcolor", │ │ │ │ + props.background.transcolor.r + "," + │ │ │ │ + props.background.transcolor.g + "," + │ │ │ │ + props.background.transcolor.b); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (props.layerlist != null && props.layerlist.length > 0) { │ │ │ │ + var layerlst = this.createElementNS("", "LAYERLIST"); │ │ │ │ + propElem.appendChild(layerlst); │ │ │ │ + │ │ │ │ + for (var ld = 0; ld < props.layerlist.length; ld++) { │ │ │ │ + var ldef = this.createElementNS("", "LAYERDEF"); │ │ │ │ + layerlst.appendChild(ldef); │ │ │ │ + │ │ │ │ + ldef.setAttribute("id", props.layerlist[ld].id); │ │ │ │ + ldef.setAttribute("visible", props.layerlist[ld].visible); │ │ │ │ + │ │ │ │ + if (typeof props.layerlist[ld].query == "object") { │ │ │ │ + var query = props.layerlist[ld].query; │ │ │ │ + │ │ │ │ + if (query.where.length < 0) { │ │ │ │ + continue; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var queryElem = null; │ │ │ │ + if (typeof query.spatialfilter == "boolean" && query.spatialfilter) { │ │ │ │ + // handle spatial filter madness │ │ │ │ + queryElem = this.createElementNS("", "SPATIALQUERY"); │ │ │ │ + } else { │ │ │ │ + queryElem = this.createElementNS("", "QUERY"); │ │ │ │ + } │ │ │ │ + │ │ │ │ + queryElem.setAttribute("where", query.where); │ │ │ │ + │ │ │ │ + if (typeof query.accuracy == "number" && query.accuracy > 0) { │ │ │ │ + queryElem.setAttribute("accuracy", query.accuracy); │ │ │ │ + } │ │ │ │ + if (typeof query.featurelimit == "number" && query.featurelimit < 2000) { │ │ │ │ + queryElem.setAttribute("featurelimit", query.featurelimit); │ │ │ │ + } │ │ │ │ + if (typeof query.subfields == "string" && query.subfields != "#ALL#") { │ │ │ │ + queryElem.setAttribute("subfields", query.subfields); │ │ │ │ + } │ │ │ │ + if (typeof query.joinexpression == "string" && query.joinexpression.length > 0) { │ │ │ │ + queryElem.setAttribute("joinexpression", query.joinexpression); │ │ │ │ + } │ │ │ │ + if (typeof query.jointables == "string" && query.jointables.length > 0) { │ │ │ │ + queryElem.setAttribute("jointables", query.jointables); │ │ │ │ + } │ │ │ │ + │ │ │ │ + ldef.appendChild(queryElem); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (typeof props.layerlist[ld].renderer == "object") { │ │ │ │ + this.addRenderer(ldef, props.layerlist[ld].renderer); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else if (request.get_feature != null) { │ │ │ │ + var getElem = this.createElementNS("", "GET_FEATURES"); │ │ │ │ + getElem.setAttribute("outputmode", "newxml"); │ │ │ │ + getElem.setAttribute("checkesc", "true"); │ │ │ │ + │ │ │ │ + if (request.get_feature.geometry) { │ │ │ │ + getElem.setAttribute("geometry", request.get_feature.geometry); │ │ │ │ + } else { │ │ │ │ + getElem.setAttribute("geometry", "false"); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (request.get_feature.compact) { │ │ │ │ + getElem.setAttribute("compact", request.get_feature.compact); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (request.get_feature.featurelimit == "number") { │ │ │ │ + getElem.setAttribute("featurelimit", request.get_feature.featurelimit); │ │ │ │ + } │ │ │ │ + │ │ │ │ + getElem.setAttribute("globalenvelope", "true"); │ │ │ │ + reqElem.appendChild(getElem); │ │ │ │ + │ │ │ │ + if (request.get_feature.layer != null && request.get_feature.layer.length > 0) { │ │ │ │ + var lyrElem = this.createElementNS("", "LAYER"); │ │ │ │ + lyrElem.setAttribute("id", request.get_feature.layer); │ │ │ │ + getElem.appendChild(lyrElem); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var fquery = request.get_feature.query; │ │ │ │ + if (fquery != null) { │ │ │ │ + var qElem = null; │ │ │ │ + if (fquery.isspatial) { │ │ │ │ + qElem = this.createElementNS("", "SPATIALQUERY"); │ │ │ │ + } else { │ │ │ │ + qElem = this.createElementNS("", "QUERY"); │ │ │ │ + } │ │ │ │ + getElem.appendChild(qElem); │ │ │ │ + │ │ │ │ + if (typeof fquery.accuracy == "number") { │ │ │ │ + qElem.setAttribute("accuracy", fquery.accuracy); │ │ │ │ + } │ │ │ │ + //qElem.setAttribute("featurelimit", "5"); │ │ │ │ + │ │ │ │ + if (fquery.featurecoordsys != null) { │ │ │ │ + var fcsElem1 = this.createElementNS("", "FEATURECOORDSYS"); │ │ │ │ + │ │ │ │ + if (fquery.featurecoordsys.id == 0) { │ │ │ │ + fcsElem1.setAttribute("string", fquery.featurecoordsys.string); │ │ │ │ + } else { │ │ │ │ + fcsElem1.setAttribute("id", fquery.featurecoordsys.id); │ │ │ │ + } │ │ │ │ + qElem.appendChild(fcsElem1); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (fquery.filtercoordsys != null) { │ │ │ │ + var fcsElem2 = this.createElementNS("", "FILTERCOORDSYS"); │ │ │ │ + │ │ │ │ + if (fquery.filtercoordsys.id === 0) { │ │ │ │ + fcsElem2.setAttribute("string", fquery.filtercoordsys.string); │ │ │ │ + } else { │ │ │ │ + fcsElem2.setAttribute("id", fquery.filtercoordsys.id); │ │ │ │ + } │ │ │ │ + qElem.appendChild(fcsElem2); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (fquery.buffer > 0) { │ │ │ │ + var bufElem = this.createElementNS("", "BUFFER"); │ │ │ │ + bufElem.setAttribute("distance", fquery.buffer); │ │ │ │ + qElem.appendChild(bufElem); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (fquery.isspatial) { │ │ │ │ + var spfElem = this.createElementNS("", "SPATIALFILTER"); │ │ │ │ + spfElem.setAttribute("relation", fquery.spatialfilter.relation); │ │ │ │ + qElem.appendChild(spfElem); │ │ │ │ + │ │ │ │ + if (fquery.spatialfilter.envelope) { │ │ │ │ + var envElem = this.createElementNS("", "ENVELOPE"); │ │ │ │ + envElem.setAttribute("minx", fquery.spatialfilter.envelope.minx); │ │ │ │ + envElem.setAttribute("miny", fquery.spatialfilter.envelope.miny); │ │ │ │ + envElem.setAttribute("maxx", fquery.spatialfilter.envelope.maxx); │ │ │ │ + envElem.setAttribute("maxy", fquery.spatialfilter.envelope.maxy); │ │ │ │ + spfElem.appendChild(envElem); │ │ │ │ + } else if (typeof fquery.spatialfilter.polygon == "object") { │ │ │ │ + spfElem.appendChild(this.writePolygonGeometry(fquery.spatialfilter.polygon)); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (fquery.where != null && fquery.where.length > 0) { │ │ │ │ + qElem.setAttribute("where", fquery.where); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + root.appendChild(reqElem); │ │ │ │ + │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [root]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + addGroupRenderer: function(ldef, toprenderer) { │ │ │ │ + var topRelem = this.createElementNS("", "GROUPRENDERER"); │ │ │ │ + ldef.appendChild(topRelem); │ │ │ │ + │ │ │ │ + for (var rind = 0; rind < toprenderer.length; rind++) { │ │ │ │ + var renderer = toprenderer[rind]; │ │ │ │ + this.addRenderer(topRelem, renderer); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + addRenderer: function(topRelem, renderer) { │ │ │ │ + if (OpenLayers.Util.isArray(renderer)) { │ │ │ │ + this.addGroupRenderer(topRelem, renderer); │ │ │ │ + } else { │ │ │ │ + var renderElem = this.createElementNS("", renderer.type.toUpperCase() + "RENDERER"); │ │ │ │ + topRelem.appendChild(renderElem); │ │ │ │ + │ │ │ │ + if (renderElem.tagName == "VALUEMAPRENDERER") { │ │ │ │ + this.addValueMapRenderer(renderElem, renderer); │ │ │ │ + } else if (renderElem.tagName == "VALUEMAPLABELRENDERER") { │ │ │ │ + this.addValueMapLabelRenderer(renderElem, renderer); │ │ │ │ + } else if (renderElem.tagName == "SIMPLELABELRENDERER") { │ │ │ │ + this.addSimpleLabelRenderer(renderElem, renderer); │ │ │ │ + } else if (renderElem.tagName == "SCALEDEPENDENTRENDERER") { │ │ │ │ + this.addScaleDependentRenderer(renderElem, renderer); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + addScaleDependentRenderer: function(renderElem, renderer) { │ │ │ │ + if (typeof renderer.lower == "string" || typeof renderer.lower == "number") { │ │ │ │ + renderElem.setAttribute("lower", renderer.lower); │ │ │ │ + } │ │ │ │ + if (typeof renderer.upper == "string" || typeof renderer.upper == "number") { │ │ │ │ + renderElem.setAttribute("upper", renderer.upper); │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.addRenderer(renderElem, renderer.renderer); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + addValueMapLabelRenderer: function(renderElem, renderer) { │ │ │ │ + renderElem.setAttribute("lookupfield", renderer.lookupfield); │ │ │ │ + renderElem.setAttribute("labelfield", renderer.labelfield); │ │ │ │ + │ │ │ │ + if (typeof renderer.exacts == "object") { │ │ │ │ + for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) { │ │ │ │ + var exact = renderer.exacts[ext]; │ │ │ │ + │ │ │ │ + var eelem = this.createElementNS("", "EXACT"); │ │ │ │ + │ │ │ │ + if (typeof exact.value == "string") { │ │ │ │ + eelem.setAttribute("value", exact.value); │ │ │ │ + } │ │ │ │ + if (typeof exact.label == "string") { │ │ │ │ + eelem.setAttribute("label", exact.label); │ │ │ │ + } │ │ │ │ + if (typeof exact.method == "string") { │ │ │ │ + eelem.setAttribute("method", exact.method); │ │ │ │ + } │ │ │ │ + │ │ │ │ + renderElem.appendChild(eelem); │ │ │ │ + │ │ │ │ + if (typeof exact.symbol == "object") { │ │ │ │ + var selem = null; │ │ │ │ + │ │ │ │ + if (exact.symbol.type == "text") { │ │ │ │ + selem = this.createElementNS("", "TEXTSYMBOL"); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (selem != null) { │ │ │ │ + var keys = this.fontStyleKeys; │ │ │ │ + for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ + var key = keys[i]; │ │ │ │ + if (exact.symbol[key]) { │ │ │ │ + selem.setAttribute(key, exact.symbol[key]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + eelem.appendChild(selem); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } // for each exact │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + addValueMapRenderer: function(renderElem, renderer) { │ │ │ │ + renderElem.setAttribute("lookupfield", renderer.lookupfield); │ │ │ │ + │ │ │ │ + if (typeof renderer.ranges == "object") { │ │ │ │ + for (var rng = 0, rnglen = renderer.ranges.length; rng < rnglen; rng++) { │ │ │ │ + var range = renderer.ranges[rng]; │ │ │ │ + │ │ │ │ + var relem = this.createElementNS("", "RANGE"); │ │ │ │ + relem.setAttribute("lower", range.lower); │ │ │ │ + relem.setAttribute("upper", range.upper); │ │ │ │ + │ │ │ │ + renderElem.appendChild(relem); │ │ │ │ + │ │ │ │ + if (typeof range.symbol == "object") { │ │ │ │ + var selem = null; │ │ │ │ + │ │ │ │ + if (range.symbol.type == "simplepolygon") { │ │ │ │ + selem = this.createElementNS("", "SIMPLEPOLYGONSYMBOL"); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (selem != null) { │ │ │ │ + if (typeof range.symbol.boundarycolor == "string") { │ │ │ │ + selem.setAttribute("boundarycolor", range.symbol.boundarycolor); │ │ │ │ + } │ │ │ │ + if (typeof range.symbol.fillcolor == "string") { │ │ │ │ + selem.setAttribute("fillcolor", range.symbol.fillcolor); │ │ │ │ + } │ │ │ │ + if (typeof range.symbol.filltransparency == "number") { │ │ │ │ + selem.setAttribute("filltransparency", range.symbol.filltransparency); │ │ │ │ + } │ │ │ │ + relem.appendChild(selem); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } // for each range │ │ │ │ + } else if (typeof renderer.exacts == "object") { │ │ │ │ + for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) { │ │ │ │ + var exact = renderer.exacts[ext]; │ │ │ │ + │ │ │ │ + var eelem = this.createElementNS("", "EXACT"); │ │ │ │ + if (typeof exact.value == "string") { │ │ │ │ + eelem.setAttribute("value", exact.value); │ │ │ │ + } │ │ │ │ + if (typeof exact.label == "string") { │ │ │ │ + eelem.setAttribute("label", exact.label); │ │ │ │ + } │ │ │ │ + if (typeof exact.method == "string") { │ │ │ │ + eelem.setAttribute("method", exact.method); │ │ │ │ + } │ │ │ │ + │ │ │ │ + renderElem.appendChild(eelem); │ │ │ │ + │ │ │ │ + if (typeof exact.symbol == "object") { │ │ │ │ + var selem = null; │ │ │ │ + │ │ │ │ + if (exact.symbol.type == "simplemarker") { │ │ │ │ + selem = this.createElementNS("", "SIMPLEMARKERSYMBOL"); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (selem != null) { │ │ │ │ + if (typeof exact.symbol.antialiasing == "string") { │ │ │ │ + selem.setAttribute("antialiasing", exact.symbol.antialiasing); │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.color == "string") { │ │ │ │ + selem.setAttribute("color", exact.symbol.color); │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.outline == "string") { │ │ │ │ + selem.setAttribute("outline", exact.symbol.outline); │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.overlap == "string") { │ │ │ │ + selem.setAttribute("overlap", exact.symbol.overlap); │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.shadow == "string") { │ │ │ │ + selem.setAttribute("shadow", exact.symbol.shadow); │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.transparency == "number") { │ │ │ │ + selem.setAttribute("transparency", exact.symbol.transparency); │ │ │ │ + } │ │ │ │ + //if (typeof exact.symbol.type == "string") │ │ │ │ + // selem.setAttribute("type", exact.symbol.type); │ │ │ │ + if (typeof exact.symbol.usecentroid == "string") { │ │ │ │ + selem.setAttribute("usecentroid", exact.symbol.usecentroid); │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.width == "number") { │ │ │ │ + selem.setAttribute("width", exact.symbol.width); │ │ │ │ + } │ │ │ │ + │ │ │ │ + eelem.appendChild(selem); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } // for each exact │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + addSimpleLabelRenderer: function(renderElem, renderer) { │ │ │ │ + renderElem.setAttribute("field", renderer.field); │ │ │ │ + var keys = ['featureweight', 'howmanylabels', 'labelbufferratio', │ │ │ │ + 'labelpriorities', 'labelweight', 'linelabelposition', │ │ │ │ + 'rotationalangles' │ │ │ │ + ]; │ │ │ │ + for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ + var key = keys[i]; │ │ │ │ + if (renderer[key]) { │ │ │ │ + renderElem.setAttribute(key, renderer[key]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (renderer.symbol.type == "text") { │ │ │ │ + var symbol = renderer.symbol; │ │ │ │ + var selem = this.createElementNS("", "TEXTSYMBOL"); │ │ │ │ + renderElem.appendChild(selem); │ │ │ │ + │ │ │ │ + var keys = this.fontStyleKeys; │ │ │ │ + for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ + var key = keys[i]; │ │ │ │ + if (symbol[key]) { │ │ │ │ + selem.setAttribute(key, renderer[key]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + writePolygonGeometry: function(polygon) { │ │ │ │ + if (!(polygon instanceof OpenLayers.Geometry.Polygon)) { │ │ │ │ + throw { │ │ │ │ + message: 'Cannot write polygon geometry to ArcXML with an ' + │ │ │ │ + polygon.CLASS_NAME + ' object.', │ │ │ │ + geometry: polygon │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var polyElem = this.createElementNS("", "POLYGON"); │ │ │ │ + │ │ │ │ + for (var ln = 0, lnlen = polygon.components.length; ln < lnlen; ln++) { │ │ │ │ + var ring = polygon.components[ln]; │ │ │ │ + var ringElem = this.createElementNS("", "RING"); │ │ │ │ + │ │ │ │ + for (var rn = 0, rnlen = ring.components.length; rn < rnlen; rn++) { │ │ │ │ + var point = ring.components[rn]; │ │ │ │ + var pointElem = this.createElementNS("", "POINT"); │ │ │ │ + │ │ │ │ + pointElem.setAttribute("x", point.x); │ │ │ │ + pointElem.setAttribute("y", point.y); │ │ │ │ + │ │ │ │ + ringElem.appendChild(pointElem); │ │ │ │ + } │ │ │ │ + │ │ │ │ + polyElem.appendChild(ringElem); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return polyElem; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseResponse │ │ │ │ + * Take an ArcXML response, and parse in into this object's internal properties. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} The ArcXML response, as either a string or the │ │ │ │ + * top level DOMElement of the response. │ │ │ │ + */ │ │ │ │ + parseResponse: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + var newData = new OpenLayers.Format.XML(); │ │ │ │ + data = newData.read(data); │ │ │ │ + } │ │ │ │ + var response = new OpenLayers.Format.ArcXML.Response(); │ │ │ │ + │ │ │ │ + var errorNode = data.getElementsByTagName("ERROR"); │ │ │ │ + │ │ │ │ + if (errorNode != null && errorNode.length > 0) { │ │ │ │ + response.error = this.getChildValue(errorNode, "Unknown error."); │ │ │ │ + } else { │ │ │ │ + var responseNode = data.getElementsByTagName("RESPONSE"); │ │ │ │ + │ │ │ │ + if (responseNode == null || responseNode.length == 0) { │ │ │ │ + response.error = "No RESPONSE tag found in ArcXML response."; │ │ │ │ + return response; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var rtype = responseNode[0].firstChild.nodeName; │ │ │ │ + if (rtype == "#text") { │ │ │ │ + rtype = responseNode[0].firstChild.nextSibling.nodeName; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (rtype == "IMAGE") { │ │ │ │ + var envelopeNode = data.getElementsByTagName("ENVELOPE"); │ │ │ │ + var outputNode = data.getElementsByTagName("OUTPUT"); │ │ │ │ + │ │ │ │ + if (envelopeNode == null || envelopeNode.length == 0) { │ │ │ │ + response.error = "No ENVELOPE tag found in ArcXML response."; │ │ │ │ + } else if (outputNode == null || outputNode.length == 0) { │ │ │ │ + response.error = "No OUTPUT tag found in ArcXML response."; │ │ │ │ + } else { │ │ │ │ + var envAttr = this.parseAttributes(envelopeNode[0]); │ │ │ │ + var outputAttr = this.parseAttributes(outputNode[0]); │ │ │ │ + │ │ │ │ + if (typeof outputAttr.type == "string") { │ │ │ │ + response.image = { │ │ │ │ + envelope: envAttr, │ │ │ │ + output: { │ │ │ │ + type: outputAttr.type, │ │ │ │ + data: this.getChildValue(outputNode[0]) │ │ │ │ + } │ │ │ │ + }; │ │ │ │ + } else { │ │ │ │ + response.image = { │ │ │ │ + envelope: envAttr, │ │ │ │ + output: outputAttr │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else if (rtype == "FEATURES") { │ │ │ │ + var features = responseNode[0].getElementsByTagName("FEATURES"); │ │ │ │ + │ │ │ │ + // get the feature count │ │ │ │ + var featureCount = features[0].getElementsByTagName("FEATURECOUNT"); │ │ │ │ + response.features.featurecount = featureCount[0].getAttribute("count"); │ │ │ │ + │ │ │ │ + if (response.features.featurecount > 0) { │ │ │ │ + // get the feature envelope │ │ │ │ + var envelope = features[0].getElementsByTagName("ENVELOPE"); │ │ │ │ + response.features.envelope = this.parseAttributes(envelope[0], typeof(0)); │ │ │ │ + │ │ │ │ + // get the field values per feature │ │ │ │ + var featureList = features[0].getElementsByTagName("FEATURE"); │ │ │ │ + for (var fn = 0; fn < featureList.length; fn++) { │ │ │ │ + var feature = new OpenLayers.Feature.Vector(); │ │ │ │ + var fields = featureList[fn].getElementsByTagName("FIELD"); │ │ │ │ + │ │ │ │ + for (var fdn = 0; fdn < fields.length; fdn++) { │ │ │ │ + var fieldName = fields[fdn].getAttribute("name"); │ │ │ │ + var fieldValue = fields[fdn].getAttribute("value"); │ │ │ │ + feature.attributes[fieldName] = fieldValue; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var geom = featureList[fn].getElementsByTagName("POLYGON"); │ │ │ │ + │ │ │ │ + if (geom.length > 0) { │ │ │ │ + // if there is a polygon, create an openlayers polygon, and assign │ │ │ │ + // it to the .geometry property of the feature │ │ │ │ + var ring = geom[0].getElementsByTagName("RING"); │ │ │ │ + │ │ │ │ + var polys = []; │ │ │ │ + for (var rn = 0; rn < ring.length; rn++) { │ │ │ │ + var linearRings = []; │ │ │ │ + linearRings.push(this.parsePointGeometry(ring[rn])); │ │ │ │ + │ │ │ │ + var holes = ring[rn].getElementsByTagName("HOLE"); │ │ │ │ + for (var hn = 0; hn < holes.length; hn++) { │ │ │ │ + linearRings.push(this.parsePointGeometry(holes[hn])); │ │ │ │ + } │ │ │ │ + holes = null; │ │ │ │ + polys.push(new OpenLayers.Geometry.Polygon(linearRings)); │ │ │ │ + linearRings = null; │ │ │ │ + } │ │ │ │ + ring = null; │ │ │ │ + │ │ │ │ + if (polys.length == 1) { │ │ │ │ + feature.geometry = polys[0]; │ │ │ │ + } else { │ │ │ │ + feature.geometry = new OpenLayers.Geometry.MultiPolygon(polys); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + response.features.feature.push(feature); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + response.error = "Unidentified response type."; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return response; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseAttributes │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {<DOMElement>} An element to parse attributes from. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} An attributes object, with properties set to attribute values. │ │ │ │ + */ │ │ │ │ + parseAttributes: function(node, type) { │ │ │ │ + var attributes = {}; │ │ │ │ + for (var attr = 0; attr < node.attributes.length; attr++) { │ │ │ │ + if (type == "number") { │ │ │ │ + attributes[node.attributes[attr].nodeName] = parseFloat(node.attributes[attr].nodeValue); │ │ │ │ + } else { │ │ │ │ + attributes[node.attributes[attr].nodeName] = node.attributes[attr].nodeValue; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return attributes; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parsePointGeometry │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {<DOMElement>} An element to parse <COORDS> or <POINT> arcxml data from. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Geometry.LinearRing>} A linear ring represented by the node's points. │ │ │ │ + */ │ │ │ │ + parsePointGeometry: function(node) { │ │ │ │ + var ringPoints = []; │ │ │ │ + var coords = node.getElementsByTagName("COORDS"); │ │ │ │ + │ │ │ │ + if (coords.length > 0) { │ │ │ │ + // if coords is present, it's the only coords item │ │ │ │ + var coordArr = this.getChildValue(coords[0]); │ │ │ │ + coordArr = coordArr.split(/;/); │ │ │ │ + for (var cn = 0; cn < coordArr.length; cn++) { │ │ │ │ + var coordItems = coordArr[cn].split(/ /); │ │ │ │ + ringPoints.push(new OpenLayers.Geometry.Point(coordItems[0], coordItems[1])); │ │ │ │ + } │ │ │ │ + coords = null; │ │ │ │ + } else { │ │ │ │ + var point = node.getElementsByTagName("POINT"); │ │ │ │ + if (point.length > 0) { │ │ │ │ + for (var pn = 0; pn < point.length; pn++) { │ │ │ │ + ringPoints.push( │ │ │ │ + new OpenLayers.Geometry.Point( │ │ │ │ + parseFloat(point[pn].getAttribute("x")), │ │ │ │ + parseFloat(point[pn].getAttribute("y")) │ │ │ │ + ) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + point = null; │ │ │ │ + } │ │ │ │ + │ │ │ │ + return new OpenLayers.Geometry.LinearRing(ringPoints); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.ArcXML" │ │ │ │ +}); │ │ │ │ + │ │ │ │ +OpenLayers.Format.ArcXML.Request = OpenLayers.Class({ │ │ │ │ + initialize: function(params) { │ │ │ │ + var defaults = { │ │ │ │ + get_image: { │ │ │ │ + properties: { │ │ │ │ + background: null, │ │ │ │ + /*{ │ │ │ │ + color: { r:255, g:255, b:255 }, │ │ │ │ + transcolor: null │ │ │ │ + },*/ │ │ │ │ + draw: true, │ │ │ │ + envelope: { │ │ │ │ + minx: 0, │ │ │ │ + miny: 0, │ │ │ │ + maxx: 0, │ │ │ │ + maxy: 0 │ │ │ │ + }, │ │ │ │ + featurecoordsys: { │ │ │ │ + id: 0, │ │ │ │ + string: "", │ │ │ │ + datumtransformid: 0, │ │ │ │ + datumtransformstring: "" │ │ │ │ + }, │ │ │ │ + filtercoordsys: { │ │ │ │ + id: 0, │ │ │ │ + string: "", │ │ │ │ + datumtransformid: 0, │ │ │ │ + datumtransformstring: "" │ │ │ │ + }, │ │ │ │ + imagesize: { │ │ │ │ + height: 0, │ │ │ │ + width: 0, │ │ │ │ + dpi: 96, │ │ │ │ + printheight: 0, │ │ │ │ + printwidth: 0, │ │ │ │ + scalesymbols: false │ │ │ │ + }, │ │ │ │ + layerlist: [], │ │ │ │ + /* no support for legends */ │ │ │ │ + output: { │ │ │ │ + baseurl: "", │ │ │ │ + legendbaseurl: "", │ │ │ │ + legendname: "", │ │ │ │ + legendpath: "", │ │ │ │ + legendurl: "", │ │ │ │ + name: "", │ │ │ │ + path: "", │ │ │ │ + type: "jpg", │ │ │ │ + url: "" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + get_feature: { │ │ │ │ + layer: "", │ │ │ │ + query: { │ │ │ │ + isspatial: false, │ │ │ │ + featurecoordsys: { │ │ │ │ + id: 0, │ │ │ │ + string: "", │ │ │ │ + datumtransformid: 0, │ │ │ │ + datumtransformstring: "" │ │ │ │ + }, │ │ │ │ + filtercoordsys: { │ │ │ │ + id: 0, │ │ │ │ + string: "", │ │ │ │ + datumtransformid: 0, │ │ │ │ + datumtransformstring: "" │ │ │ │ + }, │ │ │ │ + buffer: 0, │ │ │ │ + where: "", │ │ │ │ + spatialfilter: { │ │ │ │ + relation: "envelope_intersection", │ │ │ │ + envelope: null │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + environment: { │ │ │ │ + separators: { │ │ │ │ + cs: " ", │ │ │ │ + ts: ";" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + layer: [], │ │ │ │ + workspaces: [] │ │ │ │ + }; │ │ │ │ + │ │ │ │ + return OpenLayers.Util.extend(this, defaults); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.ArcXML.Request" │ │ │ │ +}); │ │ │ │ + │ │ │ │ +OpenLayers.Format.ArcXML.Response = OpenLayers.Class({ │ │ │ │ + initialize: function(params) { │ │ │ │ + var defaults = { │ │ │ │ + image: { │ │ │ │ + envelope: null, │ │ │ │ + output: '' │ │ │ │ + }, │ │ │ │ + │ │ │ │ + features: { │ │ │ │ + featurecount: 0, │ │ │ │ + envelope: null, │ │ │ │ + feature: [] │ │ │ │ + }, │ │ │ │ + │ │ │ │ + error: '' │ │ │ │ + }; │ │ │ │ + │ │ │ │ + return OpenLayers.Util.extend(this, defaults); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.ArcXML.Response" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/ArcIMS.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 │ │ │ │ + * @requires OpenLayers/Format/ArcXML.js │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.ArcIMS │ │ │ │ + * Instances of OpenLayers.Layer.ArcIMS are used to display data from ESRI ArcIMS │ │ │ │ + * Mapping Services. Create a new ArcIMS layer with the <OpenLayers.Layer.ArcIMS> │ │ │ │ + * constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.ArcIMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: DEFAULT_PARAMS │ │ │ │ + * {Object} Default query string parameters. │ │ │ │ + */ │ │ │ │ + DEFAULT_PARAMS: { │ │ │ │ + ClientVersion: "9.2", │ │ │ │ + ServiceName: '' │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: featureCoordSys │ │ │ │ + * {String} Code for feature coordinate system. Default is "4326". │ │ │ │ + */ │ │ │ │ + featureCoordSys: "4326", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: filterCoordSys │ │ │ │ + * {String} Code for filter coordinate system. Default is "4326". │ │ │ │ + */ │ │ │ │ + filterCoordSys: "4326", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: layers │ │ │ │ + * {Array} An array of objects with layer properties. │ │ │ │ + */ │ │ │ │ + layers: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: async │ │ │ │ + * {Boolean} Request images asynchronously. Default is true. │ │ │ │ + */ │ │ │ │ + async: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: name │ │ │ │ + * {String} Layer name. Default is "ArcIMS". │ │ │ │ + */ │ │ │ │ + name: "ArcIMS", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} The layer is a base layer. Default is true. │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: DEFAULT_OPTIONS │ │ │ │ + * {Object} Default layers properties. │ │ │ │ + */ │ │ │ │ + DEFAULT_OPTIONS: { │ │ │ │ + tileSize: new OpenLayers.Size(512, 512), │ │ │ │ + featureCoordSys: "4326", │ │ │ │ + filterCoordSys: "4326", │ │ │ │ + layers: null, │ │ │ │ + isBaseLayer: true, │ │ │ │ + async: true, │ │ │ │ + name: "ArcIMS" │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.ArcIMS │ │ │ │ + * Create a new ArcIMS layer object. │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * (code) │ │ │ │ + * var arcims = new OpenLayers.Layer.ArcIMS( │ │ │ │ + * "Global Sample", │ │ │ │ + * "http://sample.avencia.com/servlet/com.esri.esrimap.Esrimap", │ │ │ │ + * { │ │ │ │ + * service: "OpenLayers_Sample", │ │ │ │ + * layers: [ │ │ │ │ + * // layers to manipulate │ │ │ │ + * {id: "1", visible: true} │ │ │ │ + * ] │ │ │ │ + * } │ │ │ │ + * ); │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} A name for the layer │ │ │ │ + * url - {String} Base url for the ArcIMS server │ │ │ │ + * options - {Object} Optional object with properties to be set on the │ │ │ │ + * layer. │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, options) { │ │ │ │ + │ │ │ │ + this.tileSize = new OpenLayers.Size(512, 512); │ │ │ │ + │ │ │ │ + // parameters │ │ │ │ + this.params = OpenLayers.Util.applyDefaults({ │ │ │ │ + ServiceName: options.serviceName │ │ │ │ + }, │ │ │ │ + this.DEFAULT_PARAMS │ │ │ │ + ); │ │ │ │ + this.options = OpenLayers.Util.applyDefaults( │ │ │ │ + options, this.DEFAULT_OPTIONS │ │ │ │ + ); │ │ │ │ + │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply( │ │ │ │ + this, [name, url, this.params, options] │ │ │ │ + ); │ │ │ │ + │ │ │ │ + //layer is transparent │ │ │ │ + if (this.transparent) { │ │ │ │ + │ │ │ │ + // unless explicitly set in options, make layer an overlay │ │ │ │ + if (!this.isBaseLayer) { │ │ │ │ + this.isBaseLayer = false; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // jpegs can never be transparent, so intelligently switch the │ │ │ │ + // format, depending on the browser's capabilities │ │ │ │ + if (this.format == "image/jpeg") { │ │ │ │ + this.format = OpenLayers.Util.alphaHack() ? "image/gif" : "image/png"; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // create an empty layer list if no layers specified in the options │ │ │ │ + if (this.options.layers === null) { │ │ │ │ + this.options.layers = []; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getURL │ │ │ │ + * Return an image url this layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the │ │ │ │ + * request. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A string with the map image's url. │ │ │ │ + */ │ │ │ │ + getURL: function(bounds) { │ │ │ │ + var url = ""; │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + │ │ │ │ + // create an arcxml request to generate the image │ │ │ │ + var axlReq = new OpenLayers.Format.ArcXML( │ │ │ │ + OpenLayers.Util.extend(this.options, { │ │ │ │ + requesttype: "image", │ │ │ │ + envelope: bounds.toArray(), │ │ │ │ + tileSize: this.tileSize │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + │ │ │ │ + // create a synchronous ajax request to get an arcims image │ │ │ │ + var req = new OpenLayers.Request.POST({ │ │ │ │ + url: this.getFullRequestString(), │ │ │ │ + data: axlReq.write(), │ │ │ │ + async: false │ │ │ │ + }); │ │ │ │ + │ │ │ │ + // if the response exists │ │ │ │ + if (req != null) { │ │ │ │ + var doc = req.responseXML; │ │ │ │ + │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = req.responseText; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // create a new arcxml format to read the response │ │ │ │ + var axlResp = new OpenLayers.Format.ArcXML(); │ │ │ │ + var arcxml = axlResp.read(doc); │ │ │ │ + url = this.getUrlOrImage(arcxml.image.output); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return url; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getURLasync │ │ │ │ + * Get an image url this layer asynchronously, and execute a callback │ │ │ │ + * when the image url is generated. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the │ │ │ │ + * request. │ │ │ │ + * callback - {Function} Function to call when image url is retrieved. │ │ │ │ + * scope - {Object} The scope of the callback method. │ │ │ │ + */ │ │ │ │ + getURLasync: function(bounds, callback, scope) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + │ │ │ │ + // create an arcxml request to generate the image │ │ │ │ + var axlReq = new OpenLayers.Format.ArcXML( │ │ │ │ + OpenLayers.Util.extend(this.options, { │ │ │ │ + requesttype: "image", │ │ │ │ + envelope: bounds.toArray(), │ │ │ │ + tileSize: this.tileSize │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + │ │ │ │ + // create an asynchronous ajax request to get an arcims image │ │ │ │ + OpenLayers.Request.POST({ │ │ │ │ + url: this.getFullRequestString(), │ │ │ │ + async: true, │ │ │ │ + data: axlReq.write(), │ │ │ │ + callback: function(req) { │ │ │ │ + // process the response from ArcIMS, and call the callback function │ │ │ │ + // to set the image URL │ │ │ │ + var doc = req.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = req.responseText; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // create a new arcxml format to read the response │ │ │ │ + var axlResp = new OpenLayers.Format.ArcXML(); │ │ │ │ + var arcxml = axlResp.read(doc); │ │ │ │ + │ │ │ │ + callback.call(scope, this.getUrlOrImage(arcxml.image.output)); │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getUrlOrImage │ │ │ │ + * Extract a url or image from the ArcXML image output. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * output - {Object} The image.output property of the object returned from │ │ │ │ + * the ArcXML format read method. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A URL for an image (potentially with the data protocol). │ │ │ │ + */ │ │ │ │ + getUrlOrImage: function(output) { │ │ │ │ + var ret = ""; │ │ │ │ + if (output.url) { │ │ │ │ + // If the image response output url is a string, then the image │ │ │ │ + // data is not inline. │ │ │ │ + ret = output.url; │ │ │ │ + } else if (output.data) { │ │ │ │ + // The image data is inline and base64 encoded, create a data │ │ │ │ + // url for the image. This will only work for small images, │ │ │ │ + // due to browser url length limits. │ │ │ │ + ret = "data:image/" + output.type + │ │ │ │ + ";base64," + output.data; │ │ │ │ + } │ │ │ │ + return ret; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setLayerQuery │ │ │ │ + * Set the query definition on this layer. Query definitions are used to │ │ │ │ + * render parts of the spatial data in an image, and can be used to │ │ │ │ + * filter features or layers in the ArcIMS service. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * id - {String} The ArcIMS layer ID. │ │ │ │ + * querydef - {Object} The query definition to apply to this layer. │ │ │ │ + */ │ │ │ │ + setLayerQuery: function(id, querydef) { │ │ │ │ + // find the matching layer, if it exists │ │ │ │ + for (var lyr = 0; lyr < this.options.layers.length; lyr++) { │ │ │ │ + if (id == this.options.layers[lyr].id) { │ │ │ │ + // replace this layer definition │ │ │ │ + this.options.layers[lyr].query = querydef; │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // no layer found, create a new definition │ │ │ │ + this.options.layers.push({ │ │ │ │ + id: id, │ │ │ │ + visible: true, │ │ │ │ + query: querydef │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getFeatureInfo │ │ │ │ + * Get feature information from ArcIMS. Using the applied geometry, apply │ │ │ │ + * the options to the query (buffer, area/envelope intersection), and │ │ │ │ + * query the ArcIMS service. │ │ │ │ + * │ │ │ │ + * A note about accuracy: │ │ │ │ + * ArcIMS interprets the accuracy attribute in feature requests to be │ │ │ │ + * something like the 'modulus' operator on feature coordinates, │ │ │ │ + * applied to the database geometry of the feature. It doesn't round, │ │ │ │ + * so your feature coordinates may be up to (1 x accuracy) offset from │ │ │ │ + * the actual feature coordinates. If the accuracy of the layer is not │ │ │ │ + * specified, the accuracy will be computed to be approximately 1 │ │ │ │ + * feature coordinate per screen pixel. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.LonLat>} or {<OpenLayers.Geometry.Polygon>} The │ │ │ │ + * geometry to use when making the query. This should be a closed │ │ │ │ + * polygon for behavior approximating a free selection. │ │ │ │ + * layer - {Object} The ArcIMS layer definition. This is an anonymous object │ │ │ │ + * that looks like: │ │ │ │ + * (code) │ │ │ │ + * { │ │ │ │ + * id: "ArcXML layer ID", // the ArcXML layer ID │ │ │ │ + * query: { │ │ │ │ + * where: "STATE = 'PA'", // the where clause of the query │ │ │ │ + * accuracy: 100 // the accuracy of the returned feature │ │ │ │ + * } │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ + * options - {Object} Object with non-default properties to set on the layer. │ │ │ │ + * Supported properties are buffer, callback, scope, and any other │ │ │ │ + * properties applicable to the ArcXML format. Set the 'callback' and │ │ │ │ + * 'scope' for an object and function to recieve the parsed features │ │ │ │ + * from ArcIMS. │ │ │ │ + */ │ │ │ │ + getFeatureInfo: function(geometry, layer, options) { │ │ │ │ + // set the buffer to 1 unit (dd/m/ft?) by default │ │ │ │ + var buffer = options.buffer || 1; │ │ │ │ + // empty callback by default │ │ │ │ + var callback = options.callback || function() {}; │ │ │ │ + // default scope is window (global) │ │ │ │ + var scope = options.scope || window; │ │ │ │ + │ │ │ │ + // apply these option to the request options │ │ │ │ + var requestOptions = {}; │ │ │ │ + OpenLayers.Util.extend(requestOptions, this.options); │ │ │ │ + │ │ │ │ + // this is a feature request │ │ │ │ + requestOptions.requesttype = "feature"; │ │ │ │ + │ │ │ │ + if (geometry instanceof OpenLayers.LonLat) { │ │ │ │ + // create an envelope if the geometry is really a lon/lat │ │ │ │ + requestOptions.polygon = null; │ │ │ │ + requestOptions.envelope = [ │ │ │ │ + geometry.lon - buffer, │ │ │ │ + geometry.lat - buffer, │ │ │ │ + geometry.lon + buffer, │ │ │ │ + geometry.lat + buffer │ │ │ │ + ]; │ │ │ │ + } else if (geometry instanceof OpenLayers.Geometry.Polygon) { │ │ │ │ + // use the polygon assigned, and empty the envelope │ │ │ │ + requestOptions.envelope = null; │ │ │ │ + requestOptions.polygon = geometry; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // create an arcxml request to get feature requests │ │ │ │ + var arcxml = new OpenLayers.Format.ArcXML(requestOptions); │ │ │ │ + │ │ │ │ + // apply any get feature options to the arcxml request │ │ │ │ + OpenLayers.Util.extend(arcxml.request.get_feature, options); │ │ │ │ + │ │ │ │ + arcxml.request.get_feature.layer = layer.id; │ │ │ │ + if (typeof layer.query.accuracy == "number") { │ │ │ │ + // set the accuracy if it was specified │ │ │ │ + arcxml.request.get_feature.query.accuracy = layer.query.accuracy; │ │ │ │ + } else { │ │ │ │ + // guess that the accuracy is 1 per screen pixel │ │ │ │ + var mapCenter = this.map.getCenter(); │ │ │ │ + var viewPx = this.map.getViewPortPxFromLonLat(mapCenter); │ │ │ │ + viewPx.x++; │ │ │ │ + var mapOffCenter = this.map.getLonLatFromPixel(viewPx); │ │ │ │ + arcxml.request.get_feature.query.accuracy = mapOffCenter.lon - mapCenter.lon; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // set the get_feature query to be the same as the layer passed in │ │ │ │ + arcxml.request.get_feature.query.where = layer.query.where; │ │ │ │ + │ │ │ │ + // use area_intersection │ │ │ │ + arcxml.request.get_feature.query.spatialfilter.relation = "area_intersection"; │ │ │ │ + │ │ │ │ + // create a new asynchronous request to get the feature info │ │ │ │ + OpenLayers.Request.POST({ │ │ │ │ + url: this.getFullRequestString({ │ │ │ │ + 'CustomService': 'Query' │ │ │ │ + }), │ │ │ │ + data: arcxml.write(), │ │ │ │ + callback: function(request) { │ │ │ │ + // parse the arcxml response │ │ │ │ + var response = arcxml.parseResponse(request.responseText); │ │ │ │ + │ │ │ │ + if (!arcxml.iserror()) { │ │ │ │ + // if the arcxml is not an error, call the callback with the features parsed │ │ │ │ + callback.call(scope, response.features); │ │ │ │ + } else { │ │ │ │ + // if the arcxml is an error, return null features selected │ │ │ │ + callback.call(scope, null); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.ArcIMS>} An exact clone of this layer │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.ArcIMS(this.name, │ │ │ │ + this.url, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.ArcIMS" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/TMS.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.TMS │ │ │ │ + * Create a layer for accessing tiles from services that conform with the │ │ │ │ + * Tile Map Service Specification │ │ │ │ + * (http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification). │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * (code) │ │ │ │ + * var layer = new OpenLayers.Layer.TMS( │ │ │ │ + * "My Layer", // name for display in LayerSwitcher │ │ │ │ + * "http://tilecache.osgeo.org/wms-c/Basic.py/", // service endpoint │ │ │ │ + * {layername: "basic", type: "png"} // required properties │ │ │ │ + * ); │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.TMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: serviceVersion │ │ │ │ + * {String} Service version for tile requests. Default is "1.0.0". │ │ │ │ + */ │ │ │ │ + serviceVersion: "1.0.0", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: layername │ │ │ │ + * {String} The identifier for the <TileMap> as advertised by the service. │ │ │ │ + * For example, if the service advertises a <TileMap> with │ │ │ │ + * 'href="http://tms.osgeo.org/1.0.0/vmap0"', the <layername> property │ │ │ │ + * would be set to "vmap0". │ │ │ │ + */ │ │ │ │ + layername: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: type │ │ │ │ + * {String} The format extension corresponding to the requested tile image │ │ │ │ + * type. This is advertised in a <TileFormat> element as the │ │ │ │ + * "extension" attribute. For example, if the service advertises a │ │ │ │ + * <TileMap> with <TileFormat width="256" height="256" mime-type="image/jpeg" extension="jpg" />, │ │ │ │ + * the <type> property would be set to "jpg". │ │ │ │ + */ │ │ │ │ + type: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} Make this layer a base layer. Default is true. Set false to │ │ │ │ + * use the layer as an overlay. │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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 bottom-left │ │ │ │ + * corner of the map's <maxExtent>. Default is ``null``. │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * (code) │ │ │ │ + * var layer = new OpenLayers.Layer.TMS( │ │ │ │ + * "My Layer", │ │ │ │ + * "http://tilecache.osgeo.org/wms-c/Basic.py/", │ │ │ │ + * { │ │ │ │ + * layername: "basic", │ │ │ │ + * type: "png", │ │ │ │ + * // set if different than the bottom left of map.maxExtent │ │ │ │ + * tileOrigin: new OpenLayers.LonLat(-180, -90) │ │ │ │ + * } │ │ │ │ + * ); │ │ │ │ + * (end) │ │ │ │ + */ │ │ │ │ + tileOrigin: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.TMS │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} Title to be displayed in a <OpenLayers.Control.LayerSwitcher> │ │ │ │ + * url - {String} Service endpoint (without the version number). E.g. │ │ │ │ + * "http://tms.osgeo.org/". │ │ │ │ + * options - {Object} Additional properties to be set on the layer. The │ │ │ │ + * <layername> and <type> properties must be set here. │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, options) { │ │ │ │ + var newArguments = []; │ │ │ │ + newArguments.push(name, url, {}, options); │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * Create a complete copy of this layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {Object} Should only be provided by subclasses that call this │ │ │ │ + * method. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.TMS>} An exact clone of this <OpenLayers.Layer.TMS> │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.TMS(this.name, │ │ │ │ + this.url, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ + var y = Math.round((bounds.bottom - this.tileOrigin.lat) / (res * this.tileSize.h)); │ │ │ │ + var z = this.getServerZoom(); │ │ │ │ + var path = this.serviceVersion + "/" + this.layername + "/" + z + "/" + x + "/" + y + "." + this.type; │ │ │ │ + var url = this.url; │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(path, url); │ │ │ │ + } │ │ │ │ + return url + path; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: 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.map.maxExtent.left, │ │ │ │ + this.map.maxExtent.bottom); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.TMS" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/KaMapCache.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 │ │ │ │ + * @requires OpenLayers/Layer/KaMap.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.KaMapCache │ │ │ │ + * │ │ │ │ + * This class is designed to talk directly to a web-accessible ka-Map │ │ │ │ + * cache generated by the precache2.php script. │ │ │ │ + * │ │ │ │ + * To create a a new KaMapCache layer, you must indicate also the "i" parameter │ │ │ │ + * (that will be used to calculate the file extension), and another special │ │ │ │ + * parameter, object names "metaTileSize", with "h" (height) and "w" (width) │ │ │ │ + * properties. │ │ │ │ + * │ │ │ │ + * // Create a new kaMapCache layer. │ │ │ │ + * var kamap_base = new OpenLayers.Layer.KaMapCache( │ │ │ │ + * "Satellite", │ │ │ │ + * "http://www.example.org/web/acessible/cache", │ │ │ │ + * {g: "satellite", map: "world", i: 'png24', metaTileSize: {w: 5, h: 5} } │ │ │ │ + * ); │ │ │ │ + * │ │ │ │ + * // Create an kaMapCache overlay layer (using "isBaseLayer: false"). │ │ │ │ + * // Forces the output to be a "gif", using the "i" parameter. │ │ │ │ + * var kamap_overlay = new OpenLayers.Layer.KaMapCache( │ │ │ │ + * "Streets", │ │ │ │ + * "http://www.example.org/web/acessible/cache", │ │ │ │ + * {g: "streets", map: "world", i: "gif", metaTileSize: {w: 5, h: 5} }, │ │ │ │ + * {isBaseLayer: false} │ │ │ │ + * ); │ │ │ │ + * │ │ │ │ + * The cache URLs must look like: │ │ │ │ + * var/cache/World/50000/Group_Name/def/t-440320/l20480 │ │ │ │ + * │ │ │ │ + * This means that the cache generated via tile.php will *not* work with │ │ │ │ + * this class, and should instead use the KaMap layer. │ │ │ │ + * │ │ │ │ + * More information is available in Ticket #1518. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.KaMap> │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.KaMapCache = OpenLayers.Class(OpenLayers.Layer.KaMap, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: IMAGE_EXTENSIONS │ │ │ │ + * {Object} Simple hash map to convert format to extension. │ │ │ │ + */ │ │ │ │ + IMAGE_EXTENSIONS: { │ │ │ │ + 'jpeg': 'jpg', │ │ │ │ + 'gif': 'gif', │ │ │ │ + 'png': 'png', │ │ │ │ + 'png8': 'png', │ │ │ │ + 'png24': 'png', │ │ │ │ + 'dithered': 'png' │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: DEFAULT_FORMAT │ │ │ │ + * {Object} Simple hash map to convert format to extension. │ │ │ │ + */ │ │ │ │ + DEFAULT_FORMAT: 'jpeg', │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.KaMapCache │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} │ │ │ │ + * url - {String} │ │ │ │ + * params - {Object} Parameters to be sent to the HTTP server in the │ │ │ │ + * query string for the tile. The format can be set via the 'i' │ │ │ │ + * parameter (defaults to jpg) , and the map should be set via │ │ │ │ + * the 'map' parameter. It has been reported that ka-Map may behave │ │ │ │ + * inconsistently if your format parameter does not match the format │ │ │ │ + * parameter configured in your config.php. (See ticket #327 for more │ │ │ │ + * information.) │ │ │ │ + * options - {Object} Additional options for the layer. Any of the │ │ │ │ + * APIProperties listed on this layer, and any layer types it │ │ │ │ + * extends, can be overridden through the options parameter. │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + OpenLayers.Layer.KaMap.prototype.initialize.apply(this, arguments); │ │ │ │ + this.extension = this.IMAGE_EXTENSIONS[this.params.i.toLowerCase() || this.DEFAULT_FORMAT]; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ + var scale = Math.round((this.map.getScale() * 10000)) / 10000; │ │ │ │ + var pX = Math.round(bounds.left / mapRes); │ │ │ │ + var pY = -Math.round(bounds.top / mapRes); │ │ │ │ + │ │ │ │ + var metaX = Math.floor(pX / this.tileSize.w / this.params.metaTileSize.w) * this.tileSize.w * this.params.metaTileSize.w; │ │ │ │ + var metaY = Math.floor(pY / this.tileSize.h / this.params.metaTileSize.h) * this.tileSize.h * this.params.metaTileSize.h; │ │ │ │ + │ │ │ │ + var components = [ │ │ │ │ + "/", │ │ │ │ + this.params.map, │ │ │ │ + "/", │ │ │ │ + scale, │ │ │ │ + "/", │ │ │ │ + this.params.g.replace(/\s/g, '_'), │ │ │ │ + "/def/t", │ │ │ │ + metaY, │ │ │ │ + "/l", │ │ │ │ + metaX, │ │ │ │ + "/t", │ │ │ │ + pY, │ │ │ │ + "l", │ │ │ │ + pX, │ │ │ │ + ".", │ │ │ │ + this.extension │ │ │ │ + ]; │ │ │ │ + │ │ │ │ + var url = this.url; │ │ │ │ + │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(components.join(''), url); │ │ │ │ + } │ │ │ │ + return url + components.join(""); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.KaMapCache" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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: "© <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/Layer/Markers.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.Markers │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Markers = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} Markers layer is never a base layer. │ │ │ │ + */ │ │ │ │ + isBaseLayer: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: markers │ │ │ │ + * {Array(<OpenLayers.Marker>)} internal marker list │ │ │ │ + */ │ │ │ │ + markers: null, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: drawn │ │ │ │ + * {Boolean} internal state of drawing. This is a workaround for the fact │ │ │ │ + * that the map does not call moveTo with a zoomChanged when the map is │ │ │ │ + * first starting up. This lets us catch the case where we have *never* │ │ │ │ + * drawn the layer, and draw it even if the zoom hasn't changed. │ │ │ │ + */ │ │ │ │ + drawn: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.Markers │ │ │ │ + * Create a Markers layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} │ │ │ │ + * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ + */ │ │ │ │ + initialize: function(name, options) { │ │ │ │ + OpenLayers.Layer.prototype.initialize.apply(this, arguments); │ │ │ │ + this.markers = []; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + this.clearMarkers(); │ │ │ │ + this.markers = null; │ │ │ │ + OpenLayers.Layer.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setOpacity │ │ │ │ + * Sets the opacity for all the markers. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * opacity - {Float} │ │ │ │ + */ │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ + if (opacity != this.opacity) { │ │ │ │ + this.opacity = opacity; │ │ │ │ + for (var i = 0, len = this.markers.length; i < len; i++) { │ │ │ │ + this.markers[i].setOpacity(this.opacity); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveTo │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * zoomChanged - {Boolean} │ │ │ │ + * dragging - {Boolean} │ │ │ │ + */ │ │ │ │ + moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ + OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ + │ │ │ │ + if (zoomChanged || !this.drawn) { │ │ │ │ + for (var i = 0, len = this.markers.length; i < len; i++) { │ │ │ │ + this.drawMarker(this.markers[i]); │ │ │ │ + } │ │ │ │ + this.drawn = true; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: addMarker │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * marker - {<OpenLayers.Marker>} │ │ │ │ + */ │ │ │ │ + addMarker: function(marker) { │ │ │ │ + this.markers.push(marker); │ │ │ │ + │ │ │ │ + if (this.opacity < 1) { │ │ │ │ + marker.setOpacity(this.opacity); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.map && this.map.getExtent()) { │ │ │ │ + marker.map = this.map; │ │ │ │ + this.drawMarker(marker); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: removeMarker │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * marker - {<OpenLayers.Marker>} │ │ │ │ + */ │ │ │ │ + removeMarker: function(marker) { │ │ │ │ + if (this.markers && this.markers.length) { │ │ │ │ + OpenLayers.Util.removeItem(this.markers, marker); │ │ │ │ + marker.erase(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clearMarkers │ │ │ │ + * This method removes all markers from a layer. The markers are not │ │ │ │ + * destroyed by this function, but are removed from the list of markers. │ │ │ │ + */ │ │ │ │ + clearMarkers: function() { │ │ │ │ + if (this.markers != null) { │ │ │ │ + while (this.markers.length > 0) { │ │ │ │ + this.removeMarker(this.markers[0]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: drawMarker │ │ │ │ + * Calculate the pixel location for the marker, create it, and │ │ │ │ + * add it to the layer's div │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * marker - {<OpenLayers.Marker>} │ │ │ │ + */ │ │ │ │ + drawMarker: function(marker) { │ │ │ │ + var px = this.map.getLayerPxFromLonLat(marker.lonlat); │ │ │ │ + if (px == null) { │ │ │ │ + marker.display(false); │ │ │ │ + } else { │ │ │ │ + if (!marker.isDrawn()) { │ │ │ │ + var markerImg = marker.draw(px); │ │ │ │ + this.div.appendChild(markerImg); │ │ │ │ + } else if (marker.icon) { │ │ │ │ + marker.icon.moveTo(px); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getDataExtent │ │ │ │ + * Calculates the max extent which includes all of the markers. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} │ │ │ │ + */ │ │ │ │ + getDataExtent: function() { │ │ │ │ + var maxExtent = null; │ │ │ │ + │ │ │ │ + if (this.markers && (this.markers.length > 0)) { │ │ │ │ + var maxExtent = new OpenLayers.Bounds(); │ │ │ │ + for (var i = 0, len = this.markers.length; i < len; i++) { │ │ │ │ + var marker = this.markers[i]; │ │ │ │ + maxExtent.extend(marker.lonlat); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + return maxExtent; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Markers" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/Text.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/Feature/Vector.js │ │ │ │ + * @requires OpenLayers/Geometry/Point.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.Text │ │ │ │ + * Read Text format. Create a new instance with the <OpenLayers.Format.Text> │ │ │ │ + * constructor. This reads text which is formatted like CSV text, using │ │ │ │ + * tabs as the seperator by default. It provides parsing of data originally │ │ │ │ + * used in the MapViewerService, described on the wiki. This Format is used │ │ │ │ + * by the <OpenLayers.Layer.Text> class. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.Text = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: defaultStyle │ │ │ │ + * defaultStyle allows one to control the default styling of the features. │ │ │ │ + * It should be a symbolizer hash. By default, this is set to match the │ │ │ │ + * Layer.Text behavior, which is to use the default OpenLayers Icon. │ │ │ │ + */ │ │ │ │ + defaultStyle: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: extractStyles │ │ │ │ + * set to true to extract styles from the TSV files, using information │ │ │ │ + * from the image or icon, iconSize and iconOffset fields. This will result │ │ │ │ + * in features with a symbolizer (style) property set, using the │ │ │ │ + * default symbolizer specified in <defaultStyle>. Set to false if you │ │ │ │ + * wish to use a styleMap or OpenLayers.Style options to style your │ │ │ │ + * layer instead. │ │ │ │ + */ │ │ │ │ + extractStyles: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.Text │ │ │ │ + * Create a new parser for TSV Text. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + │ │ │ │ + if (options.extractStyles !== false) { │ │ │ │ + options.defaultStyle = { │ │ │ │ + 'externalGraphic': OpenLayers.Util.getImageLocation("marker.png"), │ │ │ │ + 'graphicWidth': 21, │ │ │ │ + 'graphicHeight': 25, │ │ │ │ + 'graphicXOffset': -10.5, │ │ │ │ + 'graphicYOffset': -12.5 │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + │ │ │ │ + OpenLayers.Format.prototype.initialize.apply(this, [options]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Return a list of features from a Tab Seperated Values text string. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * text - {String} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ + */ │ │ │ │ + read: function(text) { │ │ │ │ + var lines = text.split('\n'); │ │ │ │ + var columns; │ │ │ │ + var features = []; │ │ │ │ + // length - 1 to allow for trailing new line │ │ │ │ + for (var lcv = 0; lcv < (lines.length - 1); lcv++) { │ │ │ │ + var currLine = lines[lcv].replace(/^\s*/, '').replace(/\s*$/, ''); │ │ │ │ + │ │ │ │ + if (currLine.charAt(0) != '#') { │ │ │ │ + /* not a comment */ │ │ │ │ + │ │ │ │ + if (!columns) { │ │ │ │ + //First line is columns │ │ │ │ + columns = currLine.split('\t'); │ │ │ │ + } else { │ │ │ │ + var vals = currLine.split('\t'); │ │ │ │ + var geometry = new OpenLayers.Geometry.Point(0, 0); │ │ │ │ + var attributes = {}; │ │ │ │ + var style = this.defaultStyle ? │ │ │ │ + OpenLayers.Util.applyDefaults({}, this.defaultStyle) : │ │ │ │ + null; │ │ │ │ + var icon, iconSize, iconOffset, overflow; │ │ │ │ + var set = false; │ │ │ │ + for (var valIndex = 0; valIndex < vals.length; valIndex++) { │ │ │ │ + if (vals[valIndex]) { │ │ │ │ + if (columns[valIndex] == 'point') { │ │ │ │ + var coords = vals[valIndex].split(','); │ │ │ │ + geometry.y = parseFloat(coords[0]); │ │ │ │ + geometry.x = parseFloat(coords[1]); │ │ │ │ + set = true; │ │ │ │ + } else if (columns[valIndex] == 'lat') { │ │ │ │ + geometry.y = parseFloat(vals[valIndex]); │ │ │ │ + set = true; │ │ │ │ + } else if (columns[valIndex] == 'lon') { │ │ │ │ + geometry.x = parseFloat(vals[valIndex]); │ │ │ │ + set = true; │ │ │ │ + } else if (columns[valIndex] == 'title') │ │ │ │ + attributes['title'] = vals[valIndex]; │ │ │ │ + else if (columns[valIndex] == 'image' || │ │ │ │ + columns[valIndex] == 'icon' && style) { │ │ │ │ + style['externalGraphic'] = vals[valIndex]; │ │ │ │ + } else if (columns[valIndex] == 'iconSize' && style) { │ │ │ │ + var size = vals[valIndex].split(','); │ │ │ │ + style['graphicWidth'] = parseFloat(size[0]); │ │ │ │ + style['graphicHeight'] = parseFloat(size[1]); │ │ │ │ + } else if (columns[valIndex] == 'iconOffset' && style) { │ │ │ │ + var offset = vals[valIndex].split(','); │ │ │ │ + style['graphicXOffset'] = parseFloat(offset[0]); │ │ │ │ + style['graphicYOffset'] = parseFloat(offset[1]); │ │ │ │ + } else if (columns[valIndex] == 'description') { │ │ │ │ + attributes['description'] = vals[valIndex]; │ │ │ │ + } else if (columns[valIndex] == 'overflow') { │ │ │ │ + attributes['overflow'] = vals[valIndex]; │ │ │ │ + } else { │ │ │ │ + // For StyleMap filtering, allow additional │ │ │ │ + // columns to be stored as attributes. │ │ │ │ + attributes[columns[valIndex]] = vals[valIndex]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (set) { │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + geometry.transform(this.externalProjection, │ │ │ │ + this.internalProjection); │ │ │ │ + } │ │ │ │ + var feature = new OpenLayers.Feature.Vector(geometry, attributes, style); │ │ │ │ + features.push(feature); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return features; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.Text" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/Text.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/Markers.js │ │ │ │ + * @requires OpenLayers/Format/Text.js │ │ │ │ + * @requires OpenLayers/Request/XMLHttpRequest.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.Text │ │ │ │ + * This layer creates markers given data in a text file. The <location> │ │ │ │ + * property of the layer (specified as a property of the options argument │ │ │ │ + * in the <OpenLayers.Layer.Text> constructor) points to a tab delimited │ │ │ │ + * file with data used to create markers. │ │ │ │ + * │ │ │ │ + * The first row of the data file should be a header line with the column names │ │ │ │ + * of the data. Each column should be delimited by a tab space. The │ │ │ │ + * possible columns are: │ │ │ │ + * - *point* lat,lon of the point where a marker is to be placed │ │ │ │ + * - *lat* Latitude of the point where a marker is to be placed │ │ │ │ + * - *lon* Longitude of the point where a marker is to be placed │ │ │ │ + * - *icon* or *image* URL of marker icon to use. │ │ │ │ + * - *iconSize* Size of Icon to use. │ │ │ │ + * - *iconOffset* Where the top-left corner of the icon is to be placed │ │ │ │ + * relative to the latitude and longitude of the point. │ │ │ │ + * - *title* The text of the 'title' is placed inside an 'h2' marker │ │ │ │ + * inside a popup, which opens when the marker is clicked. │ │ │ │ + * - *description* The text of the 'description' is placed below the h2 │ │ │ │ + * in the popup. this can be plain text or HTML. │ │ │ │ + * │ │ │ │ + * Example text file: │ │ │ │ + * (code) │ │ │ │ + * lat lon title description iconSize iconOffset icon │ │ │ │ + * 10 20 title description 21,25 -10,-25 http://www.openlayers.org/dev/img/marker.png │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Markers> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Text = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: location │ │ │ │ + * {String} URL of text file. Must be specified in the "options" argument │ │ │ │ + * of the constructor. Can not be changed once passed in. │ │ │ │ + */ │ │ │ │ + location: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: features │ │ │ │ + * {Array(<OpenLayers.Feature>)} │ │ │ │ + */ │ │ │ │ + features: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: formatOptions │ │ │ │ + * {Object} Hash of options which should be passed to the format when it is │ │ │ │ + * created. Must be passed in the constructor. │ │ │ │ + */ │ │ │ │ + formatOptions: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: selectedFeature │ │ │ │ + * {<OpenLayers.Feature>} │ │ │ │ + */ │ │ │ │ + selectedFeature: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.Text │ │ │ │ + * Create a text layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} │ │ │ │ + * options - {Object} Object with properties to be set on the layer. │ │ │ │ + * Must include <location> property. │ │ │ │ + */ │ │ │ │ + initialize: function(name, options) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.initialize.apply(this, arguments); │ │ │ │ + this.features = []; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + // Warning: Layer.Markers.destroy() must be called prior to calling │ │ │ │ + // clearFeatures() here, otherwise we leak memory. Indeed, if │ │ │ │ + // Layer.Markers.destroy() is called after clearFeatures(), it won't be │ │ │ │ + // able to remove the marker image elements from the layer's div since │ │ │ │ + // the markers will have been destroyed by clearFeatures(). │ │ │ │ + OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ + this.clearFeatures(); │ │ │ │ + this.features = null; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: loadText │ │ │ │ + * Start the load of the Text data. Don't do this when we first add the layer, │ │ │ │ + * since we may not be visible at any point, and it would therefore be a waste. │ │ │ │ + */ │ │ │ │ + loadText: function() { │ │ │ │ + if (!this.loaded) { │ │ │ │ + if (this.location != null) { │ │ │ │ + │ │ │ │ + var onFail = function(e) { │ │ │ │ + this.events.triggerEvent("loadend"); │ │ │ │ + }; │ │ │ │ + │ │ │ │ + this.events.triggerEvent("loadstart"); │ │ │ │ + OpenLayers.Request.GET({ │ │ │ │ + url: this.location, │ │ │ │ + success: this.parseData, │ │ │ │ + failure: onFail, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.loaded = true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveTo │ │ │ │ + * If layer is visible and Text has not been loaded, load Text. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {Object} │ │ │ │ + * zoomChanged - {Object} │ │ │ │ + * minor - {Object} │ │ │ │ + */ │ │ │ │ + moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ + if (this.visibility && !this.loaded) { │ │ │ │ + this.loadText(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseData │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * ajaxRequest - {<OpenLayers.Request.XMLHttpRequest>} │ │ │ │ + */ │ │ │ │ + parseData: function(ajaxRequest) { │ │ │ │ + var text = ajaxRequest.responseText; │ │ │ │ + │ │ │ │ + var options = {}; │ │ │ │ + │ │ │ │ + OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ + │ │ │ │ + if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ + options.externalProjection = this.projection; │ │ │ │ + options.internalProjection = this.map.getProjectionObject(); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var parser = new OpenLayers.Format.Text(options); │ │ │ │ + var features = parser.read(text); │ │ │ │ + for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ + var data = {}; │ │ │ │ + var feature = features[i]; │ │ │ │ + var location; │ │ │ │ + var iconSize, iconOffset; │ │ │ │ + │ │ │ │ + location = new OpenLayers.LonLat(feature.geometry.x, │ │ │ │ + feature.geometry.y); │ │ │ │ + │ │ │ │ + if (feature.style.graphicWidth && │ │ │ │ + feature.style.graphicHeight) { │ │ │ │ + iconSize = new OpenLayers.Size( │ │ │ │ + feature.style.graphicWidth, │ │ │ │ + feature.style.graphicHeight); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // FIXME: At the moment, we only use this if we have an │ │ │ │ + // externalGraphic, because icon has no setOffset API Method. │ │ │ │ + /** │ │ │ │ + * FIXME FIRST!! │ │ │ │ + * The Text format does all sorts of parseFloating │ │ │ │ + * The result of a parseFloat for a bogus string is NaN. That │ │ │ │ + * means the three possible values here are undefined, NaN, or a │ │ │ │ + * number. The previous check was an identity check for null. This │ │ │ │ + * means it was failing for all undefined or NaN. A slightly better │ │ │ │ + * check is for undefined. An even better check is to see if the │ │ │ │ + * value is a number (see #1441). │ │ │ │ + */ │ │ │ │ + if (feature.style.graphicXOffset !== undefined && │ │ │ │ + feature.style.graphicYOffset !== undefined) { │ │ │ │ + iconOffset = new OpenLayers.Pixel( │ │ │ │ + feature.style.graphicXOffset, │ │ │ │ + feature.style.graphicYOffset); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (feature.style.externalGraphic != null) { │ │ │ │ + data.icon = new OpenLayers.Icon(feature.style.externalGraphic, │ │ │ │ + iconSize, │ │ │ │ + iconOffset); │ │ │ │ + } else { │ │ │ │ + data.icon = OpenLayers.Marker.defaultIcon(); │ │ │ │ + │ │ │ │ + //allows for the case where the image url is not │ │ │ │ + // specified but the size is. use a default icon │ │ │ │ + // but change the size │ │ │ │ + if (iconSize != null) { │ │ │ │ + data.icon.setSize(iconSize); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + if ((feature.attributes.title != null) && │ │ │ │ + (feature.attributes.description != null)) { │ │ │ │ + data['popupContentHTML'] = │ │ │ │ + '<h2>' + feature.attributes.title + '</h2>' + │ │ │ │ + '<p>' + feature.attributes.description + '</p>'; │ │ │ │ + } │ │ │ │ + │ │ │ │ + data['overflow'] = feature.attributes.overflow || "auto"; │ │ │ │ + │ │ │ │ + var markerFeature = new OpenLayers.Feature(this, location, data); │ │ │ │ + this.features.push(markerFeature); │ │ │ │ + var marker = markerFeature.createMarker(); │ │ │ │ + if ((feature.attributes.title != null) && │ │ │ │ + (feature.attributes.description != null)) { │ │ │ │ + marker.events.register('click', markerFeature, this.markerClick); │ │ │ │ + } │ │ │ │ + this.addMarker(marker); │ │ │ │ + } │ │ │ │ + this.events.triggerEvent("loadend"); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: markerClick │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + * │ │ │ │ + * Context: │ │ │ │ + * - {<OpenLayers.Feature>} │ │ │ │ + */ │ │ │ │ + markerClick: function(evt) { │ │ │ │ + var sameMarkerClicked = (this == this.layer.selectedFeature); │ │ │ │ + this.layer.selectedFeature = (!sameMarkerClicked) ? this : null; │ │ │ │ + for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ + this.layer.map.removePopup(this.layer.map.popups[i]); │ │ │ │ + } │ │ │ │ + if (!sameMarkerClicked) { │ │ │ │ + this.layer.map.addPopup(this.createPopup()); │ │ │ │ + } │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clearFeatures │ │ │ │ + */ │ │ │ │ + clearFeatures: function() { │ │ │ │ + if (this.features != null) { │ │ │ │ + while (this.features.length > 0) { │ │ │ │ + var feature = this.features[0]; │ │ │ │ + OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ + feature.destroy(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Text" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/MapGuide.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/Request/XMLHttpRequest.js │ │ │ │ + * @requires OpenLayers/Layer/Grid.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.MapGuide │ │ │ │ + * Instances of OpenLayers.Layer.MapGuide are used to display │ │ │ │ + * data from a MapGuide OS instance. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} Treat this layer as a base layer. Default is true. │ │ │ │ + **/ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: useHttpTile │ │ │ │ + * {Boolean} use a tile cache exposed directly via a webserver rather than the │ │ │ │ + * via mapguide server. This does require extra configuration on the Mapguide Server, │ │ │ │ + * and will only work when singleTile is false. The url for the layer must be set to the │ │ │ │ + * webserver path rather than the Mapguide mapagent. │ │ │ │ + * See http://trac.osgeo.org/mapguide/wiki/CodeSamples/Tiles/ServingTilesViaHttp │ │ │ │ + **/ │ │ │ │ + useHttpTile: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: singleTile │ │ │ │ + * {Boolean} use tile server or request single tile image. │ │ │ │ + **/ │ │ │ │ + singleTile: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: useOverlay │ │ │ │ + * {Boolean} flag to indicate if the layer should be retrieved using │ │ │ │ + * GETMAPIMAGE (default) or using GETDYNAMICOVERLAY requests. │ │ │ │ + **/ │ │ │ │ + useOverlay: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: useAsyncOverlay │ │ │ │ + * {Boolean} indicates if the MapGuide site supports the asynchronous │ │ │ │ + * GETDYNAMICOVERLAY requests which is available in MapGuide Enterprise 2010 │ │ │ │ + * and MapGuide Open Source v2.0.3 or higher. The newer versions of MG │ │ │ │ + * is called asynchronously, allows selections to be drawn separately from │ │ │ │ + * the map and offers styling options. │ │ │ │ + * │ │ │ │ + * With older versions of MapGuide, set useAsyncOverlay=false. Note that in │ │ │ │ + * this case a synchronous AJAX call is issued and the mapname and session │ │ │ │ + * parameters must be used to initialize the layer, not the mapdefinition │ │ │ │ + * parameter. Also note that this will issue a synchronous AJAX request │ │ │ │ + * before the image request can be issued so the users browser may lock │ │ │ │ + * up if the MG Web tier does not respond in a timely fashion. │ │ │ │ + **/ │ │ │ │ + useAsyncOverlay: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: TILE_PARAMS │ │ │ │ + * {Object} Hashtable of default parameter key/value pairs for tiled layer │ │ │ │ + */ │ │ │ │ + TILE_PARAMS: { │ │ │ │ + operation: 'GETTILEIMAGE', │ │ │ │ + version: '1.2.0' │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: SINGLE_TILE_PARAMS │ │ │ │ + * {Object} Hashtable of default parameter key/value pairs for untiled layer │ │ │ │ + */ │ │ │ │ + SINGLE_TILE_PARAMS: { │ │ │ │ + operation: 'GETMAPIMAGE', │ │ │ │ + format: 'PNG', │ │ │ │ + locale: 'en', │ │ │ │ + clip: '1', │ │ │ │ + version: '1.0.0' │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: OVERLAY_PARAMS │ │ │ │ + * {Object} Hashtable of default parameter key/value pairs for untiled layer │ │ │ │ + */ │ │ │ │ + OVERLAY_PARAMS: { │ │ │ │ + operation: 'GETDYNAMICMAPOVERLAYIMAGE', │ │ │ │ + format: 'PNG', │ │ │ │ + locale: 'en', │ │ │ │ + clip: '1', │ │ │ │ + version: '2.0.0' │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: FOLDER_PARAMS │ │ │ │ + * {Object} Hashtable of parameter key/value pairs which describe │ │ │ │ + * the folder structure for tiles as configured in the mapguide │ │ │ │ + * serverconfig.ini section [TileServiceProperties] │ │ │ │ + */ │ │ │ │ + FOLDER_PARAMS: { │ │ │ │ + tileColumnsPerFolder: 30, │ │ │ │ + tileRowsPerFolder: 30, │ │ │ │ + format: 'png', │ │ │ │ + querystring: null │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: defaultSize │ │ │ │ + * {<OpenLayers.Size>} Tile size as produced by MapGuide server │ │ │ │ + **/ │ │ │ │ + defaultSize: new OpenLayers.Size(300, 300), │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: tileOriginCorner │ │ │ │ + * {String} MapGuide tile server uses top-left as tile origin │ │ │ │ + **/ │ │ │ │ + tileOriginCorner: "tl", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.MapGuide │ │ │ │ + * Create a new Mapguide layer, either tiled or untiled. │ │ │ │ + * │ │ │ │ + * For tiled layers, the 'groupName' and 'mapDefinition' values │ │ │ │ + * must be specified as parameters in the constructor. │ │ │ │ + * │ │ │ │ + * For untiled base layers, specify either combination of 'mapName' and │ │ │ │ + * 'session', or 'mapDefinition' and 'locale'. │ │ │ │ + * │ │ │ │ + * For older versions of MapGuide and overlay layers, set useAsyncOverlay │ │ │ │ + * to false and in this case mapName and session are required parameters │ │ │ │ + * for the constructor. │ │ │ │ + * │ │ │ │ + * NOTE: MapGuide OS uses a DPI value and degrees to meters conversion │ │ │ │ + * factor that are different than the defaults used in OpenLayers, │ │ │ │ + * so these must be adjusted accordingly in your application. │ │ │ │ + * See the MapGuide example for how to set these values for MGOS. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} Name of the layer displayed in the interface │ │ │ │ + * url - {String} Location of the MapGuide mapagent executable │ │ │ │ + * (e.g. http://localhost:8008/mapguide/mapagent/mapagent.fcgi) │ │ │ │ + * params - {Object} hashtable of additional parameters to use. Some │ │ │ │ + * parameters may require additional code on the server. The ones that │ │ │ │ + * you may want to use are: │ │ │ │ + * - mapDefinition - {String} The MapGuide resource definition │ │ │ │ + * (e.g. Library://Samples/Gmap/Maps/gmapTiled.MapDefinition) │ │ │ │ + * - locale - Locale setting │ │ │ │ + * (for untiled overlays layers only) │ │ │ │ + * - mapName - {String} Name of the map as stored in the MapGuide session. │ │ │ │ + * (for untiled layers with a session parameter only) │ │ │ │ + * - session - { String} MapGuide session ID │ │ │ │ + * (for untiled overlays layers only) │ │ │ │ + * - basemaplayergroupname - {String} GroupName for tiled MapGuide layers only │ │ │ │ + * - format - Image format to be returned (for untiled overlay layers only) │ │ │ │ + * - showLayers - {String} A comma separated list of GUID's for the │ │ │ │ + * layers to display eg: 'cvc-xcv34,453-345-345sdf'. │ │ │ │ + * - hideLayers - {String} A comma separated list of GUID's for the │ │ │ │ + * layers to hide eg: 'cvc-xcv34,453-345-345sdf'. │ │ │ │ + * - showGroups - {String} A comma separated list of GUID's for the │ │ │ │ + * groups to display eg: 'cvc-xcv34,453-345-345sdf'. │ │ │ │ + * - hideGroups - {String} A comma separated list of GUID's for the │ │ │ │ + * groups to hide eg: 'cvc-xcv34,453-345-345sdf' │ │ │ │ + * - selectionXml - {String} A selection xml string Some server plumbing │ │ │ │ + * is required to read such a value. │ │ │ │ + * options - {Object} Hashtable of extra options to tag onto the layer; │ │ │ │ + * will vary depending if tiled or untiled maps are being requested │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ + │ │ │ │ + // unless explicitly set in options, if the layer is transparent, │ │ │ │ + // it will be an overlay │ │ │ │ + if (options == null || options.isBaseLayer == null) { │ │ │ │ + this.isBaseLayer = ((this.transparent != "true") && │ │ │ │ + (this.transparent != true)); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (options && options.useOverlay != null) { │ │ │ │ + this.useOverlay = options.useOverlay; │ │ │ │ + } │ │ │ │ + │ │ │ │ + //initialize for untiled layers │ │ │ │ + if (this.singleTile) { │ │ │ │ + if (this.useOverlay) { │ │ │ │ + OpenLayers.Util.applyDefaults( │ │ │ │ + this.params, │ │ │ │ + this.OVERLAY_PARAMS │ │ │ │ + ); │ │ │ │ + if (!this.useAsyncOverlay) { │ │ │ │ + this.params.version = "1.0.0"; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Util.applyDefaults( │ │ │ │ + this.params, │ │ │ │ + this.SINGLE_TILE_PARAMS │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + //initialize for tiled layers │ │ │ │ + if (this.useHttpTile) { │ │ │ │ + OpenLayers.Util.applyDefaults( │ │ │ │ + this.params, │ │ │ │ + this.FOLDER_PARAMS │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + OpenLayers.Util.applyDefaults( │ │ │ │ + this.params, │ │ │ │ + this.TILE_PARAMS │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + this.setTileSize(this.defaultSize); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.MapGuide>} An exact clone of this layer │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.MapGuide(this.name, │ │ │ │ + this.url, │ │ │ │ + this.params, │ │ │ │ + this.getOptions()); │ │ │ │ + } │ │ │ │ + //get all additions from superclasses │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + │ │ │ │ + return obj; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getURL │ │ │ │ + * Return a 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) { │ │ │ │ + var url; │ │ │ │ + var center = bounds.getCenterLonLat(); │ │ │ │ + var mapSize = this.map.getSize(); │ │ │ │ + │ │ │ │ + if (this.singleTile) { │ │ │ │ + //set up the call for GETMAPIMAGE or GETDYNAMICMAPOVERLAY with │ │ │ │ + //dynamic map parameters │ │ │ │ + var params = { │ │ │ │ + setdisplaydpi: OpenLayers.DOTS_PER_INCH, │ │ │ │ + setdisplayheight: mapSize.h * this.ratio, │ │ │ │ + setdisplaywidth: mapSize.w * this.ratio, │ │ │ │ + setviewcenterx: center.lon, │ │ │ │ + setviewcentery: center.lat, │ │ │ │ + setviewscale: this.map.getScale() │ │ │ │ + }; │ │ │ │ + │ │ │ │ + if (this.useOverlay && !this.useAsyncOverlay) { │ │ │ │ + //first we need to call GETVISIBLEMAPEXTENT to set the extent │ │ │ │ + var getVisParams = {}; │ │ │ │ + getVisParams = OpenLayers.Util.extend(getVisParams, params); │ │ │ │ + getVisParams.operation = "GETVISIBLEMAPEXTENT"; │ │ │ │ + getVisParams.version = "1.0.0"; │ │ │ │ + getVisParams.session = this.params.session; │ │ │ │ + getVisParams.mapName = this.params.mapName; │ │ │ │ + getVisParams.format = 'text/xml'; │ │ │ │ + url = this.getFullRequestString(getVisParams); │ │ │ │ + │ │ │ │ + OpenLayers.Request.GET({ │ │ │ │ + url: url, │ │ │ │ + async: false │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + //construct the full URL │ │ │ │ + url = this.getFullRequestString(params); │ │ │ │ + } else { │ │ │ │ + │ │ │ │ + //tiled version │ │ │ │ + var currentRes = this.map.getResolution(); │ │ │ │ + var colidx = Math.floor((bounds.left - this.maxExtent.left) / currentRes); │ │ │ │ + colidx = Math.round(colidx / this.tileSize.w); │ │ │ │ + var rowidx = Math.floor((this.maxExtent.top - bounds.top) / currentRes); │ │ │ │ + rowidx = Math.round(rowidx / this.tileSize.h); │ │ │ │ + │ │ │ │ + if (this.useHttpTile) { │ │ │ │ + url = this.getImageFilePath({ │ │ │ │ + tilecol: colidx, │ │ │ │ + tilerow: rowidx, │ │ │ │ + scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ + }); │ │ │ │ + │ │ │ │ + } else { │ │ │ │ + url = this.getFullRequestString({ │ │ │ │ + tilecol: colidx, │ │ │ │ + tilerow: rowidx, │ │ │ │ + scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return url; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getFullRequestString │ │ │ │ + * getFullRequestString on MapGuide layers is special, because we │ │ │ │ + * do a regular expression replace on ',' in parameters to '+'. │ │ │ │ + * This is why it is subclassed here. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * altUrl - {String} Alternative base URL to use. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A string with the layer's url appropriately encoded for MapGuide │ │ │ │ + */ │ │ │ │ + getFullRequestString: function(newParams, altUrl) { │ │ │ │ + // use layer's url unless altUrl passed in │ │ │ │ + var url = (altUrl == null) ? this.url : altUrl; │ │ │ │ + │ │ │ │ + // if url is not a string, it should be an array of strings, │ │ │ │ + // in which case we will randomly select one of them in order │ │ │ │ + // to evenly distribute requests to different urls. │ │ │ │ + if (typeof url == "object") { │ │ │ │ + url = url[Math.floor(Math.random() * url.length)]; │ │ │ │ + } │ │ │ │ + // requestString always starts with url │ │ │ │ + var requestString = 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); │ │ │ │ + // 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]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ + │ │ │ │ + /* MapGuide needs '+' seperating things like bounds/height/width. │ │ │ │ + Since typically this is URL encoded, we use a slight hack: we │ │ │ │ + depend on the list-like functionality of getParameterString to │ │ │ │ + leave ',' only in the case of list items (since otherwise it is │ │ │ │ + encoded) then do a regular expression replace on the , characters │ │ │ │ + to '+' */ │ │ │ │ + paramsString = paramsString.replace(/,/g, "+"); │ │ │ │ + │ │ │ │ + if (paramsString != "") { │ │ │ │ + var lastServerChar = url.charAt(url.length - 1); │ │ │ │ + if ((lastServerChar == "&") || (lastServerChar == "?")) { │ │ │ │ + requestString += paramsString; │ │ │ │ + } else { │ │ │ │ + if (url.indexOf('?') == -1) { │ │ │ │ + //serverPath has no ? -- add one │ │ │ │ + requestString += '?' + paramsString; │ │ │ │ + } else { │ │ │ │ + //serverPath contains ?, so must already have paramsString at the end │ │ │ │ + requestString += '&' + paramsString; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return requestString; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getImageFilePath │ │ │ │ + * special handler to request mapguide tiles from an http exposed tilecache │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * altUrl - {String} Alternative base URL to use. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A string with the url for the tile image │ │ │ │ + */ │ │ │ │ + getImageFilePath: function(newParams, altUrl) { │ │ │ │ + // use layer's url unless altUrl passed in │ │ │ │ + var url = (altUrl == null) ? this.url : altUrl; │ │ │ │ + │ │ │ │ + // if url is not a string, it should be an array of strings, │ │ │ │ + // in which case we will randomly select one of them in order │ │ │ │ + // to evenly distribute requests to different urls. │ │ │ │ + if (typeof url == "object") { │ │ │ │ + url = url[Math.floor(Math.random() * url.length)]; │ │ │ │ + } │ │ │ │ + // requestString always starts with url │ │ │ │ + var requestString = url; │ │ │ │ + │ │ │ │ + var tileRowGroup = ""; │ │ │ │ + var tileColGroup = ""; │ │ │ │ + │ │ │ │ + if (newParams.tilerow < 0) { │ │ │ │ + tileRowGroup = '-'; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (newParams.tilerow == 0) { │ │ │ │ + tileRowGroup += '0'; │ │ │ │ + } else { │ │ │ │ + tileRowGroup += Math.floor(Math.abs(newParams.tilerow / this.params.tileRowsPerFolder)) * this.params.tileRowsPerFolder; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (newParams.tilecol < 0) { │ │ │ │ + tileColGroup = '-'; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (newParams.tilecol == 0) { │ │ │ │ + tileColGroup += '0'; │ │ │ │ + } else { │ │ │ │ + tileColGroup += Math.floor(Math.abs(newParams.tilecol / this.params.tileColumnsPerFolder)) * this.params.tileColumnsPerFolder; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var tilePath = '/S' + Math.floor(newParams.scaleindex) + │ │ │ │ + '/' + this.params.basemaplayergroupname + │ │ │ │ + '/R' + tileRowGroup + │ │ │ │ + '/C' + tileColGroup + │ │ │ │ + '/' + (newParams.tilerow % this.params.tileRowsPerFolder) + │ │ │ │ + '_' + (newParams.tilecol % this.params.tileColumnsPerFolder) + │ │ │ │ + '.' + this.params.format; │ │ │ │ + │ │ │ │ + if (this.params.querystring) { │ │ │ │ + tilePath += "?" + this.params.querystring; │ │ │ │ + } │ │ │ │ + │ │ │ │ + requestString += tilePath; │ │ │ │ + return requestString; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.MapGuide" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/Zoomify.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. */ │ │ │ │ + │ │ │ │ +/* │ │ │ │ + * Development supported by a R&D grant DC08P02OUK006 - Old Maps Online │ │ │ │ + * (www.oldmapsonline.org) from Ministry of Culture of the Czech Republic. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Layer/Grid.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.Zoomify │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Zoomify = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: size │ │ │ │ + * {<OpenLayers.Size>} The Zoomify image size in pixels. │ │ │ │ + */ │ │ │ │ + size: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: standardTileSize │ │ │ │ + * {Integer} The size of a standard (non-border) square tile in pixels. │ │ │ │ + */ │ │ │ │ + standardTileSize: 256, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: tileOriginCorner │ │ │ │ + * {String} This layer uses top-left as tile origin │ │ │ │ + **/ │ │ │ │ + tileOriginCorner: "tl", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: numberOfTiers │ │ │ │ + * {Integer} Depth of the Zoomify pyramid, number of tiers (zoom levels) │ │ │ │ + * - filled during Zoomify pyramid initialization. │ │ │ │ + */ │ │ │ │ + numberOfTiers: 0, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: tileCountUpToTier │ │ │ │ + * {Array(Integer)} Number of tiles up to the given tier of pyramid. │ │ │ │ + * - filled during Zoomify pyramid initialization. │ │ │ │ + */ │ │ │ │ + tileCountUpToTier: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: tierSizeInTiles │ │ │ │ + * {Array(<OpenLayers.Size>)} Size (in tiles) for each tier of pyramid. │ │ │ │ + * - filled during Zoomify pyramid initialization. │ │ │ │ + */ │ │ │ │ + tierSizeInTiles: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: tierImageSize │ │ │ │ + * {Array(<OpenLayers.Size>)} Image size in pixels for each pyramid tier. │ │ │ │ + * - filled during Zoomify pyramid initialization. │ │ │ │ + */ │ │ │ │ + tierImageSize: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.Zoomify │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} A name for the layer. │ │ │ │ + * url - {String} - Relative or absolute path to the image or more │ │ │ │ + * precisly to the TileGroup[X] directories root. │ │ │ │ + * Flash plugin use the variable name "zoomifyImagePath" for this. │ │ │ │ + * size - {<OpenLayers.Size>} The size (in pixels) of the image. │ │ │ │ + * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, size, options) { │ │ │ │ + │ │ │ │ + // initilize the Zoomify pyramid for given size │ │ │ │ + this.initializeZoomify(size); │ │ │ │ + │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, [ │ │ │ │ + name, url, size, {}, │ │ │ │ + options │ │ │ │ + ]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: initializeZoomify │ │ │ │ + * It generates constants for all tiers of the Zoomify pyramid │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * size - {<OpenLayers.Size>} The size of the image in pixels │ │ │ │ + * │ │ │ │ + */ │ │ │ │ + initializeZoomify: function(size) { │ │ │ │ + │ │ │ │ + var imageSize = size.clone(); │ │ │ │ + this.size = size.clone(); │ │ │ │ + var tiles = new OpenLayers.Size( │ │ │ │ + Math.ceil(imageSize.w / this.standardTileSize), │ │ │ │ + Math.ceil(imageSize.h / this.standardTileSize) │ │ │ │ + ); │ │ │ │ + │ │ │ │ + this.tierSizeInTiles = [tiles]; │ │ │ │ + this.tierImageSize = [imageSize]; │ │ │ │ + │ │ │ │ + while (imageSize.w > this.standardTileSize || │ │ │ │ + imageSize.h > this.standardTileSize) { │ │ │ │ + │ │ │ │ + imageSize = new OpenLayers.Size( │ │ │ │ + Math.floor(imageSize.w / 2), │ │ │ │ + Math.floor(imageSize.h / 2) │ │ │ │ + ); │ │ │ │ + tiles = new OpenLayers.Size( │ │ │ │ + Math.ceil(imageSize.w / this.standardTileSize), │ │ │ │ + Math.ceil(imageSize.h / this.standardTileSize) │ │ │ │ + ); │ │ │ │ + this.tierSizeInTiles.push(tiles); │ │ │ │ + this.tierImageSize.push(imageSize); │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.tierSizeInTiles.reverse(); │ │ │ │ + this.tierImageSize.reverse(); │ │ │ │ + │ │ │ │ + this.numberOfTiers = this.tierSizeInTiles.length; │ │ │ │ + var resolutions = [1]; │ │ │ │ + this.tileCountUpToTier = [0]; │ │ │ │ + for (var i = 1; i < this.numberOfTiers; i++) { │ │ │ │ + resolutions.unshift(Math.pow(2, i)); │ │ │ │ + this.tileCountUpToTier.push( │ │ │ │ + this.tierSizeInTiles[i - 1].w * this.tierSizeInTiles[i - 1].h + │ │ │ │ + this.tileCountUpToTier[i - 1] │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (!this.serverResolutions) { │ │ │ │ + this.serverResolutions = resolutions; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod:destroy │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + // for now, nothing special to do here. │ │ │ │ + OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments); │ │ │ │ + │ │ │ │ + // Remove from memory the Zoomify pyramid - is that enough? │ │ │ │ + this.tileCountUpToTier.length = 0; │ │ │ │ + this.tierSizeInTiles.length = 0; │ │ │ │ + this.tierImageSize.length = 0; │ │ │ │ + │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.Zoomify>} An exact clone of this <OpenLayers.Layer.Zoomify> │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.Zoomify(this.name, │ │ │ │ + this.url, │ │ │ │ + this.size, │ │ │ │ + this.options); │ │ │ │ + } │ │ │ │ + │ │ │ │ + //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; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ + var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ + var z = this.getZoomForResolution(res); │ │ │ │ + │ │ │ │ + var tileIndex = x + y * this.tierSizeInTiles[z].w + this.tileCountUpToTier[z]; │ │ │ │ + var path = "TileGroup" + Math.floor((tileIndex) / 256) + │ │ │ │ + "/" + z + "-" + x + "-" + y + ".jpg"; │ │ │ │ + var url = this.url; │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(path, url); │ │ │ │ + } │ │ │ │ + return url + path; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getImageSize │ │ │ │ + * getImageSize returns size for a particular tile. If bounds are given as │ │ │ │ + * first argument, size is calculated (bottom-right tiles are non square). │ │ │ │ + * │ │ │ │ + */ │ │ │ │ + getImageSize: function() { │ │ │ │ + if (arguments.length > 0) { │ │ │ │ + var bounds = this.adjustBounds(arguments[0]); │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ + var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ + var z = this.getZoomForResolution(res); │ │ │ │ + var w = this.standardTileSize; │ │ │ │ + var h = this.standardTileSize; │ │ │ │ + if (x == this.tierSizeInTiles[z].w - 1) { │ │ │ │ + var w = this.tierImageSize[z].w % this.standardTileSize; │ │ │ │ + } │ │ │ │ + if (y == this.tierSizeInTiles[z].h - 1) { │ │ │ │ + var h = this.tierImageSize[z].h % this.standardTileSize; │ │ │ │ + } │ │ │ │ + return (new OpenLayers.Size(w, h)); │ │ │ │ + } else { │ │ │ │ + return this.tileSize; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ + this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left, │ │ │ │ + this.map.maxExtent.top); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Zoomify" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/TileCache.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.TileCache │ │ │ │ + * A read only TileCache layer. Used to requests tiles cached by TileCache in │ │ │ │ + * a web accessible cache. This means that you have to pre-populate your │ │ │ │ + * cache before this layer can be used. It is meant only to read tiles │ │ │ │ + * created by TileCache, and not to make calls to TileCache for tile │ │ │ │ + * creation. Create a new instance with the │ │ │ │ + * <OpenLayers.Layer.TileCache> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.TileCache = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} Treat this layer as a base layer. Default is true. │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: format │ │ │ │ + * {String} Mime type of the images returned. Default is image/png. │ │ │ │ + */ │ │ │ │ + format: 'image/png', │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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. (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.TileCache │ │ │ │ + * Create a new read only TileCache layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} Name of the layer displayed in the interface │ │ │ │ + * url - {String} Location of the web accessible cache (not the location of │ │ │ │ + * your tilecache script!) │ │ │ │ + * layername - {String} Layer name as defined in the TileCache │ │ │ │ + * configuration │ │ │ │ + * options - {Object} Optional object with properties to be set on the │ │ │ │ + * layer. Note that you should speficy your resolutions to match │ │ │ │ + * your TileCache configuration. This can be done by setting │ │ │ │ + * the resolutions array directly (here or on the map), by setting │ │ │ │ + * maxResolution and numZoomLevels, or by using scale based properties. │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, layername, options) { │ │ │ │ + this.layername = layername; │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, │ │ │ │ + [name, url, {}, options]); │ │ │ │ + this.extension = this.format.split('/')[1].toLowerCase(); │ │ │ │ + this.extension = (this.extension == 'jpg') ? 'jpeg' : this.extension; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * obj - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.TileCache>} An exact clone of this │ │ │ │ + * <OpenLayers.Layer.TileCache> │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.TileCache(this.name, │ │ │ │ + this.url, │ │ │ │ + this.layername, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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 res = this.getServerResolution(); │ │ │ │ + var bbox = this.maxExtent; │ │ │ │ + var size = this.tileSize; │ │ │ │ + var tileX = Math.round((bounds.left - bbox.left) / (res * size.w)); │ │ │ │ + var tileY = Math.round((bounds.bottom - bbox.bottom) / (res * size.h)); │ │ │ │ + var tileZ = this.serverResolutions != null ? │ │ │ │ + OpenLayers.Util.indexOf(this.serverResolutions, res) : │ │ │ │ + this.map.getZoom(); │ │ │ │ + │ │ │ │ + var components = [ │ │ │ │ + this.layername, │ │ │ │ + OpenLayers.Number.zeroPad(tileZ, 2), │ │ │ │ + OpenLayers.Number.zeroPad(parseInt(tileX / 1000000), 3), │ │ │ │ + OpenLayers.Number.zeroPad((parseInt(tileX / 1000) % 1000), 3), │ │ │ │ + OpenLayers.Number.zeroPad((parseInt(tileX) % 1000), 3), │ │ │ │ + OpenLayers.Number.zeroPad(parseInt(tileY / 1000000), 3), │ │ │ │ + OpenLayers.Number.zeroPad((parseInt(tileY / 1000) % 1000), 3), │ │ │ │ + OpenLayers.Number.zeroPad((parseInt(tileY) % 1000), 3) + '.' + this.extension │ │ │ │ + ]; │ │ │ │ + var path = components.join('/'); │ │ │ │ + var url = this.url; │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(path, url); │ │ │ │ + } │ │ │ │ + url = (url.charAt(url.length - 1) == '/') ? url : url + '/'; │ │ │ │ + return url + path; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.TileCache" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/WMTS.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.WMTS │ │ │ │ + * Instances of the WMTS class allow viewing of tiles from a service that │ │ │ │ + * implements the OGC WMTS specification version 1.0.0. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.WMTS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} The layer will be considered a base layer. Default is true. │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} WMTS version. Default is "1.0.0". │ │ │ │ + */ │ │ │ │ + version: "1.0.0", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: requestEncoding │ │ │ │ + * {String} Request encoding. Can be "REST" or "KVP". Default is "KVP". │ │ │ │ + */ │ │ │ │ + requestEncoding: "KVP", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: url │ │ │ │ + * {String|Array(String)} The base URL or request URL template for the WMTS │ │ │ │ + * service. Must be provided. Array is only supported for base URLs, not │ │ │ │ + * for request URL templates. URL templates are only supported for │ │ │ │ + * REST <requestEncoding>. │ │ │ │ + */ │ │ │ │ + url: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: layer │ │ │ │ + * {String} The layer identifier advertised by the WMTS service. Must be │ │ │ │ + * provided. │ │ │ │ + */ │ │ │ │ + layer: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: matrixSet │ │ │ │ + * {String} One of the advertised matrix set identifiers. Must be provided. │ │ │ │ + */ │ │ │ │ + matrixSet: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: style │ │ │ │ + * {String} One of the advertised layer styles. Must be provided. │ │ │ │ + */ │ │ │ │ + style: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: format │ │ │ │ + * {String} The image MIME type. Default is "image/jpeg". │ │ │ │ + */ │ │ │ │ + format: "image/jpeg", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: tileOrigin │ │ │ │ + * {<OpenLayers.LonLat>} The top-left corner of the tile matrix in map │ │ │ │ + * units. If the tile origin for each matrix in a set is different, │ │ │ │ + * the <matrixIds> should include a topLeftCorner property. If │ │ │ │ + * not provided, the tile origin will default to the top left corner │ │ │ │ + * of the layer <maxExtent>. │ │ │ │ + */ │ │ │ │ + tileOrigin: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: tileFullExtent │ │ │ │ + * {<OpenLayers.Bounds>} The full extent of the tile set. If not supplied, │ │ │ │ + * the layer's <maxExtent> property will be used. │ │ │ │ + */ │ │ │ │ + tileFullExtent: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: formatSuffix │ │ │ │ + * {String} For REST request encoding, an image format suffix must be │ │ │ │ + * included in the request. If not provided, the suffix will be derived │ │ │ │ + * from the <format> property. │ │ │ │ + */ │ │ │ │ + formatSuffix: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: matrixIds │ │ │ │ + * {Array} A list of tile matrix identifiers. If not provided, the matrix │ │ │ │ + * identifiers will be assumed to be integers corresponding to the │ │ │ │ + * map zoom level. If a list of strings is provided, each item should │ │ │ │ + * be the matrix identifier that corresponds to the map zoom level. │ │ │ │ + * Additionally, a list of objects can be provided. Each object should │ │ │ │ + * describe the matrix as presented in the WMTS capabilities. These │ │ │ │ + * objects should have the propertes shown below. │ │ │ │ + * │ │ │ │ + * Matrix properties: │ │ │ │ + * identifier - {String} The matrix identifier (required). │ │ │ │ + * scaleDenominator - {Number} The matrix scale denominator. │ │ │ │ + * topLeftCorner - {<OpenLayers.LonLat>} The top left corner of the │ │ │ │ + * matrix. Must be provided if different than the layer <tileOrigin>. │ │ │ │ + * tileWidth - {Number} The tile width for the matrix. Must be provided │ │ │ │ + * if different than the width given in the layer <tileSize>. │ │ │ │ + * tileHeight - {Number} The tile height for the matrix. Must be provided │ │ │ │ + * if different than the height given in the layer <tileSize>. │ │ │ │ + */ │ │ │ │ + matrixIds: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: dimensions │ │ │ │ + * {Array} For RESTful request encoding, extra dimensions may be specified. │ │ │ │ + * Items in this list should be property names in the <params> object. │ │ │ │ + * Values of extra dimensions will be determined from the corresponding │ │ │ │ + * values in the <params> object. │ │ │ │ + */ │ │ │ │ + dimensions: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: params │ │ │ │ + * {Object} Extra parameters to include in tile requests. For KVP │ │ │ │ + * <requestEncoding>, these properties will be encoded in the request │ │ │ │ + * query string. For REST <requestEncoding>, these properties will │ │ │ │ + * become part of the request path, with order determined by the │ │ │ │ + * <dimensions> list. │ │ │ │ + */ │ │ │ │ + params: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: zoomOffset │ │ │ │ + * {Number} If your cache has more 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). Additionally, if this layer is to be used │ │ │ │ + * as an overlay and the cache has fewer zoom levels than the base │ │ │ │ + * layer, you can supply a negative zoomOffset. For example, if a │ │ │ │ + * map zoom level of 1 corresponds to your cache level zero, you would │ │ │ │ + * supply a -1 zoomOffset (and set the maxResolution of the layer │ │ │ │ + * appropriately). The zoomOffset value has no effect if complete │ │ │ │ + * matrix definitions (including scaleDenominator) are supplied in │ │ │ │ + * the <matrixIds> property. Defaults to 0 (no zoom offset). │ │ │ │ + */ │ │ │ │ + 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, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: formatSuffixMap │ │ │ │ + * {Object} a map between WMTS 'format' request parameter and tile image file suffix │ │ │ │ + */ │ │ │ │ + formatSuffixMap: { │ │ │ │ + "image/png": "png", │ │ │ │ + "image/png8": "png", │ │ │ │ + "image/png24": "png", │ │ │ │ + "image/png32": "png", │ │ │ │ + "png": "png", │ │ │ │ + "image/jpeg": "jpg", │ │ │ │ + "image/jpg": "jpg", │ │ │ │ + "jpeg": "jpg", │ │ │ │ + "jpg": "jpg" │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: matrix │ │ │ │ + * {Object} Matrix definition for the current map resolution. Updated by │ │ │ │ + * the <updateMatrixProperties> method. │ │ │ │ + */ │ │ │ │ + matrix: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.WMTS │ │ │ │ + * Create a new WMTS layer. │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * (code) │ │ │ │ + * var wmts = new OpenLayers.Layer.WMTS({ │ │ │ │ + * name: "My WMTS Layer", │ │ │ │ + * url: "http://example.com/wmts", │ │ │ │ + * layer: "layer_id", │ │ │ │ + * style: "default", │ │ │ │ + * matrixSet: "matrix_id" │ │ │ │ + * }); │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * config - {Object} Configuration properties for the layer. │ │ │ │ + * │ │ │ │ + * Required configuration properties: │ │ │ │ + * url - {String} The base url for the service. See the <url> property. │ │ │ │ + * layer - {String} The layer identifier. See the <layer> property. │ │ │ │ + * style - {String} The layer style identifier. See the <style> property. │ │ │ │ + * matrixSet - {String} The tile matrix set identifier. See the <matrixSet> │ │ │ │ + * property. │ │ │ │ + * │ │ │ │ + * Any other documented layer properties can be provided in the config object. │ │ │ │ + */ │ │ │ │ + initialize: function(config) { │ │ │ │ + │ │ │ │ + // confirm required properties are supplied │ │ │ │ + var required = { │ │ │ │ + url: true, │ │ │ │ + layer: true, │ │ │ │ + style: true, │ │ │ │ + matrixSet: true │ │ │ │ + }; │ │ │ │ + for (var prop in required) { │ │ │ │ + if (!(prop in config)) { │ │ │ │ + throw new Error("Missing property '" + prop + "' in layer configuration."); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + config.params = OpenLayers.Util.upperCaseObject(config.params); │ │ │ │ + var args = [config.name, config.url, config.params, config]; │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, args); │ │ │ │ + │ │ │ │ + │ │ │ │ + // determine format suffix (for REST) │ │ │ │ + if (!this.formatSuffix) { │ │ │ │ + this.formatSuffix = this.formatSuffixMap[this.format] || this.format.split("/").pop(); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // expand matrixIds (may be array of string or array of object) │ │ │ │ + if (this.matrixIds) { │ │ │ │ + var len = this.matrixIds.length; │ │ │ │ + if (len && typeof this.matrixIds[0] === "string") { │ │ │ │ + var ids = this.matrixIds; │ │ │ │ + this.matrixIds = new Array(len); │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ + this.matrixIds[i] = { │ │ │ │ + identifier: ids[i] │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ + */ │ │ │ │ + setMap: function() { │ │ │ │ + OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: updateMatrixProperties │ │ │ │ + * Called when map resolution changes to update matrix related properties. │ │ │ │ + */ │ │ │ │ + updateMatrixProperties: function() { │ │ │ │ + this.matrix = this.getMatrix(); │ │ │ │ + if (this.matrix) { │ │ │ │ + if (this.matrix.topLeftCorner) { │ │ │ │ + this.tileOrigin = this.matrix.topLeftCorner; │ │ │ │ + } │ │ │ │ + if (this.matrix.tileWidth && this.matrix.tileHeight) { │ │ │ │ + this.tileSize = new OpenLayers.Size( │ │ │ │ + this.matrix.tileWidth, this.matrix.tileHeight │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (!this.tileOrigin) { │ │ │ │ + this.tileOrigin = new OpenLayers.LonLat( │ │ │ │ + this.maxExtent.left, this.maxExtent.top │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (!this.tileFullExtent) { │ │ │ │ + this.tileFullExtent = this.maxExtent; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ + if (zoomChanged || !this.matrix) { │ │ │ │ + this.updateMatrixProperties(); │ │ │ │ + } │ │ │ │ + return OpenLayers.Layer.Grid.prototype.moveTo.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.WMTS>} An exact clone of this <OpenLayers.Layer.WMTS> │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.WMTS(this.options); │ │ │ │ + } │ │ │ │ + //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; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getIdentifier │ │ │ │ + * Get the current index in the matrixIds array. │ │ │ │ + */ │ │ │ │ + getIdentifier: function() { │ │ │ │ + return this.getServerZoom(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getMatrix │ │ │ │ + * Get the appropriate matrix definition for the current map resolution. │ │ │ │ + */ │ │ │ │ + getMatrix: function() { │ │ │ │ + var matrix; │ │ │ │ + if (!this.matrixIds || this.matrixIds.length === 0) { │ │ │ │ + matrix = { │ │ │ │ + identifier: this.getIdentifier() │ │ │ │ + }; │ │ │ │ + } else { │ │ │ │ + // get appropriate matrix given the map scale if possible │ │ │ │ + if ("scaleDenominator" in this.matrixIds[0]) { │ │ │ │ + // scale denominator calculation based on WMTS spec │ │ │ │ + var denom = │ │ │ │ + OpenLayers.METERS_PER_INCH * │ │ │ │ + OpenLayers.INCHES_PER_UNIT[this.units] * │ │ │ │ + this.getServerResolution() / 0.28E-3; │ │ │ │ + var diff = Number.POSITIVE_INFINITY; │ │ │ │ + var delta; │ │ │ │ + for (var i = 0, ii = this.matrixIds.length; i < ii; ++i) { │ │ │ │ + delta = Math.abs(1 - (this.matrixIds[i].scaleDenominator / denom)); │ │ │ │ + if (delta < diff) { │ │ │ │ + diff = delta; │ │ │ │ + matrix = this.matrixIds[i]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + // fall back on zoom as index │ │ │ │ + matrix = this.matrixIds[this.getIdentifier()]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return matrix; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getTileInfo │ │ │ │ + * Get tile information for a given location at the current map resolution. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * loc - {<OpenLayers.LonLat} A location in map coordinates. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} An object with "col", "row", "i", and "j" properties. The col │ │ │ │ + * and row values are zero based tile indexes from the top left. The │ │ │ │ + * i and j values are the number of pixels to the left and top │ │ │ │ + * (respectively) of the given location within the target tile. │ │ │ │ + */ │ │ │ │ + getTileInfo: function(loc) { │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + │ │ │ │ + var fx = (loc.lon - this.tileOrigin.lon) / (res * this.tileSize.w); │ │ │ │ + var fy = (this.tileOrigin.lat - loc.lat) / (res * this.tileSize.h); │ │ │ │ + │ │ │ │ + var col = Math.floor(fx); │ │ │ │ + var row = Math.floor(fy); │ │ │ │ + │ │ │ │ + return { │ │ │ │ + col: col, │ │ │ │ + row: row, │ │ │ │ + i: Math.floor((fx - col) * this.tileSize.w), │ │ │ │ + j: Math.floor((fy - row) * this.tileSize.h) │ │ │ │ + }; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getURL │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A URL for the tile corresponding to the given bounds. │ │ │ │ + */ │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var url = ""; │ │ │ │ + if (!this.tileFullExtent || this.tileFullExtent.intersectsBounds(bounds)) { │ │ │ │ + │ │ │ │ + var center = bounds.getCenterLonLat(); │ │ │ │ + var info = this.getTileInfo(center); │ │ │ │ + var matrixId = this.matrix.identifier; │ │ │ │ + var dimensions = this.dimensions, │ │ │ │ + params; │ │ │ │ + │ │ │ │ + if (OpenLayers.Util.isArray(this.url)) { │ │ │ │ + url = this.selectUrl([ │ │ │ │ + this.version, this.style, this.matrixSet, │ │ │ │ + this.matrix.identifier, info.row, info.col │ │ │ │ + ].join(","), this.url); │ │ │ │ + } else { │ │ │ │ + url = this.url; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.requestEncoding.toUpperCase() === "REST") { │ │ │ │ + params = this.params; │ │ │ │ + if (url.indexOf("{") !== -1) { │ │ │ │ + var template = url.replace(/\{/g, "${"); │ │ │ │ + var context = { │ │ │ │ + // spec does not make clear if capital S or not │ │ │ │ + style: this.style, │ │ │ │ + Style: this.style, │ │ │ │ + TileMatrixSet: this.matrixSet, │ │ │ │ + TileMatrix: this.matrix.identifier, │ │ │ │ + TileRow: info.row, │ │ │ │ + TileCol: info.col │ │ │ │ + }; │ │ │ │ + if (dimensions) { │ │ │ │ + var dimension, i; │ │ │ │ + for (i = dimensions.length - 1; i >= 0; --i) { │ │ │ │ + dimension = dimensions[i]; │ │ │ │ + context[dimension] = params[dimension.toUpperCase()]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + url = OpenLayers.String.format(template, context); │ │ │ │ + } else { │ │ │ │ + // include 'version', 'layer' and 'style' in tile resource url │ │ │ │ + var path = this.version + "/" + this.layer + "/" + this.style + "/"; │ │ │ │ + │ │ │ │ + // append optional dimension path elements │ │ │ │ + if (dimensions) { │ │ │ │ + for (var i = 0; i < dimensions.length; i++) { │ │ │ │ + if (params[dimensions[i]]) { │ │ │ │ + path = path + params[dimensions[i]] + "/"; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // append other required path elements │ │ │ │ + path = path + this.matrixSet + "/" + this.matrix.identifier + │ │ │ │ + "/" + info.row + "/" + info.col + "." + this.formatSuffix; │ │ │ │ + │ │ │ │ + if (!url.match(/\/$/)) { │ │ │ │ + url = url + "/"; │ │ │ │ + } │ │ │ │ + url = url + path; │ │ │ │ + } │ │ │ │ + } else if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ + │ │ │ │ + // assemble all required parameters │ │ │ │ + params = { │ │ │ │ + SERVICE: "WMTS", │ │ │ │ + REQUEST: "GetTile", │ │ │ │ + VERSION: this.version, │ │ │ │ + LAYER: this.layer, │ │ │ │ + STYLE: this.style, │ │ │ │ + TILEMATRIXSET: this.matrixSet, │ │ │ │ + TILEMATRIX: this.matrix.identifier, │ │ │ │ + TILEROW: info.row, │ │ │ │ + TILECOL: info.col, │ │ │ │ + FORMAT: this.format │ │ │ │ + }; │ │ │ │ + url = OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this, [params]); │ │ │ │ + │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return url; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: mergeNewParams │ │ │ │ + * Extend the existing layer <params> with new properties. Tiles will be │ │ │ │ + * reloaded with updated params in the request. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * newParams - {Object} Properties to extend to existing <params>. │ │ │ │ + */ │ │ │ │ + mergeNewParams: function(newParams) { │ │ │ │ + if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ + return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply( │ │ │ │ + this, [OpenLayers.Util.upperCaseObject(newParams)] │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.WMTS" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/GeoRSS.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/Markers.js │ │ │ │ + * @requires OpenLayers/Request/XMLHttpRequest.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.GeoRSS │ │ │ │ + * Add GeoRSS Point features to your map. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Markers> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.GeoRSS = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: location │ │ │ │ + * {String} store url of text file │ │ │ │ + */ │ │ │ │ + location: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: features │ │ │ │ + * {Array(<OpenLayers.Feature>)} │ │ │ │ + */ │ │ │ │ + features: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: formatOptions │ │ │ │ + * {Object} Hash of options which should be passed to the format when it is │ │ │ │ + * created. Must be passed in the constructor. │ │ │ │ + */ │ │ │ │ + formatOptions: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: selectedFeature │ │ │ │ + * {<OpenLayers.Feature>} │ │ │ │ + */ │ │ │ │ + selectedFeature: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: icon │ │ │ │ + * {<OpenLayers.Icon>}. This determines the Icon to be used on the map │ │ │ │ + * for this GeoRSS layer. │ │ │ │ + */ │ │ │ │ + icon: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: popupSize │ │ │ │ + * {<OpenLayers.Size>} This determines the size of GeoRSS popups. If │ │ │ │ + * not provided, defaults to 250px by 120px. │ │ │ │ + */ │ │ │ │ + popupSize: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: useFeedTitle │ │ │ │ + * {Boolean} Set layer.name to the first <title> element in the feed. Default is true. │ │ │ │ + */ │ │ │ │ + useFeedTitle: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.GeoRSS │ │ │ │ + * Create a GeoRSS Layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} │ │ │ │ + * location - {String} │ │ │ │ + * options - {Object} │ │ │ │ + */ │ │ │ │ + initialize: function(name, location, options) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.initialize.apply(this, [name, options]); │ │ │ │ + this.location = location; │ │ │ │ + this.features = []; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + // Warning: Layer.Markers.destroy() must be called prior to calling │ │ │ │ + // clearFeatures() here, otherwise we leak memory. Indeed, if │ │ │ │ + // Layer.Markers.destroy() is called after clearFeatures(), it won't be │ │ │ │ + // able to remove the marker image elements from the layer's div since │ │ │ │ + // the markers will have been destroyed by clearFeatures(). │ │ │ │ + OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ + this.clearFeatures(); │ │ │ │ + this.features = null; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: loadRSS │ │ │ │ + * Start the load of the RSS data. Don't do this when we first add the layer, │ │ │ │ + * since we may not be visible at any point, and it would therefore be a waste. │ │ │ │ + */ │ │ │ │ + loadRSS: function() { │ │ │ │ + if (!this.loaded) { │ │ │ │ + this.events.triggerEvent("loadstart"); │ │ │ │ + OpenLayers.Request.GET({ │ │ │ │ + url: this.location, │ │ │ │ + success: this.parseData, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.loaded = true; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveTo │ │ │ │ + * If layer is visible and RSS has not been loaded, load RSS. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {Object} │ │ │ │ + * zoomChanged - {Object} │ │ │ │ + * minor - {Object} │ │ │ │ + */ │ │ │ │ + moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ + if (this.visibility && !this.loaded) { │ │ │ │ + this.loadRSS(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseData │ │ │ │ + * Parse the data returned from the Events call. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * ajaxRequest - {<OpenLayers.Request.XMLHttpRequest>} │ │ │ │ + */ │ │ │ │ + parseData: function(ajaxRequest) { │ │ │ │ + var doc = ajaxRequest.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = OpenLayers.Format.XML.prototype.read(ajaxRequest.responseText); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.useFeedTitle) { │ │ │ │ + var name = null; │ │ │ │ + try { │ │ │ │ + name = doc.getElementsByTagNameNS('*', 'title')[0].firstChild.nodeValue; │ │ │ │ + } catch (e) { │ │ │ │ + try { │ │ │ │ + name = doc.getElementsByTagName('title')[0].firstChild.nodeValue; │ │ │ │ + } catch (e) {} │ │ │ │ + } │ │ │ │ + if (name) { │ │ │ │ + this.setName(name); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + var options = {}; │ │ │ │ + │ │ │ │ + OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ + │ │ │ │ + if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ + options.externalProjection = this.projection; │ │ │ │ + options.internalProjection = this.map.getProjectionObject(); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var format = new OpenLayers.Format.GeoRSS(options); │ │ │ │ + var features = format.read(doc); │ │ │ │ + │ │ │ │ + for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ + var data = {}; │ │ │ │ + var feature = features[i]; │ │ │ │ + │ │ │ │ + // we don't support features with no geometry in the GeoRSS │ │ │ │ + // layer at this time. │ │ │ │ + if (!feature.geometry) { │ │ │ │ + continue; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var title = feature.attributes.title ? │ │ │ │ + feature.attributes.title : "Untitled"; │ │ │ │ + │ │ │ │ + var description = feature.attributes.description ? │ │ │ │ + feature.attributes.description : "No description."; │ │ │ │ + │ │ │ │ + var link = feature.attributes.link ? feature.attributes.link : ""; │ │ │ │ + │ │ │ │ + var location = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ + │ │ │ │ + │ │ │ │ + data.icon = this.icon == null ? │ │ │ │ + OpenLayers.Marker.defaultIcon() : │ │ │ │ + this.icon.clone(); │ │ │ │ + │ │ │ │ + data.popupSize = this.popupSize ? │ │ │ │ + this.popupSize.clone() : │ │ │ │ + new OpenLayers.Size(250, 120); │ │ │ │ + │ │ │ │ + if (title || description) { │ │ │ │ + // we have supplemental data, store them. │ │ │ │ + data.title = title; │ │ │ │ + data.description = description; │ │ │ │ + │ │ │ │ + var contentHTML = '<div class="olLayerGeoRSSClose">[x]</div>'; │ │ │ │ + contentHTML += '<div class="olLayerGeoRSSTitle">'; │ │ │ │ + if (link) { │ │ │ │ + contentHTML += '<a class="link" href="' + link + '" target="_blank">'; │ │ │ │ + } │ │ │ │ + contentHTML += title; │ │ │ │ + if (link) { │ │ │ │ + contentHTML += '</a>'; │ │ │ │ + } │ │ │ │ + contentHTML += '</div>'; │ │ │ │ + contentHTML += '<div style="" class="olLayerGeoRSSDescription">'; │ │ │ │ + contentHTML += description; │ │ │ │ + contentHTML += '</div>'; │ │ │ │ + data['popupContentHTML'] = contentHTML; │ │ │ │ + } │ │ │ │ + var feature = new OpenLayers.Feature(this, location, data); │ │ │ │ + this.features.push(feature); │ │ │ │ + var marker = feature.createMarker(); │ │ │ │ + marker.events.register('click', feature, this.markerClick); │ │ │ │ + this.addMarker(marker); │ │ │ │ + } │ │ │ │ + this.events.triggerEvent("loadend"); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: markerClick │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + */ │ │ │ │ + markerClick: function(evt) { │ │ │ │ + var sameMarkerClicked = (this == this.layer.selectedFeature); │ │ │ │ + this.layer.selectedFeature = (!sameMarkerClicked) ? this : null; │ │ │ │ + for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ + this.layer.map.removePopup(this.layer.map.popups[i]); │ │ │ │ + } │ │ │ │ + if (!sameMarkerClicked) { │ │ │ │ + var popup = this.createPopup(); │ │ │ │ + OpenLayers.Event.observe(popup.div, "click", │ │ │ │ + OpenLayers.Function.bind(function() { │ │ │ │ + for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ + this.layer.map.removePopup(this.layer.map.popups[i]); │ │ │ │ + } │ │ │ │ + }, this) │ │ │ │ + ); │ │ │ │ + this.layer.map.addPopup(popup); │ │ │ │ + } │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clearFeatures │ │ │ │ + * Destroy all features in this layer. │ │ │ │ + */ │ │ │ │ + clearFeatures: function() { │ │ │ │ + if (this.features != null) { │ │ │ │ + while (this.features.length > 0) { │ │ │ │ + var feature = this.features[0]; │ │ │ │ + OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ + feature.destroy(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.GeoRSS" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/ArcGIS93Rest.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.ArcGIS93Rest │ │ │ │ + * Instances of OpenLayers.Layer.ArcGIS93Rest are used to display data from │ │ │ │ + * ESRI ArcGIS Server 9.3 (and up?) Mapping Services using the REST API. │ │ │ │ + * Create a new ArcGIS93Rest layer with the <OpenLayers.Layer.ArcGIS93Rest> │ │ │ │ + * constructor. More detail on the REST API is available at │ │ │ │ + * http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/index.html ; │ │ │ │ + * specifically, the URL provided to this layer should be an export service │ │ │ │ + * URL: http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/export.html │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.ArcGIS93Rest = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: DEFAULT_PARAMS │ │ │ │ + * {Object} Hashtable of default parameter key/value pairs │ │ │ │ + */ │ │ │ │ + DEFAULT_PARAMS: { │ │ │ │ + format: "png" │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} Default is true for ArcGIS93Rest layer │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.ArcGIS93Rest │ │ │ │ + * Create a new ArcGIS93Rest layer object. │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * (code) │ │ │ │ + * var arcims = new OpenLayers.Layer.ArcGIS93Rest("MyName", │ │ │ │ + * "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/export", │ │ │ │ + * { │ │ │ │ + * layers: "0,1,2" │ │ │ │ + * }); │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} A name for the layer │ │ │ │ + * url - {String} Base url for the ArcGIS server REST service │ │ │ │ + * options - {Object} An object with key/value pairs representing the │ │ │ │ + * options and option values. │ │ │ │ + * │ │ │ │ + * Valid Options: │ │ │ │ + * format - {String} MIME type of desired image type. │ │ │ │ + * layers - {String} Comma-separated list of layers to display. │ │ │ │ + * srs - {String} Projection ID. │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + var newArguments = []; │ │ │ │ + //uppercase params │ │ │ │ + params = OpenLayers.Util.upperCaseObject(params); │ │ │ │ + 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.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 == "jpg") { │ │ │ │ + this.params.FORMAT = OpenLayers.Util.alphaHack() ? "gif" : │ │ │ │ + "png"; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.ArcGIS93Rest>} An exact clone of this layer │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.ArcGIS93Rest(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; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getURL │ │ │ │ + * Return an image url this layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the │ │ │ │ + * request. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A string with the map image's url. │ │ │ │ + */ │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + │ │ │ │ + // ArcGIS Server only wants the numeric portion of the projection ID. │ │ │ │ + var projWords = this.projection.getCode().split(":"); │ │ │ │ + var srid = projWords[projWords.length - 1]; │ │ │ │ + │ │ │ │ + var imageSize = this.getImageSize(); │ │ │ │ + var newParams = { │ │ │ │ + 'BBOX': bounds.toBBOX(), │ │ │ │ + 'SIZE': imageSize.w + "," + imageSize.h, │ │ │ │ + // We always want image, the other options were json, image with a whole lotta html around it, etc. │ │ │ │ + 'F': "image", │ │ │ │ + 'BBOXSR': srid, │ │ │ │ + 'IMAGESR': srid │ │ │ │ + }; │ │ │ │ + │ │ │ │ + // Now add the filter parameters. │ │ │ │ + if (this.layerDefs) { │ │ │ │ + var layerDefStrList = []; │ │ │ │ + var layerID; │ │ │ │ + for (layerID in this.layerDefs) { │ │ │ │ + if (this.layerDefs.hasOwnProperty(layerID)) { │ │ │ │ + if (this.layerDefs[layerID]) { │ │ │ │ + layerDefStrList.push(layerID); │ │ │ │ + layerDefStrList.push(":"); │ │ │ │ + layerDefStrList.push(this.layerDefs[layerID]); │ │ │ │ + layerDefStrList.push(";"); │ │ │ │ + } │ │ │ │ } │ │ │ │ - node.appendChild(child); │ │ │ │ } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ + if (layerDefStrList.length > 0) { │ │ │ │ + newParams['LAYERDEFS'] = layerDefStrList.join(""); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var requestString = this.getFullRequestString(newParams); │ │ │ │ + return requestString; │ │ │ │ + }, │ │ │ │ │ │ │ │ + /** │ │ │ │ + * Method: setLayerFilter │ │ │ │ + * addTile creates a tile, initializes it, and adds it to the layer div. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * id - {String} The id of the layer to which the filter applies. │ │ │ │ + * queryDef - {String} A sql-ish query filter, for more detail see the ESRI │ │ │ │ + * documentation at http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/export.html │ │ │ │ + */ │ │ │ │ + setLayerFilter: function(id, queryDef) { │ │ │ │ + if (!this.layerDefs) { │ │ │ │ + this.layerDefs = {}; │ │ │ │ + } │ │ │ │ + if (queryDef) { │ │ │ │ + this.layerDefs[id] = queryDef; │ │ │ │ + } else { │ │ │ │ + delete this.layerDefs[id]; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.Filter.v1_0_0" │ │ │ │ + /** │ │ │ │ + * Method: clearLayerFilter │ │ │ │ + * Clears layer filters, either from a specific layer, │ │ │ │ + * or all of them. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * id - {String} The id of the layer from which to remove any │ │ │ │ + * filter. If unspecified/blank, all filters │ │ │ │ + * will be removed. │ │ │ │ + */ │ │ │ │ + clearLayerFilter: function(id) { │ │ │ │ + if (id) { │ │ │ │ + delete this.layerDefs[id]; │ │ │ │ + } else { │ │ │ │ + delete this.layerDefs; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.ArcGIS93Rest" │ │ │ │ +}); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/SLD/v1.js │ │ │ │ + OpenLayers/Layer/Boxes.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/Rule.js │ │ │ │ - * @requires OpenLayers/Format/SLD.js │ │ │ │ - * @requires OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Point.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Line.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Polygon.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Text.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Raster.js │ │ │ │ + * @requires OpenLayers/Layer.js │ │ │ │ + * @requires OpenLayers/Layer/Markers.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.SLD.v1 │ │ │ │ - * Superclass for SLD version 1 parsers. │ │ │ │ + * Class: OpenLayers.Layer.Boxes │ │ │ │ + * Draw divs as 'boxes' on the layer. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.Filter.v1_0_0> │ │ │ │ + * - <OpenLayers.Layer.Markers> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { │ │ │ │ +OpenLayers.Layer.Boxes = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + * Constructor: OpenLayers.Layer.Boxes │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} │ │ │ │ + * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ */ │ │ │ │ - namespaces: { │ │ │ │ - sld: "http://www.opengis.net/sld", │ │ │ │ - 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" │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: drawMarker │ │ │ │ + * Calculate the pixel location for the marker, create it, and │ │ │ │ + * add it to the layer's div │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * marker - {<OpenLayers.Marker.Box>} │ │ │ │ + */ │ │ │ │ + drawMarker: function(marker) { │ │ │ │ + var topleft = this.map.getLayerPxFromLonLat({ │ │ │ │ + lon: marker.bounds.left, │ │ │ │ + lat: marker.bounds.top │ │ │ │ + }); │ │ │ │ + var botright = this.map.getLayerPxFromLonLat({ │ │ │ │ + lon: marker.bounds.right, │ │ │ │ + lat: marker.bounds.bottom │ │ │ │ + }); │ │ │ │ + if (botright == null || topleft == null) { │ │ │ │ + marker.display(false); │ │ │ │ + } else { │ │ │ │ + var markerDiv = marker.draw(topleft, { │ │ │ │ + w: Math.max(1, botright.x - topleft.x), │ │ │ │ + h: Math.max(1, botright.y - topleft.y) │ │ │ │ + }); │ │ │ │ + if (!marker.drawn) { │ │ │ │ + this.div.appendChild(markerDiv); │ │ │ │ + marker.drawn = true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ + * APIMethod: removeMarker │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * marker - {<OpenLayers.Marker.Box>} │ │ │ │ */ │ │ │ │ - defaultPrefix: "sld", │ │ │ │ + removeMarker: function(marker) { │ │ │ │ + OpenLayers.Util.removeItem(this.markers, marker); │ │ │ │ + if ((marker.div != null) && │ │ │ │ + (marker.div.parentNode == this.div)) { │ │ │ │ + this.div.removeChild(marker.div); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Boxes" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/WorldWind.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.WorldWind │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.WorldWind = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + DEFAULT_PARAMS: {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} Schema location for a particular minor version. │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} WorldWind layer is a base layer by default. │ │ │ │ */ │ │ │ │ - schemaLocation: null, │ │ │ │ + isBaseLayer: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: multipleSymbolizers │ │ │ │ - * {Boolean} Support multiple symbolizers per rule. Default is false. if │ │ │ │ - * true, an OpenLayers.Style2 instance will be created to represent │ │ │ │ - * user styles instead of an OpenLayers.Style instace. The │ │ │ │ - * OpenLayers.Style2 class allows collections of rules with multiple │ │ │ │ - * symbolizers, but is not currently useful for client side rendering. │ │ │ │ - * If multiple symbolizers is true, multiple FeatureTypeStyle elements │ │ │ │ - * are preserved in reading/writing by setting symbolizer zIndex values. │ │ │ │ - * In addition, the <defaultSymbolizer> property is ignored if │ │ │ │ - * multiple symbolizers are supported (defaults should be applied │ │ │ │ - * when rendering). │ │ │ │ + * APIProperty: lzd │ │ │ │ + * {Float} LevelZeroTileSizeDegrees │ │ │ │ */ │ │ │ │ - multipleSymbolizers: false, │ │ │ │ + lzd: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: featureTypeCounter │ │ │ │ - * {Number} Private counter for multiple feature type styles. │ │ │ │ + * APIProperty: zoomLevels │ │ │ │ + * {Integer} Number of zoom levels. │ │ │ │ */ │ │ │ │ - featureTypeCounter: null, │ │ │ │ + zoomLevels: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: defaultSymbolizer. │ │ │ │ - * {Object} A symbolizer with the SLD defaults. │ │ │ │ + * Constructor: OpenLayers.Layer.WorldWind │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} Name of Layer │ │ │ │ + * url - {String} Base URL │ │ │ │ + * lzd - {Float} Level zero tile size degrees │ │ │ │ + * zoomLevels - {Integer} number of zoom levels │ │ │ │ + * params - {Object} additional parameters │ │ │ │ + * options - {Object} additional options │ │ │ │ */ │ │ │ │ - defaultSymbolizer: { │ │ │ │ - fillColor: "#808080", │ │ │ │ - fillOpacity: 1, │ │ │ │ - strokeColor: "#000000", │ │ │ │ - strokeOpacity: 1, │ │ │ │ - strokeWidth: 1, │ │ │ │ - strokeDashstyle: "solid", │ │ │ │ - pointRadius: 3, │ │ │ │ - graphicName: "square" │ │ │ │ + initialize: function(name, url, lzd, zoomLevels, params, options) { │ │ │ │ + this.lzd = lzd; │ │ │ │ + this.zoomLevels = zoomLevels; │ │ │ │ + var newArguments = []; │ │ │ │ + newArguments.push(name, url, params, options); │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments); │ │ │ │ + this.params = OpenLayers.Util.applyDefaults( │ │ │ │ + this.params, this.DEFAULT_PARAMS │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.SLD.v1 │ │ │ │ - * Instances of this class are not created directly. Use the │ │ │ │ - * <OpenLayers.Format.SLD> constructor instead. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * Method: getZoom │ │ │ │ + * Convert map zoom to WW zoom. │ │ │ │ */ │ │ │ │ + getZoom: function() { │ │ │ │ + var zoom = this.map.getZoom(); │ │ │ │ + var extent = this.map.getMaxExtent(); │ │ │ │ + zoom = zoom - Math.log(this.maxResolution / (this.lzd / 512)) / Math.log(2); │ │ │ │ + return zoom; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: read │ │ │ │ + * Method: getURL │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * data - {DOMElement} An SLD document element. │ │ │ │ - * options - {Object} Options for the reader. │ │ │ │ - * │ │ │ │ - * Valid options: │ │ │ │ - * namedLayersAsArray - {Boolean} Generate a namedLayers array. If false, │ │ │ │ - * the namedLayers property value will be an object keyed by layer name. │ │ │ │ - * Default is false. │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} An object representing the SLD. │ │ │ │ + * {String} A string with the layer's url and parameters and also the │ │ │ │ + * passed-in bounds and appropriate tile size specified as │ │ │ │ + * parameters │ │ │ │ */ │ │ │ │ - read: function(data, options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ - var sld = { │ │ │ │ - namedLayers: options.namedLayersAsArray === true ? [] : {} │ │ │ │ - }; │ │ │ │ - this.readChildNodes(data, sld); │ │ │ │ - return sld; │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var zoom = this.getZoom(); │ │ │ │ + var extent = this.map.getMaxExtent(); │ │ │ │ + var deg = this.lzd / Math.pow(2, this.getZoom()); │ │ │ │ + var x = Math.floor((bounds.left - extent.left) / deg); │ │ │ │ + var y = Math.floor((bounds.bottom - extent.bottom) / deg); │ │ │ │ + if (this.map.getResolution() <= (this.lzd / 512) && │ │ │ │ + this.getZoom() <= this.zoomLevels) { │ │ │ │ + return this.getFullRequestString({ │ │ │ │ + L: zoom, │ │ │ │ + X: x, │ │ │ │ + Y: y │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + return OpenLayers.Util.getImageLocation("blank.gif"); │ │ │ │ + } │ │ │ │ + │ │ │ │ }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.WorldWind" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Constant: DEFAULT_PARAMS │ │ │ │ + * {Object} Hashtable of default parameter key/value pairs │ │ │ │ */ │ │ │ │ - readers: OpenLayers.Util.applyDefaults({ │ │ │ │ - "sld": { │ │ │ │ - "StyledLayerDescriptor": function(node, sld) { │ │ │ │ - sld.version = node.getAttribute("version"); │ │ │ │ - this.readChildNodes(node, sld); │ │ │ │ - }, │ │ │ │ - "Name": function(node, obj) { │ │ │ │ - obj.name = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Title": function(node, obj) { │ │ │ │ - obj.title = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Abstract": function(node, obj) { │ │ │ │ - obj.description = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "NamedLayer": function(node, sld) { │ │ │ │ - var layer = { │ │ │ │ - userStyles: [], │ │ │ │ - namedStyles: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, layer); │ │ │ │ - // give each of the user styles this layer name │ │ │ │ - for (var i = 0, len = layer.userStyles.length; i < len; ++i) { │ │ │ │ - layer.userStyles[i].layerName = layer.name; │ │ │ │ - } │ │ │ │ - if (OpenLayers.Util.isArray(sld.namedLayers)) { │ │ │ │ - sld.namedLayers.push(layer); │ │ │ │ - } else { │ │ │ │ - sld.namedLayers[layer.name] = layer; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "NamedStyle": function(node, layer) { │ │ │ │ - layer.namedStyles.push( │ │ │ │ - this.getChildName(node.firstChild) │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "UserStyle": function(node, layer) { │ │ │ │ - var obj = { │ │ │ │ - defaultsPerSymbolizer: true, │ │ │ │ - rules: [] │ │ │ │ - }; │ │ │ │ - this.featureTypeCounter = -1; │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - var style; │ │ │ │ - if (this.multipleSymbolizers) { │ │ │ │ - delete obj.defaultsPerSymbolizer; │ │ │ │ - style = new OpenLayers.Style2(obj); │ │ │ │ - } else { │ │ │ │ - style = new OpenLayers.Style(this.defaultSymbolizer, obj); │ │ │ │ - } │ │ │ │ - layer.userStyles.push(style); │ │ │ │ - }, │ │ │ │ - "IsDefault": function(node, style) { │ │ │ │ - if (this.getChildValue(node) == "1") { │ │ │ │ - style.isDefault = true; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "FeatureTypeStyle": function(node, style) { │ │ │ │ - ++this.featureTypeCounter; │ │ │ │ - var obj = { │ │ │ │ - rules: this.multipleSymbolizers ? style.rules : [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - if (!this.multipleSymbolizers) { │ │ │ │ - style.rules = obj.rules; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Rule": function(node, obj) { │ │ │ │ - var config; │ │ │ │ - if (this.multipleSymbolizers) { │ │ │ │ - config = { │ │ │ │ - symbolizers: [] │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - var rule = new OpenLayers.Rule(config); │ │ │ │ - this.readChildNodes(node, rule); │ │ │ │ - obj.rules.push(rule); │ │ │ │ - }, │ │ │ │ - "ElseFilter": function(node, rule) { │ │ │ │ - rule.elseFilter = true; │ │ │ │ - }, │ │ │ │ - "MinScaleDenominator": function(node, rule) { │ │ │ │ - rule.minScaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "MaxScaleDenominator": function(node, rule) { │ │ │ │ - rule.maxScaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "TextSymbolizer": function(node, rule) { │ │ │ │ - var config = {}; │ │ │ │ - this.readChildNodes(node, config); │ │ │ │ - if (this.multipleSymbolizers) { │ │ │ │ - config.zIndex = this.featureTypeCounter; │ │ │ │ - rule.symbolizers.push( │ │ │ │ - new OpenLayers.Symbolizer.Text(config) │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - rule.symbolizer["Text"] = OpenLayers.Util.applyDefaults( │ │ │ │ - config, rule.symbolizer["Text"] │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "LabelPlacement": function(node, symbolizer) { │ │ │ │ - this.readChildNodes(node, symbolizer); │ │ │ │ - }, │ │ │ │ - "PointPlacement": function(node, symbolizer) { │ │ │ │ - var config = {}; │ │ │ │ - this.readChildNodes(node, config); │ │ │ │ - config.labelRotation = config.rotation; │ │ │ │ - delete config.rotation; │ │ │ │ - var labelAlign, │ │ │ │ - x = symbolizer.labelAnchorPointX, │ │ │ │ - y = symbolizer.labelAnchorPointY; │ │ │ │ - if (x <= 1 / 3) { │ │ │ │ - labelAlign = 'l'; │ │ │ │ - } else if (x > 1 / 3 && x < 2 / 3) { │ │ │ │ - labelAlign = 'c'; │ │ │ │ - } else if (x >= 2 / 3) { │ │ │ │ - labelAlign = 'r'; │ │ │ │ - } │ │ │ │ - if (y <= 1 / 3) { │ │ │ │ - labelAlign += 'b'; │ │ │ │ - } else if (y > 1 / 3 && y < 2 / 3) { │ │ │ │ - labelAlign += 'm'; │ │ │ │ - } else if (y >= 2 / 3) { │ │ │ │ - labelAlign += 't'; │ │ │ │ - } │ │ │ │ - config.labelAlign = labelAlign; │ │ │ │ - OpenLayers.Util.applyDefaults(symbolizer, config); │ │ │ │ - }, │ │ │ │ - "AnchorPoint": function(node, symbolizer) { │ │ │ │ - this.readChildNodes(node, symbolizer); │ │ │ │ - }, │ │ │ │ - "AnchorPointX": function(node, symbolizer) { │ │ │ │ - var labelAnchorPointX = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (labelAnchorPointX) { │ │ │ │ - symbolizer.labelAnchorPointX = labelAnchorPointX; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "AnchorPointY": function(node, symbolizer) { │ │ │ │ - var labelAnchorPointY = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (labelAnchorPointY) { │ │ │ │ - symbolizer.labelAnchorPointY = labelAnchorPointY; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Displacement": function(node, symbolizer) { │ │ │ │ - this.readChildNodes(node, symbolizer); │ │ │ │ - }, │ │ │ │ - "DisplacementX": function(node, symbolizer) { │ │ │ │ - var labelXOffset = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (labelXOffset) { │ │ │ │ - symbolizer.labelXOffset = labelXOffset; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "DisplacementY": function(node, symbolizer) { │ │ │ │ - var labelYOffset = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (labelYOffset) { │ │ │ │ - symbolizer.labelYOffset = labelYOffset; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "LinePlacement": function(node, symbolizer) { │ │ │ │ - this.readChildNodes(node, symbolizer); │ │ │ │ - }, │ │ │ │ - "PerpendicularOffset": function(node, symbolizer) { │ │ │ │ - var labelPerpendicularOffset = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (labelPerpendicularOffset) { │ │ │ │ - symbolizer.labelPerpendicularOffset = labelPerpendicularOffset; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Label": function(node, symbolizer) { │ │ │ │ - var value = this.readers.ogc._expression.call(this, node); │ │ │ │ - if (value) { │ │ │ │ - symbolizer.label = value; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Font": function(node, symbolizer) { │ │ │ │ - this.readChildNodes(node, symbolizer); │ │ │ │ - }, │ │ │ │ - "Halo": function(node, symbolizer) { │ │ │ │ - // halo has a fill, so send fresh object │ │ │ │ - var obj = {}; │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - symbolizer.haloRadius = obj.haloRadius; │ │ │ │ - symbolizer.haloColor = obj.fillColor; │ │ │ │ - symbolizer.haloOpacity = obj.fillOpacity; │ │ │ │ - }, │ │ │ │ - "Radius": function(node, symbolizer) { │ │ │ │ - var radius = this.readers.ogc._expression.call(this, node); │ │ │ │ - if (radius != null) { │ │ │ │ - // radius is only used for halo │ │ │ │ - symbolizer.haloRadius = radius; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "RasterSymbolizer": function(node, rule) { │ │ │ │ - var config = {}; │ │ │ │ - this.readChildNodes(node, config); │ │ │ │ - if (this.multipleSymbolizers) { │ │ │ │ - config.zIndex = this.featureTypeCounter; │ │ │ │ - rule.symbolizers.push( │ │ │ │ - new OpenLayers.Symbolizer.Raster(config) │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - rule.symbolizer["Raster"] = OpenLayers.Util.applyDefaults( │ │ │ │ - config, rule.symbolizer["Raster"] │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Geometry": function(node, obj) { │ │ │ │ - obj.geometry = {}; │ │ │ │ - this.readChildNodes(node, obj.geometry); │ │ │ │ - }, │ │ │ │ - "ColorMap": function(node, symbolizer) { │ │ │ │ - symbolizer.colorMap = []; │ │ │ │ - this.readChildNodes(node, symbolizer.colorMap); │ │ │ │ - }, │ │ │ │ - "ColorMapEntry": function(node, colorMap) { │ │ │ │ - var q = node.getAttribute("quantity"); │ │ │ │ - var o = node.getAttribute("opacity"); │ │ │ │ - colorMap.push({ │ │ │ │ - color: node.getAttribute("color"), │ │ │ │ - quantity: q !== null ? parseFloat(q) : undefined, │ │ │ │ - label: node.getAttribute("label") || undefined, │ │ │ │ - opacity: o !== null ? parseFloat(o) : undefined │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "LineSymbolizer": function(node, rule) { │ │ │ │ - var config = {}; │ │ │ │ - this.readChildNodes(node, config); │ │ │ │ - if (this.multipleSymbolizers) { │ │ │ │ - config.zIndex = this.featureTypeCounter; │ │ │ │ - rule.symbolizers.push( │ │ │ │ - new OpenLayers.Symbolizer.Line(config) │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - rule.symbolizer["Line"] = OpenLayers.Util.applyDefaults( │ │ │ │ - config, rule.symbolizer["Line"] │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "PolygonSymbolizer": function(node, rule) { │ │ │ │ - var config = { │ │ │ │ - fill: false, │ │ │ │ - stroke: false │ │ │ │ - }; │ │ │ │ - if (!this.multipleSymbolizers) { │ │ │ │ - config = rule.symbolizer["Polygon"] || config; │ │ │ │ - } │ │ │ │ - this.readChildNodes(node, config); │ │ │ │ - if (this.multipleSymbolizers) { │ │ │ │ - config.zIndex = this.featureTypeCounter; │ │ │ │ - rule.symbolizers.push( │ │ │ │ - new OpenLayers.Symbolizer.Polygon(config) │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - rule.symbolizer["Polygon"] = config; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "PointSymbolizer": function(node, rule) { │ │ │ │ - var config = { │ │ │ │ - fill: false, │ │ │ │ - stroke: false, │ │ │ │ - graphic: false │ │ │ │ - }; │ │ │ │ - if (!this.multipleSymbolizers) { │ │ │ │ - config = rule.symbolizer["Point"] || config; │ │ │ │ - } │ │ │ │ - this.readChildNodes(node, config); │ │ │ │ - if (this.multipleSymbolizers) { │ │ │ │ - config.zIndex = this.featureTypeCounter; │ │ │ │ - rule.symbolizers.push( │ │ │ │ - new OpenLayers.Symbolizer.Point(config) │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - rule.symbolizer["Point"] = config; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Stroke": function(node, symbolizer) { │ │ │ │ - symbolizer.stroke = true; │ │ │ │ - this.readChildNodes(node, symbolizer); │ │ │ │ - }, │ │ │ │ - "Fill": function(node, symbolizer) { │ │ │ │ - symbolizer.fill = true; │ │ │ │ - this.readChildNodes(node, symbolizer); │ │ │ │ - }, │ │ │ │ - "CssParameter": function(node, symbolizer) { │ │ │ │ - var cssProperty = node.getAttribute("name"); │ │ │ │ - var symProperty = this.cssMap[cssProperty]; │ │ │ │ - // for labels, fill should map to fontColor and fill-opacity │ │ │ │ - // to fontOpacity │ │ │ │ - if (symbolizer.label) { │ │ │ │ - if (cssProperty === 'fill') { │ │ │ │ - symProperty = "fontColor"; │ │ │ │ - } else if (cssProperty === 'fill-opacity') { │ │ │ │ - symProperty = "fontOpacity"; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (symProperty) { │ │ │ │ - // Limited support for parsing of OGC expressions │ │ │ │ - var value = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be an empty string │ │ │ │ - if (value) { │ │ │ │ - symbolizer[symProperty] = value; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Graphic": function(node, symbolizer) { │ │ │ │ - symbolizer.graphic = true; │ │ │ │ - var graphic = {}; │ │ │ │ - // painter's order not respected here, clobber previous with next │ │ │ │ - this.readChildNodes(node, graphic); │ │ │ │ - // directly properties with names that match symbolizer properties │ │ │ │ - var properties = [ │ │ │ │ - "stroke", "strokeColor", "strokeWidth", "strokeOpacity", │ │ │ │ - "strokeLinecap", "fill", "fillColor", "fillOpacity", │ │ │ │ - "graphicName", "rotation", "graphicFormat" │ │ │ │ - ]; │ │ │ │ - var prop, value; │ │ │ │ - for (var i = 0, len = properties.length; i < len; ++i) { │ │ │ │ - prop = properties[i]; │ │ │ │ - value = graphic[prop]; │ │ │ │ - if (value != undefined) { │ │ │ │ - symbolizer[prop] = value; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - // set other generic properties with specific graphic property names │ │ │ │ - if (graphic.opacity != undefined) { │ │ │ │ - symbolizer.graphicOpacity = graphic.opacity; │ │ │ │ - } │ │ │ │ - if (graphic.size != undefined) { │ │ │ │ - var pointRadius = graphic.size / 2; │ │ │ │ - if (isNaN(pointRadius)) { │ │ │ │ - // likely a property name │ │ │ │ - symbolizer.graphicWidth = graphic.size; │ │ │ │ - } else { │ │ │ │ - symbolizer.pointRadius = graphic.size / 2; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (graphic.href != undefined) { │ │ │ │ - symbolizer.externalGraphic = graphic.href; │ │ │ │ - } │ │ │ │ - if (graphic.rotation != undefined) { │ │ │ │ - symbolizer.rotation = graphic.rotation; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "ExternalGraphic": function(node, graphic) { │ │ │ │ - this.readChildNodes(node, graphic); │ │ │ │ - }, │ │ │ │ - "Mark": function(node, graphic) { │ │ │ │ - this.readChildNodes(node, graphic); │ │ │ │ - }, │ │ │ │ - "WellKnownName": function(node, graphic) { │ │ │ │ - graphic.graphicName = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Opacity": function(node, obj) { │ │ │ │ - var opacity = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (opacity) { │ │ │ │ - obj.opacity = opacity; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Size": function(node, obj) { │ │ │ │ - var size = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (size) { │ │ │ │ - obj.size = size; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Rotation": function(node, obj) { │ │ │ │ - var rotation = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (rotation) { │ │ │ │ - obj.rotation = rotation; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "OnlineResource": function(node, obj) { │ │ │ │ - obj.href = this.getAttributeNS( │ │ │ │ - node, this.namespaces.xlink, "href" │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "Format": function(node, graphic) { │ │ │ │ - graphic.graphicFormat = this.getChildValue(node); │ │ │ │ + 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"; │ │ │ │ } │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.Filter.v1_0_0.prototype.readers), │ │ │ │ + │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: cssMap │ │ │ │ - * {Object} Object mapping supported css property names to OpenLayers │ │ │ │ - * symbolizer property names. │ │ │ │ + * Method: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.WMS>} An exact clone of this layer │ │ │ │ */ │ │ │ │ - cssMap: { │ │ │ │ - "stroke": "strokeColor", │ │ │ │ - "stroke-opacity": "strokeOpacity", │ │ │ │ - "stroke-width": "strokeWidth", │ │ │ │ - "stroke-linecap": "strokeLinecap", │ │ │ │ - "stroke-dasharray": "strokeDashstyle", │ │ │ │ - "fill": "fillColor", │ │ │ │ - "fill-opacity": "fillOpacity", │ │ │ │ - "font-family": "fontFamily", │ │ │ │ - "font-size": "fontSize", │ │ │ │ - "font-weight": "fontWeight", │ │ │ │ - "font-style": "fontStyle" │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getCssProperty │ │ │ │ - * Given a symbolizer property, get the corresponding CSS property │ │ │ │ - * from the <cssMap>. │ │ │ │ + * 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: │ │ │ │ - * sym - {String} A symbolizer property name. │ │ │ │ + * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the │ │ │ │ + * request. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} A CSS property name or null if none found. │ │ │ │ + * {String} A string with the layer's url and parameters and also the │ │ │ │ + * passed-in bounds and appropriate tile size specified as │ │ │ │ + * parameters. │ │ │ │ */ │ │ │ │ - getCssProperty: function(sym) { │ │ │ │ - var css = null; │ │ │ │ - for (var prop in this.cssMap) { │ │ │ │ - if (this.cssMap[prop] == sym) { │ │ │ │ - css = prop; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return css; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getGraphicFormat │ │ │ │ - * Given a href for an external graphic, try to determine the mime-type. │ │ │ │ - * This method doesn't try too hard, and will fall back to │ │ │ │ - * <defaultGraphicFormat> if one of the known <graphicFormats> is not │ │ │ │ - * the file extension of the provided href. │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * href - {String} │ │ │ │ + * 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} The graphic format. │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - getGraphicFormat: function(href) { │ │ │ │ - var format, regex; │ │ │ │ - for (var key in this.graphicFormats) { │ │ │ │ - if (this.graphicFormats[key].test(href)) { │ │ │ │ - format = key; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - return format || this.defaultGraphicFormat; │ │ │ │ + │ │ │ │ + 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/Layer/PointTrack.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.PointTrack │ │ │ │ + * Vector layer to display ordered point features as a line, creating one │ │ │ │ + * LineString feature for each pair of two points. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Vector> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.PointTrack = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Property: defaultGraphicFormat │ │ │ │ - * {String} If none other can be determined from <getGraphicFormat>, this │ │ │ │ - * default will be returned. │ │ │ │ + * APIProperty: dataFrom │ │ │ │ + * {<OpenLayers.Layer.PointTrack.TARGET_NODE>} or │ │ │ │ + * {<OpenLayers.Layer.PointTrack.SOURCE_NODE>} optional. If the lines │ │ │ │ + * should get the data/attributes from one of the two points it is │ │ │ │ + * composed of, which one should it be? │ │ │ │ */ │ │ │ │ - defaultGraphicFormat: "image/png", │ │ │ │ + dataFrom: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: graphicFormats │ │ │ │ - * {Object} Mapping of image mime-types to regular extensions matching │ │ │ │ - * well-known file extensions. │ │ │ │ + * APIProperty: styleFrom │ │ │ │ + * {<OpenLayers.Layer.PointTrack.TARGET_NODE>} or │ │ │ │ + * {<OpenLayers.Layer.PointTrack.SOURCE_NODE>} optional. If the lines │ │ │ │ + * should get the style from one of the two points it is composed of, │ │ │ │ + * which one should it be? │ │ │ │ */ │ │ │ │ - graphicFormats: { │ │ │ │ - "image/jpeg": /\.jpe?g$/i, │ │ │ │ - "image/gif": /\.gif$/i, │ │ │ │ - "image/png": /\.png$/i │ │ │ │ - }, │ │ │ │ + styleFrom: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: write │ │ │ │ + * Constructor: OpenLayers.PointTrack │ │ │ │ + * Constructor for a new OpenLayers.PointTrack instance. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * sld - {Object} An object representing the SLD. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} The root of an SLD document. │ │ │ │ + * name - {String} name of the layer │ │ │ │ + * options - {Object} Optional object with properties to tag onto the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - write: function(sld) { │ │ │ │ - return this.writers.sld.StyledLayerDescriptor.apply(this, [sld]); │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: addNodes │ │ │ │ + * Adds point features that will be used to create lines from, using point │ │ │ │ + * pairs. The first point of a pair will be the source node, the second │ │ │ │ + * will be the target node. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * pointFeatures - {Array(<OpenLayers.Feature>)} │ │ │ │ + * options - {Object} │ │ │ │ + * │ │ │ │ + * Supported options: │ │ │ │ + * silent - {Boolean} true to suppress (before)feature(s)added events │ │ │ │ + */ │ │ │ │ + addNodes: function(pointFeatures, options) { │ │ │ │ + if (pointFeatures.length < 2) { │ │ │ │ + throw new Error("At least two point features have to be added to " + │ │ │ │ + "create a line from"); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var lines = new Array(pointFeatures.length - 1); │ │ │ │ + │ │ │ │ + var pointFeature, startPoint, endPoint; │ │ │ │ + for (var i = 0, len = pointFeatures.length; i < len; i++) { │ │ │ │ + pointFeature = pointFeatures[i]; │ │ │ │ + endPoint = pointFeature.geometry; │ │ │ │ + │ │ │ │ + if (!endPoint) { │ │ │ │ + var lonlat = pointFeature.lonlat; │ │ │ │ + endPoint = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat); │ │ │ │ + } else if (endPoint.CLASS_NAME != "OpenLayers.Geometry.Point") { │ │ │ │ + throw new TypeError("Only features with point geometries are supported."); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (i > 0) { │ │ │ │ + var attributes = (this.dataFrom != null) ? │ │ │ │ + (pointFeatures[i + this.dataFrom].data || │ │ │ │ + pointFeatures[i + this.dataFrom].attributes) : │ │ │ │ + null; │ │ │ │ + var style = (this.styleFrom != null) ? │ │ │ │ + (pointFeatures[i + this.styleFrom].style) : │ │ │ │ + null; │ │ │ │ + var line = new OpenLayers.Geometry.LineString([startPoint, │ │ │ │ + endPoint │ │ │ │ + ]); │ │ │ │ + │ │ │ │ + lines[i - 1] = new OpenLayers.Feature.Vector(line, attributes, │ │ │ │ + style); │ │ │ │ + } │ │ │ │ + │ │ │ │ + startPoint = endPoint; │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.addFeatures(lines, options); │ │ │ │ }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.PointTrack" │ │ │ │ +}); │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Layer.PointTrack.SOURCE_NODE │ │ │ │ + * {Number} value for <OpenLayers.Layer.PointTrack.dataFrom> and │ │ │ │ + * <OpenLayers.Layer.PointTrack.styleFrom> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.PointTrack.SOURCE_NODE = -1; │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Layer.PointTrack.TARGET_NODE │ │ │ │ + * {Number} value for <OpenLayers.Layer.PointTrack.dataFrom> and │ │ │ │ + * <OpenLayers.Layer.PointTrack.styleFrom> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.PointTrack.TARGET_NODE = 0; │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Layer.PointTrack.dataFrom │ │ │ │ + * {Object} with the following keys - *deprecated* │ │ │ │ + * - SOURCE_NODE: take data/attributes from the source node of the line │ │ │ │ + * - TARGET_NODE: take data/attributes from the target node of the line │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.PointTrack.dataFrom = { │ │ │ │ + 'SOURCE_NODE': -1, │ │ │ │ + 'TARGET_NODE': 0 │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/Google/v3.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/Google.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Layer.Google.v3 │ │ │ │ + * │ │ │ │ + * Mixin providing functionality specific to the Google Maps API v3. │ │ │ │ + * │ │ │ │ + * To use this layer, you must include the GMaps v3 API in your html. │ │ │ │ + * │ │ │ │ + * Note that this layer configures the google.maps.map object with the │ │ │ │ + * "disableDefaultUI" option set to true. Using UI controls that the Google │ │ │ │ + * Maps API provides is not supported by the OpenLayers API. │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Google.v3 = { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Constant: DEFAULTS │ │ │ │ + * {Object} It is not recommended to change the properties set here. Note │ │ │ │ + * that Google.v3 layers only work when sphericalMercator is set to true. │ │ │ │ + * │ │ │ │ + * (code) │ │ │ │ + * { │ │ │ │ + * sphericalMercator: true, │ │ │ │ + * projection: "EPSG:900913" │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ */ │ │ │ │ - writers: OpenLayers.Util.applyDefaults({ │ │ │ │ - "sld": { │ │ │ │ - "_OGCExpression": function(nodeName, value) { │ │ │ │ - // only the simplest of ogc:expression handled │ │ │ │ - // {label: "some text and a ${propertyName}"} │ │ │ │ - var node = this.createElementNSPlus(nodeName); │ │ │ │ - var tokens = typeof value == "string" ? │ │ │ │ - value.split("${") : [value]; │ │ │ │ - node.appendChild(this.createTextNode(tokens[0])); │ │ │ │ - var item, last; │ │ │ │ - for (var i = 1, len = tokens.length; i < len; i++) { │ │ │ │ - item = tokens[i]; │ │ │ │ - last = item.indexOf("}"); │ │ │ │ - if (last > 0) { │ │ │ │ - this.writeNode( │ │ │ │ - "ogc:PropertyName", { │ │ │ │ - property: item.substring(0, last) │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - node.appendChild( │ │ │ │ - this.createTextNode(item.substring(++last)) │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - // no ending }, so this is a literal ${ │ │ │ │ - node.appendChild( │ │ │ │ - this.createTextNode("${" + item) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "StyledLayerDescriptor": function(sld) { │ │ │ │ - var root = this.createElementNSPlus( │ │ │ │ - "sld:StyledLayerDescriptor", { │ │ │ │ - attributes: { │ │ │ │ - "version": this.VERSION, │ │ │ │ - "xsi:schemaLocation": this.schemaLocation │ │ │ │ - } │ │ │ │ - } │ │ │ │ - ); │ │ │ │ + DEFAULTS: { │ │ │ │ + sphericalMercator: true, │ │ │ │ + projection: "EPSG:900913" │ │ │ │ + }, │ │ │ │ │ │ │ │ - // For ArcGIS Server it is necessary to define this │ │ │ │ - // at the root level (see ticket:2166). │ │ │ │ - root.setAttribute("xmlns:ogc", this.namespaces.ogc); │ │ │ │ - root.setAttribute("xmlns:gml", this.namespaces.gml); │ │ │ │ + /** │ │ │ │ + * APIProperty: animationEnabled │ │ │ │ + * {Boolean} If set to true, the transition between zoom levels will be │ │ │ │ + * animated (if supported by the GMaps API for the device used). Set to │ │ │ │ + * false to match the zooming experience of other layer types. Default │ │ │ │ + * is true. Note that the GMaps API does not give us control over zoom │ │ │ │ + * animation, so if set to false, when zooming, this will make the │ │ │ │ + * layer temporarily invisible, wait until GMaps reports the map being │ │ │ │ + * idle, and make it visible again. The result will be a blank layer │ │ │ │ + * for a few moments while zooming. │ │ │ │ + */ │ │ │ │ + animationEnabled: true, │ │ │ │ │ │ │ │ - // add in optional name │ │ │ │ - if (sld.name) { │ │ │ │ - this.writeNode("Name", sld.name, root); │ │ │ │ - } │ │ │ │ - // add in optional title │ │ │ │ - if (sld.title) { │ │ │ │ - this.writeNode("Title", sld.title, root); │ │ │ │ - } │ │ │ │ - // add in optional description │ │ │ │ - if (sld.description) { │ │ │ │ - this.writeNode("Abstract", sld.description, root); │ │ │ │ - } │ │ │ │ - // add in named layers │ │ │ │ - // allow namedLayers to be an array │ │ │ │ - if (OpenLayers.Util.isArray(sld.namedLayers)) { │ │ │ │ - for (var i = 0, len = sld.namedLayers.length; i < len; ++i) { │ │ │ │ - this.writeNode("NamedLayer", sld.namedLayers[i], root); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - for (var name in sld.namedLayers) { │ │ │ │ - this.writeNode("NamedLayer", sld.namedLayers[name], root); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return root; │ │ │ │ - }, │ │ │ │ - "Name": function(name) { │ │ │ │ - return this.createElementNSPlus("sld:Name", { │ │ │ │ - value: name │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Title": function(title) { │ │ │ │ - return this.createElementNSPlus("sld:Title", { │ │ │ │ - value: title │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Abstract": function(description) { │ │ │ │ - return this.createElementNSPlus( │ │ │ │ - "sld:Abstract", { │ │ │ │ - value: description │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "NamedLayer": function(layer) { │ │ │ │ - var node = this.createElementNSPlus("sld:NamedLayer"); │ │ │ │ + /** │ │ │ │ + * Method: loadMapObject │ │ │ │ + * Load the GMap and register appropriate event listeners. │ │ │ │ + */ │ │ │ │ + loadMapObject: function() { │ │ │ │ + if (!this.type) { │ │ │ │ + this.type = google.maps.MapTypeId.ROADMAP; │ │ │ │ + } │ │ │ │ + var mapObject; │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + // there are already Google layers added to this map │ │ │ │ + mapObject = cache.mapObject; │ │ │ │ + // increment the layer count │ │ │ │ + ++cache.count; │ │ │ │ + } else { │ │ │ │ + // this is the first Google layer for this map │ │ │ │ + // create GMap │ │ │ │ + var center = this.map.getCenter(); │ │ │ │ + var container = document.createElement('div'); │ │ │ │ + container.className = "olForeignContainer"; │ │ │ │ + container.style.width = '100%'; │ │ │ │ + container.style.height = '100%'; │ │ │ │ + mapObject = new google.maps.Map(container, { │ │ │ │ + center: center ? │ │ │ │ + new google.maps.LatLng(center.lat, center.lon) : new google.maps.LatLng(0, 0), │ │ │ │ + zoom: this.map.getZoom() || 0, │ │ │ │ + mapTypeId: this.type, │ │ │ │ + disableDefaultUI: true, │ │ │ │ + keyboardShortcuts: false, │ │ │ │ + draggable: false, │ │ │ │ + disableDoubleClickZoom: true, │ │ │ │ + scrollwheel: false, │ │ │ │ + streetViewControl: false │ │ │ │ + }); │ │ │ │ + var googleControl = document.createElement('div'); │ │ │ │ + googleControl.style.width = '100%'; │ │ │ │ + googleControl.style.height = '100%'; │ │ │ │ + mapObject.controls[google.maps.ControlPosition.TOP_LEFT].push(googleControl); │ │ │ │ │ │ │ │ - // add in required name │ │ │ │ - this.writeNode("Name", layer.name, node); │ │ │ │ + // cache elements for use by any other google layers added to │ │ │ │ + // this same map │ │ │ │ + cache = { │ │ │ │ + googleControl: googleControl, │ │ │ │ + mapObject: mapObject, │ │ │ │ + count: 1 │ │ │ │ + }; │ │ │ │ + OpenLayers.Layer.Google.cache[this.map.id] = cache; │ │ │ │ + } │ │ │ │ + this.mapObject = mapObject; │ │ │ │ + this.setGMapVisibility(this.visibility); │ │ │ │ + }, │ │ │ │ │ │ │ │ - // optional sld:LayerFeatureConstraints here │ │ │ │ + /** │ │ │ │ + * APIMethod: onMapResize │ │ │ │ + */ │ │ │ │ + onMapResize: function() { │ │ │ │ + if (this.visibility) { │ │ │ │ + google.maps.event.trigger(this.mapObject, "resize"); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - // add in named styles │ │ │ │ - if (layer.namedStyles) { │ │ │ │ - for (var i = 0, len = layer.namedStyles.length; i < len; ++i) { │ │ │ │ - this.writeNode( │ │ │ │ - "NamedStyle", layer.namedStyles[i], node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Method: setGMapVisibility │ │ │ │ + * Display the GMap container and associated elements. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * visible - {Boolean} Display the GMap elements. │ │ │ │ + */ │ │ │ │ + setGMapVisibility: function(visible) { │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + var map = this.map; │ │ │ │ + if (cache) { │ │ │ │ + var type = this.type; │ │ │ │ + var layers = map.layers; │ │ │ │ + var layer; │ │ │ │ + for (var i = layers.length - 1; i >= 0; --i) { │ │ │ │ + layer = layers[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.Google && │ │ │ │ + layer.visibility === true && layer.inRange === true) { │ │ │ │ + type = layer.type; │ │ │ │ + visible = true; │ │ │ │ + break; │ │ │ │ } │ │ │ │ - │ │ │ │ - // add in user styles │ │ │ │ - if (layer.userStyles) { │ │ │ │ - for (var i = 0, len = layer.userStyles.length; i < len; ++i) { │ │ │ │ - this.writeNode( │ │ │ │ - "UserStyle", layer.userStyles[i], node │ │ │ │ - ); │ │ │ │ + } │ │ │ │ + var container = this.mapObject.getDiv(); │ │ │ │ + if (visible === true) { │ │ │ │ + if (container.parentNode !== map.div) { │ │ │ │ + if (!cache.rendered) { │ │ │ │ + var me = this; │ │ │ │ + google.maps.event.addListenerOnce(this.mapObject, 'tilesloaded', function() { │ │ │ │ + cache.rendered = true; │ │ │ │ + me.setGMapVisibility(me.getVisibility()); │ │ │ │ + me.moveTo(me.map.getCenter()); │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + map.div.appendChild(container); │ │ │ │ + cache.googleControl.appendChild(map.viewPortDiv); │ │ │ │ + google.maps.event.trigger(this.mapObject, 'resize'); │ │ │ │ } │ │ │ │ } │ │ │ │ + this.mapObject.setMapTypeId(type); │ │ │ │ + } else if (cache.googleControl.hasChildNodes()) { │ │ │ │ + map.div.appendChild(map.viewPortDiv); │ │ │ │ + map.div.removeChild(container); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "NamedStyle": function(name) { │ │ │ │ - var node = this.createElementNSPlus("sld:NamedStyle"); │ │ │ │ - this.writeNode("Name", name, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "UserStyle": function(style) { │ │ │ │ - var node = this.createElementNSPlus("sld:UserStyle"); │ │ │ │ + /** │ │ │ │ + * Method: getMapContainer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} the GMap container's div │ │ │ │ + */ │ │ │ │ + getMapContainer: function() { │ │ │ │ + return this.mapObject.getDiv(); │ │ │ │ + }, │ │ │ │ │ │ │ │ - // add in optional name │ │ │ │ - if (style.name) { │ │ │ │ - this.writeNode("Name", style.name, node); │ │ │ │ - } │ │ │ │ - // add in optional title │ │ │ │ - if (style.title) { │ │ │ │ - this.writeNode("Title", style.title, node); │ │ │ │ - } │ │ │ │ - // add in optional description │ │ │ │ - if (style.description) { │ │ │ │ - this.writeNode("Abstract", style.description, node); │ │ │ │ - } │ │ │ │ + // │ │ │ │ + // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ + // │ │ │ │ │ │ │ │ - // add isdefault │ │ │ │ - if (style.isDefault) { │ │ │ │ - this.writeNode("IsDefault", style.isDefault, node); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectBoundsFromOLBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * olBounds - {<OpenLayers.Bounds>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} A MapObject Bounds, translated from olBounds │ │ │ │ + * Returns null if null value is passed in │ │ │ │ + */ │ │ │ │ + getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ + var moBounds = null; │ │ │ │ + if (olBounds != null) { │ │ │ │ + var sw = this.sphericalMercator ? │ │ │ │ + this.inverseMercator(olBounds.bottom, olBounds.left) : │ │ │ │ + new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ + var ne = this.sphericalMercator ? │ │ │ │ + this.inverseMercator(olBounds.top, olBounds.right) : │ │ │ │ + new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ + moBounds = new google.maps.LatLngBounds( │ │ │ │ + new google.maps.LatLng(sw.lat, sw.lon), │ │ │ │ + new google.maps.LatLng(ne.lat, ne.lon) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return moBounds; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // add FeatureTypeStyles │ │ │ │ - if (this.multipleSymbolizers && style.rules) { │ │ │ │ - // group style objects by symbolizer zIndex │ │ │ │ - var rulesByZ = { │ │ │ │ - 0: [] │ │ │ │ - }; │ │ │ │ - var zValues = [0]; │ │ │ │ - var rule, ruleMap, symbolizer, zIndex, clone; │ │ │ │ - for (var i = 0, ii = style.rules.length; i < ii; ++i) { │ │ │ │ - rule = style.rules[i]; │ │ │ │ - if (rule.symbolizers) { │ │ │ │ - ruleMap = {}; │ │ │ │ - for (var j = 0, jj = rule.symbolizers.length; j < jj; ++j) { │ │ │ │ - symbolizer = rule.symbolizers[j]; │ │ │ │ - zIndex = symbolizer.zIndex; │ │ │ │ - if (!(zIndex in ruleMap)) { │ │ │ │ - clone = rule.clone(); │ │ │ │ - clone.symbolizers = []; │ │ │ │ - ruleMap[zIndex] = clone; │ │ │ │ - } │ │ │ │ - ruleMap[zIndex].symbolizers.push(symbolizer.clone()); │ │ │ │ - } │ │ │ │ - for (zIndex in ruleMap) { │ │ │ │ - if (!(zIndex in rulesByZ)) { │ │ │ │ - zValues.push(zIndex); │ │ │ │ - rulesByZ[zIndex] = []; │ │ │ │ - } │ │ │ │ - rulesByZ[zIndex].push(ruleMap[zIndex]); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - // no symbolizers in rule │ │ │ │ - rulesByZ[0].push(rule.clone()); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - // write one FeatureTypeStyle per zIndex │ │ │ │ - zValues.sort(); │ │ │ │ - var rules; │ │ │ │ - for (var i = 0, ii = zValues.length; i < ii; ++i) { │ │ │ │ - rules = rulesByZ[zValues[i]]; │ │ │ │ - if (rules.length > 0) { │ │ │ │ - clone = style.clone(); │ │ │ │ - clone.rules = rulesByZ[zValues[i]]; │ │ │ │ - this.writeNode("FeatureTypeStyle", clone, node); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.writeNode("FeatureTypeStyle", style, node); │ │ │ │ - } │ │ │ │ │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "IsDefault": function(bool) { │ │ │ │ - return this.createElementNSPlus( │ │ │ │ - "sld:IsDefault", { │ │ │ │ - value: (bool) ? "1" : "0" │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "FeatureTypeStyle": function(style) { │ │ │ │ - var node = this.createElementNSPlus("sld:FeatureTypeStyle"); │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Interface Controls * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ │ │ │ │ - // OpenLayers currently stores no Name, Title, Abstract, │ │ │ │ - // FeatureTypeName, or SemanticTypeIdentifier information │ │ │ │ - // related to FeatureTypeStyle │ │ │ │ │ │ │ │ - // add in rules │ │ │ │ - for (var i = 0, len = style.rules.length; i < len; ++i) { │ │ │ │ - this.writeNode("Rule", style.rules[i], node); │ │ │ │ - } │ │ │ │ + // LonLat - Pixel Translation │ │ │ │ │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Rule": function(rule) { │ │ │ │ - var node = this.createElementNSPlus("sld:Rule"); │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectLonLatFromMapObjectPixel │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moPixel - {Object} MapObject Pixel format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject LonLat translated from MapObject Pixel │ │ │ │ + */ │ │ │ │ + getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ + var size = this.map.getSize(); │ │ │ │ + var lon = this.getLongitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ + var lat = this.getLatitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ │ │ │ │ - // add in optional name │ │ │ │ - if (rule.name) { │ │ │ │ - this.writeNode("Name", rule.name, node); │ │ │ │ - } │ │ │ │ - // add in optional title │ │ │ │ - if (rule.title) { │ │ │ │ - this.writeNode("Title", rule.title, node); │ │ │ │ - } │ │ │ │ - // add in optional description │ │ │ │ - if (rule.description) { │ │ │ │ - this.writeNode("Abstract", rule.description, node); │ │ │ │ - } │ │ │ │ + var delta_x = moPixel.x - (size.w / 2); │ │ │ │ + var delta_y = moPixel.y - (size.h / 2); │ │ │ │ │ │ │ │ - // add in LegendGraphic here │ │ │ │ + var lonlat = new OpenLayers.LonLat( │ │ │ │ + lon + delta_x * res, │ │ │ │ + lat - delta_y * res │ │ │ │ + ); │ │ │ │ │ │ │ │ - // add in optional filters │ │ │ │ - if (rule.elseFilter) { │ │ │ │ - this.writeNode("ElseFilter", null, node); │ │ │ │ - } else if (rule.filter) { │ │ │ │ - this.writeNode("ogc:Filter", rule.filter, node); │ │ │ │ - } │ │ │ │ + if (this.wrapDateLine) { │ │ │ │ + lonlat = lonlat.wrapDateLine(this.maxExtent); │ │ │ │ + } │ │ │ │ + return this.getMapObjectLonLatFromLonLat(lonlat.lon, lonlat.lat); │ │ │ │ + }, │ │ │ │ │ │ │ │ - // add in scale limits │ │ │ │ - if (rule.minScaleDenominator != undefined) { │ │ │ │ - this.writeNode( │ │ │ │ - "MinScaleDenominator", rule.minScaleDenominator, node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (rule.maxScaleDenominator != undefined) { │ │ │ │ - this.writeNode( │ │ │ │ - "MaxScaleDenominator", rule.maxScaleDenominator, node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectPixelFromMapObjectLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moLonLat - {Object} MapObject LonLat format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Pixel transtlated from MapObject LonLat │ │ │ │ + */ │ │ │ │ + getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); │ │ │ │ + var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ + var extent = this.map.getExtent(); │ │ │ │ + return this.getMapObjectPixelFromXY((1 / res * (lon - extent.left)), │ │ │ │ + (1 / res * (extent.top - lat))); │ │ │ │ + }, │ │ │ │ │ │ │ │ - var type, symbolizer; │ │ │ │ - if (this.multipleSymbolizers && rule.symbolizers) { │ │ │ │ - var symbolizer; │ │ │ │ - for (var i = 0, ii = rule.symbolizers.length; i < ii; ++i) { │ │ │ │ - symbolizer = rule.symbolizers[i]; │ │ │ │ - type = symbolizer.CLASS_NAME.split(".").pop(); │ │ │ │ - this.writeNode( │ │ │ │ - type + "Symbolizer", symbolizer, node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - // add in symbolizers (relies on geometry type keys) │ │ │ │ - var types = OpenLayers.Style.SYMBOLIZER_PREFIXES; │ │ │ │ - for (var i = 0, len = types.length; i < len; ++i) { │ │ │ │ - type = types[i]; │ │ │ │ - symbolizer = rule.symbolizer[type]; │ │ │ │ - if (symbolizer) { │ │ │ │ - this.writeNode( │ │ │ │ - type + "Symbolizer", symbolizer, node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setMapObjectCenter │ │ │ │ + * Set the mapObject to the specified center and zoom │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * center - {Object} MapObject LonLat format │ │ │ │ + * zoom - {int} MapObject zoom format │ │ │ │ + */ │ │ │ │ + setMapObjectCenter: function(center, zoom) { │ │ │ │ + if (this.animationEnabled === false && zoom != this.mapObject.zoom) { │ │ │ │ + var mapContainer = this.getMapContainer(); │ │ │ │ + google.maps.event.addListenerOnce( │ │ │ │ + this.mapObject, │ │ │ │ + "idle", │ │ │ │ + function() { │ │ │ │ + mapContainer.style.visibility = ""; │ │ │ │ } │ │ │ │ - return node; │ │ │ │ + ); │ │ │ │ + mapContainer.style.visibility = "hidden"; │ │ │ │ + } │ │ │ │ + this.mapObject.setOptions({ │ │ │ │ + center: center, │ │ │ │ + zoom: zoom │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ │ │ │ │ - }, │ │ │ │ - "ElseFilter": function() { │ │ │ │ - return this.createElementNSPlus("sld:ElseFilter"); │ │ │ │ - }, │ │ │ │ - "MinScaleDenominator": function(scale) { │ │ │ │ - return this.createElementNSPlus( │ │ │ │ - "sld:MinScaleDenominator", { │ │ │ │ - value: scale │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "MaxScaleDenominator": function(scale) { │ │ │ │ - return this.createElementNSPlus( │ │ │ │ - "sld:MaxScaleDenominator", { │ │ │ │ - value: scale │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "LineSymbolizer": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:LineSymbolizer"); │ │ │ │ - this.writeNode("Stroke", symbolizer, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Stroke": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:Stroke"); │ │ │ │ │ │ │ │ - // GraphicFill here │ │ │ │ - // GraphicStroke here │ │ │ │ + // Bounds │ │ │ │ │ │ │ │ - // add in CssParameters │ │ │ │ - if (symbolizer.strokeColor != undefined) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "strokeColor" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.strokeOpacity != undefined) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "strokeOpacity" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.strokeWidth != undefined) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "strokeWidth" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.strokeDashstyle != undefined && symbolizer.strokeDashstyle !== "solid") { │ │ │ │ - // assumes valid stroke-dasharray value │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "strokeDashstyle" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.strokeLinecap != undefined) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "strokeLinecap" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "CssParameter": function(obj) { │ │ │ │ - // not handling ogc:expressions for now │ │ │ │ - return this.createElementNSPlus("sld:CssParameter", { │ │ │ │ - attributes: { │ │ │ │ - name: this.getCssProperty(obj.key) │ │ │ │ - }, │ │ │ │ - value: obj.symbolizer[obj.key] │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "TextSymbolizer": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:TextSymbolizer"); │ │ │ │ - // add in optional Label │ │ │ │ - if (symbolizer.label != null) { │ │ │ │ - this.writeNode("Label", symbolizer.label, node); │ │ │ │ - } │ │ │ │ - // add in optional Font │ │ │ │ - if (symbolizer.fontFamily != null || │ │ │ │ - symbolizer.fontSize != null || │ │ │ │ - symbolizer.fontWeight != null || │ │ │ │ - symbolizer.fontStyle != null) { │ │ │ │ - this.writeNode("Font", symbolizer, node); │ │ │ │ - } │ │ │ │ - // add in optional LabelPlacement │ │ │ │ - if (symbolizer.labelAnchorPointX != null || │ │ │ │ - symbolizer.labelAnchorPointY != null || │ │ │ │ - symbolizer.labelAlign != null || │ │ │ │ - symbolizer.labelXOffset != null || │ │ │ │ - symbolizer.labelYOffset != null || │ │ │ │ - symbolizer.labelRotation != null || │ │ │ │ - symbolizer.labelPerpendicularOffset != null) { │ │ │ │ - this.writeNode("LabelPlacement", symbolizer, node); │ │ │ │ - } │ │ │ │ - // add in optional Halo │ │ │ │ - if (symbolizer.haloRadius != null || │ │ │ │ - symbolizer.haloColor != null || │ │ │ │ - symbolizer.haloOpacity != null) { │ │ │ │ - this.writeNode("Halo", symbolizer, node); │ │ │ │ - } │ │ │ │ - // add in optional Fill │ │ │ │ - if (symbolizer.fontColor != null || │ │ │ │ - symbolizer.fontOpacity != null) { │ │ │ │ - this.writeNode("Fill", { │ │ │ │ - fillColor: symbolizer.fontColor, │ │ │ │ - fillOpacity: symbolizer.fontOpacity │ │ │ │ - }, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "LabelPlacement": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:LabelPlacement"); │ │ │ │ - // PointPlacement and LinePlacement are choices, so don't output both │ │ │ │ - if ((symbolizer.labelAnchorPointX != null || │ │ │ │ - symbolizer.labelAnchorPointY != null || │ │ │ │ - symbolizer.labelAlign != null || │ │ │ │ - symbolizer.labelXOffset != null || │ │ │ │ - symbolizer.labelYOffset != null || │ │ │ │ - symbolizer.labelRotation != null) && │ │ │ │ - symbolizer.labelPerpendicularOffset == null) { │ │ │ │ - this.writeNode("PointPlacement", symbolizer, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.labelPerpendicularOffset != null) { │ │ │ │ - this.writeNode("LinePlacement", symbolizer, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "LinePlacement": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:LinePlacement"); │ │ │ │ - this.writeNode("PerpendicularOffset", symbolizer.labelPerpendicularOffset, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "PerpendicularOffset": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:PerpendicularOffset", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "PointPlacement": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:PointPlacement"); │ │ │ │ - if (symbolizer.labelAnchorPointX != null || │ │ │ │ - symbolizer.labelAnchorPointY != null || │ │ │ │ - symbolizer.labelAlign != null) { │ │ │ │ - this.writeNode("AnchorPoint", symbolizer, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.labelXOffset != null || │ │ │ │ - symbolizer.labelYOffset != null) { │ │ │ │ - this.writeNode("Displacement", symbolizer, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.labelRotation != null) { │ │ │ │ - this.writeNode("Rotation", symbolizer.labelRotation, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "AnchorPoint": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:AnchorPoint"); │ │ │ │ - var x = symbolizer.labelAnchorPointX, │ │ │ │ - y = symbolizer.labelAnchorPointY; │ │ │ │ - if (x != null) { │ │ │ │ - this.writeNode("AnchorPointX", x, node); │ │ │ │ - } │ │ │ │ - if (y != null) { │ │ │ │ - this.writeNode("AnchorPointY", y, node); │ │ │ │ - } │ │ │ │ - if (x == null && y == null) { │ │ │ │ - var xAlign = symbolizer.labelAlign.substr(0, 1), │ │ │ │ - yAlign = symbolizer.labelAlign.substr(1, 1); │ │ │ │ - if (xAlign === "l") { │ │ │ │ - x = 0; │ │ │ │ - } else if (xAlign === "c") { │ │ │ │ - x = 0.5; │ │ │ │ - } else if (xAlign === "r") { │ │ │ │ - x = 1; │ │ │ │ - } │ │ │ │ - if (yAlign === "b") { │ │ │ │ - y = 0; │ │ │ │ - } else if (yAlign === "m") { │ │ │ │ - y = 0.5; │ │ │ │ - } else if (yAlign === "t") { │ │ │ │ - y = 1; │ │ │ │ - } │ │ │ │ - this.writeNode("AnchorPointX", x, node); │ │ │ │ - this.writeNode("AnchorPointY", y, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "AnchorPointX": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:AnchorPointX", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "AnchorPointY": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:AnchorPointY", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Displacement": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:Displacement"); │ │ │ │ - if (symbolizer.labelXOffset != null) { │ │ │ │ - this.writeNode("DisplacementX", symbolizer.labelXOffset, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.labelYOffset != null) { │ │ │ │ - this.writeNode("DisplacementY", symbolizer.labelYOffset, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "DisplacementX": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:DisplacementX", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "DisplacementY": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:DisplacementY", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Font": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:Font"); │ │ │ │ - // add in CssParameters │ │ │ │ - if (symbolizer.fontFamily) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "fontFamily" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.fontSize) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "fontSize" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.fontWeight) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "fontWeight" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.fontStyle) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "fontStyle" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Label": function(label) { │ │ │ │ - return this.writers.sld._OGCExpression.call( │ │ │ │ - this, "sld:Label", label │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "Halo": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:Halo"); │ │ │ │ - if (symbolizer.haloRadius) { │ │ │ │ - this.writeNode("Radius", symbolizer.haloRadius, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.haloColor || symbolizer.haloOpacity) { │ │ │ │ - this.writeNode("Fill", { │ │ │ │ - fillColor: symbolizer.haloColor, │ │ │ │ - fillOpacity: symbolizer.haloOpacity │ │ │ │ - }, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Radius": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:Radius", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "RasterSymbolizer": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:RasterSymbolizer"); │ │ │ │ - if (symbolizer.geometry) { │ │ │ │ - this.writeNode("Geometry", symbolizer.geometry, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.opacity) { │ │ │ │ - this.writeNode("Opacity", symbolizer.opacity, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.colorMap) { │ │ │ │ - this.writeNode("ColorMap", symbolizer.colorMap, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Geometry": function(geometry) { │ │ │ │ - var node = this.createElementNSPlus("sld:Geometry"); │ │ │ │ - if (geometry.property) { │ │ │ │ - this.writeNode("ogc:PropertyName", geometry, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ColorMap": function(colorMap) { │ │ │ │ - var node = this.createElementNSPlus("sld:ColorMap"); │ │ │ │ - for (var i = 0, len = colorMap.length; i < len; ++i) { │ │ │ │ - this.writeNode("ColorMapEntry", colorMap[i], node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ColorMapEntry": function(colorMapEntry) { │ │ │ │ - var node = this.createElementNSPlus("sld:ColorMapEntry"); │ │ │ │ - var a = colorMapEntry; │ │ │ │ - node.setAttribute("color", a.color); │ │ │ │ - a.opacity !== undefined && node.setAttribute("opacity", │ │ │ │ - parseFloat(a.opacity)); │ │ │ │ - a.quantity !== undefined && node.setAttribute("quantity", │ │ │ │ - parseFloat(a.quantity)); │ │ │ │ - a.label !== undefined && node.setAttribute("label", a.label); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "PolygonSymbolizer": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:PolygonSymbolizer"); │ │ │ │ - if (symbolizer.fill !== false) { │ │ │ │ - this.writeNode("Fill", symbolizer, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.stroke !== false) { │ │ │ │ - this.writeNode("Stroke", symbolizer, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Fill": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:Fill"); │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectZoomFromMapObjectBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moBounds - {Object} MapObject Bounds format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Zoom for specified MapObject Bounds │ │ │ │ + */ │ │ │ │ + getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ + return this.mapObject.getBoundsZoomLevel(moBounds); │ │ │ │ + }, │ │ │ │ │ │ │ │ - // GraphicFill here │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Primitives * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ │ │ │ │ - // add in CssParameters │ │ │ │ - if (symbolizer.fillColor) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "fillColor" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.fillOpacity != null) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "fillOpacity" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "PointSymbolizer": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:PointSymbolizer"); │ │ │ │ - this.writeNode("Graphic", symbolizer, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Graphic": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:Graphic"); │ │ │ │ - if (symbolizer.externalGraphic != undefined) { │ │ │ │ - this.writeNode("ExternalGraphic", symbolizer, node); │ │ │ │ - } else { │ │ │ │ - this.writeNode("Mark", symbolizer, node); │ │ │ │ - } │ │ │ │ │ │ │ │ - if (symbolizer.graphicOpacity != undefined) { │ │ │ │ - this.writeNode("Opacity", symbolizer.graphicOpacity, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.pointRadius != undefined) { │ │ │ │ - this.writeNode("Size", symbolizer.pointRadius * 2, node); │ │ │ │ - } else if (symbolizer.graphicWidth != undefined) { │ │ │ │ - this.writeNode("Size", symbolizer.graphicWidth, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.rotation != undefined) { │ │ │ │ - this.writeNode("Rotation", symbolizer.rotation, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ExternalGraphic": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:ExternalGraphic"); │ │ │ │ - this.writeNode( │ │ │ │ - "OnlineResource", symbolizer.externalGraphic, node │ │ │ │ - ); │ │ │ │ - var format = symbolizer.graphicFormat || │ │ │ │ - this.getGraphicFormat(symbolizer.externalGraphic); │ │ │ │ - this.writeNode("Format", format, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Mark": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:Mark"); │ │ │ │ - if (symbolizer.graphicName) { │ │ │ │ - this.writeNode("WellKnownName", symbolizer.graphicName, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.fill !== false) { │ │ │ │ - this.writeNode("Fill", symbolizer, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.stroke !== false) { │ │ │ │ - this.writeNode("Stroke", symbolizer, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "WellKnownName": function(name) { │ │ │ │ - return this.createElementNSPlus("sld:WellKnownName", { │ │ │ │ - value: name │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Opacity": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:Opacity", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Size": function(value) { │ │ │ │ - return this.writers.sld._OGCExpression.call( │ │ │ │ - this, "sld:Size", value │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "Rotation": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:Rotation", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "OnlineResource": function(href) { │ │ │ │ - return this.createElementNSPlus("sld:OnlineResource", { │ │ │ │ - attributes: { │ │ │ │ - "xlink:type": "simple", │ │ │ │ - "xlink:href": href │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Format": function(format) { │ │ │ │ - return this.createElementNSPlus("sld:Format", { │ │ │ │ - value: format │ │ │ │ - }); │ │ │ │ - } │ │ │ │ + // LonLat │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectLonLatFromLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * lon - {Float} │ │ │ │ + * lat - {Float} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject LonLat built from lon and lat params │ │ │ │ + */ │ │ │ │ + getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ + var gLatLng; │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + var lonlat = this.inverseMercator(lon, lat); │ │ │ │ + gLatLng = new google.maps.LatLng(lonlat.lat, lonlat.lon); │ │ │ │ + } else { │ │ │ │ + gLatLng = new google.maps.LatLng(lat, lon); │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.Filter.v1_0_0.prototype.writers), │ │ │ │ + return gLatLng; │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SLD.v1" │ │ │ │ + // Pixel │ │ │ │ │ │ │ │ -}); │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectPixelFromXY │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * x - {Integer} │ │ │ │ + * y - {Integer} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Pixel from x and y parameters │ │ │ │ + */ │ │ │ │ + getMapObjectPixelFromXY: function(x, y) { │ │ │ │ + return new google.maps.Point(x, y); │ │ │ │ + } │ │ │ │ + │ │ │ │ +}; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/SLD/v1_0_0.js │ │ │ │ + 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/Format/SLD/v1.js │ │ │ │ - * @requires OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ + * @requires OpenLayers/Layer/Vector.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.SLD.v1_0_0 │ │ │ │ - * Write SLD version 1.0.0. │ │ │ │ - * │ │ │ │ + * 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.Format.SLD.v1> │ │ │ │ + * - <OpenLayers.Layer.Vector> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.SLD.v1_0_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.SLD.v1, { │ │ │ │ +OpenLayers.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: VERSION │ │ │ │ - * {String} 1.0.0 │ │ │ │ - */ │ │ │ │ - VERSION: "1.0.0", │ │ │ │ + /** │ │ │ │ + * Property: displayInLayerSwitcher │ │ │ │ + * Set to false for this layer type │ │ │ │ + */ │ │ │ │ + displayInLayerSwitcher: false, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} http://www.opengis.net/sld │ │ │ │ - * http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd │ │ │ │ - */ │ │ │ │ - schemaLocation: "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd", │ │ │ │ + /** │ │ │ │ + * APIProperty: layers │ │ │ │ + * Layers that are attached to this container. Required config option. │ │ │ │ + */ │ │ │ │ + layers: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.SLD.v1_0_0 │ │ │ │ - * Instances of this class are not created directly. Use the │ │ │ │ - * <OpenLayers.Format.SLD> constructor instead. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ + /** │ │ │ │ + * 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 │ │ │ │ + */ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0" │ │ │ │ + /** │ │ │ │ + * 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/SLDSelect.js │ │ │ │ + OpenLayers/Protocol/SOS.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/Layer/WMS.js │ │ │ │ - * @requires OpenLayers/Handler/RegularPolygon.js │ │ │ │ - * @requires OpenLayers/Handler/Polygon.js │ │ │ │ - * @requires OpenLayers/Handler/Path.js │ │ │ │ - * @requires OpenLayers/Handler/Click.js │ │ │ │ - * @requires OpenLayers/Filter/Spatial.js │ │ │ │ - * @requires OpenLayers/Format/SLD/v1_0_0.js │ │ │ │ + * @requires OpenLayers/Protocol.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.SLDSelect │ │ │ │ - * Perform selections on WMS layers using Styled Layer Descriptor (SLD) │ │ │ │ + * Function: OpenLayers.Protocol.SOS │ │ │ │ + * Used to create a versioned SOS protocol. Default version is 1.0.0. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Protocol>} An SOS protocol for the given version. │ │ │ │ + */ │ │ │ │ +OpenLayers.Protocol.SOS = function(options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults( │ │ │ │ + options, OpenLayers.Protocol.SOS.DEFAULTS │ │ │ │ + ); │ │ │ │ + var cls = OpenLayers.Protocol.SOS["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (!cls) { │ │ │ │ + throw "Unsupported SOS version: " + options.version; │ │ │ │ + } │ │ │ │ + return new cls(options); │ │ │ │ +}; │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Protocol.SOS.DEFAULTS │ │ │ │ + */ │ │ │ │ +OpenLayers.Protocol.SOS.DEFAULTS = { │ │ │ │ + "version": "1.0.0" │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + 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.Control> │ │ │ │ + * - <OpenLayers.Protocol> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.SLDSelect = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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>): │ │ │ │ - * selected - Triggered when a selection occurs. Listeners receive an │ │ │ │ - * event with *filters* and *layer* properties. Filters will be an │ │ │ │ - * array of OpenLayers.Filter objects created in order to perform │ │ │ │ - * the particular selection. │ │ │ │ + /** │ │ │ │ + * Property: url │ │ │ │ + * {String} Service URL, read-only, set through the options │ │ │ │ + * passed to constructor. │ │ │ │ */ │ │ │ │ + url: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: clearOnDeactivate │ │ │ │ - * {Boolean} Should the selection be cleared when the control is │ │ │ │ - * deactivated. Default value is false. │ │ │ │ + * Property: headers │ │ │ │ + * {Object} HTTP request headers, read-only, set through the options │ │ │ │ + * passed to the constructor, │ │ │ │ + * Example: {'Content-Type': 'plain/text'} │ │ │ │ */ │ │ │ │ - clearOnDeactivate: false, │ │ │ │ + headers: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layers │ │ │ │ - * {Array(<OpenLayers.Layer.WMS>)} The WMS layers this control will work │ │ │ │ - * on. │ │ │ │ + * Property: params │ │ │ │ + * {Object} Parameters of GET requests, read-only, set through the options │ │ │ │ + * passed to the constructor, │ │ │ │ + * Example: {'bbox': '5,5,5,5'} │ │ │ │ */ │ │ │ │ - layers: null, │ │ │ │ + params: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: callbacks │ │ │ │ - * {Object} The functions that are sent to the handler for callback │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - callbacks: null, │ │ │ │ + callback: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: selectionSymbolizer │ │ │ │ - * {Object} Determines the styling of the selected objects. Default is │ │ │ │ - * a selection in red. │ │ │ │ + * Property: scope │ │ │ │ + * {Object} Callback execution scope, read-only, set through the │ │ │ │ + * options passed to the constructor. │ │ │ │ */ │ │ │ │ - selectionSymbolizer: { │ │ │ │ - 'Polygon': { │ │ │ │ - fillColor: '#FF0000', │ │ │ │ - stroke: false │ │ │ │ - }, │ │ │ │ - 'Line': { │ │ │ │ - strokeColor: '#FF0000', │ │ │ │ - strokeWidth: 2 │ │ │ │ - }, │ │ │ │ - 'Point': { │ │ │ │ - graphicName: 'square', │ │ │ │ - fillColor: '#FF0000', │ │ │ │ - pointRadius: 5 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + scope: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layerOptions │ │ │ │ - * {Object} The options to apply to the selection layer, by default the │ │ │ │ - * selection layer will be kept out of the layer switcher. │ │ │ │ + * APIProperty: readWithPOST │ │ │ │ + * {Boolean} true if read operations are done with POST requests │ │ │ │ + * instead of GET, defaults to false. │ │ │ │ */ │ │ │ │ - layerOptions: null, │ │ │ │ + readWithPOST: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: handlerOptions │ │ │ │ - * {Object} Used to set non-default properties on the control's handler │ │ │ │ + * APIProperty: updateWithPOST │ │ │ │ + * {Boolean} true if update operations are done with POST requests │ │ │ │ + * defaults to false. │ │ │ │ */ │ │ │ │ + updateWithPOST: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: sketchStyle │ │ │ │ - * {<OpenLayers.Style>|Object} Style or symbolizer to use for the sketch │ │ │ │ - * handler. The recommended way of styling the sketch layer, however, is │ │ │ │ - * to configure an <OpenLayers.StyleMap> in the layerOptions of the │ │ │ │ - * <handlerOptions>: │ │ │ │ - * │ │ │ │ - * (code) │ │ │ │ - * new OpenLayers.Control.SLDSelect(OpenLayers.Handler.Path, { │ │ │ │ - * handlerOptions: { │ │ │ │ - * layerOptions: { │ │ │ │ - * styleMap: new OpenLayers.StyleMap({ │ │ │ │ - * "default": {strokeColor: "yellow"} │ │ │ │ - * }) │ │ │ │ - * } │ │ │ │ - * } │ │ │ │ - * }); │ │ │ │ - * (end) │ │ │ │ + * 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(). │ │ │ │ */ │ │ │ │ - sketchStyle: null, │ │ │ │ + deleteWithPOST: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: wfsCache │ │ │ │ - * {Object} Cache to use for storing parsed results from │ │ │ │ - * <OpenLayers.Format.WFSDescribeFeatureType.read>. If not provided, │ │ │ │ - * these will be cached on the prototype. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - wfsCache: {}, │ │ │ │ + wildcarded: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layerCache │ │ │ │ - * {Object} Cache to use for storing references to the selection layers. │ │ │ │ - * Normally each source layer will have exactly 1 selection layer of │ │ │ │ - * type OpenLayers.Layer.WMS. If not provided, layers will │ │ │ │ - * be cached on the prototype. Note that if <clearOnDeactivate> is │ │ │ │ - * true, the layer will no longer be cached after deactivating the │ │ │ │ - * control. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - layerCache: {}, │ │ │ │ + srsInBBOX: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.SLDSelect │ │ │ │ - * Create a new control for selecting features in WMS layers using │ │ │ │ - * Styled Layer Descriptor (SLD). │ │ │ │ + * Constructor: OpenLayers.Protocol.HTTP │ │ │ │ + * A class for giving layers generic HTTP protocol. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * handler - {<OpenLayers.Class>} A sketch handler class. This determines │ │ │ │ - * the type of selection, e.g. box (<OpenLayers.Handler.Box>), point │ │ │ │ - * (<OpenLayers.Handler.Point>), path (<OpenLayers.Handler.Path>) or │ │ │ │ - * polygon (<OpenLayers.Handler.Polygon>) selection. To use circle │ │ │ │ - * type selection, use <OpenLayers.Handler.RegularPolygon> and pass │ │ │ │ - * the number of desired sides (e.g. 40) as "sides" property to the │ │ │ │ - * <handlerOptions>. │ │ │ │ - * options - {Object} An object containing all configuration properties for │ │ │ │ - * the control. │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ * │ │ │ │ - * Valid options: │ │ │ │ - * layers - Array({<OpenLayers.Layer.WMS>}) The layers to perform the │ │ │ │ - * selection on. │ │ │ │ + * Valid options include: │ │ │ │ + * url - {String} │ │ │ │ + * headers - {Object} │ │ │ │ + * params - {Object} URL parameters for GET requests │ │ │ │ + * format - {<OpenLayers.Format>} │ │ │ │ + * callback - {Function} │ │ │ │ + * scope - {Object} │ │ │ │ */ │ │ │ │ - initialize: function(handler, options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + this.params = {}; │ │ │ │ + this.headers = {}; │ │ │ │ + OpenLayers.Protocol.prototype.initialize.apply(this, arguments); │ │ │ │ │ │ │ │ - this.callbacks = OpenLayers.Util.extend({ │ │ │ │ - done: this.select, │ │ │ │ - click: this.select │ │ │ │ - }, this.callbacks); │ │ │ │ - this.handlerOptions = this.handlerOptions || {}; │ │ │ │ - this.layerOptions = OpenLayers.Util.applyDefaults(this.layerOptions, { │ │ │ │ - displayInLayerSwitcher: false, │ │ │ │ - tileOptions: { │ │ │ │ - maxGetUrlLength: 2048 │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (this.sketchStyle) { │ │ │ │ - this.handlerOptions.layerOptions = OpenLayers.Util.applyDefaults( │ │ │ │ - this.handlerOptions.layerOptions, { │ │ │ │ - styleMap: new OpenLayers.StyleMap({ │ │ │ │ - "default": this.sketchStyle │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - ); │ │ │ │ + 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); │ │ │ │ + }; │ │ │ │ } │ │ │ │ - this.handler = new handler(this, this.callbacks, this.handlerOptions); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: destroy │ │ │ │ - * Take care of things that are not handled in superclass. │ │ │ │ + * Clean up the protocol. │ │ │ │ */ │ │ │ │ destroy: function() { │ │ │ │ - for (var key in this.layerCache) { │ │ │ │ - delete this.layerCache[key]; │ │ │ │ + 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 │ │ │ │ + ); │ │ │ │ } │ │ │ │ - for (var key in this.wfsCache) { │ │ │ │ - delete this.wfsCache[key]; │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ } │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + return resp; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: coupleLayerVisiblity │ │ │ │ - * Couple the selection layer and the source layer with respect to │ │ │ │ - * layer visibility. So if the source layer is turned off, the │ │ │ │ - * selection layer is also turned off. │ │ │ │ + * Method: handleRead │ │ │ │ + * Individual callbacks are created for read, create and update, should │ │ │ │ + * a subclass need to override each one separately. │ │ │ │ * │ │ │ │ - * Context: │ │ │ │ - * - {<OpenLayers.Layer>} │ │ │ │ + * 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: │ │ │ │ - * evt - {Object} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - coupleLayerVisiblity: function(evt) { │ │ │ │ - this.setVisibility(evt.object.getVisibility()); │ │ │ │ + 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: createSelectionLayer │ │ │ │ - * Creates a "clone" from the source layer in which the selection can │ │ │ │ - * be drawn. This ensures both the source layer and the selection are │ │ │ │ - * visible and not only the selection. │ │ │ │ + * Method: handleCreate │ │ │ │ + * Called the the request issued by <create> is complete. May be overridden │ │ │ │ + * by subclasses. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * source - {<OpenLayers.Layer.WMS>} The source layer on which the selection │ │ │ │ - * is performed. │ │ │ │ + * 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.Layer.WMS>} A WMS layer with maxGetUrlLength configured to 2048 │ │ │ │ - * since SLD selections can easily get quite long. │ │ │ │ + * {<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. │ │ │ │ */ │ │ │ │ - createSelectionLayer: function(source) { │ │ │ │ - // check if we already have a selection layer for the source layer │ │ │ │ - var selectionLayer; │ │ │ │ - if (!this.layerCache[source.id]) { │ │ │ │ - selectionLayer = new OpenLayers.Layer.WMS(source.name, │ │ │ │ - source.url, source.params, │ │ │ │ - OpenLayers.Util.applyDefaults( │ │ │ │ - this.layerOptions, │ │ │ │ - source.getOptions()) │ │ │ │ - ); │ │ │ │ - this.layerCache[source.id] = selectionLayer; │ │ │ │ - // make sure the layers are coupled wrt visibility, but only │ │ │ │ - // if they are not displayed in the layer switcher, because in │ │ │ │ - // that case the user cannot control visibility. │ │ │ │ - if (this.layerOptions.displayInLayerSwitcher === false) { │ │ │ │ - source.events.on({ │ │ │ │ - "visibilitychanged": this.coupleLayerVisiblity, │ │ │ │ - scope: selectionLayer │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - this.map.addLayer(selectionLayer); │ │ │ │ - } else { │ │ │ │ - selectionLayer = this.layerCache[source.id]; │ │ │ │ - } │ │ │ │ - return selectionLayer; │ │ │ │ + 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: createSLD │ │ │ │ - * Create the SLD document for the layer using the supplied filters. │ │ │ │ + * Method: handleUpdate │ │ │ │ + * Called the the request issued by <update> is complete. May be overridden │ │ │ │ + * by subclasses. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.WMS>} │ │ │ │ - * filters - Array({<OpenLayers.Filter>}) The filters to be applied. │ │ │ │ - * geometryAttributes - Array({Object}) The geometry attributes of the │ │ │ │ - * layer. │ │ │ │ + * 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: │ │ │ │ - * {String} The SLD document generated as a string. │ │ │ │ + * {<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. │ │ │ │ */ │ │ │ │ - createSLD: function(layer, filters, geometryAttributes) { │ │ │ │ - var sld = { │ │ │ │ - version: "1.0.0", │ │ │ │ - namedLayers: {} │ │ │ │ + "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 │ │ │ │ }; │ │ │ │ - var layerNames = [layer.params.LAYERS].join(",").split(","); │ │ │ │ - for (var i = 0, len = layerNames.length; i < len; i++) { │ │ │ │ - var name = layerNames[i]; │ │ │ │ - sld.namedLayers[name] = { │ │ │ │ - name: name, │ │ │ │ - userStyles: [] │ │ │ │ - }; │ │ │ │ - var symbolizer = this.selectionSymbolizer; │ │ │ │ - var geometryAttribute = geometryAttributes[i]; │ │ │ │ - if (geometryAttribute.type.indexOf('Polygon') >= 0) { │ │ │ │ - symbolizer = { │ │ │ │ - Polygon: this.selectionSymbolizer['Polygon'] │ │ │ │ - }; │ │ │ │ - } else if (geometryAttribute.type.indexOf('LineString') >= 0) { │ │ │ │ - symbolizer = { │ │ │ │ - Line: this.selectionSymbolizer['Line'] │ │ │ │ - }; │ │ │ │ - } else if (geometryAttribute.type.indexOf('Point') >= 0) { │ │ │ │ - symbolizer = { │ │ │ │ - Point: this.selectionSymbolizer['Point'] │ │ │ │ - }; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - var filter = filters[i]; │ │ │ │ - sld.namedLayers[name].userStyles.push({ │ │ │ │ - name: 'default', │ │ │ │ - rules: [ │ │ │ │ - new OpenLayers.Rule({ │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - filter: filter, │ │ │ │ - maxScaleDenominator: layer.options.minScale │ │ │ │ - }) │ │ │ │ - ] │ │ │ │ - }); │ │ │ │ + options.callback.call(options.scope, resp); │ │ │ │ } │ │ │ │ - return new OpenLayers.Format.SLD({ │ │ │ │ - srsName: this.map.getProjection() │ │ │ │ - }).write(sld); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseDescribeLayer │ │ │ │ - * Parse the SLD WMS DescribeLayer response and issue the corresponding │ │ │ │ - * WFS DescribeFeatureType request │ │ │ │ + * Method: parseFeatures │ │ │ │ + * Read HTTP response body and return features. │ │ │ │ * │ │ │ │ - * request - {XMLHttpRequest} The request object. │ │ │ │ + * Parameters: │ │ │ │ + * request - {XMLHttpRequest} The request object │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array({<OpenLayers.Feature.Vector>})} or │ │ │ │ + * {<OpenLayers.Feature.Vector>} Array of features or a single feature. │ │ │ │ */ │ │ │ │ - parseDescribeLayer: function(request) { │ │ │ │ - var format = new OpenLayers.Format.WMSDescribeLayer(); │ │ │ │ + parseFeatures: function(request) { │ │ │ │ var doc = request.responseXML; │ │ │ │ if (!doc || !doc.documentElement) { │ │ │ │ doc = request.responseText; │ │ │ │ } │ │ │ │ - var describeLayer = format.read(doc); │ │ │ │ - var typeNames = []; │ │ │ │ - var url = null; │ │ │ │ - for (var i = 0, len = describeLayer.length; i < len; i++) { │ │ │ │ - // perform a WFS DescribeFeatureType request │ │ │ │ - if (describeLayer[i].owsType == "WFS") { │ │ │ │ - typeNames.push(describeLayer[i].typeName); │ │ │ │ - url = describeLayer[i].owsURL; │ │ │ │ - } │ │ │ │ + if (!doc || doc.length <= 0) { │ │ │ │ + return null; │ │ │ │ } │ │ │ │ - var options = { │ │ │ │ - url: url, │ │ │ │ - params: { │ │ │ │ - SERVICE: "WFS", │ │ │ │ - TYPENAME: typeNames.toString(), │ │ │ │ - REQUEST: "DescribeFeatureType", │ │ │ │ - VERSION: "1.0.0" │ │ │ │ - }, │ │ │ │ - callback: function(request) { │ │ │ │ - var format = new OpenLayers.Format.WFSDescribeFeatureType(); │ │ │ │ - var doc = request.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = request.responseText; │ │ │ │ - } │ │ │ │ - var describeFeatureType = format.read(doc); │ │ │ │ - this.control.wfsCache[this.layer.id] = describeFeatureType; │ │ │ │ - this.control._queue && this.control.applySelection(); │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }; │ │ │ │ - OpenLayers.Request.GET(options); │ │ │ │ + return this.format.read(doc); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getGeometryAttributes │ │ │ │ - * Look up the geometry attributes from the WFS DescribeFeatureType response │ │ │ │ + * APIMethod: commit │ │ │ │ + * Iterate over each feature and take action based on the feature state. │ │ │ │ + * Possible actions are create, update and delete. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.WMS>} The layer for which to look up the │ │ │ │ - * geometry attributes. │ │ │ │ + * 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({Object}) Array of geometry attributes │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - getGeometryAttributes: function(layer) { │ │ │ │ - var result = []; │ │ │ │ - var cache = this.wfsCache[layer.id]; │ │ │ │ - for (var i = 0, len = cache.featureTypes.length; i < len; i++) { │ │ │ │ - var typeName = cache.featureTypes[i]; │ │ │ │ - var properties = typeName.properties; │ │ │ │ - for (var j = 0, lenj = properties.length; j < lenj; j++) { │ │ │ │ - var property = properties[j]; │ │ │ │ - var type = property.type; │ │ │ │ - if ((type.indexOf('LineString') >= 0) || │ │ │ │ - (type.indexOf('GeometryAssociationType') >= 0) || │ │ │ │ - (type.indexOf('GeometryPropertyType') >= 0) || │ │ │ │ - (type.indexOf('Point') >= 0) || │ │ │ │ - (type.indexOf('Polygon') >= 0)) { │ │ │ │ - result.push(property); │ │ │ │ - } │ │ │ │ + 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); │ │ │ │ } │ │ │ │ } │ │ │ │ - return result; │ │ │ │ - }, │ │ │ │ + // 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; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the control. Activating the control will perform a SLD WMS │ │ │ │ - * DescribeLayer request followed by a WFS DescribeFeatureType request │ │ │ │ - * so that the proper symbolizers can be chosen based on the geometry │ │ │ │ - * type. │ │ │ │ - */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ - var layer = this.layers[i]; │ │ │ │ - if (layer && !this.wfsCache[layer.id]) { │ │ │ │ - var options = { │ │ │ │ - url: layer.url, │ │ │ │ - params: { │ │ │ │ - SERVICE: "WMS", │ │ │ │ - VERSION: layer.params.VERSION, │ │ │ │ - LAYERS: layer.params.LAYERS, │ │ │ │ - REQUEST: "DescribeLayer" │ │ │ │ - }, │ │ │ │ - callback: this.parseDescribeLayer, │ │ │ │ - scope: { │ │ │ │ - layer: layer, │ │ │ │ - control: this │ │ │ │ - } │ │ │ │ - }; │ │ │ │ - OpenLayers.Request.GET(options); │ │ │ │ + // 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]); │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ + │ │ │ │ + // 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: deactivate │ │ │ │ - * Deactivate the control. If clearOnDeactivate is true, remove the │ │ │ │ - * selection layer(s). │ │ │ │ + * 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>} │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ - var layer = this.layers[i]; │ │ │ │ - if (layer && this.clearOnDeactivate === true) { │ │ │ │ - var layerCache = this.layerCache; │ │ │ │ - var selectionLayer = layerCache[layer.id]; │ │ │ │ - if (selectionLayer) { │ │ │ │ - layer.events.un({ │ │ │ │ - "visibilitychanged": this.coupleLayerVisiblity, │ │ │ │ - scope: selectionLayer │ │ │ │ - }); │ │ │ │ - selectionLayer.destroy(); │ │ │ │ - delete layerCache[layer.id]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + response.priv.abort(); │ │ │ │ } │ │ │ │ - return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setLayers │ │ │ │ - * Set the layers on which the selection should be performed. Call the │ │ │ │ - * setLayers method if the layer(s) to be used change and the same │ │ │ │ - * control should be used on a new set of layers. │ │ │ │ - * If the control is already active, it will be active after the new │ │ │ │ - * set of layers is set. │ │ │ │ + * 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: │ │ │ │ - * layers - {Array(<OpenLayers.Layer.WMS>)} The new set of layers on which │ │ │ │ - * the selection should be performed. │ │ │ │ + * resp - {<OpenLayers.Protocol.Response>} │ │ │ │ + * options - {Object} The map of options passed to the commit call. │ │ │ │ */ │ │ │ │ - setLayers: function(layers) { │ │ │ │ - if (this.active) { │ │ │ │ - this.deactivate(); │ │ │ │ - this.layers = layers; │ │ │ │ - this.activate(); │ │ │ │ - } else { │ │ │ │ - this.layers = layers; │ │ │ │ + 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/Protocol/CSW.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.CSW │ │ │ │ + * Used to create a versioned CSW protocol. Default version is 2.0.2. │ │ │ │ + */ │ │ │ │ +OpenLayers.Protocol.CSW = function(options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults( │ │ │ │ + options, OpenLayers.Protocol.CSW.DEFAULTS │ │ │ │ + ); │ │ │ │ + var cls = OpenLayers.Protocol.CSW["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (!cls) { │ │ │ │ + throw "Unsupported CSW version: " + options.version; │ │ │ │ + } │ │ │ │ + return new cls(options); │ │ │ │ +}; │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Protocol.CSW.DEFAULTS │ │ │ │ + */ │ │ │ │ +OpenLayers.Protocol.CSW.DEFAULTS = { │ │ │ │ + "version": "2.0.2" │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Protocol/Script.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/Feature/Vector.js │ │ │ │ + * @requires OpenLayers/Format/GeoJSON.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.Script │ │ │ │ + * A basic Script protocol for vector layers. Create a new instance with the │ │ │ │ + * <OpenLayers.Protocol.Script> constructor. A script protocol is used to │ │ │ │ + * get around the same origin policy. It works with services that return │ │ │ │ + * JSONP - that is, JSON wrapped in a client-specified callback. The │ │ │ │ + * protocol handles fetching and parsing of feature data and sends parsed │ │ │ │ + * features to the <callback> configured with the protocol. The protocol │ │ │ │ + * expects features serialized as GeoJSON by default, but can be configured │ │ │ │ + * to work with other formats by setting the <format> property. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Protocol> │ │ │ │ + */ │ │ │ │ +OpenLayers.Protocol.Script = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Function: createFilter │ │ │ │ - * Create the filter to be used in the SLD. │ │ │ │ + * APIProperty: url │ │ │ │ + * {String} Service URL. The service is expected to return serialized │ │ │ │ + * features wrapped in a named callback (where the callback name is │ │ │ │ + * generated by this protocol). │ │ │ │ + * Read-only, set through the options passed to the constructor. │ │ │ │ + */ │ │ │ │ + url: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: params │ │ │ │ + * {Object} Query string parameters to be appended to the URL. │ │ │ │ + * Read-only, set through the options passed to the constructor. │ │ │ │ + * Example: {maxFeatures: 50} │ │ │ │ + */ │ │ │ │ + params: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: callback │ │ │ │ + * {Object} Function to be called when the <read> operation completes. │ │ │ │ + */ │ │ │ │ + callback: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: callbackTemplate │ │ │ │ + * {String} Template for creating a unique callback function name │ │ │ │ + * for the registry. Should include ${id}. The ${id} variable will be │ │ │ │ + * replaced with a string identifier prefixed with a "c" (e.g. c1, c2). │ │ │ │ + * Default is "OpenLayers.Protocol.Script.registry.${id}". │ │ │ │ + */ │ │ │ │ + callbackTemplate: "OpenLayers.Protocol.Script.registry.${id}", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: callbackKey │ │ │ │ + * {String} The name of the query string parameter that the service │ │ │ │ + * recognizes as the callback identifier. Default is "callback". │ │ │ │ + * This key is used to generate the URL for the script. For example │ │ │ │ + * setting <callbackKey> to "myCallback" would result in a URL like │ │ │ │ + * http://example.com/?myCallback=... │ │ │ │ + */ │ │ │ │ + callbackKey: "callback", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: callbackPrefix │ │ │ │ + * {String} Where a service requires that the callback query string │ │ │ │ + * parameter value is prefixed by some string, this value may be set. │ │ │ │ + * For example, setting <callbackPrefix> to "foo:" would result in a │ │ │ │ + * URL like http://example.com/?callback=foo:... Default is "". │ │ │ │ + */ │ │ │ │ + callbackPrefix: "", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: scope │ │ │ │ + * {Object} Optional ``this`` object for the callback. Read-only, set │ │ │ │ + * through the options passed to the constructor. │ │ │ │ + */ │ │ │ │ + scope: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: format │ │ │ │ + * {<OpenLayers.Format>} Format for parsing features. Default is an │ │ │ │ + * <OpenLayers.Format.GeoJSON> format. If an alternative is provided, │ │ │ │ + * the format's read method must take an object and return an array │ │ │ │ + * of features. │ │ │ │ + */ │ │ │ │ + format: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: pendingRequests │ │ │ │ + * {Object} References all pending requests. Property names are script │ │ │ │ + * identifiers and property values are script elements. │ │ │ │ + */ │ │ │ │ + pendingRequests: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: srsInBBOX │ │ │ │ + * {Boolean} Include the SRS identifier in BBOX query string parameter. │ │ │ │ + * Setting this property has no effect if a custom filterToParams method │ │ │ │ + * is provided. 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.Script │ │ │ │ + * A class for giving layers generic Script protocol. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * geometryAttribute - {Object} Used to get the name of the geometry │ │ │ │ - * attribute which is needed for constructing the spatial filter. │ │ │ │ - * geometry - {<OpenLayers.Geometry>} The geometry to use. │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Filter.Spatial>} The spatial filter created. │ │ │ │ + * Valid options include: │ │ │ │ + * url - {String} │ │ │ │ + * params - {Object} │ │ │ │ + * callback - {Function} │ │ │ │ + * scope - {Object} │ │ │ │ */ │ │ │ │ - createFilter: function(geometryAttribute, geometry) { │ │ │ │ - var filter = null; │ │ │ │ - if (this.handler instanceof OpenLayers.Handler.RegularPolygon) { │ │ │ │ - // box │ │ │ │ - if (this.handler.irregular === true) { │ │ │ │ - filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ - property: geometryAttribute.name, │ │ │ │ - value: geometry.getBounds() │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ - property: geometryAttribute.name, │ │ │ │ - value: geometry │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } else if (this.handler instanceof OpenLayers.Handler.Polygon) { │ │ │ │ - filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ - property: geometryAttribute.name, │ │ │ │ - value: geometry │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + this.params = {}; │ │ │ │ + this.pendingRequests = {}; │ │ │ │ + OpenLayers.Protocol.prototype.initialize.apply(this, arguments); │ │ │ │ + if (!this.format) { │ │ │ │ + this.format = new OpenLayers.Format.GeoJSON(); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (!this.filterToParams && OpenLayers.Format.QueryStringFilter) { │ │ │ │ + var format = new OpenLayers.Format.QueryStringFilter({ │ │ │ │ + srsInBBOX: this.srsInBBOX │ │ │ │ }); │ │ │ │ - } else if (this.handler instanceof OpenLayers.Handler.Path) { │ │ │ │ - // if source layer is point based, use DWITHIN instead │ │ │ │ - if (geometryAttribute.type.indexOf('Point') >= 0) { │ │ │ │ - filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.DWITHIN, │ │ │ │ - property: geometryAttribute.name, │ │ │ │ - distance: this.map.getExtent().getWidth() * 0.01, │ │ │ │ - distanceUnits: this.map.getUnits(), │ │ │ │ - value: geometry │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ - property: geometryAttribute.name, │ │ │ │ - value: geometry │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } else if (this.handler instanceof OpenLayers.Handler.Click) { │ │ │ │ - if (geometryAttribute.type.indexOf('Polygon') >= 0) { │ │ │ │ - filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ - property: geometryAttribute.name, │ │ │ │ - value: geometry │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.DWITHIN, │ │ │ │ - property: geometryAttribute.name, │ │ │ │ - distance: this.map.getExtent().getWidth() * 0.01, │ │ │ │ - distanceUnits: this.map.getUnits(), │ │ │ │ - value: geometry │ │ │ │ - }); │ │ │ │ - } │ │ │ │ + this.filterToParams = function(filter, params) { │ │ │ │ + return format.write(filter, params); │ │ │ │ + }; │ │ │ │ } │ │ │ │ - return filter; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: select │ │ │ │ - * When the handler is done, use SLD_BODY on the selection layer to │ │ │ │ - * display the selection in the map. │ │ │ │ + * APIMethod: read │ │ │ │ + * Construct a request for reading new features. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * geometry - {Object} or {<OpenLayers.Geometry>} │ │ │ │ + * 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. │ │ │ │ + * filter - {<OpenLayers.Filter>} Filter to get serialized as a │ │ │ │ + * query string. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Protocol.Response>} A response object, whose "priv" property │ │ │ │ + * references the injected script. 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. │ │ │ │ */ │ │ │ │ - select: function(geometry) { │ │ │ │ - this._queue = function() { │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ - var layer = this.layers[i]; │ │ │ │ - var geometryAttributes = this.getGeometryAttributes(layer); │ │ │ │ - var filters = []; │ │ │ │ - for (var j = 0, lenj = geometryAttributes.length; j < lenj; j++) { │ │ │ │ - var geometryAttribute = geometryAttributes[j]; │ │ │ │ - if (geometryAttribute !== null) { │ │ │ │ - // from the click handler we will not get an actual │ │ │ │ - // geometry so transform │ │ │ │ - if (!(geometry instanceof OpenLayers.Geometry)) { │ │ │ │ - var point = this.map.getLonLatFromPixel( │ │ │ │ - geometry.xy); │ │ │ │ - geometry = new OpenLayers.Geometry.Point( │ │ │ │ - point.lon, point.lat); │ │ │ │ - } │ │ │ │ - var filter = this.createFilter(geometryAttribute, │ │ │ │ - geometry); │ │ │ │ - if (filter !== null) { │ │ │ │ - filters.push(filter); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + read: function(options) { │ │ │ │ + OpenLayers.Protocol.prototype.read.apply(this, arguments); │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ + options.params = OpenLayers.Util.applyDefaults( │ │ │ │ + options.params, this.options.params │ │ │ │ + ); │ │ │ │ + if (options.filter && this.filterToParams) { │ │ │ │ + options.params = this.filterToParams( │ │ │ │ + options.filter, options.params │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + var response = new OpenLayers.Protocol.Response({ │ │ │ │ + requestType: "read" │ │ │ │ + }); │ │ │ │ + var request = this.createRequest( │ │ │ │ + options.url, │ │ │ │ + options.params, │ │ │ │ + OpenLayers.Function.bind(function(data) { │ │ │ │ + response.data = data; │ │ │ │ + this.handleRead(response, options); │ │ │ │ + }, this) │ │ │ │ + ); │ │ │ │ + response.priv = request; │ │ │ │ + return response; │ │ │ │ + }, │ │ │ │ │ │ │ │ - var selectionLayer = this.createSelectionLayer(layer); │ │ │ │ + /** │ │ │ │ + * 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, any filter will not be serialized. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * filter - {<OpenLayers.Filter>} filter to convert. │ │ │ │ + * params - {Object} The parameters object. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} The resulting parameters object. │ │ │ │ + */ │ │ │ │ │ │ │ │ - this.events.triggerEvent("selected", { │ │ │ │ - layer: layer, │ │ │ │ - filters: filters │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * Method: createRequest │ │ │ │ + * Issues a request for features by creating injecting a script in the │ │ │ │ + * document head. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * url - {String} Service URL. │ │ │ │ + * params - {Object} Query string parameters. │ │ │ │ + * callback - {Function} Callback to be called with resulting data. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {HTMLScriptElement} The script pending execution. │ │ │ │ + */ │ │ │ │ + createRequest: function(url, params, callback) { │ │ │ │ + var id = OpenLayers.Protocol.Script.register(callback); │ │ │ │ + var name = OpenLayers.String.format(this.callbackTemplate, { │ │ │ │ + id: id │ │ │ │ + }); │ │ │ │ + params = OpenLayers.Util.extend({}, params); │ │ │ │ + params[this.callbackKey] = this.callbackPrefix + name; │ │ │ │ + url = OpenLayers.Util.urlAppend( │ │ │ │ + url, OpenLayers.Util.getParameterString(params) │ │ │ │ + ); │ │ │ │ + var script = document.createElement("script"); │ │ │ │ + script.type = "text/javascript"; │ │ │ │ + script.src = url; │ │ │ │ + script.id = "OpenLayers_Protocol_Script_" + id; │ │ │ │ + this.pendingRequests[script.id] = script; │ │ │ │ + var head = document.getElementsByTagName("head")[0]; │ │ │ │ + head.appendChild(script); │ │ │ │ + return script; │ │ │ │ + }, │ │ │ │ │ │ │ │ - var sld = this.createSLD(layer, filters, geometryAttributes); │ │ │ │ + /** │ │ │ │ + * Method: destroyRequest │ │ │ │ + * Remove a script node associated with a response from the document. Also │ │ │ │ + * unregisters the callback and removes the script from the │ │ │ │ + * <pendingRequests> object. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * script - {HTMLScriptElement} │ │ │ │ + */ │ │ │ │ + destroyRequest: function(script) { │ │ │ │ + OpenLayers.Protocol.Script.unregister(script.id.split("_").pop()); │ │ │ │ + delete this.pendingRequests[script.id]; │ │ │ │ + if (script.parentNode) { │ │ │ │ + script.parentNode.removeChild(script); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - selectionLayer.mergeNewParams({ │ │ │ │ - SLD_BODY: sld │ │ │ │ - }); │ │ │ │ - delete this._queue; │ │ │ │ + /** │ │ │ │ + * Method: handleRead │ │ │ │ + * Individual callbacks are created for read, create and update, should │ │ │ │ + * a subclass need to override each one separately. │ │ │ │ + * │ │ │ │ + * 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) { │ │ │ │ + this.handleResponse(response, options); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: handleResponse │ │ │ │ + * Called by CRUD specific handlers. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * response - {<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(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + if (response.data) { │ │ │ │ + response.features = this.parseFeatures(response.data); │ │ │ │ + response.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ + } else { │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ } │ │ │ │ - }; │ │ │ │ - this.applySelection(); │ │ │ │ + this.destroyRequest(response.priv); │ │ │ │ + options.callback.call(options.scope, response); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: applySelection │ │ │ │ - * Checks if all required wfs data is cached, and applies the selection │ │ │ │ + * Method: parseFeatures │ │ │ │ + * Read Script response body and return features. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {Object} The data sent to the callback function by the server. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array({<OpenLayers.Feature.Vector>})} or │ │ │ │ + * {<OpenLayers.Feature.Vector>} Array of features or a single feature. │ │ │ │ */ │ │ │ │ - applySelection: function() { │ │ │ │ - var canApply = true; │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ - if (!this.wfsCache[this.layers[i].id]) { │ │ │ │ - canApply = false; │ │ │ │ - break; │ │ │ │ + parseFeatures: function(data) { │ │ │ │ + return this.format.read(data); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: abort │ │ │ │ + * Abort an ongoing request. If no response is provided, all pending │ │ │ │ + * requests will be aborted. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} The response object returned │ │ │ │ + * from a <read> request. │ │ │ │ + */ │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + this.destroyRequest(response.priv); │ │ │ │ + } else { │ │ │ │ + for (var key in this.pendingRequests) { │ │ │ │ + this.destroyRequest(this.pendingRequests[key]); │ │ │ │ } │ │ │ │ } │ │ │ │ - canApply && this._queue.call(this); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.SLDSelect" │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Clean up the protocol. │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + this.abort(); │ │ │ │ + delete this.params; │ │ │ │ + delete this.format; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.Script" │ │ │ │ }); │ │ │ │ + │ │ │ │ +(function() { │ │ │ │ + var o = OpenLayers.Protocol.Script; │ │ │ │ + var counter = 0; │ │ │ │ + o.registry = {}; │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Function: OpenLayers.Protocol.Script.register │ │ │ │ + * Register a callback for a newly created script. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * callback - {Function} The callback to be executed when the newly added │ │ │ │ + * script loads. This callback will be called with a single argument │ │ │ │ + * that is the JSON returned by the service. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Number} An identifier for retrieving the registered callback. │ │ │ │ + */ │ │ │ │ + o.register = function(callback) { │ │ │ │ + var id = "c" + (++counter); │ │ │ │ + o.registry[id] = function() { │ │ │ │ + callback.apply(this, arguments); │ │ │ │ + }; │ │ │ │ + return id; │ │ │ │ + }; │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Function: OpenLayers.Protocol.Script.unregister │ │ │ │ + * Unregister a callback previously registered with the register function. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * id - {Number} The identifer returned by the register function. │ │ │ │ + */ │ │ │ │ + o.unregister = function(id) { │ │ │ │ + delete o.registry[id]; │ │ │ │ + }; │ │ │ │ +})(); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Button.js │ │ │ │ + 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/Control.js │ │ │ │ + * @requires OpenLayers/Protocol.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Button │ │ │ │ - * The Button control is a very simple push-button, for use with │ │ │ │ - * <OpenLayers.Control.Panel>. │ │ │ │ - * When clicked, the function trigger() is executed. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * Class: OpenLayers.Protocol.WFS │ │ │ │ + * Used to create a versioned WFS protocol. Default version is 1.0.0. │ │ │ │ * │ │ │ │ - * Use: │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Protocol>} A WFS protocol of the given version. │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ * (code) │ │ │ │ - * var button = new OpenLayers.Control.Button({ │ │ │ │ - * displayClass: "MyButton", trigger: myFunction │ │ │ │ - * }); │ │ │ │ - * panel.addControls([button]); │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Will create a button with CSS class MyButtonItemInactive, that │ │ │ │ - * will call the function MyFunction() when clicked. │ │ │ │ + * 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.Control.Button = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +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/Format/SOSGetFeatureOfInterest.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/v3.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.SOSGetFeatureOfInterest │ │ │ │ + * Read and write SOS GetFeatureOfInterest. This is used to get to │ │ │ │ + * the location of the features (stations). The stations can have 1 or more │ │ │ │ + * sensors. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.SOSGetFeatureOfInterest = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.XML, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: VERSION │ │ │ │ + * {String} 1.0.0 │ │ │ │ + */ │ │ │ │ + VERSION: "1.0.0", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + */ │ │ │ │ + namespaces: { │ │ │ │ + sos: "http://www.opengis.net/sos/1.0", │ │ │ │ + gml: "http://www.opengis.net/gml", │ │ │ │ + sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} Schema location │ │ │ │ + */ │ │ │ │ + schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosAll.xsd", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: defaultPrefix │ │ │ │ + */ │ │ │ │ + defaultPrefix: "sos", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ + */ │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.SOSGetFeatureOfInterest │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Parse a GetFeatureOfInterest response and return an array 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]); │ │ │ │ + } │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var info = { │ │ │ │ + features: [] │ │ │ │ + }; │ │ │ │ + this.readNode(data, info); │ │ │ │ + │ │ │ │ + var features = []; │ │ │ │ + for (var i = 0, len = info.features.length; i < len; i++) { │ │ │ │ + var container = info.features[i]; │ │ │ │ + // reproject features if needed │ │ │ │ + if (this.internalProjection && this.externalProjection && │ │ │ │ + container.components[0]) { │ │ │ │ + container.components[0].transform( │ │ │ │ + this.externalProjection, this.internalProjection │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + var feature = new OpenLayers.Feature.Vector( │ │ │ │ + container.components[0], container.attributes); │ │ │ │ + features.push(feature); │ │ │ │ + } │ │ │ │ + return 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: { │ │ │ │ + "sa": { │ │ │ │ + "SamplingPoint": function(node, obj) { │ │ │ │ + // sampling point can also be without a featureMember if │ │ │ │ + // there is only 1 │ │ │ │ + if (!obj.attributes) { │ │ │ │ + var feature = { │ │ │ │ + attributes: {} │ │ │ │ + }; │ │ │ │ + obj.features.push(feature); │ │ │ │ + obj = feature; │ │ │ │ + } │ │ │ │ + obj.attributes.id = this.getAttributeNS(node, │ │ │ │ + this.namespaces.gml, "id"); │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "position": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "gml": OpenLayers.Util.applyDefaults({ │ │ │ │ + "FeatureCollection": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "featureMember": function(node, obj) { │ │ │ │ + var feature = { │ │ │ │ + attributes: {} │ │ │ │ + }; │ │ │ │ + obj.features.push(feature); │ │ │ │ + this.readChildNodes(node, feature); │ │ │ │ + }, │ │ │ │ + "name": function(node, obj) { │ │ │ │ + obj.attributes.name = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "pos": function(node, obj) { │ │ │ │ + // we need to parse the srsName to get to the │ │ │ │ + // externalProjection, that's why we cannot use │ │ │ │ + // GML v3 for this │ │ │ │ + if (!this.externalProjection) { │ │ │ │ + this.externalProjection = new OpenLayers.Projection( │ │ │ │ + node.getAttribute("srsName")); │ │ │ │ + } │ │ │ │ + OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply( │ │ │ │ + this, [node, obj]); │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.GML.v3.prototype.readers.gml) │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "sos": { │ │ │ │ + "GetFeatureOfInterest": function(options) { │ │ │ │ + var node = this.createElementNSPlus("GetFeatureOfInterest", { │ │ │ │ + attributes: { │ │ │ │ + version: this.VERSION, │ │ │ │ + service: 'SOS', │ │ │ │ + "xsi:schemaLocation": this.schemaLocation │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + for (var i = 0, len = options.fois.length; i < len; i++) { │ │ │ │ + this.writeNode("FeatureOfInterestId", { │ │ │ │ + foi: options.fois[i] │ │ │ │ + }, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "FeatureOfInterestId": function(options) { │ │ │ │ + var node = this.createElementNSPlus("FeatureOfInterestId", { │ │ │ │ + value: options.foi │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SOSGetFeatureOfInterest" │ │ │ │ + │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Protocol/SOS/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/SOS.js │ │ │ │ + * @requires OpenLayers/Format/SOSGetFeatureOfInterest.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Protocol.SOS.v1_0_0 │ │ │ │ + * An SOS v1.0.0 Protocol for vector layers. Create a new instance with the │ │ │ │ + * <OpenLayers.Protocol.SOS.v1_0_0> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Protocol> │ │ │ │ + */ │ │ │ │ +OpenLayers.Protocol.SOS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Property: type │ │ │ │ - * {Integer} OpenLayers.Control.TYPE_BUTTON. │ │ │ │ + * APIProperty: fois │ │ │ │ + * {Array(String)} Array of features of interest (foi) │ │ │ │ */ │ │ │ │ - type: OpenLayers.Control.TYPE_BUTTON, │ │ │ │ + fois: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: trigger │ │ │ │ - * Called by a control panel when the button is clicked. │ │ │ │ + * 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, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Protocol.SOS │ │ │ │ + * A class for giving layers an SOS 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). │ │ │ │ + * fois - {Array} The features of interest (required). │ │ │ │ + */ │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ + if (!options.format) { │ │ │ │ + this.format = new OpenLayers.Format.SOSGetFeatureOfInterest( │ │ │ │ + this.formatOptions); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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 sensor positions. This is done by │ │ │ │ + * issuing one GetFeatureOfInterest request. │ │ │ │ + */ │ │ │ │ + read: function(options) { │ │ │ │ + options = OpenLayers.Util.extend({}, options); │ │ │ │ + OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ + var response = new OpenLayers.Protocol.Response({ │ │ │ │ + requestType: "read" │ │ │ │ + }); │ │ │ │ + var format = this.format; │ │ │ │ + var data = OpenLayers.Format.XML.prototype.write.apply(format, │ │ │ │ + [format.writeNode("sos:GetFeatureOfInterest", { │ │ │ │ + fois: this.fois │ │ │ │ + })] │ │ │ │ + ); │ │ │ │ + response.priv = OpenLayers.Request.POST({ │ │ │ │ + url: options.url, │ │ │ │ + callback: this.createCallback(this.handleRead, response, options), │ │ │ │ + data: data │ │ │ │ + }); │ │ │ │ + return response; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ + if (options.callback) { │ │ │ │ + var request = response.priv; │ │ │ │ + if (request.status >= 200 && request.status < 300) { │ │ │ │ + // success │ │ │ │ + response.features = this.parseFeatures(request); │ │ │ │ + response.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ + } else { │ │ │ │ + // failure │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ + } │ │ │ │ + options.callback.call(options.scope, response); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseFeatures │ │ │ │ + * Read HTTP response body and return features │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * request - {XMLHttpRequest} The request object │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array({<OpenLayers.Feature.Vector>})} Array of features │ │ │ │ */ │ │ │ │ - trigger: function() {}, │ │ │ │ + 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); │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Button" │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.SOS.v1_0_0" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/NavigationHistory.js │ │ │ │ + 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/Control.js │ │ │ │ - * @requires OpenLayers/Control/Button.js │ │ │ │ + * @requires OpenLayers/Protocol/WFS.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.NavigationHistory │ │ │ │ - * A navigation history control. This is a meta-control, that creates two │ │ │ │ - * dependent controls: <previous> and <next>. Call the trigger method │ │ │ │ - * on the <previous> and <next> controls to restore previous and next │ │ │ │ - * history states. The previous and next controls will become active │ │ │ │ - * when there are available states to restore and will become deactive │ │ │ │ - * when there are no states to restore. │ │ │ │ + * Class: OpenLayers.Protocol.WFS.v1 │ │ │ │ + * Abstract class for for v1.0.0 and v1.1.0 protocol. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * - <OpenLayers.Protocol> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.NavigationHistory = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: type │ │ │ │ - * {String} Note that this control is not intended to be added directly │ │ │ │ - * to a control panel. Instead, add the sub-controls previous and │ │ │ │ - * next. These sub-controls are button type controls that activate │ │ │ │ - * and deactivate themselves. If this parent control is added to │ │ │ │ - * a panel, it will act as a toggle. │ │ │ │ + * Property: version │ │ │ │ + * {String} WFS version number. │ │ │ │ */ │ │ │ │ - type: OpenLayers.Control.TYPE_TOGGLE, │ │ │ │ + version: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: previous │ │ │ │ - * {<OpenLayers.Control>} A button type control whose trigger method restores │ │ │ │ - * the previous state managed by this control. │ │ │ │ + * Property: srsName │ │ │ │ + * {String} Name of spatial reference system. Default is "EPSG:4326". │ │ │ │ */ │ │ │ │ - previous: null, │ │ │ │ + srsName: "EPSG:4326", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: previousOptions │ │ │ │ - * {Object} Set this property on the options argument of the constructor │ │ │ │ - * to set optional properties on the <previous> control. │ │ │ │ + * Property: featureType │ │ │ │ + * {String} Local feature typeName. │ │ │ │ */ │ │ │ │ - previousOptions: null, │ │ │ │ + featureType: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: next │ │ │ │ - * {<OpenLayers.Control>} A button type control whose trigger method restores │ │ │ │ - * the next state managed by this control. │ │ │ │ + * Property: featureNS │ │ │ │ + * {String} Feature namespace. │ │ │ │ */ │ │ │ │ - next: null, │ │ │ │ + featureNS: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: nextOptions │ │ │ │ - * {Object} Set this property on the options argument of the constructor │ │ │ │ - * to set optional properties on the <next> control. │ │ │ │ + * Property: geometryName │ │ │ │ + * {String} Name of the geometry attribute for features. Default is │ │ │ │ + * "the_geom" for WFS <version> 1.0, and null for higher versions. │ │ │ │ */ │ │ │ │ - nextOptions: null, │ │ │ │ + geometryName: "the_geom", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: limit │ │ │ │ - * {Integer} Optional limit on the number of history items to retain. If │ │ │ │ - * null, there is no limit. Default is 50. │ │ │ │ + * Property: maxFeatures │ │ │ │ + * {Integer} Optional maximum number of features to retrieve. │ │ │ │ */ │ │ │ │ - limit: 50, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - autoActivate: true, │ │ │ │ + schema: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: clearOnDeactivate │ │ │ │ - * {Boolean} Clear the history when the control is deactivated. Default │ │ │ │ - * is false. │ │ │ │ + * Property: featurePrefix │ │ │ │ + * {String} Namespace alias for feature type. Default is "feature". │ │ │ │ */ │ │ │ │ - clearOnDeactivate: false, │ │ │ │ + featurePrefix: "feature", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: registry │ │ │ │ - * {Object} An object with keys corresponding to event types. Values │ │ │ │ - * are functions that return an object representing the current state. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - registry: null, │ │ │ │ + formatOptions: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: nextStack │ │ │ │ - * {Array} Array of items in the history. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - nextStack: null, │ │ │ │ + readFormat: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: previousStack │ │ │ │ - * {Array} List of items in the history. First item represents the current │ │ │ │ - * state. │ │ │ │ + * Property: readOptions │ │ │ │ + * {Object} Optional object to pass to format's read. │ │ │ │ */ │ │ │ │ - previousStack: null, │ │ │ │ + readOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: listeners │ │ │ │ - * {Object} An object containing properties corresponding to event types. │ │ │ │ - * This object is used to configure the control and is modified on │ │ │ │ - * construction. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - listeners: null, │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: restoring │ │ │ │ - * {Boolean} Currently restoring a history state. This is set to true │ │ │ │ - * before calling restore and set to false after restore returns. │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Clean up the protocol. │ │ │ │ */ │ │ │ │ - restoring: false, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.options && !this.options.format) { │ │ │ │ + this.format.destroy(); │ │ │ │ + } │ │ │ │ + this.format = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.NavigationHistory │ │ │ │ - * │ │ │ │ + * 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} An optional object whose properties will be used │ │ │ │ - * to extend the control. │ │ │ │ + * 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) │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - │ │ │ │ - this.registry = OpenLayers.Util.extend({ │ │ │ │ - "moveend": this.getState │ │ │ │ - }, this.registry); │ │ │ │ + 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 previousOptions = { │ │ │ │ - trigger: OpenLayers.Function.bind(this.previousTrigger, this), │ │ │ │ - displayClass: this.displayClass + " " + this.displayClass + "Previous" │ │ │ │ - }; │ │ │ │ - OpenLayers.Util.extend(previousOptions, this.previousOptions); │ │ │ │ - this.previous = new OpenLayers.Control.Button(previousOptions); │ │ │ │ + var data = OpenLayers.Format.XML.prototype.write.apply( │ │ │ │ + this.format, [this.format.writeNode("wfs:GetFeature", options)] │ │ │ │ + ); │ │ │ │ │ │ │ │ - var nextOptions = { │ │ │ │ - trigger: OpenLayers.Function.bind(this.nextTrigger, this), │ │ │ │ - displayClass: this.displayClass + " " + this.displayClass + "Next" │ │ │ │ - }; │ │ │ │ - OpenLayers.Util.extend(nextOptions, this.nextOptions); │ │ │ │ - this.next = new OpenLayers.Control.Button(nextOptions); │ │ │ │ + response.priv = OpenLayers.Request.POST({ │ │ │ │ + url: options.url, │ │ │ │ + callback: this.createCallback(this.handleRead, response, options), │ │ │ │ + params: options.params, │ │ │ │ + headers: options.headers, │ │ │ │ + data: data │ │ │ │ + }); │ │ │ │ │ │ │ │ - this.clear(); │ │ │ │ + return response; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onPreviousChange │ │ │ │ - * Called when the previous history stack changes. │ │ │ │ + * APIMethod: setFeatureType │ │ │ │ + * Change the feature type on the fly. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * state - {Object} An object representing the state to be restored │ │ │ │ - * if previous is triggered again or null if no previous states remain. │ │ │ │ - * length - {Integer} The number of remaining previous states that can │ │ │ │ - * be restored. │ │ │ │ + * featureType - {String} Local (without prefix) feature typeName. │ │ │ │ */ │ │ │ │ - onPreviousChange: function(state, length) { │ │ │ │ - if (state && !this.previous.active) { │ │ │ │ - this.previous.activate(); │ │ │ │ - } else if (!state && this.previous.active) { │ │ │ │ - this.previous.deactivate(); │ │ │ │ - } │ │ │ │ + setFeatureType: function(featureType) { │ │ │ │ + this.featureType = featureType; │ │ │ │ + this.format.featureType = featureType; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onNextChange │ │ │ │ - * Called when the next history stack changes. │ │ │ │ + * APIMethod: setGeometryName │ │ │ │ + * Sets the geometryName option after instantiation. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * state - {Object} An object representing the state to be restored │ │ │ │ - * if next is triggered again or null if no next states remain. │ │ │ │ - * length - {Integer} The number of remaining next states that can │ │ │ │ - * be restored. │ │ │ │ + * geometryName - {String} Name of geometry attribute. │ │ │ │ */ │ │ │ │ - onNextChange: function(state, length) { │ │ │ │ - if (state && !this.next.active) { │ │ │ │ - this.next.activate(); │ │ │ │ - } else if (!state && this.next.active) { │ │ │ │ - this.next.deactivate(); │ │ │ │ - } │ │ │ │ + setGeometryName: function(geometryName) { │ │ │ │ + this.geometryName = geometryName; │ │ │ │ + this.format.geometryName = geometryName; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Destroy the control. │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this); │ │ │ │ - this.previous.destroy(); │ │ │ │ - this.next.destroy(); │ │ │ │ - this.deactivate(); │ │ │ │ - for (var prop in this) { │ │ │ │ - this[prop] = null; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * Set the map property for the control and <previous> and <next> child │ │ │ │ - * controls. │ │ │ │ + * Method: handleRead │ │ │ │ + * Deal with response from the read request. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} The response object to pass │ │ │ │ + * to the user callback. │ │ │ │ + * options - {Object} The user options passed to the read call. │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - this.map = map; │ │ │ │ - this.next.setMap(map); │ │ │ │ - this.previous.setMap(map); │ │ │ │ - }, │ │ │ │ + handleRead: function(response, options) { │ │ │ │ + options = OpenLayers.Util.extend({}, options); │ │ │ │ + OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * Called when the control is added to the map. │ │ │ │ - */ │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - this.next.draw(); │ │ │ │ - this.previous.draw(); │ │ │ │ + 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: previousTrigger │ │ │ │ - * Restore the previous state. If no items are in the previous history │ │ │ │ - * stack, this has no effect. │ │ │ │ + * 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} Item representing state that was restored. Undefined if no │ │ │ │ - * items are in the previous history stack. │ │ │ │ + * {Object} or {Array({<OpenLayers.Feature.Vector>})} or │ │ │ │ + * {<OpenLayers.Feature.Vector>} │ │ │ │ + * An object with a features property, an array of features or a single │ │ │ │ + * feature. │ │ │ │ */ │ │ │ │ - previousTrigger: function() { │ │ │ │ - var current = this.previousStack.shift(); │ │ │ │ - var state = this.previousStack.shift(); │ │ │ │ - if (state != undefined) { │ │ │ │ - this.nextStack.unshift(current); │ │ │ │ - this.previousStack.unshift(state); │ │ │ │ - this.restoring = true; │ │ │ │ - this.restore(state); │ │ │ │ - this.restoring = false; │ │ │ │ - this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ - this.onPreviousChange( │ │ │ │ - this.previousStack[1], this.previousStack.length - 1 │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - this.previousStack.unshift(current); │ │ │ │ + parseResponse: function(request, options) { │ │ │ │ + var doc = request.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = request.responseText; │ │ │ │ } │ │ │ │ - return state; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: nextTrigger │ │ │ │ - * Restore the next state. If no items are in the next history │ │ │ │ - * stack, this has no effect. The next history stack is populated │ │ │ │ - * as states are restored from the previous history stack. │ │ │ │ + * 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: │ │ │ │ - * {Object} Item representing state that was restored. Undefined if no │ │ │ │ - * items are in the next history stack. │ │ │ │ + * {<OpenLayers.Protocol.Response>} A response object with a features │ │ │ │ + * property containing any insertIds and a priv property referencing │ │ │ │ + * the XMLHttpRequest object. │ │ │ │ */ │ │ │ │ - nextTrigger: function() { │ │ │ │ - var state = this.nextStack.shift(); │ │ │ │ - if (state != undefined) { │ │ │ │ - this.previousStack.unshift(state); │ │ │ │ - this.restoring = true; │ │ │ │ - this.restore(state); │ │ │ │ - this.restoring = false; │ │ │ │ - this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ - this.onPreviousChange( │ │ │ │ - this.previousStack[1], this.previousStack.length - 1 │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return state; │ │ │ │ - }, │ │ │ │ + commit: function(features, options) { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: clear │ │ │ │ - * Clear history. │ │ │ │ - */ │ │ │ │ - clear: function() { │ │ │ │ - this.previousStack = []; │ │ │ │ - this.previous.deactivate(); │ │ │ │ - this.nextStack = []; │ │ │ │ - this.next.deactivate(); │ │ │ │ - }, │ │ │ │ + options = OpenLayers.Util.extend({}, options); │ │ │ │ + OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getState │ │ │ │ - * Get the current state and return it. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An object representing the current state. │ │ │ │ - */ │ │ │ │ - getState: function() { │ │ │ │ - return { │ │ │ │ - center: this.map.getCenter(), │ │ │ │ - resolution: this.map.getResolution(), │ │ │ │ - projection: this.map.getProjectionObject(), │ │ │ │ - units: this.map.getProjectionObject().getUnits() || │ │ │ │ - this.map.units || this.map.baseLayer.units │ │ │ │ - }; │ │ │ │ + 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: restore │ │ │ │ - * Update the state with the given object. │ │ │ │ - * │ │ │ │ + * Method: handleCommit │ │ │ │ + * Called when the commit request returns. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * state - {Object} An object representing the state to restore. │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} The response object to pass │ │ │ │ + * to the user callback. │ │ │ │ + * options - {Object} The user options passed to the commit call. │ │ │ │ */ │ │ │ │ - restore: function(state) { │ │ │ │ - var center, zoom; │ │ │ │ - if (this.map.getProjectionObject() == state.projection) { │ │ │ │ - zoom = this.map.getZoomForResolution(state.resolution); │ │ │ │ - center = state.center; │ │ │ │ - } else { │ │ │ │ - center = state.center.clone(); │ │ │ │ - center.transform(state.projection, this.map.getProjectionObject()); │ │ │ │ - var sourceUnits = state.units; │ │ │ │ - var targetUnits = this.map.getProjectionObject().getUnits() || │ │ │ │ - this.map.units || this.map.baseLayer.units; │ │ │ │ - var resolutionFactor = sourceUnits && targetUnits ? │ │ │ │ - OpenLayers.INCHES_PER_UNIT[sourceUnits] / OpenLayers.INCHES_PER_UNIT[targetUnits] : 1; │ │ │ │ - zoom = this.map.getZoomForResolution(resolutionFactor * state.resolution); │ │ │ │ - } │ │ │ │ - this.map.setCenter(center, zoom); │ │ │ │ - }, │ │ │ │ + handleCommit: function(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + var request = response.priv; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setListeners │ │ │ │ - * Sets functions to be registered in the listeners object. │ │ │ │ - */ │ │ │ │ - setListeners: function() { │ │ │ │ - this.listeners = {}; │ │ │ │ - for (var type in this.registry) { │ │ │ │ - this.listeners[type] = OpenLayers.Function.bind(function() { │ │ │ │ - if (!this.restoring) { │ │ │ │ - var state = this.registry[type].apply(this, arguments); │ │ │ │ - this.previousStack.unshift(state); │ │ │ │ - if (this.previousStack.length > 1) { │ │ │ │ - this.onPreviousChange( │ │ │ │ - this.previousStack[1], this.previousStack.length - 1 │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (this.previousStack.length > (this.limit + 1)) { │ │ │ │ - this.previousStack.pop(); │ │ │ │ - } │ │ │ │ - if (this.nextStack.length > 0) { │ │ │ │ - this.nextStack = []; │ │ │ │ - this.onNextChange(null, 0); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return true; │ │ │ │ - }, this); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + // ensure that we have an xml doc │ │ │ │ + var data = request.responseXML; │ │ │ │ + if (!data || !data.documentElement) { │ │ │ │ + data = request.responseText; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the control. This registers any listeners. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Control successfully activated. │ │ │ │ - */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (this.map) { │ │ │ │ - if (OpenLayers.Control.prototype.activate.apply(this)) { │ │ │ │ - if (this.listeners == null) { │ │ │ │ - this.setListeners(); │ │ │ │ - } │ │ │ │ - for (var type in this.listeners) { │ │ │ │ - this.map.events.register(type, this, this.listeners[type]); │ │ │ │ - } │ │ │ │ - activated = true; │ │ │ │ - if (this.previousStack.length == 0) { │ │ │ │ - this.initStack(); │ │ │ │ - } │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: initStack │ │ │ │ - * Called after the control is activated if the previous history stack is │ │ │ │ - * empty. │ │ │ │ + * Method: filterDelete │ │ │ │ + * Send a request that deletes all features by their filter. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * filter - {<OpenLayers.Filter>} filter │ │ │ │ */ │ │ │ │ - initStack: function() { │ │ │ │ - if (this.map.getCenter()) { │ │ │ │ - this.listeners.moveend(); │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ + │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the control. This unregisters any listeners. │ │ │ │ + * 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). │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Control successfully deactivated. │ │ │ │ + * Parameters: │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = false; │ │ │ │ - if (this.map) { │ │ │ │ - if (OpenLayers.Control.prototype.deactivate.apply(this)) { │ │ │ │ - for (var type in this.listeners) { │ │ │ │ - this.map.events.unregister( │ │ │ │ - type, this, this.listeners[type] │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (this.clearOnDeactivate) { │ │ │ │ - this.clear(); │ │ │ │ - } │ │ │ │ - deactivated = true; │ │ │ │ - } │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + response.priv.abort(); │ │ │ │ } │ │ │ │ - return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.NavigationHistory" │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.WFS.v1" │ │ │ │ }); │ │ │ │ - │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Geolocate.js │ │ │ │ + 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/Control.js │ │ │ │ - * @requires OpenLayers/Geometry/Point.js │ │ │ │ - * @requires OpenLayers/Projection.js │ │ │ │ + * @requires OpenLayers/Format/GML/Base.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. │ │ │ │ + * Class: OpenLayers.Format.GML.v2 │ │ │ │ + * Parses GML version 2. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * - <OpenLayers.Format.GML.Base> │ │ │ │ */ │ │ │ │ -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, │ │ │ │ +OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} Schema location for a particular minor version. │ │ │ │ */ │ │ │ │ - geolocationOptions: null, │ │ │ │ + schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.Geolocate │ │ │ │ - * Create a new control to deal with browser geolocation API │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ - * Activates the control. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The control was effectively activated. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + 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) │ │ │ │ ); │ │ │ │ - } else { │ │ │ │ - this.getCurrentLocation(); │ │ │ │ } │ │ │ │ - return true; │ │ │ │ - } │ │ │ │ - return false; │ │ │ │ + }, OpenLayers.Format.GML.Base.prototype.readers["gml"]), │ │ │ │ + "feature": OpenLayers.Format.GML.Base.prototype.readers["feature"], │ │ │ │ + "wfs": OpenLayers.Format.GML.Base.prototype.readers["wfs"] │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Deactivates the control. │ │ │ │ + * Method: write │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector} │ │ │ │ + * An array of features or a single feature. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} The control was effectively deactivated. │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - if (this.active && this.watchId !== null) { │ │ │ │ - this.geolocation.clearWatch(this.watchId); │ │ │ │ + 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"; │ │ │ │ } │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply( │ │ │ │ - this, arguments │ │ │ │ + var root = this.writeNode(name, features); │ │ │ │ + this.setAttributeNS( │ │ │ │ + root, this.namespaces["xsi"], │ │ │ │ + "xsi:schemaLocation", this.schemaLocation │ │ │ │ ); │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 │ │ │ │ - ) │ │ │ │ - }); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [root]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getCurrentLocation │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Returns true if a event will be fired (successfull │ │ │ │ - * registration) │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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"] │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: failure │ │ │ │ - * method called on browser's geolocation failure │ │ │ │ - * │ │ │ │ - */ │ │ │ │ - failure: function(error) { │ │ │ │ - this.events.triggerEvent("locationfailed", { │ │ │ │ - error: error │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.GML.v2" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Geolocate" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/PanZoom.js │ │ │ │ + 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/Control.js │ │ │ │ - * @requires OpenLayers/Events/buttonclick.js │ │ │ │ + * @requires OpenLayers/Format/GML/v2.js │ │ │ │ + * @requires OpenLayers/Format/Filter/v1.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.PanZoom │ │ │ │ - * The PanZoom is a visible control, composed of a │ │ │ │ - * <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomPanel>. By │ │ │ │ - * default it is drawn in the upper left corner of the map. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.Filter.v1_0_0 │ │ │ │ + * Write ogc:Filter version 1.0.0. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * - <OpenLayers.Format.GML.v2> │ │ │ │ + * - <OpenLayers.Format.Filter.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: slideFactor │ │ │ │ - * {Integer} Number of pixels by which we'll pan the map in any direction │ │ │ │ - * on clicking the arrow buttons. If you want to pan by some ratio │ │ │ │ - * of the map dimensions, use <slideRatio> instead. │ │ │ │ - */ │ │ │ │ - slideFactor: 50, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: slideRatio │ │ │ │ - * {Number} The fraction of map width/height by which we'll pan the map │ │ │ │ - * on clicking the arrow buttons. Default is null. If set, will │ │ │ │ - * override <slideFactor>. E.g. if slideRatio is .5, then the Pan Up │ │ │ │ - * button will pan up half the map height. │ │ │ │ - */ │ │ │ │ - slideRatio: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: buttons │ │ │ │ - * {Array(DOMElement)} Array of Button Divs │ │ │ │ - */ │ │ │ │ - buttons: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: position │ │ │ │ - * {<OpenLayers.Pixel>} │ │ │ │ - */ │ │ │ │ - position: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.PanZoom │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X, │ │ │ │ - OpenLayers.Control.PanZoom.Y); │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ - } │ │ │ │ - this.removeButtons(); │ │ │ │ - this.buttons = null; │ │ │ │ - this.position = null; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * │ │ │ │ - * Properties: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ - */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - this.map.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * px - {<OpenLayers.Pixel>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A reference to the container div for the PanZoom control. │ │ │ │ - */ │ │ │ │ - draw: function(px) { │ │ │ │ - // initialize our internal div │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - px = this.position; │ │ │ │ - │ │ │ │ - // place the controls │ │ │ │ - this.buttons = []; │ │ │ │ - │ │ │ │ - var sz = { │ │ │ │ - w: 18, │ │ │ │ - h: 18 │ │ │ │ - }; │ │ │ │ - var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ - │ │ │ │ - this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ - px.y = centered.y + sz.h; │ │ │ │ - this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ - this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz); │ │ │ │ - this._addButton("pandown", "south-mini.png", │ │ │ │ - centered.add(0, sz.h * 2), sz); │ │ │ │ - this._addButton("zoomin", "zoom-plus-mini.png", │ │ │ │ - centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ - this._addButton("zoomworld", "zoom-world-mini.png", │ │ │ │ - centered.add(0, sz.h * 4 + 5), sz); │ │ │ │ - this._addButton("zoomout", "zoom-minus-mini.png", │ │ │ │ - centered.add(0, sz.h * 5 + 5), sz); │ │ │ │ - return this.div; │ │ │ │ - }, │ │ │ │ +OpenLayers.Format.Filter.v1_0_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.GML.v2, OpenLayers.Format.Filter.v1, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: _addButton │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * id - {String} │ │ │ │ - * img - {String} │ │ │ │ - * xy - {<OpenLayers.Pixel>} │ │ │ │ - * sz - {<OpenLayers.Size>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A Div (an alphaImageDiv, to be precise) that contains the │ │ │ │ - * image of the button, and has all the proper event handlers set. │ │ │ │ - */ │ │ │ │ - _addButton: function(id, img, xy, sz) { │ │ │ │ - var imgLocation = OpenLayers.Util.getImageLocation(img); │ │ │ │ - var btn = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ - this.id + "_" + id, │ │ │ │ - xy, sz, imgLocation, "absolute"); │ │ │ │ - btn.style.cursor = "pointer"; │ │ │ │ - //we want to add the outer div │ │ │ │ - this.div.appendChild(btn); │ │ │ │ - btn.action = id; │ │ │ │ - btn.className = "olButton"; │ │ │ │ + /** │ │ │ │ + * Constant: VERSION │ │ │ │ + * {String} 1.0.0 │ │ │ │ + */ │ │ │ │ + VERSION: "1.0.0", │ │ │ │ │ │ │ │ - //we want to remember/reference the outer div │ │ │ │ - this.buttons.push(btn); │ │ │ │ - return btn; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: _removeButton │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * btn - {Object} │ │ │ │ - */ │ │ │ │ - _removeButton: function(btn) { │ │ │ │ - this.div.removeChild(btn); │ │ │ │ - OpenLayers.Util.removeItem(this.buttons, btn); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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] │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: removeButtons │ │ │ │ - */ │ │ │ │ - removeButtons: function() { │ │ │ │ - for (var i = this.buttons.length - 1; i >= 0; --i) { │ │ │ │ - this._removeButton(this.buttons[i]); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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"] │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: onButtonClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - */ │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - var btn = evt.buttonElement; │ │ │ │ - switch (btn.action) { │ │ │ │ - case "panup": │ │ │ │ - this.map.pan(0, -this.getSlideFactor("h")); │ │ │ │ - break; │ │ │ │ - case "pandown": │ │ │ │ - this.map.pan(0, this.getSlideFactor("h")); │ │ │ │ - break; │ │ │ │ - case "panleft": │ │ │ │ - this.map.pan(-this.getSlideFactor("w"), 0); │ │ │ │ - break; │ │ │ │ - case "panright": │ │ │ │ - this.map.pan(this.getSlideFactor("w"), 0); │ │ │ │ - break; │ │ │ │ - case "zoomin": │ │ │ │ - this.map.zoomIn(); │ │ │ │ - break; │ │ │ │ - case "zoomout": │ │ │ │ - this.map.zoomOut(); │ │ │ │ - break; │ │ │ │ - case "zoomworld": │ │ │ │ - this.map.zoomToMaxExtent(); │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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: getSlideFactor │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * dim - {String} "w" or "h" (for width or height). │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Number} The slide factor for panning in the requested direction. │ │ │ │ - */ │ │ │ │ - getSlideFactor: function(dim) { │ │ │ │ - return this.slideRatio ? │ │ │ │ - this.map.getSize()[dim] * this.slideRatio : │ │ │ │ - this.slideFactor; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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.Control.PanZoom" │ │ │ │ -}); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: X │ │ │ │ - * {Integer} │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.PanZoom.X = 4; │ │ │ │ + CLASS_NAME: "OpenLayers.Format.Filter.v1_0_0" │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: Y │ │ │ │ - * {Integer} │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.PanZoom.Y = 4; │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/PanZoomBar.js │ │ │ │ + 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/Control/PanZoom.js │ │ │ │ + * @requires OpenLayers/Format/WFST/v1.js │ │ │ │ + * @requires OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.PanZoomBar │ │ │ │ - * The PanZoomBar is a visible control composed of a │ │ │ │ - * <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomBar>. │ │ │ │ - * By default it is displayed in the upper left corner of the map as 4 │ │ │ │ - * directional arrows above a vertical slider. │ │ │ │ + * 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.Control.PanZoom> │ │ │ │ + * - <OpenLayers.Format.Filter.v1_0_0> │ │ │ │ + * - <OpenLayers.Format.WFST.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.PanZoomBar = OpenLayers.Class(OpenLayers.Control.PanZoom, { │ │ │ │ +OpenLayers.Format.WFST.v1_0_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.Filter.v1_0_0, OpenLayers.Format.WFST.v1, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: zoomStopWidth │ │ │ │ - */ │ │ │ │ - zoomStopWidth: 18, │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} WFS version number. │ │ │ │ + */ │ │ │ │ + version: "1.0.0", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: zoomStopHeight │ │ │ │ - */ │ │ │ │ - zoomStopHeight: 11, │ │ │ │ + /** │ │ │ │ + * 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: slider │ │ │ │ - */ │ │ │ │ - slider: null, │ │ │ │ + /** │ │ │ │ + * Property: schemaLocations │ │ │ │ + * {Object} Properties are namespace aliases, values are schema locations. │ │ │ │ + */ │ │ │ │ + schemaLocations: { │ │ │ │ + "wfs": "http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd" │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: sliderEvents │ │ │ │ - * {<OpenLayers.Events>} │ │ │ │ - */ │ │ │ │ - sliderEvents: null, │ │ │ │ + /** │ │ │ │ + * 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]); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: zoombarDiv │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - zoombarDiv: null, │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: zoomWorldIcon │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - zoomWorldIcon: false, │ │ │ │ + /** │ │ │ │ + * 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"] │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: panIcons │ │ │ │ - * {Boolean} Set this property to false not to display the pan icons. If │ │ │ │ - * false the zoom world icon is placed under the zoom bar. Defaults to │ │ │ │ - * true. │ │ │ │ - */ │ │ │ │ - panIcons: true, │ │ │ │ + /** │ │ │ │ + * 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"] │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: forceFixedZoomLevel │ │ │ │ - * {Boolean} Force a fixed zoom level even though the map has │ │ │ │ - * fractionalZoom │ │ │ │ - */ │ │ │ │ - forceFixedZoomLevel: false, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFST.v1_0_0" │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Protocol/WFS/v1_0_0.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: mouseDragStart │ │ │ │ - * {<OpenLayers.Pixel>} │ │ │ │ - */ │ │ │ │ - mouseDragStart: null, │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: deltaY │ │ │ │ - * {Number} The cumulative vertical pixel offset during a zoom bar drag. │ │ │ │ - */ │ │ │ │ - deltaY: null, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Protocol/WFS/v1.js │ │ │ │ + * @requires OpenLayers/Format/WFST/v1_0_0.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: zoomStart │ │ │ │ - * {<OpenLayers.Pixel>} │ │ │ │ - */ │ │ │ │ - zoomStart: null, │ │ │ │ +/** │ │ │ │ + * 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, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.PanZoomBar │ │ │ │ + * Property: version │ │ │ │ + * {String} WFS version number. │ │ │ │ */ │ │ │ │ + version: "1.0.0", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ + * 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'. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ │ │ │ │ - this._removeZoomBar(); │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.WFS.v1_0_0" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Protocol/WFS/v1_1_0.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - this.map.events.un({ │ │ │ │ - "changebaselayer": this.redraw, │ │ │ │ - "updatesize": this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Protocol/WFS/v1.js │ │ │ │ + * @requires OpenLayers/Format/WFST/v1_1_0.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - delete this.mouseDragStart; │ │ │ │ - delete this.zoomStart; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Protocol.WFS.v1_1_0 │ │ │ │ + * A WFS v1.1.0 protocol for vector layers. Create a new instance with the │ │ │ │ + * <OpenLayers.Protocol.WFS.v1_1_0> constructor. │ │ │ │ + * │ │ │ │ + * Differences from the v1.0.0 protocol: │ │ │ │ + * - uses Filter Encoding 1.1.0 instead of 1.0.0 │ │ │ │ + * - uses GML 3 instead of 2 if no format is provided │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Protocol.WFS.v1> │ │ │ │ + */ │ │ │ │ +OpenLayers.Protocol.WFS.v1_1_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setMap │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ - */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments); │ │ │ │ - this.map.events.on({ │ │ │ │ - "changebaselayer": this.redraw, │ │ │ │ - "updatesize": this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: redraw │ │ │ │ - * clear the div and start over. │ │ │ │ + * Property: version │ │ │ │ + * {String} WFS version number. │ │ │ │ */ │ │ │ │ - redraw: function() { │ │ │ │ - if (this.div != null) { │ │ │ │ - this.removeButtons(); │ │ │ │ - this._removeZoomBar(); │ │ │ │ - } │ │ │ │ - this.draw(); │ │ │ │ - }, │ │ │ │ + version: "1.1.0", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: draw │ │ │ │ + * Constructor: OpenLayers.Protocol.WFS.v1_1_0 │ │ │ │ + * A class for giving layers WFS v1.1.0 protocol. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * px - {<OpenLayers.Pixel>} │ │ │ │ + * 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'. │ │ │ │ + * outputFormat - {String} Optional output format to use for WFS GetFeature │ │ │ │ + * requests. This can be any format advertized by the WFS's │ │ │ │ + * GetCapabilities response. If set, an appropriate readFormat also │ │ │ │ + * has to be provided, unless outputFormat is GML3, GML2 or JSON. │ │ │ │ + * readFormat - {<OpenLayers.Format>} An appropriate format parser if │ │ │ │ + * outputFormat is none of GML3, GML2 or JSON. │ │ │ │ */ │ │ │ │ - draw: function(px) { │ │ │ │ - // initialize our internal div │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - px = this.position.clone(); │ │ │ │ - │ │ │ │ - // place the controls │ │ │ │ - this.buttons = []; │ │ │ │ - │ │ │ │ - var sz = { │ │ │ │ - w: 18, │ │ │ │ - h: 18 │ │ │ │ - }; │ │ │ │ - if (this.panIcons) { │ │ │ │ - var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ - var wposition = sz.w; │ │ │ │ - │ │ │ │ - if (this.zoomWorldIcon) { │ │ │ │ - centered = new OpenLayers.Pixel(px.x + sz.w, px.y); │ │ │ │ - } │ │ │ │ - │ │ │ │ - this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ - px.y = centered.y + sz.h; │ │ │ │ - this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ - if (this.zoomWorldIcon) { │ │ │ │ - this._addButton("zoomworld", "zoom-world-mini.png", px.add(sz.w, 0), sz); │ │ │ │ - │ │ │ │ - wposition *= 2; │ │ │ │ - } │ │ │ │ - this._addButton("panright", "east-mini.png", px.add(wposition, 0), sz); │ │ │ │ - this._addButton("pandown", "south-mini.png", centered.add(0, sz.h * 2), sz); │ │ │ │ - this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ - centered = this._addZoomBar(centered.add(0, sz.h * 4 + 5)); │ │ │ │ - this._addButton("zoomout", "zoom-minus-mini.png", centered, sz); │ │ │ │ - } else { │ │ │ │ - this._addButton("zoomin", "zoom-plus-mini.png", px, sz); │ │ │ │ - centered = this._addZoomBar(px.add(0, sz.h)); │ │ │ │ - this._addButton("zoomout", "zoom-minus-mini.png", centered, sz); │ │ │ │ - if (this.zoomWorldIcon) { │ │ │ │ - centered = centered.add(0, sz.h + 3); │ │ │ │ - this._addButton("zoomworld", "zoom-world-mini.png", centered, sz); │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Protocol.WFS.v1.prototype.initialize.apply(this, arguments); │ │ │ │ + if (this.outputFormat && !this.readFormat) { │ │ │ │ + if (this.outputFormat.toLowerCase() == "gml2") { │ │ │ │ + this.readFormat = new OpenLayers.Format.GML.v2({ │ │ │ │ + featureType: this.featureType, │ │ │ │ + featureNS: this.featureNS, │ │ │ │ + geometryName: this.geometryName │ │ │ │ + }); │ │ │ │ + } else if (this.outputFormat.toLowerCase() == "json") { │ │ │ │ + this.readFormat = new OpenLayers.Format.GeoJSON(); │ │ │ │ } │ │ │ │ } │ │ │ │ - return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: _addZoomBar │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * centered - {<OpenLayers.Pixel>} where zoombar drawing is to start. │ │ │ │ - */ │ │ │ │ - _addZoomBar: function(centered) { │ │ │ │ - var imgLocation = OpenLayers.Util.getImageLocation("slider.png"); │ │ │ │ - var id = this.id + "_" + this.map.id; │ │ │ │ - var minZoom = this.map.getMinZoom(); │ │ │ │ - var zoomsToEnd = this.map.getNumZoomLevels() - 1 - this.map.getZoom(); │ │ │ │ - var slider = OpenLayers.Util.createAlphaImageDiv(id, │ │ │ │ - centered.add(-1, zoomsToEnd * this.zoomStopHeight), { │ │ │ │ - w: 20, │ │ │ │ - h: 9 │ │ │ │ - }, │ │ │ │ - imgLocation, │ │ │ │ - "absolute"); │ │ │ │ - slider.style.cursor = "move"; │ │ │ │ - this.slider = slider; │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.WFS.v1_1_0" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/CSWGetRecords.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - this.sliderEvents = new OpenLayers.Events(this, slider, null, true, { │ │ │ │ - includeXY: true │ │ │ │ - }); │ │ │ │ - this.sliderEvents.on({ │ │ │ │ - "touchstart": this.zoomBarDown, │ │ │ │ - "touchmove": this.zoomBarDrag, │ │ │ │ - "touchend": this.zoomBarUp, │ │ │ │ - "mousedown": this.zoomBarDown, │ │ │ │ - "mousemove": this.zoomBarDrag, │ │ │ │ - "mouseup": this.zoomBarUp │ │ │ │ - }); │ │ │ │ +/* 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 sz = { │ │ │ │ - w: this.zoomStopWidth, │ │ │ │ - h: this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom) │ │ │ │ - }; │ │ │ │ - var imgLocation = OpenLayers.Util.getImageLocation("zoombar.png"); │ │ │ │ - var div = null; │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (OpenLayers.Util.alphaHack()) { │ │ │ │ - var id = this.id + "_" + this.map.id; │ │ │ │ - div = OpenLayers.Util.createAlphaImageDiv(id, centered, { │ │ │ │ - w: sz.w, │ │ │ │ - h: this.zoomStopHeight │ │ │ │ - }, │ │ │ │ - imgLocation, │ │ │ │ - "absolute", null, "crop"); │ │ │ │ - div.style.height = sz.h + "px"; │ │ │ │ - } else { │ │ │ │ - div = OpenLayers.Util.createDiv( │ │ │ │ - 'OpenLayers_Control_PanZoomBar_Zoombar' + this.map.id, │ │ │ │ - centered, │ │ │ │ - sz, │ │ │ │ - imgLocation); │ │ │ │ - } │ │ │ │ - div.style.cursor = "pointer"; │ │ │ │ - div.className = "olButton"; │ │ │ │ - this.zoombarDiv = div; │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.CSWGetRecords │ │ │ │ + * Default version is 2.0.2. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Format>} A CSWGetRecords format of the given version. │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.CSWGetRecords = function(options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults( │ │ │ │ + options, OpenLayers.Format.CSWGetRecords.DEFAULTS │ │ │ │ + ); │ │ │ │ + var cls = OpenLayers.Format.CSWGetRecords["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (!cls) { │ │ │ │ + throw "Unsupported CSWGetRecords version: " + options.version; │ │ │ │ + } │ │ │ │ + return new cls(options); │ │ │ │ +}; │ │ │ │ │ │ │ │ - this.div.appendChild(div); │ │ │ │ +/** │ │ │ │ + * Constant: DEFAULTS │ │ │ │ + * {Object} Default properties for the CSWGetRecords format. │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.CSWGetRecords.DEFAULTS = { │ │ │ │ + "version": "2.0.2" │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/CSWGetRecords/v2_0_2.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - this.startTop = parseInt(div.style.top); │ │ │ │ - this.div.appendChild(slider); │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - this.map.events.register("zoomend", this, this.moveZoomBar); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/XML.js │ │ │ │ + * @requires OpenLayers/Format/CSWGetRecords.js │ │ │ │ + * @requires OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ + * @requires OpenLayers/Format/Filter/v1_1_0.js │ │ │ │ + * @requires OpenLayers/Format/OWSCommon/v1_0_0.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - centered = centered.add(0, │ │ │ │ - this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom)); │ │ │ │ - return centered; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.CSWGetRecords.v2_0_2 │ │ │ │ + * A format for creating CSWGetRecords v2.0.2 transactions. │ │ │ │ + * Create a new instance with the │ │ │ │ + * <OpenLayers.Format.CSWGetRecords.v2_0_2> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.CSWGetRecords.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: _removeZoomBar │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ - _removeZoomBar: function() { │ │ │ │ - this.sliderEvents.un({ │ │ │ │ - "touchstart": this.zoomBarDown, │ │ │ │ - "touchmove": this.zoomBarDrag, │ │ │ │ - "touchend": this.zoomBarUp, │ │ │ │ - "mousedown": this.zoomBarDown, │ │ │ │ - "mousemove": this.zoomBarDrag, │ │ │ │ - "mouseup": this.zoomBarUp │ │ │ │ - }); │ │ │ │ - this.sliderEvents.destroy(); │ │ │ │ - │ │ │ │ - this.div.removeChild(this.zoombarDiv); │ │ │ │ - this.zoombarDiv = null; │ │ │ │ - this.div.removeChild(this.slider); │ │ │ │ - this.slider = null; │ │ │ │ - │ │ │ │ - this.map.events.unregister("zoomend", this, this.moveZoomBar); │ │ │ │ + namespaces: { │ │ │ │ + csw: "http://www.opengis.net/cat/csw/2.0.2", │ │ │ │ + dc: "http://purl.org/dc/elements/1.1/", │ │ │ │ + dct: "http://purl.org/dc/terms/", │ │ │ │ + gmd: "http://www.isotc211.org/2005/gmd", │ │ │ │ + geonet: "http://www.fao.org/geonetwork", │ │ │ │ + ogc: "http://www.opengis.net/ogc", │ │ │ │ + ows: "http://www.opengis.net/ows", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onButtonClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * Property: defaultPrefix │ │ │ │ + * {String} The default prefix (used by Format.XML). │ │ │ │ */ │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this, arguments); │ │ │ │ - if (evt.buttonElement === this.zoombarDiv) { │ │ │ │ - var levels = evt.buttonXY.y / this.zoomStopHeight; │ │ │ │ - if (this.forceFixedZoomLevel || !this.map.fractionalZoom) { │ │ │ │ - levels = Math.floor(levels); │ │ │ │ - } │ │ │ │ - var zoom = (this.map.getNumZoomLevels() - 1) - levels; │ │ │ │ - zoom = Math.min(Math.max(zoom, 0), this.map.getNumZoomLevels() - 1); │ │ │ │ - this.map.zoomTo(zoom); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + defaultPrefix: "csw", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: passEventToSlider │ │ │ │ - * This function is used to pass events that happen on the div, or the map, │ │ │ │ - * through to the slider, which then does its moving thing. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ - */ │ │ │ │ - passEventToSlider: function(evt) { │ │ │ │ - this.sliderEvents.handleBrowserEvent(evt); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /* │ │ │ │ - * Method: zoomBarDown │ │ │ │ - * event listener for clicks on the slider │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ + * Property: version │ │ │ │ + * {String} CSW version number. │ │ │ │ */ │ │ │ │ - zoomBarDown: function(evt) { │ │ │ │ - if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - this.map.events.on({ │ │ │ │ - "touchmove": this.passEventToSlider, │ │ │ │ - "mousemove": this.passEventToSlider, │ │ │ │ - "mouseup": this.passEventToSlider, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.mouseDragStart = evt.xy.clone(); │ │ │ │ - this.zoomStart = evt.xy.clone(); │ │ │ │ - this.div.style.cursor = "move"; │ │ │ │ - // reset the div offsets just in case the div moved │ │ │ │ - this.zoombarDiv.offsets = null; │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - }, │ │ │ │ + version: "2.0.2", │ │ │ │ │ │ │ │ - /* │ │ │ │ - * Method: zoomBarDrag │ │ │ │ - * This is what happens when a click has occurred, and the client is │ │ │ │ - * dragging. Here we must ensure that the slider doesn't go beyond the │ │ │ │ - * bottom/top of the zoombar div, as well as moving the slider to its new │ │ │ │ - * visual location │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ + /** │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} http://www.opengis.net/cat/csw/2.0.2 │ │ │ │ + * http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd │ │ │ │ */ │ │ │ │ - zoomBarDrag: function(evt) { │ │ │ │ - if (this.mouseDragStart != null) { │ │ │ │ - var deltaY = this.mouseDragStart.y - evt.xy.y; │ │ │ │ - var offsets = OpenLayers.Util.pagePosition(this.zoombarDiv); │ │ │ │ - if ((evt.clientY - offsets[1]) > 0 && │ │ │ │ - (evt.clientY - offsets[1]) < parseInt(this.zoombarDiv.style.height) - 2) { │ │ │ │ - var newTop = parseInt(this.slider.style.top) - deltaY; │ │ │ │ - this.slider.style.top = newTop + "px"; │ │ │ │ - this.mouseDragStart = evt.xy.clone(); │ │ │ │ - } │ │ │ │ - // set cumulative displacement │ │ │ │ - this.deltaY = this.zoomStart.y - evt.xy.y; │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ │ │ │ │ - /* │ │ │ │ - * Method: zoomBarUp │ │ │ │ - * Perform cleanup when a mouseup event is received -- discover new zoom │ │ │ │ - * level and switch to it. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ + /** │ │ │ │ + * APIProperty: requestId │ │ │ │ + * {String} Value of the requestId attribute of the GetRecords element. │ │ │ │ */ │ │ │ │ - zoomBarUp: function(evt) { │ │ │ │ - if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - if (this.mouseDragStart) { │ │ │ │ - this.div.style.cursor = ""; │ │ │ │ - this.map.events.un({ │ │ │ │ - "touchmove": this.passEventToSlider, │ │ │ │ - "mouseup": this.passEventToSlider, │ │ │ │ - "mousemove": this.passEventToSlider, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - var zoomLevel = this.map.zoom; │ │ │ │ - if (!this.forceFixedZoomLevel && this.map.fractionalZoom) { │ │ │ │ - zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ - zoomLevel = Math.min(Math.max(zoomLevel, 0), │ │ │ │ - this.map.getNumZoomLevels() - 1); │ │ │ │ - } else { │ │ │ │ - zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ - zoomLevel = Math.max(Math.round(zoomLevel), 0); │ │ │ │ - } │ │ │ │ - this.map.zoomTo(zoomLevel); │ │ │ │ - this.mouseDragStart = null; │ │ │ │ - this.zoomStart = null; │ │ │ │ - this.deltaY = 0; │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + requestId: null, │ │ │ │ │ │ │ │ - /* │ │ │ │ - * Method: moveZoomBar │ │ │ │ - * Change the location of the slider to match the current zoom level. │ │ │ │ + /** │ │ │ │ + * APIProperty: resultType │ │ │ │ + * {String} Value of the resultType attribute of the GetRecords element, │ │ │ │ + * specifies the result type in the GetRecords response, "hits" is │ │ │ │ + * the default. │ │ │ │ */ │ │ │ │ - moveZoomBar: function() { │ │ │ │ - var newTop = │ │ │ │ - ((this.map.getNumZoomLevels() - 1) - this.map.getZoom()) * │ │ │ │ - this.zoomStopHeight + this.startTop + 1; │ │ │ │ - this.slider.style.top = newTop + "px"; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.PanZoomBar" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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, { │ │ │ │ + resultType: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: outputFormat │ │ │ │ + * {String} Value of the outputFormat attribute of the GetRecords element, │ │ │ │ + * specifies the format of the GetRecords response, │ │ │ │ + * "application/xml" is the default. │ │ │ │ */ │ │ │ │ - started: false, │ │ │ │ + outputFormat: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: stopDown │ │ │ │ - * {Boolean} Stop propagation of touchstart events from getting to │ │ │ │ - * listeners on the same element. Default is false. │ │ │ │ + * APIProperty: outputSchema │ │ │ │ + * {String} Value of the outputSchema attribute of the GetRecords element, │ │ │ │ + * specifies the schema of the GetRecords response. │ │ │ │ */ │ │ │ │ - stopDown: false, │ │ │ │ + outputSchema: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: pinching │ │ │ │ - * {Boolean} │ │ │ │ + * APIProperty: startPosition │ │ │ │ + * {String} Value of the startPosition attribute of the GetRecords element, │ │ │ │ + * specifies the start position (offset+1) for the GetRecords response, │ │ │ │ + * 1 is the default. │ │ │ │ */ │ │ │ │ - pinching: false, │ │ │ │ + startPosition: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: last │ │ │ │ - * {Object} Object that store informations related to pinch last touch. │ │ │ │ + * APIProperty: maxRecords │ │ │ │ + * {String} Value of the maxRecords attribute of the GetRecords element, │ │ │ │ + * specifies the maximum number of records in the GetRecords response, │ │ │ │ + * 10 is the default. │ │ │ │ */ │ │ │ │ - last: null, │ │ │ │ + maxRecords: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: start │ │ │ │ - * {Object} Object that store informations related to pinch touchstart. │ │ │ │ + * APIProperty: DistributedSearch │ │ │ │ + * {String} Value of the csw:DistributedSearch element, used when writing │ │ │ │ + * a csw:GetRecords document. │ │ │ │ */ │ │ │ │ - start: null, │ │ │ │ + DistributedSearch: 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} │ │ │ │ + * APIProperty: ResponseHandler │ │ │ │ + * {Array({String})} Values of the csw:ResponseHandler elements, used when │ │ │ │ + * writting a csw:GetRecords document. │ │ │ │ */ │ │ │ │ + ResponseHandler: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: touchstart │ │ │ │ - * Handle touchstart events │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * APIProperty: Query │ │ │ │ + * {String} Value of the csw:Query element, used when writing a csw:GetRecords │ │ │ │ + * document. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - }, │ │ │ │ + Query: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: touchmove │ │ │ │ - * Handle touchmove events │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: touchend │ │ │ │ - * Handle touchend events │ │ │ │ + * Constructor: OpenLayers.Format.CSWGetRecords.v2_0_2 │ │ │ │ + * A class for parsing and generating CSWGetRecords v2.0.2 transactions. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * Valid options properties (documented as class properties): │ │ │ │ + * - requestId │ │ │ │ + * - resultType │ │ │ │ + * - outputFormat │ │ │ │ + * - outputSchema │ │ │ │ + * - startPosition │ │ │ │ + * - maxRecords │ │ │ │ + * - DistributedSearch │ │ │ │ + * - ResponseHandler │ │ │ │ + * - Query │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ - * Activate the handler. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The handler was successfully activated. │ │ │ │ + * APIMethod: read │ │ │ │ + * Parse the response from a GetRecords request. │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.pinching = false; │ │ │ │ - activated = true; │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement; │ │ │ │ + } │ │ │ │ + var obj = {}; │ │ │ │ + this.readNode(data, obj); │ │ │ │ + return obj; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Deactivate the handler. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The handler was successfully deactivated. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + readers: { │ │ │ │ + "csw": { │ │ │ │ + "GetRecordsResponse": function(node, obj) { │ │ │ │ + obj.records = []; │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + var version = this.getAttributeNS(node, "", 'version'); │ │ │ │ + if (version != "") { │ │ │ │ + obj.version = version; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "RequestId": function(node, obj) { │ │ │ │ + obj.RequestId = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "SearchStatus": function(node, obj) { │ │ │ │ + obj.SearchStatus = {}; │ │ │ │ + var timestamp = this.getAttributeNS(node, "", 'timestamp'); │ │ │ │ + if (timestamp != "") { │ │ │ │ + obj.SearchStatus.timestamp = timestamp; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "SearchResults": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var SearchResults = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + if ((attrs[i].name == "numberOfRecordsMatched") || │ │ │ │ + (attrs[i].name == "numberOfRecordsReturned") || │ │ │ │ + (attrs[i].name == "nextRecord")) { │ │ │ │ + SearchResults[attrs[i].name] = parseInt(attrs[i].nodeValue); │ │ │ │ + } else { │ │ │ │ + SearchResults[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + obj.SearchResults = SearchResults; │ │ │ │ + }, │ │ │ │ + "SummaryRecord": function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "SummaryRecord" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record); │ │ │ │ + }, │ │ │ │ + "BriefRecord": function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "BriefRecord" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record); │ │ │ │ + }, │ │ │ │ + "DCMIRecord": function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "DCMIRecord" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record); │ │ │ │ + }, │ │ │ │ + "Record": function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "Record" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record); │ │ │ │ + }, │ │ │ │ + "*": function(node, obj) { │ │ │ │ + var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ + obj[name] = this.getChildValue(node); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "geonet": { │ │ │ │ + "info": function(node, obj) { │ │ │ │ + var gninfo = {}; │ │ │ │ + this.readChildNodes(node, gninfo); │ │ │ │ + obj.gninfo = gninfo; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "dc": { │ │ │ │ + // audience, contributor, coverage, creator, date, description, format, │ │ │ │ + // identifier, language, provenance, publisher, relation, rights, │ │ │ │ + // rightsHolder, source, subject, title, type, URI │ │ │ │ + "*": function(node, obj) { │ │ │ │ + var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ + if (!(OpenLayers.Util.isArray(obj[name]))) { │ │ │ │ + obj[name] = []; │ │ │ │ + } │ │ │ │ + var dc_element = {}; │ │ │ │ + var attrs = node.attributes; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + dc_element[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ + } │ │ │ │ + dc_element.value = this.getChildValue(node); │ │ │ │ + if (dc_element.value != "") { │ │ │ │ + obj[name].push(dc_element); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "dct": { │ │ │ │ + // abstract, modified, spatial │ │ │ │ + "*": function(node, obj) { │ │ │ │ + var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ + if (!(OpenLayers.Util.isArray(obj[name]))) { │ │ │ │ + obj[name] = []; │ │ │ │ + } │ │ │ │ + obj[name].push(this.getChildValue(node)); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "ows": OpenLayers.Util.applyDefaults({ │ │ │ │ + "BoundingBox": function(node, obj) { │ │ │ │ + if (obj.bounds) { │ │ │ │ + obj.BoundingBox = [{ │ │ │ │ + crs: obj.projection, │ │ │ │ + value: [ │ │ │ │ + obj.bounds.left, │ │ │ │ + obj.bounds.bottom, │ │ │ │ + obj.bounds.right, │ │ │ │ + obj.bounds.top │ │ │ │ + ] │ │ │ │ + }]; │ │ │ │ + delete obj.projection; │ │ │ │ + delete obj.bounds; │ │ │ │ + } │ │ │ │ + OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]["BoundingBox"].apply( │ │ │ │ + this, arguments); │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]) │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getDistance │ │ │ │ - * Get the distance in pixels between two touches. │ │ │ │ + * Method: write │ │ │ │ + * Given an configuration js object, write a CSWGetRecords request. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * touches - {Array(Object)} │ │ │ │ + * options - {Object} A object mapping the request. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Number} The distance in pixels. │ │ │ │ + * {String} A serialized CSWGetRecords request. │ │ │ │ */ │ │ │ │ - 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) │ │ │ │ - ); │ │ │ │ + write: function(options) { │ │ │ │ + var node = this.writeNode("csw:GetRecords", options); │ │ │ │ + node.setAttribute("xmlns:gmd", this.namespaces.gmd); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [node]); │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: getPinchData │ │ │ │ - * Get informations about the pinch event. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} Object that contains data about the current pinch. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }; │ │ │ │ + writers: { │ │ │ │ + "csw": { │ │ │ │ + "GetRecords": function(options) { │ │ │ │ + if (!options) { │ │ │ │ + options = {}; │ │ │ │ + } │ │ │ │ + var node = this.createElementNSPlus("csw:GetRecords", { │ │ │ │ + attributes: { │ │ │ │ + service: "CSW", │ │ │ │ + version: this.version, │ │ │ │ + requestId: options.requestId || this.requestId, │ │ │ │ + resultType: options.resultType || this.resultType, │ │ │ │ + outputFormat: options.outputFormat || this.outputFormat, │ │ │ │ + outputSchema: options.outputSchema || this.outputSchema, │ │ │ │ + startPosition: options.startPosition || this.startPosition, │ │ │ │ + maxRecords: options.maxRecords || this.maxRecords │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (options.DistributedSearch || this.DistributedSearch) { │ │ │ │ + this.writeNode( │ │ │ │ + "csw:DistributedSearch", │ │ │ │ + options.DistributedSearch || this.DistributedSearch, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + var ResponseHandler = options.ResponseHandler || this.ResponseHandler; │ │ │ │ + if (OpenLayers.Util.isArray(ResponseHandler) && ResponseHandler.length > 0) { │ │ │ │ + // ResponseHandler must be a non-empty array │ │ │ │ + for (var i = 0, len = ResponseHandler.length; i < len; i++) { │ │ │ │ + this.writeNode( │ │ │ │ + "csw:ResponseHandler", │ │ │ │ + ResponseHandler[i], │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.writeNode("Query", options.Query || this.Query, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "DistributedSearch": function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:DistributedSearch", { │ │ │ │ + attributes: { │ │ │ │ + hopCount: options.hopCount │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ResponseHandler": function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:ResponseHandler", { │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Query": function(options) { │ │ │ │ + if (!options) { │ │ │ │ + options = {}; │ │ │ │ + } │ │ │ │ + var node = this.createElementNSPlus("csw:Query", { │ │ │ │ + attributes: { │ │ │ │ + typeNames: options.typeNames || "csw:Record" │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + var ElementName = options.ElementName; │ │ │ │ + if (OpenLayers.Util.isArray(ElementName) && ElementName.length > 0) { │ │ │ │ + // ElementName must be a non-empty array │ │ │ │ + for (var i = 0, len = ElementName.length; i < len; i++) { │ │ │ │ + this.writeNode( │ │ │ │ + "csw:ElementName", │ │ │ │ + ElementName[i], │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.writeNode( │ │ │ │ + "csw:ElementSetName", │ │ │ │ + options.ElementSetName || { │ │ │ │ + value: 'summary' │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (options.Constraint) { │ │ │ │ + this.writeNode( │ │ │ │ + "csw:Constraint", │ │ │ │ + options.Constraint, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (options.SortBy) { │ │ │ │ + this.writeNode( │ │ │ │ + "ogc:SortBy", │ │ │ │ + options.SortBy, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ElementName": function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:ElementName", { │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ElementSetName": function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:ElementSetName", { │ │ │ │ + attributes: { │ │ │ │ + typeNames: options.typeNames │ │ │ │ + }, │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Constraint": function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:Constraint", { │ │ │ │ + attributes: { │ │ │ │ + version: options.version │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (options.Filter) { │ │ │ │ + var format = new OpenLayers.Format.Filter({ │ │ │ │ + version: options.version │ │ │ │ + }); │ │ │ │ + node.appendChild(format.write(options.Filter)); │ │ │ │ + } else if (options.CqlText) { │ │ │ │ + var child = this.createElementNSPlus("CqlText", { │ │ │ │ + value: options.CqlText.value │ │ │ │ + }); │ │ │ │ + node.appendChild(child); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "ogc": OpenLayers.Format.Filter.v1_1_0.prototype.writers["ogc"] │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Pinch" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.CSWGetRecords.v2_0_2" │ │ │ │ }); │ │ │ │ - │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/PinchZoom.js │ │ │ │ + OpenLayers/Protocol/CSW/v2_0_2.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 │ │ │ │ + * @requires OpenLayers/Protocol/CSW.js │ │ │ │ + * @requires OpenLayers/Format/CSWGetRecords/v2_0_2.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.PinchZoom │ │ │ │ + * Class: OpenLayers.Protocol.CSW.v2_0_2 │ │ │ │ + * CS-W (Catalogue services for the Web) version 2.0.2 protocol. │ │ │ │ * │ │ │ │ - * Inherits: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Protocol> │ │ │ │ */ │ │ │ │ -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, │ │ │ │ +OpenLayers.Protocol.CSW.v2_0_2 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: handlerOptions │ │ │ │ - * {Object} Used to set non-default properties on the pinch handler │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.PinchZoom │ │ │ │ - * Create a control for zooming with pinch gestures. This works on devices │ │ │ │ - * with multi-touch support. │ │ │ │ + * Constructor: OpenLayers.Protocol.CSW.v2_0_2 │ │ │ │ + * A class for CSW version 2.0.2 protocol management. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * the control │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ 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); │ │ │ │ + OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ + if (!options.format) { │ │ │ │ + this.format = new OpenLayers.Format.CSWGetRecords.v2_0_2(OpenLayers.Util.extend({}, this.formatOptions)); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Clean up the protocol. │ │ │ │ */ │ │ │ │ - pinchStart: function(evt, pinchData) { │ │ │ │ - var xy = (this.preserveCenter) ? │ │ │ │ - this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; │ │ │ │ - this.pinchOrigin = xy; │ │ │ │ - this.currentCenter = xy; │ │ │ │ + destroy: function() { │ │ │ │ + if (this.options && !this.options.format) { │ │ │ │ + this.format.destroy(); │ │ │ │ + } │ │ │ │ + this.format = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: read │ │ │ │ + * Construct a request for reading new records from the Catalogue. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + read: function(options) { │ │ │ │ + options = OpenLayers.Util.extend({}, options); │ │ │ │ + OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ + var response = new OpenLayers.Protocol.Response({ │ │ │ │ + requestType: "read" │ │ │ │ + }); │ │ │ │ │ │ │ │ - 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)); │ │ │ │ + var data = this.format.write(options.params || options); │ │ │ │ │ │ │ │ - this.map.applyTransform(dx, dy, scale); │ │ │ │ - this.currentCenter = current; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: pinchDone │ │ │ │ + * Method: handleRead │ │ │ │ + * Deal with response from the read request. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} The response object to pass │ │ │ │ + * to the user callback. │ │ │ │ + * This response is given a code property, and optionally a data property. │ │ │ │ + * The latter represents the CSW records as returned by the call to │ │ │ │ + * the CSW format read method. │ │ │ │ + * options - {Object} The user options passed to the read call. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + handleRead: function(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + var request = response.priv; │ │ │ │ + if (request.status >= 200 && request.status < 300) { │ │ │ │ + // success │ │ │ │ + response.data = this.parseData(request); │ │ │ │ + response.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ + } else { │ │ │ │ + // failure │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ + } │ │ │ │ + options.callback.call(options.scope, response); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.PinchZoom" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/ZoomIn.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/Button.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.ZoomIn │ │ │ │ - * The ZoomIn control is a button to increase the zoom level of a map. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.ZoomIn = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: trigger │ │ │ │ + * Method: parseData │ │ │ │ + * Read HTTP response body and return records │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * request - {XMLHttpRequest} The request object │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} The CSW records as returned by the call to the format read method. │ │ │ │ */ │ │ │ │ - trigger: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.zoomIn(); │ │ │ │ + parseData: 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); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomIn" │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.CSW.v2_0_2" │ │ │ │ + │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Control/ScaleLine.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ @@ -54086,3398 +57518,4261 @@ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Control.ScaleLine" │ │ │ │ }); │ │ │ │ │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Handler/Hover.js │ │ │ │ + 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/Handler.js │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Handler/Drag.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Handler.Hover │ │ │ │ - * The hover handler is to be used to emulate mouseovers on objects │ │ │ │ - * on the map that aren't DOM elements. For example one can use │ │ │ │ - * this handler to send WMS/GetFeatureInfo requests as the user │ │ │ │ - * moves the mouve over the map. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Control.DragPan │ │ │ │ + * The DragPan control pans the map with a drag of the mouse. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Handler> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ +OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: type │ │ │ │ + * {OpenLayers.Control.TYPES} │ │ │ │ + */ │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: delay │ │ │ │ - * {Integer} - Number of milliseconds between mousemoves before │ │ │ │ - * the event is considered a hover. Default is 500. │ │ │ │ + * Property: panned │ │ │ │ + * {Boolean} The map moved. │ │ │ │ */ │ │ │ │ - delay: 500, │ │ │ │ + panned: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: pixelTolerance │ │ │ │ - * {Integer} - Maximum number of pixels between mousemoves for │ │ │ │ - * an event to be considered a hover. Default is null. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - pixelTolerance: null, │ │ │ │ + interval: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: stopMove │ │ │ │ - * {Boolean} - Stop other listeners from being notified on mousemoves. │ │ │ │ - * Default is false. │ │ │ │ + * APIProperty: documentDrag │ │ │ │ + * {Boolean} If set to true, mouse dragging will continue even if the │ │ │ │ + * mouse cursor leaves the map viewport. Default is false. │ │ │ │ */ │ │ │ │ - stopMove: false, │ │ │ │ + documentDrag: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: px │ │ │ │ - * {<OpenLayers.Pixel>} - The location of the last mousemove, expressed │ │ │ │ - * in pixels. │ │ │ │ + * Property: kinetic │ │ │ │ + * {<OpenLayers.Kinetic>} The OpenLayers.Kinetic object. │ │ │ │ */ │ │ │ │ - px: null, │ │ │ │ + kinetic: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: timerId │ │ │ │ - * {Number} - The id of the timer. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - timerId: null, │ │ │ │ + enableKinetic: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Handler.Hover │ │ │ │ - * Construct a hover 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. │ │ │ │ - * callbacks - {Object} An object with keys corresponding to callbacks │ │ │ │ - * that will be called by the handler. The callbacks should │ │ │ │ - * expect to receive a single argument, the event. Callbacks for │ │ │ │ - * 'move', the mouse is moving, and 'pause', the mouse is pausing, │ │ │ │ - * are supported. │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * the handler. │ │ │ │ + * 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: mousemove │ │ │ │ - * Called when the mouse moves on the map. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Continue propagating this event. │ │ │ │ + * Method: draw │ │ │ │ + * Creates a Drag handler, using <panMap> and │ │ │ │ + * <panMapDone> as callbacks. │ │ │ │ */ │ │ │ │ - mousemove: function(evt) { │ │ │ │ - if (this.passesTolerance(evt.xy)) { │ │ │ │ - this.clearTimer(); │ │ │ │ - this.callback('move', [evt]); │ │ │ │ - this.px = evt.xy; │ │ │ │ - // clone the evt so original properties can be accessed even │ │ │ │ - // if the browser deletes them during the delay │ │ │ │ - evt = OpenLayers.Util.extend({}, evt); │ │ │ │ - this.timerId = window.setTimeout( │ │ │ │ - OpenLayers.Function.bind(this.delayedCall, this, evt), │ │ │ │ - this.delay │ │ │ │ - ); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - return !this.stopMove; │ │ │ │ + this.handler = new OpenLayers.Handler.Drag(this, { │ │ │ │ + "move": this.panMap, │ │ │ │ + "done": this.panMapDone, │ │ │ │ + "down": this.panMapStart │ │ │ │ + }, { │ │ │ │ + interval: this.interval, │ │ │ │ + documentDrag: this.documentDrag │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: mouseout │ │ │ │ - * Called when the mouse goes out of the map. │ │ │ │ + * Method: panMapStart │ │ │ │ + */ │ │ │ │ + panMapStart: function() { │ │ │ │ + if (this.kinetic) { │ │ │ │ + this.kinetic.begin(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: panMap │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Continue propagating this event. │ │ │ │ + * xy - {<OpenLayers.Pixel>} Pixel of the mouse position │ │ │ │ */ │ │ │ │ - mouseout: function(evt) { │ │ │ │ - if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ - this.clearTimer(); │ │ │ │ - this.callback('move', [evt]); │ │ │ │ + panMap: function(xy) { │ │ │ │ + if (this.kinetic) { │ │ │ │ + this.kinetic.update(xy); │ │ │ │ } │ │ │ │ - return true; │ │ │ │ + this.panned = true; │ │ │ │ + this.map.pan( │ │ │ │ + this.handler.last.x - xy.x, │ │ │ │ + this.handler.last.y - xy.y, { │ │ │ │ + dragging: true, │ │ │ │ + animate: false │ │ │ │ + } │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: passesTolerance │ │ │ │ - * Determine whether the mouse move is within the optional pixel tolerance. │ │ │ │ + * Method: panMapDone │ │ │ │ + * Finish the panning operation. Only call setCenter (through <panMap>) │ │ │ │ + * if the map has actually been moved. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * px - {<OpenLayers.Pixel>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The mouse move is within the pixel tolerance. │ │ │ │ + * xy - {<OpenLayers.Pixel>} Pixel of the mouse position │ │ │ │ */ │ │ │ │ - passesTolerance: function(px) { │ │ │ │ - var passes = true; │ │ │ │ - if (this.pixelTolerance && this.px) { │ │ │ │ - var dpx = Math.sqrt( │ │ │ │ - Math.pow(this.px.x - px.x, 2) + │ │ │ │ - Math.pow(this.px.y - px.y, 2) │ │ │ │ + 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 (dpx < this.pixelTolerance) { │ │ │ │ - passes = 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; │ │ │ │ } │ │ │ │ - return passes; │ │ │ │ }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.DragPan" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/Button.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.Button │ │ │ │ + * The Button control is a very simple push-button, for use with │ │ │ │ + * <OpenLayers.Control.Panel>. │ │ │ │ + * When clicked, the function trigger() is executed. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + * │ │ │ │ + * Use: │ │ │ │ + * (code) │ │ │ │ + * var button = new OpenLayers.Control.Button({ │ │ │ │ + * displayClass: "MyButton", trigger: myFunction │ │ │ │ + * }); │ │ │ │ + * panel.addControls([button]); │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Will create a button with CSS class MyButtonItemInactive, that │ │ │ │ + * will call the function MyFunction() when clicked. │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.Button = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ /** │ │ │ │ - * Method: clearTimer │ │ │ │ - * Clear the timer and set <timerId> to null. │ │ │ │ + * Property: type │ │ │ │ + * {Integer} OpenLayers.Control.TYPE_BUTTON. │ │ │ │ */ │ │ │ │ - clearTimer: function() { │ │ │ │ - if (this.timerId != null) { │ │ │ │ - window.clearTimeout(this.timerId); │ │ │ │ - this.timerId = null; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + type: OpenLayers.Control.TYPE_BUTTON, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: delayedCall │ │ │ │ - * Triggers pause callback. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ + * Method: trigger │ │ │ │ + * Called by a control panel when the button is clicked. │ │ │ │ */ │ │ │ │ - delayedCall: function(evt) { │ │ │ │ - this.callback('pause', [evt]); │ │ │ │ - }, │ │ │ │ + trigger: function() {}, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Button" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/ZoomIn.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/Button.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.ZoomIn │ │ │ │ + * The ZoomIn control is a button to increase the zoom level of a map. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.ZoomIn = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the handler. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The handler was successfully deactivated. │ │ │ │ + * Method: trigger │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = false; │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - this.clearTimer(); │ │ │ │ - deactivated = true; │ │ │ │ + trigger: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.zoomIn(); │ │ │ │ } │ │ │ │ - return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Hover" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomIn" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSGetFeatureInfo.js │ │ │ │ + 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/Format/XML.js │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WMSGetFeatureInfo │ │ │ │ - * Class to read GetFeatureInfo responses from Web Mapping Services │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ + * 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.Format.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ +OpenLayers.Events.buttonclick = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layerIdentifier │ │ │ │ - * {String} All xml nodes containing this search criteria will populate an │ │ │ │ - * internal array of layer nodes. │ │ │ │ + * Property: target │ │ │ │ + * {<OpenLayers.Events>} The events instance that the buttonclick event will │ │ │ │ + * be triggered on. │ │ │ │ */ │ │ │ │ - layerIdentifier: '_layer', │ │ │ │ + target: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: featureIdentifier │ │ │ │ - * {String} All xml nodes containing this search criteria will populate an │ │ │ │ - * internal array of feature nodes for each layer node found. │ │ │ │ + * Property: events │ │ │ │ + * {Array} Events to observe and conditionally stop from propagating when │ │ │ │ + * an element with the olButton class (or its olAlphaImg child) is │ │ │ │ + * clicked. │ │ │ │ */ │ │ │ │ - featureIdentifier: '_feature', │ │ │ │ + events: [ │ │ │ │ + 'mousedown', 'mouseup', 'click', 'dblclick', │ │ │ │ + 'touchstart', 'touchmove', 'touchend', 'keydown' │ │ │ │ + ], │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ + * Property: startRegEx │ │ │ │ + * {RegExp} Regular expression to test Event.type for events that start │ │ │ │ + * a buttonclick sequence. │ │ │ │ */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ - }, │ │ │ │ + startRegEx: /^mousedown|touchstart$/, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: gmlFormat │ │ │ │ - * {<OpenLayers.Format.GML>} internal GML format for parsing geometries │ │ │ │ - * in msGMLOutput │ │ │ │ + * Property: cancelRegEx │ │ │ │ + * {RegExp} Regular expression to test Event.type for events that cancel │ │ │ │ + * a buttonclick sequence. │ │ │ │ */ │ │ │ │ - gmlFormat: null, │ │ │ │ + cancelRegEx: /^touchmove$/, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WMSGetFeatureInfo │ │ │ │ - * Create a new parser for WMS GetFeatureInfo responses │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * Property: completeRegEx │ │ │ │ + * {RegExp} Regular expression to test Event.type for events that complete │ │ │ │ + * a buttonclick sequence. │ │ │ │ */ │ │ │ │ + completeRegEx: /^mouseup|touchend$/, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read WMS GetFeatureInfo data from a string, and return an array of features │ │ │ │ + * 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: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} An array of features. │ │ │ │ + * target - {<OpenLayers.Events>} The events instance that the buttonclick │ │ │ │ + * event will be triggered on. │ │ │ │ */ │ │ │ │ - read: function(data) { │ │ │ │ - var result; │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - } │ │ │ │ - var root = data.documentElement; │ │ │ │ - if (root) { │ │ │ │ - var scope = this; │ │ │ │ - var read = this["read_" + root.nodeName]; │ │ │ │ - if (read) { │ │ │ │ - result = read.call(this, root); │ │ │ │ - } else { │ │ │ │ - // fall-back to GML since this is a common output format for WMS │ │ │ │ - // GetFeatureInfo responses │ │ │ │ - result = new OpenLayers.Format.GML((this.options ? this.options : {})).read(data); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - result = data; │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ } │ │ │ │ - return result; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: read_msGMLOutput │ │ │ │ - * Parse msGMLOutput nodes. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {DOMElement} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - read_msGMLOutput: function(data) { │ │ │ │ - var response = []; │ │ │ │ - var layerNodes = this.getSiblingNodesByTagCriteria(data, │ │ │ │ - this.layerIdentifier); │ │ │ │ - if (layerNodes) { │ │ │ │ - for (var i = 0, len = layerNodes.length; i < len; ++i) { │ │ │ │ - var node = layerNodes[i]; │ │ │ │ - var layerName = node.nodeName; │ │ │ │ - if (node.prefix) { │ │ │ │ - layerName = layerName.split(':')[1]; │ │ │ │ - } │ │ │ │ - var layerName = layerName.replace(this.layerIdentifier, ''); │ │ │ │ - var featureNodes = this.getSiblingNodesByTagCriteria(node, │ │ │ │ - this.featureIdentifier); │ │ │ │ - if (featureNodes) { │ │ │ │ - for (var j = 0; j < featureNodes.length; j++) { │ │ │ │ - var featureNode = featureNodes[j]; │ │ │ │ - var geomInfo = this.parseGeometry(featureNode); │ │ │ │ - var attributes = this.parseAttributes(featureNode); │ │ │ │ - var feature = new OpenLayers.Feature.Vector(geomInfo.geometry, │ │ │ │ - attributes, null); │ │ │ │ - feature.bounds = geomInfo.bounds; │ │ │ │ - feature.type = layerName; │ │ │ │ - response.push(feature); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + destroy: function() { │ │ │ │ + for (var i = this.events.length - 1; i >= 0; --i) { │ │ │ │ + this.target.unregister(this.events[i], this, this.buttonClick); │ │ │ │ } │ │ │ │ - return response; │ │ │ │ + delete this.target; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: read_FeatureInfoResponse │ │ │ │ - * Parse FeatureInfoResponse nodes. │ │ │ │ + * Method: getPressedButton │ │ │ │ + * Get the pressed button, if any. Returns undefined if no button │ │ │ │ + * was pressed. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * data - {DOMElement} │ │ │ │ + * Arguments: │ │ │ │ + * element - {DOMElement} The event target. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Array} │ │ │ │ + * {DOMElement} The button element, or undefined. │ │ │ │ */ │ │ │ │ - read_FeatureInfoResponse: function(data) { │ │ │ │ - var response = []; │ │ │ │ - var featureNodes = this.getElementsByTagNameNS(data, '*', │ │ │ │ - 'FIELDS'); │ │ │ │ - │ │ │ │ - for (var i = 0, len = featureNodes.length; i < len; i++) { │ │ │ │ - var featureNode = featureNodes[i]; │ │ │ │ - var geom = null; │ │ │ │ - │ │ │ │ - // attributes can be actual attributes on the FIELDS tag, │ │ │ │ - // or FIELD children │ │ │ │ - var attributes = {}; │ │ │ │ - var j; │ │ │ │ - var jlen = featureNode.attributes.length; │ │ │ │ - if (jlen > 0) { │ │ │ │ - for (j = 0; j < jlen; j++) { │ │ │ │ - var attribute = featureNode.attributes[j]; │ │ │ │ - attributes[attribute.nodeName] = attribute.nodeValue; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - var nodes = featureNode.childNodes; │ │ │ │ - for (j = 0, jlen = nodes.length; j < jlen; ++j) { │ │ │ │ - var node = nodes[j]; │ │ │ │ - if (node.nodeType != 3) { │ │ │ │ - attributes[node.getAttribute("name")] = │ │ │ │ - node.getAttribute("value"); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + getPressedButton: function(element) { │ │ │ │ + var depth = 3, // limit the search depth │ │ │ │ + button; │ │ │ │ + do { │ │ │ │ + if (OpenLayers.Element.hasClass(element, "olButton")) { │ │ │ │ + // hit! │ │ │ │ + button = element; │ │ │ │ + break; │ │ │ │ } │ │ │ │ - │ │ │ │ - response.push( │ │ │ │ - new OpenLayers.Feature.Vector(geom, attributes, null) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return response; │ │ │ │ + element = element.parentNode; │ │ │ │ + } while (--depth > 0 && element); │ │ │ │ + return button; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getSiblingNodesByTagCriteria │ │ │ │ - * Recursively searches passed xml node and all it's descendant levels for │ │ │ │ - * nodes whose tagName contains the passed search string. This returns an │ │ │ │ - * array of all sibling nodes which match the criteria from the highest │ │ │ │ - * hierarchial level from which a match is found. │ │ │ │ - * │ │ │ │ + * Method: ignore │ │ │ │ + * Check for event target elements that should be ignored by OpenLayers. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} An xml node │ │ │ │ - * criteria - {String} Search string which will match some part of a tagName │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * Array({DOMElement}) An array of sibling xml nodes │ │ │ │ + * element - {DOMElement} The event target. │ │ │ │ */ │ │ │ │ - getSiblingNodesByTagCriteria: function(node, criteria) { │ │ │ │ - var nodes = []; │ │ │ │ - var children, tagName, n, matchNodes, child; │ │ │ │ - if (node && node.hasChildNodes()) { │ │ │ │ - children = node.childNodes; │ │ │ │ - n = children.length; │ │ │ │ - │ │ │ │ - for (var k = 0; k < n; k++) { │ │ │ │ - child = children[k]; │ │ │ │ - while (child && child.nodeType != 1) { │ │ │ │ - child = child.nextSibling; │ │ │ │ - k++; │ │ │ │ - } │ │ │ │ - tagName = (child ? child.nodeName : ''); │ │ │ │ - if (tagName.length > 0 && tagName.indexOf(criteria) > -1) { │ │ │ │ - nodes.push(child); │ │ │ │ - } else { │ │ │ │ - matchNodes = this.getSiblingNodesByTagCriteria( │ │ │ │ - child, criteria); │ │ │ │ - │ │ │ │ - if (matchNodes.length > 0) { │ │ │ │ - (nodes.length == 0) ? │ │ │ │ - nodes = matchNodes: nodes.push(matchNodes); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + ignore: function(element) { │ │ │ │ + var depth = 3, │ │ │ │ + ignore = false; │ │ │ │ + do { │ │ │ │ + if (element.nodeName.toLowerCase() === 'a') { │ │ │ │ + ignore = true; │ │ │ │ + break; │ │ │ │ } │ │ │ │ - │ │ │ │ - } │ │ │ │ - return nodes; │ │ │ │ + element = element.parentNode; │ │ │ │ + } while (--depth > 0 && element); │ │ │ │ + return ignore; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseAttributes │ │ │ │ + * Method: buttonClick │ │ │ │ + * Check if a button was clicked, and fire the buttonclick event │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {<DOMElement>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An attributes object. │ │ │ │ - * │ │ │ │ - * Notes: │ │ │ │ - * Assumes that attributes are direct child xml nodes of the passed node │ │ │ │ - * and contain only a single text node. │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - parseAttributes: function(node) { │ │ │ │ - var attributes = {}; │ │ │ │ - if (node.nodeType == 1) { │ │ │ │ - var children = node.childNodes; │ │ │ │ - var n = children.length; │ │ │ │ - for (var i = 0; i < n; ++i) { │ │ │ │ - var child = children[i]; │ │ │ │ - if (child.nodeType == 1) { │ │ │ │ - var grandchildren = child.childNodes; │ │ │ │ - var name = (child.prefix) ? │ │ │ │ - child.nodeName.split(":")[1] : child.nodeName; │ │ │ │ - if (grandchildren.length == 0) { │ │ │ │ - attributes[name] = null; │ │ │ │ - } else if (grandchildren.length == 1) { │ │ │ │ - var grandchild = grandchildren[0]; │ │ │ │ - if (grandchild.nodeType == 3 || │ │ │ │ - grandchild.nodeType == 4) { │ │ │ │ - var value = grandchild.nodeValue.replace( │ │ │ │ - this.regExes.trimSpace, ""); │ │ │ │ - attributes[name] = value; │ │ │ │ - } │ │ │ │ + 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 attributes; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: parseGeometry │ │ │ │ - * Parse the geometry and the feature bounds out of the node using │ │ │ │ - * Format.GML │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {<DOMElement>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An object containing the geometry and the feature bounds │ │ │ │ - */ │ │ │ │ - parseGeometry: function(node) { │ │ │ │ - // we need to use the old Format.GML parser since we do not know the │ │ │ │ - // geometry name │ │ │ │ - if (!this.gmlFormat) { │ │ │ │ - this.gmlFormat = new OpenLayers.Format.GML(); │ │ │ │ - } │ │ │ │ - var feature = this.gmlFormat.parseFeature(node); │ │ │ │ - var geometry, bounds = null; │ │ │ │ - if (feature) { │ │ │ │ - geometry = feature.geometry && feature.geometry.clone(); │ │ │ │ - bounds = feature.bounds && feature.bounds.clone(); │ │ │ │ - feature.destroy(); │ │ │ │ - } │ │ │ │ - return { │ │ │ │ - geometry: geometry, │ │ │ │ - bounds: bounds │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSGetFeatureInfo" │ │ │ │ + return propagate; │ │ │ │ + } │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/WMSGetFeatureInfo.js │ │ │ │ + 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/Handler/Click.js │ │ │ │ - * @requires OpenLayers/Handler/Hover.js │ │ │ │ - * @requires OpenLayers/Request.js │ │ │ │ - * @requires OpenLayers/Format/WMSGetFeatureInfo.js │ │ │ │ + * @requires OpenLayers/Events/buttonclick.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.WMSGetFeatureInfo │ │ │ │ - * The WMSGetFeatureInfo control uses a WMS query to get information about a point on the map. The │ │ │ │ - * information may be in a display-friendly format such as HTML, or a machine-friendly format such │ │ │ │ - * as GML, depending on the server's capabilities and the client's configuration. This control │ │ │ │ - * handles click or hover events, attempts to parse the results using an OpenLayers.Format, and │ │ │ │ - * fires a 'getfeatureinfo' event with the click position, the raw body of the response, and an │ │ │ │ - * array of features if it successfully read the response. │ │ │ │ + * 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.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: hover │ │ │ │ - * {Boolean} Send GetFeatureInfo requests when mouse stops moving. │ │ │ │ - * Default is false. │ │ │ │ - */ │ │ │ │ - hover: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: drillDown │ │ │ │ - * {Boolean} Drill down over all WMS layers in the map. When │ │ │ │ - * using drillDown mode, hover is not possible, and an infoFormat that │ │ │ │ - * returns parseable features is required. Default is false. │ │ │ │ - */ │ │ │ │ - drillDown: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: maxFeatures │ │ │ │ - * {Integer} Maximum number of features to return from a WMS query. This │ │ │ │ - * sets the feature_count parameter on WMS GetFeatureInfo │ │ │ │ - * requests. │ │ │ │ - */ │ │ │ │ - maxFeatures: 10, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: clickCallback │ │ │ │ - * {String} The click callback to register in the │ │ │ │ - * {<OpenLayers.Handler.Click>} object created when the hover │ │ │ │ - * option is set to false. Default is "click". │ │ │ │ - */ │ │ │ │ - clickCallback: "click", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: output │ │ │ │ - * {String} Either "features" or "object". When triggering a getfeatureinfo │ │ │ │ - * request should we pass on an array of features or an object with with │ │ │ │ - * a "features" property and other properties (such as the url of the │ │ │ │ - * WMS). Default is "features". │ │ │ │ - */ │ │ │ │ - output: "features", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: layers │ │ │ │ - * {Array(<OpenLayers.Layer.WMS>)} The layers to query for feature info. │ │ │ │ - * If omitted, all map WMS layers with a url that matches this <url> or │ │ │ │ - * <layerUrls> will be considered. │ │ │ │ - */ │ │ │ │ - layers: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: queryVisible │ │ │ │ - * {Boolean} If true, filter out hidden layers when searching the map for │ │ │ │ - * layers to query. Default is false. │ │ │ │ - */ │ │ │ │ - queryVisible: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: url │ │ │ │ - * {String} The URL of the WMS service to use. If not provided, the url │ │ │ │ - * of the first eligible layer will be used. │ │ │ │ - */ │ │ │ │ - url: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: layerUrls │ │ │ │ - * {Array(String)} Optional list of urls for layers that should be queried. │ │ │ │ - * This can be used when the layer url differs from the url used for │ │ │ │ - * making GetFeatureInfo requests (in the case of a layer using cached │ │ │ │ - * tiles). │ │ │ │ - */ │ │ │ │ - layerUrls: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: infoFormat │ │ │ │ - * {String} The mimetype to request from the server. If you are using │ │ │ │ - * drillDown mode and have multiple servers that do not share a common │ │ │ │ - * infoFormat, you can override the control's infoFormat by providing an │ │ │ │ - * INFO_FORMAT parameter in your <OpenLayers.Layer.WMS> instance(s). │ │ │ │ - */ │ │ │ │ - infoFormat: 'text/html', │ │ │ │ - │ │ │ │ +OpenLayers.Control.Panel = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ /** │ │ │ │ - * APIProperty: vendorParams │ │ │ │ - * {Object} Additional parameters that will be added to the request, for │ │ │ │ - * WMS implementations that support them. This could e.g. look like │ │ │ │ - * (start code) │ │ │ │ - * { │ │ │ │ - * radius: 5 │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ + * Property: controls │ │ │ │ + * {Array(<OpenLayers.Control>)} │ │ │ │ */ │ │ │ │ - vendorParams: {}, │ │ │ │ + controls: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: format │ │ │ │ - * {<OpenLayers.Format>} A format for parsing GetFeatureInfo responses. │ │ │ │ - * Default is <OpenLayers.Format.WMSGetFeatureInfo>. │ │ │ │ + * APIProperty: autoActivate │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * true. │ │ │ │ */ │ │ │ │ - format: null, │ │ │ │ + autoActivate: true, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: formatOptions │ │ │ │ - * {Object} Optional properties to set on the format (if one is not provided │ │ │ │ - * in the <format> property. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - formatOptions: null, │ │ │ │ + defaultControl: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: handlerOptions │ │ │ │ - * {Object} Additional options for the handlers used by this control, e.g. │ │ │ │ - * (start code) │ │ │ │ - * { │ │ │ │ - * "click": {delay: 100}, │ │ │ │ - * "hover": {delay: 300} │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: handler │ │ │ │ - * {Object} Reference to the <OpenLayers.Handler> for this control │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - handler: null, │ │ │ │ + allowDepress: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: hoverRequest │ │ │ │ - * {<OpenLayers.Request>} contains the currently running hover request │ │ │ │ - * (if any). │ │ │ │ + * Property: activeState │ │ │ │ + * {Object} stores the active state of this panel's controls. │ │ │ │ */ │ │ │ │ - hoverRequest: null, │ │ │ │ + activeState: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: events │ │ │ │ - * {<OpenLayers.Events>} Events instance for listeners and triggering │ │ │ │ - * control specific events. │ │ │ │ + * Constructor: OpenLayers.Control.Panel │ │ │ │ + * Create a new control panel. │ │ │ │ * │ │ │ │ - * Register a listener for a particular event with the following syntax: │ │ │ │ - * (code) │ │ │ │ - * control.events.register(type, obj, listener); │ │ │ │ - * (end) │ │ │ │ + * Each control in the panel is represented by an icon. When clicking │ │ │ │ + * on an icon, the <activateControl> method is called. │ │ │ │ * │ │ │ │ - * Supported event types (in addition to those from <OpenLayers.Control.events>): │ │ │ │ - * beforegetfeatureinfo - Triggered before the request is sent. │ │ │ │ - * The event object has an *xy* property with the position of the │ │ │ │ - * mouse click or hover event that triggers the request. │ │ │ │ - * nogetfeatureinfo - no queryable layers were found. │ │ │ │ - * getfeatureinfo - Triggered when a GetFeatureInfo response is received. │ │ │ │ - * The event object has a *text* property with the body of the │ │ │ │ - * response (String), a *features* property with an array of the │ │ │ │ - * parsed features, an *xy* property with the position of the mouse │ │ │ │ - * click or hover event that triggered the request, and a *request* │ │ │ │ - * property with the request itself. If drillDown is set to true and │ │ │ │ - * multiple requests were issued to collect feature info from all │ │ │ │ - * layers, *text* and *request* will only contain the response body │ │ │ │ - * and request object of the last request. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: <OpenLayers.Control.WMSGetFeatureInfo> │ │ │ │ + * 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} │ │ │ │ + * options - {Object} An optional object whose properties will be used │ │ │ │ + * to extend the control. │ │ │ │ */ │ │ │ │ initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.handlerOptions = options.handlerOptions || {}; │ │ │ │ - │ │ │ │ OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.controls = []; │ │ │ │ + this.activeState = {}; │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (!this.format) { │ │ │ │ - this.format = new OpenLayers.Format.WMSGetFeatureInfo( │ │ │ │ - options.formatOptions │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.drillDown === true) { │ │ │ │ - this.hover = false; │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ } │ │ │ │ - │ │ │ │ - if (this.hover) { │ │ │ │ - this.handler = new OpenLayers.Handler.Hover( │ │ │ │ - this, { │ │ │ │ - 'move': this.cancelHover, │ │ │ │ - 'pause': this.getInfoForHover │ │ │ │ - }, │ │ │ │ - OpenLayers.Util.extend(this.handlerOptions.hover || {}, { │ │ │ │ - 'delay': 250 │ │ │ │ - })); │ │ │ │ - } else { │ │ │ │ - var callbacks = {}; │ │ │ │ - callbacks[this.clickCallback] = this.getInfoForClick; │ │ │ │ - this.handler = new OpenLayers.Handler.Click( │ │ │ │ - this, callbacks, this.handlerOptions.click || {}); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getInfoForClick │ │ │ │ - * Called on click │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ + * APIMethod: activate │ │ │ │ */ │ │ │ │ - getInfoForClick: function(evt) { │ │ │ │ - this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ - xy: evt.xy │ │ │ │ - }); │ │ │ │ - // Set the cursor to "wait" to tell the user we're working on their │ │ │ │ - // click. │ │ │ │ - OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - this.request(evt.xy, {}); │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getInfoForHover │ │ │ │ - * Pause callback for the hover handler │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} │ │ │ │ + * APIMethod: deactivate │ │ │ │ */ │ │ │ │ - getInfoForHover: function(evt) { │ │ │ │ - this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ - xy: evt.xy │ │ │ │ - }); │ │ │ │ - this.request(evt.xy, { │ │ │ │ - hover: true │ │ │ │ - }); │ │ │ │ + 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: cancelHover │ │ │ │ - * Cancel callback for the hover handler │ │ │ │ + * Method: draw │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - cancelHover: function() { │ │ │ │ - if (this.hoverRequest) { │ │ │ │ - this.hoverRequest.abort(); │ │ │ │ - this.hoverRequest = null; │ │ │ │ + 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: findLayers │ │ │ │ - * Internal method to get the layers, independent of whether we are │ │ │ │ - * inspecting the map or using a client-provided array │ │ │ │ + * Method: redraw │ │ │ │ */ │ │ │ │ - findLayers: function() { │ │ │ │ - │ │ │ │ - var candidates = this.layers || this.map.layers; │ │ │ │ - var layers = []; │ │ │ │ - var layer, url; │ │ │ │ - for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ - layer = candidates[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.WMS && │ │ │ │ - (!this.queryVisible || layer.getVisibility())) { │ │ │ │ - url = OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url; │ │ │ │ - // if the control was not configured with a url, set it │ │ │ │ - // to the first layer url │ │ │ │ - if (this.drillDown === false && !this.url) { │ │ │ │ - this.url = url; │ │ │ │ - } │ │ │ │ - if (this.drillDown === true || this.urlMatches(url)) { │ │ │ │ - layers.push(layer); │ │ │ │ - } │ │ │ │ + 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); │ │ │ │ } │ │ │ │ } │ │ │ │ - return layers; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: urlMatches │ │ │ │ - * Test to see if the provided url matches either the control <url> or one │ │ │ │ - * of the <layerUrls>. │ │ │ │ + * APIMethod: activateControl │ │ │ │ + * This method is called when the user click on the icon representing a │ │ │ │ + * control in the panel. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * url - {String} The url to test. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The provided url matches the control <url> or one of the │ │ │ │ - * <layerUrls>. │ │ │ │ + * control - {<OpenLayers.Control>} │ │ │ │ */ │ │ │ │ - urlMatches: function(url) { │ │ │ │ - var matches = OpenLayers.Util.isEquivalentUrl(this.url, url); │ │ │ │ - if (!matches && this.layerUrls) { │ │ │ │ - for (var i = 0, len = this.layerUrls.length; i < len; ++i) { │ │ │ │ - if (OpenLayers.Util.isEquivalentUrl(this.layerUrls[i], url)) { │ │ │ │ - matches = true; │ │ │ │ - break; │ │ │ │ + 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(); │ │ │ │ } │ │ │ │ - return matches; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: buildWMSOptions │ │ │ │ - * Build an object with the relevant WMS options for the GetFeatureInfo request │ │ │ │ + * 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: │ │ │ │ - * url - {String} The url to be used for sending the request │ │ │ │ - * layers - {Array(<OpenLayers.Layer.WMS)} An array of layers │ │ │ │ - * clickPosition - {<OpenLayers.Pixel>} The position on the map where the mouse │ │ │ │ - * event occurred. │ │ │ │ - * format - {String} The format from the corresponding GetMap request │ │ │ │ + * controls - {<OpenLayers.Control>} Controls to add in the panel. │ │ │ │ */ │ │ │ │ - buildWMSOptions: function(url, layers, clickPosition, format) { │ │ │ │ - var layerNames = [], │ │ │ │ - styleNames = []; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - if (layers[i].params.LAYERS != null) { │ │ │ │ - layerNames = layerNames.concat(layers[i].params.LAYERS); │ │ │ │ - styleNames = styleNames.concat(this.getStyleNames(layers[i])); │ │ │ │ - } │ │ │ │ + addControls: function(controls) { │ │ │ │ + if (!(OpenLayers.Util.isArray(controls))) { │ │ │ │ + controls = [controls]; │ │ │ │ } │ │ │ │ - var firstLayer = layers[0]; │ │ │ │ - // use the firstLayer's projection if it matches the map projection - │ │ │ │ - // this assumes that all layers will be available in this projection │ │ │ │ - var projection = this.map.getProjection(); │ │ │ │ - var layerProj = firstLayer.projection; │ │ │ │ - if (layerProj && layerProj.equals(this.map.getProjectionObject())) { │ │ │ │ - projection = layerProj.getCode(); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - var params = OpenLayers.Util.extend({ │ │ │ │ - service: "WMS", │ │ │ │ - version: firstLayer.params.VERSION, │ │ │ │ - request: "GetFeatureInfo", │ │ │ │ - exceptions: firstLayer.params.EXCEPTIONS, │ │ │ │ - bbox: this.map.getExtent().toBBOX(null, │ │ │ │ - firstLayer.reverseAxisOrder()), │ │ │ │ - feature_count: this.maxFeatures, │ │ │ │ - height: this.map.getSize().h, │ │ │ │ - width: this.map.getSize().w, │ │ │ │ - format: format, │ │ │ │ - info_format: firstLayer.params.INFO_FORMAT || this.infoFormat │ │ │ │ - }, (parseFloat(firstLayer.params.VERSION) >= 1.3) ? { │ │ │ │ - crs: projection, │ │ │ │ - i: parseInt(clickPosition.x), │ │ │ │ - j: parseInt(clickPosition.y) │ │ │ │ - } : { │ │ │ │ - srs: projection, │ │ │ │ - x: parseInt(clickPosition.x), │ │ │ │ - y: parseInt(clickPosition.y) │ │ │ │ - }); │ │ │ │ - if (layerNames.length != 0) { │ │ │ │ - params = OpenLayers.Util.extend({ │ │ │ │ - layers: layerNames, │ │ │ │ - query_layers: layerNames, │ │ │ │ - styles: styleNames │ │ │ │ - }, params); │ │ │ │ + │ │ │ │ + if (this.map) { // map.addControl() has already been called on the panel │ │ │ │ + this.addControlsToMap(controls); │ │ │ │ + this.redraw(); │ │ │ │ } │ │ │ │ - OpenLayers.Util.applyDefaults(params, this.vendorParams); │ │ │ │ - return { │ │ │ │ - url: url, │ │ │ │ - params: OpenLayers.Util.upperCaseObject(params), │ │ │ │ - callback: function(request) { │ │ │ │ - this.handleResponse(clickPosition, request, url); │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getStyleNames │ │ │ │ - * Gets the STYLES parameter for the layer. Make sure the STYLES parameter │ │ │ │ - * matches the LAYERS parameter │ │ │ │ + * 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: │ │ │ │ - * layer - {<OpenLayers.Layer.WMS>} │ │ │ │ + * control - {<OpenLayers.Control>} The control to create the HTML │ │ │ │ + * markup for. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Array(String)} The STYLES parameter │ │ │ │ + * {DOMElement} The markup. │ │ │ │ */ │ │ │ │ - getStyleNames: function(layer) { │ │ │ │ - // in the event of a WMS layer bundling multiple layers but not │ │ │ │ - // specifying styles,we need the same number of commas to specify │ │ │ │ - // the default style for each of the layers. We can't just leave it │ │ │ │ - // blank as we may be including other layers that do specify styles. │ │ │ │ - var styleNames; │ │ │ │ - if (layer.params.STYLES) { │ │ │ │ - styleNames = layer.params.STYLES; │ │ │ │ - } else { │ │ │ │ - if (OpenLayers.Util.isArray(layer.params.LAYERS)) { │ │ │ │ - styleNames = new Array(layer.params.LAYERS.length); │ │ │ │ - } else { // Assume it's a String │ │ │ │ - styleNames = layer.params.LAYERS.replace(/[^,]/g, ""); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return styleNames; │ │ │ │ + createControlMarkup: function(control) { │ │ │ │ + return document.createElement("div"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: request │ │ │ │ - * Sends a GetFeatureInfo request to the WMS │ │ │ │ + * Method: addControlsToMap │ │ │ │ + * Only for internal use in draw() and addControls() methods. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * clickPosition - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ - * mouse event occurred. │ │ │ │ - * options - {Object} additional options for this method. │ │ │ │ - * │ │ │ │ - * Valid options: │ │ │ │ - * - *hover* {Boolean} true if we do the request for the hover handler │ │ │ │ + * controls - {Array(<OpenLayers.Control>)} Controls to add into map. │ │ │ │ */ │ │ │ │ - request: function(clickPosition, options) { │ │ │ │ - var layers = this.findLayers(); │ │ │ │ - if (layers.length == 0) { │ │ │ │ - this.events.triggerEvent("nogetfeatureinfo"); │ │ │ │ - // Reset the cursor. │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - │ │ │ │ - options = options || {}; │ │ │ │ - if (this.drillDown === false) { │ │ │ │ - var wmsOptions = this.buildWMSOptions(this.url, layers, │ │ │ │ - clickPosition, layers[0].params.FORMAT); │ │ │ │ - var request = OpenLayers.Request.GET(wmsOptions); │ │ │ │ - │ │ │ │ - if (options.hover === true) { │ │ │ │ - this.hoverRequest = request; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this._requestCount = 0; │ │ │ │ - this._numRequests = 0; │ │ │ │ - this.features = []; │ │ │ │ - // group according to service url to combine requests │ │ │ │ - var services = {}, │ │ │ │ - url; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - var layer = layers[i]; │ │ │ │ - var service, found = false; │ │ │ │ - url = OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url; │ │ │ │ - if (url in services) { │ │ │ │ - services[url].push(layer); │ │ │ │ - } else { │ │ │ │ - this._numRequests++; │ │ │ │ - services[url] = [layer]; │ │ │ │ - } │ │ │ │ + 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(); │ │ │ │ } │ │ │ │ - var layers; │ │ │ │ - for (var url in services) { │ │ │ │ - layers = services[url]; │ │ │ │ - var wmsOptions = this.buildWMSOptions(url, layers, │ │ │ │ - clickPosition, layers[0].params.FORMAT); │ │ │ │ - OpenLayers.Request.GET(wmsOptions); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: triggerGetFeatureInfo │ │ │ │ - * Trigger the getfeatureinfo event when all is done │ │ │ │ + * APIMethod: getControlsBy │ │ │ │ + * Get a list of controls with properties matching the given criteria. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * request - {XMLHttpRequest} The request object │ │ │ │ - * xy - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ - * mouse event occurred. │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} or │ │ │ │ - * {Array({Object}) when output is "object". The object has a url and a │ │ │ │ - * features property which contains an array of features. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - triggerGetFeatureInfo: function(request, xy, features) { │ │ │ │ - this.events.triggerEvent("getfeatureinfo", { │ │ │ │ - text: request.responseText, │ │ │ │ - features: features, │ │ │ │ - request: request, │ │ │ │ - xy: xy │ │ │ │ + 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])); │ │ │ │ }); │ │ │ │ - │ │ │ │ - // Reset the cursor. │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + return found; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handleResponse │ │ │ │ - * Handler for the GetFeatureInfo response. │ │ │ │ + * APIMethod: getControlsByName │ │ │ │ + * Get a list of contorls with names matching the given name. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * xy - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ - * mouse event occurred. │ │ │ │ - * request - {XMLHttpRequest} The request object. │ │ │ │ - * url - {String} The url which was used for this request. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - handleResponse: function(xy, request, url) { │ │ │ │ + getControlsByName: function(match) { │ │ │ │ + return this.getControlsBy("name", match); │ │ │ │ + }, │ │ │ │ │ │ │ │ - var doc = request.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = request.responseText; │ │ │ │ - } │ │ │ │ - var features = this.format.read(doc); │ │ │ │ - if (this.drillDown === false) { │ │ │ │ - this.triggerGetFeatureInfo(request, xy, features); │ │ │ │ - } else { │ │ │ │ - this._requestCount++; │ │ │ │ - if (this.output === "object") { │ │ │ │ - this._features = (this._features || []).concat({ │ │ │ │ - url: url, │ │ │ │ - features: features │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - this._features = (this._features || []).concat(features); │ │ │ │ - } │ │ │ │ - if (this._requestCount === this._numRequests) { │ │ │ │ - this.triggerGetFeatureInfo(request, xy, this._features.concat()); │ │ │ │ - delete this._features; │ │ │ │ - delete this._requestCount; │ │ │ │ - delete this._numRequests; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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.WMSGetFeatureInfo" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Panel" │ │ │ │ }); │ │ │ │ + │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/OverviewMap.js │ │ │ │ + OpenLayers/Control/PanZoom.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/BaseTypes.js │ │ │ │ * @requires OpenLayers/Events/buttonclick.js │ │ │ │ - * @requires OpenLayers/Map.js │ │ │ │ - * @requires OpenLayers/Handler/Click.js │ │ │ │ - * @requires OpenLayers/Handler/Drag.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.OverviewMap │ │ │ │ - * The OverMap control creates a small overview map, useful to display the │ │ │ │ - * extent of a zoomed map and your main map and provide additional │ │ │ │ - * navigation options to the User. By default the overview map is drawn in │ │ │ │ - * the lower right corner of the main map. Create a new overview map with the │ │ │ │ - * <OpenLayers.Control.OverviewMap> constructor. │ │ │ │ + * Class: OpenLayers.Control.PanZoom │ │ │ │ + * The PanZoom is a visible control, composed of a │ │ │ │ + * <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomPanel>. By │ │ │ │ + * default it is drawn in the upper left corner of the map. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: element │ │ │ │ - * {DOMElement} The DOM element that contains the overview map │ │ │ │ + /** │ │ │ │ + * APIProperty: slideFactor │ │ │ │ + * {Integer} Number of pixels by which we'll pan the map in any direction │ │ │ │ + * on clicking the arrow buttons. If you want to pan by some ratio │ │ │ │ + * of the map dimensions, use <slideRatio> instead. │ │ │ │ */ │ │ │ │ - element: null, │ │ │ │ + slideFactor: 50, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: ovmap │ │ │ │ - * {<OpenLayers.Map>} A reference to the overview map itself. │ │ │ │ + /** │ │ │ │ + * APIProperty: slideRatio │ │ │ │ + * {Number} The fraction of map width/height by which we'll pan the map │ │ │ │ + * on clicking the arrow buttons. Default is null. If set, will │ │ │ │ + * override <slideFactor>. E.g. if slideRatio is .5, then the Pan Up │ │ │ │ + * button will pan up half the map height. │ │ │ │ */ │ │ │ │ - ovmap: null, │ │ │ │ + slideRatio: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: size │ │ │ │ - * {<OpenLayers.Size>} The overvew map size in pixels. Note that this is │ │ │ │ - * the size of the map itself - the element that contains the map (default │ │ │ │ - * class name olControlOverviewMapElement) may have padding or other style │ │ │ │ - * attributes added via CSS. │ │ │ │ + /** │ │ │ │ + * Property: buttons │ │ │ │ + * {Array(DOMElement)} Array of Button Divs │ │ │ │ */ │ │ │ │ - size: { │ │ │ │ - w: 180, │ │ │ │ - h: 90 │ │ │ │ - }, │ │ │ │ + buttons: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: layers │ │ │ │ - * {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map. │ │ │ │ - * If none are sent at construction, the base layer for the main map is used. │ │ │ │ + /** │ │ │ │ + * Property: position │ │ │ │ + * {<OpenLayers.Pixel>} │ │ │ │ */ │ │ │ │ - layers: null, │ │ │ │ + position: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: minRectSize │ │ │ │ - * {Integer} The minimum width or height (in pixels) of the extent │ │ │ │ - * rectangle on the overview map. When the extent rectangle reaches │ │ │ │ - * this size, it will be replaced depending on the value of the │ │ │ │ - * <minRectDisplayClass> property. Default is 15 pixels. │ │ │ │ + * Constructor: OpenLayers.Control.PanZoom │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ - minRectSize: 15, │ │ │ │ + initialize: function(options) { │ │ │ │ + this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X, │ │ │ │ + OpenLayers.Control.PanZoom.Y); │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: minRectDisplayClass │ │ │ │ - * {String} Replacement style class name for the extent rectangle when │ │ │ │ - * <minRectSize> is reached. This string will be suffixed on to the │ │ │ │ - * displayClass. Default is "RectReplacement". │ │ │ │ - * │ │ │ │ - * Example CSS declaration: │ │ │ │ - * (code) │ │ │ │ - * .olControlOverviewMapRectReplacement { │ │ │ │ - * overflow: hidden; │ │ │ │ - * cursor: move; │ │ │ │ - * background-image: url("img/overview_replacement.gif"); │ │ │ │ - * background-repeat: no-repeat; │ │ │ │ - * background-position: center; │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ + * APIMethod: destroy │ │ │ │ */ │ │ │ │ - minRectDisplayClass: "RectReplacement", │ │ │ │ + destroy: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ + } │ │ │ │ + this.removeButtons(); │ │ │ │ + this.buttons = null; │ │ │ │ + this.position = null; │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: minRatio │ │ │ │ - * {Float} The ratio of the overview map resolution to the main map │ │ │ │ - * resolution at which to zoom farther out on the overview map. │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ + * │ │ │ │ + * Properties: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - minRatio: 8, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + this.map.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: maxRatio │ │ │ │ - * {Float} The ratio of the overview map resolution to the main map │ │ │ │ - * resolution at which to zoom farther in on the overview map. │ │ │ │ + * Method: draw │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * px - {<OpenLayers.Pixel>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A reference to the container div for the PanZoom control. │ │ │ │ */ │ │ │ │ - maxRatio: 32, │ │ │ │ + draw: function(px) { │ │ │ │ + // initialize our internal div │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + px = this.position; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: mapOptions │ │ │ │ - * {Object} An object containing any non-default properties to be sent to │ │ │ │ - * the overview map's map constructor. These should include any │ │ │ │ - * non-default options that the main map was constructed with. │ │ │ │ - */ │ │ │ │ - mapOptions: null, │ │ │ │ + // place the controls │ │ │ │ + this.buttons = []; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: autoPan │ │ │ │ - * {Boolean} Always pan the overview map, so the extent marker remains in │ │ │ │ - * the center. Default is false. If true, when you drag the extent │ │ │ │ - * marker, the overview map will update itself so the marker returns │ │ │ │ - * to the center. │ │ │ │ - */ │ │ │ │ - autoPan: false, │ │ │ │ + var sz = { │ │ │ │ + w: 18, │ │ │ │ + h: 18 │ │ │ │ + }; │ │ │ │ + var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: handlers │ │ │ │ - * {Object} │ │ │ │ - */ │ │ │ │ - handlers: null, │ │ │ │ + this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ + px.y = centered.y + sz.h; │ │ │ │ + this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ + this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz); │ │ │ │ + this._addButton("pandown", "south-mini.png", │ │ │ │ + centered.add(0, sz.h * 2), sz); │ │ │ │ + this._addButton("zoomin", "zoom-plus-mini.png", │ │ │ │ + centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ + this._addButton("zoomworld", "zoom-world-mini.png", │ │ │ │ + centered.add(0, sz.h * 4 + 5), sz); │ │ │ │ + this._addButton("zoomout", "zoom-minus-mini.png", │ │ │ │ + centered.add(0, sz.h * 5 + 5), sz); │ │ │ │ + return this.div; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: resolutionFactor │ │ │ │ - * {Object} │ │ │ │ + * Method: _addButton │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * id - {String} │ │ │ │ + * img - {String} │ │ │ │ + * xy - {<OpenLayers.Pixel>} │ │ │ │ + * sz - {<OpenLayers.Size>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A Div (an alphaImageDiv, to be precise) that contains the │ │ │ │ + * image of the button, and has all the proper event handlers set. │ │ │ │ */ │ │ │ │ - resolutionFactor: 1, │ │ │ │ + _addButton: function(id, img, xy, sz) { │ │ │ │ + var imgLocation = OpenLayers.Util.getImageLocation(img); │ │ │ │ + var btn = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ + this.id + "_" + id, │ │ │ │ + xy, sz, imgLocation, "absolute"); │ │ │ │ + btn.style.cursor = "pointer"; │ │ │ │ + //we want to add the outer div │ │ │ │ + this.div.appendChild(btn); │ │ │ │ + btn.action = id; │ │ │ │ + btn.className = "olButton"; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: maximized │ │ │ │ - * {Boolean} Start as maximized (visible). Defaults to false. │ │ │ │ - */ │ │ │ │ - maximized: false, │ │ │ │ + //we want to remember/reference the outer div │ │ │ │ + this.buttons.push(btn); │ │ │ │ + return btn; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: maximizeTitle │ │ │ │ - * {String} This property is used for showing a tooltip over the │ │ │ │ - * maximize div. Defaults to "" (no title). │ │ │ │ + * Method: _removeButton │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * btn - {Object} │ │ │ │ */ │ │ │ │ - maximizeTitle: "", │ │ │ │ + _removeButton: function(btn) { │ │ │ │ + this.div.removeChild(btn); │ │ │ │ + OpenLayers.Util.removeItem(this.buttons, btn); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: minimizeTitle │ │ │ │ - * {String} This property is used for showing a tooltip over the │ │ │ │ - * minimize div. Defaults to "" (no title). │ │ │ │ + * Method: removeButtons │ │ │ │ */ │ │ │ │ - minimizeTitle: "", │ │ │ │ + removeButtons: function() { │ │ │ │ + for (var i = this.buttons.length - 1; i >= 0; --i) { │ │ │ │ + this._removeButton(this.buttons[i]); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.OverviewMap │ │ │ │ - * Create a new overview map │ │ │ │ + * Method: onButtonClick │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Properties of this object will be set on the overview │ │ │ │ - * map object. Note, to set options on the map object contained in this │ │ │ │ - * control, set <mapOptions> as one of the options properties. │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - this.layers = []; │ │ │ │ - this.handlers = {}; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + var btn = evt.buttonElement; │ │ │ │ + switch (btn.action) { │ │ │ │ + case "panup": │ │ │ │ + this.map.pan(0, -this.getSlideFactor("h")); │ │ │ │ + break; │ │ │ │ + case "pandown": │ │ │ │ + this.map.pan(0, this.getSlideFactor("h")); │ │ │ │ + break; │ │ │ │ + case "panleft": │ │ │ │ + this.map.pan(-this.getSlideFactor("w"), 0); │ │ │ │ + break; │ │ │ │ + case "panright": │ │ │ │ + this.map.pan(this.getSlideFactor("w"), 0); │ │ │ │ + break; │ │ │ │ + case "zoomin": │ │ │ │ + this.map.zoomIn(); │ │ │ │ + break; │ │ │ │ + case "zoomout": │ │ │ │ + this.map.zoomOut(); │ │ │ │ + break; │ │ │ │ + case "zoomworld": │ │ │ │ + this.map.zoomToMaxExtent(); │ │ │ │ + break; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Deconstruct the control │ │ │ │ + * Method: getSlideFactor │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * dim - {String} "w" or "h" (for width or height). │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Number} The slide factor for panning in the requested direction. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - if (!this.mapDiv) { // we've already been destroyed │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - if (this.handlers.click) { │ │ │ │ - this.handlers.click.destroy(); │ │ │ │ - } │ │ │ │ - if (this.handlers.drag) { │ │ │ │ - this.handlers.drag.destroy(); │ │ │ │ - } │ │ │ │ - │ │ │ │ - this.ovmap && this.ovmap.viewPortDiv.removeChild(this.extentRectangle); │ │ │ │ - this.extentRectangle = null; │ │ │ │ - │ │ │ │ - if (this.rectEvents) { │ │ │ │ - this.rectEvents.destroy(); │ │ │ │ - this.rectEvents = null; │ │ │ │ - } │ │ │ │ + getSlideFactor: function(dim) { │ │ │ │ + return this.slideRatio ? │ │ │ │ + this.map.getSize()[dim] * this.slideRatio : │ │ │ │ + this.slideFactor; │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (this.ovmap) { │ │ │ │ - this.ovmap.destroy(); │ │ │ │ - this.ovmap = null; │ │ │ │ - } │ │ │ │ + CLASS_NAME: "OpenLayers.Control.PanZoom" │ │ │ │ +}); │ │ │ │ │ │ │ │ - this.element.removeChild(this.mapDiv); │ │ │ │ - this.mapDiv = null; │ │ │ │ +/** │ │ │ │ + * Constant: X │ │ │ │ + * {Integer} │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.PanZoom.X = 4; │ │ │ │ │ │ │ │ - this.div.removeChild(this.element); │ │ │ │ - this.element = null; │ │ │ │ +/** │ │ │ │ + * Constant: Y │ │ │ │ + * {Integer} │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.PanZoom.Y = 4; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/PanZoomBar.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - if (this.maximizeDiv) { │ │ │ │ - this.div.removeChild(this.maximizeDiv); │ │ │ │ - this.maximizeDiv = null; │ │ │ │ - } │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - if (this.minimizeDiv) { │ │ │ │ - this.div.removeChild(this.minimizeDiv); │ │ │ │ - this.minimizeDiv = null; │ │ │ │ - } │ │ │ │ │ │ │ │ - this.map.events.un({ │ │ │ │ - buttonclick: this.onButtonClick, │ │ │ │ - moveend: this.update, │ │ │ │ - changebaselayer: this.baseLayerDraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Control/PanZoom.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.PanZoomBar │ │ │ │ + * The PanZoomBar is a visible control composed of a │ │ │ │ + * <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomBar>. │ │ │ │ + * By default it is displayed in the upper left corner of the map as 4 │ │ │ │ + * directional arrows above a vertical slider. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control.PanZoom> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.PanZoomBar = OpenLayers.Class(OpenLayers.Control.PanZoom, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * Render the control in the browser. │ │ │ │ + /** │ │ │ │ + * APIProperty: zoomStopWidth │ │ │ │ */ │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (this.layers.length === 0) { │ │ │ │ - if (this.map.baseLayer) { │ │ │ │ - var layer = this.map.baseLayer.clone(); │ │ │ │ - this.layers = [layer]; │ │ │ │ - } else { │ │ │ │ - this.map.events.register("changebaselayer", this, this.baseLayerDraw); │ │ │ │ - return this.div; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // create overview map DOM elements │ │ │ │ - this.element = document.createElement('div'); │ │ │ │ - this.element.className = this.displayClass + 'Element'; │ │ │ │ - this.element.style.display = 'none'; │ │ │ │ - │ │ │ │ - this.mapDiv = document.createElement('div'); │ │ │ │ - this.mapDiv.style.width = this.size.w + 'px'; │ │ │ │ - this.mapDiv.style.height = this.size.h + 'px'; │ │ │ │ - this.mapDiv.style.position = 'relative'; │ │ │ │ - this.mapDiv.style.overflow = 'hidden'; │ │ │ │ - this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap'); │ │ │ │ - │ │ │ │ - this.extentRectangle = document.createElement('div'); │ │ │ │ - this.extentRectangle.style.position = 'absolute'; │ │ │ │ - this.extentRectangle.style.zIndex = 1000; //HACK │ │ │ │ - this.extentRectangle.className = this.displayClass + 'ExtentRectangle'; │ │ │ │ - │ │ │ │ - this.element.appendChild(this.mapDiv); │ │ │ │ - │ │ │ │ - this.div.appendChild(this.element); │ │ │ │ + zoomStopWidth: 18, │ │ │ │ │ │ │ │ - // Optionally add min/max buttons if the control will go in the │ │ │ │ - // map viewport. │ │ │ │ - if (!this.outsideViewport) { │ │ │ │ - this.div.className += " " + this.displayClass + 'Container'; │ │ │ │ - // maximize button div │ │ │ │ - var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png'); │ │ │ │ - this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ - this.displayClass + 'MaximizeButton', │ │ │ │ - null, │ │ │ │ - null, │ │ │ │ - img, │ │ │ │ - 'absolute'); │ │ │ │ - this.maximizeDiv.style.display = 'none'; │ │ │ │ - this.maximizeDiv.className = this.displayClass + 'MaximizeButton olButton'; │ │ │ │ - if (this.maximizeTitle) { │ │ │ │ - this.maximizeDiv.title = this.maximizeTitle; │ │ │ │ - } │ │ │ │ - this.div.appendChild(this.maximizeDiv); │ │ │ │ + /** │ │ │ │ + * APIProperty: zoomStopHeight │ │ │ │ + */ │ │ │ │ + zoomStopHeight: 11, │ │ │ │ │ │ │ │ - // minimize button div │ │ │ │ - var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png'); │ │ │ │ - this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ - 'OpenLayers_Control_minimizeDiv', │ │ │ │ - null, │ │ │ │ - null, │ │ │ │ - img, │ │ │ │ - 'absolute'); │ │ │ │ - this.minimizeDiv.style.display = 'none'; │ │ │ │ - this.minimizeDiv.className = this.displayClass + 'MinimizeButton olButton'; │ │ │ │ - if (this.minimizeTitle) { │ │ │ │ - this.minimizeDiv.title = this.minimizeTitle; │ │ │ │ - } │ │ │ │ - this.div.appendChild(this.minimizeDiv); │ │ │ │ - this.minimizeControl(); │ │ │ │ - } else { │ │ │ │ - // show the overview map │ │ │ │ - this.element.style.display = ''; │ │ │ │ - } │ │ │ │ - if (this.map.getExtent()) { │ │ │ │ - this.update(); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: slider │ │ │ │ + */ │ │ │ │ + slider: null, │ │ │ │ │ │ │ │ - this.map.events.on({ │ │ │ │ - buttonclick: this.onButtonClick, │ │ │ │ - moveend: this.update, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * Property: sliderEvents │ │ │ │ + * {<OpenLayers.Events>} │ │ │ │ + */ │ │ │ │ + sliderEvents: null, │ │ │ │ │ │ │ │ - if (this.maximized) { │ │ │ │ - this.maximizeControl(); │ │ │ │ - } │ │ │ │ - return this.div; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: zoombarDiv │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + zoombarDiv: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: baseLayerDraw │ │ │ │ - * Draw the base layer - called if unable to complete in the initial draw │ │ │ │ + /** │ │ │ │ + * APIProperty: zoomWorldIcon │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - baseLayerDraw: function() { │ │ │ │ - this.draw(); │ │ │ │ - this.map.events.unregister("changebaselayer", this, this.baseLayerDraw); │ │ │ │ - }, │ │ │ │ + zoomWorldIcon: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: rectDrag │ │ │ │ - * Handle extent rectangle drag │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * px - {<OpenLayers.Pixel>} The pixel location of the drag. │ │ │ │ + * APIProperty: panIcons │ │ │ │ + * {Boolean} Set this property to false not to display the pan icons. If │ │ │ │ + * false the zoom world icon is placed under the zoom bar. Defaults to │ │ │ │ + * true. │ │ │ │ */ │ │ │ │ - rectDrag: function(px) { │ │ │ │ - var deltaX = this.handlers.drag.last.x - px.x; │ │ │ │ - var deltaY = this.handlers.drag.last.y - px.y; │ │ │ │ - if (deltaX != 0 || deltaY != 0) { │ │ │ │ - var rectTop = this.rectPxBounds.top; │ │ │ │ - var rectLeft = this.rectPxBounds.left; │ │ │ │ - var rectHeight = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ - var rectWidth = this.rectPxBounds.getWidth(); │ │ │ │ - // don't allow dragging off of parent element │ │ │ │ - var newTop = Math.max(0, (rectTop - deltaY)); │ │ │ │ - newTop = Math.min(newTop, │ │ │ │ - this.ovmap.size.h - this.hComp - rectHeight); │ │ │ │ - var newLeft = Math.max(0, (rectLeft - deltaX)); │ │ │ │ - newLeft = Math.min(newLeft, │ │ │ │ - this.ovmap.size.w - this.wComp - rectWidth); │ │ │ │ - this.setRectPxBounds(new OpenLayers.Bounds(newLeft, │ │ │ │ - newTop + rectHeight, │ │ │ │ - newLeft + rectWidth, │ │ │ │ - newTop)); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + panIcons: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: mapDivClick │ │ │ │ - * Handle browser events │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} evt │ │ │ │ + * APIProperty: forceFixedZoomLevel │ │ │ │ + * {Boolean} Force a fixed zoom level even though the map has │ │ │ │ + * fractionalZoom │ │ │ │ */ │ │ │ │ - mapDivClick: function(evt) { │ │ │ │ - var pxCenter = this.rectPxBounds.getCenterPixel(); │ │ │ │ - var deltaX = evt.xy.x - pxCenter.x; │ │ │ │ - var deltaY = evt.xy.y - pxCenter.y; │ │ │ │ - var top = this.rectPxBounds.top; │ │ │ │ - var left = this.rectPxBounds.left; │ │ │ │ - var height = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ - var width = this.rectPxBounds.getWidth(); │ │ │ │ - var newTop = Math.max(0, (top + deltaY)); │ │ │ │ - newTop = Math.min(newTop, this.ovmap.size.h - height); │ │ │ │ - var newLeft = Math.max(0, (left + deltaX)); │ │ │ │ - newLeft = Math.min(newLeft, this.ovmap.size.w - width); │ │ │ │ - this.setRectPxBounds(new OpenLayers.Bounds(newLeft, │ │ │ │ - newTop + height, │ │ │ │ - newLeft + width, │ │ │ │ - newTop)); │ │ │ │ - this.updateMapToRect(); │ │ │ │ - }, │ │ │ │ + forceFixedZoomLevel: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onButtonClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * Property: mouseDragStart │ │ │ │ + * {<OpenLayers.Pixel>} │ │ │ │ */ │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - if (evt.buttonElement === this.minimizeDiv) { │ │ │ │ - this.minimizeControl(); │ │ │ │ - } else if (evt.buttonElement === this.maximizeDiv) { │ │ │ │ - this.maximizeControl(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + mouseDragStart: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: maximizeControl │ │ │ │ - * Unhide the control. Called when the control is in the map viewport. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {<OpenLayers.Event>} │ │ │ │ + * Property: deltaY │ │ │ │ + * {Number} The cumulative vertical pixel offset during a zoom bar drag. │ │ │ │ */ │ │ │ │ - maximizeControl: function(e) { │ │ │ │ - this.element.style.display = ''; │ │ │ │ - this.showToggle(false); │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + deltaY: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: minimizeControl │ │ │ │ - * Hide all the contents of the control, shrink the size, │ │ │ │ - * add the maximize icon │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {<OpenLayers.Event>} │ │ │ │ + * Property: zoomStart │ │ │ │ + * {<OpenLayers.Pixel>} │ │ │ │ */ │ │ │ │ - minimizeControl: function(e) { │ │ │ │ - this.element.style.display = 'none'; │ │ │ │ - this.showToggle(true); │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + zoomStart: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: showToggle │ │ │ │ - * Hide/Show the toggle depending on whether the control is minimized │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * minimize - {Boolean} │ │ │ │ + * Constructor: OpenLayers.Control.PanZoomBar │ │ │ │ */ │ │ │ │ - showToggle: function(minimize) { │ │ │ │ - if (this.maximizeDiv) { │ │ │ │ - this.maximizeDiv.style.display = minimize ? '' : 'none'; │ │ │ │ - } │ │ │ │ - if (this.minimizeDiv) { │ │ │ │ - this.minimizeDiv.style.display = minimize ? 'none' : ''; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: update │ │ │ │ - * Update the overview map after layers move. │ │ │ │ + * APIMethod: destroy │ │ │ │ */ │ │ │ │ - update: function() { │ │ │ │ - if (this.ovmap == null) { │ │ │ │ - this.createMap(); │ │ │ │ - } │ │ │ │ + destroy: function() { │ │ │ │ │ │ │ │ - if (this.autoPan || !this.isSuitableOverview()) { │ │ │ │ - this.updateOverview(); │ │ │ │ - } │ │ │ │ + this._removeZoomBar(); │ │ │ │ │ │ │ │ - // update extent rectangle │ │ │ │ - this.updateRectToMap(); │ │ │ │ + this.map.events.un({ │ │ │ │ + "changebaselayer": this.redraw, │ │ │ │ + "updatesize": this.redraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + │ │ │ │ + OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments); │ │ │ │ + │ │ │ │ + delete this.mouseDragStart; │ │ │ │ + delete this.zoomStart; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: isSuitableOverview │ │ │ │ - * Determines if the overview map is suitable given the extent and │ │ │ │ - * resolution of the main map. │ │ │ │ + * Method: setMap │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - isSuitableOverview: function() { │ │ │ │ - var mapExtent = this.map.getExtent(); │ │ │ │ - var maxExtent = this.map.getMaxExtent(); │ │ │ │ - var testExtent = new OpenLayers.Bounds( │ │ │ │ - Math.max(mapExtent.left, maxExtent.left), │ │ │ │ - Math.max(mapExtent.bottom, maxExtent.bottom), │ │ │ │ - Math.min(mapExtent.right, maxExtent.right), │ │ │ │ - Math.min(mapExtent.top, maxExtent.top)); │ │ │ │ - │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - testExtent = testExtent.transform( │ │ │ │ - this.map.getProjectionObject(), │ │ │ │ - this.ovmap.getProjectionObject()); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var resRatio = this.ovmap.getResolution() / this.map.getResolution(); │ │ │ │ - return ((resRatio > this.minRatio) && │ │ │ │ - (resRatio <= this.maxRatio) && │ │ │ │ - (this.ovmap.getExtent().containsBounds(testExtent))); │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments); │ │ │ │ + this.map.events.on({ │ │ │ │ + "changebaselayer": this.redraw, │ │ │ │ + "updatesize": this.redraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method updateOverview │ │ │ │ - * Called by <update> if <isSuitableOverview> returns true │ │ │ │ + /** │ │ │ │ + * Method: redraw │ │ │ │ + * clear the div and start over. │ │ │ │ */ │ │ │ │ - updateOverview: function() { │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ - var targetRes = this.ovmap.getResolution(); │ │ │ │ - var resRatio = targetRes / mapRes; │ │ │ │ - if (resRatio > this.maxRatio) { │ │ │ │ - // zoom in overview map │ │ │ │ - targetRes = this.minRatio * mapRes; │ │ │ │ - } else if (resRatio <= this.minRatio) { │ │ │ │ - // zoom out overview map │ │ │ │ - targetRes = this.maxRatio * mapRes; │ │ │ │ - } │ │ │ │ - var center; │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - center = this.map.center.clone(); │ │ │ │ - center.transform(this.map.getProjectionObject(), │ │ │ │ - this.ovmap.getProjectionObject()); │ │ │ │ - } else { │ │ │ │ - center = this.map.center; │ │ │ │ + redraw: function() { │ │ │ │ + if (this.div != null) { │ │ │ │ + this.removeButtons(); │ │ │ │ + this._removeZoomBar(); │ │ │ │ } │ │ │ │ - this.ovmap.setCenter(center, this.ovmap.getZoomForResolution( │ │ │ │ - targetRes * this.resolutionFactor)); │ │ │ │ - this.updateRectToMap(); │ │ │ │ + this.draw(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createMap │ │ │ │ - * Construct the map that this control contains │ │ │ │ + * Method: draw │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * px - {<OpenLayers.Pixel>} │ │ │ │ */ │ │ │ │ - createMap: function() { │ │ │ │ - // create the overview map │ │ │ │ - var options = OpenLayers.Util.extend({ │ │ │ │ - controls: [], │ │ │ │ - maxResolution: 'auto', │ │ │ │ - fallThrough: false │ │ │ │ - }, this.mapOptions); │ │ │ │ - this.ovmap = new OpenLayers.Map(this.mapDiv, options); │ │ │ │ - this.ovmap.viewPortDiv.appendChild(this.extentRectangle); │ │ │ │ + draw: function(px) { │ │ │ │ + // initialize our internal div │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + px = this.position.clone(); │ │ │ │ │ │ │ │ - // prevent ovmap from being destroyed when the page unloads, because │ │ │ │ - // the OverviewMap control has to do this (and does it). │ │ │ │ - OpenLayers.Event.stopObserving(window, 'unload', this.ovmap.unloadDestroy); │ │ │ │ + // place the controls │ │ │ │ + this.buttons = []; │ │ │ │ │ │ │ │ - this.ovmap.addLayers(this.layers); │ │ │ │ - this.ovmap.zoomToMaxExtent(); │ │ │ │ - // check extent rectangle border width │ │ │ │ - this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ - 'border-left-width')) + │ │ │ │ - parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ - 'border-right-width')); │ │ │ │ - this.wComp = (this.wComp) ? this.wComp : 2; │ │ │ │ - this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ - 'border-top-width')) + │ │ │ │ - parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ - 'border-bottom-width')); │ │ │ │ - this.hComp = (this.hComp) ? this.hComp : 2; │ │ │ │ + var sz = { │ │ │ │ + w: 18, │ │ │ │ + h: 18 │ │ │ │ + }; │ │ │ │ + if (this.panIcons) { │ │ │ │ + var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ + var wposition = sz.w; │ │ │ │ │ │ │ │ - this.handlers.drag = new OpenLayers.Handler.Drag( │ │ │ │ - this, { │ │ │ │ - move: this.rectDrag, │ │ │ │ - done: this.updateMapToRect │ │ │ │ - }, { │ │ │ │ - map: this.ovmap │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - this.handlers.click = new OpenLayers.Handler.Click( │ │ │ │ - this, { │ │ │ │ - "click": this.mapDivClick │ │ │ │ - }, { │ │ │ │ - "single": true, │ │ │ │ - "double": false, │ │ │ │ - "stopSingle": true, │ │ │ │ - "stopDouble": true, │ │ │ │ - "pixelTolerance": 1, │ │ │ │ - map: this.ovmap │ │ │ │ + if (this.zoomWorldIcon) { │ │ │ │ + centered = new OpenLayers.Pixel(px.x + sz.w, px.y); │ │ │ │ } │ │ │ │ - ); │ │ │ │ - this.handlers.click.activate(); │ │ │ │ │ │ │ │ - this.rectEvents = new OpenLayers.Events(this, this.extentRectangle, │ │ │ │ - null, true); │ │ │ │ - this.rectEvents.register("mouseover", this, function(e) { │ │ │ │ - if (!this.handlers.drag.active && !this.map.dragging) { │ │ │ │ - this.handlers.drag.activate(); │ │ │ │ + this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ + px.y = centered.y + sz.h; │ │ │ │ + this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ + if (this.zoomWorldIcon) { │ │ │ │ + this._addButton("zoomworld", "zoom-world-mini.png", px.add(sz.w, 0), sz); │ │ │ │ + │ │ │ │ + wposition *= 2; │ │ │ │ } │ │ │ │ - }); │ │ │ │ - this.rectEvents.register("mouseout", this, function(e) { │ │ │ │ - if (!this.handlers.drag.dragging) { │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ + this._addButton("panright", "east-mini.png", px.add(wposition, 0), sz); │ │ │ │ + this._addButton("pandown", "south-mini.png", centered.add(0, sz.h * 2), sz); │ │ │ │ + this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ + centered = this._addZoomBar(centered.add(0, sz.h * 4 + 5)); │ │ │ │ + this._addButton("zoomout", "zoom-minus-mini.png", centered, sz); │ │ │ │ + } else { │ │ │ │ + this._addButton("zoomin", "zoom-plus-mini.png", px, sz); │ │ │ │ + centered = this._addZoomBar(px.add(0, sz.h)); │ │ │ │ + this._addButton("zoomout", "zoom-minus-mini.png", centered, sz); │ │ │ │ + if (this.zoomWorldIcon) { │ │ │ │ + centered = centered.add(0, sz.h + 3); │ │ │ │ + this._addButton("zoomworld", "zoom-world-mini.png", centered, sz); │ │ │ │ } │ │ │ │ - }); │ │ │ │ - │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - var sourceUnits = this.map.getProjectionObject().getUnits() || │ │ │ │ - this.map.units || this.map.baseLayer.units; │ │ │ │ - var targetUnits = this.ovmap.getProjectionObject().getUnits() || │ │ │ │ - this.ovmap.units || this.ovmap.baseLayer.units; │ │ │ │ - this.resolutionFactor = sourceUnits && targetUnits ? │ │ │ │ - OpenLayers.INCHES_PER_UNIT[sourceUnits] / │ │ │ │ - OpenLayers.INCHES_PER_UNIT[targetUnits] : 1; │ │ │ │ } │ │ │ │ + return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: updateRectToMap │ │ │ │ - * Updates the extent rectangle position and size to match the map extent │ │ │ │ + /** │ │ │ │ + * Method: _addZoomBar │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * centered - {<OpenLayers.Pixel>} where zoombar drawing is to start. │ │ │ │ */ │ │ │ │ - updateRectToMap: function() { │ │ │ │ - // If the projections differ we need to reproject │ │ │ │ - var bounds; │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - bounds = this.map.getExtent().transform( │ │ │ │ - this.map.getProjectionObject(), │ │ │ │ - this.ovmap.getProjectionObject()); │ │ │ │ + _addZoomBar: function(centered) { │ │ │ │ + var imgLocation = OpenLayers.Util.getImageLocation("slider.png"); │ │ │ │ + var id = this.id + "_" + this.map.id; │ │ │ │ + var minZoom = this.map.getMinZoom(); │ │ │ │ + var zoomsToEnd = this.map.getNumZoomLevels() - 1 - this.map.getZoom(); │ │ │ │ + var slider = OpenLayers.Util.createAlphaImageDiv(id, │ │ │ │ + centered.add(-1, zoomsToEnd * this.zoomStopHeight), { │ │ │ │ + w: 20, │ │ │ │ + h: 9 │ │ │ │ + }, │ │ │ │ + imgLocation, │ │ │ │ + "absolute"); │ │ │ │ + slider.style.cursor = "move"; │ │ │ │ + this.slider = slider; │ │ │ │ + │ │ │ │ + this.sliderEvents = new OpenLayers.Events(this, slider, null, true, { │ │ │ │ + includeXY: true │ │ │ │ + }); │ │ │ │ + this.sliderEvents.on({ │ │ │ │ + "touchstart": this.zoomBarDown, │ │ │ │ + "touchmove": this.zoomBarDrag, │ │ │ │ + "touchend": this.zoomBarUp, │ │ │ │ + "mousedown": this.zoomBarDown, │ │ │ │ + "mousemove": this.zoomBarDrag, │ │ │ │ + "mouseup": this.zoomBarUp │ │ │ │ + }); │ │ │ │ + │ │ │ │ + var sz = { │ │ │ │ + w: this.zoomStopWidth, │ │ │ │ + h: this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom) │ │ │ │ + }; │ │ │ │ + var imgLocation = OpenLayers.Util.getImageLocation("zoombar.png"); │ │ │ │ + var div = null; │ │ │ │ + │ │ │ │ + if (OpenLayers.Util.alphaHack()) { │ │ │ │ + var id = this.id + "_" + this.map.id; │ │ │ │ + div = OpenLayers.Util.createAlphaImageDiv(id, centered, { │ │ │ │ + w: sz.w, │ │ │ │ + h: this.zoomStopHeight │ │ │ │ + }, │ │ │ │ + imgLocation, │ │ │ │ + "absolute", null, "crop"); │ │ │ │ + div.style.height = sz.h + "px"; │ │ │ │ } else { │ │ │ │ - bounds = this.map.getExtent(); │ │ │ │ - } │ │ │ │ - var pxBounds = this.getRectBoundsFromMapBounds(bounds); │ │ │ │ - if (pxBounds) { │ │ │ │ - this.setRectPxBounds(pxBounds); │ │ │ │ + div = OpenLayers.Util.createDiv( │ │ │ │ + 'OpenLayers_Control_PanZoomBar_Zoombar' + this.map.id, │ │ │ │ + centered, │ │ │ │ + sz, │ │ │ │ + imgLocation); │ │ │ │ } │ │ │ │ + div.style.cursor = "pointer"; │ │ │ │ + div.className = "olButton"; │ │ │ │ + this.zoombarDiv = div; │ │ │ │ + │ │ │ │ + this.div.appendChild(div); │ │ │ │ + │ │ │ │ + this.startTop = parseInt(div.style.top); │ │ │ │ + this.div.appendChild(slider); │ │ │ │ + │ │ │ │ + this.map.events.register("zoomend", this, this.moveZoomBar); │ │ │ │ + │ │ │ │ + centered = centered.add(0, │ │ │ │ + this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom)); │ │ │ │ + return centered; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: updateMapToRect │ │ │ │ - * Updates the map extent to match the extent rectangle position and size │ │ │ │ + * Method: _removeZoomBar │ │ │ │ */ │ │ │ │ - updateMapToRect: function() { │ │ │ │ - var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds); │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - lonLatBounds = lonLatBounds.transform( │ │ │ │ - this.ovmap.getProjectionObject(), │ │ │ │ - this.map.getProjectionObject()); │ │ │ │ - } │ │ │ │ - this.map.panTo(lonLatBounds.getCenterLonLat()); │ │ │ │ + _removeZoomBar: function() { │ │ │ │ + this.sliderEvents.un({ │ │ │ │ + "touchstart": this.zoomBarDown, │ │ │ │ + "touchmove": this.zoomBarDrag, │ │ │ │ + "touchend": this.zoomBarUp, │ │ │ │ + "mousedown": this.zoomBarDown, │ │ │ │ + "mousemove": this.zoomBarDrag, │ │ │ │ + "mouseup": this.zoomBarUp │ │ │ │ + }); │ │ │ │ + this.sliderEvents.destroy(); │ │ │ │ + │ │ │ │ + this.div.removeChild(this.zoombarDiv); │ │ │ │ + this.zoombarDiv = null; │ │ │ │ + this.div.removeChild(this.slider); │ │ │ │ + this.slider = null; │ │ │ │ + │ │ │ │ + this.map.events.unregister("zoomend", this, this.moveZoomBar); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setRectPxBounds │ │ │ │ - * Set extent rectangle pixel bounds. │ │ │ │ + * Method: onButtonClick │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * pxBounds - {<OpenLayers.Bounds>} │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - setRectPxBounds: function(pxBounds) { │ │ │ │ - var top = Math.max(pxBounds.top, 0); │ │ │ │ - var left = Math.max(pxBounds.left, 0); │ │ │ │ - var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()), │ │ │ │ - this.ovmap.size.h - this.hComp); │ │ │ │ - var right = Math.min(pxBounds.left + pxBounds.getWidth(), │ │ │ │ - this.ovmap.size.w - this.wComp); │ │ │ │ - var width = Math.max(right - left, 0); │ │ │ │ - var height = Math.max(bottom - top, 0); │ │ │ │ - if (width < this.minRectSize || height < this.minRectSize) { │ │ │ │ - this.extentRectangle.className = this.displayClass + │ │ │ │ - this.minRectDisplayClass; │ │ │ │ - var rLeft = left + (width / 2) - (this.minRectSize / 2); │ │ │ │ - var rTop = top + (height / 2) - (this.minRectSize / 2); │ │ │ │ - this.extentRectangle.style.top = Math.round(rTop) + 'px'; │ │ │ │ - this.extentRectangle.style.left = Math.round(rLeft) + 'px'; │ │ │ │ - this.extentRectangle.style.height = this.minRectSize + 'px'; │ │ │ │ - this.extentRectangle.style.width = this.minRectSize + 'px'; │ │ │ │ - } else { │ │ │ │ - this.extentRectangle.className = this.displayClass + │ │ │ │ - 'ExtentRectangle'; │ │ │ │ - this.extentRectangle.style.top = Math.round(top) + 'px'; │ │ │ │ - this.extentRectangle.style.left = Math.round(left) + 'px'; │ │ │ │ - this.extentRectangle.style.height = Math.round(height) + 'px'; │ │ │ │ - this.extentRectangle.style.width = Math.round(width) + 'px'; │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this, arguments); │ │ │ │ + if (evt.buttonElement === this.zoombarDiv) { │ │ │ │ + var levels = evt.buttonXY.y / this.zoomStopHeight; │ │ │ │ + if (this.forceFixedZoomLevel || !this.map.fractionalZoom) { │ │ │ │ + levels = Math.floor(levels); │ │ │ │ + } │ │ │ │ + var zoom = (this.map.getNumZoomLevels() - 1) - levels; │ │ │ │ + zoom = Math.min(Math.max(zoom, 0), this.map.getNumZoomLevels() - 1); │ │ │ │ + this.map.zoomTo(zoom); │ │ │ │ } │ │ │ │ - this.rectPxBounds = new OpenLayers.Bounds( │ │ │ │ - Math.round(left), Math.round(bottom), │ │ │ │ - Math.round(right), Math.round(top) │ │ │ │ - ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getRectBoundsFromMapBounds │ │ │ │ - * Get the rect bounds from the map bounds. │ │ │ │ + * Method: passEventToSlider │ │ │ │ + * This function is used to pass events that happen on the div, or the map, │ │ │ │ + * through to the slider, which then does its moving thing. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * lonLatBounds - {<OpenLayers.Bounds>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent │ │ │ │ - * translated into pixel bounds for the overview map │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ */ │ │ │ │ - getRectBoundsFromMapBounds: function(lonLatBounds) { │ │ │ │ - var leftBottomPx = this.getOverviewPxFromLonLat({ │ │ │ │ - lon: lonLatBounds.left, │ │ │ │ - lat: lonLatBounds.bottom │ │ │ │ - }); │ │ │ │ - var rightTopPx = this.getOverviewPxFromLonLat({ │ │ │ │ - lon: lonLatBounds.right, │ │ │ │ - lat: lonLatBounds.top │ │ │ │ - }); │ │ │ │ - var bounds = null; │ │ │ │ - if (leftBottomPx && rightTopPx) { │ │ │ │ - bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y, │ │ │ │ - rightTopPx.x, rightTopPx.y); │ │ │ │ - } │ │ │ │ - return bounds; │ │ │ │ + passEventToSlider: function(evt) { │ │ │ │ + this.sliderEvents.handleBrowserEvent(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getMapBoundsFromRectBounds │ │ │ │ - * Get the map bounds from the rect bounds. │ │ │ │ + /* │ │ │ │ + * Method: zoomBarDown │ │ │ │ + * event listener for clicks on the slider │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * pxBounds - {<OpenLayers.Bounds>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds │ │ │ │ - * translated into lon/lat bounds for the overview map │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ */ │ │ │ │ - getMapBoundsFromRectBounds: function(pxBounds) { │ │ │ │ - var leftBottomLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ - x: pxBounds.left, │ │ │ │ - y: pxBounds.bottom │ │ │ │ - }); │ │ │ │ - var rightTopLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ - x: pxBounds.right, │ │ │ │ - y: pxBounds.top │ │ │ │ + zoomBarDown: function(evt) { │ │ │ │ + if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + this.map.events.on({ │ │ │ │ + "touchmove": this.passEventToSlider, │ │ │ │ + "mousemove": this.passEventToSlider, │ │ │ │ + "mouseup": this.passEventToSlider, │ │ │ │ + scope: this │ │ │ │ }); │ │ │ │ - return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat, │ │ │ │ - rightTopLonLat.lon, rightTopLonLat.lat); │ │ │ │ + this.mouseDragStart = evt.xy.clone(); │ │ │ │ + this.zoomStart = evt.xy.clone(); │ │ │ │ + this.div.style.cursor = "move"; │ │ │ │ + // reset the div offsets just in case the div moved │ │ │ │ + this.zoombarDiv.offsets = null; │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getLonLatFromOverviewPx │ │ │ │ - * Get a map location from a pixel location │ │ │ │ + /* │ │ │ │ + * Method: zoomBarDrag │ │ │ │ + * This is what happens when a click has occurred, and the client is │ │ │ │ + * dragging. Here we must ensure that the slider doesn't go beyond the │ │ │ │ + * bottom/top of the zoombar div, as well as moving the slider to its new │ │ │ │ + * visual location │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * overviewMapPx - {<OpenLayers.Pixel>|Object} OpenLayers.Pixel or │ │ │ │ - * an object with a │ │ │ │ - * 'x' and 'y' properties. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} Location which is the passed-in overview map │ │ │ │ - * OpenLayers.Pixel, translated into lon/lat by the overview │ │ │ │ - * map. An object with a 'lon' and 'lat' properties. │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ */ │ │ │ │ - getLonLatFromOverviewPx: function(overviewMapPx) { │ │ │ │ - var size = this.ovmap.size; │ │ │ │ - var res = this.ovmap.getResolution(); │ │ │ │ - var center = this.ovmap.getExtent().getCenterLonLat(); │ │ │ │ - │ │ │ │ - var deltaX = overviewMapPx.x - (size.w / 2); │ │ │ │ - var deltaY = overviewMapPx.y - (size.h / 2); │ │ │ │ - │ │ │ │ - return { │ │ │ │ - lon: center.lon + deltaX * res, │ │ │ │ - lat: center.lat - deltaY * res │ │ │ │ - }; │ │ │ │ + zoomBarDrag: function(evt) { │ │ │ │ + if (this.mouseDragStart != null) { │ │ │ │ + var deltaY = this.mouseDragStart.y - evt.xy.y; │ │ │ │ + var offsets = OpenLayers.Util.pagePosition(this.zoombarDiv); │ │ │ │ + if ((evt.clientY - offsets[1]) > 0 && │ │ │ │ + (evt.clientY - offsets[1]) < parseInt(this.zoombarDiv.style.height) - 2) { │ │ │ │ + var newTop = parseInt(this.slider.style.top) - deltaY; │ │ │ │ + this.slider.style.top = newTop + "px"; │ │ │ │ + this.mouseDragStart = evt.xy.clone(); │ │ │ │ + } │ │ │ │ + // set cumulative displacement │ │ │ │ + this.deltaY = this.zoomStart.y - evt.xy.y; │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getOverviewPxFromLonLat │ │ │ │ - * Get a pixel location from a map location │ │ │ │ + /* │ │ │ │ + * Method: zoomBarUp │ │ │ │ + * Perform cleanup when a mouseup event is received -- discover new zoom │ │ │ │ + * level and switch to it. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * lonlat - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an │ │ │ │ - * object with a 'lon' and 'lat' properties. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} Location which is the passed-in OpenLayers.LonLat, │ │ │ │ - * translated into overview map pixels │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ */ │ │ │ │ - getOverviewPxFromLonLat: function(lonlat) { │ │ │ │ - var res = this.ovmap.getResolution(); │ │ │ │ - var extent = this.ovmap.getExtent(); │ │ │ │ - if (extent) { │ │ │ │ - return { │ │ │ │ - x: Math.round(1 / res * (lonlat.lon - extent.left)), │ │ │ │ - y: Math.round(1 / res * (extent.top - lonlat.lat)) │ │ │ │ - }; │ │ │ │ + zoomBarUp: function(evt) { │ │ │ │ + if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + if (this.mouseDragStart) { │ │ │ │ + this.div.style.cursor = ""; │ │ │ │ + this.map.events.un({ │ │ │ │ + "touchmove": this.passEventToSlider, │ │ │ │ + "mouseup": this.passEventToSlider, │ │ │ │ + "mousemove": this.passEventToSlider, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + var zoomLevel = this.map.zoom; │ │ │ │ + if (!this.forceFixedZoomLevel && this.map.fractionalZoom) { │ │ │ │ + zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ + zoomLevel = Math.min(Math.max(zoomLevel, 0), │ │ │ │ + this.map.getNumZoomLevels() - 1); │ │ │ │ + } else { │ │ │ │ + zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ + zoomLevel = Math.max(Math.round(zoomLevel), 0); │ │ │ │ + } │ │ │ │ + this.map.zoomTo(zoomLevel); │ │ │ │ + this.mouseDragStart = null; │ │ │ │ + this.zoomStart = null; │ │ │ │ + this.deltaY = 0; │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: 'OpenLayers.Control.OverviewMap' │ │ │ │ + /* │ │ │ │ + * Method: moveZoomBar │ │ │ │ + * Change the location of the slider to match the current zoom level. │ │ │ │ + */ │ │ │ │ + moveZoomBar: function() { │ │ │ │ + var newTop = │ │ │ │ + ((this.map.getNumZoomLevels() - 1) - this.map.getZoom()) * │ │ │ │ + this.zoomStopHeight + this.startTop + 1; │ │ │ │ + this.slider.style.top = newTop + "px"; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Control.PanZoomBar" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Scale.js │ │ │ │ + OpenLayers/Format/SLD.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/Lang.js │ │ │ │ + * @requires OpenLayers/Format/XML/VersionedOGC.js │ │ │ │ + * @requires OpenLayers/Style.js │ │ │ │ + * @requires OpenLayers/Rule.js │ │ │ │ + * @requires OpenLayers/Filter/FeatureId.js │ │ │ │ + * @requires OpenLayers/Filter/Logical.js │ │ │ │ + * @requires OpenLayers/Filter/Comparison.js │ │ │ │ + * @requires OpenLayers/Filter/Spatial.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Scale │ │ │ │ - * The Scale control displays the current map scale as a ratio (e.g. Scale = │ │ │ │ - * 1:1M). By default it is displayed in the lower right corner of the map. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.SLD │ │ │ │ + * Read/Write SLD. Create a new instance with the <OpenLayers.Format.SLD> │ │ │ │ + * constructor. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.Scale = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Format.SLD = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: element │ │ │ │ - * {DOMElement} │ │ │ │ + * APIProperty: profile │ │ │ │ + * {String} If provided, use a custom profile. │ │ │ │ + * │ │ │ │ + * Currently supported profiles: │ │ │ │ + * - GeoServer - parses GeoServer vendor specific capabilities for SLD. │ │ │ │ */ │ │ │ │ - element: null, │ │ │ │ + profile: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: geodesic │ │ │ │ - * {Boolean} Use geodesic measurement. Default is false. The recommended │ │ │ │ - * setting for maps in EPSG:4326 is false, and true EPSG:900913. If set to │ │ │ │ - * true, the scale will be calculated based on the horizontal size of the │ │ │ │ - * pixel in the center of the map viewport. │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "1.0.0". │ │ │ │ */ │ │ │ │ - geodesic: false, │ │ │ │ + defaultVersion: "1.0.0", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.Scale │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * element - {DOMElement} │ │ │ │ - * options - {Object} │ │ │ │ + * APIProperty: stringifyOutput │ │ │ │ + * {Boolean} If true, write will return a string otherwise a DOMElement. │ │ │ │ + * Default is true. │ │ │ │ */ │ │ │ │ - initialize: function(element, options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.element = OpenLayers.Util.getElement(element); │ │ │ │ - }, │ │ │ │ + stringifyOutput: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: draw │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * APIProperty: namedLayersAsArray │ │ │ │ + * {Boolean} Generate a namedLayers array. If false, the namedLayers │ │ │ │ + * property value will be an object keyed by layer name. Default is │ │ │ │ + * false. │ │ │ │ */ │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (!this.element) { │ │ │ │ - this.element = document.createElement("div"); │ │ │ │ - this.div.appendChild(this.element); │ │ │ │ - } │ │ │ │ - this.map.events.register('moveend', this, this.updateScale); │ │ │ │ - this.updateScale(); │ │ │ │ - return this.div; │ │ │ │ - }, │ │ │ │ + namedLayersAsArray: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: updateScale │ │ │ │ + * APIMethod: write │ │ │ │ + * Write a SLD document given a list of styles. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * sld - {Object} An object representing the SLD. │ │ │ │ + * options - {Object} Optional configuration object. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} An SLD document string. │ │ │ │ */ │ │ │ │ - updateScale: function() { │ │ │ │ - var scale; │ │ │ │ - if (this.geodesic === true) { │ │ │ │ - var units = this.map.getUnits(); │ │ │ │ - if (!units) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - var inches = OpenLayers.INCHES_PER_UNIT; │ │ │ │ - scale = (this.map.getGeodesicPixelSize().w || 0.000001) * │ │ │ │ - inches["km"] * OpenLayers.DOTS_PER_INCH; │ │ │ │ - } else { │ │ │ │ - scale = this.map.getScale(); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (!scale) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (scale >= 9500 && scale <= 950000) { │ │ │ │ - scale = Math.round(scale / 1000) + "K"; │ │ │ │ - } else if (scale >= 950000) { │ │ │ │ - scale = Math.round(scale / 1000000) + "M"; │ │ │ │ - } else { │ │ │ │ - scale = Math.round(scale); │ │ │ │ - } │ │ │ │ │ │ │ │ - this.element.innerHTML = OpenLayers.i18n("Scale = 1 : ${scaleDenom}", { │ │ │ │ - 'scaleDenom': scale │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read and SLD doc and return an object representing the SLD. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String | DOMElement} Data to read. │ │ │ │ + * options - {Object} Options for the reader. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} An object representing the SLD. │ │ │ │ + */ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Scale" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SLD" │ │ │ │ }); │ │ │ │ - │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Graticule.js │ │ │ │ + OpenLayers/Format/SLD/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/Control.js │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ * @requires OpenLayers/Rule.js │ │ │ │ - * @requires OpenLayers/StyleMap.js │ │ │ │ - * @requires OpenLayers/Layer/Vector.js │ │ │ │ + * @requires OpenLayers/Format/SLD.js │ │ │ │ + * @requires OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Point.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Line.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Polygon.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Text.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Raster.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Graticule │ │ │ │ - * The Graticule displays a grid of latitude/longitude lines reprojected on │ │ │ │ - * the map. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.SLD.v1 │ │ │ │ + * Superclass for SLD version 1 parsers. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - * │ │ │ │ + * - <OpenLayers.Format.Filter.v1_0_0> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.Graticule = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ - */ │ │ │ │ - autoActivate: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: intervals │ │ │ │ - * {Array(Float)} A list of possible graticule widths in degrees. │ │ │ │ - */ │ │ │ │ - intervals: [45, 30, 20, 10, 5, 2, 1, │ │ │ │ - 0.5, 0.2, 0.1, 0.05, 0.01, │ │ │ │ - 0.005, 0.002, 0.001 │ │ │ │ - ], │ │ │ │ +OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: displayInLayerSwitcher │ │ │ │ - * {Boolean} Allows the Graticule control to be switched on and off by │ │ │ │ - * LayerSwitcher control. Defaults is true. │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ - displayInLayerSwitcher: true, │ │ │ │ + namespaces: { │ │ │ │ + sld: "http://www.opengis.net/sld", │ │ │ │ + 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" │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: visible │ │ │ │ - * {Boolean} should the graticule be initially visible (default=true) │ │ │ │ + * Property: defaultPrefix │ │ │ │ */ │ │ │ │ - visible: true, │ │ │ │ + defaultPrefix: "sld", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: numPoints │ │ │ │ - * {Integer} The number of points to use in each graticule line. Higher │ │ │ │ - * numbers result in a smoother curve for projected maps │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} Schema location for a particular minor version. │ │ │ │ */ │ │ │ │ - numPoints: 50, │ │ │ │ + schemaLocation: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: targetSize │ │ │ │ - * {Integer} The maximum size of the grid in pixels on the map │ │ │ │ + /** │ │ │ │ + * APIProperty: multipleSymbolizers │ │ │ │ + * {Boolean} Support multiple symbolizers per rule. Default is false. if │ │ │ │ + * true, an OpenLayers.Style2 instance will be created to represent │ │ │ │ + * user styles instead of an OpenLayers.Style instace. The │ │ │ │ + * OpenLayers.Style2 class allows collections of rules with multiple │ │ │ │ + * symbolizers, but is not currently useful for client side rendering. │ │ │ │ + * If multiple symbolizers is true, multiple FeatureTypeStyle elements │ │ │ │ + * are preserved in reading/writing by setting symbolizer zIndex values. │ │ │ │ + * In addition, the <defaultSymbolizer> property is ignored if │ │ │ │ + * multiple symbolizers are supported (defaults should be applied │ │ │ │ + * when rendering). │ │ │ │ */ │ │ │ │ - targetSize: 200, │ │ │ │ + multipleSymbolizers: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layerName │ │ │ │ - * {String} The name to be displayed in the layer switcher, default is set │ │ │ │ - * by {<OpenLayers.Lang>}. │ │ │ │ + * Property: featureTypeCounter │ │ │ │ + * {Number} Private counter for multiple feature type styles. │ │ │ │ */ │ │ │ │ - layerName: null, │ │ │ │ + featureTypeCounter: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: labelled │ │ │ │ - * {Boolean} Should the graticule lines be labelled?. default=true │ │ │ │ + * APIProperty: defaultSymbolizer. │ │ │ │ + * {Object} A symbolizer with the SLD defaults. │ │ │ │ */ │ │ │ │ - labelled: true, │ │ │ │ + defaultSymbolizer: { │ │ │ │ + fillColor: "#808080", │ │ │ │ + fillOpacity: 1, │ │ │ │ + strokeColor: "#000000", │ │ │ │ + strokeOpacity: 1, │ │ │ │ + strokeWidth: 1, │ │ │ │ + strokeDashstyle: "solid", │ │ │ │ + pointRadius: 3, │ │ │ │ + graphicName: "square" │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: labelFormat │ │ │ │ - * {String} the format of the labels, default = 'dm'. See │ │ │ │ - * <OpenLayers.Util.getFormattedLonLat> for other options. │ │ │ │ + * Constructor: OpenLayers.Format.SLD.v1 │ │ │ │ + * Instances of this class are not created directly. Use the │ │ │ │ + * <OpenLayers.Format.SLD> constructor instead. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ */ │ │ │ │ - labelFormat: 'dm', │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: lineSymbolizer │ │ │ │ - * {symbolizer} the symbolizer used to render lines │ │ │ │ + * Method: read │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {DOMElement} An SLD document element. │ │ │ │ + * options - {Object} Options for the reader. │ │ │ │ + * │ │ │ │ + * Valid options: │ │ │ │ + * namedLayersAsArray - {Boolean} Generate a namedLayers array. If false, │ │ │ │ + * the namedLayers property value will be an object keyed by layer name. │ │ │ │ + * Default is false. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} An object representing the SLD. │ │ │ │ */ │ │ │ │ - lineSymbolizer: { │ │ │ │ - strokeColor: "#333", │ │ │ │ - strokeWidth: 1, │ │ │ │ - strokeOpacity: 0.5 │ │ │ │ + read: function(data, options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ + var sld = { │ │ │ │ + namedLayers: options.namedLayersAsArray === true ? [] : {} │ │ │ │ + }; │ │ │ │ + this.readChildNodes(data, sld); │ │ │ │ + return sld; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: labelSymbolizer │ │ │ │ - * {symbolizer} the symbolizer used to render labels │ │ │ │ - */ │ │ │ │ - labelSymbolizer: {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: gratLayer │ │ │ │ - * {<OpenLayers.Layer.Vector>} vector layer used to draw the graticule on │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - gratLayer: null, │ │ │ │ + readers: OpenLayers.Util.applyDefaults({ │ │ │ │ + "sld": { │ │ │ │ + "StyledLayerDescriptor": function(node, sld) { │ │ │ │ + sld.version = node.getAttribute("version"); │ │ │ │ + this.readChildNodes(node, sld); │ │ │ │ + }, │ │ │ │ + "Name": function(node, obj) { │ │ │ │ + obj.name = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Title": function(node, obj) { │ │ │ │ + obj.title = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Abstract": function(node, obj) { │ │ │ │ + obj.description = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "NamedLayer": function(node, sld) { │ │ │ │ + var layer = { │ │ │ │ + userStyles: [], │ │ │ │ + namedStyles: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, layer); │ │ │ │ + // give each of the user styles this layer name │ │ │ │ + for (var i = 0, len = layer.userStyles.length; i < len; ++i) { │ │ │ │ + layer.userStyles[i].layerName = layer.name; │ │ │ │ + } │ │ │ │ + if (OpenLayers.Util.isArray(sld.namedLayers)) { │ │ │ │ + sld.namedLayers.push(layer); │ │ │ │ + } else { │ │ │ │ + sld.namedLayers[layer.name] = layer; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "NamedStyle": function(node, layer) { │ │ │ │ + layer.namedStyles.push( │ │ │ │ + this.getChildName(node.firstChild) │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "UserStyle": function(node, layer) { │ │ │ │ + var obj = { │ │ │ │ + defaultsPerSymbolizer: true, │ │ │ │ + rules: [] │ │ │ │ + }; │ │ │ │ + this.featureTypeCounter = -1; │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + var style; │ │ │ │ + if (this.multipleSymbolizers) { │ │ │ │ + delete obj.defaultsPerSymbolizer; │ │ │ │ + style = new OpenLayers.Style2(obj); │ │ │ │ + } else { │ │ │ │ + style = new OpenLayers.Style(this.defaultSymbolizer, obj); │ │ │ │ + } │ │ │ │ + layer.userStyles.push(style); │ │ │ │ + }, │ │ │ │ + "IsDefault": function(node, style) { │ │ │ │ + if (this.getChildValue(node) == "1") { │ │ │ │ + style.isDefault = true; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "FeatureTypeStyle": function(node, style) { │ │ │ │ + ++this.featureTypeCounter; │ │ │ │ + var obj = { │ │ │ │ + rules: this.multipleSymbolizers ? style.rules : [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + if (!this.multipleSymbolizers) { │ │ │ │ + style.rules = obj.rules; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Rule": function(node, obj) { │ │ │ │ + var config; │ │ │ │ + if (this.multipleSymbolizers) { │ │ │ │ + config = { │ │ │ │ + symbolizers: [] │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + var rule = new OpenLayers.Rule(config); │ │ │ │ + this.readChildNodes(node, rule); │ │ │ │ + obj.rules.push(rule); │ │ │ │ + }, │ │ │ │ + "ElseFilter": function(node, rule) { │ │ │ │ + rule.elseFilter = true; │ │ │ │ + }, │ │ │ │ + "MinScaleDenominator": function(node, rule) { │ │ │ │ + rule.minScaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "MaxScaleDenominator": function(node, rule) { │ │ │ │ + rule.maxScaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "TextSymbolizer": function(node, rule) { │ │ │ │ + var config = {}; │ │ │ │ + this.readChildNodes(node, config); │ │ │ │ + if (this.multipleSymbolizers) { │ │ │ │ + config.zIndex = this.featureTypeCounter; │ │ │ │ + rule.symbolizers.push( │ │ │ │ + new OpenLayers.Symbolizer.Text(config) │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + rule.symbolizer["Text"] = OpenLayers.Util.applyDefaults( │ │ │ │ + config, rule.symbolizer["Text"] │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "LabelPlacement": function(node, symbolizer) { │ │ │ │ + this.readChildNodes(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "PointPlacement": function(node, symbolizer) { │ │ │ │ + var config = {}; │ │ │ │ + this.readChildNodes(node, config); │ │ │ │ + config.labelRotation = config.rotation; │ │ │ │ + delete config.rotation; │ │ │ │ + var labelAlign, │ │ │ │ + x = symbolizer.labelAnchorPointX, │ │ │ │ + y = symbolizer.labelAnchorPointY; │ │ │ │ + if (x <= 1 / 3) { │ │ │ │ + labelAlign = 'l'; │ │ │ │ + } else if (x > 1 / 3 && x < 2 / 3) { │ │ │ │ + labelAlign = 'c'; │ │ │ │ + } else if (x >= 2 / 3) { │ │ │ │ + labelAlign = 'r'; │ │ │ │ + } │ │ │ │ + if (y <= 1 / 3) { │ │ │ │ + labelAlign += 'b'; │ │ │ │ + } else if (y > 1 / 3 && y < 2 / 3) { │ │ │ │ + labelAlign += 'm'; │ │ │ │ + } else if (y >= 2 / 3) { │ │ │ │ + labelAlign += 't'; │ │ │ │ + } │ │ │ │ + config.labelAlign = labelAlign; │ │ │ │ + OpenLayers.Util.applyDefaults(symbolizer, config); │ │ │ │ + }, │ │ │ │ + "AnchorPoint": function(node, symbolizer) { │ │ │ │ + this.readChildNodes(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "AnchorPointX": function(node, symbolizer) { │ │ │ │ + var labelAnchorPointX = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (labelAnchorPointX) { │ │ │ │ + symbolizer.labelAnchorPointX = labelAnchorPointX; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "AnchorPointY": function(node, symbolizer) { │ │ │ │ + var labelAnchorPointY = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (labelAnchorPointY) { │ │ │ │ + symbolizer.labelAnchorPointY = labelAnchorPointY; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Displacement": function(node, symbolizer) { │ │ │ │ + this.readChildNodes(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "DisplacementX": function(node, symbolizer) { │ │ │ │ + var labelXOffset = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (labelXOffset) { │ │ │ │ + symbolizer.labelXOffset = labelXOffset; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "DisplacementY": function(node, symbolizer) { │ │ │ │ + var labelYOffset = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (labelYOffset) { │ │ │ │ + symbolizer.labelYOffset = labelYOffset; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "LinePlacement": function(node, symbolizer) { │ │ │ │ + this.readChildNodes(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "PerpendicularOffset": function(node, symbolizer) { │ │ │ │ + var labelPerpendicularOffset = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (labelPerpendicularOffset) { │ │ │ │ + symbolizer.labelPerpendicularOffset = labelPerpendicularOffset; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Label": function(node, symbolizer) { │ │ │ │ + var value = this.readers.ogc._expression.call(this, node); │ │ │ │ + if (value) { │ │ │ │ + symbolizer.label = value; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Font": function(node, symbolizer) { │ │ │ │ + this.readChildNodes(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "Halo": function(node, symbolizer) { │ │ │ │ + // halo has a fill, so send fresh object │ │ │ │ + var obj = {}; │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + symbolizer.haloRadius = obj.haloRadius; │ │ │ │ + symbolizer.haloColor = obj.fillColor; │ │ │ │ + symbolizer.haloOpacity = obj.fillOpacity; │ │ │ │ + }, │ │ │ │ + "Radius": function(node, symbolizer) { │ │ │ │ + var radius = this.readers.ogc._expression.call(this, node); │ │ │ │ + if (radius != null) { │ │ │ │ + // radius is only used for halo │ │ │ │ + symbolizer.haloRadius = radius; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "RasterSymbolizer": function(node, rule) { │ │ │ │ + var config = {}; │ │ │ │ + this.readChildNodes(node, config); │ │ │ │ + if (this.multipleSymbolizers) { │ │ │ │ + config.zIndex = this.featureTypeCounter; │ │ │ │ + rule.symbolizers.push( │ │ │ │ + new OpenLayers.Symbolizer.Raster(config) │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + rule.symbolizer["Raster"] = OpenLayers.Util.applyDefaults( │ │ │ │ + config, rule.symbolizer["Raster"] │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Geometry": function(node, obj) { │ │ │ │ + obj.geometry = {}; │ │ │ │ + this.readChildNodes(node, obj.geometry); │ │ │ │ + }, │ │ │ │ + "ColorMap": function(node, symbolizer) { │ │ │ │ + symbolizer.colorMap = []; │ │ │ │ + this.readChildNodes(node, symbolizer.colorMap); │ │ │ │ + }, │ │ │ │ + "ColorMapEntry": function(node, colorMap) { │ │ │ │ + var q = node.getAttribute("quantity"); │ │ │ │ + var o = node.getAttribute("opacity"); │ │ │ │ + colorMap.push({ │ │ │ │ + color: node.getAttribute("color"), │ │ │ │ + quantity: q !== null ? parseFloat(q) : undefined, │ │ │ │ + label: node.getAttribute("label") || undefined, │ │ │ │ + opacity: o !== null ? parseFloat(o) : undefined │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "LineSymbolizer": function(node, rule) { │ │ │ │ + var config = {}; │ │ │ │ + this.readChildNodes(node, config); │ │ │ │ + if (this.multipleSymbolizers) { │ │ │ │ + config.zIndex = this.featureTypeCounter; │ │ │ │ + rule.symbolizers.push( │ │ │ │ + new OpenLayers.Symbolizer.Line(config) │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + rule.symbolizer["Line"] = OpenLayers.Util.applyDefaults( │ │ │ │ + config, rule.symbolizer["Line"] │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "PolygonSymbolizer": function(node, rule) { │ │ │ │ + var config = { │ │ │ │ + fill: false, │ │ │ │ + stroke: false │ │ │ │ + }; │ │ │ │ + if (!this.multipleSymbolizers) { │ │ │ │ + config = rule.symbolizer["Polygon"] || config; │ │ │ │ + } │ │ │ │ + this.readChildNodes(node, config); │ │ │ │ + if (this.multipleSymbolizers) { │ │ │ │ + config.zIndex = this.featureTypeCounter; │ │ │ │ + rule.symbolizers.push( │ │ │ │ + new OpenLayers.Symbolizer.Polygon(config) │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + rule.symbolizer["Polygon"] = config; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "PointSymbolizer": function(node, rule) { │ │ │ │ + var config = { │ │ │ │ + fill: false, │ │ │ │ + stroke: false, │ │ │ │ + graphic: false │ │ │ │ + }; │ │ │ │ + if (!this.multipleSymbolizers) { │ │ │ │ + config = rule.symbolizer["Point"] || config; │ │ │ │ + } │ │ │ │ + this.readChildNodes(node, config); │ │ │ │ + if (this.multipleSymbolizers) { │ │ │ │ + config.zIndex = this.featureTypeCounter; │ │ │ │ + rule.symbolizers.push( │ │ │ │ + new OpenLayers.Symbolizer.Point(config) │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + rule.symbolizer["Point"] = config; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Stroke": function(node, symbolizer) { │ │ │ │ + symbolizer.stroke = true; │ │ │ │ + this.readChildNodes(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "Fill": function(node, symbolizer) { │ │ │ │ + symbolizer.fill = true; │ │ │ │ + this.readChildNodes(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "CssParameter": function(node, symbolizer) { │ │ │ │ + var cssProperty = node.getAttribute("name"); │ │ │ │ + var symProperty = this.cssMap[cssProperty]; │ │ │ │ + // for labels, fill should map to fontColor and fill-opacity │ │ │ │ + // to fontOpacity │ │ │ │ + if (symbolizer.label) { │ │ │ │ + if (cssProperty === 'fill') { │ │ │ │ + symProperty = "fontColor"; │ │ │ │ + } else if (cssProperty === 'fill-opacity') { │ │ │ │ + symProperty = "fontOpacity"; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (symProperty) { │ │ │ │ + // Limited support for parsing of OGC expressions │ │ │ │ + var value = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be an empty string │ │ │ │ + if (value) { │ │ │ │ + symbolizer[symProperty] = value; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Graphic": function(node, symbolizer) { │ │ │ │ + symbolizer.graphic = true; │ │ │ │ + var graphic = {}; │ │ │ │ + // painter's order not respected here, clobber previous with next │ │ │ │ + this.readChildNodes(node, graphic); │ │ │ │ + // directly properties with names that match symbolizer properties │ │ │ │ + var properties = [ │ │ │ │ + "stroke", "strokeColor", "strokeWidth", "strokeOpacity", │ │ │ │ + "strokeLinecap", "fill", "fillColor", "fillOpacity", │ │ │ │ + "graphicName", "rotation", "graphicFormat" │ │ │ │ + ]; │ │ │ │ + var prop, value; │ │ │ │ + for (var i = 0, len = properties.length; i < len; ++i) { │ │ │ │ + prop = properties[i]; │ │ │ │ + value = graphic[prop]; │ │ │ │ + if (value != undefined) { │ │ │ │ + symbolizer[prop] = value; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + // set other generic properties with specific graphic property names │ │ │ │ + if (graphic.opacity != undefined) { │ │ │ │ + symbolizer.graphicOpacity = graphic.opacity; │ │ │ │ + } │ │ │ │ + if (graphic.size != undefined) { │ │ │ │ + var pointRadius = graphic.size / 2; │ │ │ │ + if (isNaN(pointRadius)) { │ │ │ │ + // likely a property name │ │ │ │ + symbolizer.graphicWidth = graphic.size; │ │ │ │ + } else { │ │ │ │ + symbolizer.pointRadius = graphic.size / 2; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (graphic.href != undefined) { │ │ │ │ + symbolizer.externalGraphic = graphic.href; │ │ │ │ + } │ │ │ │ + if (graphic.rotation != undefined) { │ │ │ │ + symbolizer.rotation = graphic.rotation; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "ExternalGraphic": function(node, graphic) { │ │ │ │ + this.readChildNodes(node, graphic); │ │ │ │ + }, │ │ │ │ + "Mark": function(node, graphic) { │ │ │ │ + this.readChildNodes(node, graphic); │ │ │ │ + }, │ │ │ │ + "WellKnownName": function(node, graphic) { │ │ │ │ + graphic.graphicName = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Opacity": function(node, obj) { │ │ │ │ + var opacity = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (opacity) { │ │ │ │ + obj.opacity = opacity; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Size": function(node, obj) { │ │ │ │ + var size = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (size) { │ │ │ │ + obj.size = size; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Rotation": function(node, obj) { │ │ │ │ + var rotation = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (rotation) { │ │ │ │ + obj.rotation = rotation; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "OnlineResource": function(node, obj) { │ │ │ │ + obj.href = this.getAttributeNS( │ │ │ │ + node, this.namespaces.xlink, "href" │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "Format": function(node, graphic) { │ │ │ │ + graphic.graphicFormat = this.getChildValue(node); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.Filter.v1_0_0.prototype.readers), │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.Graticule │ │ │ │ - * Create a new graticule control to display a grid of latitude longitude │ │ │ │ - * lines. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be used │ │ │ │ - * to extend the control. │ │ │ │ + * Property: cssMap │ │ │ │ + * {Object} Object mapping supported css property names to OpenLayers │ │ │ │ + * symbolizer property names. │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.layerName = options.layerName || OpenLayers.i18n("Graticule"); │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - │ │ │ │ - this.labelSymbolizer.stroke = false; │ │ │ │ - this.labelSymbolizer.fill = false; │ │ │ │ - this.labelSymbolizer.label = "${label}"; │ │ │ │ - this.labelSymbolizer.labelAlign = "${labelAlign}"; │ │ │ │ - this.labelSymbolizer.labelXOffset = "${xOffset}"; │ │ │ │ - this.labelSymbolizer.labelYOffset = "${yOffset}"; │ │ │ │ + cssMap: { │ │ │ │ + "stroke": "strokeColor", │ │ │ │ + "stroke-opacity": "strokeOpacity", │ │ │ │ + "stroke-width": "strokeWidth", │ │ │ │ + "stroke-linecap": "strokeLinecap", │ │ │ │ + "stroke-dasharray": "strokeDashstyle", │ │ │ │ + "fill": "fillColor", │ │ │ │ + "fill-opacity": "fillOpacity", │ │ │ │ + "font-family": "fontFamily", │ │ │ │ + "font-size": "fontSize", │ │ │ │ + "font-weight": "fontWeight", │ │ │ │ + "font-style": "fontStyle" │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ + * Method: getCssProperty │ │ │ │ + * Given a symbolizer property, get the corresponding CSS property │ │ │ │ + * from the <cssMap>. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * sym - {String} A symbolizer property name. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A CSS property name or null if none found. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - if (this.gratLayer) { │ │ │ │ - this.gratLayer.destroy(); │ │ │ │ - this.gratLayer = null; │ │ │ │ + getCssProperty: function(sym) { │ │ │ │ + var css = null; │ │ │ │ + for (var prop in this.cssMap) { │ │ │ │ + if (this.cssMap[prop] == sym) { │ │ │ │ + css = prop; │ │ │ │ + break; │ │ │ │ + } │ │ │ │ } │ │ │ │ + return css; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: draw │ │ │ │ + * Method: getGraphicFormat │ │ │ │ + * Given a href for an external graphic, try to determine the mime-type. │ │ │ │ + * This method doesn't try too hard, and will fall back to │ │ │ │ + * <defaultGraphicFormat> if one of the known <graphicFormats> is not │ │ │ │ + * the file extension of the provided href. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * href - {String} │ │ │ │ * │ │ │ │ - * initializes the graticule layer and does the initial update │ │ │ │ - * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * {String} The graphic format. │ │ │ │ */ │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (!this.gratLayer) { │ │ │ │ - var gratStyle = new OpenLayers.Style({}, { │ │ │ │ - rules: [new OpenLayers.Rule({ │ │ │ │ - 'symbolizer': { │ │ │ │ - "Point": this.labelSymbolizer, │ │ │ │ - "Line": this.lineSymbolizer │ │ │ │ - } │ │ │ │ - })] │ │ │ │ - }); │ │ │ │ - this.gratLayer = new OpenLayers.Layer.Vector(this.layerName, { │ │ │ │ - styleMap: new OpenLayers.StyleMap({ │ │ │ │ - 'default': gratStyle │ │ │ │ - }), │ │ │ │ - visibility: this.visible, │ │ │ │ - displayInLayerSwitcher: this.displayInLayerSwitcher │ │ │ │ - }); │ │ │ │ + getGraphicFormat: function(href) { │ │ │ │ + var format, regex; │ │ │ │ + for (var key in this.graphicFormats) { │ │ │ │ + if (this.graphicFormats[key].test(href)) { │ │ │ │ + format = key; │ │ │ │ + break; │ │ │ │ + } │ │ │ │ } │ │ │ │ - return this.div; │ │ │ │ + return format || this.defaultGraphicFormat; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: activate │ │ │ │ + * Property: defaultGraphicFormat │ │ │ │ + * {String} If none other can be determined from <getGraphicFormat>, this │ │ │ │ + * default will be returned. │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.map.addLayer(this.gratLayer); │ │ │ │ - this.map.events.register('moveend', this, this.update); │ │ │ │ - this.update(); │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + defaultGraphicFormat: "image/png", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ + * Property: graphicFormats │ │ │ │ + * {Object} Mapping of image mime-types to regular extensions matching │ │ │ │ + * well-known file extensions. │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - this.map.events.unregister('moveend', this, this.update); │ │ │ │ - this.map.removeLayer(this.gratLayer); │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ + graphicFormats: { │ │ │ │ + "image/jpeg": /\.jpe?g$/i, │ │ │ │ + "image/gif": /\.gif$/i, │ │ │ │ + "image/png": /\.png$/i │ │ │ │ }, │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: update │ │ │ │ + * Method: write │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * sld - {Object} An object representing the SLD. │ │ │ │ * │ │ │ │ - * calculates the grid to be displayed and actually draws it │ │ │ │ - * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * {DOMElement} The root of an SLD document. │ │ │ │ */ │ │ │ │ - update: function() { │ │ │ │ - //wait for the map to be initialized before proceeding │ │ │ │ - var mapBounds = this.map.getExtent(); │ │ │ │ - if (!mapBounds) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - │ │ │ │ - //clear out the old grid │ │ │ │ - this.gratLayer.destroyFeatures(); │ │ │ │ - │ │ │ │ - //get the projection objects required │ │ │ │ - var llProj = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ - var mapProj = this.map.getProjectionObject(); │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ - │ │ │ │ - //if the map is in lon/lat, then the lines are straight and only one │ │ │ │ - //point is required │ │ │ │ - if (mapProj.proj && mapProj.proj.projName == "longlat") { │ │ │ │ - this.numPoints = 1; │ │ │ │ - } │ │ │ │ + write: function(sld) { │ │ │ │ + return this.writers.sld.StyledLayerDescriptor.apply(this, [sld]); │ │ │ │ + }, │ │ │ │ │ │ │ │ - //get the map center in EPSG:4326 │ │ │ │ - var mapCenter = this.map.getCenter(); //lon and lat here are really map x and y │ │ │ │ - var mapCenterLL = new OpenLayers.Pixel(mapCenter.lon, mapCenter.lat); │ │ │ │ - OpenLayers.Projection.transform(mapCenterLL, mapProj, llProj); │ │ │ │ + /** │ │ │ │ + * 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: OpenLayers.Util.applyDefaults({ │ │ │ │ + "sld": { │ │ │ │ + "_OGCExpression": function(nodeName, value) { │ │ │ │ + // only the simplest of ogc:expression handled │ │ │ │ + // {label: "some text and a ${propertyName}"} │ │ │ │ + var node = this.createElementNSPlus(nodeName); │ │ │ │ + var tokens = typeof value == "string" ? │ │ │ │ + value.split("${") : [value]; │ │ │ │ + node.appendChild(this.createTextNode(tokens[0])); │ │ │ │ + var item, last; │ │ │ │ + for (var i = 1, len = tokens.length; i < len; i++) { │ │ │ │ + item = tokens[i]; │ │ │ │ + last = item.indexOf("}"); │ │ │ │ + if (last > 0) { │ │ │ │ + this.writeNode( │ │ │ │ + "ogc:PropertyName", { │ │ │ │ + property: item.substring(0, last) │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + node.appendChild( │ │ │ │ + this.createTextNode(item.substring(++last)) │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + // no ending }, so this is a literal ${ │ │ │ │ + node.appendChild( │ │ │ │ + this.createTextNode("${" + item) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "StyledLayerDescriptor": function(sld) { │ │ │ │ + var root = this.createElementNSPlus( │ │ │ │ + "sld:StyledLayerDescriptor", { │ │ │ │ + attributes: { │ │ │ │ + "version": this.VERSION, │ │ │ │ + "xsi:schemaLocation": this.schemaLocation │ │ │ │ + } │ │ │ │ + } │ │ │ │ + ); │ │ │ │ │ │ │ │ - /* This block of code determines the lon/lat interval to use for the │ │ │ │ - * grid by calculating the diagonal size of one grid cell at the map │ │ │ │ - * center. Iterates through the intervals array until the diagonal │ │ │ │ - * length is less than the targetSize option. │ │ │ │ - */ │ │ │ │ - //find lat/lon interval that results in a grid of less than the target size │ │ │ │ - var testSq = this.targetSize * mapRes; │ │ │ │ - testSq *= testSq; //compare squares rather than doing a square root to save time │ │ │ │ - var llInterval; │ │ │ │ - for (var i = 0; i < this.intervals.length; ++i) { │ │ │ │ - llInterval = this.intervals[i]; //could do this for both x and y?? │ │ │ │ - var delta = llInterval / 2; │ │ │ │ - var p1 = mapCenterLL.offset({ │ │ │ │ - x: -delta, │ │ │ │ - y: -delta │ │ │ │ - }); //test coords in EPSG:4326 space │ │ │ │ - var p2 = mapCenterLL.offset({ │ │ │ │ - x: delta, │ │ │ │ - y: delta │ │ │ │ - }); │ │ │ │ - OpenLayers.Projection.transform(p1, llProj, mapProj); // convert them back to map projection │ │ │ │ - OpenLayers.Projection.transform(p2, llProj, mapProj); │ │ │ │ - var distSq = (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y); │ │ │ │ - if (distSq <= testSq) { │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - //alert(llInterval); │ │ │ │ + // For ArcGIS Server it is necessary to define this │ │ │ │ + // at the root level (see ticket:2166). │ │ │ │ + root.setAttribute("xmlns:ogc", this.namespaces.ogc); │ │ │ │ + root.setAttribute("xmlns:gml", this.namespaces.gml); │ │ │ │ │ │ │ │ - //round the LL center to an even number based on the interval │ │ │ │ - mapCenterLL.x = Math.floor(mapCenterLL.x / llInterval) * llInterval; │ │ │ │ - mapCenterLL.y = Math.floor(mapCenterLL.y / llInterval) * llInterval; │ │ │ │ - //TODO adjust for minutses/seconds? │ │ │ │ + // add in optional name │ │ │ │ + if (sld.name) { │ │ │ │ + this.writeNode("Name", sld.name, root); │ │ │ │ + } │ │ │ │ + // add in optional title │ │ │ │ + if (sld.title) { │ │ │ │ + this.writeNode("Title", sld.title, root); │ │ │ │ + } │ │ │ │ + // add in optional description │ │ │ │ + if (sld.description) { │ │ │ │ + this.writeNode("Abstract", sld.description, root); │ │ │ │ + } │ │ │ │ + // add in named layers │ │ │ │ + // allow namedLayers to be an array │ │ │ │ + if (OpenLayers.Util.isArray(sld.namedLayers)) { │ │ │ │ + for (var i = 0, len = sld.namedLayers.length; i < len; ++i) { │ │ │ │ + this.writeNode("NamedLayer", sld.namedLayers[i], root); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + for (var name in sld.namedLayers) { │ │ │ │ + this.writeNode("NamedLayer", sld.namedLayers[name], root); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return root; │ │ │ │ + }, │ │ │ │ + "Name": function(name) { │ │ │ │ + return this.createElementNSPlus("sld:Name", { │ │ │ │ + value: name │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Title": function(title) { │ │ │ │ + return this.createElementNSPlus("sld:Title", { │ │ │ │ + value: title │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Abstract": function(description) { │ │ │ │ + return this.createElementNSPlus( │ │ │ │ + "sld:Abstract", { │ │ │ │ + value: description │ │ │ │ + } │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "NamedLayer": function(layer) { │ │ │ │ + var node = this.createElementNSPlus("sld:NamedLayer"); │ │ │ │ │ │ │ │ - /* The following 2 blocks calculate the nodes of the grid along a │ │ │ │ - * line of constant longitude (then latitiude) running through the │ │ │ │ - * center of the map until it reaches the map edge. The calculation │ │ │ │ - * goes from the center in both directions to the edge. │ │ │ │ - */ │ │ │ │ - //get the central longitude line, increment the latitude │ │ │ │ - var iter = 0; │ │ │ │ - var centerLonPoints = [mapCenterLL.clone()]; │ │ │ │ - var newPoint = mapCenterLL.clone(); │ │ │ │ - var mapXY; │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: 0, │ │ │ │ - y: llInterval │ │ │ │ - }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLonPoints.unshift(newPoint); │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ - newPoint = mapCenterLL.clone(); │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: 0, │ │ │ │ - y: -llInterval │ │ │ │ - }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLonPoints.push(newPoint); │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ + // add in required name │ │ │ │ + this.writeNode("Name", layer.name, node); │ │ │ │ │ │ │ │ - //get the central latitude line, increment the longitude │ │ │ │ - iter = 0; │ │ │ │ - var centerLatPoints = [mapCenterLL.clone()]; │ │ │ │ - newPoint = mapCenterLL.clone(); │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: -llInterval, │ │ │ │ - y: 0 │ │ │ │ - }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLatPoints.unshift(newPoint); │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ - newPoint = mapCenterLL.clone(); │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: llInterval, │ │ │ │ - y: 0 │ │ │ │ - }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLatPoints.push(newPoint); │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ + // optional sld:LayerFeatureConstraints here │ │ │ │ │ │ │ │ - //now generate a line for each node in the central lat and lon lines │ │ │ │ - //first loop over constant longitude │ │ │ │ - var lines = []; │ │ │ │ - for (var i = 0; i < centerLatPoints.length; ++i) { │ │ │ │ - var lon = centerLatPoints[i].x; │ │ │ │ - var pointList = []; │ │ │ │ - var labelPoint = null; │ │ │ │ - var latEnd = Math.min(centerLonPoints[0].y, 90); │ │ │ │ - var latStart = Math.max(centerLonPoints[centerLonPoints.length - 1].y, -90); │ │ │ │ - var latDelta = (latEnd - latStart) / this.numPoints; │ │ │ │ - var lat = latStart; │ │ │ │ - for (var j = 0; j <= this.numPoints; ++j) { │ │ │ │ - var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ - gridPoint.transform(llProj, mapProj); │ │ │ │ - pointList.push(gridPoint); │ │ │ │ - lat += latDelta; │ │ │ │ - if (gridPoint.y >= mapBounds.bottom && !labelPoint) { │ │ │ │ - labelPoint = gridPoint; │ │ │ │ + // add in named styles │ │ │ │ + if (layer.namedStyles) { │ │ │ │ + for (var i = 0, len = layer.namedStyles.length; i < len; ++i) { │ │ │ │ + this.writeNode( │ │ │ │ + "NamedStyle", layer.namedStyles[i], node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ } │ │ │ │ - } │ │ │ │ - if (this.labelled) { │ │ │ │ - //keep track of when this grid line crosses the map bounds to set │ │ │ │ - //the label position │ │ │ │ - //labels along the bottom, add 10 pixel offset up into the map │ │ │ │ - //TODO add option for labels on top │ │ │ │ - var labelPos = new OpenLayers.Geometry.Point(labelPoint.x, mapBounds.bottom); │ │ │ │ - var labelAttrs = { │ │ │ │ - value: lon, │ │ │ │ - label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lon, "lon", this.labelFormat) : "", │ │ │ │ - labelAlign: "cb", │ │ │ │ - xOffset: 0, │ │ │ │ - yOffset: 2 │ │ │ │ - }; │ │ │ │ - this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)); │ │ │ │ - } │ │ │ │ - var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ - lines.push(new OpenLayers.Feature.Vector(geom)); │ │ │ │ - } │ │ │ │ │ │ │ │ - //now draw the lines of constant latitude │ │ │ │ - for (var j = 0; j < centerLonPoints.length; ++j) { │ │ │ │ - lat = centerLonPoints[j].y; │ │ │ │ - if (lat < -90 || lat > 90) { //latitudes only valid between -90 and 90 │ │ │ │ - continue; │ │ │ │ - } │ │ │ │ - var pointList = []; │ │ │ │ - var lonStart = centerLatPoints[0].x; │ │ │ │ - var lonEnd = centerLatPoints[centerLatPoints.length - 1].x; │ │ │ │ - var lonDelta = (lonEnd - lonStart) / this.numPoints; │ │ │ │ - var lon = lonStart; │ │ │ │ - var labelPoint = null; │ │ │ │ - for (var i = 0; i <= this.numPoints; ++i) { │ │ │ │ - var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ - gridPoint.transform(llProj, mapProj); │ │ │ │ - pointList.push(gridPoint); │ │ │ │ - lon += lonDelta; │ │ │ │ - if (gridPoint.x < mapBounds.right) { │ │ │ │ - labelPoint = gridPoint; │ │ │ │ + // add in user styles │ │ │ │ + if (layer.userStyles) { │ │ │ │ + for (var i = 0, len = layer.userStyles.length; i < len; ++i) { │ │ │ │ + this.writeNode( │ │ │ │ + "UserStyle", layer.userStyles[i], node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ } │ │ │ │ - } │ │ │ │ - if (this.labelled) { │ │ │ │ - //keep track of when this grid line crosses the map bounds to set │ │ │ │ - //the label position │ │ │ │ - //labels along the right, 30 pixel offset left into the map │ │ │ │ - //TODO add option for labels on left │ │ │ │ - var labelPos = new OpenLayers.Geometry.Point(mapBounds.right, labelPoint.y); │ │ │ │ - var labelAttrs = { │ │ │ │ - value: lat, │ │ │ │ - label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lat, "lat", this.labelFormat) : "", │ │ │ │ - labelAlign: "rb", │ │ │ │ - xOffset: -2, │ │ │ │ - yOffset: 2 │ │ │ │ - }; │ │ │ │ - this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)); │ │ │ │ - } │ │ │ │ - var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ - lines.push(new OpenLayers.Feature.Vector(geom)); │ │ │ │ - } │ │ │ │ - this.gratLayer.addFeatures(lines); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Graticule" │ │ │ │ -}); │ │ │ │ │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/ArgParser.js │ │ │ │ - ====================================================================== */ │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "NamedStyle": function(name) { │ │ │ │ + var node = this.createElementNSPlus("sld:NamedStyle"); │ │ │ │ + this.writeNode("Name", name, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "UserStyle": function(style) { │ │ │ │ + var node = this.createElementNSPlus("sld:UserStyle"); │ │ │ │ │ │ │ │ -/* 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. */ │ │ │ │ + // add in optional name │ │ │ │ + if (style.name) { │ │ │ │ + this.writeNode("Name", style.name, node); │ │ │ │ + } │ │ │ │ + // add in optional title │ │ │ │ + if (style.title) { │ │ │ │ + this.writeNode("Title", style.title, node); │ │ │ │ + } │ │ │ │ + // add in optional description │ │ │ │ + if (style.description) { │ │ │ │ + this.writeNode("Abstract", style.description, node); │ │ │ │ + } │ │ │ │ │ │ │ │ + // add isdefault │ │ │ │ + if (style.isDefault) { │ │ │ │ + this.writeNode("IsDefault", style.isDefault, node); │ │ │ │ + } │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Control.js │ │ │ │ - */ │ │ │ │ + // add FeatureTypeStyles │ │ │ │ + if (this.multipleSymbolizers && style.rules) { │ │ │ │ + // group style objects by symbolizer zIndex │ │ │ │ + var rulesByZ = { │ │ │ │ + 0: [] │ │ │ │ + }; │ │ │ │ + var zValues = [0]; │ │ │ │ + var rule, ruleMap, symbolizer, zIndex, clone; │ │ │ │ + for (var i = 0, ii = style.rules.length; i < ii; ++i) { │ │ │ │ + rule = style.rules[i]; │ │ │ │ + if (rule.symbolizers) { │ │ │ │ + ruleMap = {}; │ │ │ │ + for (var j = 0, jj = rule.symbolizers.length; j < jj; ++j) { │ │ │ │ + symbolizer = rule.symbolizers[j]; │ │ │ │ + zIndex = symbolizer.zIndex; │ │ │ │ + if (!(zIndex in ruleMap)) { │ │ │ │ + clone = rule.clone(); │ │ │ │ + clone.symbolizers = []; │ │ │ │ + ruleMap[zIndex] = clone; │ │ │ │ + } │ │ │ │ + ruleMap[zIndex].symbolizers.push(symbolizer.clone()); │ │ │ │ + } │ │ │ │ + for (zIndex in ruleMap) { │ │ │ │ + if (!(zIndex in rulesByZ)) { │ │ │ │ + zValues.push(zIndex); │ │ │ │ + rulesByZ[zIndex] = []; │ │ │ │ + } │ │ │ │ + rulesByZ[zIndex].push(ruleMap[zIndex]); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + // no symbolizers in rule │ │ │ │ + rulesByZ[0].push(rule.clone()); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + // write one FeatureTypeStyle per zIndex │ │ │ │ + zValues.sort(); │ │ │ │ + var rules; │ │ │ │ + for (var i = 0, ii = zValues.length; i < ii; ++i) { │ │ │ │ + rules = rulesByZ[zValues[i]]; │ │ │ │ + if (rules.length > 0) { │ │ │ │ + clone = style.clone(); │ │ │ │ + clone.rules = rulesByZ[zValues[i]]; │ │ │ │ + this.writeNode("FeatureTypeStyle", clone, node); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.writeNode("FeatureTypeStyle", style, node); │ │ │ │ + } │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.ArgParser │ │ │ │ - * The ArgParser control adds location bar query string parsing functionality │ │ │ │ - * to an OpenLayers Map. │ │ │ │ - * When added to a Map control, on a page load/refresh, the Map will │ │ │ │ - * automatically take the href string and parse it for lon, lat, zoom, and │ │ │ │ - * layers information. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "IsDefault": function(bool) { │ │ │ │ + return this.createElementNSPlus( │ │ │ │ + "sld:IsDefault", { │ │ │ │ + value: (bool) ? "1" : "0" │ │ │ │ + } │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "FeatureTypeStyle": function(style) { │ │ │ │ + var node = this.createElementNSPlus("sld:FeatureTypeStyle"); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: center │ │ │ │ - * {<OpenLayers.LonLat>} │ │ │ │ - */ │ │ │ │ - center: null, │ │ │ │ + // OpenLayers currently stores no Name, Title, Abstract, │ │ │ │ + // FeatureTypeName, or SemanticTypeIdentifier information │ │ │ │ + // related to FeatureTypeStyle │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: zoom │ │ │ │ - * {int} │ │ │ │ - */ │ │ │ │ - zoom: null, │ │ │ │ + // add in rules │ │ │ │ + for (var i = 0, len = style.rules.length; i < len; ++i) { │ │ │ │ + this.writeNode("Rule", style.rules[i], node); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: layers │ │ │ │ - * {String} Each character represents the state of the corresponding layer │ │ │ │ - * on the map. │ │ │ │ - */ │ │ │ │ - layers: null, │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Rule": function(rule) { │ │ │ │ + var node = this.createElementNSPlus("sld:Rule"); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: displayProjection │ │ │ │ - * {<OpenLayers.Projection>} Requires proj4js support. │ │ │ │ - * Projection used when reading the coordinates from the URL. This will │ │ │ │ - * reproject the map coordinates from the URL into the map's │ │ │ │ - * projection. │ │ │ │ - * │ │ │ │ - * If you are using this functionality, be aware that any permalink │ │ │ │ - * which is added to the map will determine the coordinate type which │ │ │ │ - * is read from the URL, which means you should not add permalinks with │ │ │ │ - * different displayProjections to the same map. │ │ │ │ - */ │ │ │ │ - displayProjection: null, │ │ │ │ + // add in optional name │ │ │ │ + if (rule.name) { │ │ │ │ + this.writeNode("Name", rule.name, node); │ │ │ │ + } │ │ │ │ + // add in optional title │ │ │ │ + if (rule.title) { │ │ │ │ + this.writeNode("Title", rule.title, node); │ │ │ │ + } │ │ │ │ + // add in optional description │ │ │ │ + if (rule.description) { │ │ │ │ + this.writeNode("Abstract", rule.description, node); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.ArgParser │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ - */ │ │ │ │ + // add in LegendGraphic here │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getParameters │ │ │ │ - */ │ │ │ │ - getParameters: function(url) { │ │ │ │ - url = url || window.location.href; │ │ │ │ - var parameters = OpenLayers.Util.getParameters(url); │ │ │ │ + // add in optional filters │ │ │ │ + if (rule.elseFilter) { │ │ │ │ + this.writeNode("ElseFilter", null, node); │ │ │ │ + } else if (rule.filter) { │ │ │ │ + this.writeNode("ogc:Filter", rule.filter, node); │ │ │ │ + } │ │ │ │ │ │ │ │ - // If we have an anchor in the url use it to split the url │ │ │ │ - var index = url.indexOf('#'); │ │ │ │ - if (index > 0) { │ │ │ │ - // create an url to parse on the getParameters │ │ │ │ - url = '?' + url.substring(index + 1, url.length); │ │ │ │ + // add in scale limits │ │ │ │ + if (rule.minScaleDenominator != undefined) { │ │ │ │ + this.writeNode( │ │ │ │ + "MinScaleDenominator", rule.minScaleDenominator, node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (rule.maxScaleDenominator != undefined) { │ │ │ │ + this.writeNode( │ │ │ │ + "MaxScaleDenominator", rule.maxScaleDenominator, node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ │ │ │ │ - OpenLayers.Util.extend(parameters, │ │ │ │ - OpenLayers.Util.getParameters(url)); │ │ │ │ - } │ │ │ │ - return parameters; │ │ │ │ - }, │ │ │ │ + var type, symbolizer; │ │ │ │ + if (this.multipleSymbolizers && rule.symbolizers) { │ │ │ │ + var symbolizer; │ │ │ │ + for (var i = 0, ii = rule.symbolizers.length; i < ii; ++i) { │ │ │ │ + symbolizer = rule.symbolizers[i]; │ │ │ │ + type = symbolizer.CLASS_NAME.split(".").pop(); │ │ │ │ + this.writeNode( │ │ │ │ + type + "Symbolizer", symbolizer, node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + // add in symbolizers (relies on geometry type keys) │ │ │ │ + var types = OpenLayers.Style.SYMBOLIZER_PREFIXES; │ │ │ │ + for (var i = 0, len = types.length; i < len; ++i) { │ │ │ │ + type = types[i]; │ │ │ │ + symbolizer = rule.symbolizer[type]; │ │ │ │ + if (symbolizer) { │ │ │ │ + this.writeNode( │ │ │ │ + type + "Symbolizer", symbolizer, node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * Set the map property for the control. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ - */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + "ElseFilter": function() { │ │ │ │ + return this.createElementNSPlus("sld:ElseFilter"); │ │ │ │ + }, │ │ │ │ + "MinScaleDenominator": function(scale) { │ │ │ │ + return this.createElementNSPlus( │ │ │ │ + "sld:MinScaleDenominator", { │ │ │ │ + value: scale │ │ │ │ + } │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "MaxScaleDenominator": function(scale) { │ │ │ │ + return this.createElementNSPlus( │ │ │ │ + "sld:MaxScaleDenominator", { │ │ │ │ + value: scale │ │ │ │ + } │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "LineSymbolizer": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:LineSymbolizer"); │ │ │ │ + this.writeNode("Stroke", symbolizer, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Stroke": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:Stroke"); │ │ │ │ │ │ │ │ - //make sure we dont already have an arg parser attached │ │ │ │ - for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ - var control = this.map.controls[i]; │ │ │ │ - if ((control != this) && │ │ │ │ - (control.CLASS_NAME == "OpenLayers.Control.ArgParser")) { │ │ │ │ + // GraphicFill here │ │ │ │ + // GraphicStroke here │ │ │ │ │ │ │ │ - // If a second argparser is added to the map, then we │ │ │ │ - // override the displayProjection to be the one added to the │ │ │ │ - // map. │ │ │ │ - if (control.displayProjection != this.displayProjection) { │ │ │ │ - this.displayProjection = control.displayProjection; │ │ │ │ + // add in CssParameters │ │ │ │ + if (symbolizer.strokeColor != undefined) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "strokeColor" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ } │ │ │ │ + if (symbolizer.strokeOpacity != undefined) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "strokeOpacity" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (symbolizer.strokeWidth != undefined) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "strokeWidth" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (symbolizer.strokeDashstyle != undefined && symbolizer.strokeDashstyle !== "solid") { │ │ │ │ + // assumes valid stroke-dasharray value │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "strokeDashstyle" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (symbolizer.strokeLinecap != undefined) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "strokeLinecap" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "CssParameter": function(obj) { │ │ │ │ + // not handling ogc:expressions for now │ │ │ │ + return this.createElementNSPlus("sld:CssParameter", { │ │ │ │ + attributes: { │ │ │ │ + name: this.getCssProperty(obj.key) │ │ │ │ + }, │ │ │ │ + value: obj.symbolizer[obj.key] │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "TextSymbolizer": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:TextSymbolizer"); │ │ │ │ + // add in optional Label │ │ │ │ + if (symbolizer.label != null) { │ │ │ │ + this.writeNode("Label", symbolizer.label, node); │ │ │ │ + } │ │ │ │ + // add in optional Font │ │ │ │ + if (symbolizer.fontFamily != null || │ │ │ │ + symbolizer.fontSize != null || │ │ │ │ + symbolizer.fontWeight != null || │ │ │ │ + symbolizer.fontStyle != null) { │ │ │ │ + this.writeNode("Font", symbolizer, node); │ │ │ │ + } │ │ │ │ + // add in optional LabelPlacement │ │ │ │ + if (symbolizer.labelAnchorPointX != null || │ │ │ │ + symbolizer.labelAnchorPointY != null || │ │ │ │ + symbolizer.labelAlign != null || │ │ │ │ + symbolizer.labelXOffset != null || │ │ │ │ + symbolizer.labelYOffset != null || │ │ │ │ + symbolizer.labelRotation != null || │ │ │ │ + symbolizer.labelPerpendicularOffset != null) { │ │ │ │ + this.writeNode("LabelPlacement", symbolizer, node); │ │ │ │ + } │ │ │ │ + // add in optional Halo │ │ │ │ + if (symbolizer.haloRadius != null || │ │ │ │ + symbolizer.haloColor != null || │ │ │ │ + symbolizer.haloOpacity != null) { │ │ │ │ + this.writeNode("Halo", symbolizer, node); │ │ │ │ + } │ │ │ │ + // add in optional Fill │ │ │ │ + if (symbolizer.fontColor != null || │ │ │ │ + symbolizer.fontOpacity != null) { │ │ │ │ + this.writeNode("Fill", { │ │ │ │ + fillColor: symbolizer.fontColor, │ │ │ │ + fillOpacity: symbolizer.fontOpacity │ │ │ │ + }, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "LabelPlacement": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:LabelPlacement"); │ │ │ │ + // PointPlacement and LinePlacement are choices, so don't output both │ │ │ │ + if ((symbolizer.labelAnchorPointX != null || │ │ │ │ + symbolizer.labelAnchorPointY != null || │ │ │ │ + symbolizer.labelAlign != null || │ │ │ │ + symbolizer.labelXOffset != null || │ │ │ │ + symbolizer.labelYOffset != null || │ │ │ │ + symbolizer.labelRotation != null) && │ │ │ │ + symbolizer.labelPerpendicularOffset == null) { │ │ │ │ + this.writeNode("PointPlacement", symbolizer, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.labelPerpendicularOffset != null) { │ │ │ │ + this.writeNode("LinePlacement", symbolizer, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "LinePlacement": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:LinePlacement"); │ │ │ │ + this.writeNode("PerpendicularOffset", symbolizer.labelPerpendicularOffset, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "PerpendicularOffset": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:PerpendicularOffset", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "PointPlacement": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:PointPlacement"); │ │ │ │ + if (symbolizer.labelAnchorPointX != null || │ │ │ │ + symbolizer.labelAnchorPointY != null || │ │ │ │ + symbolizer.labelAlign != null) { │ │ │ │ + this.writeNode("AnchorPoint", symbolizer, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.labelXOffset != null || │ │ │ │ + symbolizer.labelYOffset != null) { │ │ │ │ + this.writeNode("Displacement", symbolizer, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.labelRotation != null) { │ │ │ │ + this.writeNode("Rotation", symbolizer.labelRotation, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "AnchorPoint": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:AnchorPoint"); │ │ │ │ + var x = symbolizer.labelAnchorPointX, │ │ │ │ + y = symbolizer.labelAnchorPointY; │ │ │ │ + if (x != null) { │ │ │ │ + this.writeNode("AnchorPointX", x, node); │ │ │ │ + } │ │ │ │ + if (y != null) { │ │ │ │ + this.writeNode("AnchorPointY", y, node); │ │ │ │ + } │ │ │ │ + if (x == null && y == null) { │ │ │ │ + var xAlign = symbolizer.labelAlign.substr(0, 1), │ │ │ │ + yAlign = symbolizer.labelAlign.substr(1, 1); │ │ │ │ + if (xAlign === "l") { │ │ │ │ + x = 0; │ │ │ │ + } else if (xAlign === "c") { │ │ │ │ + x = 0.5; │ │ │ │ + } else if (xAlign === "r") { │ │ │ │ + x = 1; │ │ │ │ + } │ │ │ │ + if (yAlign === "b") { │ │ │ │ + y = 0; │ │ │ │ + } else if (yAlign === "m") { │ │ │ │ + y = 0.5; │ │ │ │ + } else if (yAlign === "t") { │ │ │ │ + y = 1; │ │ │ │ + } │ │ │ │ + this.writeNode("AnchorPointX", x, node); │ │ │ │ + this.writeNode("AnchorPointY", y, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "AnchorPointX": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:AnchorPointX", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "AnchorPointY": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:AnchorPointY", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Displacement": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:Displacement"); │ │ │ │ + if (symbolizer.labelXOffset != null) { │ │ │ │ + this.writeNode("DisplacementX", symbolizer.labelXOffset, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.labelYOffset != null) { │ │ │ │ + this.writeNode("DisplacementY", symbolizer.labelYOffset, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "DisplacementX": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:DisplacementX", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "DisplacementY": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:DisplacementY", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Font": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:Font"); │ │ │ │ + // add in CssParameters │ │ │ │ + if (symbolizer.fontFamily) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "fontFamily" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (symbolizer.fontSize) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "fontSize" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (symbolizer.fontWeight) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "fontWeight" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (symbolizer.fontStyle) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "fontStyle" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Label": function(label) { │ │ │ │ + return this.writers.sld._OGCExpression.call( │ │ │ │ + this, "sld:Label", label │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "Halo": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:Halo"); │ │ │ │ + if (symbolizer.haloRadius) { │ │ │ │ + this.writeNode("Radius", symbolizer.haloRadius, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.haloColor || symbolizer.haloOpacity) { │ │ │ │ + this.writeNode("Fill", { │ │ │ │ + fillColor: symbolizer.haloColor, │ │ │ │ + fillOpacity: symbolizer.haloOpacity │ │ │ │ + }, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Radius": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:Radius", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "RasterSymbolizer": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:RasterSymbolizer"); │ │ │ │ + if (symbolizer.geometry) { │ │ │ │ + this.writeNode("Geometry", symbolizer.geometry, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.opacity) { │ │ │ │ + this.writeNode("Opacity", symbolizer.opacity, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.colorMap) { │ │ │ │ + this.writeNode("ColorMap", symbolizer.colorMap, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Geometry": function(geometry) { │ │ │ │ + var node = this.createElementNSPlus("sld:Geometry"); │ │ │ │ + if (geometry.property) { │ │ │ │ + this.writeNode("ogc:PropertyName", geometry, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ColorMap": function(colorMap) { │ │ │ │ + var node = this.createElementNSPlus("sld:ColorMap"); │ │ │ │ + for (var i = 0, len = colorMap.length; i < len; ++i) { │ │ │ │ + this.writeNode("ColorMapEntry", colorMap[i], node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ColorMapEntry": function(colorMapEntry) { │ │ │ │ + var node = this.createElementNSPlus("sld:ColorMapEntry"); │ │ │ │ + var a = colorMapEntry; │ │ │ │ + node.setAttribute("color", a.color); │ │ │ │ + a.opacity !== undefined && node.setAttribute("opacity", │ │ │ │ + parseFloat(a.opacity)); │ │ │ │ + a.quantity !== undefined && node.setAttribute("quantity", │ │ │ │ + parseFloat(a.quantity)); │ │ │ │ + a.label !== undefined && node.setAttribute("label", a.label); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "PolygonSymbolizer": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:PolygonSymbolizer"); │ │ │ │ + if (symbolizer.fill !== false) { │ │ │ │ + this.writeNode("Fill", symbolizer, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.stroke !== false) { │ │ │ │ + this.writeNode("Stroke", symbolizer, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Fill": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:Fill"); │ │ │ │ │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (i == this.map.controls.length) { │ │ │ │ - │ │ │ │ - var args = this.getParameters(); │ │ │ │ - // Be careful to set layer first, to not trigger unnecessary layer loads │ │ │ │ - if (args.layers) { │ │ │ │ - this.layers = args.layers; │ │ │ │ + // GraphicFill here │ │ │ │ │ │ │ │ - // when we add a new layer, set its visibility │ │ │ │ - this.map.events.register('addlayer', this, │ │ │ │ - this.configureLayers); │ │ │ │ - this.configureLayers(); │ │ │ │ - } │ │ │ │ - if (args.lat && args.lon) { │ │ │ │ - this.center = new OpenLayers.LonLat(parseFloat(args.lon), │ │ │ │ - parseFloat(args.lat)); │ │ │ │ - if (args.zoom) { │ │ │ │ - this.zoom = parseFloat(args.zoom); │ │ │ │ + // add in CssParameters │ │ │ │ + if (symbolizer.fillColor) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "fillColor" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (symbolizer.fillOpacity != null) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "fillOpacity" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "PointSymbolizer": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:PointSymbolizer"); │ │ │ │ + this.writeNode("Graphic", symbolizer, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Graphic": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:Graphic"); │ │ │ │ + if (symbolizer.externalGraphic != undefined) { │ │ │ │ + this.writeNode("ExternalGraphic", symbolizer, node); │ │ │ │ + } else { │ │ │ │ + this.writeNode("Mark", symbolizer, node); │ │ │ │ } │ │ │ │ │ │ │ │ - // when we add a new baselayer to see when we can set the center │ │ │ │ - this.map.events.register('changebaselayer', this, │ │ │ │ - this.setCenter); │ │ │ │ - this.setCenter(); │ │ │ │ + if (symbolizer.graphicOpacity != undefined) { │ │ │ │ + this.writeNode("Opacity", symbolizer.graphicOpacity, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.pointRadius != undefined) { │ │ │ │ + this.writeNode("Size", symbolizer.pointRadius * 2, node); │ │ │ │ + } else if (symbolizer.graphicWidth != undefined) { │ │ │ │ + this.writeNode("Size", symbolizer.graphicWidth, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.rotation != undefined) { │ │ │ │ + this.writeNode("Rotation", symbolizer.rotation, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ExternalGraphic": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:ExternalGraphic"); │ │ │ │ + this.writeNode( │ │ │ │ + "OnlineResource", symbolizer.externalGraphic, node │ │ │ │ + ); │ │ │ │ + var format = symbolizer.graphicFormat || │ │ │ │ + this.getGraphicFormat(symbolizer.externalGraphic); │ │ │ │ + this.writeNode("Format", format, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Mark": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:Mark"); │ │ │ │ + if (symbolizer.graphicName) { │ │ │ │ + this.writeNode("WellKnownName", symbolizer.graphicName, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.fill !== false) { │ │ │ │ + this.writeNode("Fill", symbolizer, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.stroke !== false) { │ │ │ │ + this.writeNode("Stroke", symbolizer, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "WellKnownName": function(name) { │ │ │ │ + return this.createElementNSPlus("sld:WellKnownName", { │ │ │ │ + value: name │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Opacity": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:Opacity", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Size": function(value) { │ │ │ │ + return this.writers.sld._OGCExpression.call( │ │ │ │ + this, "sld:Size", value │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "Rotation": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:Rotation", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "OnlineResource": function(href) { │ │ │ │ + return this.createElementNSPlus("sld:OnlineResource", { │ │ │ │ + attributes: { │ │ │ │ + "xlink:type": "simple", │ │ │ │ + "xlink:href": href │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Format": function(format) { │ │ │ │ + return this.createElementNSPlus("sld:Format", { │ │ │ │ + value: format │ │ │ │ + }); │ │ │ │ } │ │ │ │ } │ │ │ │ - }, │ │ │ │ + }, OpenLayers.Format.Filter.v1_0_0.prototype.writers), │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setCenter │ │ │ │ - * As soon as a baseLayer has been loaded, we center and zoom │ │ │ │ - * ...and remove the handler. │ │ │ │ - */ │ │ │ │ - setCenter: function() { │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SLD.v1" │ │ │ │ │ │ │ │ - if (this.map.baseLayer) { │ │ │ │ - //dont need to listen for this one anymore │ │ │ │ - this.map.events.unregister('changebaselayer', this, │ │ │ │ - this.setCenter); │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/SLD/v1_0_0.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - if (this.displayProjection) { │ │ │ │ - this.center.transform(this.displayProjection, │ │ │ │ - this.map.getProjectionObject()); │ │ │ │ - } │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - this.map.setCenter(this.center, this.zoom); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/SLD/v1.js │ │ │ │ + * @requires OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: configureLayers │ │ │ │ - * As soon as all the layers are loaded, cycle through them and │ │ │ │ - * hide or show them. │ │ │ │ - */ │ │ │ │ - configureLayers: function() { │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.SLD.v1_0_0 │ │ │ │ + * Write SLD version 1.0.0. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.SLD.v1> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.SLD.v1_0_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.SLD.v1, { │ │ │ │ │ │ │ │ - if (this.layers.length == this.map.layers.length) { │ │ │ │ - this.map.events.unregister('addlayer', this, this.configureLayers); │ │ │ │ + /** │ │ │ │ + * Constant: VERSION │ │ │ │ + * {String} 1.0.0 │ │ │ │ + */ │ │ │ │ + VERSION: "1.0.0", │ │ │ │ │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ + /** │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} http://www.opengis.net/sld │ │ │ │ + * http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd │ │ │ │ + */ │ │ │ │ + schemaLocation: "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd", │ │ │ │ │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - var c = this.layers.charAt(i); │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.SLD.v1_0_0 │ │ │ │ + * Instances of this class are not created directly. Use the │ │ │ │ + * <OpenLayers.Format.SLD> constructor instead. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (c == "B") { │ │ │ │ - this.map.setBaseLayer(layer); │ │ │ │ - } else if ((c == "T") || (c == "F")) { │ │ │ │ - layer.setVisibility(c == "T"); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ArgParser" │ │ │ │ -}); │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Permalink.js │ │ │ │ + OpenLayers/Control/SLDSelect.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/Control/ArgParser.js │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ + * @requires OpenLayers/Layer/WMS.js │ │ │ │ + * @requires OpenLayers/Handler/RegularPolygon.js │ │ │ │ + * @requires OpenLayers/Handler/Polygon.js │ │ │ │ + * @requires OpenLayers/Handler/Path.js │ │ │ │ + * @requires OpenLayers/Handler/Click.js │ │ │ │ + * @requires OpenLayers/Filter/Spatial.js │ │ │ │ + * @requires OpenLayers/Format/SLD/v1_0_0.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Permalink │ │ │ │ - * The Permalink control is hyperlink that will return the user to the │ │ │ │ - * current map view. By default it is drawn in the lower right corner of the │ │ │ │ - * map. The href is updated as the map is zoomed, panned and whilst layers │ │ │ │ - * are switched. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Control.SLDSelect │ │ │ │ + * Perform selections on WMS layers using Styled Layer Descriptor (SLD) │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Control.SLDSelect = 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>): │ │ │ │ + * selected - Triggered when a selection occurs. Listeners receive an │ │ │ │ + * event with *filters* and *layer* properties. Filters will be an │ │ │ │ + * array of OpenLayers.Filter objects created in order to perform │ │ │ │ + * the particular selection. │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: argParserClass │ │ │ │ - * {Class} The ArgParser control class (not instance) to use with this │ │ │ │ - * control. │ │ │ │ + * APIProperty: clearOnDeactivate │ │ │ │ + * {Boolean} Should the selection be cleared when the control is │ │ │ │ + * deactivated. Default value is false. │ │ │ │ */ │ │ │ │ - argParserClass: OpenLayers.Control.ArgParser, │ │ │ │ + clearOnDeactivate: false, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: element │ │ │ │ - * {DOMElement} │ │ │ │ + /** │ │ │ │ + * APIProperty: layers │ │ │ │ + * {Array(<OpenLayers.Layer.WMS>)} The WMS layers this control will work │ │ │ │ + * on. │ │ │ │ */ │ │ │ │ - element: null, │ │ │ │ + layers: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: anchor │ │ │ │ - * {Boolean} This option changes 3 things: │ │ │ │ - * the character '#' is used in place of the character '?', │ │ │ │ - * the window.href is updated if no element is provided. │ │ │ │ - * When this option is set to true it's not recommend to provide │ │ │ │ - * a base without provide an element. │ │ │ │ + /** │ │ │ │ + * Property: callbacks │ │ │ │ + * {Object} The functions that are sent to the handler for callback │ │ │ │ */ │ │ │ │ - anchor: false, │ │ │ │ + callbacks: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: base │ │ │ │ - * {String} │ │ │ │ + /** │ │ │ │ + * APIProperty: selectionSymbolizer │ │ │ │ + * {Object} Determines the styling of the selected objects. Default is │ │ │ │ + * a selection in red. │ │ │ │ */ │ │ │ │ - base: '', │ │ │ │ + selectionSymbolizer: { │ │ │ │ + 'Polygon': { │ │ │ │ + fillColor: '#FF0000', │ │ │ │ + stroke: false │ │ │ │ + }, │ │ │ │ + 'Line': { │ │ │ │ + strokeColor: '#FF0000', │ │ │ │ + strokeWidth: 2 │ │ │ │ + }, │ │ │ │ + 'Point': { │ │ │ │ + graphicName: 'square', │ │ │ │ + fillColor: '#FF0000', │ │ │ │ + pointRadius: 5 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: displayProjection │ │ │ │ - * {<OpenLayers.Projection>} Requires proj4js support. Projection used │ │ │ │ - * when creating the coordinates in the link. This will reproject the │ │ │ │ - * map coordinates into display coordinates. If you are using this │ │ │ │ - * functionality, the permalink which is last added to the map will │ │ │ │ - * determine the coordinate type which is read from the URL, which │ │ │ │ - * means you should not add permalinks with different │ │ │ │ - * displayProjections to the same map. │ │ │ │ + /** │ │ │ │ + * APIProperty: layerOptions │ │ │ │ + * {Object} The options to apply to the selection layer, by default the │ │ │ │ + * selection layer will be kept out of the layer switcher. │ │ │ │ */ │ │ │ │ - displayProjection: null, │ │ │ │ + layerOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.Permalink │ │ │ │ + * APIProperty: handlerOptions │ │ │ │ + * {Object} Used to set non-default properties on the control's handler │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: sketchStyle │ │ │ │ + * {<OpenLayers.Style>|Object} Style or symbolizer to use for the sketch │ │ │ │ + * handler. The recommended way of styling the sketch layer, however, is │ │ │ │ + * to configure an <OpenLayers.StyleMap> in the layerOptions of the │ │ │ │ + * <handlerOptions>: │ │ │ │ + * │ │ │ │ + * (code) │ │ │ │ + * new OpenLayers.Control.SLDSelect(OpenLayers.Handler.Path, { │ │ │ │ + * handlerOptions: { │ │ │ │ + * layerOptions: { │ │ │ │ + * styleMap: new OpenLayers.StyleMap({ │ │ │ │ + * "default": {strokeColor: "yellow"} │ │ │ │ + * }) │ │ │ │ + * } │ │ │ │ + * } │ │ │ │ + * }); │ │ │ │ + * (end) │ │ │ │ + */ │ │ │ │ + sketchStyle: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: wfsCache │ │ │ │ + * {Object} Cache to use for storing parsed results from │ │ │ │ + * <OpenLayers.Format.WFSDescribeFeatureType.read>. If not provided, │ │ │ │ + * these will be cached on the prototype. │ │ │ │ + */ │ │ │ │ + wfsCache: {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: layerCache │ │ │ │ + * {Object} Cache to use for storing references to the selection layers. │ │ │ │ + * Normally each source layer will have exactly 1 selection layer of │ │ │ │ + * type OpenLayers.Layer.WMS. If not provided, layers will │ │ │ │ + * be cached on the prototype. Note that if <clearOnDeactivate> is │ │ │ │ + * true, the layer will no longer be cached after deactivating the │ │ │ │ + * control. │ │ │ │ + */ │ │ │ │ + layerCache: {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.SLDSelect │ │ │ │ + * Create a new control for selecting features in WMS layers using │ │ │ │ + * Styled Layer Descriptor (SLD). │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * element - {DOMElement} │ │ │ │ - * base - {String} │ │ │ │ - * options - {Object} options to the control. │ │ │ │ + * Parameters: │ │ │ │ + * handler - {<OpenLayers.Class>} A sketch handler class. This determines │ │ │ │ + * the type of selection, e.g. box (<OpenLayers.Handler.Box>), point │ │ │ │ + * (<OpenLayers.Handler.Point>), path (<OpenLayers.Handler.Path>) or │ │ │ │ + * polygon (<OpenLayers.Handler.Polygon>) selection. To use circle │ │ │ │ + * type selection, use <OpenLayers.Handler.RegularPolygon> and pass │ │ │ │ + * the number of desired sides (e.g. 40) as "sides" property to the │ │ │ │ + * <handlerOptions>. │ │ │ │ + * options - {Object} An object containing all configuration properties for │ │ │ │ + * the control. │ │ │ │ * │ │ │ │ - * Or for anchor: │ │ │ │ - * options - {Object} options to the control. │ │ │ │ + * Valid options: │ │ │ │ + * layers - Array({<OpenLayers.Layer.WMS>}) The layers to perform the │ │ │ │ + * selection on. │ │ │ │ */ │ │ │ │ - initialize: function(element, base, options) { │ │ │ │ - if (element !== null && typeof element == 'object' && !OpenLayers.Util.isElement(element)) { │ │ │ │ - options = element; │ │ │ │ - this.base = document.location.href; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - if (this.element != null) { │ │ │ │ - this.element = OpenLayers.Util.getElement(this.element); │ │ │ │ + initialize: function(handler, options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + │ │ │ │ + this.callbacks = OpenLayers.Util.extend({ │ │ │ │ + done: this.select, │ │ │ │ + click: this.select │ │ │ │ + }, this.callbacks); │ │ │ │ + this.handlerOptions = this.handlerOptions || {}; │ │ │ │ + this.layerOptions = OpenLayers.Util.applyDefaults(this.layerOptions, { │ │ │ │ + displayInLayerSwitcher: false, │ │ │ │ + tileOptions: { │ │ │ │ + maxGetUrlLength: 2048 │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.element = OpenLayers.Util.getElement(element); │ │ │ │ - this.base = base || document.location.href; │ │ │ │ + }); │ │ │ │ + if (this.sketchStyle) { │ │ │ │ + this.handlerOptions.layerOptions = OpenLayers.Util.applyDefaults( │ │ │ │ + this.handlerOptions.layerOptions, { │ │ │ │ + styleMap: new OpenLayers.StyleMap({ │ │ │ │ + "default": this.sketchStyle │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + ); │ │ │ │ } │ │ │ │ + this.handler = new handler(this, this.callbacks, this.handlerOptions); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: destroy │ │ │ │ + * Take care of things that are not handled in superclass. │ │ │ │ */ │ │ │ │ destroy: function() { │ │ │ │ - if (this.element && this.element.parentNode == this.div) { │ │ │ │ - this.div.removeChild(this.element); │ │ │ │ - this.element = null; │ │ │ │ + for (var key in this.layerCache) { │ │ │ │ + delete this.layerCache[key]; │ │ │ │ } │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.unregister('moveend', this, this.updateLink); │ │ │ │ + for (var key in this.wfsCache) { │ │ │ │ + delete this.wfsCache[key]; │ │ │ │ } │ │ │ │ - │ │ │ │ OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setMap │ │ │ │ - * Set the map property for the control. │ │ │ │ - * │ │ │ │ + * Method: coupleLayerVisiblity │ │ │ │ + * Couple the selection layer and the source layer with respect to │ │ │ │ + * layer visibility. So if the source layer is turned off, the │ │ │ │ + * selection layer is also turned off. │ │ │ │ + * │ │ │ │ + * Context: │ │ │ │ + * - {<OpenLayers.Layer>} │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * evt - {Object} │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - │ │ │ │ - //make sure we have an arg parser attached │ │ │ │ - for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ - var control = this.map.controls[i]; │ │ │ │ - if (control.CLASS_NAME == this.argParserClass.CLASS_NAME) { │ │ │ │ - │ │ │ │ - // If a permalink is added to the map, and an ArgParser already │ │ │ │ - // exists, we override the displayProjection to be the one │ │ │ │ - // on the permalink. │ │ │ │ - if (control.displayProjection != this.displayProjection) { │ │ │ │ - this.displayProjection = control.displayProjection; │ │ │ │ - } │ │ │ │ + coupleLayerVisiblity: function(evt) { │ │ │ │ + this.setVisibility(evt.object.getVisibility()); │ │ │ │ + }, │ │ │ │ │ │ │ │ - break; │ │ │ │ + /** │ │ │ │ + * Method: createSelectionLayer │ │ │ │ + * Creates a "clone" from the source layer in which the selection can │ │ │ │ + * be drawn. This ensures both the source layer and the selection are │ │ │ │ + * visible and not only the selection. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * source - {<OpenLayers.Layer.WMS>} The source layer on which the selection │ │ │ │ + * is performed. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.WMS>} A WMS layer with maxGetUrlLength configured to 2048 │ │ │ │ + * since SLD selections can easily get quite long. │ │ │ │ + */ │ │ │ │ + createSelectionLayer: function(source) { │ │ │ │ + // check if we already have a selection layer for the source layer │ │ │ │ + var selectionLayer; │ │ │ │ + if (!this.layerCache[source.id]) { │ │ │ │ + selectionLayer = new OpenLayers.Layer.WMS(source.name, │ │ │ │ + source.url, source.params, │ │ │ │ + OpenLayers.Util.applyDefaults( │ │ │ │ + this.layerOptions, │ │ │ │ + source.getOptions()) │ │ │ │ + ); │ │ │ │ + this.layerCache[source.id] = selectionLayer; │ │ │ │ + // make sure the layers are coupled wrt visibility, but only │ │ │ │ + // if they are not displayed in the layer switcher, because in │ │ │ │ + // that case the user cannot control visibility. │ │ │ │ + if (this.layerOptions.displayInLayerSwitcher === false) { │ │ │ │ + source.events.on({ │ │ │ │ + "visibilitychanged": this.coupleLayerVisiblity, │ │ │ │ + scope: selectionLayer │ │ │ │ + }); │ │ │ │ } │ │ │ │ + this.map.addLayer(selectionLayer); │ │ │ │ + } else { │ │ │ │ + selectionLayer = this.layerCache[source.id]; │ │ │ │ } │ │ │ │ - if (i == this.map.controls.length) { │ │ │ │ - this.map.addControl(new this.argParserClass({ │ │ │ │ - 'displayProjection': this.displayProjection │ │ │ │ - })); │ │ │ │ - } │ │ │ │ - │ │ │ │ + return selectionLayer; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: draw │ │ │ │ + * Method: createSLD │ │ │ │ + * Create the SLD document for the layer using the supplied filters. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.WMS>} │ │ │ │ + * filters - Array({<OpenLayers.Filter>}) The filters to be applied. │ │ │ │ + * geometryAttributes - Array({Object}) The geometry attributes of the │ │ │ │ + * layer. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * {String} The SLD document generated as a string. │ │ │ │ */ │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + createSLD: function(layer, filters, geometryAttributes) { │ │ │ │ + var sld = { │ │ │ │ + version: "1.0.0", │ │ │ │ + namedLayers: {} │ │ │ │ + }; │ │ │ │ + var layerNames = [layer.params.LAYERS].join(",").split(","); │ │ │ │ + for (var i = 0, len = layerNames.length; i < len; i++) { │ │ │ │ + var name = layerNames[i]; │ │ │ │ + sld.namedLayers[name] = { │ │ │ │ + name: name, │ │ │ │ + userStyles: [] │ │ │ │ + }; │ │ │ │ + var symbolizer = this.selectionSymbolizer; │ │ │ │ + var geometryAttribute = geometryAttributes[i]; │ │ │ │ + if (geometryAttribute.type.indexOf('Polygon') >= 0) { │ │ │ │ + symbolizer = { │ │ │ │ + Polygon: this.selectionSymbolizer['Polygon'] │ │ │ │ + }; │ │ │ │ + } else if (geometryAttribute.type.indexOf('LineString') >= 0) { │ │ │ │ + symbolizer = { │ │ │ │ + Line: this.selectionSymbolizer['Line'] │ │ │ │ + }; │ │ │ │ + } else if (geometryAttribute.type.indexOf('Point') >= 0) { │ │ │ │ + symbolizer = { │ │ │ │ + Point: this.selectionSymbolizer['Point'] │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + var filter = filters[i]; │ │ │ │ + sld.namedLayers[name].userStyles.push({ │ │ │ │ + name: 'default', │ │ │ │ + rules: [ │ │ │ │ + new OpenLayers.Rule({ │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + filter: filter, │ │ │ │ + maxScaleDenominator: layer.options.minScale │ │ │ │ + }) │ │ │ │ + ] │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + return new OpenLayers.Format.SLD({ │ │ │ │ + srsName: this.map.getProjection() │ │ │ │ + }).write(sld); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (!this.element && !this.anchor) { │ │ │ │ - this.element = document.createElement("a"); │ │ │ │ - this.element.innerHTML = OpenLayers.i18n("Permalink"); │ │ │ │ - this.element.href = ""; │ │ │ │ - this.div.appendChild(this.element); │ │ │ │ + /** │ │ │ │ + * Method: parseDescribeLayer │ │ │ │ + * Parse the SLD WMS DescribeLayer response and issue the corresponding │ │ │ │ + * WFS DescribeFeatureType request │ │ │ │ + * │ │ │ │ + * request - {XMLHttpRequest} The request object. │ │ │ │ + */ │ │ │ │ + parseDescribeLayer: function(request) { │ │ │ │ + var format = new OpenLayers.Format.WMSDescribeLayer(); │ │ │ │ + var doc = request.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = request.responseText; │ │ │ │ } │ │ │ │ - this.map.events.on({ │ │ │ │ - 'moveend': this.updateLink, │ │ │ │ - 'changelayer': this.updateLink, │ │ │ │ - 'changebaselayer': this.updateLink, │ │ │ │ + var describeLayer = format.read(doc); │ │ │ │ + var typeNames = []; │ │ │ │ + var url = null; │ │ │ │ + for (var i = 0, len = describeLayer.length; i < len; i++) { │ │ │ │ + // perform a WFS DescribeFeatureType request │ │ │ │ + if (describeLayer[i].owsType == "WFS") { │ │ │ │ + typeNames.push(describeLayer[i].typeName); │ │ │ │ + url = describeLayer[i].owsURL; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var options = { │ │ │ │ + url: url, │ │ │ │ + params: { │ │ │ │ + SERVICE: "WFS", │ │ │ │ + TYPENAME: typeNames.toString(), │ │ │ │ + REQUEST: "DescribeFeatureType", │ │ │ │ + VERSION: "1.0.0" │ │ │ │ + }, │ │ │ │ + callback: function(request) { │ │ │ │ + var format = new OpenLayers.Format.WFSDescribeFeatureType(); │ │ │ │ + var doc = request.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = request.responseText; │ │ │ │ + } │ │ │ │ + var describeFeatureType = format.read(doc); │ │ │ │ + this.control.wfsCache[this.layer.id] = describeFeatureType; │ │ │ │ + this.control._queue && this.control.applySelection(); │ │ │ │ + }, │ │ │ │ scope: this │ │ │ │ - }); │ │ │ │ - │ │ │ │ - // Make it so there is at least a link even though the map may not have │ │ │ │ - // moved yet. │ │ │ │ - this.updateLink(); │ │ │ │ - │ │ │ │ - return this.div; │ │ │ │ + }; │ │ │ │ + OpenLayers.Request.GET(options); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: updateLink │ │ │ │ + * Method: getGeometryAttributes │ │ │ │ + * Look up the geometry attributes from the WFS DescribeFeatureType response │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.WMS>} The layer for which to look up the │ │ │ │ + * geometry attributes. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * Array({Object}) Array of geometry attributes │ │ │ │ */ │ │ │ │ - updateLink: function() { │ │ │ │ - var separator = this.anchor ? '#' : '?'; │ │ │ │ - var href = this.base; │ │ │ │ - var anchor = null; │ │ │ │ - if (href.indexOf("#") != -1 && this.anchor == false) { │ │ │ │ - anchor = href.substring(href.indexOf("#"), href.length); │ │ │ │ + getGeometryAttributes: function(layer) { │ │ │ │ + var result = []; │ │ │ │ + var cache = this.wfsCache[layer.id]; │ │ │ │ + for (var i = 0, len = cache.featureTypes.length; i < len; i++) { │ │ │ │ + var typeName = cache.featureTypes[i]; │ │ │ │ + var properties = typeName.properties; │ │ │ │ + for (var j = 0, lenj = properties.length; j < lenj; j++) { │ │ │ │ + var property = properties[j]; │ │ │ │ + var type = property.type; │ │ │ │ + if ((type.indexOf('LineString') >= 0) || │ │ │ │ + (type.indexOf('GeometryAssociationType') >= 0) || │ │ │ │ + (type.indexOf('GeometryPropertyType') >= 0) || │ │ │ │ + (type.indexOf('Point') >= 0) || │ │ │ │ + (type.indexOf('Polygon') >= 0)) { │ │ │ │ + result.push(property); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - if (href.indexOf(separator) != -1) { │ │ │ │ - href = href.substring(0, href.indexOf(separator)); │ │ │ │ + return result; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the control. Activating the control will perform a SLD WMS │ │ │ │ + * DescribeLayer request followed by a WFS DescribeFeatureType request │ │ │ │ + * so that the proper symbolizers can be chosen based on the geometry │ │ │ │ + * type. │ │ │ │ + */ │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ + var layer = this.layers[i]; │ │ │ │ + if (layer && !this.wfsCache[layer.id]) { │ │ │ │ + var options = { │ │ │ │ + url: layer.url, │ │ │ │ + params: { │ │ │ │ + SERVICE: "WMS", │ │ │ │ + VERSION: layer.params.VERSION, │ │ │ │ + LAYERS: layer.params.LAYERS, │ │ │ │ + REQUEST: "DescribeLayer" │ │ │ │ + }, │ │ │ │ + callback: this.parseDescribeLayer, │ │ │ │ + scope: { │ │ │ │ + layer: layer, │ │ │ │ + control: this │ │ │ │ + } │ │ │ │ + }; │ │ │ │ + OpenLayers.Request.GET(options); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - var splits = href.split("#"); │ │ │ │ - href = splits[0] + separator + OpenLayers.Util.getParameterString(this.createParams()); │ │ │ │ - if (anchor) { │ │ │ │ - href += anchor; │ │ │ │ + return activated; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the control. If clearOnDeactivate is true, remove the │ │ │ │ + * selection layer(s). │ │ │ │ + */ │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ + var layer = this.layers[i]; │ │ │ │ + if (layer && this.clearOnDeactivate === true) { │ │ │ │ + var layerCache = this.layerCache; │ │ │ │ + var selectionLayer = layerCache[layer.id]; │ │ │ │ + if (selectionLayer) { │ │ │ │ + layer.events.un({ │ │ │ │ + "visibilitychanged": this.coupleLayerVisiblity, │ │ │ │ + scope: selectionLayer │ │ │ │ + }); │ │ │ │ + selectionLayer.destroy(); │ │ │ │ + delete layerCache[layer.id]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - if (this.anchor && !this.element) { │ │ │ │ - window.location.href = href; │ │ │ │ + return deactivated; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setLayers │ │ │ │ + * Set the layers on which the selection should be performed. Call the │ │ │ │ + * setLayers method if the layer(s) to be used change and the same │ │ │ │ + * control should be used on a new set of layers. │ │ │ │ + * If the control is already active, it will be active after the new │ │ │ │ + * set of layers is set. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layers - {Array(<OpenLayers.Layer.WMS>)} The new set of layers on which │ │ │ │ + * the selection should be performed. │ │ │ │ + */ │ │ │ │ + setLayers: function(layers) { │ │ │ │ + if (this.active) { │ │ │ │ + this.deactivate(); │ │ │ │ + this.layers = layers; │ │ │ │ + this.activate(); │ │ │ │ } else { │ │ │ │ - this.element.href = href; │ │ │ │ + this.layers = layers; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: createParams │ │ │ │ - * Creates the parameters that need to be encoded into the permalink url. │ │ │ │ - * │ │ │ │ + * Function: createFilter │ │ │ │ + * Create the filter to be used in the SLD. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * center - {<OpenLayers.LonLat>} center to encode in the permalink. │ │ │ │ - * Defaults to the current map center. │ │ │ │ - * zoom - {Integer} zoom level to encode in the permalink. Defaults to the │ │ │ │ - * current map zoom level. │ │ │ │ - * layers - {Array(<OpenLayers.Layer>)} layers to encode in the permalink. │ │ │ │ - * Defaults to the current map layers. │ │ │ │ - * │ │ │ │ + * geometryAttribute - {Object} Used to get the name of the geometry │ │ │ │ + * attribute which is needed for constructing the spatial filter. │ │ │ │ + * geometry - {<OpenLayers.Geometry>} The geometry to use. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} Hash of parameters that will be url-encoded into the │ │ │ │ - * permalink. │ │ │ │ + * {<OpenLayers.Filter.Spatial>} The spatial filter created. │ │ │ │ */ │ │ │ │ - createParams: function(center, zoom, layers) { │ │ │ │ - center = center || this.map.getCenter(); │ │ │ │ + createFilter: function(geometryAttribute, geometry) { │ │ │ │ + var filter = null; │ │ │ │ + if (this.handler instanceof OpenLayers.Handler.RegularPolygon) { │ │ │ │ + // box │ │ │ │ + if (this.handler.irregular === true) { │ │ │ │ + filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ + property: geometryAttribute.name, │ │ │ │ + value: geometry.getBounds() │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ + property: geometryAttribute.name, │ │ │ │ + value: geometry │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } else if (this.handler instanceof OpenLayers.Handler.Polygon) { │ │ │ │ + filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ + property: geometryAttribute.name, │ │ │ │ + value: geometry │ │ │ │ + }); │ │ │ │ + } else if (this.handler instanceof OpenLayers.Handler.Path) { │ │ │ │ + // if source layer is point based, use DWITHIN instead │ │ │ │ + if (geometryAttribute.type.indexOf('Point') >= 0) { │ │ │ │ + filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.DWITHIN, │ │ │ │ + property: geometryAttribute.name, │ │ │ │ + distance: this.map.getExtent().getWidth() * 0.01, │ │ │ │ + distanceUnits: this.map.getUnits(), │ │ │ │ + value: geometry │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ + property: geometryAttribute.name, │ │ │ │ + value: geometry │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } else if (this.handler instanceof OpenLayers.Handler.Click) { │ │ │ │ + if (geometryAttribute.type.indexOf('Polygon') >= 0) { │ │ │ │ + filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ + property: geometryAttribute.name, │ │ │ │ + value: geometry │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.DWITHIN, │ │ │ │ + property: geometryAttribute.name, │ │ │ │ + distance: this.map.getExtent().getWidth() * 0.01, │ │ │ │ + distanceUnits: this.map.getUnits(), │ │ │ │ + value: geometry │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return filter; │ │ │ │ + }, │ │ │ │ │ │ │ │ - var params = OpenLayers.Util.getParameters(this.base); │ │ │ │ + /** │ │ │ │ + * Method: select │ │ │ │ + * When the handler is done, use SLD_BODY on the selection layer to │ │ │ │ + * display the selection in the map. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {Object} or {<OpenLayers.Geometry>} │ │ │ │ + */ │ │ │ │ + select: function(geometry) { │ │ │ │ + this._queue = function() { │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ + var layer = this.layers[i]; │ │ │ │ + var geometryAttributes = this.getGeometryAttributes(layer); │ │ │ │ + var filters = []; │ │ │ │ + for (var j = 0, lenj = geometryAttributes.length; j < lenj; j++) { │ │ │ │ + var geometryAttribute = geometryAttributes[j]; │ │ │ │ + if (geometryAttribute !== null) { │ │ │ │ + // from the click handler we will not get an actual │ │ │ │ + // geometry so transform │ │ │ │ + if (!(geometry instanceof OpenLayers.Geometry)) { │ │ │ │ + var point = this.map.getLonLatFromPixel( │ │ │ │ + geometry.xy); │ │ │ │ + geometry = new OpenLayers.Geometry.Point( │ │ │ │ + point.lon, point.lat); │ │ │ │ + } │ │ │ │ + var filter = this.createFilter(geometryAttribute, │ │ │ │ + geometry); │ │ │ │ + if (filter !== null) { │ │ │ │ + filters.push(filter); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - // If there's still no center, map is not initialized yet. │ │ │ │ - // Break out of this function, and simply return the params from the │ │ │ │ - // base link. │ │ │ │ - if (center) { │ │ │ │ + var selectionLayer = this.createSelectionLayer(layer); │ │ │ │ │ │ │ │ - //zoom │ │ │ │ - params.zoom = zoom || this.map.getZoom(); │ │ │ │ + this.events.triggerEvent("selected", { │ │ │ │ + layer: layer, │ │ │ │ + filters: filters │ │ │ │ + }); │ │ │ │ │ │ │ │ - //lon,lat │ │ │ │ - var lat = center.lat; │ │ │ │ - var lon = center.lon; │ │ │ │ + var sld = this.createSLD(layer, filters, geometryAttributes); │ │ │ │ │ │ │ │ - if (this.displayProjection) { │ │ │ │ - var mapPosition = OpenLayers.Projection.transform({ │ │ │ │ - x: lon, │ │ │ │ - y: lat │ │ │ │ - }, │ │ │ │ - this.map.getProjectionObject(), │ │ │ │ - this.displayProjection); │ │ │ │ - lon = mapPosition.x; │ │ │ │ - lat = mapPosition.y; │ │ │ │ + selectionLayer.mergeNewParams({ │ │ │ │ + SLD_BODY: sld │ │ │ │ + }); │ │ │ │ + delete this._queue; │ │ │ │ } │ │ │ │ - params.lat = Math.round(lat * 100000) / 100000; │ │ │ │ - params.lon = Math.round(lon * 100000) / 100000; │ │ │ │ - │ │ │ │ - //layers │ │ │ │ - layers = layers || this.map.layers; │ │ │ │ - params.layers = ''; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - var layer = layers[i]; │ │ │ │ + }; │ │ │ │ + this.applySelection(); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (layer.isBaseLayer) { │ │ │ │ - params.layers += (layer == this.map.baseLayer) ? "B" : "0"; │ │ │ │ - } else { │ │ │ │ - params.layers += (layer.getVisibility()) ? "T" : "F"; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Method: applySelection │ │ │ │ + * Checks if all required wfs data is cached, and applies the selection │ │ │ │ + */ │ │ │ │ + applySelection: function() { │ │ │ │ + var canApply = true; │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ + if (!this.wfsCache[this.layers[i].id]) { │ │ │ │ + canApply = false; │ │ │ │ + break; │ │ │ │ } │ │ │ │ } │ │ │ │ - │ │ │ │ - return params; │ │ │ │ + canApply && this._queue.call(this); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Permalink" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.SLDSelect" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Measure.js │ │ │ │ + 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/Feature/Vector.js │ │ │ │ + * @requires OpenLayers/Geometry/Point.js │ │ │ │ + * @requires OpenLayers/Projection.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Measure │ │ │ │ - * Allows for drawing of features for measurements. │ │ │ │ + * 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.Measure = OpenLayers.Class(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>): │ │ │ │ - * measure - Triggered when a measurement sketch is complete. Listeners │ │ │ │ - * will receive an event with measure, units, order, and geometry │ │ │ │ - * properties. │ │ │ │ - * measurepartial - Triggered when a new point is added to the │ │ │ │ - * measurement sketch or if the <immediate> property is true and the │ │ │ │ - * measurement sketch is modified. Listeners receive an event with measure, │ │ │ │ - * units, order, and geometry. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: handlerOptions │ │ │ │ - * {Object} Used to set non-default properties on the control's handler │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: callbacks │ │ │ │ - * {Object} The functions that are sent to the handler for callback │ │ │ │ - */ │ │ │ │ - callbacks: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: displaySystem │ │ │ │ - * {String} Display system for output measurements. Supported values │ │ │ │ - * are 'english', 'metric', and 'geographic'. Default is 'metric'. │ │ │ │ - */ │ │ │ │ - displaySystem: 'metric', │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: geodesic │ │ │ │ - * {Boolean} Calculate geodesic metrics instead of planar metrics. This │ │ │ │ - * requires that geometries can be transformed into Geographic/WGS84 │ │ │ │ - * (if that is not already the map projection). Default is false. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - geodesic: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: displaySystemUnits │ │ │ │ - * {Object} Units for various measurement systems. Values are arrays │ │ │ │ - * of unit abbreviations (from OpenLayers.INCHES_PER_UNIT) in decreasing │ │ │ │ - * order of length. │ │ │ │ + * Property: geolocation │ │ │ │ + * {Object} The geolocation engine, as a property to be possibly mocked. │ │ │ │ + * This is set lazily to avoid a memory leak in IE9. │ │ │ │ */ │ │ │ │ - displaySystemUnits: { │ │ │ │ - geographic: ['dd'], │ │ │ │ - english: ['mi', 'ft', 'in'], │ │ │ │ - metric: ['km', 'm'] │ │ │ │ - }, │ │ │ │ + geolocation: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: delay │ │ │ │ - * {Number} Number of milliseconds between clicks before the event is │ │ │ │ - * considered a double-click. The "measurepartial" event will not │ │ │ │ - * be triggered if the sketch is completed within this time. This │ │ │ │ - * is required for IE where creating a browser reflow (if a listener │ │ │ │ - * is modifying the DOM by displaying the measurement values) messes │ │ │ │ - * with the dblclick listener in the sketch handler. │ │ │ │ + * Property: available │ │ │ │ + * {Boolean} The navigator.geolocation object is available. │ │ │ │ */ │ │ │ │ - partialDelay: 300, │ │ │ │ + available: ('geolocation' in navigator), │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: delayedTrigger │ │ │ │ - * {Number} Timeout id of trigger for measurepartial. │ │ │ │ + * APIProperty: bind │ │ │ │ + * {Boolean} If true, map center will be set on location update. │ │ │ │ */ │ │ │ │ - delayedTrigger: null, │ │ │ │ + bind: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: persist │ │ │ │ - * {Boolean} Keep the temporary measurement sketch drawn after the │ │ │ │ - * measurement is complete. The geometry will persist until a new │ │ │ │ - * measurement is started, the control is deactivated, or <cancel> is │ │ │ │ - * called. │ │ │ │ + * APIProperty: watch │ │ │ │ + * {Boolean} If true, position will be update regularly. │ │ │ │ */ │ │ │ │ - persist: false, │ │ │ │ + watch: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: immediate │ │ │ │ - * {Boolean} Activates the immediate measurement so that the "measurepartial" │ │ │ │ - * event is also fired once the measurement sketch is modified. │ │ │ │ - * Default is 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. │ │ │ │ */ │ │ │ │ - immediate: false, │ │ │ │ + geolocationOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.Measure │ │ │ │ + * Constructor: OpenLayers.Control.Geolocate │ │ │ │ + * Create a new control to deal with browser geolocation API │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * handler - {<OpenLayers.Handler>} │ │ │ │ - * options - {Object} │ │ │ │ - */ │ │ │ │ - initialize: function(handler, options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - var callbacks = { │ │ │ │ - done: this.measureComplete, │ │ │ │ - point: this.measurePartial │ │ │ │ - }; │ │ │ │ - if (this.immediate) { │ │ │ │ - callbacks.modify = this.measureImmediate; │ │ │ │ - } │ │ │ │ - this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks); │ │ │ │ - │ │ │ │ - // let the handler options override, so old code that passes 'persist' │ │ │ │ - // directly to the handler does not need an update │ │ │ │ - this.handlerOptions = OpenLayers.Util.extend({ │ │ │ │ - persist: this.persist │ │ │ │ - }, this.handlerOptions); │ │ │ │ - this.handler = new handler(this, this.callbacks, this.handlerOptions); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - */ │ │ │ │ - deactivate: function() { │ │ │ │ - this.cancelDelay(); │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: cancel │ │ │ │ - * Stop the control from measuring. If <persist> is true, the temporary │ │ │ │ - * sketch will be erased. │ │ │ │ */ │ │ │ │ - cancel: function() { │ │ │ │ - this.cancelDelay(); │ │ │ │ - this.handler.cancel(); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setImmediate │ │ │ │ - * Sets the <immediate> property. Changes the activity of immediate │ │ │ │ - * measurement. │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - setImmediate: function(immediate) { │ │ │ │ - this.immediate = immediate; │ │ │ │ - if (this.immediate) { │ │ │ │ - this.callbacks.modify = this.measureImmediate; │ │ │ │ - } else { │ │ │ │ - delete this.callbacks.modify; │ │ │ │ - } │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: updateHandler │ │ │ │ + * Method: activate │ │ │ │ + * Activates the control. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * handler - {Function} One of the sketch handler constructors. │ │ │ │ - * options - {Object} Options for the handler. │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The control was effectively activated. │ │ │ │ */ │ │ │ │ - updateHandler: function(handler, options) { │ │ │ │ - var active = this.active; │ │ │ │ - if (active) { │ │ │ │ - this.deactivate(); │ │ │ │ + activate: function() { │ │ │ │ + if (this.available && !this.geolocation) { │ │ │ │ + // set lazily to avoid IE9 memory leak │ │ │ │ + this.geolocation = navigator.geolocation; │ │ │ │ } │ │ │ │ - this.handler = new handler(this, this.callbacks, options); │ │ │ │ - if (active) { │ │ │ │ - this.activate(); │ │ │ │ + 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: measureComplete │ │ │ │ - * Called when the measurement sketch is done. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - */ │ │ │ │ - measureComplete: function(geometry) { │ │ │ │ - this.cancelDelay(); │ │ │ │ - this.measure(geometry, "measure"); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: measurePartial │ │ │ │ - * Called each time a new point is added to the measurement sketch. │ │ │ │ + * Method: deactivate │ │ │ │ + * Deactivates the control. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * point - {<OpenLayers.Geometry.Point>} The last point added. │ │ │ │ - * geometry - {<OpenLayers.Geometry>} The sketch geometry. │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The control was effectively deactivated. │ │ │ │ */ │ │ │ │ - measurePartial: function(point, geometry) { │ │ │ │ - this.cancelDelay(); │ │ │ │ - geometry = geometry.clone(); │ │ │ │ - // when we're wating for a dblclick, we have to trigger measurepartial │ │ │ │ - // after some delay to deal with reflow issues in IE │ │ │ │ - if (this.handler.freehandMode(this.handler.evt)) { │ │ │ │ - // no dblclick in freehand mode │ │ │ │ - this.measure(geometry, "measurepartial"); │ │ │ │ - } else { │ │ │ │ - this.delayedTrigger = window.setTimeout( │ │ │ │ - OpenLayers.Function.bind(function() { │ │ │ │ - this.delayedTrigger = null; │ │ │ │ - this.measure(geometry, "measurepartial"); │ │ │ │ - }, this), │ │ │ │ - this.partialDelay │ │ │ │ - ); │ │ │ │ + deactivate: function() { │ │ │ │ + if (this.active && this.watchId !== null) { │ │ │ │ + this.geolocation.clearWatch(this.watchId); │ │ │ │ } │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply( │ │ │ │ + this, arguments │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: measureImmediate │ │ │ │ - * Called each time the measurement sketch is modified. │ │ │ │ + * Method: geolocate │ │ │ │ + * Activates the control. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * point - {<OpenLayers.Geometry.Point>} The point at the mouse position. │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The sketch feature. │ │ │ │ - * drawing - {Boolean} Indicates whether we're currently drawing. │ │ │ │ */ │ │ │ │ - measureImmediate: function(point, feature, drawing) { │ │ │ │ - if (drawing && !this.handler.freehandMode(this.handler.evt)) { │ │ │ │ - this.cancelDelay(); │ │ │ │ - this.measure(feature.geometry, "measurepartial"); │ │ │ │ + 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 │ │ │ │ + ) │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: cancelDelay │ │ │ │ - * Cancels the delay measurement that measurePartial began. │ │ │ │ + * APIMethod: getCurrentLocation │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Returns true if a event will be fired (successfull │ │ │ │ + * registration) │ │ │ │ */ │ │ │ │ - cancelDelay: function() { │ │ │ │ - if (this.delayedTrigger !== null) { │ │ │ │ - window.clearTimeout(this.delayedTrigger); │ │ │ │ - this.delayedTrigger = null; │ │ │ │ + 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: measure │ │ │ │ + * Method: failure │ │ │ │ + * method called on browser's geolocation failure │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * eventType - {String} │ │ │ │ */ │ │ │ │ - measure: function(geometry, eventType) { │ │ │ │ - var stat, order; │ │ │ │ - if (geometry.CLASS_NAME.indexOf('LineString') > -1) { │ │ │ │ - stat = this.getBestLength(geometry); │ │ │ │ - order = 1; │ │ │ │ - } else { │ │ │ │ - stat = this.getBestArea(geometry); │ │ │ │ - order = 2; │ │ │ │ - } │ │ │ │ - this.events.triggerEvent(eventType, { │ │ │ │ - measure: stat[0], │ │ │ │ - units: stat[1], │ │ │ │ - order: order, │ │ │ │ - geometry: geometry │ │ │ │ + failure: function(error) { │ │ │ │ + this.events.triggerEvent("locationfailed", { │ │ │ │ + error: error │ │ │ │ }); │ │ │ │ }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Geolocate" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: getBestArea │ │ │ │ - * Based on the <displaySystem> returns the area of a geometry. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * 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: │ │ │ │ - * {Array([Float, String])} Returns a two item array containing the │ │ │ │ - * area and the units abbreviation. │ │ │ │ + * {DOMElement} A reference to the DOMElement containing the zoom links. │ │ │ │ */ │ │ │ │ - getBestArea: function(geometry) { │ │ │ │ - var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ - var unit, area; │ │ │ │ - for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ - unit = units[i]; │ │ │ │ - area = this.getArea(geometry, unit); │ │ │ │ - if (area > 1) { │ │ │ │ - break; │ │ │ │ - } │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - return [area, unit]; │ │ │ │ + eventsInstance.register("buttonclick", this, this.onZoomClick); │ │ │ │ + │ │ │ │ + this.zoomInLink = zoomIn; │ │ │ │ + this.zoomOutLink = zoomOut; │ │ │ │ + return div; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getArea │ │ │ │ - * │ │ │ │ + * Method: getOrCreateLinks │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * units - {String} Unit abbreviation │ │ │ │ + * el - {DOMElement} │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Float} The geometry area in the given units. │ │ │ │ + * Return: │ │ │ │ + * {Object} Object with zoomIn and zoomOut properties referencing links. │ │ │ │ */ │ │ │ │ - getArea: function(geometry, units) { │ │ │ │ - var area, geomUnits; │ │ │ │ - if (this.geodesic) { │ │ │ │ - area = geometry.getGeodesicArea(this.map.getProjectionObject()); │ │ │ │ - geomUnits = "m"; │ │ │ │ - } else { │ │ │ │ - area = geometry.getArea(); │ │ │ │ - geomUnits = this.map.getUnits(); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ - if (inPerDisplayUnit) { │ │ │ │ - var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ - area *= Math.pow((inPerMapUnit / inPerDisplayUnit), 2); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - return area; │ │ │ │ + OpenLayers.Element.addClass(zoomOut, "olButton"); │ │ │ │ + return { │ │ │ │ + zoomIn: zoomIn, │ │ │ │ + zoomOut: zoomOut │ │ │ │ + }; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getBestLength │ │ │ │ - * Based on the <displaySystem> returns the length of a geometry. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array([Float, String])} Returns a two item array containing the │ │ │ │ - * length and the units abbreviation. │ │ │ │ + * Method: onZoomClick │ │ │ │ + * Called when zoomin/out link is clicked. │ │ │ │ */ │ │ │ │ - getBestLength: function(geometry) { │ │ │ │ - var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ - var unit, length; │ │ │ │ - for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ - unit = units[i]; │ │ │ │ - length = this.getLength(geometry, unit); │ │ │ │ - if (length > 1) { │ │ │ │ - break; │ │ │ │ - } │ │ │ │ + onZoomClick: function(evt) { │ │ │ │ + var button = evt.buttonElement; │ │ │ │ + if (button === this.zoomInLink) { │ │ │ │ + this.map.zoomIn(); │ │ │ │ + } else if (button === this.zoomOutLink) { │ │ │ │ + this.map.zoomOut(); │ │ │ │ } │ │ │ │ - return [length, unit]; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getLength │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * units - {String} Unit abbreviation │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Float} The geometry length in the given units. │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + * Clean up. │ │ │ │ */ │ │ │ │ - getLength: function(geometry, units) { │ │ │ │ - var length, geomUnits; │ │ │ │ - if (this.geodesic) { │ │ │ │ - length = geometry.getGeodesicLength(this.map.getProjectionObject()); │ │ │ │ - geomUnits = "m"; │ │ │ │ - } else { │ │ │ │ - length = geometry.getLength(); │ │ │ │ - geomUnits = this.map.getUnits(); │ │ │ │ - } │ │ │ │ - var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ - if (inPerDisplayUnit) { │ │ │ │ - var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ - length *= (inPerMapUnit / inPerDisplayUnit); │ │ │ │ + destroy: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.unregister("buttonclick", this, this.onZoomClick); │ │ │ │ } │ │ │ │ - return length; │ │ │ │ + delete this.zoomInLink; │ │ │ │ + delete this.zoomOutLink; │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Measure" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Zoom" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Handler/Box.js │ │ │ │ + OpenLayers/Control/UTFGrid.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/Handler/Drag.js │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Handler/Hover.js │ │ │ │ + * @requires OpenLayers/Handler/Click.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Handler.Box │ │ │ │ - * Handler for dragging a rectangle across the map. Box is displayed │ │ │ │ - * on mouse down, moves on mouse move, and is finished on mouse up. │ │ │ │ + * Class: OpenLayers.Control.UTFGrid │ │ │ │ + * │ │ │ │ + * This Control provides behavior associated with UTFGrid Layers. │ │ │ │ + * These 'hit grids' provide underlying feature attributes without │ │ │ │ + * calling the server (again). This control allows Mousemove, Hovering │ │ │ │ + * and Click events to trigger callbacks that use the attributes in │ │ │ │ + * whatever way you need. │ │ │ │ + * │ │ │ │ + * The most common example may be a UTFGrid layer containing feature │ │ │ │ + * attributes that are displayed in a div as you mouseover. │ │ │ │ + * │ │ │ │ + * Example Code: │ │ │ │ + * │ │ │ │ + * (start code) │ │ │ │ + * var world_utfgrid = new OpenLayers.Layer.UTFGrid( │ │ │ │ + * 'UTFGrid Layer', │ │ │ │ + * "http://tiles/world_utfgrid/${z}/${x}/${y}.json" │ │ │ │ + * ); │ │ │ │ + * map.addLayer(world_utfgrid); │ │ │ │ + * │ │ │ │ + * var control = new OpenLayers.Control.UTFGrid({ │ │ │ │ + * layers: [world_utfgrid], │ │ │ │ + * handlerMode: 'move', │ │ │ │ + * callback: function(infoLookup) { │ │ │ │ + * // do something with returned data │ │ │ │ + * │ │ │ │ + * } │ │ │ │ + * }) │ │ │ │ + * (end code) │ │ │ │ + * │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Handler> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ +OpenLayers.Control.UTFGrid = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: autoActivate │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * true. │ │ │ │ + */ │ │ │ │ + autoActivate: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: dragHandler │ │ │ │ - * {<OpenLayers.Handler.Drag>} │ │ │ │ + * APIProperty: Layers │ │ │ │ + * List of layers to consider. Must be Layer.UTFGrids │ │ │ │ + * `null` is the default indicating all UTFGrid Layers are queried. │ │ │ │ + * {Array} <OpenLayers.Layer.UTFGrid> │ │ │ │ */ │ │ │ │ - dragHandler: null, │ │ │ │ + layers: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: boxDivClassName │ │ │ │ - * {String} The CSS class to use for drawing the box. Default is │ │ │ │ - * olHandlerBoxZoomBox │ │ │ │ + /* Property: defaultHandlerOptions │ │ │ │ + * The default opts passed to the handler constructors │ │ │ │ */ │ │ │ │ - boxDivClassName: 'olHandlerBoxZoomBox', │ │ │ │ + defaultHandlerOptions: { │ │ │ │ + 'delay': 300, │ │ │ │ + 'pixelTolerance': 4, │ │ │ │ + 'stopMove': false, │ │ │ │ + 'single': true, │ │ │ │ + 'double': false, │ │ │ │ + 'stopSingle': false, │ │ │ │ + 'stopDouble': false │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: boxOffsets │ │ │ │ - * {Object} Caches box offsets from css. This is used by the getBoxOffsets │ │ │ │ - * method. │ │ │ │ + /* APIProperty: handlerMode │ │ │ │ + * Defaults to 'click'. Can be 'hover' or 'move'. │ │ │ │ */ │ │ │ │ - boxOffsets: null, │ │ │ │ + handlerMode: 'click', │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Handler.Box │ │ │ │ + * APIMethod: setHandler │ │ │ │ + * sets this.handlerMode and calls resetHandler() │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * control - {<OpenLayers.Control>} │ │ │ │ - * callbacks - {Object} An object with a properties whose values are │ │ │ │ - * functions. Various callbacks described below. │ │ │ │ - * options - {Object} │ │ │ │ - * │ │ │ │ - * Named callbacks: │ │ │ │ - * start - Called when the box drag operation starts. │ │ │ │ - * done - Called when the box drag operation is finished. │ │ │ │ - * The callback should expect to receive a single argument, the box │ │ │ │ - * bounds or a pixel. If the box dragging didn't span more than a 5 │ │ │ │ - * pixel distance, a pixel will be returned instead of a bounds object. │ │ │ │ + * hm - {String} Handler Mode string; 'click', 'hover' or 'move'. │ │ │ │ */ │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ - this.dragHandler = new OpenLayers.Handler.Drag( │ │ │ │ - this, { │ │ │ │ - down: this.startBox, │ │ │ │ - move: this.moveBox, │ │ │ │ - out: this.removeBox, │ │ │ │ - up: this.endBox │ │ │ │ - }, { │ │ │ │ - keyMask: this.keyMask │ │ │ │ - } │ │ │ │ - ); │ │ │ │ + setHandler: function(hm) { │ │ │ │ + this.handlerMode = hm; │ │ │ │ + this.resetHandler(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroy │ │ │ │ + * Method: resetHandler │ │ │ │ + * Deactivates the old hanlder and creates a new │ │ │ │ + * <OpenLayers.Handler> based on the mode specified in │ │ │ │ + * this.handlerMode │ │ │ │ + * │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ - if (this.dragHandler) { │ │ │ │ - this.dragHandler.destroy(); │ │ │ │ - this.dragHandler = null; │ │ │ │ + resetHandler: function() { │ │ │ │ + if (this.handler) { │ │ │ │ + this.handler.deactivate(); │ │ │ │ + this.handler.destroy(); │ │ │ │ + this.handler = null; │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Handler.prototype.setMap.apply(this, arguments); │ │ │ │ - if (this.dragHandler) { │ │ │ │ - this.dragHandler.setMap(map); │ │ │ │ + if (this.handlerMode == 'hover') { │ │ │ │ + // Handle this event on hover │ │ │ │ + this.handler = new OpenLayers.Handler.Hover( │ │ │ │ + this, { │ │ │ │ + 'pause': this.handleEvent, │ │ │ │ + 'move': this.reset │ │ │ │ + }, │ │ │ │ + this.handlerOptions │ │ │ │ + ); │ │ │ │ + } else if (this.handlerMode == 'click') { │ │ │ │ + // Handle this event on click │ │ │ │ + this.handler = new OpenLayers.Handler.Click( │ │ │ │ + this, { │ │ │ │ + 'click': this.handleEvent │ │ │ │ + }, this.handlerOptions │ │ │ │ + ); │ │ │ │ + } else if (this.handlerMode == 'move') { │ │ │ │ + this.handler = new OpenLayers.Handler.Hover( │ │ │ │ + this, │ │ │ │ + // Handle this event while hovering OR moving │ │ │ │ + { │ │ │ │ + 'pause': this.handleEvent, │ │ │ │ + 'move': this.handleEvent │ │ │ │ + }, │ │ │ │ + this.handlerOptions │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (this.handler) { │ │ │ │ + return true; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: startBox │ │ │ │ + * Constructor: <OpenLayers.Control.UTFGrid> │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * xy - {<OpenLayers.Pixel>} │ │ │ │ - */ │ │ │ │ - startBox: function(xy) { │ │ │ │ - this.callback("start", []); │ │ │ │ - this.zoomBox = OpenLayers.Util.createDiv('zoomBox', { │ │ │ │ - x: -9999, │ │ │ │ - y: -9999 │ │ │ │ - }); │ │ │ │ - this.zoomBox.className = this.boxDivClassName; │ │ │ │ - this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1; │ │ │ │ - │ │ │ │ - this.map.viewPortDiv.appendChild(this.zoomBox); │ │ │ │ - │ │ │ │ - OpenLayers.Element.addClass( │ │ │ │ - this.map.viewPortDiv, "olDrawBox" │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: moveBox │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ - moveBox: function(xy) { │ │ │ │ - var startX = this.dragHandler.start.x; │ │ │ │ - var startY = this.dragHandler.start.y; │ │ │ │ - var deltaX = Math.abs(startX - xy.x); │ │ │ │ - var deltaY = Math.abs(startY - xy.y); │ │ │ │ - │ │ │ │ - var offset = this.getBoxOffsets(); │ │ │ │ - this.zoomBox.style.width = (deltaX + offset.width + 1) + "px"; │ │ │ │ - this.zoomBox.style.height = (deltaY + offset.height + 1) + "px"; │ │ │ │ - this.zoomBox.style.left = (xy.x < startX ? │ │ │ │ - startX - deltaX - offset.left : startX - offset.left) + "px"; │ │ │ │ - this.zoomBox.style.top = (xy.y < startY ? │ │ │ │ - startY - deltaY - offset.top : startY - offset.top) + "px"; │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + options.handlerOptions = options.handlerOptions || this.defaultHandlerOptions; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.resetHandler(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: endBox │ │ │ │ + * Method: handleEvent │ │ │ │ + * Internal method called when specified event is triggered. │ │ │ │ + * │ │ │ │ + * This method does several things: │ │ │ │ + * │ │ │ │ + * Gets the lonLat of the event. │ │ │ │ + * │ │ │ │ + * Loops through the appropriate hit grid layers and gathers the attributes. │ │ │ │ + * │ │ │ │ + * Passes the attributes to the callback │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ */ │ │ │ │ - endBox: function(end) { │ │ │ │ - var result; │ │ │ │ - if (Math.abs(this.dragHandler.start.x - end.x) > 5 || │ │ │ │ - Math.abs(this.dragHandler.start.y - end.y) > 5) { │ │ │ │ - var start = this.dragHandler.start; │ │ │ │ - var top = Math.min(start.y, end.y); │ │ │ │ - var bottom = Math.max(start.y, end.y); │ │ │ │ - var left = Math.min(start.x, end.x); │ │ │ │ - var right = Math.max(start.x, end.x); │ │ │ │ - result = new OpenLayers.Bounds(left, bottom, right, top); │ │ │ │ - } else { │ │ │ │ - result = this.dragHandler.start.clone(); // i.e. OL.Pixel │ │ │ │ + handleEvent: function(evt) { │ │ │ │ + if (evt == null) { │ │ │ │ + this.reset(); │ │ │ │ + return; │ │ │ │ } │ │ │ │ - this.removeBox(); │ │ │ │ - │ │ │ │ - this.callback("done", [result]); │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: removeBox │ │ │ │ - * Remove the zoombox from the screen and nullify our reference to it. │ │ │ │ - */ │ │ │ │ - removeBox: function() { │ │ │ │ - this.map.viewPortDiv.removeChild(this.zoomBox); │ │ │ │ - this.zoomBox = null; │ │ │ │ - this.boxOffsets = null; │ │ │ │ - OpenLayers.Element.removeClass( │ │ │ │ - this.map.viewPortDiv, "olDrawBox" │ │ │ │ - ); │ │ │ │ + var lonLat = this.map.getLonLatFromPixel(evt.xy); │ │ │ │ + if (!lonLat) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ │ │ │ │ + var layers = this.findLayers(); │ │ │ │ + if (layers.length > 0) { │ │ │ │ + var infoLookup = {}; │ │ │ │ + var layer, idx; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + layer = layers[i]; │ │ │ │ + idx = OpenLayers.Util.indexOf(this.map.layers, layer); │ │ │ │ + infoLookup[idx] = layer.getFeatureInfo(lonLat); │ │ │ │ + } │ │ │ │ + this.callback(infoLookup, lonLat, evt.xy); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ + * APIMethod: callback │ │ │ │ + * Function to be called when a mouse event corresponds with a location that │ │ │ │ + * includes data in one of the configured UTFGrid layers. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * infoLookup - {Object} Keys of this object are layer indexes and can be │ │ │ │ + * used to resolve a layer in the map.layers array. The structure of │ │ │ │ + * the property values depend on the data included in the underlying │ │ │ │ + * UTFGrid and may be any valid JSON type. │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.dragHandler.activate(); │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ + callback: function(infoLookup) { │ │ │ │ + // to be provided in the constructor │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ + * Method: reset │ │ │ │ + * Calls the callback with null. │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - if (this.dragHandler.deactivate()) { │ │ │ │ - if (this.zoomBox) { │ │ │ │ - this.removeBox(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ + reset: function(evt) { │ │ │ │ + this.callback(null); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getBoxOffsets │ │ │ │ - * Determines border offsets for a box, according to the box model. │ │ │ │ - * │ │ │ │ + * Method: findLayers │ │ │ │ + * Internal method to get the layers, independent of whether we are │ │ │ │ + * inspecting the map or using a client-provided array │ │ │ │ + * │ │ │ │ + * The default value of this.layers is null; this causes the │ │ │ │ + * findLayers method to return ALL UTFGrid layers encountered. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * None │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} an object with the following offsets: │ │ │ │ - * - left │ │ │ │ - * - right │ │ │ │ - * - top │ │ │ │ - * - bottom │ │ │ │ - * - width │ │ │ │ - * - height │ │ │ │ + * {Array} Layers to handle on each event │ │ │ │ */ │ │ │ │ - getBoxOffsets: function() { │ │ │ │ - if (!this.boxOffsets) { │ │ │ │ - // Determine the box model. If the testDiv's clientWidth is 3, then │ │ │ │ - // the borders are outside and we are dealing with the w3c box │ │ │ │ - // model. Otherwise, the browser uses the traditional box model and │ │ │ │ - // the borders are inside the box bounds, leaving us with a │ │ │ │ - // clientWidth of 1. │ │ │ │ - var testDiv = document.createElement("div"); │ │ │ │ - //testDiv.style.visibility = "hidden"; │ │ │ │ - testDiv.style.position = "absolute"; │ │ │ │ - testDiv.style.border = "1px solid black"; │ │ │ │ - testDiv.style.width = "3px"; │ │ │ │ - document.body.appendChild(testDiv); │ │ │ │ - var w3cBoxModel = testDiv.clientWidth == 3; │ │ │ │ - document.body.removeChild(testDiv); │ │ │ │ - │ │ │ │ - var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ - "border-left-width")); │ │ │ │ - var right = parseInt(OpenLayers.Element.getStyle( │ │ │ │ - this.zoomBox, "border-right-width")); │ │ │ │ - var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ - "border-top-width")); │ │ │ │ - var bottom = parseInt(OpenLayers.Element.getStyle( │ │ │ │ - this.zoomBox, "border-bottom-width")); │ │ │ │ - this.boxOffsets = { │ │ │ │ - left: left, │ │ │ │ - right: right, │ │ │ │ - top: top, │ │ │ │ - bottom: bottom, │ │ │ │ - width: w3cBoxModel === false ? left + right : 0, │ │ │ │ - height: w3cBoxModel === false ? top + bottom : 0 │ │ │ │ - }; │ │ │ │ + findLayers: function() { │ │ │ │ + var candidates = this.layers || this.map.layers; │ │ │ │ + var layers = []; │ │ │ │ + var layer; │ │ │ │ + for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ + layer = candidates[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.UTFGrid) { │ │ │ │ + layers.push(layer); │ │ │ │ + } │ │ │ │ } │ │ │ │ - return this.boxOffsets; │ │ │ │ + return layers; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Box" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.UTFGrid" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Control/ZoomBox.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ @@ -57611,450 +61906,14 @@ │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Control.ZoomBox" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - 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/Handler/MouseWheel.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.MouseWheel │ │ │ │ - * Handler for wheel up/down events. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Handler> │ │ │ │ - */ │ │ │ │ -OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - /** │ │ │ │ - * Property: wheelListener │ │ │ │ - * {function} │ │ │ │ - */ │ │ │ │ - wheelListener: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: interval │ │ │ │ - * {Integer} In order to increase server performance, an interval (in │ │ │ │ - * milliseconds) can be set to reduce the number of up/down events │ │ │ │ - * called. If set, a new up/down event will not be set until the │ │ │ │ - * interval has passed. │ │ │ │ - * Defaults to 0, meaning no interval. │ │ │ │ - */ │ │ │ │ - interval: 0, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: maxDelta │ │ │ │ - * {Integer} Maximum delta to collect before breaking from the current │ │ │ │ - * interval. In cumulative mode, this also limits the maximum delta │ │ │ │ - * returned from the handler. Default is Number.POSITIVE_INFINITY. │ │ │ │ - */ │ │ │ │ - maxDelta: Number.POSITIVE_INFINITY, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: delta │ │ │ │ - * {Integer} When interval is set, delta collects the mousewheel z-deltas │ │ │ │ - * of the events that occur within the interval. │ │ │ │ - * See also the cumulative option │ │ │ │ - */ │ │ │ │ - delta: 0, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: cumulative │ │ │ │ - * {Boolean} When interval is set: true to collect all the mousewheel │ │ │ │ - * z-deltas, false to only record the delta direction (positive or │ │ │ │ - * negative) │ │ │ │ - */ │ │ │ │ - cumulative: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Handler.MouseWheel │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * control - {<OpenLayers.Control>} │ │ │ │ - * 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 point geometry. │ │ │ │ - * options - {Object} │ │ │ │ - */ │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ - this.wheelListener = OpenLayers.Function.bindAsEventListener( │ │ │ │ - this.onWheelEvent, this │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ - this.wheelListener = null; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/ │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: onWheelEvent │ │ │ │ - * Catch the wheel event and handle it xbrowserly │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {Event} │ │ │ │ - */ │ │ │ │ - onWheelEvent: function(e) { │ │ │ │ - │ │ │ │ - // make sure we have a map and check keyboard modifiers │ │ │ │ - if (!this.map || !this.checkModifiers(e)) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // Ride up the element's DOM hierarchy to determine if it or any of │ │ │ │ - // its ancestors was: │ │ │ │ - // * specifically marked as scrollable (CSS overflow property) │ │ │ │ - // * one of our layer divs or a div marked as scrollable │ │ │ │ - // ('olScrollable' CSS class) │ │ │ │ - // * the map div │ │ │ │ - // │ │ │ │ - var overScrollableDiv = false; │ │ │ │ - var allowScroll = false; │ │ │ │ - var overMapDiv = false; │ │ │ │ - │ │ │ │ - var elem = OpenLayers.Event.element(e); │ │ │ │ - while ((elem != null) && !overMapDiv && !overScrollableDiv) { │ │ │ │ - │ │ │ │ - if (!overScrollableDiv) { │ │ │ │ - try { │ │ │ │ - var overflow; │ │ │ │ - if (elem.currentStyle) { │ │ │ │ - overflow = elem.currentStyle["overflow"]; │ │ │ │ - } else { │ │ │ │ - var style = │ │ │ │ - document.defaultView.getComputedStyle(elem, null); │ │ │ │ - overflow = style.getPropertyValue("overflow"); │ │ │ │ - } │ │ │ │ - overScrollableDiv = (overflow && │ │ │ │ - (overflow == "auto") || (overflow == "scroll")); │ │ │ │ - } catch (err) { │ │ │ │ - //sometimes when scrolling in a popup, this causes │ │ │ │ - // obscure browser error │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (!allowScroll) { │ │ │ │ - allowScroll = OpenLayers.Element.hasClass(elem, 'olScrollable'); │ │ │ │ - if (!allowScroll) { │ │ │ │ - for (var i = 0, len = this.map.layers.length; i < len; i++) { │ │ │ │ - // Are we in the layer div? Note that we have two cases │ │ │ │ - // here: one is to catch EventPane layers, which have a │ │ │ │ - // pane above the layer (layer.pane) │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - if (elem == layer.div || elem == layer.pane) { │ │ │ │ - allowScroll = true; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - overMapDiv = (elem == this.map.div); │ │ │ │ - │ │ │ │ - elem = elem.parentNode; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // Logic below is the following: │ │ │ │ - // │ │ │ │ - // If we are over a scrollable div or not over the map div: │ │ │ │ - // * do nothing (let the browser handle scrolling) │ │ │ │ - // │ │ │ │ - // otherwise │ │ │ │ - // │ │ │ │ - // If we are over the layer div or a 'olScrollable' div: │ │ │ │ - // * zoom/in out │ │ │ │ - // then │ │ │ │ - // * kill event (so as not to also scroll the page after zooming) │ │ │ │ - // │ │ │ │ - // otherwise │ │ │ │ - // │ │ │ │ - // Kill the event (dont scroll the page if we wheel over the │ │ │ │ - // layerswitcher or the pan/zoom control) │ │ │ │ - // │ │ │ │ - if (!overScrollableDiv && overMapDiv) { │ │ │ │ - if (allowScroll) { │ │ │ │ - var delta = 0; │ │ │ │ - │ │ │ │ - if (e.wheelDelta) { │ │ │ │ - delta = e.wheelDelta; │ │ │ │ - if (delta % 160 === 0) { │ │ │ │ - // opera have steps of 160 instead of 120 │ │ │ │ - delta = delta * 0.75; │ │ │ │ - } │ │ │ │ - delta = delta / 120; │ │ │ │ - } else if (e.detail) { │ │ │ │ - // detail in Firefox on OS X is 1/3 of Windows │ │ │ │ - // so force delta 1 / -1 │ │ │ │ - delta = -(e.detail / Math.abs(e.detail)); │ │ │ │ - } │ │ │ │ - this.delta += delta; │ │ │ │ - │ │ │ │ - window.clearTimeout(this._timeoutId); │ │ │ │ - if (this.interval && Math.abs(this.delta) < this.maxDelta) { │ │ │ │ - // store e because window.event might change during delay │ │ │ │ - var evt = OpenLayers.Util.extend({}, e); │ │ │ │ - this._timeoutId = window.setTimeout( │ │ │ │ - OpenLayers.Function.bind(function() { │ │ │ │ - this.wheelZoom(evt); │ │ │ │ - }, this), │ │ │ │ - this.interval │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - this.wheelZoom(e); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - OpenLayers.Event.stop(e); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: wheelZoom │ │ │ │ - * Given the wheel event, we carry out the appropriate zooming in or out, │ │ │ │ - * based on the 'wheelDelta' or 'detail' property of the event. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {Event} │ │ │ │ - */ │ │ │ │ - wheelZoom: function(e) { │ │ │ │ - var delta = this.delta; │ │ │ │ - this.delta = 0; │ │ │ │ - │ │ │ │ - if (delta) { │ │ │ │ - e.xy = this.map.events.getMousePosition(e); │ │ │ │ - if (delta < 0) { │ │ │ │ - this.callback("down", │ │ │ │ - [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]); │ │ │ │ - } else { │ │ │ │ - this.callback("up", │ │ │ │ - [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: activate │ │ │ │ - */ │ │ │ │ - activate: function(evt) { │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - //register mousewheel events specifically on the window and document │ │ │ │ - var wheelListener = this.wheelListener; │ │ │ │ - OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener); │ │ │ │ - OpenLayers.Event.observe(window, "mousewheel", wheelListener); │ │ │ │ - OpenLayers.Event.observe(document, "mousewheel", wheelListener); │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: deactivate │ │ │ │ - */ │ │ │ │ - deactivate: function(evt) { │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - // unregister mousewheel events specifically on the window and document │ │ │ │ - var wheelListener = this.wheelListener; │ │ │ │ - OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener); │ │ │ │ - OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener); │ │ │ │ - OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener); │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.MouseWheel" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ OpenLayers/Control/Navigation.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. */ │ │ │ │ @@ -58463,14 +62322,2352 @@ │ │ │ │ } │ │ │ │ return div; │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Control.NavToolbar" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ + OpenLayers/Format/WMSGetFeatureInfo.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.WMSGetFeatureInfo │ │ │ │ + * Class to read GetFeatureInfo responses from Web Mapping Services │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: layerIdentifier │ │ │ │ + * {String} All xml nodes containing this search criteria will populate an │ │ │ │ + * internal array of layer nodes. │ │ │ │ + */ │ │ │ │ + layerIdentifier: '_layer', │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: featureIdentifier │ │ │ │ + * {String} All xml nodes containing this search criteria will populate an │ │ │ │ + * internal array of feature nodes for each layer node found. │ │ │ │ + */ │ │ │ │ + featureIdentifier: '_feature', │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ + */ │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: gmlFormat │ │ │ │ + * {<OpenLayers.Format.GML>} internal GML format for parsing geometries │ │ │ │ + * in msGMLOutput │ │ │ │ + */ │ │ │ │ + gmlFormat: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMSGetFeatureInfo │ │ │ │ + * Create a new parser for WMS GetFeatureInfo responses │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read WMS GetFeatureInfo data from a string, and return an array of features │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} An array of features. │ │ │ │ + */ │ │ │ │ + read: function(data) { │ │ │ │ + var result; │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ + } │ │ │ │ + var root = data.documentElement; │ │ │ │ + if (root) { │ │ │ │ + var scope = this; │ │ │ │ + var read = this["read_" + root.nodeName]; │ │ │ │ + if (read) { │ │ │ │ + result = read.call(this, root); │ │ │ │ + } else { │ │ │ │ + // fall-back to GML since this is a common output format for WMS │ │ │ │ + // GetFeatureInfo responses │ │ │ │ + result = new OpenLayers.Format.GML((this.options ? this.options : {})).read(data); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + result = data; │ │ │ │ + } │ │ │ │ + return result; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: read_msGMLOutput │ │ │ │ + * Parse msGMLOutput nodes. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {DOMElement} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array} │ │ │ │ + */ │ │ │ │ + read_msGMLOutput: function(data) { │ │ │ │ + var response = []; │ │ │ │ + var layerNodes = this.getSiblingNodesByTagCriteria(data, │ │ │ │ + this.layerIdentifier); │ │ │ │ + if (layerNodes) { │ │ │ │ + for (var i = 0, len = layerNodes.length; i < len; ++i) { │ │ │ │ + var node = layerNodes[i]; │ │ │ │ + var layerName = node.nodeName; │ │ │ │ + if (node.prefix) { │ │ │ │ + layerName = layerName.split(':')[1]; │ │ │ │ + } │ │ │ │ + var layerName = layerName.replace(this.layerIdentifier, ''); │ │ │ │ + var featureNodes = this.getSiblingNodesByTagCriteria(node, │ │ │ │ + this.featureIdentifier); │ │ │ │ + if (featureNodes) { │ │ │ │ + for (var j = 0; j < featureNodes.length; j++) { │ │ │ │ + var featureNode = featureNodes[j]; │ │ │ │ + var geomInfo = this.parseGeometry(featureNode); │ │ │ │ + var attributes = this.parseAttributes(featureNode); │ │ │ │ + var feature = new OpenLayers.Feature.Vector(geomInfo.geometry, │ │ │ │ + attributes, null); │ │ │ │ + feature.bounds = geomInfo.bounds; │ │ │ │ + feature.type = layerName; │ │ │ │ + response.push(feature); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return response; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: read_FeatureInfoResponse │ │ │ │ + * Parse FeatureInfoResponse nodes. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {DOMElement} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array} │ │ │ │ + */ │ │ │ │ + read_FeatureInfoResponse: function(data) { │ │ │ │ + var response = []; │ │ │ │ + var featureNodes = this.getElementsByTagNameNS(data, '*', │ │ │ │ + 'FIELDS'); │ │ │ │ + │ │ │ │ + for (var i = 0, len = featureNodes.length; i < len; i++) { │ │ │ │ + var featureNode = featureNodes[i]; │ │ │ │ + var geom = null; │ │ │ │ + │ │ │ │ + // attributes can be actual attributes on the FIELDS tag, │ │ │ │ + // or FIELD children │ │ │ │ + var attributes = {}; │ │ │ │ + var j; │ │ │ │ + var jlen = featureNode.attributes.length; │ │ │ │ + if (jlen > 0) { │ │ │ │ + for (j = 0; j < jlen; j++) { │ │ │ │ + var attribute = featureNode.attributes[j]; │ │ │ │ + attributes[attribute.nodeName] = attribute.nodeValue; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + var nodes = featureNode.childNodes; │ │ │ │ + for (j = 0, jlen = nodes.length; j < jlen; ++j) { │ │ │ │ + var node = nodes[j]; │ │ │ │ + if (node.nodeType != 3) { │ │ │ │ + attributes[node.getAttribute("name")] = │ │ │ │ + node.getAttribute("value"); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + response.push( │ │ │ │ + new OpenLayers.Feature.Vector(geom, attributes, null) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return response; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getSiblingNodesByTagCriteria │ │ │ │ + * Recursively searches passed xml node and all it's descendant levels for │ │ │ │ + * nodes whose tagName contains the passed search string. This returns an │ │ │ │ + * array of all sibling nodes which match the criteria from the highest │ │ │ │ + * hierarchial level from which a match is found. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} An xml node │ │ │ │ + * criteria - {String} Search string which will match some part of a tagName │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * Array({DOMElement}) An array of sibling xml nodes │ │ │ │ + */ │ │ │ │ + getSiblingNodesByTagCriteria: function(node, criteria) { │ │ │ │ + var nodes = []; │ │ │ │ + var children, tagName, n, matchNodes, child; │ │ │ │ + if (node && node.hasChildNodes()) { │ │ │ │ + children = node.childNodes; │ │ │ │ + n = children.length; │ │ │ │ + │ │ │ │ + for (var k = 0; k < n; k++) { │ │ │ │ + child = children[k]; │ │ │ │ + while (child && child.nodeType != 1) { │ │ │ │ + child = child.nextSibling; │ │ │ │ + k++; │ │ │ │ + } │ │ │ │ + tagName = (child ? child.nodeName : ''); │ │ │ │ + if (tagName.length > 0 && tagName.indexOf(criteria) > -1) { │ │ │ │ + nodes.push(child); │ │ │ │ + } else { │ │ │ │ + matchNodes = this.getSiblingNodesByTagCriteria( │ │ │ │ + child, criteria); │ │ │ │ + │ │ │ │ + if (matchNodes.length > 0) { │ │ │ │ + (nodes.length == 0) ? │ │ │ │ + nodes = matchNodes: nodes.push(matchNodes); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + } │ │ │ │ + return nodes; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseAttributes │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {<DOMElement>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} An attributes object. │ │ │ │ + * │ │ │ │ + * Notes: │ │ │ │ + * Assumes that attributes are direct child xml nodes of the passed node │ │ │ │ + * and contain only a single text node. │ │ │ │ + */ │ │ │ │ + parseAttributes: function(node) { │ │ │ │ + var attributes = {}; │ │ │ │ + if (node.nodeType == 1) { │ │ │ │ + var children = node.childNodes; │ │ │ │ + var n = children.length; │ │ │ │ + for (var i = 0; i < n; ++i) { │ │ │ │ + var child = children[i]; │ │ │ │ + if (child.nodeType == 1) { │ │ │ │ + var grandchildren = child.childNodes; │ │ │ │ + var name = (child.prefix) ? │ │ │ │ + child.nodeName.split(":")[1] : child.nodeName; │ │ │ │ + if (grandchildren.length == 0) { │ │ │ │ + attributes[name] = null; │ │ │ │ + } else if (grandchildren.length == 1) { │ │ │ │ + var grandchild = grandchildren[0]; │ │ │ │ + if (grandchild.nodeType == 3 || │ │ │ │ + grandchild.nodeType == 4) { │ │ │ │ + var value = grandchild.nodeValue.replace( │ │ │ │ + this.regExes.trimSpace, ""); │ │ │ │ + attributes[name] = value; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return attributes; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseGeometry │ │ │ │ + * Parse the geometry and the feature bounds out of the node using │ │ │ │ + * Format.GML │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {<DOMElement>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} An object containing the geometry and the feature bounds │ │ │ │ + */ │ │ │ │ + parseGeometry: function(node) { │ │ │ │ + // we need to use the old Format.GML parser since we do not know the │ │ │ │ + // geometry name │ │ │ │ + if (!this.gmlFormat) { │ │ │ │ + this.gmlFormat = new OpenLayers.Format.GML(); │ │ │ │ + } │ │ │ │ + var feature = this.gmlFormat.parseFeature(node); │ │ │ │ + var geometry, bounds = null; │ │ │ │ + if (feature) { │ │ │ │ + geometry = feature.geometry && feature.geometry.clone(); │ │ │ │ + bounds = feature.bounds && feature.bounds.clone(); │ │ │ │ + feature.destroy(); │ │ │ │ + } │ │ │ │ + return { │ │ │ │ + geometry: geometry, │ │ │ │ + bounds: bounds │ │ │ │ + }; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSGetFeatureInfo" │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/WMSGetFeatureInfo.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/Click.js │ │ │ │ + * @requires OpenLayers/Handler/Hover.js │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ + * @requires OpenLayers/Format/WMSGetFeatureInfo.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.WMSGetFeatureInfo │ │ │ │ + * The WMSGetFeatureInfo control uses a WMS query to get information about a point on the map. The │ │ │ │ + * information may be in a display-friendly format such as HTML, or a machine-friendly format such │ │ │ │ + * as GML, depending on the server's capabilities and the client's configuration. This control │ │ │ │ + * handles click or hover events, attempts to parse the results using an OpenLayers.Format, and │ │ │ │ + * fires a 'getfeatureinfo' event with the click position, the raw body of the response, and an │ │ │ │ + * array of features if it successfully read the response. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: hover │ │ │ │ + * {Boolean} Send GetFeatureInfo requests when mouse stops moving. │ │ │ │ + * Default is false. │ │ │ │ + */ │ │ │ │ + hover: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: drillDown │ │ │ │ + * {Boolean} Drill down over all WMS layers in the map. When │ │ │ │ + * using drillDown mode, hover is not possible, and an infoFormat that │ │ │ │ + * returns parseable features is required. Default is false. │ │ │ │ + */ │ │ │ │ + drillDown: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: maxFeatures │ │ │ │ + * {Integer} Maximum number of features to return from a WMS query. This │ │ │ │ + * sets the feature_count parameter on WMS GetFeatureInfo │ │ │ │ + * requests. │ │ │ │ + */ │ │ │ │ + maxFeatures: 10, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: clickCallback │ │ │ │ + * {String} The click callback to register in the │ │ │ │ + * {<OpenLayers.Handler.Click>} object created when the hover │ │ │ │ + * option is set to false. Default is "click". │ │ │ │ + */ │ │ │ │ + clickCallback: "click", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: output │ │ │ │ + * {String} Either "features" or "object". When triggering a getfeatureinfo │ │ │ │ + * request should we pass on an array of features or an object with with │ │ │ │ + * a "features" property and other properties (such as the url of the │ │ │ │ + * WMS). Default is "features". │ │ │ │ + */ │ │ │ │ + output: "features", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: layers │ │ │ │ + * {Array(<OpenLayers.Layer.WMS>)} The layers to query for feature info. │ │ │ │ + * If omitted, all map WMS layers with a url that matches this <url> or │ │ │ │ + * <layerUrls> will be considered. │ │ │ │ + */ │ │ │ │ + layers: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: queryVisible │ │ │ │ + * {Boolean} If true, filter out hidden layers when searching the map for │ │ │ │ + * layers to query. Default is false. │ │ │ │ + */ │ │ │ │ + queryVisible: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: url │ │ │ │ + * {String} The URL of the WMS service to use. If not provided, the url │ │ │ │ + * of the first eligible layer will be used. │ │ │ │ + */ │ │ │ │ + url: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: layerUrls │ │ │ │ + * {Array(String)} Optional list of urls for layers that should be queried. │ │ │ │ + * This can be used when the layer url differs from the url used for │ │ │ │ + * making GetFeatureInfo requests (in the case of a layer using cached │ │ │ │ + * tiles). │ │ │ │ + */ │ │ │ │ + layerUrls: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: infoFormat │ │ │ │ + * {String} The mimetype to request from the server. If you are using │ │ │ │ + * drillDown mode and have multiple servers that do not share a common │ │ │ │ + * infoFormat, you can override the control's infoFormat by providing an │ │ │ │ + * INFO_FORMAT parameter in your <OpenLayers.Layer.WMS> instance(s). │ │ │ │ + */ │ │ │ │ + infoFormat: 'text/html', │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: vendorParams │ │ │ │ + * {Object} Additional parameters that will be added to the request, for │ │ │ │ + * WMS implementations that support them. This could e.g. look like │ │ │ │ + * (start code) │ │ │ │ + * { │ │ │ │ + * radius: 5 │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ + */ │ │ │ │ + vendorParams: {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: format │ │ │ │ + * {<OpenLayers.Format>} A format for parsing GetFeatureInfo responses. │ │ │ │ + * Default is <OpenLayers.Format.WMSGetFeatureInfo>. │ │ │ │ + */ │ │ │ │ + format: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: formatOptions │ │ │ │ + * {Object} Optional properties to set on the format (if one is not provided │ │ │ │ + * in the <format> property. │ │ │ │ + */ │ │ │ │ + formatOptions: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: handlerOptions │ │ │ │ + * {Object} Additional options for the handlers used by this control, e.g. │ │ │ │ + * (start code) │ │ │ │ + * { │ │ │ │ + * "click": {delay: 100}, │ │ │ │ + * "hover": {delay: 300} │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: handler │ │ │ │ + * {Object} Reference to the <OpenLayers.Handler> for this control │ │ │ │ + */ │ │ │ │ + handler: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: hoverRequest │ │ │ │ + * {<OpenLayers.Request>} contains the currently running hover request │ │ │ │ + * (if any). │ │ │ │ + */ │ │ │ │ + hoverRequest: 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>): │ │ │ │ + * beforegetfeatureinfo - Triggered before the request is sent. │ │ │ │ + * The event object has an *xy* property with the position of the │ │ │ │ + * mouse click or hover event that triggers the request. │ │ │ │ + * nogetfeatureinfo - no queryable layers were found. │ │ │ │ + * getfeatureinfo - Triggered when a GetFeatureInfo response is received. │ │ │ │ + * The event object has a *text* property with the body of the │ │ │ │ + * response (String), a *features* property with an array of the │ │ │ │ + * parsed features, an *xy* property with the position of the mouse │ │ │ │ + * click or hover event that triggered the request, and a *request* │ │ │ │ + * property with the request itself. If drillDown is set to true and │ │ │ │ + * multiple requests were issued to collect feature info from all │ │ │ │ + * layers, *text* and *request* will only contain the response body │ │ │ │ + * and request object of the last request. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: <OpenLayers.Control.WMSGetFeatureInfo> │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} │ │ │ │ + */ │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + options.handlerOptions = options.handlerOptions || {}; │ │ │ │ + │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + │ │ │ │ + if (!this.format) { │ │ │ │ + this.format = new OpenLayers.Format.WMSGetFeatureInfo( │ │ │ │ + options.formatOptions │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.drillDown === true) { │ │ │ │ + this.hover = false; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.hover) { │ │ │ │ + this.handler = new OpenLayers.Handler.Hover( │ │ │ │ + this, { │ │ │ │ + 'move': this.cancelHover, │ │ │ │ + 'pause': this.getInfoForHover │ │ │ │ + }, │ │ │ │ + OpenLayers.Util.extend(this.handlerOptions.hover || {}, { │ │ │ │ + 'delay': 250 │ │ │ │ + })); │ │ │ │ + } else { │ │ │ │ + var callbacks = {}; │ │ │ │ + callbacks[this.clickCallback] = this.getInfoForClick; │ │ │ │ + this.handler = new OpenLayers.Handler.Click( │ │ │ │ + this, callbacks, this.handlerOptions.click || {}); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getInfoForClick │ │ │ │ + * Called on click │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ + */ │ │ │ │ + getInfoForClick: function(evt) { │ │ │ │ + this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ + xy: evt.xy │ │ │ │ + }); │ │ │ │ + // Set the cursor to "wait" to tell the user we're working on their │ │ │ │ + // click. │ │ │ │ + OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + this.request(evt.xy, {}); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getInfoForHover │ │ │ │ + * Pause callback for the hover handler │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Object} │ │ │ │ + */ │ │ │ │ + getInfoForHover: function(evt) { │ │ │ │ + this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ + xy: evt.xy │ │ │ │ + }); │ │ │ │ + this.request(evt.xy, { │ │ │ │ + hover: true │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: cancelHover │ │ │ │ + * Cancel callback for the hover handler │ │ │ │ + */ │ │ │ │ + cancelHover: function() { │ │ │ │ + if (this.hoverRequest) { │ │ │ │ + this.hoverRequest.abort(); │ │ │ │ + this.hoverRequest = null; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: findLayers │ │ │ │ + * Internal method to get the layers, independent of whether we are │ │ │ │ + * inspecting the map or using a client-provided array │ │ │ │ + */ │ │ │ │ + findLayers: function() { │ │ │ │ + │ │ │ │ + var candidates = this.layers || this.map.layers; │ │ │ │ + var layers = []; │ │ │ │ + var layer, url; │ │ │ │ + for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ + layer = candidates[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.WMS && │ │ │ │ + (!this.queryVisible || layer.getVisibility())) { │ │ │ │ + url = OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url; │ │ │ │ + // if the control was not configured with a url, set it │ │ │ │ + // to the first layer url │ │ │ │ + if (this.drillDown === false && !this.url) { │ │ │ │ + this.url = url; │ │ │ │ + } │ │ │ │ + if (this.drillDown === true || this.urlMatches(url)) { │ │ │ │ + layers.push(layer); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return layers; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: urlMatches │ │ │ │ + * Test to see if the provided url matches either the control <url> or one │ │ │ │ + * of the <layerUrls>. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * url - {String} The url to test. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The provided url matches the control <url> or one of the │ │ │ │ + * <layerUrls>. │ │ │ │ + */ │ │ │ │ + urlMatches: function(url) { │ │ │ │ + var matches = OpenLayers.Util.isEquivalentUrl(this.url, url); │ │ │ │ + if (!matches && this.layerUrls) { │ │ │ │ + for (var i = 0, len = this.layerUrls.length; i < len; ++i) { │ │ │ │ + if (OpenLayers.Util.isEquivalentUrl(this.layerUrls[i], url)) { │ │ │ │ + matches = true; │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return matches; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: buildWMSOptions │ │ │ │ + * Build an object with the relevant WMS options for the GetFeatureInfo request │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * url - {String} The url to be used for sending the request │ │ │ │ + * layers - {Array(<OpenLayers.Layer.WMS)} An array of layers │ │ │ │ + * clickPosition - {<OpenLayers.Pixel>} The position on the map where the mouse │ │ │ │ + * event occurred. │ │ │ │ + * format - {String} The format from the corresponding GetMap request │ │ │ │ + */ │ │ │ │ + buildWMSOptions: function(url, layers, clickPosition, format) { │ │ │ │ + var layerNames = [], │ │ │ │ + styleNames = []; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + if (layers[i].params.LAYERS != null) { │ │ │ │ + layerNames = layerNames.concat(layers[i].params.LAYERS); │ │ │ │ + styleNames = styleNames.concat(this.getStyleNames(layers[i])); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var firstLayer = layers[0]; │ │ │ │ + // use the firstLayer's projection if it matches the map projection - │ │ │ │ + // this assumes that all layers will be available in this projection │ │ │ │ + var projection = this.map.getProjection(); │ │ │ │ + var layerProj = firstLayer.projection; │ │ │ │ + if (layerProj && layerProj.equals(this.map.getProjectionObject())) { │ │ │ │ + projection = layerProj.getCode(); │ │ │ │ + } │ │ │ │ + var params = OpenLayers.Util.extend({ │ │ │ │ + service: "WMS", │ │ │ │ + version: firstLayer.params.VERSION, │ │ │ │ + request: "GetFeatureInfo", │ │ │ │ + exceptions: firstLayer.params.EXCEPTIONS, │ │ │ │ + bbox: this.map.getExtent().toBBOX(null, │ │ │ │ + firstLayer.reverseAxisOrder()), │ │ │ │ + feature_count: this.maxFeatures, │ │ │ │ + height: this.map.getSize().h, │ │ │ │ + width: this.map.getSize().w, │ │ │ │ + format: format, │ │ │ │ + info_format: firstLayer.params.INFO_FORMAT || this.infoFormat │ │ │ │ + }, (parseFloat(firstLayer.params.VERSION) >= 1.3) ? { │ │ │ │ + crs: projection, │ │ │ │ + i: parseInt(clickPosition.x), │ │ │ │ + j: parseInt(clickPosition.y) │ │ │ │ + } : { │ │ │ │ + srs: projection, │ │ │ │ + x: parseInt(clickPosition.x), │ │ │ │ + y: parseInt(clickPosition.y) │ │ │ │ + }); │ │ │ │ + if (layerNames.length != 0) { │ │ │ │ + params = OpenLayers.Util.extend({ │ │ │ │ + layers: layerNames, │ │ │ │ + query_layers: layerNames, │ │ │ │ + styles: styleNames │ │ │ │ + }, params); │ │ │ │ + } │ │ │ │ + OpenLayers.Util.applyDefaults(params, this.vendorParams); │ │ │ │ + return { │ │ │ │ + url: url, │ │ │ │ + params: OpenLayers.Util.upperCaseObject(params), │ │ │ │ + callback: function(request) { │ │ │ │ + this.handleResponse(clickPosition, request, url); │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getStyleNames │ │ │ │ + * Gets the STYLES parameter for the layer. Make sure the STYLES parameter │ │ │ │ + * matches the LAYERS parameter │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.WMS>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array(String)} The STYLES parameter │ │ │ │ + */ │ │ │ │ + getStyleNames: function(layer) { │ │ │ │ + // in the event of a WMS layer bundling multiple layers but not │ │ │ │ + // specifying styles,we need the same number of commas to specify │ │ │ │ + // the default style for each of the layers. We can't just leave it │ │ │ │ + // blank as we may be including other layers that do specify styles. │ │ │ │ + var styleNames; │ │ │ │ + if (layer.params.STYLES) { │ │ │ │ + styleNames = layer.params.STYLES; │ │ │ │ + } else { │ │ │ │ + if (OpenLayers.Util.isArray(layer.params.LAYERS)) { │ │ │ │ + styleNames = new Array(layer.params.LAYERS.length); │ │ │ │ + } else { // Assume it's a String │ │ │ │ + styleNames = layer.params.LAYERS.replace(/[^,]/g, ""); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return styleNames; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: request │ │ │ │ + * Sends a GetFeatureInfo request to the WMS │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * clickPosition - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ + * mouse event occurred. │ │ │ │ + * options - {Object} additional options for this method. │ │ │ │ + * │ │ │ │ + * Valid options: │ │ │ │ + * - *hover* {Boolean} true if we do the request for the hover handler │ │ │ │ + */ │ │ │ │ + request: function(clickPosition, options) { │ │ │ │ + var layers = this.findLayers(); │ │ │ │ + if (layers.length == 0) { │ │ │ │ + this.events.triggerEvent("nogetfeatureinfo"); │ │ │ │ + // Reset the cursor. │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + │ │ │ │ + options = options || {}; │ │ │ │ + if (this.drillDown === false) { │ │ │ │ + var wmsOptions = this.buildWMSOptions(this.url, layers, │ │ │ │ + clickPosition, layers[0].params.FORMAT); │ │ │ │ + var request = OpenLayers.Request.GET(wmsOptions); │ │ │ │ + │ │ │ │ + if (options.hover === true) { │ │ │ │ + this.hoverRequest = request; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this._requestCount = 0; │ │ │ │ + this._numRequests = 0; │ │ │ │ + this.features = []; │ │ │ │ + // group according to service url to combine requests │ │ │ │ + var services = {}, │ │ │ │ + url; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + var layer = layers[i]; │ │ │ │ + var service, found = false; │ │ │ │ + url = OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url; │ │ │ │ + if (url in services) { │ │ │ │ + services[url].push(layer); │ │ │ │ + } else { │ │ │ │ + this._numRequests++; │ │ │ │ + services[url] = [layer]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var layers; │ │ │ │ + for (var url in services) { │ │ │ │ + layers = services[url]; │ │ │ │ + var wmsOptions = this.buildWMSOptions(url, layers, │ │ │ │ + clickPosition, layers[0].params.FORMAT); │ │ │ │ + OpenLayers.Request.GET(wmsOptions); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: triggerGetFeatureInfo │ │ │ │ + * Trigger the getfeatureinfo event when all is done │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * request - {XMLHttpRequest} The request object │ │ │ │ + * xy - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ + * mouse event occurred. │ │ │ │ + * features - {Array(<OpenLayers.Feature.Vector>)} or │ │ │ │ + * {Array({Object}) when output is "object". The object has a url and a │ │ │ │ + * features property which contains an array of features. │ │ │ │ + */ │ │ │ │ + triggerGetFeatureInfo: function(request, xy, features) { │ │ │ │ + this.events.triggerEvent("getfeatureinfo", { │ │ │ │ + text: request.responseText, │ │ │ │ + features: features, │ │ │ │ + request: request, │ │ │ │ + xy: xy │ │ │ │ + }); │ │ │ │ + │ │ │ │ + // Reset the cursor. │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: handleResponse │ │ │ │ + * Handler for the GetFeatureInfo response. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * xy - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ + * mouse event occurred. │ │ │ │ + * request - {XMLHttpRequest} The request object. │ │ │ │ + * url - {String} The url which was used for this request. │ │ │ │ + */ │ │ │ │ + handleResponse: function(xy, request, url) { │ │ │ │ + │ │ │ │ + var doc = request.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = request.responseText; │ │ │ │ + } │ │ │ │ + var features = this.format.read(doc); │ │ │ │ + if (this.drillDown === false) { │ │ │ │ + this.triggerGetFeatureInfo(request, xy, features); │ │ │ │ + } else { │ │ │ │ + this._requestCount++; │ │ │ │ + if (this.output === "object") { │ │ │ │ + this._features = (this._features || []).concat({ │ │ │ │ + url: url, │ │ │ │ + features: features │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + this._features = (this._features || []).concat(features); │ │ │ │ + } │ │ │ │ + if (this._requestCount === this._numRequests) { │ │ │ │ + this.triggerGetFeatureInfo(request, xy, this._features.concat()); │ │ │ │ + delete this._features; │ │ │ │ + delete this._requestCount; │ │ │ │ + delete this._numRequests; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Control.WMSGetFeatureInfo" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/DragFeature.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/Feature.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.DragFeature │ │ │ │ + * The DragFeature control moves a feature with a drag of the mouse. Create a │ │ │ │ + * new control with the <OpenLayers.Control.DragFeature> constructor. │ │ │ │ + * │ │ │ │ + * Inherits From: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.DragFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: geometryTypes │ │ │ │ + * {Array(String)} To restrict dragging to a limited set of geometry types, │ │ │ │ + * send a list of strings corresponding to the geometry class names. │ │ │ │ + */ │ │ │ │ + geometryTypes: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: onStart │ │ │ │ + * {Function} Define this function if you want to know when a drag starts. │ │ │ │ + * The function should expect to receive two arguments: the feature │ │ │ │ + * that is about to be dragged and the pixel location of the mouse. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature that is about to be │ │ │ │ + * dragged. │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. │ │ │ │ + */ │ │ │ │ + onStart: function(feature, pixel) {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: onDrag │ │ │ │ + * {Function} Define this function if you want to know about each move of a │ │ │ │ + * feature. The function should expect to receive two arguments: the │ │ │ │ + * feature that is being dragged and the pixel location of the mouse. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. │ │ │ │ + */ │ │ │ │ + onDrag: function(feature, pixel) {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: onComplete │ │ │ │ + * {Function} Define this function if you want to know when a feature is │ │ │ │ + * done dragging. The function should expect to receive two arguments: │ │ │ │ + * the feature that is being dragged and the pixel location of the │ │ │ │ + * mouse. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. │ │ │ │ + */ │ │ │ │ + onComplete: function(feature, pixel) {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: onEnter │ │ │ │ + * {Function} Define this function if you want to know when the mouse │ │ │ │ + * goes over a feature and thereby makes this feature a candidate │ │ │ │ + * for dragging. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature that is ready │ │ │ │ + * to be dragged. │ │ │ │ + */ │ │ │ │ + onEnter: function(feature) {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: onLeave │ │ │ │ + * {Function} Define this function if you want to know when the mouse │ │ │ │ + * goes out of the feature that was dragged. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. │ │ │ │ + */ │ │ │ │ + onLeave: function(feature) {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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: layer │ │ │ │ + * {<OpenLayers.Layer.Vector>} │ │ │ │ + */ │ │ │ │ + layer: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: feature │ │ │ │ + * {<OpenLayers.Feature.Vector>} │ │ │ │ + */ │ │ │ │ + feature: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: dragCallbacks │ │ │ │ + * {Object} The functions that are sent to the drag handler for callback. │ │ │ │ + */ │ │ │ │ + dragCallbacks: {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: featureCallbacks │ │ │ │ + * {Object} The functions that are sent to the feature handler for callback. │ │ │ │ + */ │ │ │ │ + featureCallbacks: {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: lastPixel │ │ │ │ + * {<OpenLayers.Pixel>} │ │ │ │ + */ │ │ │ │ + lastPixel: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.DragFeature │ │ │ │ + * Create a new control to drag features. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} The layer containing features to be │ │ │ │ + * dragged. │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * control. │ │ │ │ + */ │ │ │ │ + initialize: function(layer, options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.layer = layer; │ │ │ │ + this.handlers = { │ │ │ │ + drag: new OpenLayers.Handler.Drag( │ │ │ │ + this, OpenLayers.Util.extend({ │ │ │ │ + down: this.downFeature, │ │ │ │ + move: this.moveFeature, │ │ │ │ + up: this.upFeature, │ │ │ │ + out: this.cancel, │ │ │ │ + done: this.doneDragging │ │ │ │ + }, this.dragCallbacks), { │ │ │ │ + documentDrag: this.documentDrag │ │ │ │ + } │ │ │ │ + ), │ │ │ │ + feature: new OpenLayers.Handler.Feature( │ │ │ │ + this, this.layer, OpenLayers.Util.extend({ │ │ │ │ + // 'click' and 'clickout' callback are for the mobile │ │ │ │ + // support: no 'over' or 'out' in touch based browsers. │ │ │ │ + click: this.clickFeature, │ │ │ │ + clickout: this.clickoutFeature, │ │ │ │ + over: this.overFeature, │ │ │ │ + out: this.outFeature │ │ │ │ + }, this.featureCallbacks), { │ │ │ │ + geometryTypes: this.geometryTypes │ │ │ │ + } │ │ │ │ + ) │ │ │ │ + }; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clickFeature │ │ │ │ + * Called when the feature handler detects a click-in on a feature. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + */ │ │ │ │ + clickFeature: function(feature) { │ │ │ │ + if (this.handlers.feature.touch && !this.over && this.overFeature(feature)) { │ │ │ │ + this.handlers.drag.dragstart(this.handlers.feature.evt); │ │ │ │ + // to let the events propagate to the feature handler (click callback) │ │ │ │ + this.handlers.drag.stopDown = false; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clickoutFeature │ │ │ │ + * Called when the feature handler detects a click-out on a feature. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + */ │ │ │ │ + clickoutFeature: function(feature) { │ │ │ │ + if (this.handlers.feature.touch && this.over) { │ │ │ │ + this.outFeature(feature); │ │ │ │ + this.handlers.drag.stopDown = true; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Take care of things that are not handled in superclass │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + this.layer = null; │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, []); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the control and the feature handler. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Successfully activated the control and feature handler. │ │ │ │ + */ │ │ │ │ + activate: function() { │ │ │ │ + return (this.handlers.feature.activate() && │ │ │ │ + OpenLayers.Control.prototype.activate.apply(this, arguments)); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the control and all handlers. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Successfully deactivated the control. │ │ │ │ + */ │ │ │ │ + deactivate: function() { │ │ │ │ + // the return from the handlers is unimportant in this case │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ + this.handlers.feature.deactivate(); │ │ │ │ + this.feature = null; │ │ │ │ + this.dragging = false; │ │ │ │ + this.lastPixel = null; │ │ │ │ + OpenLayers.Element.removeClass( │ │ │ │ + this.map.viewPortDiv, this.displayClass + "Over" │ │ │ │ + ); │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: overFeature │ │ │ │ + * Called when the feature handler detects a mouse-over on a feature. │ │ │ │ + * This activates the drag handler. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The selected feature. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Successfully activated the drag handler. │ │ │ │ + */ │ │ │ │ + overFeature: function(feature) { │ │ │ │ + var activated = false; │ │ │ │ + if (!this.handlers.drag.dragging) { │ │ │ │ + this.feature = feature; │ │ │ │ + this.handlers.drag.activate(); │ │ │ │ + activated = true; │ │ │ │ + this.over = true; │ │ │ │ + OpenLayers.Element.addClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ + this.onEnter(feature); │ │ │ │ + } else { │ │ │ │ + if (this.feature.id == feature.id) { │ │ │ │ + this.over = true; │ │ │ │ + } else { │ │ │ │ + this.over = false; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return activated; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: downFeature │ │ │ │ + * Called when the drag handler detects a mouse-down. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * pixel - {<OpenLayers.Pixel>} Location of the mouse event. │ │ │ │ + */ │ │ │ │ + downFeature: function(pixel) { │ │ │ │ + this.lastPixel = pixel; │ │ │ │ + this.onStart(this.feature, pixel); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveFeature │ │ │ │ + * Called when the drag handler detects a mouse-move. Also calls the │ │ │ │ + * optional onDrag method. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * pixel - {<OpenLayers.Pixel>} Location of the mouse event. │ │ │ │ + */ │ │ │ │ + moveFeature: function(pixel) { │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ + this.feature.geometry.move(res * (pixel.x - this.lastPixel.x), │ │ │ │ + res * (this.lastPixel.y - pixel.y)); │ │ │ │ + this.layer.drawFeature(this.feature); │ │ │ │ + this.lastPixel = pixel; │ │ │ │ + this.onDrag(this.feature, pixel); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: upFeature │ │ │ │ + * Called when the drag handler detects a mouse-up. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * pixel - {<OpenLayers.Pixel>} Location of the mouse event. │ │ │ │ + */ │ │ │ │ + upFeature: function(pixel) { │ │ │ │ + if (!this.over) { │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: doneDragging │ │ │ │ + * Called when the drag handler is done dragging. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The last event pixel location. If this event │ │ │ │ + * came from a mouseout, this may not be in the map viewport. │ │ │ │ + */ │ │ │ │ + doneDragging: function(pixel) { │ │ │ │ + this.onComplete(this.feature, pixel); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: outFeature │ │ │ │ + * Called when the feature handler detects a mouse-out on a feature. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature that the mouse left. │ │ │ │ + */ │ │ │ │ + outFeature: function(feature) { │ │ │ │ + if (!this.handlers.drag.dragging) { │ │ │ │ + this.over = false; │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ + OpenLayers.Element.removeClass( │ │ │ │ + this.map.viewPortDiv, this.displayClass + "Over" │ │ │ │ + ); │ │ │ │ + this.onLeave(feature); │ │ │ │ + this.feature = null; │ │ │ │ + } else { │ │ │ │ + if (this.feature.id == feature.id) { │ │ │ │ + this.over = false; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: cancel │ │ │ │ + * Called when the drag handler detects a mouse-out (from the map viewport). │ │ │ │ + */ │ │ │ │ + cancel: function() { │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ + this.over = false; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ + this.handlers.feature.setMap(map); │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Control.DragFeature" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/Scale.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/Lang.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.Scale │ │ │ │ + * The Scale control displays the current map scale as a ratio (e.g. Scale = │ │ │ │ + * 1:1M). By default it is displayed in the lower right corner of the map. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.Scale = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: element │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + element: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: geodesic │ │ │ │ + * {Boolean} Use geodesic measurement. Default is false. The recommended │ │ │ │ + * setting for maps in EPSG:4326 is false, and true EPSG:900913. If set to │ │ │ │ + * true, the scale will be calculated based on the horizontal size of the │ │ │ │ + * pixel in the center of the map viewport. │ │ │ │ + */ │ │ │ │ + geodesic: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.Scale │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * element - {DOMElement} │ │ │ │ + * options - {Object} │ │ │ │ + */ │ │ │ │ + initialize: function(element, options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.element = OpenLayers.Util.getElement(element); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: draw │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (!this.element) { │ │ │ │ + this.element = document.createElement("div"); │ │ │ │ + this.div.appendChild(this.element); │ │ │ │ + } │ │ │ │ + this.map.events.register('moveend', this, this.updateScale); │ │ │ │ + this.updateScale(); │ │ │ │ + return this.div; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: updateScale │ │ │ │ + */ │ │ │ │ + updateScale: function() { │ │ │ │ + var scale; │ │ │ │ + if (this.geodesic === true) { │ │ │ │ + var units = this.map.getUnits(); │ │ │ │ + if (!units) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + var inches = OpenLayers.INCHES_PER_UNIT; │ │ │ │ + scale = (this.map.getGeodesicPixelSize().w || 0.000001) * │ │ │ │ + inches["km"] * OpenLayers.DOTS_PER_INCH; │ │ │ │ + } else { │ │ │ │ + scale = this.map.getScale(); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (!scale) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (scale >= 9500 && scale <= 950000) { │ │ │ │ + scale = Math.round(scale / 1000) + "K"; │ │ │ │ + } else if (scale >= 950000) { │ │ │ │ + scale = Math.round(scale / 1000000) + "M"; │ │ │ │ + } else { │ │ │ │ + scale = Math.round(scale); │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.element.innerHTML = OpenLayers.i18n("Scale = 1 : ${scaleDenom}", { │ │ │ │ + 'scaleDenom': scale │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Scale" │ │ │ │ +}); │ │ │ │ + │ │ │ │ +/* ====================================================================== │ │ │ │ + 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/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/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/Control/TransformFeature.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. */ │ │ │ │ @@ -59026,1853 +65223,686 @@ │ │ │ │ control.events.triggerEvent("transformcomplete", { │ │ │ │ feature: control.feature │ │ │ │ }); │ │ │ │ } │ │ │ │ }); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: drawHandles │ │ │ │ - * Draws the handles to match the box. │ │ │ │ - */ │ │ │ │ - drawHandles: function() { │ │ │ │ - var layer = this.layer; │ │ │ │ - for (var i = 0; i < 8; ++i) { │ │ │ │ - if (this.rotate && i % 2 === 0) { │ │ │ │ - layer.drawFeature(this.rotationHandles[i / 2], │ │ │ │ - this.rotationHandleSymbolizer); │ │ │ │ - } │ │ │ │ - layer.drawFeature(this.handles[i], this.renderIntent); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: transformFeature │ │ │ │ - * Transforms the feature. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * mods - {Object} An object with optional scale, ratio, rotation and │ │ │ │ - * center properties. │ │ │ │ - */ │ │ │ │ - transformFeature: function(mods) { │ │ │ │ - if (!this._setfeature) { │ │ │ │ - this.scale *= (mods.scale || 1); │ │ │ │ - this.ratio *= (mods.ratio || 1); │ │ │ │ - var oldRotation = this.rotation; │ │ │ │ - this.rotation = (this.rotation + (mods.rotation || 0)) % 360; │ │ │ │ - │ │ │ │ - if (this.events.triggerEvent("beforetransform", mods) !== false) { │ │ │ │ - var feature = this.feature; │ │ │ │ - var geom = feature.geometry; │ │ │ │ - var center = this.center; │ │ │ │ - geom.rotate(-oldRotation, center); │ │ │ │ - if (mods.scale || mods.ratio) { │ │ │ │ - geom.resize(mods.scale, center, mods.ratio); │ │ │ │ - } else if (mods.center) { │ │ │ │ - feature.move(mods.center.getBounds().getCenterLonLat()); │ │ │ │ - } │ │ │ │ - geom.rotate(this.rotation, center); │ │ │ │ - this.layer.drawFeature(feature); │ │ │ │ - feature.toState(OpenLayers.State.UPDATE); │ │ │ │ - this.events.triggerEvent("transform", mods); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.layer.drawFeature(this.box, this.renderIntent); │ │ │ │ - this.drawHandles(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Take care of things that are not handled in superclass. │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - var geom; │ │ │ │ - for (var i = 0; i < 8; ++i) { │ │ │ │ - geom = this.box.geometry.components[i]; │ │ │ │ - geom._handle.destroy(); │ │ │ │ - geom._handle = null; │ │ │ │ - geom._rotationHandle && geom._rotationHandle.destroy(); │ │ │ │ - geom._rotationHandle = null; │ │ │ │ - } │ │ │ │ - this.center = null; │ │ │ │ - this.feature = null; │ │ │ │ - this.handles = null; │ │ │ │ - this.rotationHandleSymbolizer = null; │ │ │ │ - this.rotationHandles = null; │ │ │ │ - this.box.destroy(); │ │ │ │ - this.box = null; │ │ │ │ - this.layer = null; │ │ │ │ - this.dragControl.destroy(); │ │ │ │ - this.dragControl = null; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.TransformFeature" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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/Control/ZoomOut.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/Button.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.ZoomOut │ │ │ │ - * The ZoomOut control is a button to decrease the zoom level of a map. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.ZoomOut = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: trigger │ │ │ │ - */ │ │ │ │ - trigger: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.zoomOut(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomOut" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/UTFGrid.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/Hover.js │ │ │ │ - * @requires OpenLayers/Handler/Click.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.UTFGrid │ │ │ │ - * │ │ │ │ - * This Control provides behavior associated with UTFGrid Layers. │ │ │ │ - * These 'hit grids' provide underlying feature attributes without │ │ │ │ - * calling the server (again). This control allows Mousemove, Hovering │ │ │ │ - * and Click events to trigger callbacks that use the attributes in │ │ │ │ - * whatever way you need. │ │ │ │ - * │ │ │ │ - * The most common example may be a UTFGrid layer containing feature │ │ │ │ - * attributes that are displayed in a div as you mouseover. │ │ │ │ - * │ │ │ │ - * Example Code: │ │ │ │ - * │ │ │ │ - * (start code) │ │ │ │ - * var world_utfgrid = new OpenLayers.Layer.UTFGrid( │ │ │ │ - * 'UTFGrid Layer', │ │ │ │ - * "http://tiles/world_utfgrid/${z}/${x}/${y}.json" │ │ │ │ - * ); │ │ │ │ - * map.addLayer(world_utfgrid); │ │ │ │ - * │ │ │ │ - * var control = new OpenLayers.Control.UTFGrid({ │ │ │ │ - * layers: [world_utfgrid], │ │ │ │ - * handlerMode: 'move', │ │ │ │ - * callback: function(infoLookup) { │ │ │ │ - * // do something with returned data │ │ │ │ - * │ │ │ │ - * } │ │ │ │ - * }) │ │ │ │ - * (end code) │ │ │ │ - * │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.UTFGrid = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ - */ │ │ │ │ - autoActivate: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: Layers │ │ │ │ - * List of layers to consider. Must be Layer.UTFGrids │ │ │ │ - * `null` is the default indicating all UTFGrid Layers are queried. │ │ │ │ - * {Array} <OpenLayers.Layer.UTFGrid> │ │ │ │ - */ │ │ │ │ - layers: null, │ │ │ │ - │ │ │ │ - /* Property: defaultHandlerOptions │ │ │ │ - * The default opts passed to the handler constructors │ │ │ │ - */ │ │ │ │ - defaultHandlerOptions: { │ │ │ │ - 'delay': 300, │ │ │ │ - 'pixelTolerance': 4, │ │ │ │ - 'stopMove': false, │ │ │ │ - 'single': true, │ │ │ │ - 'double': false, │ │ │ │ - 'stopSingle': false, │ │ │ │ - 'stopDouble': false │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /* APIProperty: handlerMode │ │ │ │ - * Defaults to 'click'. Can be 'hover' or 'move'. │ │ │ │ - */ │ │ │ │ - handlerMode: 'click', │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: setHandler │ │ │ │ - * sets this.handlerMode and calls resetHandler() │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * hm - {String} Handler Mode string; 'click', 'hover' or 'move'. │ │ │ │ - */ │ │ │ │ - setHandler: function(hm) { │ │ │ │ - this.handlerMode = hm; │ │ │ │ - this.resetHandler(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: resetHandler │ │ │ │ - * Deactivates the old hanlder and creates a new │ │ │ │ - * <OpenLayers.Handler> based on the mode specified in │ │ │ │ - * this.handlerMode │ │ │ │ - * │ │ │ │ - */ │ │ │ │ - resetHandler: function() { │ │ │ │ - if (this.handler) { │ │ │ │ - this.handler.deactivate(); │ │ │ │ - this.handler.destroy(); │ │ │ │ - this.handler = null; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.handlerMode == 'hover') { │ │ │ │ - // Handle this event on hover │ │ │ │ - this.handler = new OpenLayers.Handler.Hover( │ │ │ │ - this, { │ │ │ │ - 'pause': this.handleEvent, │ │ │ │ - 'move': this.reset │ │ │ │ - }, │ │ │ │ - this.handlerOptions │ │ │ │ - ); │ │ │ │ - } else if (this.handlerMode == 'click') { │ │ │ │ - // Handle this event on click │ │ │ │ - this.handler = new OpenLayers.Handler.Click( │ │ │ │ - this, { │ │ │ │ - 'click': this.handleEvent │ │ │ │ - }, this.handlerOptions │ │ │ │ - ); │ │ │ │ - } else if (this.handlerMode == 'move') { │ │ │ │ - this.handler = new OpenLayers.Handler.Hover( │ │ │ │ - this, │ │ │ │ - // Handle this event while hovering OR moving │ │ │ │ - { │ │ │ │ - 'pause': this.handleEvent, │ │ │ │ - 'move': this.handleEvent │ │ │ │ - }, │ │ │ │ - this.handlerOptions │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (this.handler) { │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: <OpenLayers.Control.UTFGrid> │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.handlerOptions = options.handlerOptions || this.defaultHandlerOptions; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.resetHandler(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: handleEvent │ │ │ │ - * Internal method called when specified event is triggered. │ │ │ │ - * │ │ │ │ - * This method does several things: │ │ │ │ - * │ │ │ │ - * Gets the lonLat of the event. │ │ │ │ - * │ │ │ │ - * Loops through the appropriate hit grid layers and gathers the attributes. │ │ │ │ - * │ │ │ │ - * Passes the attributes to the callback │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ - */ │ │ │ │ - handleEvent: function(evt) { │ │ │ │ - if (evt == null) { │ │ │ │ - this.reset(); │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var lonLat = this.map.getLonLatFromPixel(evt.xy); │ │ │ │ - if (!lonLat) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var layers = this.findLayers(); │ │ │ │ - if (layers.length > 0) { │ │ │ │ - var infoLookup = {}; │ │ │ │ - var layer, idx; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - layer = layers[i]; │ │ │ │ - idx = OpenLayers.Util.indexOf(this.map.layers, layer); │ │ │ │ - infoLookup[idx] = layer.getFeatureInfo(lonLat); │ │ │ │ - } │ │ │ │ - this.callback(infoLookup, lonLat, evt.xy); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: callback │ │ │ │ - * Function to be called when a mouse event corresponds with a location that │ │ │ │ - * includes data in one of the configured UTFGrid layers. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * infoLookup - {Object} Keys of this object are layer indexes and can be │ │ │ │ - * used to resolve a layer in the map.layers array. The structure of │ │ │ │ - * the property values depend on the data included in the underlying │ │ │ │ - * UTFGrid and may be any valid JSON type. │ │ │ │ - */ │ │ │ │ - callback: function(infoLookup) { │ │ │ │ - // to be provided in the constructor │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: reset │ │ │ │ - * Calls the callback with null. │ │ │ │ - */ │ │ │ │ - reset: function(evt) { │ │ │ │ - this.callback(null); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: findLayers │ │ │ │ - * Internal method to get the layers, independent of whether we are │ │ │ │ - * inspecting the map or using a client-provided array │ │ │ │ - * │ │ │ │ - * The default value of this.layers is null; this causes the │ │ │ │ - * findLayers method to return ALL UTFGrid layers encountered. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * None │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} Layers to handle on each event │ │ │ │ - */ │ │ │ │ - findLayers: function() { │ │ │ │ - var candidates = this.layers || this.map.layers; │ │ │ │ - var layers = []; │ │ │ │ - var layer; │ │ │ │ - for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ - layer = candidates[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.UTFGrid) { │ │ │ │ - layers.push(layer); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return layers; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.UTFGrid" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/EditingToolbar.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/Panel.js │ │ │ │ - * @requires OpenLayers/Control/Navigation.js │ │ │ │ - * @requires OpenLayers/Control/DrawFeature.js │ │ │ │ - * @requires OpenLayers/Handler/Point.js │ │ │ │ - * @requires OpenLayers/Handler/Path.js │ │ │ │ - * @requires OpenLayers/Handler/Polygon.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.EditingToolbar │ │ │ │ - * The EditingToolbar is a panel of 4 controls to draw polygons, lines, │ │ │ │ - * points, or to navigate the map by panning. By default it appears in the │ │ │ │ - * upper right corner of the map. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control.Panel> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.EditingToolbar = OpenLayers.Class( │ │ │ │ - OpenLayers.Control.Panel, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.EditingToolbar │ │ │ │ - * Create an editing toolbar for a given layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} │ │ │ │ - * options - {Object} │ │ │ │ - */ │ │ │ │ - initialize: function(layer, options) { │ │ │ │ - OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ - │ │ │ │ - this.addControls( │ │ │ │ - [new OpenLayers.Control.Navigation()] │ │ │ │ - ); │ │ │ │ - var controls = [ │ │ │ │ - new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Point, { │ │ │ │ - displayClass: 'olControlDrawFeaturePoint', │ │ │ │ - handlerOptions: { │ │ │ │ - citeCompliant: this.citeCompliant │ │ │ │ - } │ │ │ │ - }), │ │ │ │ - new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Path, { │ │ │ │ - displayClass: 'olControlDrawFeaturePath', │ │ │ │ - handlerOptions: { │ │ │ │ - citeCompliant: this.citeCompliant │ │ │ │ - } │ │ │ │ - }), │ │ │ │ - new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Polygon, { │ │ │ │ - displayClass: 'olControlDrawFeaturePolygon', │ │ │ │ - handlerOptions: { │ │ │ │ - citeCompliant: this.citeCompliant │ │ │ │ - } │ │ │ │ - }) │ │ │ │ - ]; │ │ │ │ - this.addControls(controls); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Method: drawHandles │ │ │ │ + * Draws the handles to match the box. │ │ │ │ + */ │ │ │ │ + drawHandles: function() { │ │ │ │ + var layer = this.layer; │ │ │ │ + for (var i = 0; i < 8; ++i) { │ │ │ │ + if (this.rotate && i % 2 === 0) { │ │ │ │ + layer.drawFeature(this.rotationHandles[i / 2], │ │ │ │ + this.rotationHandleSymbolizer); │ │ │ │ + } │ │ │ │ + layer.drawFeature(this.handles[i], this.renderIntent); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * calls the default draw, and then activates mouse defaults. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - draw: function() { │ │ │ │ - var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments); │ │ │ │ - if (this.defaultControl === null) { │ │ │ │ - this.defaultControl = this.controls[0]; │ │ │ │ + /** │ │ │ │ + * Method: transformFeature │ │ │ │ + * Transforms the feature. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * mods - {Object} An object with optional scale, ratio, rotation and │ │ │ │ + * center properties. │ │ │ │ + */ │ │ │ │ + transformFeature: function(mods) { │ │ │ │ + if (!this._setfeature) { │ │ │ │ + this.scale *= (mods.scale || 1); │ │ │ │ + this.ratio *= (mods.ratio || 1); │ │ │ │ + var oldRotation = this.rotation; │ │ │ │ + this.rotation = (this.rotation + (mods.rotation || 0)) % 360; │ │ │ │ + │ │ │ │ + if (this.events.triggerEvent("beforetransform", mods) !== false) { │ │ │ │ + var feature = this.feature; │ │ │ │ + var geom = feature.geometry; │ │ │ │ + var center = this.center; │ │ │ │ + geom.rotate(-oldRotation, center); │ │ │ │ + if (mods.scale || mods.ratio) { │ │ │ │ + geom.resize(mods.scale, center, mods.ratio); │ │ │ │ + } else if (mods.center) { │ │ │ │ + feature.move(mods.center.getBounds().getCenterLonLat()); │ │ │ │ + } │ │ │ │ + geom.rotate(this.rotation, center); │ │ │ │ + this.layer.drawFeature(feature); │ │ │ │ + feature.toState(OpenLayers.State.UPDATE); │ │ │ │ + this.events.triggerEvent("transform", mods); │ │ │ │ } │ │ │ │ - return div; │ │ │ │ - }, │ │ │ │ + } │ │ │ │ + this.layer.drawFeature(this.box, this.renderIntent); │ │ │ │ + this.drawHandles(); │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.EditingToolbar" │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Take care of things that are not handled in superclass. │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + var geom; │ │ │ │ + for (var i = 0; i < 8; ++i) { │ │ │ │ + geom = this.box.geometry.components[i]; │ │ │ │ + geom._handle.destroy(); │ │ │ │ + geom._handle = null; │ │ │ │ + geom._rotationHandle && geom._rotationHandle.destroy(); │ │ │ │ + geom._rotationHandle = null; │ │ │ │ + } │ │ │ │ + this.center = null; │ │ │ │ + this.feature = null; │ │ │ │ + this.handles = null; │ │ │ │ + this.rotationHandleSymbolizer = null; │ │ │ │ + this.rotationHandles = null; │ │ │ │ + this.box.destroy(); │ │ │ │ + this.box = null; │ │ │ │ + this.layer = null; │ │ │ │ + this.dragControl.destroy(); │ │ │ │ + this.dragControl = null; │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Control.TransformFeature" │ │ │ │ +}); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Zoom.js │ │ │ │ + OpenLayers/Control/KeyboardDefaults.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 │ │ │ │ + * @requires OpenLayers/Handler/Keyboard.js │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Zoom │ │ │ │ - * The Zoom control is a pair of +/- links for zooming in and out. │ │ │ │ + * Class: OpenLayers.Control.KeyboardDefaults │ │ │ │ + * The KeyboardDefaults control adds panning and zooming functions, controlled │ │ │ │ + * with the keyboard. By default arrow keys pan, +/- keys zoom & Page Up/Page │ │ │ │ + * Down/Home/End scroll by three quarters of a page. │ │ │ │ + * │ │ │ │ + * This control has no visible appearance. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.Zoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Control.KeyboardDefaults = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: zoomInText │ │ │ │ - * {String} │ │ │ │ - * Text for zoom-in link. Default is "+". │ │ │ │ + * APIProperty: autoActivate │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * true. │ │ │ │ */ │ │ │ │ - zoomInText: "+", │ │ │ │ + autoActivate: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: slideFactor │ │ │ │ + * Pixels to slide by. │ │ │ │ */ │ │ │ │ - zoomInId: "olZoomInLink", │ │ │ │ + slideFactor: 75, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: zoomOutText │ │ │ │ - * {String} │ │ │ │ - * Text for zoom-out link. Default is "\u2212". │ │ │ │ + * APIProperty: observeElement │ │ │ │ + * {DOMelement|String} The DOM element to handle keys for. You │ │ │ │ + * can use the map div here, to have the navigation keys │ │ │ │ + * work when the map div has the focus. If undefined the │ │ │ │ + * document is used. │ │ │ │ */ │ │ │ │ - zoomOutText: "\u2212", │ │ │ │ + observeElement: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Constructor: OpenLayers.Control.KeyboardDefaults │ │ │ │ */ │ │ │ │ - zoomOutId: "olZoomOutLink", │ │ │ │ │ │ │ │ /** │ │ │ │ * Method: draw │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A reference to the DOMElement containing the zoom links. │ │ │ │ + * Create handler. │ │ │ │ */ │ │ │ │ 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; │ │ │ │ + var observeElement = this.observeElement || document; │ │ │ │ + this.handler = new OpenLayers.Handler.Keyboard(this, { │ │ │ │ + "keydown": this.defaultKeyPress │ │ │ │ + }, { │ │ │ │ + observeElement: observeElement │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getOrCreateLinks │ │ │ │ + * Method: defaultKeyPress │ │ │ │ + * When handling the key event, we only use evt.keyCode. This holds │ │ │ │ + * some drawbacks, though we get around them below. When interpretting │ │ │ │ + * the keycodes below (including the comments associated with them), │ │ │ │ + * consult the URL below. For instance, the Safari browser returns │ │ │ │ + * "IE keycodes", and so is supported by any keycode labeled "IE". │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * el - {DOMElement} │ │ │ │ + * Very informative URL: │ │ │ │ + * http://unixpapa.com/js/key.html │ │ │ │ * │ │ │ │ - * Return: │ │ │ │ - * {Object} Object with zoomIn and zoomOut properties referencing links. │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ + defaultKeyPress: function(evt) { │ │ │ │ + var size, handled = true; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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(); │ │ │ │ + var target = OpenLayers.Event.element(evt); │ │ │ │ + if (target && │ │ │ │ + (target.tagName == 'INPUT' || │ │ │ │ + target.tagName == 'TEXTAREA' || │ │ │ │ + target.tagName == 'SELECT')) { │ │ │ │ + return; │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - * Clean up. │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.unregister("buttonclick", this, this.onZoomClick); │ │ │ │ + switch (evt.keyCode) { │ │ │ │ + case OpenLayers.Event.KEY_LEFT: │ │ │ │ + this.map.pan(-this.slideFactor, 0); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Event.KEY_RIGHT: │ │ │ │ + this.map.pan(this.slideFactor, 0); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Event.KEY_UP: │ │ │ │ + this.map.pan(0, -this.slideFactor); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Event.KEY_DOWN: │ │ │ │ + this.map.pan(0, this.slideFactor); │ │ │ │ + break; │ │ │ │ + │ │ │ │ + case 33: // Page Up. Same in all browsers. │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(0, -0.75 * size.h); │ │ │ │ + break; │ │ │ │ + case 34: // Page Down. Same in all browsers. │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(0, 0.75 * size.h); │ │ │ │ + break; │ │ │ │ + case 35: // End. Same in all browsers. │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(0.75 * size.w, 0); │ │ │ │ + break; │ │ │ │ + case 36: // Home. Same in all browsers. │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(-0.75 * size.w, 0); │ │ │ │ + break; │ │ │ │ + │ │ │ │ + case 43: // +/= (ASCII), keypad + (ASCII, Opera) │ │ │ │ + case 61: // +/= (Mozilla, Opera, some ASCII) │ │ │ │ + case 187: // +/= (IE) │ │ │ │ + case 107: // keypad + (IE, Mozilla) │ │ │ │ + this.map.zoomIn(); │ │ │ │ + break; │ │ │ │ + case 45: // -/_ (ASCII, Opera), keypad - (ASCII, Opera) │ │ │ │ + case 109: // -/_ (Mozilla), keypad - (Mozilla, IE) │ │ │ │ + case 189: // -/_ (IE) │ │ │ │ + case 95: // -/_ (some ASCII) │ │ │ │ + this.map.zoomOut(); │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + handled = false; │ │ │ │ + } │ │ │ │ + if (handled) { │ │ │ │ + // prevent browser default not to move the page │ │ │ │ + // when moving the page with the keyboard │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ } │ │ │ │ - delete this.zoomInLink; │ │ │ │ - delete this.zoomOutLink; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Zoom" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.KeyboardDefaults" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Handler/Keyboard.js │ │ │ │ + OpenLayers/Control/ZoomToMaxExtent.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 │ │ │ │ + * @requires OpenLayers/Control/Button.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.handler.Keyboard │ │ │ │ - * A handler for keyboard events. Create a new instance with the │ │ │ │ - * <OpenLayers.Handler.Keyboard> constructor. │ │ │ │ + * Class: OpenLayers.Control.ZoomToMaxExtent │ │ │ │ + * The ZoomToMaxExtent control is a button that zooms out to the maximum │ │ │ │ + * extent of the map. It is designed to be used with a │ │ │ │ + * <OpenLayers.Control.Panel>. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Handler> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -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, │ │ │ │ +OpenLayers.Control.ZoomToMaxExtent = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Handler.Keyboard │ │ │ │ - * Returns a new keyboard handler. │ │ │ │ + * Method: trigger │ │ │ │ * │ │ │ │ - * 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 │ │ │ │ + * Called whenever this control is being rendered inside of a panel and a │ │ │ │ + * click occurs on this controls element. Actually zooms to the maximum │ │ │ │ + * extent of this controls map. │ │ │ │ */ │ │ │ │ - handleKeyEvent: function(evt) { │ │ │ │ - if (this.checkModifiers(evt)) { │ │ │ │ - this.callback(evt.type, [evt]); │ │ │ │ + trigger: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.zoomToMaxExtent(); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Keyboard" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomToMaxExtent" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/ModifyFeature.js │ │ │ │ + OpenLayers/Control/WMTSGetFeatureInfo.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 │ │ │ │ + * @requires OpenLayers/Handler/Click.js │ │ │ │ + * @requires OpenLayers/Handler/Hover.js │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ + * @requires OpenLayers/Format/WMSGetFeatureInfo.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. │ │ │ │ + * Class: OpenLayers.Control.WMTSGetFeatureInfo │ │ │ │ + * The WMTSGetFeatureInfo control uses a WMTS query to get information about a │ │ │ │ + * point on the map. The information may be in a display-friendly format │ │ │ │ + * such as HTML, or a machine-friendly format such as GML, depending on the │ │ │ │ + * server's capabilities and the client's configuration. This control │ │ │ │ + * handles click or hover events, attempts to parse the results using an │ │ │ │ + * OpenLayers.Format, and fires a 'getfeatureinfo' event for each layer │ │ │ │ + * queried. │ │ │ │ * │ │ │ │ - * Inherits From: │ │ │ │ + * 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, │ │ │ │ +OpenLayers.Control.WMTSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: layer │ │ │ │ - * {<OpenLayers.Layer.Vector>} │ │ │ │ + * APIProperty: hover │ │ │ │ + * {Boolean} Send GetFeatureInfo requests when mouse stops moving. │ │ │ │ + * Default is false. │ │ │ │ */ │ │ │ │ - layer: null, │ │ │ │ + hover: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: feature │ │ │ │ - * {<OpenLayers.Feature.Vector>} Feature currently available for modification. │ │ │ │ + * Property: requestEncoding │ │ │ │ + * {String} One of "KVP" or "REST". Only KVP encoding is supported at this │ │ │ │ + * time. │ │ │ │ */ │ │ │ │ - feature: null, │ │ │ │ + requestEncoding: "KVP", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: vertex │ │ │ │ - * {<OpenLayers.Feature.Vector>} Vertex currently being modified. │ │ │ │ + * APIProperty: drillDown │ │ │ │ + * {Boolean} Drill down over all WMTS layers in the map. When │ │ │ │ + * using drillDown mode, hover is not possible. A getfeatureinfo event │ │ │ │ + * will be fired for each layer queried. │ │ │ │ */ │ │ │ │ - vertex: null, │ │ │ │ + drillDown: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: vertices │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} Verticies currently available │ │ │ │ - * for dragging. │ │ │ │ + * APIProperty: maxFeatures │ │ │ │ + * {Integer} Maximum number of features to return from a WMTS query. This │ │ │ │ + * sets the feature_count parameter on WMTS GetFeatureInfo │ │ │ │ + * requests. │ │ │ │ */ │ │ │ │ - vertices: null, │ │ │ │ + maxFeatures: 10, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: virtualVertices │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} Virtual vertices in the middle │ │ │ │ - * of each edge. │ │ │ │ + /** APIProperty: clickCallback │ │ │ │ + * {String} The click callback to register in the │ │ │ │ + * {<OpenLayers.Handler.Click>} object created when the hover │ │ │ │ + * option is set to false. Default is "click". │ │ │ │ */ │ │ │ │ - virtualVertices: null, │ │ │ │ + clickCallback: "click", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: handlers │ │ │ │ - * {Object} │ │ │ │ + * Property: layers │ │ │ │ + * {Array(<OpenLayers.Layer.WMTS>)} The layers to query for feature info. │ │ │ │ + * If omitted, all map WMTS layers will be considered. │ │ │ │ */ │ │ │ │ - handlers: null, │ │ │ │ + layers: 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. │ │ │ │ + * APIProperty: queryVisible │ │ │ │ + * {Boolean} Filter out hidden layers when searching the map for layers to │ │ │ │ + * query. Default is true. │ │ │ │ */ │ │ │ │ - deleteCodes: null, │ │ │ │ + queryVisible: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: virtualStyle │ │ │ │ - * {Object} A symbolizer to be used for virtual vertices. │ │ │ │ + * Property: infoFormat │ │ │ │ + * {String} The mimetype to request from the server │ │ │ │ */ │ │ │ │ - virtualStyle: null, │ │ │ │ + infoFormat: 'text/html', │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: vendorParams │ │ │ │ + * {Object} Additional parameters that will be added to the request, for │ │ │ │ + * WMTS implementations that support them. This could e.g. look like │ │ │ │ + * (start code) │ │ │ │ + * { │ │ │ │ + * radius: 5 │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ */ │ │ │ │ - vertexRenderIntent: null, │ │ │ │ + vendorParams: {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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) │ │ │ │ + * Property: format │ │ │ │ + * {<OpenLayers.Format>} A format for parsing GetFeatureInfo responses. │ │ │ │ + * Default is <OpenLayers.Format.WMSGetFeatureInfo>. │ │ │ │ */ │ │ │ │ - mode: null, │ │ │ │ + format: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: createVertices │ │ │ │ - * {Boolean} Create new vertices by dragging the virtual vertices │ │ │ │ - * in the middle of each edge. Default is true. │ │ │ │ + * Property: formatOptions │ │ │ │ + * {Object} Optional properties to set on the format (if one is not provided │ │ │ │ + * in the <format> property. │ │ │ │ */ │ │ │ │ - createVertices: true, │ │ │ │ + formatOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: modified │ │ │ │ - * {Boolean} The currently selected feature has been modified. │ │ │ │ + * APIProperty: handlerOptions │ │ │ │ + * {Object} Additional options for the handlers used by this control, e.g. │ │ │ │ + * (start code) │ │ │ │ + * { │ │ │ │ + * "click": {delay: 100}, │ │ │ │ + * "hover": {delay: 300} │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ */ │ │ │ │ - modified: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: radiusHandle │ │ │ │ - * {<OpenLayers.Feature.Vector>} A handle for rotating/resizing a feature. │ │ │ │ + * Property: handler │ │ │ │ + * {Object} Reference to the <OpenLayers.Handler> for this control │ │ │ │ */ │ │ │ │ - radiusHandle: null, │ │ │ │ + handler: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: dragHandle │ │ │ │ - * {<OpenLayers.Feature.Vector>} A handle for dragging a feature. │ │ │ │ + * Property: hoverRequest │ │ │ │ + * {<OpenLayers.Request>} contains the currently running hover request │ │ │ │ + * (if any). │ │ │ │ */ │ │ │ │ - dragHandle: null, │ │ │ │ + hoverRequest: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: onModificationStart │ │ │ │ - * {Function} *Deprecated*. Register for "beforefeaturemodified" instead. │ │ │ │ - * The "beforefeaturemodified" event is triggered on the layer before │ │ │ │ - * any modification begins. │ │ │ │ + /** │ │ │ │ + * APIProperty: events │ │ │ │ + * {<OpenLayers.Events>} Events instance for listeners and triggering │ │ │ │ + * control specific events. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Register a listener for a particular event with the following syntax: │ │ │ │ + * (code) │ │ │ │ + * control.events.register(type, obj, listener); │ │ │ │ + * (end) │ │ │ │ * │ │ │ │ - * Optional function to be called when a feature has been │ │ │ │ - * modified. The function should expect to be called with a feature. │ │ │ │ + * Supported event types (in addition to those from <OpenLayers.Control.events>): │ │ │ │ + * beforegetfeatureinfo - Triggered before each request is sent. │ │ │ │ + * The event object has an *xy* property with the position of the │ │ │ │ + * mouse click or hover event that triggers the request and a *layer* │ │ │ │ + * property referencing the layer about to be queried. If a listener │ │ │ │ + * returns false, the request will not be issued. │ │ │ │ + * getfeatureinfo - Triggered when a GetFeatureInfo response is received. │ │ │ │ + * The event object has a *text* property with the body of the │ │ │ │ + * response (String), a *features* property with an array of the │ │ │ │ + * parsed features, an *xy* property with the position of the mouse │ │ │ │ + * click or hover event that triggered the request, a *layer* property │ │ │ │ + * referencing the layer queried and a *request* property with the │ │ │ │ + * request itself. If drillDown is set to true, one event will be fired │ │ │ │ + * for each layer queried. │ │ │ │ + * exception - Triggered when a GetFeatureInfo request fails (with a │ │ │ │ + * status other than 200) or whenparsing fails. Listeners will receive │ │ │ │ + * an event with *request*, *xy*, and *layer* properties. In the case │ │ │ │ + * of a parsing error, the event will also contain an *error* property. │ │ │ │ */ │ │ │ │ - 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. │ │ │ │ + /** │ │ │ │ + * Property: pending │ │ │ │ + * {Number} The number of pending requests. │ │ │ │ */ │ │ │ │ - onModificationEnd: function() {}, │ │ │ │ + pending: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.ModifyFeature │ │ │ │ - * Create a new modify feature control. │ │ │ │ + * Constructor: <OpenLayers.Control.WMTSGetFeatureInfo> │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ - initialize: function(layer, options) { │ │ │ │ + initialize: function(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 │ │ │ │ - }; │ │ │ │ + options.handlerOptions = options.handlerOptions || {}; │ │ │ │ │ │ │ │ - // 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) │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 │ │ │ │ - }); │ │ │ │ + if (!this.format) { │ │ │ │ + this.format = new OpenLayers.Format.WMSGetFeatureInfo( │ │ │ │ + options.formatOptions │ │ │ │ + ); │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + if (this.drillDown === true) { │ │ │ │ + this.hover = false; │ │ │ │ } │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - ); │ │ │ │ + if (this.hover) { │ │ │ │ + this.handler = new OpenLayers.Handler.Hover( │ │ │ │ + this, { │ │ │ │ + move: this.cancelHover, │ │ │ │ + pause: this.getInfoForHover │ │ │ │ + }, │ │ │ │ + OpenLayers.Util.extend( │ │ │ │ + this.handlerOptions.hover || {}, { │ │ │ │ + delay: 250 │ │ │ │ + } │ │ │ │ + ) │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + var callbacks = {}; │ │ │ │ + callbacks[this.clickCallback] = this.getInfoForClick; │ │ │ │ + this.handler = new OpenLayers.Handler.Click( │ │ │ │ + this, callbacks, this.handlerOptions.click || {} │ │ │ │ + ); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: getInfoForClick │ │ │ │ + * Called on click │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} the selected feature. │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ + getInfoForClick: function(evt) { │ │ │ │ + this.request(evt.xy, {}); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: unselectFeature │ │ │ │ - * Called when the select feature control unselects a feature. │ │ │ │ + * Method: getInfoForHover │ │ │ │ + * Pause callback for the hover handler │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The unselected feature. │ │ │ │ + * evt - {Object} │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + getInfoForHover: function(evt) { │ │ │ │ + this.request(evt.xy, { │ │ │ │ + hover: true │ │ │ │ }); │ │ │ │ - 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. │ │ │ │ + * Method: cancelHover │ │ │ │ + * Cancel callback for the hover handler │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + cancelHover: function() { │ │ │ │ + if (this.hoverRequest) { │ │ │ │ + --this.pending; │ │ │ │ + if (this.pending <= 0) { │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + this.pending = 0; │ │ │ │ } │ │ │ │ - this.selectFeature(feature); │ │ │ │ - } │ │ │ │ - if (feature._sketch || isPoint) { │ │ │ │ - // feature is a drag or virtual handle or point │ │ │ │ - this.vertex = feature; │ │ │ │ - this.handlers.drag.stopDown = true; │ │ │ │ + this.hoverRequest.abort(); │ │ │ │ + this.hoverRequest = null; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: findLayers │ │ │ │ + * Internal method to get the layers, independent of whether we are │ │ │ │ + * inspecting the map or using a client-provided array │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + findLayers: function() { │ │ │ │ + var candidates = this.layers || this.map.layers; │ │ │ │ + var layers = []; │ │ │ │ + var layer; │ │ │ │ + for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ + layer = candidates[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.WMTS && │ │ │ │ + layer.requestEncoding === this.requestEncoding && │ │ │ │ + (!this.queryVisible || layer.getVisibility())) { │ │ │ │ + layers.push(layer); │ │ │ │ + if (!this.drillDown || this.hover) { │ │ │ │ + break; │ │ │ │ } │ │ │ │ - } 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); │ │ │ │ + return layers; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: dragComplete │ │ │ │ - * Called by the drag handler when the feature dragging is complete. │ │ │ │ + * Method: buildRequestOptions │ │ │ │ + * Build an object with the relevant options for the GetFeatureInfo request. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged. │ │ │ │ + * layer - {<OpenLayers.Layer.WMTS>} A WMTS layer. │ │ │ │ + * xy - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ + * mouse event occurred. │ │ │ │ */ │ │ │ │ - dragComplete: function(vertex) { │ │ │ │ - this.resetVertices(); │ │ │ │ - this.setFeatureState(); │ │ │ │ - this.onModification(this.feature); │ │ │ │ - this.layer.events.triggerEvent("featuremodified", { │ │ │ │ - feature: this.feature │ │ │ │ + buildRequestOptions: function(layer, xy) { │ │ │ │ + var loc = this.map.getLonLatFromPixel(xy); │ │ │ │ + var getTileUrl = layer.getURL( │ │ │ │ + new OpenLayers.Bounds(loc.lon, loc.lat, loc.lon, loc.lat) │ │ │ │ + ); │ │ │ │ + var params = OpenLayers.Util.getParameters(getTileUrl); │ │ │ │ + var tileInfo = layer.getTileInfo(loc); │ │ │ │ + OpenLayers.Util.extend(params, { │ │ │ │ + service: "WMTS", │ │ │ │ + version: layer.version, │ │ │ │ + request: "GetFeatureInfo", │ │ │ │ + infoFormat: this.infoFormat, │ │ │ │ + i: tileInfo.i, │ │ │ │ + j: tileInfo.j │ │ │ │ }); │ │ │ │ + OpenLayers.Util.applyDefaults(params, this.vendorParams); │ │ │ │ + return { │ │ │ │ + url: OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url, │ │ │ │ + params: OpenLayers.Util.upperCaseObject(params), │ │ │ │ + callback: function(request) { │ │ │ │ + this.handleResponse(xy, request, layer); │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + * Method: request │ │ │ │ + * Sends a GetFeatureInfo request to the WMTS │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} Keypress event. │ │ │ │ + * xy - {<OpenLayers.Pixel>} The position on the map where the mouse event │ │ │ │ + * occurred. │ │ │ │ + * options - {Object} additional options for this method. │ │ │ │ + * │ │ │ │ + * Valid options: │ │ │ │ + * - *hover* {Boolean} true if we do the request for the hover handler │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + request: function(xy, options) { │ │ │ │ + options = options || {}; │ │ │ │ + var layers = this.findLayers(); │ │ │ │ + if (layers.length > 0) { │ │ │ │ + var issue, layer; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + layer = layers[i]; │ │ │ │ + issue = this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ + xy: xy, │ │ │ │ + layer: layer │ │ │ │ }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - } │ │ │ │ + if (issue !== false) { │ │ │ │ + ++this.pending; │ │ │ │ + var requestOptions = this.buildRequestOptions(layer, xy); │ │ │ │ + var request = OpenLayers.Request.GET(requestOptions); │ │ │ │ + if (options.hover === true) { │ │ │ │ + this.hoverRequest = request; │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ - } │ │ │ │ - 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); │ │ │ │ + if (this.pending > 0) { │ │ │ │ + OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ } │ │ │ │ - }; │ │ │ │ - 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 │ │ │ │ + * Method: handleResponse │ │ │ │ + * Handler for the GetFeatureInfo response. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Object} │ │ │ │ + * xy - {<OpenLayers.Pixel>} The position on the map where the mouse event │ │ │ │ + * occurred. │ │ │ │ + * request - {XMLHttpRequest} The request object. │ │ │ │ + * layer - {<OpenLayers.Layer.WMTS>} The queried layer. │ │ │ │ */ │ │ │ │ - handleMapEvents: function(evt) { │ │ │ │ - if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ - this.moveLayerToTop(); │ │ │ │ + handleResponse: function(xy, request, layer) { │ │ │ │ + --this.pending; │ │ │ │ + if (this.pending <= 0) { │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + this.pending = 0; │ │ │ │ } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + if (request.status && (request.status < 200 || request.status >= 300)) { │ │ │ │ + this.events.triggerEvent("exception", { │ │ │ │ + xy: xy, │ │ │ │ + request: request, │ │ │ │ + layer: layer │ │ │ │ + }); │ │ │ │ } else { │ │ │ │ - this.map.setLayerZIndex(this.layer, │ │ │ │ - this.map.getLayerIndex(this.layer)); │ │ │ │ + var doc = request.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = request.responseText; │ │ │ │ + } │ │ │ │ + var features, except; │ │ │ │ + try { │ │ │ │ + features = this.format.read(doc); │ │ │ │ + } catch (error) { │ │ │ │ + except = true; │ │ │ │ + this.events.triggerEvent("exception", { │ │ │ │ + xy: xy, │ │ │ │ + request: request, │ │ │ │ + error: error, │ │ │ │ + layer: layer │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + if (!except) { │ │ │ │ + this.events.triggerEvent("getfeatureinfo", { │ │ │ │ + text: request.responseText, │ │ │ │ + features: features, │ │ │ │ + request: request, │ │ │ │ + xy: xy, │ │ │ │ + layer: layer │ │ │ │ + }); │ │ │ │ + } │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ModifyFeature" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.WMTSGetFeatureInfo" │ │ │ │ }); │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * 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/Control/Pan.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 │ │ │ │ @@ -61042,14 +66072,462 @@ │ │ │ │ new OpenLayers.Control.Pan(OpenLayers.Control.Pan.WEST, options) │ │ │ │ ]); │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Control.PanPanel" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ + OpenLayers/Control/ArgParser.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.ArgParser │ │ │ │ + * The ArgParser control adds location bar query string parsing functionality │ │ │ │ + * to an OpenLayers Map. │ │ │ │ + * When added to a Map control, on a page load/refresh, the Map will │ │ │ │ + * automatically take the href string and parse it for lon, lat, zoom, and │ │ │ │ + * layers information. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: center │ │ │ │ + * {<OpenLayers.LonLat>} │ │ │ │ + */ │ │ │ │ + center: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: zoom │ │ │ │ + * {int} │ │ │ │ + */ │ │ │ │ + zoom: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: layers │ │ │ │ + * {String} Each character represents the state of the corresponding layer │ │ │ │ + * on the map. │ │ │ │ + */ │ │ │ │ + layers: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: displayProjection │ │ │ │ + * {<OpenLayers.Projection>} Requires proj4js support. │ │ │ │ + * Projection used when reading the coordinates from the URL. This will │ │ │ │ + * reproject the map coordinates from the URL into the map's │ │ │ │ + * projection. │ │ │ │ + * │ │ │ │ + * If you are using this functionality, be aware that any permalink │ │ │ │ + * which is added to the map will determine the coordinate type which │ │ │ │ + * is read from the URL, which means you should not add permalinks with │ │ │ │ + * different displayProjections to the same map. │ │ │ │ + */ │ │ │ │ + displayProjection: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.ArgParser │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getParameters │ │ │ │ + */ │ │ │ │ + getParameters: function(url) { │ │ │ │ + url = url || window.location.href; │ │ │ │ + var parameters = OpenLayers.Util.getParameters(url); │ │ │ │ + │ │ │ │ + // If we have an anchor in the url use it to split the url │ │ │ │ + var index = url.indexOf('#'); │ │ │ │ + if (index > 0) { │ │ │ │ + // create an url to parse on the getParameters │ │ │ │ + url = '?' + url.substring(index + 1, url.length); │ │ │ │ + │ │ │ │ + OpenLayers.Util.extend(parameters, │ │ │ │ + OpenLayers.Util.getParameters(url)); │ │ │ │ + } │ │ │ │ + return parameters; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ + * Set the map property for the control. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + │ │ │ │ + //make sure we dont already have an arg parser attached │ │ │ │ + for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ + var control = this.map.controls[i]; │ │ │ │ + if ((control != this) && │ │ │ │ + (control.CLASS_NAME == "OpenLayers.Control.ArgParser")) { │ │ │ │ + │ │ │ │ + // If a second argparser is added to the map, then we │ │ │ │ + // override the displayProjection to be the one added to the │ │ │ │ + // map. │ │ │ │ + if (control.displayProjection != this.displayProjection) { │ │ │ │ + this.displayProjection = control.displayProjection; │ │ │ │ + } │ │ │ │ + │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (i == this.map.controls.length) { │ │ │ │ + │ │ │ │ + var args = this.getParameters(); │ │ │ │ + // Be careful to set layer first, to not trigger unnecessary layer loads │ │ │ │ + if (args.layers) { │ │ │ │ + this.layers = args.layers; │ │ │ │ + │ │ │ │ + // when we add a new layer, set its visibility │ │ │ │ + this.map.events.register('addlayer', this, │ │ │ │ + this.configureLayers); │ │ │ │ + this.configureLayers(); │ │ │ │ + } │ │ │ │ + if (args.lat && args.lon) { │ │ │ │ + this.center = new OpenLayers.LonLat(parseFloat(args.lon), │ │ │ │ + parseFloat(args.lat)); │ │ │ │ + if (args.zoom) { │ │ │ │ + this.zoom = parseFloat(args.zoom); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // when we add a new baselayer to see when we can set the center │ │ │ │ + this.map.events.register('changebaselayer', this, │ │ │ │ + this.setCenter); │ │ │ │ + this.setCenter(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setCenter │ │ │ │ + * As soon as a baseLayer has been loaded, we center and zoom │ │ │ │ + * ...and remove the handler. │ │ │ │ + */ │ │ │ │ + setCenter: function() { │ │ │ │ + │ │ │ │ + if (this.map.baseLayer) { │ │ │ │ + //dont need to listen for this one anymore │ │ │ │ + this.map.events.unregister('changebaselayer', this, │ │ │ │ + this.setCenter); │ │ │ │ + │ │ │ │ + if (this.displayProjection) { │ │ │ │ + this.center.transform(this.displayProjection, │ │ │ │ + this.map.getProjectionObject()); │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.map.setCenter(this.center, this.zoom); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: configureLayers │ │ │ │ + * As soon as all the layers are loaded, cycle through them and │ │ │ │ + * hide or show them. │ │ │ │ + */ │ │ │ │ + configureLayers: function() { │ │ │ │ + │ │ │ │ + if (this.layers.length == this.map.layers.length) { │ │ │ │ + this.map.events.unregister('addlayer', this, this.configureLayers); │ │ │ │ + │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ + │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + var c = this.layers.charAt(i); │ │ │ │ + │ │ │ │ + if (c == "B") { │ │ │ │ + this.map.setBaseLayer(layer); │ │ │ │ + } else if ((c == "T") || (c == "F")) { │ │ │ │ + layer.setVisibility(c == "T"); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ArgParser" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/Permalink.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/Control/ArgParser.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.Permalink │ │ │ │ + * The Permalink control is hyperlink that will return the user to the │ │ │ │ + * current map view. By default it is drawn in the lower right corner of the │ │ │ │ + * map. The href is updated as the map is zoomed, panned and whilst layers │ │ │ │ + * are switched. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: argParserClass │ │ │ │ + * {Class} The ArgParser control class (not instance) to use with this │ │ │ │ + * control. │ │ │ │ + */ │ │ │ │ + argParserClass: OpenLayers.Control.ArgParser, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: element │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + element: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: anchor │ │ │ │ + * {Boolean} This option changes 3 things: │ │ │ │ + * the character '#' is used in place of the character '?', │ │ │ │ + * the window.href is updated if no element is provided. │ │ │ │ + * When this option is set to true it's not recommend to provide │ │ │ │ + * a base without provide an element. │ │ │ │ + */ │ │ │ │ + anchor: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: base │ │ │ │ + * {String} │ │ │ │ + */ │ │ │ │ + base: '', │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: displayProjection │ │ │ │ + * {<OpenLayers.Projection>} Requires proj4js support. Projection used │ │ │ │ + * when creating the coordinates in the link. This will reproject the │ │ │ │ + * map coordinates into display coordinates. If you are using this │ │ │ │ + * functionality, the permalink which is last added to the map will │ │ │ │ + * determine the coordinate type which is read from the URL, which │ │ │ │ + * means you should not add permalinks with different │ │ │ │ + * displayProjections to the same map. │ │ │ │ + */ │ │ │ │ + displayProjection: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.Permalink │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * element - {DOMElement} │ │ │ │ + * base - {String} │ │ │ │ + * options - {Object} options to the control. │ │ │ │ + * │ │ │ │ + * Or for anchor: │ │ │ │ + * options - {Object} options to the control. │ │ │ │ + */ │ │ │ │ + initialize: function(element, base, options) { │ │ │ │ + if (element !== null && typeof element == 'object' && !OpenLayers.Util.isElement(element)) { │ │ │ │ + options = element; │ │ │ │ + this.base = document.location.href; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + if (this.element != null) { │ │ │ │ + this.element = OpenLayers.Util.getElement(this.element); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.element = OpenLayers.Util.getElement(element); │ │ │ │ + this.base = base || document.location.href; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + if (this.element && this.element.parentNode == this.div) { │ │ │ │ + this.div.removeChild(this.element); │ │ │ │ + this.element = null; │ │ │ │ + } │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.unregister('moveend', this, this.updateLink); │ │ │ │ + } │ │ │ │ + │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ + * Set the map property for the control. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + │ │ │ │ + //make sure we have an arg parser attached │ │ │ │ + for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ + var control = this.map.controls[i]; │ │ │ │ + if (control.CLASS_NAME == this.argParserClass.CLASS_NAME) { │ │ │ │ + │ │ │ │ + // If a permalink is added to the map, and an ArgParser already │ │ │ │ + // exists, we override the displayProjection to be the one │ │ │ │ + // on the permalink. │ │ │ │ + if (control.displayProjection != this.displayProjection) { │ │ │ │ + this.displayProjection = control.displayProjection; │ │ │ │ + } │ │ │ │ + │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (i == this.map.controls.length) { │ │ │ │ + this.map.addControl(new this.argParserClass({ │ │ │ │ + 'displayProjection': this.displayProjection │ │ │ │ + })); │ │ │ │ + } │ │ │ │ + │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: draw │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + │ │ │ │ + if (!this.element && !this.anchor) { │ │ │ │ + this.element = document.createElement("a"); │ │ │ │ + this.element.innerHTML = OpenLayers.i18n("Permalink"); │ │ │ │ + this.element.href = ""; │ │ │ │ + this.div.appendChild(this.element); │ │ │ │ + } │ │ │ │ + this.map.events.on({ │ │ │ │ + 'moveend': this.updateLink, │ │ │ │ + 'changelayer': this.updateLink, │ │ │ │ + 'changebaselayer': this.updateLink, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + │ │ │ │ + // Make it so there is at least a link even though the map may not have │ │ │ │ + // moved yet. │ │ │ │ + this.updateLink(); │ │ │ │ + │ │ │ │ + return this.div; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: updateLink │ │ │ │ + */ │ │ │ │ + updateLink: function() { │ │ │ │ + var separator = this.anchor ? '#' : '?'; │ │ │ │ + var href = this.base; │ │ │ │ + var anchor = null; │ │ │ │ + if (href.indexOf("#") != -1 && this.anchor == false) { │ │ │ │ + anchor = href.substring(href.indexOf("#"), href.length); │ │ │ │ + } │ │ │ │ + if (href.indexOf(separator) != -1) { │ │ │ │ + href = href.substring(0, href.indexOf(separator)); │ │ │ │ + } │ │ │ │ + var splits = href.split("#"); │ │ │ │ + href = splits[0] + separator + OpenLayers.Util.getParameterString(this.createParams()); │ │ │ │ + if (anchor) { │ │ │ │ + href += anchor; │ │ │ │ + } │ │ │ │ + if (this.anchor && !this.element) { │ │ │ │ + window.location.href = href; │ │ │ │ + } else { │ │ │ │ + this.element.href = href; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: createParams │ │ │ │ + * Creates the parameters that need to be encoded into the permalink url. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * center - {<OpenLayers.LonLat>} center to encode in the permalink. │ │ │ │ + * Defaults to the current map center. │ │ │ │ + * zoom - {Integer} zoom level to encode in the permalink. Defaults to the │ │ │ │ + * current map zoom level. │ │ │ │ + * layers - {Array(<OpenLayers.Layer>)} layers to encode in the permalink. │ │ │ │ + * Defaults to the current map layers. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} Hash of parameters that will be url-encoded into the │ │ │ │ + * permalink. │ │ │ │ + */ │ │ │ │ + createParams: function(center, zoom, layers) { │ │ │ │ + center = center || this.map.getCenter(); │ │ │ │ + │ │ │ │ + var params = OpenLayers.Util.getParameters(this.base); │ │ │ │ + │ │ │ │ + // If there's still no center, map is not initialized yet. │ │ │ │ + // Break out of this function, and simply return the params from the │ │ │ │ + // base link. │ │ │ │ + if (center) { │ │ │ │ + │ │ │ │ + //zoom │ │ │ │ + params.zoom = zoom || this.map.getZoom(); │ │ │ │ + │ │ │ │ + //lon,lat │ │ │ │ + var lat = center.lat; │ │ │ │ + var lon = center.lon; │ │ │ │ + │ │ │ │ + if (this.displayProjection) { │ │ │ │ + var mapPosition = OpenLayers.Projection.transform({ │ │ │ │ + x: lon, │ │ │ │ + y: lat │ │ │ │ + }, │ │ │ │ + this.map.getProjectionObject(), │ │ │ │ + this.displayProjection); │ │ │ │ + lon = mapPosition.x; │ │ │ │ + lat = mapPosition.y; │ │ │ │ + } │ │ │ │ + params.lat = Math.round(lat * 100000) / 100000; │ │ │ │ + params.lon = Math.round(lon * 100000) / 100000; │ │ │ │ + │ │ │ │ + //layers │ │ │ │ + layers = layers || this.map.layers; │ │ │ │ + params.layers = ''; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + var layer = layers[i]; │ │ │ │ + │ │ │ │ + if (layer.isBaseLayer) { │ │ │ │ + params.layers += (layer == this.map.baseLayer) ? "B" : "0"; │ │ │ │ + } else { │ │ │ │ + params.layers += (layer.getVisibility()) ? "T" : "F"; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + return params; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Permalink" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ OpenLayers/Control/GetFeature.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. */ │ │ │ │ @@ -61662,2639 +67140,996 @@ │ │ │ │ var ur = this.map.getLonLatFromPixel(urPx); │ │ │ │ return new OpenLayers.Bounds(ll.lon, ll.lat, ur.lon, ur.lat); │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Control.GetFeature" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/ZoomToMaxExtent.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/Button.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.ZoomToMaxExtent │ │ │ │ - * The ZoomToMaxExtent control is a button that zooms out to the maximum │ │ │ │ - * extent of the map. It is designed to be used with a │ │ │ │ - * <OpenLayers.Control.Panel>. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.ZoomToMaxExtent = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: trigger │ │ │ │ - * │ │ │ │ - * Called whenever this control is being rendered inside of a panel and a │ │ │ │ - * click occurs on this controls element. Actually zooms to the maximum │ │ │ │ - * extent of this controls map. │ │ │ │ - */ │ │ │ │ - trigger: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.zoomToMaxExtent(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomToMaxExtent" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/CacheRead.js │ │ │ │ + OpenLayers/Control/Graticule.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/Lang.js │ │ │ │ + * @requires OpenLayers/Rule.js │ │ │ │ + * @requires OpenLayers/StyleMap.js │ │ │ │ + * @requires OpenLayers/Layer/Vector.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.CacheRead │ │ │ │ - * A control for using image tiles cached with <OpenLayers.Control.CacheWrite> │ │ │ │ - * from the browser's local storage. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Control.Graticule │ │ │ │ + * The Graticule displays a grid of latitude/longitude lines reprojected on │ │ │ │ + * the map. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Control> │ │ │ │ + * │ │ │ │ */ │ │ │ │ -OpenLayers.Control.CacheRead = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: fetchEvent │ │ │ │ - * {String} The layer event to listen to for replacing remote resource tile │ │ │ │ - * URLs with cached data URIs. Supported values are "tileerror" (try │ │ │ │ - * remote first, fall back to cached) and "tileloadstart" (try cache │ │ │ │ - * first, fall back to remote). Default is "tileloadstart". │ │ │ │ - * │ │ │ │ - * Note that "tileerror" will not work for CORS enabled images (see │ │ │ │ - * https://developer.mozilla.org/en/CORS_Enabled_Image), i.e. layers │ │ │ │ - * configured with a <OpenLayers.Tile.Image.crossOriginKeyword> in │ │ │ │ - * <OpenLayers.Layer.Grid.tileOptions>. │ │ │ │ - */ │ │ │ │ - fetchEvent: "tileloadstart", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: layers │ │ │ │ - * {Array(<OpenLayers.Layer.Grid>)}. Optional. If provided, only these │ │ │ │ - * layers will receive tiles from the cache. │ │ │ │ - */ │ │ │ │ - layers: null, │ │ │ │ +OpenLayers.Control.Graticule = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * true. │ │ │ │ */ │ │ │ │ autoActivate: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.CacheRead │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Object with API properties for this control │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * Set the map property for the control. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ - */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - var i, layers = this.layers || map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.addLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - if (!this.layers) { │ │ │ │ - map.events.on({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: addLayer │ │ │ │ - * Adds a layer to the control. Once added, tiles requested for this layer │ │ │ │ - * will be cached. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} Object with a layer property referencing an │ │ │ │ - * <OpenLayers.Layer> instance │ │ │ │ - */ │ │ │ │ - addLayer: function(evt) { │ │ │ │ - evt.layer.events.register(this.fetchEvent, this, this.fetch); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: removeLayer │ │ │ │ - * Removes a layer from the control. Once removed, tiles requested for this │ │ │ │ - * layer will no longer be cached. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} Object with a layer property referencing an │ │ │ │ - * <OpenLayers.Layer> instance │ │ │ │ - */ │ │ │ │ - removeLayer: function(evt) { │ │ │ │ - evt.layer.events.unregister(this.fetchEvent, this, this.fetch); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: fetch │ │ │ │ - * Listener to the <fetchEvent> event. Replaces a tile's url with a data │ │ │ │ - * URI from the cache. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} Event object with a tile property. │ │ │ │ + * APIProperty: intervals │ │ │ │ + * {Array(Float)} A list of possible graticule widths in degrees. │ │ │ │ */ │ │ │ │ - fetch: function(evt) { │ │ │ │ - if (this.active && window.localStorage && │ │ │ │ - evt.tile instanceof OpenLayers.Tile.Image) { │ │ │ │ - var tile = evt.tile, │ │ │ │ - url = tile.url; │ │ │ │ - // deal with modified tile urls when both CacheWrite and CacheRead │ │ │ │ - // are active │ │ │ │ - if (!tile.layer.crossOriginKeyword && OpenLayers.ProxyHost && │ │ │ │ - url.indexOf(OpenLayers.ProxyHost) === 0) { │ │ │ │ - url = OpenLayers.Control.CacheWrite.urlMap[url]; │ │ │ │ - } │ │ │ │ - var dataURI = window.localStorage.getItem("olCache_" + url); │ │ │ │ - if (dataURI) { │ │ │ │ - tile.url = dataURI; │ │ │ │ - if (evt.type === "tileerror") { │ │ │ │ - tile.setImgSrc(dataURI); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + intervals: [45, 30, 20, 10, 5, 2, 1, │ │ │ │ + 0.5, 0.2, 0.1, 0.05, 0.01, │ │ │ │ + 0.005, 0.002, 0.001 │ │ │ │ + ], │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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.layers || this.map) { │ │ │ │ - var i, layers = this.layers || this.map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.removeLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.un({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.CacheRead" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/LayerSwitcher.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/Lang.js │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ - * @requires OpenLayers/Events/buttonclick.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.LayerSwitcher │ │ │ │ - * The LayerSwitcher control displays a table of contents for the map. This │ │ │ │ - * allows the user interface to switch between BaseLasyers and to show or hide │ │ │ │ - * Overlays. By default the switcher is shown minimized on the right edge of │ │ │ │ - * the map, the user may expand it by clicking on the handle. │ │ │ │ - * │ │ │ │ - * To create the LayerSwitcher outside of the map, pass the Id of a html div │ │ │ │ - * as the first argument to the constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.LayerSwitcher = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: layerStates │ │ │ │ - * {Array(Object)} Basically a copy of the "state" of the map's layers │ │ │ │ - * the last time the control was drawn. We have this in order to avoid │ │ │ │ - * unnecessarily redrawing the control. │ │ │ │ + * APIProperty: displayInLayerSwitcher │ │ │ │ + * {Boolean} Allows the Graticule control to be switched on and off by │ │ │ │ + * LayerSwitcher control. Defaults is true. │ │ │ │ */ │ │ │ │ - layerStates: null, │ │ │ │ - │ │ │ │ - // DOM Elements │ │ │ │ + displayInLayerSwitcher: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: layersDiv │ │ │ │ - * {DOMElement} │ │ │ │ + * APIProperty: visible │ │ │ │ + * {Boolean} should the graticule be initially visible (default=true) │ │ │ │ */ │ │ │ │ - layersDiv: null, │ │ │ │ + visible: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: baseLayersDiv │ │ │ │ - * {DOMElement} │ │ │ │ + * APIProperty: numPoints │ │ │ │ + * {Integer} The number of points to use in each graticule line. Higher │ │ │ │ + * numbers result in a smoother curve for projected maps │ │ │ │ */ │ │ │ │ - baseLayersDiv: null, │ │ │ │ + numPoints: 50, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: baseLayers │ │ │ │ - * {Array(Object)} │ │ │ │ + * APIProperty: targetSize │ │ │ │ + * {Integer} The maximum size of the grid in pixels on the map │ │ │ │ */ │ │ │ │ - baseLayers: null, │ │ │ │ - │ │ │ │ + targetSize: 200, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: dataLbl │ │ │ │ - * {DOMElement} │ │ │ │ + * APIProperty: layerName │ │ │ │ + * {String} The name to be displayed in the layer switcher, default is set │ │ │ │ + * by {<OpenLayers.Lang>}. │ │ │ │ */ │ │ │ │ - dataLbl: null, │ │ │ │ + layerName: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: dataLayersDiv │ │ │ │ - * {DOMElement} │ │ │ │ + * APIProperty: labelled │ │ │ │ + * {Boolean} Should the graticule lines be labelled?. default=true │ │ │ │ */ │ │ │ │ - dataLayersDiv: null, │ │ │ │ + labelled: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: dataLayers │ │ │ │ - * {Array(Object)} │ │ │ │ + * APIProperty: labelFormat │ │ │ │ + * {String} the format of the labels, default = 'dm'. See │ │ │ │ + * <OpenLayers.Util.getFormattedLonLat> for other options. │ │ │ │ */ │ │ │ │ - dataLayers: null, │ │ │ │ - │ │ │ │ + labelFormat: 'dm', │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: minimizeDiv │ │ │ │ - * {DOMElement} │ │ │ │ + * APIProperty: lineSymbolizer │ │ │ │ + * {symbolizer} the symbolizer used to render lines │ │ │ │ */ │ │ │ │ - minimizeDiv: null, │ │ │ │ + lineSymbolizer: { │ │ │ │ + strokeColor: "#333", │ │ │ │ + strokeWidth: 1, │ │ │ │ + strokeOpacity: 0.5 │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: maximizeDiv │ │ │ │ - * {DOMElement} │ │ │ │ + * APIProperty: labelSymbolizer │ │ │ │ + * {symbolizer} the symbolizer used to render labels │ │ │ │ */ │ │ │ │ - maximizeDiv: null, │ │ │ │ + labelSymbolizer: {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: ascending │ │ │ │ - * {Boolean} │ │ │ │ + * Property: gratLayer │ │ │ │ + * {<OpenLayers.Layer.Vector>} vector layer used to draw the graticule on │ │ │ │ */ │ │ │ │ - ascending: true, │ │ │ │ + gratLayer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.LayerSwitcher │ │ │ │ - * │ │ │ │ + * Constructor: OpenLayers.Control.Graticule │ │ │ │ + * Create a new graticule control to display a grid of latitude longitude │ │ │ │ + * lines. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ + * options - {Object} An optional object whose properties will be used │ │ │ │ + * to extend the control. │ │ │ │ */ │ │ │ │ initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ - this.layerStates = []; │ │ │ │ + options = options || {}; │ │ │ │ + options.layerName = options.layerName || OpenLayers.i18n("Graticule"); │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + │ │ │ │ + this.labelSymbolizer.stroke = false; │ │ │ │ + this.labelSymbolizer.fill = false; │ │ │ │ + this.labelSymbolizer.label = "${label}"; │ │ │ │ + this.labelSymbolizer.labelAlign = "${labelAlign}"; │ │ │ │ + this.labelSymbolizer.labelXOffset = "${xOffset}"; │ │ │ │ + this.labelSymbolizer.labelYOffset = "${yOffset}"; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: destroy │ │ │ │ */ │ │ │ │ destroy: function() { │ │ │ │ - │ │ │ │ - //clear out layers info and unregister their events │ │ │ │ - this.clearLayersArray("base"); │ │ │ │ - this.clearLayersArray("data"); │ │ │ │ - │ │ │ │ - this.map.events.un({ │ │ │ │ - buttonclick: this.onButtonClick, │ │ │ │ - addlayer: this.redraw, │ │ │ │ - changelayer: this.redraw, │ │ │ │ - removelayer: this.redraw, │ │ │ │ - changebaselayer: this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ - │ │ │ │ + this.deactivate(); │ │ │ │ OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * │ │ │ │ - * Properties: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ - */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - │ │ │ │ - this.map.events.on({ │ │ │ │ - addlayer: this.redraw, │ │ │ │ - changelayer: this.redraw, │ │ │ │ - removelayer: this.redraw, │ │ │ │ - changebaselayer: this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - if (this.outsideViewport) { │ │ │ │ - this.events.attachToElement(this.div); │ │ │ │ - this.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ - } else { │ │ │ │ - this.map.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ + if (this.gratLayer) { │ │ │ │ + this.gratLayer.destroy(); │ │ │ │ + this.gratLayer = null; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * Method: draw │ │ │ │ * │ │ │ │ + * initializes the graticule layer and does the initial update │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} A reference to the DIV DOMElement containing the │ │ │ │ - * switcher tabs. │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this); │ │ │ │ - │ │ │ │ - // create layout divs │ │ │ │ - this.loadContents(); │ │ │ │ - │ │ │ │ - // set mode to minimize │ │ │ │ - if (!this.outsideViewport) { │ │ │ │ - this.minimizeControl(); │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (!this.gratLayer) { │ │ │ │ + var gratStyle = new OpenLayers.Style({}, { │ │ │ │ + rules: [new OpenLayers.Rule({ │ │ │ │ + 'symbolizer': { │ │ │ │ + "Point": this.labelSymbolizer, │ │ │ │ + "Line": this.lineSymbolizer │ │ │ │ + } │ │ │ │ + })] │ │ │ │ + }); │ │ │ │ + this.gratLayer = new OpenLayers.Layer.Vector(this.layerName, { │ │ │ │ + styleMap: new OpenLayers.StyleMap({ │ │ │ │ + 'default': gratStyle │ │ │ │ + }), │ │ │ │ + visibility: this.visible, │ │ │ │ + displayInLayerSwitcher: this.displayInLayerSwitcher │ │ │ │ + }); │ │ │ │ } │ │ │ │ - │ │ │ │ - // populate div with current info │ │ │ │ - this.redraw(); │ │ │ │ - │ │ │ │ return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onButtonClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - */ │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - var button = evt.buttonElement; │ │ │ │ - if (button === this.minimizeDiv) { │ │ │ │ - this.minimizeControl(); │ │ │ │ - } else if (button === this.maximizeDiv) { │ │ │ │ - this.maximizeControl(); │ │ │ │ - } else if (button._layerSwitcher === this.id) { │ │ │ │ - if (button["for"]) { │ │ │ │ - button = document.getElementById(button["for"]); │ │ │ │ - } │ │ │ │ - if (!button.disabled) { │ │ │ │ - if (button.type == "radio") { │ │ │ │ - button.checked = true; │ │ │ │ - this.map.setBaseLayer(this.map.getLayer(button._layer)); │ │ │ │ - } else { │ │ │ │ - button.checked = !button.checked; │ │ │ │ - this.updateMap(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: clearLayersArray │ │ │ │ - * User specifies either "base" or "data". we then clear all the │ │ │ │ - * corresponding listeners, the div, and reinitialize a new array. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layersType - {String} │ │ │ │ - */ │ │ │ │ - clearLayersArray: function(layersType) { │ │ │ │ - this[layersType + "LayersDiv"].innerHTML = ""; │ │ │ │ - this[layersType + "Layers"] = []; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: checkRedraw │ │ │ │ - * Checks if the layer state has changed since the last redraw() call. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The layer state changed since the last redraw() call. │ │ │ │ + * APIMethod: activate │ │ │ │ */ │ │ │ │ - checkRedraw: function() { │ │ │ │ - if (!this.layerStates.length || │ │ │ │ - (this.map.layers.length != this.layerStates.length)) { │ │ │ │ + activate: function() { │ │ │ │ + if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.map.addLayer(this.gratLayer); │ │ │ │ + this.map.events.register('moveend', this, this.update); │ │ │ │ + this.update(); │ │ │ │ return true; │ │ │ │ - } │ │ │ │ - │ │ │ │ - for (var i = 0, len = this.layerStates.length; i < len; i++) { │ │ │ │ - var layerState = this.layerStates[i]; │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - if ((layerState.name != layer.name) || │ │ │ │ - (layerState.inRange != layer.inRange) || │ │ │ │ - (layerState.id != layer.id) || │ │ │ │ - (layerState.visibility != layer.visibility)) { │ │ │ │ - return true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return false; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: redraw │ │ │ │ - * Goes through and takes the current state of the Map and rebuilds the │ │ │ │ - * control to display that state. Groups base layers into a │ │ │ │ - * radio-button group and lists each data layer with a checkbox. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A reference to the DIV DOMElement containing the control │ │ │ │ - */ │ │ │ │ - redraw: function() { │ │ │ │ - //if the state hasn't changed since last redraw, no need │ │ │ │ - // to do anything. Just return the existing div. │ │ │ │ - if (!this.checkRedraw()) { │ │ │ │ - return this.div; │ │ │ │ - } │ │ │ │ - │ │ │ │ - //clear out previous layers │ │ │ │ - this.clearLayersArray("base"); │ │ │ │ - this.clearLayersArray("data"); │ │ │ │ - │ │ │ │ - var containsOverlays = false; │ │ │ │ - var containsBaseLayers = false; │ │ │ │ - │ │ │ │ - // Save state -- for checking layer if the map state changed. │ │ │ │ - // We save this before redrawing, because in the process of redrawing │ │ │ │ - // we will trigger more visibility changes, and we want to not redraw │ │ │ │ - // and enter an infinite loop. │ │ │ │ - var len = this.map.layers.length; │ │ │ │ - this.layerStates = new Array(len); │ │ │ │ - for (var i = 0; i < len; i++) { │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - this.layerStates[i] = { │ │ │ │ - 'name': layer.name, │ │ │ │ - 'visibility': layer.visibility, │ │ │ │ - 'inRange': layer.inRange, │ │ │ │ - 'id': layer.id │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var layers = this.map.layers.slice(); │ │ │ │ - if (!this.ascending) { │ │ │ │ - layers.reverse(); │ │ │ │ - } │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - var layer = layers[i]; │ │ │ │ - var baseLayer = layer.isBaseLayer; │ │ │ │ - │ │ │ │ - if (layer.displayInLayerSwitcher) { │ │ │ │ - │ │ │ │ - if (baseLayer) { │ │ │ │ - containsBaseLayers = true; │ │ │ │ - } else { │ │ │ │ - containsOverlays = true; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // only check a baselayer if it is *the* baselayer, check data │ │ │ │ - // layers if they are visible │ │ │ │ - var checked = (baseLayer) ? (layer == this.map.baseLayer) : │ │ │ │ - layer.getVisibility(); │ │ │ │ - │ │ │ │ - // create input element │ │ │ │ - var inputElem = document.createElement("input"), │ │ │ │ - // The input shall have an id attribute so we can use │ │ │ │ - // labels to interact with them. │ │ │ │ - inputId = OpenLayers.Util.createUniqueID( │ │ │ │ - this.id + "_input_" │ │ │ │ - ); │ │ │ │ - │ │ │ │ - inputElem.id = inputId; │ │ │ │ - inputElem.name = (baseLayer) ? this.id + "_baseLayers" : layer.name; │ │ │ │ - inputElem.type = (baseLayer) ? "radio" : "checkbox"; │ │ │ │ - inputElem.value = layer.name; │ │ │ │ - inputElem.checked = checked; │ │ │ │ - inputElem.defaultChecked = checked; │ │ │ │ - inputElem.className = "olButton"; │ │ │ │ - inputElem._layer = layer.id; │ │ │ │ - inputElem._layerSwitcher = this.id; │ │ │ │ - │ │ │ │ - if (!baseLayer && !layer.inRange) { │ │ │ │ - inputElem.disabled = true; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // create span │ │ │ │ - var labelSpan = document.createElement("label"); │ │ │ │ - // this isn't the DOM attribute 'for', but an arbitrary name we │ │ │ │ - // use to find the appropriate input element in <onButtonClick> │ │ │ │ - labelSpan["for"] = inputElem.id; │ │ │ │ - OpenLayers.Element.addClass(labelSpan, "labelSpan olButton"); │ │ │ │ - labelSpan._layer = layer.id; │ │ │ │ - labelSpan._layerSwitcher = this.id; │ │ │ │ - if (!baseLayer && !layer.inRange) { │ │ │ │ - labelSpan.style.color = "gray"; │ │ │ │ - } │ │ │ │ - labelSpan.innerHTML = layer.name; │ │ │ │ - labelSpan.style.verticalAlign = (baseLayer) ? "bottom" : │ │ │ │ - "baseline"; │ │ │ │ - // create line break │ │ │ │ - var br = document.createElement("br"); │ │ │ │ - │ │ │ │ - │ │ │ │ - var groupArray = (baseLayer) ? this.baseLayers : │ │ │ │ - this.dataLayers; │ │ │ │ - groupArray.push({ │ │ │ │ - 'layer': layer, │ │ │ │ - 'inputElem': inputElem, │ │ │ │ - 'labelSpan': labelSpan │ │ │ │ - }); │ │ │ │ - │ │ │ │ - │ │ │ │ - var groupDiv = (baseLayer) ? this.baseLayersDiv : │ │ │ │ - this.dataLayersDiv; │ │ │ │ - groupDiv.appendChild(inputElem); │ │ │ │ - groupDiv.appendChild(labelSpan); │ │ │ │ - groupDiv.appendChild(br); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // if no overlays, dont display the overlay label │ │ │ │ - this.dataLbl.style.display = (containsOverlays) ? "" : "none"; │ │ │ │ - │ │ │ │ - // if no baselayers, dont display the baselayer label │ │ │ │ - this.baseLbl.style.display = (containsBaseLayers) ? "" : "none"; │ │ │ │ - │ │ │ │ - return this.div; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: updateMap │ │ │ │ - * Cycles through the loaded data and base layer input arrays and makes │ │ │ │ - * the necessary calls to the Map object such that that the map's │ │ │ │ - * visual state corresponds to what the user has selected in │ │ │ │ - * the control. │ │ │ │ - */ │ │ │ │ - updateMap: function() { │ │ │ │ - │ │ │ │ - // set the newly selected base layer │ │ │ │ - for (var i = 0, len = this.baseLayers.length; i < len; i++) { │ │ │ │ - var layerEntry = this.baseLayers[i]; │ │ │ │ - if (layerEntry.inputElem.checked) { │ │ │ │ - this.map.setBaseLayer(layerEntry.layer, false); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // set the correct visibilities for the overlays │ │ │ │ - for (var i = 0, len = this.dataLayers.length; i < len; i++) { │ │ │ │ - var layerEntry = this.dataLayers[i]; │ │ │ │ - layerEntry.layer.setVisibility(layerEntry.inputElem.checked); │ │ │ │ - } │ │ │ │ - │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: maximizeControl │ │ │ │ - * Set up the labels and divs for the control │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {Event} │ │ │ │ - */ │ │ │ │ - maximizeControl: function(e) { │ │ │ │ - │ │ │ │ - // set the div's width and height to empty values, so │ │ │ │ - // the div dimensions can be controlled by CSS │ │ │ │ - this.div.style.width = ""; │ │ │ │ - this.div.style.height = ""; │ │ │ │ - │ │ │ │ - this.showControls(false); │ │ │ │ - │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: minimizeControl │ │ │ │ - * Hide all the contents of the control, shrink the size, │ │ │ │ - * add the maximize icon │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {Event} │ │ │ │ - */ │ │ │ │ - minimizeControl: function(e) { │ │ │ │ - │ │ │ │ - // to minimize the control we set its div's width │ │ │ │ - // and height to 0px, we cannot just set "display" │ │ │ │ - // to "none" because it would hide the maximize │ │ │ │ - // div │ │ │ │ - this.div.style.width = "0px"; │ │ │ │ - this.div.style.height = "0px"; │ │ │ │ - │ │ │ │ - this.showControls(true); │ │ │ │ - │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: showControls │ │ │ │ - * Hide/Show all LayerSwitcher controls depending on whether we are │ │ │ │ - * minimized or not │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * minimize - {Boolean} │ │ │ │ - */ │ │ │ │ - showControls: function(minimize) { │ │ │ │ - │ │ │ │ - this.maximizeDiv.style.display = minimize ? "" : "none"; │ │ │ │ - this.minimizeDiv.style.display = minimize ? "none" : ""; │ │ │ │ - │ │ │ │ - this.layersDiv.style.display = minimize ? "none" : ""; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: loadContents │ │ │ │ - * Set up the labels and divs for the control │ │ │ │ - */ │ │ │ │ - loadContents: function() { │ │ │ │ - │ │ │ │ - // layers list div │ │ │ │ - this.layersDiv = document.createElement("div"); │ │ │ │ - this.layersDiv.id = this.id + "_layersDiv"; │ │ │ │ - OpenLayers.Element.addClass(this.layersDiv, "layersDiv"); │ │ │ │ - │ │ │ │ - this.baseLbl = document.createElement("div"); │ │ │ │ - this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer"); │ │ │ │ - OpenLayers.Element.addClass(this.baseLbl, "baseLbl"); │ │ │ │ - │ │ │ │ - this.baseLayersDiv = document.createElement("div"); │ │ │ │ - OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv"); │ │ │ │ - │ │ │ │ - this.dataLbl = document.createElement("div"); │ │ │ │ - this.dataLbl.innerHTML = OpenLayers.i18n("Overlays"); │ │ │ │ - OpenLayers.Element.addClass(this.dataLbl, "dataLbl"); │ │ │ │ - │ │ │ │ - this.dataLayersDiv = document.createElement("div"); │ │ │ │ - OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv"); │ │ │ │ - │ │ │ │ - if (this.ascending) { │ │ │ │ - this.layersDiv.appendChild(this.baseLbl); │ │ │ │ - this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ - this.layersDiv.appendChild(this.dataLbl); │ │ │ │ - this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ } else { │ │ │ │ - this.layersDiv.appendChild(this.dataLbl); │ │ │ │ - this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ - this.layersDiv.appendChild(this.baseLbl); │ │ │ │ - this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ + return false; │ │ │ │ } │ │ │ │ - │ │ │ │ - this.div.appendChild(this.layersDiv); │ │ │ │ - │ │ │ │ - // maximize button div │ │ │ │ - var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png'); │ │ │ │ - this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ - "OpenLayers_Control_MaximizeDiv", │ │ │ │ - null, │ │ │ │ - null, │ │ │ │ - img, │ │ │ │ - "absolute"); │ │ │ │ - OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv olButton"); │ │ │ │ - this.maximizeDiv.style.display = "none"; │ │ │ │ - │ │ │ │ - this.div.appendChild(this.maximizeDiv); │ │ │ │ - │ │ │ │ - // minimize button div │ │ │ │ - var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png'); │ │ │ │ - this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ - "OpenLayers_Control_MinimizeDiv", │ │ │ │ - null, │ │ │ │ - null, │ │ │ │ - img, │ │ │ │ - "absolute"); │ │ │ │ - OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton"); │ │ │ │ - this.minimizeDiv.style.display = "none"; │ │ │ │ - │ │ │ │ - this.div.appendChild(this.minimizeDiv); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.LayerSwitcher" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/ZoomPanel.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/Panel.js │ │ │ │ - * @requires OpenLayers/Control/ZoomIn.js │ │ │ │ - * @requires OpenLayers/Control/ZoomOut.js │ │ │ │ - * @requires OpenLayers/Control/ZoomToMaxExtent.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.ZoomPanel │ │ │ │ - * The ZoomPanel control is a compact collecton of 3 zoom controls: a │ │ │ │ - * <OpenLayers.Control.ZoomIn>, a <OpenLayers.Control.ZoomToMaxExtent>, and a │ │ │ │ - * <OpenLayers.Control.ZoomOut>. By default it is drawn in the upper left │ │ │ │ - * corner of the map. │ │ │ │ - * │ │ │ │ - * Note: │ │ │ │ - * If you wish to use this class with the default images and you want │ │ │ │ - * it to look nice in ie6, you should add the following, conditionally │ │ │ │ - * added css stylesheet to your HTML file: │ │ │ │ - * │ │ │ │ - * (code) │ │ │ │ - * <!--[if lte IE 6]> │ │ │ │ - * <link rel="stylesheet" href="../theme/default/ie6-style.css" type="text/css" /> │ │ │ │ - * <![endif]--> │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control.Panel> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.ZoomPanel = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.ZoomPanel │ │ │ │ - * Add the three zooming controls. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be used │ │ │ │ - * to extend the control. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ - this.addControls([ │ │ │ │ - new OpenLayers.Control.ZoomIn(), │ │ │ │ - new OpenLayers.Control.ZoomToMaxExtent(), │ │ │ │ - new OpenLayers.Control.ZoomOut() │ │ │ │ - ]); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomPanel" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/WMTSGetFeatureInfo.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/Click.js │ │ │ │ - * @requires OpenLayers/Handler/Hover.js │ │ │ │ - * @requires OpenLayers/Request.js │ │ │ │ - * @requires OpenLayers/Format/WMSGetFeatureInfo.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.WMTSGetFeatureInfo │ │ │ │ - * The WMTSGetFeatureInfo control uses a WMTS query to get information about a │ │ │ │ - * point on the map. The information may be in a display-friendly format │ │ │ │ - * such as HTML, or a machine-friendly format such as GML, depending on the │ │ │ │ - * server's capabilities and the client's configuration. This control │ │ │ │ - * handles click or hover events, attempts to parse the results using an │ │ │ │ - * OpenLayers.Format, and fires a 'getfeatureinfo' event for each layer │ │ │ │ - * queried. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.WMTSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: hover │ │ │ │ - * {Boolean} Send GetFeatureInfo requests when mouse stops moving. │ │ │ │ - * Default is false. │ │ │ │ - */ │ │ │ │ - hover: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: requestEncoding │ │ │ │ - * {String} One of "KVP" or "REST". Only KVP encoding is supported at this │ │ │ │ - * time. │ │ │ │ - */ │ │ │ │ - requestEncoding: "KVP", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: drillDown │ │ │ │ - * {Boolean} Drill down over all WMTS layers in the map. When │ │ │ │ - * using drillDown mode, hover is not possible. A getfeatureinfo event │ │ │ │ - * will be fired for each layer queried. │ │ │ │ - */ │ │ │ │ - drillDown: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: maxFeatures │ │ │ │ - * {Integer} Maximum number of features to return from a WMTS query. This │ │ │ │ - * sets the feature_count parameter on WMTS GetFeatureInfo │ │ │ │ - * requests. │ │ │ │ - */ │ │ │ │ - maxFeatures: 10, │ │ │ │ - │ │ │ │ - /** APIProperty: clickCallback │ │ │ │ - * {String} The click callback to register in the │ │ │ │ - * {<OpenLayers.Handler.Click>} object created when the hover │ │ │ │ - * option is set to false. Default is "click". │ │ │ │ - */ │ │ │ │ - clickCallback: "click", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: layers │ │ │ │ - * {Array(<OpenLayers.Layer.WMTS>)} The layers to query for feature info. │ │ │ │ - * If omitted, all map WMTS layers will be considered. │ │ │ │ - */ │ │ │ │ - layers: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: queryVisible │ │ │ │ - * {Boolean} Filter out hidden layers when searching the map for layers to │ │ │ │ - * query. Default is true. │ │ │ │ - */ │ │ │ │ - queryVisible: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: infoFormat │ │ │ │ - * {String} The mimetype to request from the server │ │ │ │ - */ │ │ │ │ - infoFormat: 'text/html', │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: vendorParams │ │ │ │ - * {Object} Additional parameters that will be added to the request, for │ │ │ │ - * WMTS implementations that support them. This could e.g. look like │ │ │ │ - * (start code) │ │ │ │ - * { │ │ │ │ - * radius: 5 │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ - */ │ │ │ │ - vendorParams: {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: format │ │ │ │ - * {<OpenLayers.Format>} A format for parsing GetFeatureInfo responses. │ │ │ │ - * Default is <OpenLayers.Format.WMSGetFeatureInfo>. │ │ │ │ - */ │ │ │ │ - format: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: formatOptions │ │ │ │ - * {Object} Optional properties to set on the format (if one is not provided │ │ │ │ - * in the <format> property. │ │ │ │ - */ │ │ │ │ - formatOptions: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: handlerOptions │ │ │ │ - * {Object} Additional options for the handlers used by this control, e.g. │ │ │ │ - * (start code) │ │ │ │ - * { │ │ │ │ - * "click": {delay: 100}, │ │ │ │ - * "hover": {delay: 300} │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: handler │ │ │ │ - * {Object} Reference to the <OpenLayers.Handler> for this control │ │ │ │ - */ │ │ │ │ - handler: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: hoverRequest │ │ │ │ - * {<OpenLayers.Request>} contains the currently running hover request │ │ │ │ - * (if any). │ │ │ │ - */ │ │ │ │ - hoverRequest: 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>): │ │ │ │ - * beforegetfeatureinfo - Triggered before each request is sent. │ │ │ │ - * The event object has an *xy* property with the position of the │ │ │ │ - * mouse click or hover event that triggers the request and a *layer* │ │ │ │ - * property referencing the layer about to be queried. If a listener │ │ │ │ - * returns false, the request will not be issued. │ │ │ │ - * getfeatureinfo - Triggered when a GetFeatureInfo response is received. │ │ │ │ - * The event object has a *text* property with the body of the │ │ │ │ - * response (String), a *features* property with an array of the │ │ │ │ - * parsed features, an *xy* property with the position of the mouse │ │ │ │ - * click or hover event that triggered the request, a *layer* property │ │ │ │ - * referencing the layer queried and a *request* property with the │ │ │ │ - * request itself. If drillDown is set to true, one event will be fired │ │ │ │ - * for each layer queried. │ │ │ │ - * exception - Triggered when a GetFeatureInfo request fails (with a │ │ │ │ - * status other than 200) or whenparsing fails. Listeners will receive │ │ │ │ - * an event with *request*, *xy*, and *layer* properties. In the case │ │ │ │ - * of a parsing error, the event will also contain an *error* property. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: pending │ │ │ │ - * {Number} The number of pending requests. │ │ │ │ - */ │ │ │ │ - pending: 0, │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Constructor: <OpenLayers.Control.WMTSGetFeatureInfo> │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ + * APIMethod: deactivate │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.handlerOptions = options.handlerOptions || {}; │ │ │ │ - │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - │ │ │ │ - if (!this.format) { │ │ │ │ - this.format = new OpenLayers.Format.WMSGetFeatureInfo( │ │ │ │ - options.formatOptions │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.drillDown === true) { │ │ │ │ - this.hover = false; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.hover) { │ │ │ │ - this.handler = new OpenLayers.Handler.Hover( │ │ │ │ - this, { │ │ │ │ - move: this.cancelHover, │ │ │ │ - pause: this.getInfoForHover │ │ │ │ - }, │ │ │ │ - OpenLayers.Util.extend( │ │ │ │ - this.handlerOptions.hover || {}, { │ │ │ │ - delay: 250 │ │ │ │ - } │ │ │ │ - ) │ │ │ │ - ); │ │ │ │ + deactivate: function() { │ │ │ │ + if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + this.map.events.unregister('moveend', this, this.update); │ │ │ │ + this.map.removeLayer(this.gratLayer); │ │ │ │ + return true; │ │ │ │ } else { │ │ │ │ - var callbacks = {}; │ │ │ │ - callbacks[this.clickCallback] = this.getInfoForClick; │ │ │ │ - this.handler = new OpenLayers.Handler.Click( │ │ │ │ - this, callbacks, this.handlerOptions.click || {} │ │ │ │ - ); │ │ │ │ + return false; │ │ │ │ } │ │ │ │ }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getInfoForClick │ │ │ │ - * Called on click │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ - */ │ │ │ │ - getInfoForClick: function(evt) { │ │ │ │ - this.request(evt.xy, {}); │ │ │ │ - }, │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: getInfoForHover │ │ │ │ - * Pause callback for the hover handler │ │ │ │ + * Method: update │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} │ │ │ │ - */ │ │ │ │ - getInfoForHover: function(evt) { │ │ │ │ - this.request(evt.xy, { │ │ │ │ - hover: true │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: cancelHover │ │ │ │ - * Cancel callback for the hover handler │ │ │ │ + * calculates the grid to be displayed and actually draws it │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - cancelHover: function() { │ │ │ │ - if (this.hoverRequest) { │ │ │ │ - --this.pending; │ │ │ │ - if (this.pending <= 0) { │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - this.pending = 0; │ │ │ │ - } │ │ │ │ - this.hoverRequest.abort(); │ │ │ │ - this.hoverRequest = null; │ │ │ │ + update: function() { │ │ │ │ + //wait for the map to be initialized before proceeding │ │ │ │ + var mapBounds = this.map.getExtent(); │ │ │ │ + if (!mapBounds) { │ │ │ │ + return; │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: findLayers │ │ │ │ - * Internal method to get the layers, independent of whether we are │ │ │ │ - * inspecting the map or using a client-provided array │ │ │ │ - */ │ │ │ │ - findLayers: function() { │ │ │ │ - var candidates = this.layers || this.map.layers; │ │ │ │ - var layers = []; │ │ │ │ - var layer; │ │ │ │ - for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ - layer = candidates[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.WMTS && │ │ │ │ - layer.requestEncoding === this.requestEncoding && │ │ │ │ - (!this.queryVisible || layer.getVisibility())) { │ │ │ │ - layers.push(layer); │ │ │ │ - if (!this.drillDown || this.hover) { │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return layers; │ │ │ │ - }, │ │ │ │ + //clear out the old grid │ │ │ │ + this.gratLayer.destroyFeatures(); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: buildRequestOptions │ │ │ │ - * Build an object with the relevant options for the GetFeatureInfo request. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.WMTS>} A WMTS layer. │ │ │ │ - * xy - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ - * mouse event occurred. │ │ │ │ - */ │ │ │ │ - buildRequestOptions: function(layer, xy) { │ │ │ │ - var loc = this.map.getLonLatFromPixel(xy); │ │ │ │ - var getTileUrl = layer.getURL( │ │ │ │ - new OpenLayers.Bounds(loc.lon, loc.lat, loc.lon, loc.lat) │ │ │ │ - ); │ │ │ │ - var params = OpenLayers.Util.getParameters(getTileUrl); │ │ │ │ - var tileInfo = layer.getTileInfo(loc); │ │ │ │ - OpenLayers.Util.extend(params, { │ │ │ │ - service: "WMTS", │ │ │ │ - version: layer.version, │ │ │ │ - request: "GetFeatureInfo", │ │ │ │ - infoFormat: this.infoFormat, │ │ │ │ - i: tileInfo.i, │ │ │ │ - j: tileInfo.j │ │ │ │ - }); │ │ │ │ - OpenLayers.Util.applyDefaults(params, this.vendorParams); │ │ │ │ - return { │ │ │ │ - url: OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url, │ │ │ │ - params: OpenLayers.Util.upperCaseObject(params), │ │ │ │ - callback: function(request) { │ │ │ │ - this.handleResponse(xy, request, layer); │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ + //get the projection objects required │ │ │ │ + var llProj = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ + var mapProj = this.map.getProjectionObject(); │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: request │ │ │ │ - * Sends a GetFeatureInfo request to the WMTS │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * xy - {<OpenLayers.Pixel>} The position on the map where the mouse event │ │ │ │ - * occurred. │ │ │ │ - * options - {Object} additional options for this method. │ │ │ │ - * │ │ │ │ - * Valid options: │ │ │ │ - * - *hover* {Boolean} true if we do the request for the hover handler │ │ │ │ - */ │ │ │ │ - request: function(xy, options) { │ │ │ │ - options = options || {}; │ │ │ │ - var layers = this.findLayers(); │ │ │ │ - if (layers.length > 0) { │ │ │ │ - var issue, layer; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - layer = layers[i]; │ │ │ │ - issue = this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ - xy: xy, │ │ │ │ - layer: layer │ │ │ │ - }); │ │ │ │ - if (issue !== false) { │ │ │ │ - ++this.pending; │ │ │ │ - var requestOptions = this.buildRequestOptions(layer, xy); │ │ │ │ - var request = OpenLayers.Request.GET(requestOptions); │ │ │ │ - if (options.hover === true) { │ │ │ │ - this.hoverRequest = request; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.pending > 0) { │ │ │ │ - OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - } │ │ │ │ + //if the map is in lon/lat, then the lines are straight and only one │ │ │ │ + //point is required │ │ │ │ + if (mapProj.proj && mapProj.proj.projName == "longlat") { │ │ │ │ + this.numPoints = 1; │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: handleResponse │ │ │ │ - * Handler for the GetFeatureInfo response. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * xy - {<OpenLayers.Pixel>} The position on the map where the mouse event │ │ │ │ - * occurred. │ │ │ │ - * request - {XMLHttpRequest} The request object. │ │ │ │ - * layer - {<OpenLayers.Layer.WMTS>} The queried layer. │ │ │ │ - */ │ │ │ │ - handleResponse: function(xy, request, layer) { │ │ │ │ - --this.pending; │ │ │ │ - if (this.pending <= 0) { │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - this.pending = 0; │ │ │ │ - } │ │ │ │ - if (request.status && (request.status < 200 || request.status >= 300)) { │ │ │ │ - this.events.triggerEvent("exception", { │ │ │ │ - xy: xy, │ │ │ │ - request: request, │ │ │ │ - layer: layer │ │ │ │ + //get the map center in EPSG:4326 │ │ │ │ + var mapCenter = this.map.getCenter(); //lon and lat here are really map x and y │ │ │ │ + var mapCenterLL = new OpenLayers.Pixel(mapCenter.lon, mapCenter.lat); │ │ │ │ + OpenLayers.Projection.transform(mapCenterLL, mapProj, llProj); │ │ │ │ + │ │ │ │ + /* This block of code determines the lon/lat interval to use for the │ │ │ │ + * grid by calculating the diagonal size of one grid cell at the map │ │ │ │ + * center. Iterates through the intervals array until the diagonal │ │ │ │ + * length is less than the targetSize option. │ │ │ │ + */ │ │ │ │ + //find lat/lon interval that results in a grid of less than the target size │ │ │ │ + var testSq = this.targetSize * mapRes; │ │ │ │ + testSq *= testSq; //compare squares rather than doing a square root to save time │ │ │ │ + var llInterval; │ │ │ │ + for (var i = 0; i < this.intervals.length; ++i) { │ │ │ │ + llInterval = this.intervals[i]; //could do this for both x and y?? │ │ │ │ + var delta = llInterval / 2; │ │ │ │ + var p1 = mapCenterLL.offset({ │ │ │ │ + x: -delta, │ │ │ │ + y: -delta │ │ │ │ + }); //test coords in EPSG:4326 space │ │ │ │ + var p2 = mapCenterLL.offset({ │ │ │ │ + x: delta, │ │ │ │ + y: delta │ │ │ │ }); │ │ │ │ - } else { │ │ │ │ - var doc = request.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = request.responseText; │ │ │ │ - } │ │ │ │ - var features, except; │ │ │ │ - try { │ │ │ │ - features = this.format.read(doc); │ │ │ │ - } catch (error) { │ │ │ │ - except = true; │ │ │ │ - this.events.triggerEvent("exception", { │ │ │ │ - xy: xy, │ │ │ │ - request: request, │ │ │ │ - error: error, │ │ │ │ - layer: layer │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - if (!except) { │ │ │ │ - this.events.triggerEvent("getfeatureinfo", { │ │ │ │ - text: request.responseText, │ │ │ │ - features: features, │ │ │ │ - request: request, │ │ │ │ - xy: xy, │ │ │ │ - layer: layer │ │ │ │ - }); │ │ │ │ + OpenLayers.Projection.transform(p1, llProj, mapProj); // convert them back to map projection │ │ │ │ + OpenLayers.Projection.transform(p2, llProj, mapProj); │ │ │ │ + var distSq = (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y); │ │ │ │ + if (distSq <= testSq) { │ │ │ │ + break; │ │ │ │ } │ │ │ │ } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.WMTSGetFeatureInfo" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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}", │ │ │ │ + //alert(llInterval); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.Attribution │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Options for control. │ │ │ │ - */ │ │ │ │ + //round the LL center to an even number based on the interval │ │ │ │ + mapCenterLL.x = Math.floor(mapCenterLL.x / llInterval) * llInterval; │ │ │ │ + mapCenterLL.y = Math.floor(mapCenterLL.y / llInterval) * llInterval; │ │ │ │ + //TODO adjust for minutses/seconds? │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - * Destroy control. │ │ │ │ + /* The following 2 blocks calculate the nodes of the grid along a │ │ │ │ + * line of constant longitude (then latitiude) running through the │ │ │ │ + * center of the map until it reaches the map edge. The calculation │ │ │ │ + * goes from the center in both directions to the edge. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - this.map.events.un({ │ │ │ │ - "removelayer": this.updateAttribution, │ │ │ │ - "addlayer": this.updateAttribution, │ │ │ │ - "changelayer": this.updateAttribution, │ │ │ │ - "changebaselayer": this.updateAttribution, │ │ │ │ - scope: this │ │ │ │ + //get the central longitude line, increment the latitude │ │ │ │ + var iter = 0; │ │ │ │ + var centerLonPoints = [mapCenterLL.clone()]; │ │ │ │ + var newPoint = mapCenterLL.clone(); │ │ │ │ + var mapXY; │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: 0, │ │ │ │ + y: llInterval │ │ │ │ }); │ │ │ │ - │ │ │ │ - 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 │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLonPoints.unshift(newPoint); │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ + newPoint = mapCenterLL.clone(); │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: 0, │ │ │ │ + y: -llInterval │ │ │ │ }); │ │ │ │ - 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/Control/Split.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/Path.js │ │ │ │ - * @requires OpenLayers/Layer/Vector.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.Split │ │ │ │ - * Acts as a split feature agent while editing vector features. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.Split = 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>): │ │ │ │ - * beforesplit - Triggered before a split occurs. Listeners receive an │ │ │ │ - * event object with *source* and *target* properties. │ │ │ │ - * split - Triggered when a split occurs. Listeners receive an event with │ │ │ │ - * an *original* property and a *features* property. The original │ │ │ │ - * is a reference to the target feature that the sketch or modified │ │ │ │ - * feature intersects. The features property is a list of all features │ │ │ │ - * that result from this single split. This event is triggered before │ │ │ │ - * the resulting features are added to the layer (while the layer still │ │ │ │ - * has a reference to the original). │ │ │ │ - * aftersplit - Triggered after all splits resulting from a single sketch │ │ │ │ - * or feature modification have occurred. The original features │ │ │ │ - * have been destroyed and features that result from the split │ │ │ │ - * have already been added to the layer. Listeners receive an event │ │ │ │ - * with a *source* and *features* property. The source references the │ │ │ │ - * sketch or modified feature used as a splitter. The features │ │ │ │ - * property is a list of all resulting features. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: layer │ │ │ │ - * {<OpenLayers.Layer.Vector>} The target layer with features to be split. │ │ │ │ - * Set at construction or after construction with <setLayer>. │ │ │ │ - */ │ │ │ │ - layer: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: source │ │ │ │ - * {<OpenLayers.Layer.Vector>} Optional source layer. Any newly created │ │ │ │ - * or modified features from this layer will be used to split features │ │ │ │ - * on the target layer. If not provided, a temporary sketch layer will │ │ │ │ - * be created. │ │ │ │ - */ │ │ │ │ - source: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: sourceOptions │ │ │ │ - * {Options} If a temporary sketch layer is created, these layer options │ │ │ │ - * will be applied. │ │ │ │ - */ │ │ │ │ - sourceOptions: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: tolerance │ │ │ │ - * {Number} Distance between the calculated intersection and a vertex on │ │ │ │ - * the source geometry below which the existing vertex will be used │ │ │ │ - * for the split. Default is null. │ │ │ │ - */ │ │ │ │ - tolerance: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: edge │ │ │ │ - * {Boolean} Allow splits given intersection of edges only. Default is │ │ │ │ - * true. If false, a vertex on the source must be within the │ │ │ │ - * <tolerance> distance of the calculated intersection for a split │ │ │ │ - * to occur. │ │ │ │ - */ │ │ │ │ - edge: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: deferDelete │ │ │ │ - * {Boolean} Instead of removing features from the layer, set feature │ │ │ │ - * states of split features to DELETE. This assumes a save strategy │ │ │ │ - * or other component is in charge of removing features from the │ │ │ │ - * layer. Default is false. If false, split features will be │ │ │ │ - * immediately deleted from the layer. │ │ │ │ - */ │ │ │ │ - deferDelete: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: mutual │ │ │ │ - * {Boolean} If source and target layers are the same, split source │ │ │ │ - * features and target features where they intersect. Default is │ │ │ │ - * true. If false, only target features will be split. │ │ │ │ - */ │ │ │ │ - mutual: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: targetFilter │ │ │ │ - * {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ - * to determine if a feature from the target layer is eligible for │ │ │ │ - * splitting. │ │ │ │ - */ │ │ │ │ - targetFilter: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: sourceFilter │ │ │ │ - * {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ - * to determine if a feature from the source layer is eligible for │ │ │ │ - * splitting. │ │ │ │ - */ │ │ │ │ - sourceFilter: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: handler │ │ │ │ - * {<OpenLayers.Handler.Path>} The temporary sketch handler created if │ │ │ │ - * no source layer is provided. │ │ │ │ - */ │ │ │ │ - handler: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.Split │ │ │ │ - * Creates a new split control. A control is constructed with a target │ │ │ │ - * layer and an optional source layer. While the control is active, │ │ │ │ - * creating new features or modifying existing features on the source │ │ │ │ - * layer will result in splitting any eligible features on the target │ │ │ │ - * layer. If no source layer is provided, a temporary sketch layer will │ │ │ │ - * be created to create lines for splitting features on the target. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An object containing all configuration properties for │ │ │ │ - * the control. │ │ │ │ - * │ │ │ │ - * Valid options: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} The target layer. Features from this │ │ │ │ - * layer will be split by new or modified features on the source layer │ │ │ │ - * or temporary sketch layer. │ │ │ │ - * source - {<OpenLayers.Layer.Vector>} Optional source layer. If provided │ │ │ │ - * newly created features or modified features will be used to split │ │ │ │ - * features on the target layer. If not provided, a temporary sketch │ │ │ │ - * layer will be created for drawing lines. │ │ │ │ - * tolerance - {Number} Optional value for the distance between a source │ │ │ │ - * vertex and the calculated intersection below which the split will │ │ │ │ - * occur at the vertex. │ │ │ │ - * edge - {Boolean} Allow splits given intersection of edges only. Default │ │ │ │ - * is true. If false, a vertex on the source must be within the │ │ │ │ - * <tolerance> distance of the calculated intersection for a split │ │ │ │ - * to occur. │ │ │ │ - * mutual - {Boolean} If source and target are the same, split source │ │ │ │ - * features and target features where they intersect. Default is │ │ │ │ - * true. If false, only target features will be split. │ │ │ │ - * targetFilter - {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ - * to determine if a feature from the target layer is eligible for │ │ │ │ - * splitting. │ │ │ │ - * sourceFilter - {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ - * to determine if a feature from the target layer is eligible for │ │ │ │ - * splitting. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.options = options || {}; // TODO: this could be done by the super │ │ │ │ - │ │ │ │ - // set the source layer if provided │ │ │ │ - if (this.options.source) { │ │ │ │ - this.setSource(this.options.source); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLonPoints.push(newPoint); │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: setSource │ │ │ │ - * Set the source layer for edits layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} The new source layer layer. If │ │ │ │ - * null, a temporary sketch layer will be created. │ │ │ │ - */ │ │ │ │ - setSource: function(layer) { │ │ │ │ - if (this.active) { │ │ │ │ - this.deactivate(); │ │ │ │ - if (this.handler) { │ │ │ │ - this.handler.destroy(); │ │ │ │ - delete this.handler; │ │ │ │ - } │ │ │ │ - this.source = layer; │ │ │ │ - this.activate(); │ │ │ │ - } else { │ │ │ │ - this.source = layer; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + //get the central latitude line, increment the longitude │ │ │ │ + iter = 0; │ │ │ │ + var centerLatPoints = [mapCenterLL.clone()]; │ │ │ │ + newPoint = mapCenterLL.clone(); │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: -llInterval, │ │ │ │ + y: 0 │ │ │ │ + }); │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLatPoints.unshift(newPoint); │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ + newPoint = mapCenterLL.clone(); │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: llInterval, │ │ │ │ + y: 0 │ │ │ │ + }); │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLatPoints.push(newPoint); │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the control. Activating the control registers listeners for │ │ │ │ - * editing related events so that during feature creation and │ │ │ │ - * modification, features in the target will be considered for │ │ │ │ - * splitting. │ │ │ │ - */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - if (!this.source) { │ │ │ │ - if (!this.handler) { │ │ │ │ - this.handler = new OpenLayers.Handler.Path(this, { │ │ │ │ - done: function(geometry) { │ │ │ │ - this.onSketchComplete({ │ │ │ │ - feature: new OpenLayers.Feature.Vector(geometry) │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }, { │ │ │ │ - layerOptions: this.sourceOptions │ │ │ │ - }); │ │ │ │ + //now generate a line for each node in the central lat and lon lines │ │ │ │ + //first loop over constant longitude │ │ │ │ + var lines = []; │ │ │ │ + for (var i = 0; i < centerLatPoints.length; ++i) { │ │ │ │ + var lon = centerLatPoints[i].x; │ │ │ │ + var pointList = []; │ │ │ │ + var labelPoint = null; │ │ │ │ + var latEnd = Math.min(centerLonPoints[0].y, 90); │ │ │ │ + var latStart = Math.max(centerLonPoints[centerLonPoints.length - 1].y, -90); │ │ │ │ + var latDelta = (latEnd - latStart) / this.numPoints; │ │ │ │ + var lat = latStart; │ │ │ │ + for (var j = 0; j <= this.numPoints; ++j) { │ │ │ │ + var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ + gridPoint.transform(llProj, mapProj); │ │ │ │ + pointList.push(gridPoint); │ │ │ │ + lat += latDelta; │ │ │ │ + if (gridPoint.y >= mapBounds.bottom && !labelPoint) { │ │ │ │ + labelPoint = gridPoint; │ │ │ │ } │ │ │ │ - this.handler.activate(); │ │ │ │ - } else if (this.source.events) { │ │ │ │ - this.source.events.on({ │ │ │ │ - sketchcomplete: this.onSketchComplete, │ │ │ │ - afterfeaturemodified: this.afterFeatureModified, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return activated; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the control. Deactivating the control unregisters listeners │ │ │ │ - * so feature editing may proceed without engaging the split agent. │ │ │ │ - */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - if (this.source && this.source.events) { │ │ │ │ - this.source.events.un({ │ │ │ │ - sketchcomplete: this.onSketchComplete, │ │ │ │ - afterfeaturemodified: this.afterFeatureModified, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ } │ │ │ │ - } │ │ │ │ - return deactivated; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: onSketchComplete │ │ │ │ - * Registered as a listener for the sketchcomplete event on the editable │ │ │ │ - * layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * event - {Object} The sketch complete event. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Stop the sketch from being added to the layer (it has been │ │ │ │ - * split). │ │ │ │ - */ │ │ │ │ - onSketchComplete: function(event) { │ │ │ │ - this.feature = null; │ │ │ │ - return !this.considerSplit(event.feature); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: afterFeatureModified │ │ │ │ - * Registered as a listener for the afterfeaturemodified event on the │ │ │ │ - * editable layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * event - {Object} The after feature modified event. │ │ │ │ - */ │ │ │ │ - afterFeatureModified: function(event) { │ │ │ │ - if (event.modified) { │ │ │ │ - var feature = event.feature; │ │ │ │ - if (typeof feature.geometry.split === "function") { │ │ │ │ - this.feature = event.feature; │ │ │ │ - this.considerSplit(event.feature); │ │ │ │ + if (this.labelled) { │ │ │ │ + //keep track of when this grid line crosses the map bounds to set │ │ │ │ + //the label position │ │ │ │ + //labels along the bottom, add 10 pixel offset up into the map │ │ │ │ + //TODO add option for labels on top │ │ │ │ + var labelPos = new OpenLayers.Geometry.Point(labelPoint.x, mapBounds.bottom); │ │ │ │ + var labelAttrs = { │ │ │ │ + value: lon, │ │ │ │ + label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lon, "lon", this.labelFormat) : "", │ │ │ │ + labelAlign: "cb", │ │ │ │ + xOffset: 0, │ │ │ │ + yOffset: 2 │ │ │ │ + }; │ │ │ │ + this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)); │ │ │ │ } │ │ │ │ + var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ + lines.push(new OpenLayers.Feature.Vector(geom)); │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: removeByGeometry │ │ │ │ - * Remove a feature from a list based on the given geometry. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} A list of features. │ │ │ │ - * geometry - {<OpenLayers.Geometry>} A geometry. │ │ │ │ - */ │ │ │ │ - removeByGeometry: function(features, geometry) { │ │ │ │ - for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ - if (features[i].geometry === geometry) { │ │ │ │ - features.splice(i, 1); │ │ │ │ - break; │ │ │ │ + //now draw the lines of constant latitude │ │ │ │ + for (var j = 0; j < centerLonPoints.length; ++j) { │ │ │ │ + lat = centerLonPoints[j].y; │ │ │ │ + if (lat < -90 || lat > 90) { //latitudes only valid between -90 and 90 │ │ │ │ + continue; │ │ │ │ } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: isEligible │ │ │ │ - * Test if a target feature is eligible for splitting. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * target - {<OpenLayers.Feature.Vector>} The target feature. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The target is eligible for splitting. │ │ │ │ - */ │ │ │ │ - isEligible: function(target) { │ │ │ │ - if (!target.geometry) { │ │ │ │ - return false; │ │ │ │ - } else { │ │ │ │ - return ( │ │ │ │ - target.state !== OpenLayers.State.DELETE │ │ │ │ - ) && ( │ │ │ │ - typeof target.geometry.split === "function" │ │ │ │ - ) && ( │ │ │ │ - this.feature !== target │ │ │ │ - ) && ( │ │ │ │ - !this.targetFilter || │ │ │ │ - this.targetFilter.evaluate(target.attributes) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: considerSplit │ │ │ │ - * Decide whether or not to split target features with the supplied │ │ │ │ - * feature. If <mutual> is true, both the source and target features │ │ │ │ - * will be split if eligible. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The newly created or modified │ │ │ │ - * feature. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The supplied feature was split (and destroyed). │ │ │ │ - */ │ │ │ │ - considerSplit: function(feature) { │ │ │ │ - var sourceSplit = false; │ │ │ │ - var targetSplit = false; │ │ │ │ - if (!this.sourceFilter || │ │ │ │ - this.sourceFilter.evaluate(feature.attributes)) { │ │ │ │ - var features = this.layer && this.layer.features || []; │ │ │ │ - var target, results, proceed; │ │ │ │ - var additions = [], │ │ │ │ - removals = []; │ │ │ │ - var mutual = (this.layer === this.source) && this.mutual; │ │ │ │ - var options = { │ │ │ │ - edge: this.edge, │ │ │ │ - tolerance: this.tolerance, │ │ │ │ - mutual: mutual │ │ │ │ - }; │ │ │ │ - var sourceParts = [feature.geometry]; │ │ │ │ - var targetFeature, targetParts; │ │ │ │ - var source, parts; │ │ │ │ - for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ - targetFeature = features[i]; │ │ │ │ - if (this.isEligible(targetFeature)) { │ │ │ │ - targetParts = [targetFeature.geometry]; │ │ │ │ - // work through source geoms - this array may change │ │ │ │ - for (var j = 0; j < sourceParts.length; ++j) { │ │ │ │ - source = sourceParts[j]; │ │ │ │ - // work through target parts - this array may change │ │ │ │ - for (var k = 0; k < targetParts.length; ++k) { │ │ │ │ - target = targetParts[k]; │ │ │ │ - if (source.getBounds().intersectsBounds(target.getBounds())) { │ │ │ │ - results = source.split(target, options); │ │ │ │ - if (results) { │ │ │ │ - proceed = this.events.triggerEvent( │ │ │ │ - "beforesplit", { │ │ │ │ - source: feature, │ │ │ │ - target: targetFeature │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - if (proceed !== false) { │ │ │ │ - if (mutual) { │ │ │ │ - parts = results[0]; │ │ │ │ - // handle parts that result from source splitting │ │ │ │ - if (parts.length > 1) { │ │ │ │ - // splice in new source parts │ │ │ │ - parts.unshift(j, 1); // add args for splice below │ │ │ │ - Array.prototype.splice.apply(sourceParts, parts); │ │ │ │ - j += parts.length - 3; │ │ │ │ - } │ │ │ │ - results = results[1]; │ │ │ │ - } │ │ │ │ - // handle parts that result from target splitting │ │ │ │ - if (results.length > 1) { │ │ │ │ - // splice in new target parts │ │ │ │ - results.unshift(k, 1); // add args for splice below │ │ │ │ - Array.prototype.splice.apply(targetParts, results); │ │ │ │ - k += results.length - 3; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (targetParts && targetParts.length > 1) { │ │ │ │ - this.geomsToFeatures(targetFeature, targetParts); │ │ │ │ - this.events.triggerEvent("split", { │ │ │ │ - original: targetFeature, │ │ │ │ - features: targetParts │ │ │ │ - }); │ │ │ │ - Array.prototype.push.apply(additions, targetParts); │ │ │ │ - removals.push(targetFeature); │ │ │ │ - targetSplit = true; │ │ │ │ - } │ │ │ │ + var pointList = []; │ │ │ │ + var lonStart = centerLatPoints[0].x; │ │ │ │ + var lonEnd = centerLatPoints[centerLatPoints.length - 1].x; │ │ │ │ + var lonDelta = (lonEnd - lonStart) / this.numPoints; │ │ │ │ + var lon = lonStart; │ │ │ │ + var labelPoint = null; │ │ │ │ + for (var i = 0; i <= this.numPoints; ++i) { │ │ │ │ + var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ + gridPoint.transform(llProj, mapProj); │ │ │ │ + pointList.push(gridPoint); │ │ │ │ + lon += lonDelta; │ │ │ │ + if (gridPoint.x < mapBounds.right) { │ │ │ │ + labelPoint = gridPoint; │ │ │ │ } │ │ │ │ } │ │ │ │ - if (sourceParts && sourceParts.length > 1) { │ │ │ │ - this.geomsToFeatures(feature, sourceParts); │ │ │ │ - this.events.triggerEvent("split", { │ │ │ │ - original: feature, │ │ │ │ - features: sourceParts │ │ │ │ - }); │ │ │ │ - Array.prototype.push.apply(additions, sourceParts); │ │ │ │ - removals.push(feature); │ │ │ │ - sourceSplit = true; │ │ │ │ - } │ │ │ │ - if (sourceSplit || targetSplit) { │ │ │ │ - // remove and add feature events are suppressed │ │ │ │ - // listen for split event on this control instead │ │ │ │ - if (this.deferDelete) { │ │ │ │ - // Set state instead of removing. Take care to avoid │ │ │ │ - // setting delete for features that have not yet been │ │ │ │ - // inserted - those should be destroyed immediately. │ │ │ │ - var feat, destroys = []; │ │ │ │ - for (var i = 0, len = removals.length; i < len; ++i) { │ │ │ │ - feat = removals[i]; │ │ │ │ - if (feat.state === OpenLayers.State.INSERT) { │ │ │ │ - destroys.push(feat); │ │ │ │ - } else { │ │ │ │ - feat.state = OpenLayers.State.DELETE; │ │ │ │ - this.layer.drawFeature(feat); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.layer.destroyFeatures(destroys, { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ - for (var i = 0, len = additions.length; i < len; ++i) { │ │ │ │ - additions[i].state = OpenLayers.State.INSERT; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.layer.destroyFeatures(removals, { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - this.layer.addFeatures(additions, { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ - this.events.triggerEvent("aftersplit", { │ │ │ │ - source: feature, │ │ │ │ - features: additions │ │ │ │ - }); │ │ │ │ + if (this.labelled) { │ │ │ │ + //keep track of when this grid line crosses the map bounds to set │ │ │ │ + //the label position │ │ │ │ + //labels along the right, 30 pixel offset left into the map │ │ │ │ + //TODO add option for labels on left │ │ │ │ + var labelPos = new OpenLayers.Geometry.Point(mapBounds.right, labelPoint.y); │ │ │ │ + var labelAttrs = { │ │ │ │ + value: lat, │ │ │ │ + label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lat, "lat", this.labelFormat) : "", │ │ │ │ + labelAlign: "rb", │ │ │ │ + xOffset: -2, │ │ │ │ + yOffset: 2 │ │ │ │ + }; │ │ │ │ + this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)); │ │ │ │ } │ │ │ │ + var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ + lines.push(new OpenLayers.Feature.Vector(geom)); │ │ │ │ } │ │ │ │ - return sourceSplit; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: geomsToFeatures │ │ │ │ - * Create new features given a template feature and a list of geometries. │ │ │ │ - * The list of geometries is modified in place. The result will be │ │ │ │ - * a list of new features. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature to be cloned. │ │ │ │ - * geoms - {Array(<OpenLayers.Geometry>)} List of goemetries. This will │ │ │ │ - * become a list of new features. │ │ │ │ - */ │ │ │ │ - geomsToFeatures: function(feature, geoms) { │ │ │ │ - var clone = feature.clone(); │ │ │ │ - delete clone.geometry; │ │ │ │ - var newFeature; │ │ │ │ - for (var i = 0, len = geoms.length; i < len; ++i) { │ │ │ │ - // turn results list from geoms to features │ │ │ │ - newFeature = clone.clone(); │ │ │ │ - newFeature.geometry = geoms[i]; │ │ │ │ - newFeature.state = OpenLayers.State.INSERT; │ │ │ │ - geoms[i] = newFeature; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - * Clean up the control. │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.active) { │ │ │ │ - this.deactivate(); // TODO: this should be handled by the super │ │ │ │ - } │ │ │ │ - OpenLayers.Control.prototype.destroy.call(this); │ │ │ │ + this.gratLayer.addFeatures(lines); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Split" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Graticule" │ │ │ │ }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/KeyboardDefaults.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/Keyboard.js │ │ │ │ - * @requires OpenLayers/Events.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.KeyboardDefaults │ │ │ │ - * The KeyboardDefaults control adds panning and zooming functions, controlled │ │ │ │ - * with the keyboard. By default arrow keys pan, +/- keys zoom & Page Up/Page │ │ │ │ - * Down/Home/End scroll by three quarters of a page. │ │ │ │ - * │ │ │ │ - * This control has no visible appearance. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.KeyboardDefaults = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ - */ │ │ │ │ - autoActivate: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: slideFactor │ │ │ │ - * Pixels to slide by. │ │ │ │ - */ │ │ │ │ - slideFactor: 75, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: observeElement │ │ │ │ - * {DOMelement|String} The DOM element to handle keys for. You │ │ │ │ - * can use the map div here, to have the navigation keys │ │ │ │ - * work when the map div has the focus. If undefined the │ │ │ │ - * document is used. │ │ │ │ - */ │ │ │ │ - observeElement: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.KeyboardDefaults │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * Create handler. │ │ │ │ - */ │ │ │ │ - draw: function() { │ │ │ │ - var observeElement = this.observeElement || document; │ │ │ │ - this.handler = new OpenLayers.Handler.Keyboard(this, { │ │ │ │ - "keydown": this.defaultKeyPress │ │ │ │ - }, { │ │ │ │ - observeElement: observeElement │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: defaultKeyPress │ │ │ │ - * When handling the key event, we only use evt.keyCode. This holds │ │ │ │ - * some drawbacks, though we get around them below. When interpretting │ │ │ │ - * the keycodes below (including the comments associated with them), │ │ │ │ - * consult the URL below. For instance, the Safari browser returns │ │ │ │ - * "IE keycodes", and so is supported by any keycode labeled "IE". │ │ │ │ - * │ │ │ │ - * Very informative URL: │ │ │ │ - * http://unixpapa.com/js/key.html │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - */ │ │ │ │ - defaultKeyPress: function(evt) { │ │ │ │ - var size, handled = true; │ │ │ │ - │ │ │ │ - var target = OpenLayers.Event.element(evt); │ │ │ │ - if (target && │ │ │ │ - (target.tagName == 'INPUT' || │ │ │ │ - target.tagName == 'TEXTAREA' || │ │ │ │ - target.tagName == 'SELECT')) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - │ │ │ │ - switch (evt.keyCode) { │ │ │ │ - case OpenLayers.Event.KEY_LEFT: │ │ │ │ - this.map.pan(-this.slideFactor, 0); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Event.KEY_RIGHT: │ │ │ │ - this.map.pan(this.slideFactor, 0); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Event.KEY_UP: │ │ │ │ - this.map.pan(0, -this.slideFactor); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Event.KEY_DOWN: │ │ │ │ - this.map.pan(0, this.slideFactor); │ │ │ │ - break; │ │ │ │ - │ │ │ │ - case 33: // Page Up. Same in all browsers. │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(0, -0.75 * size.h); │ │ │ │ - break; │ │ │ │ - case 34: // Page Down. Same in all browsers. │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(0, 0.75 * size.h); │ │ │ │ - break; │ │ │ │ - case 35: // End. Same in all browsers. │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(0.75 * size.w, 0); │ │ │ │ - break; │ │ │ │ - case 36: // Home. Same in all browsers. │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(-0.75 * size.w, 0); │ │ │ │ - break; │ │ │ │ - │ │ │ │ - case 43: // +/= (ASCII), keypad + (ASCII, Opera) │ │ │ │ - case 61: // +/= (Mozilla, Opera, some ASCII) │ │ │ │ - case 187: // +/= (IE) │ │ │ │ - case 107: // keypad + (IE, Mozilla) │ │ │ │ - this.map.zoomIn(); │ │ │ │ - break; │ │ │ │ - case 45: // -/_ (ASCII, Opera), keypad - (ASCII, Opera) │ │ │ │ - case 109: // -/_ (Mozilla), keypad - (Mozilla, IE) │ │ │ │ - case 189: // -/_ (IE) │ │ │ │ - case 95: // -/_ (some ASCII) │ │ │ │ - this.map.zoomOut(); │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - handled = false; │ │ │ │ - } │ │ │ │ - if (handled) { │ │ │ │ - // prevent browser default not to move the page │ │ │ │ - // when moving the page with the keyboard │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.KeyboardDefaults" │ │ │ │ -}); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/SelectFeature.js │ │ │ │ + OpenLayers/Control/Snapping.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 │ │ │ │ + * @requires OpenLayers/Layer/Vector.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.SelectFeature │ │ │ │ - * The SelectFeature control selects vector features from a given layer on │ │ │ │ - * click or hover. │ │ │ │ + * Class: OpenLayers.Control.Snapping │ │ │ │ + * Acts as a snapping agent while editing vector features. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Control.Snapping = 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. │ │ │ │ + * beforesnap - Triggered before a snap occurs. Listeners receive an │ │ │ │ + * event object with *point*, *x*, *y*, *distance*, *layer*, and │ │ │ │ + * *snapType* properties. The point property will be original point │ │ │ │ + * geometry considered for snapping. The x and y properties represent │ │ │ │ + * coordinates the point will receive. The distance is the distance │ │ │ │ + * of the snap. The layer is the target layer. The snapType property │ │ │ │ + * will be one of "node", "vertex", or "edge". Return false to stop │ │ │ │ + * snapping from occurring. │ │ │ │ + * snap - Triggered when a snap occurs. Listeners receive an event with │ │ │ │ + * *point*, *snapType*, *layer*, and *distance* properties. The point │ │ │ │ + * will be the location snapped to. The snapType will be one of "node", │ │ │ │ + * "vertex", or "edge". The layer will be the target layer. The │ │ │ │ + * distance will be the distance of the snap in map units. │ │ │ │ + * unsnap - Triggered when a vertex is unsnapped. Listeners receive an │ │ │ │ + * event with a *point* property. │ │ │ │ */ │ │ │ │ - onUnselect: function() {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: scope │ │ │ │ - * {Object} The scope to use with the onBeforeSelect, onSelect, onUnselect │ │ │ │ - * callbacks. If null the scope will be this control. │ │ │ │ + * CONSTANT: DEFAULTS │ │ │ │ + * Default target properties. │ │ │ │ */ │ │ │ │ - scope: null, │ │ │ │ + DEFAULTS: { │ │ │ │ + tolerance: 10, │ │ │ │ + node: true, │ │ │ │ + edge: true, │ │ │ │ + vertex: true │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: greedy │ │ │ │ + * {Boolean} Snap to closest feature in first layer with an eligible │ │ │ │ + * feature. Default is true. │ │ │ │ */ │ │ │ │ - geometryTypes: null, │ │ │ │ + greedy: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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). │ │ │ │ + * Property: precedence │ │ │ │ + * {Array} List representing precedence of different snapping types. │ │ │ │ + * Default is "node", "vertex", "edge". │ │ │ │ */ │ │ │ │ - layer: null, │ │ │ │ + precedence: ["node", "vertex", "edge"], │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: layers │ │ │ │ - * {Array(<OpenLayers.Layer.Vector>)} The layers this control will work on, │ │ │ │ - * or null if the control was configured with a single layer │ │ │ │ + * Property: resolution │ │ │ │ + * {Float} The map resolution for the previously considered snap. │ │ │ │ */ │ │ │ │ - layers: null, │ │ │ │ + resolution: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: callbacks │ │ │ │ - * {Object} The functions that are sent to the handlers.feature for callback │ │ │ │ + * Property: geoToleranceCache │ │ │ │ + * {Object} A cache of geo-tolerances. Tolerance values (in map units) are │ │ │ │ + * calculated when the map resolution changes. │ │ │ │ */ │ │ │ │ - callbacks: null, │ │ │ │ + geoToleranceCache: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: selectStyle │ │ │ │ - * {Object} Hash of styles │ │ │ │ + * Property: layer │ │ │ │ + * {<OpenLayers.Layer.Vector>} The current editable layer. Set at │ │ │ │ + * construction or after construction with <setLayer>. │ │ │ │ */ │ │ │ │ - selectStyle: null, │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: renderIntent │ │ │ │ - * {String} key used to retrieve the select style from the layer's │ │ │ │ - * style map. │ │ │ │ + * Property: feature │ │ │ │ + * {<OpenLayers.Feature.Vector>} The current editable feature. │ │ │ │ */ │ │ │ │ - renderIntent: "select", │ │ │ │ + feature: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: handlers │ │ │ │ - * {Object} Object with references to multiple <OpenLayers.Handler> │ │ │ │ - * instances. │ │ │ │ + * Property: point │ │ │ │ + * {<OpenLayers.Geometry.Point>} The currently snapped vertex. │ │ │ │ */ │ │ │ │ - handlers: null, │ │ │ │ + point: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.SelectFeature │ │ │ │ - * Create a new control for selecting features. │ │ │ │ + * Constructor: OpenLayers.Control.Snapping │ │ │ │ + * Creates a new snapping control. A control is constructed with an editable │ │ │ │ + * layer and a set of configuration objects for target layers. While the │ │ │ │ + * control is active, dragging vertices while drawing new features or │ │ │ │ + * modifying existing features on the editable layer will engage │ │ │ │ + * snapping to features on the target layers. Whether a vertex snaps to │ │ │ │ + * a feature on a target layer depends on the target layer configuration. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * layers - {<OpenLayers.Layer.Vector>}, or an array of vector layers. The │ │ │ │ - * layer(s) this control will select features from. │ │ │ │ - * options - {Object} │ │ │ │ + * options - {Object} An object containing all configuration properties for │ │ │ │ + * the control. │ │ │ │ + * │ │ │ │ + * Valid options: │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} The editable layer. Features from this │ │ │ │ + * layer that are digitized or modified may have vertices snapped to │ │ │ │ + * features from any of the target layers. │ │ │ │ + * targets - {Array(Object | OpenLayers.Layer.Vector)} A list of objects for │ │ │ │ + * configuring target layers. See valid properties of the target │ │ │ │ + * objects below. If the items in the targets list are vector layers │ │ │ │ + * (instead of configuration objects), the defaults from the <defaults> │ │ │ │ + * property will apply. The editable layer itself may be a target │ │ │ │ + * layer, allowing newly created or edited features to be snapped to │ │ │ │ + * existing features from the same layer. If no targets are provided │ │ │ │ + * the layer given in the constructor (as <layer>) will become the │ │ │ │ + * initial target. │ │ │ │ + * defaults - {Object} An object with default properties to be applied │ │ │ │ + * to all target objects. │ │ │ │ + * greedy - {Boolean} Snap to closest feature in first target layer that │ │ │ │ + * applies. Default is true. If false, all features in all target │ │ │ │ + * layers will be checked and the closest feature in all target layers │ │ │ │ + * will be chosen. The greedy property determines if the order of the │ │ │ │ + * target layers is significant. By default, the order of the target │ │ │ │ + * layers is significant where layers earlier in the target layer list │ │ │ │ + * have precedence over layers later in the list. Within a single │ │ │ │ + * layer, the closest feature is always chosen for snapping. This │ │ │ │ + * property only determines whether the search for a closer feature │ │ │ │ + * continues after an eligible feature is found in a target layer. │ │ │ │ + * │ │ │ │ + * Valid target properties: │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} A target layer. Features from this │ │ │ │ + * layer will be eligible to act as snapping target for the editable │ │ │ │ + * layer. │ │ │ │ + * tolerance - {Float} The distance (in pixels) at which snapping may occur. │ │ │ │ + * Default is 10. │ │ │ │ + * node - {Boolean} Snap to nodes (first or last point in a geometry) in │ │ │ │ + * target layer. Default is true. │ │ │ │ + * nodeTolerance - {Float} Optional distance at which snapping may occur │ │ │ │ + * for nodes specifically. If none is provided, <tolerance> will be │ │ │ │ + * used. │ │ │ │ + * vertex - {Boolean} Snap to vertices in target layer. Default is true. │ │ │ │ + * vertexTolerance - {Float} Optional distance at which snapping may occur │ │ │ │ + * for vertices specifically. If none is provided, <tolerance> will be │ │ │ │ + * used. │ │ │ │ + * edge - {Boolean} Snap to edges in target layer. Default is true. │ │ │ │ + * edgeTolerance - {Float} Optional distance at which snapping may occur │ │ │ │ + * for edges specifically. If none is provided, <tolerance> will be │ │ │ │ + * used. │ │ │ │ + * filter - {<OpenLayers.Filter>} Optional filter to evaluate to determine if │ │ │ │ + * feature is eligible for snapping. If filter evaluates to true for a │ │ │ │ + * target feature a vertex may be snapped to the feature. │ │ │ │ + * minResolution - {Number} If a minResolution is provided, snapping to this │ │ │ │ + * target will only be considered if the map resolution is greater than │ │ │ │ + * or equal to this value (the minResolution is inclusive). Default is │ │ │ │ + * no minimum resolution limit. │ │ │ │ + * maxResolution - {Number} If a maxResolution is provided, snapping to this │ │ │ │ + * target will only be considered if the map resolution is strictly │ │ │ │ + * less than this value (the maxResolution is exclusive). Default is │ │ │ │ + * no maximum resolution limit. │ │ │ │ */ │ │ │ │ - initialize: function(layers, options) { │ │ │ │ + initialize: function(options) { │ │ │ │ OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.options = options || {}; // TODO: this could be done by the super │ │ │ │ │ │ │ │ - if (this.scope === null) { │ │ │ │ - this.scope = this; │ │ │ │ + // set the editable layer if provided │ │ │ │ + if (this.options.layer) { │ │ │ │ + this.setLayer(this.options.layer); │ │ │ │ } │ │ │ │ - this.initLayer(layers); │ │ │ │ - var callbacks = { │ │ │ │ - click: this.clickFeature, │ │ │ │ - clickout: this.clickoutFeature │ │ │ │ - }; │ │ │ │ - if (this.hover) { │ │ │ │ - callbacks.over = this.overFeature; │ │ │ │ - callbacks.out = this.outFeature; │ │ │ │ + // configure target layers │ │ │ │ + var defaults = OpenLayers.Util.extend({}, this.options.defaults); │ │ │ │ + this.defaults = OpenLayers.Util.applyDefaults(defaults, this.DEFAULTS); │ │ │ │ + this.setTargets(this.options.targets); │ │ │ │ + if (this.targets.length === 0 && this.layer) { │ │ │ │ + this.addTargetLayer(this.layer); │ │ │ │ } │ │ │ │ │ │ │ │ - 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" │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + this.geoToleranceCache = {}; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: initLayer │ │ │ │ - * Assign the layer property. If layers is an array, we need to use │ │ │ │ - * a RootContainer. │ │ │ │ + * APIMethod: setLayer │ │ │ │ + * Set the editable layer. Call the setLayer method if the editable layer │ │ │ │ + * changes and the same control should be used on a new editable layer. │ │ │ │ + * If the control is already active, it will be active after the new │ │ │ │ + * layer is set. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * layers - {<OpenLayers.Layer.Vector>}, or an array of vector layers. │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} The new editable layer. │ │ │ │ */ │ │ │ │ - initLayer: function(layers) { │ │ │ │ - if (OpenLayers.Util.isArray(layers)) { │ │ │ │ - this.layers = layers; │ │ │ │ - this.layer = new OpenLayers.Layer.Vector.RootContainer( │ │ │ │ - this.id + "_container", { │ │ │ │ - layers: layers │ │ │ │ - } │ │ │ │ - ); │ │ │ │ + setLayer: function(layer) { │ │ │ │ + if (this.active) { │ │ │ │ + this.deactivate(); │ │ │ │ + this.layer = layer; │ │ │ │ + this.activate(); │ │ │ │ } 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(); │ │ │ │ + this.layer = layer; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ - * Activates the control. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The control was effectively activated. │ │ │ │ + * Method: setTargets │ │ │ │ + * Set the targets for the snapping agent. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * targets - {Array} An array of target configs or target layers. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ + setTargets: function(targets) { │ │ │ │ + this.targets = []; │ │ │ │ + if (targets && targets.length) { │ │ │ │ + var target; │ │ │ │ + for (var i = 0, len = targets.length; i < len; ++i) { │ │ │ │ + target = targets[i]; │ │ │ │ + if (target instanceof OpenLayers.Layer.Vector) { │ │ │ │ + this.addTargetLayer(target); │ │ │ │ + } else { │ │ │ │ + this.addTarget(target); │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ - return OpenLayers.Control.prototype.activate.apply( │ │ │ │ - this, arguments │ │ │ │ - ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Deactivates the control. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The control was effectively deactivated. │ │ │ │ + * Method: addTargetLayer │ │ │ │ + * Add a target layer with the default target config. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} A target layer. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - ); │ │ │ │ + addTargetLayer: function(layer) { │ │ │ │ + this.addTarget({ │ │ │ │ + layer: layer │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: unselectAll │ │ │ │ - * Unselect all selected features. To unselect all except for a single │ │ │ │ - * feature, set the options.except property to the feature. │ │ │ │ + * Method: addTarget │ │ │ │ + * Add a configured target layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional configuration object. │ │ │ │ + * target - {Object} A target config. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + addTarget: function(target) { │ │ │ │ + target = OpenLayers.Util.applyDefaults(target, this.defaults); │ │ │ │ + target.nodeTolerance = target.nodeTolerance || target.tolerance; │ │ │ │ + target.vertexTolerance = target.vertexTolerance || target.tolerance; │ │ │ │ + target.edgeTolerance = target.edgeTolerance || target.tolerance; │ │ │ │ + this.targets.push(target); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clickFeature │ │ │ │ - * Called on click in a feature │ │ │ │ - * Only responds if this.hover is false. │ │ │ │ + * Method: removeTargetLayer │ │ │ │ + * Remove a target layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} The target layer to remove. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + removeTargetLayer: function(layer) { │ │ │ │ + var target; │ │ │ │ + for (var i = this.targets.length - 1; i >= 0; --i) { │ │ │ │ + target = this.targets[i]; │ │ │ │ + if (target.layer === layer) { │ │ │ │ + this.removeTarget(target); │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: multipleSelect │ │ │ │ - * Allow for multiple selected features based on <multiple> property and │ │ │ │ - * <multipleKey> event modifier. │ │ │ │ + * Method: removeTarget │ │ │ │ + * Remove a target. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Parameters: │ │ │ │ + * target - {Object} A target config. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Toggle the selected state of a feature. │ │ │ │ + * {Array} The targets array. │ │ │ │ */ │ │ │ │ - toggleSelect: function() { │ │ │ │ - return this.toggle || (this.handlers.feature.evt && │ │ │ │ - this.handlers.feature.evt[this.toggleKey]); │ │ │ │ + removeTarget: function(target) { │ │ │ │ + return OpenLayers.Util.removeItem(this.targets, target); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clickoutFeature │ │ │ │ - * Called on click outside a previously clicked (selected) feature. │ │ │ │ - * Only responds if this.hover is false. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Vector.Feature>} │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the control. Activating the control registers listeners for │ │ │ │ + * editing related events so that during feature creation and │ │ │ │ + * modification, moving vertices will trigger snapping. │ │ │ │ */ │ │ │ │ - clickoutFeature: function(feature) { │ │ │ │ - if (!this.hover && this.clickout) { │ │ │ │ - this.unselectAll(); │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + if (this.layer && this.layer.events) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + sketchstarted: this.onSketchModified, │ │ │ │ + sketchmodified: this.onSketchModified, │ │ │ │ + vertexmodified: this.onVertexModified, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ } │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: overFeature │ │ │ │ - * Called on over a feature. │ │ │ │ - * Only responds if this.hover is true. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the control. Deactivating the control unregisters listeners │ │ │ │ + * so feature editing may proceed without engaging the snapping agent. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + if (this.layer && this.layer.events) { │ │ │ │ + this.layer.events.un({ │ │ │ │ + sketchstarted: this.onSketchModified, │ │ │ │ + sketchmodified: this.onSketchModified, │ │ │ │ + vertexmodified: this.onVertexModified, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ } │ │ │ │ } │ │ │ │ + this.feature = null; │ │ │ │ + this.point = null; │ │ │ │ + return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: outFeature │ │ │ │ - * Called on out of a selected feature. │ │ │ │ - * Only responds if this.hover is true. │ │ │ │ + * Method: onSketchModified │ │ │ │ + * Registered as a listener for the sketchmodified event on the editable │ │ │ │ + * layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * event - {Object} The sketch modified event. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + onSketchModified: function(event) { │ │ │ │ + this.feature = event.feature; │ │ │ │ + this.considerSnapping(event.vertex, event.vertex); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: highlight │ │ │ │ - * Redraw feature with the select style. │ │ │ │ + * Method: onVertexModified │ │ │ │ + * Registered as a listener for the vertexmodified event on the editable │ │ │ │ + * layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * event - {Object} The vertex modified event. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ - } │ │ │ │ + onVertexModified: function(event) { │ │ │ │ + this.feature = event.feature; │ │ │ │ + var loc = this.layer.map.getLonLatFromViewPortPx(event.pixel); │ │ │ │ + this.considerSnapping( │ │ │ │ + event.vertex, new OpenLayers.Geometry.Point(loc.lon, loc.lat) │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: unhighlight │ │ │ │ - * Redraw feature with the "default" style │ │ │ │ + * Method: considerSnapping │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} The vertex to be snapped (or │ │ │ │ + * unsnapped). │ │ │ │ + * loc - {<OpenLayers.Geometry.Point>} The location of the mouse in map │ │ │ │ + * coords. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + considerSnapping: function(point, loc) { │ │ │ │ + var best = { │ │ │ │ + rank: Number.POSITIVE_INFINITY, │ │ │ │ + dist: Number.POSITIVE_INFINITY, │ │ │ │ + x: null, │ │ │ │ + y: null │ │ │ │ + }; │ │ │ │ + var snapped = false; │ │ │ │ + var result, target; │ │ │ │ + for (var i = 0, len = this.targets.length; i < len; ++i) { │ │ │ │ + target = this.targets[i]; │ │ │ │ + result = this.testTarget(target, loc); │ │ │ │ + if (result) { │ │ │ │ + if (this.greedy) { │ │ │ │ + best = result; │ │ │ │ + best.target = target; │ │ │ │ + snapped = true; │ │ │ │ + break; │ │ │ │ + } else { │ │ │ │ + if ((result.rank < best.rank) || │ │ │ │ + (result.rank === best.rank && result.dist < best.dist)) { │ │ │ │ + best = result; │ │ │ │ + best.target = target; │ │ │ │ + snapped = true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - 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 (snapped) { │ │ │ │ + var proceed = this.events.triggerEvent("beforesnap", { │ │ │ │ + point: point, │ │ │ │ + x: best.x, │ │ │ │ + y: best.y, │ │ │ │ + distance: best.dist, │ │ │ │ + layer: best.target.layer, │ │ │ │ + snapType: this.precedence[best.rank] │ │ │ │ }); │ │ │ │ - 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 │ │ │ │ + if (proceed !== false) { │ │ │ │ + point.x = best.x; │ │ │ │ + point.y = best.y; │ │ │ │ + this.point = point; │ │ │ │ + this.events.triggerEvent("snap", { │ │ │ │ + point: point, │ │ │ │ + snapType: this.precedence[best.rank], │ │ │ │ + layer: best.target.layer, │ │ │ │ + distance: best.dist │ │ │ │ }); │ │ │ │ - this.onSelect.call(this.scope, feature); │ │ │ │ + } else { │ │ │ │ + snapped = false; │ │ │ │ } │ │ │ │ } │ │ │ │ + if (this.point && !snapped) { │ │ │ │ + point.x = loc.x; │ │ │ │ + point.y = loc.y; │ │ │ │ + this.point = null; │ │ │ │ + this.events.triggerEvent("unsnap", { │ │ │ │ + point: point │ │ │ │ + }); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: unselect │ │ │ │ - * Remove feature from the layer's selectedFeature array, render the feature as │ │ │ │ - * normal, and call the onUnselect function. │ │ │ │ + * Method: testTarget │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * target - {Object} Object with target layer configuration. │ │ │ │ + * loc - {<OpenLayers.Geometry.Point>} The location of the mouse in map │ │ │ │ + * coords. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * position - {<OpenLayers.Bounds> || <OpenLayers.Pixel> } │ │ │ │ + * Returns: │ │ │ │ + * {Object} A result object with rank, dist, x, and y properties. │ │ │ │ + * Returns null if candidate is not eligible for snapping. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ + testTarget: function(target, loc) { │ │ │ │ + var resolution = this.layer.map.getResolution(); │ │ │ │ + if ("minResolution" in target) { │ │ │ │ + if (resolution < target.minResolution) { │ │ │ │ + return null; │ │ │ │ } │ │ │ │ - │ │ │ │ - // 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); │ │ │ │ + } │ │ │ │ + if ("maxResolution" in target) { │ │ │ │ + if (resolution >= target.maxResolution) { │ │ │ │ + return null; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var tolerance = { │ │ │ │ + node: this.getGeoTolerance(target.nodeTolerance, resolution), │ │ │ │ + vertex: this.getGeoTolerance(target.vertexTolerance, resolution), │ │ │ │ + edge: this.getGeoTolerance(target.edgeTolerance, resolution) │ │ │ │ + }; │ │ │ │ + // this could be cached if we don't support setting tolerance values directly │ │ │ │ + var maxTolerance = Math.max( │ │ │ │ + tolerance.node, tolerance.vertex, tolerance.edge │ │ │ │ + ); │ │ │ │ + var result = { │ │ │ │ + rank: Number.POSITIVE_INFINITY, │ │ │ │ + dist: Number.POSITIVE_INFINITY │ │ │ │ + }; │ │ │ │ + var eligible = false; │ │ │ │ + var features = target.layer.features; │ │ │ │ + var feature, type, vertices, vertex, closest, dist, found; │ │ │ │ + var numTypes = this.precedence.length; │ │ │ │ + var ll = new OpenLayers.LonLat(loc.x, loc.y); │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + if (feature !== this.feature && !feature._sketch && │ │ │ │ + feature.state !== OpenLayers.State.DELETE && │ │ │ │ + (!target.filter || target.filter.evaluate(feature))) { │ │ │ │ + if (feature.atPoint(ll, maxTolerance, maxTolerance)) { │ │ │ │ + for (var j = 0, stop = Math.min(result.rank + 1, numTypes); j < stop; ++j) { │ │ │ │ + type = this.precedence[j]; │ │ │ │ + if (target[type]) { │ │ │ │ + if (type === "edge") { │ │ │ │ + closest = feature.geometry.distanceTo(loc, { │ │ │ │ + details: true │ │ │ │ + }); │ │ │ │ + dist = closest.distance; │ │ │ │ + if (dist <= tolerance[type] && dist < result.dist) { │ │ │ │ + result = { │ │ │ │ + rank: j, │ │ │ │ + dist: dist, │ │ │ │ + x: closest.x0, │ │ │ │ + y: closest.y0 // closest coords on feature │ │ │ │ + }; │ │ │ │ + eligible = true; │ │ │ │ + // don't look for lower precedence types for this feature │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + // look for nodes or vertices │ │ │ │ + vertices = feature.geometry.getVertices(type === "node"); │ │ │ │ + found = false; │ │ │ │ + for (var k = 0, klen = vertices.length; k < klen; ++k) { │ │ │ │ + vertex = vertices[k]; │ │ │ │ + dist = vertex.distanceTo(loc); │ │ │ │ + if (dist <= tolerance[type] && │ │ │ │ + (j < result.rank || (j === result.rank && dist < result.dist))) { │ │ │ │ + result = { │ │ │ │ + rank: j, │ │ │ │ + dist: dist, │ │ │ │ + x: vertex.x, │ │ │ │ + y: vertex.y │ │ │ │ + }; │ │ │ │ + eligible = true; │ │ │ │ + found = true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (found) { │ │ │ │ + // don't look for lower precedence types for this feature │ │ │ │ + break; │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ - this.multiple = prevMultiple; │ │ │ │ - this.events.triggerEvent("boxselectionend", { │ │ │ │ - layers: layers │ │ │ │ - }); │ │ │ │ } │ │ │ │ + return eligible ? result : null; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * Set the map property for the control. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: getGeoTolerance │ │ │ │ + * Calculate a tolerance in map units given a tolerance in pixels. This │ │ │ │ + * takes advantage of the <geoToleranceCache> when the map resolution │ │ │ │ + * has not changed. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * tolerance - {Number} A tolerance value in pixels. │ │ │ │ + * resolution - {Number} Map resolution. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Number} A tolerance value in map units. │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - this.handlers.feature.setMap(map); │ │ │ │ - if (this.box) { │ │ │ │ - this.handlers.box.setMap(map); │ │ │ │ + getGeoTolerance: function(tolerance, resolution) { │ │ │ │ + if (resolution !== this.resolution) { │ │ │ │ + this.resolution = resolution; │ │ │ │ + this.geoToleranceCache = {}; │ │ │ │ } │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + var geoTolerance = this.geoToleranceCache[tolerance]; │ │ │ │ + if (geoTolerance === undefined) { │ │ │ │ + geoTolerance = tolerance * resolution; │ │ │ │ + this.geoToleranceCache[tolerance] = geoTolerance; │ │ │ │ + } │ │ │ │ + return geoTolerance; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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>} │ │ │ │ + * Method: destroy │ │ │ │ + * Clean up the control. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ + destroy: function() { │ │ │ │ + if (this.active) { │ │ │ │ + this.deactivate(); // TODO: this should be handled by the super │ │ │ │ } │ │ │ │ + delete this.layer; │ │ │ │ + delete this.targets; │ │ │ │ + OpenLayers.Control.prototype.destroy.call(this); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.SelectFeature" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Snapping" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Control/MousePosition.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ @@ -64519,6036 +68354,4475 @@ │ │ │ │ this.suffix; │ │ │ │ return newHtml; │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Control.MousePosition" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/TouchNavigation.js │ │ │ │ + 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/DragPan.js │ │ │ │ - * @requires OpenLayers/Control/PinchZoom.js │ │ │ │ - * @requires OpenLayers/Handler/Click.js │ │ │ │ + * @requires OpenLayers/Control.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. │ │ │ │ + * Class: OpenLayers.Control.Attribution │ │ │ │ + * The attribution control adds attribution from layers to the map display. │ │ │ │ + * It uses 'attribution' property of each layer. │ │ │ │ * │ │ │ │ - * Inherits: │ │ │ │ + * Inherits from: │ │ │ │ * - <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, │ │ │ │ +OpenLayers.Control.Attribution = │ │ │ │ + OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: documentDrag │ │ │ │ - * {Boolean} Allow panning of the map by dragging outside map viewport. │ │ │ │ - * Default is false. │ │ │ │ - */ │ │ │ │ - documentDrag: false, │ │ │ │ + /** │ │ │ │ + * APIProperty: separator │ │ │ │ + * {String} String used to separate layers. │ │ │ │ + */ │ │ │ │ + separator: ", ", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ - */ │ │ │ │ - autoActivate: true, │ │ │ │ + /** │ │ │ │ + * 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.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); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.Attribution │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} Options for control. │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: destroy │ │ │ │ + * Destroy control. │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + this.map.events.un({ │ │ │ │ + "removelayer": this.updateAttribution, │ │ │ │ + "addlayer": this.updateAttribution, │ │ │ │ + "changelayer": this.updateAttribution, │ │ │ │ + "changebaselayer": this.updateAttribution, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - }, │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 │ │ │ │ + * Initialize control. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A reference to the DIV DOMElement containing the control │ │ │ │ + */ │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ + this.map.events.on({ │ │ │ │ + 'changebaselayer': this.updateAttribution, │ │ │ │ + 'changelayer': this.updateAttribution, │ │ │ │ + 'addlayer': this.updateAttribution, │ │ │ │ + 'removelayer': this.updateAttribution, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.updateAttribution(); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: defaultClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - */ │ │ │ │ - defaultClick: function(evt) { │ │ │ │ - if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ - this.map.zoomOut(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + return this.div; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: defaultDblClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - */ │ │ │ │ - defaultDblClick: function(evt) { │ │ │ │ - this.map.zoomTo(this.map.zoom + 1, evt.xy); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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.TouchNavigation" │ │ │ │ -}); │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Attribution" │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Strategy/Cluster.js │ │ │ │ + OpenLayers/Control/LayerSwitcher.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 │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ + * @requires OpenLayers/Events/buttonclick.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Strategy.Cluster │ │ │ │ - * Strategy for vector feature clustering. │ │ │ │ + * Class: OpenLayers.Control.LayerSwitcher │ │ │ │ + * The LayerSwitcher control displays a table of contents for the map. This │ │ │ │ + * allows the user interface to switch between BaseLasyers and to show or hide │ │ │ │ + * Overlays. By default the switcher is shown minimized on the right edge of │ │ │ │ + * the map, the user may expand it by clicking on the handle. │ │ │ │ + * │ │ │ │ + * To create the LayerSwitcher outside of the map, pass the Id of a html div │ │ │ │ + * as the first argument to the constructor. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Strategy> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: distance │ │ │ │ - * {Integer} Pixel distance between features that should be considered a │ │ │ │ - * single cluster. Default is 20 pixels. │ │ │ │ - */ │ │ │ │ - distance: 20, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: threshold │ │ │ │ - * {Integer} Optional threshold below which original features will be │ │ │ │ - * added to the layer instead of clusters. For example, a threshold │ │ │ │ - * of 3 would mean that any time there are 2 or fewer features in │ │ │ │ - * a cluster, those features will be added directly to the layer instead │ │ │ │ - * of a cluster representing those features. Default is null (which is │ │ │ │ - * equivalent to 1 - meaning that clusters may contain just one feature). │ │ │ │ - */ │ │ │ │ - threshold: null, │ │ │ │ +OpenLayers.Control.LayerSwitcher = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: features │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} Cached features. │ │ │ │ + /** │ │ │ │ + * Property: layerStates │ │ │ │ + * {Array(Object)} Basically a copy of the "state" of the map's layers │ │ │ │ + * the last time the control was drawn. We have this in order to avoid │ │ │ │ + * unnecessarily redrawing the control. │ │ │ │ */ │ │ │ │ - features: null, │ │ │ │ + layerStates: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: clusters │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} Calculated clusters. │ │ │ │ - */ │ │ │ │ - clusters: null, │ │ │ │ + // DOM Elements │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: clustering │ │ │ │ - * {Boolean} The strategy is currently clustering features. │ │ │ │ + * Property: layersDiv │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - clustering: false, │ │ │ │ + layersDiv: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: resolution │ │ │ │ - * {Float} The resolution (map units per pixel) of the current cluster set. │ │ │ │ + * Property: baseLayersDiv │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - resolution: null, │ │ │ │ + baseLayersDiv: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Strategy.Cluster │ │ │ │ - * Create a new clustering strategy. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * Property: baseLayers │ │ │ │ + * {Array(Object)} │ │ │ │ */ │ │ │ │ + baseLayers: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully activated. │ │ │ │ - */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - "beforefeaturesadded": this.cacheFeatures, │ │ │ │ - "featuresremoved": this.clearCache, │ │ │ │ - "moveend": this.cluster, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - return activated; │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ - * tear-down. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully deactivated. │ │ │ │ + * Property: dataLbl │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.layer.events.un({ │ │ │ │ - "beforefeaturesadded": this.cacheFeatures, │ │ │ │ - "featuresremoved": this.clearCache, │ │ │ │ - "moveend": this.cluster, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - return deactivated; │ │ │ │ - }, │ │ │ │ + dataLbl: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: cacheFeatures │ │ │ │ - * Cache features before they are added to the layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * event - {Object} The event that this was listening for. This will come │ │ │ │ - * with a batch of features to be clustered. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} False to stop features from being added to the layer. │ │ │ │ + * Property: dataLayersDiv │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - cacheFeatures: function(event) { │ │ │ │ - var propagate = true; │ │ │ │ - if (!this.clustering) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.features = event.features; │ │ │ │ - this.cluster(); │ │ │ │ - propagate = false; │ │ │ │ - } │ │ │ │ - return propagate; │ │ │ │ - }, │ │ │ │ + dataLayersDiv: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clearCache │ │ │ │ - * Clear out the cached features. │ │ │ │ + * Property: dataLayers │ │ │ │ + * {Array(Object)} │ │ │ │ */ │ │ │ │ - clearCache: function() { │ │ │ │ - if (!this.clustering) { │ │ │ │ - this.features = null; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + dataLayers: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: cluster │ │ │ │ - * Cluster features based on some threshold distance. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * event - {Object} The event received when cluster is called as a │ │ │ │ - * result of a moveend event. │ │ │ │ - */ │ │ │ │ - cluster: function(event) { │ │ │ │ - if ((!event || event.zoomChanged) && this.features) { │ │ │ │ - var resolution = this.layer.map.getResolution(); │ │ │ │ - if (resolution != this.resolution || !this.clustersExist()) { │ │ │ │ - this.resolution = resolution; │ │ │ │ - var clusters = []; │ │ │ │ - var feature, clustered, cluster; │ │ │ │ - for (var i = 0; i < this.features.length; ++i) { │ │ │ │ - feature = this.features[i]; │ │ │ │ - if (feature.geometry) { │ │ │ │ - clustered = false; │ │ │ │ - for (var j = clusters.length - 1; j >= 0; --j) { │ │ │ │ - cluster = clusters[j]; │ │ │ │ - if (this.shouldCluster(cluster, feature)) { │ │ │ │ - this.addToCluster(cluster, feature); │ │ │ │ - clustered = true; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (!clustered) { │ │ │ │ - clusters.push(this.createCluster(this.features[i])); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.clustering = true; │ │ │ │ - this.layer.removeAllFeatures(); │ │ │ │ - this.clustering = false; │ │ │ │ - if (clusters.length > 0) { │ │ │ │ - if (this.threshold > 1) { │ │ │ │ - var clone = clusters.slice(); │ │ │ │ - clusters = []; │ │ │ │ - var candidate; │ │ │ │ - for (var i = 0, len = clone.length; i < len; ++i) { │ │ │ │ - candidate = clone[i]; │ │ │ │ - if (candidate.attributes.count < this.threshold) { │ │ │ │ - Array.prototype.push.apply(clusters, candidate.cluster); │ │ │ │ - } else { │ │ │ │ - clusters.push(candidate); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.clustering = true; │ │ │ │ - // A legitimate feature addition could occur during this │ │ │ │ - // addFeatures call. For clustering to behave well, features │ │ │ │ - // should be removed from a layer before requesting a new batch. │ │ │ │ - this.layer.addFeatures(clusters); │ │ │ │ - this.clustering = false; │ │ │ │ - } │ │ │ │ - this.clusters = clusters; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clustersExist │ │ │ │ - * Determine whether calculated clusters are already on the layer. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The calculated clusters are already on the layer. │ │ │ │ + * Property: minimizeDiv │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - clustersExist: function() { │ │ │ │ - var exist = false; │ │ │ │ - if (this.clusters && this.clusters.length > 0 && │ │ │ │ - this.clusters.length == this.layer.features.length) { │ │ │ │ - exist = true; │ │ │ │ - for (var i = 0; i < this.clusters.length; ++i) { │ │ │ │ - if (this.clusters[i] != this.layer.features[i]) { │ │ │ │ - exist = false; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return exist; │ │ │ │ - }, │ │ │ │ + minimizeDiv: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: shouldCluster │ │ │ │ - * Determine whether to include a feature in a given cluster. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * cluster - {<OpenLayers.Feature.Vector>} A cluster. │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} A feature. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The feature should be included in the cluster. │ │ │ │ + * Property: maximizeDiv │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - shouldCluster: function(cluster, feature) { │ │ │ │ - var cc = cluster.geometry.getBounds().getCenterLonLat(); │ │ │ │ - var fc = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ - var distance = ( │ │ │ │ - Math.sqrt( │ │ │ │ - Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2) │ │ │ │ - ) / this.resolution │ │ │ │ - ); │ │ │ │ - return (distance <= this.distance); │ │ │ │ - }, │ │ │ │ + maximizeDiv: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: addToCluster │ │ │ │ - * Add a feature to a cluster. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * cluster - {<OpenLayers.Feature.Vector>} A cluster. │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} A feature. │ │ │ │ + * APIProperty: ascending │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - addToCluster: function(cluster, feature) { │ │ │ │ - cluster.cluster.push(feature); │ │ │ │ - cluster.attributes.count += 1; │ │ │ │ - }, │ │ │ │ + ascending: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createCluster │ │ │ │ - * Given a feature, create a cluster. │ │ │ │ + * Constructor: OpenLayers.Control.LayerSwitcher │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} A cluster. │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ - createCluster: function(feature) { │ │ │ │ - var center = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ - var cluster = new OpenLayers.Feature.Vector( │ │ │ │ - new OpenLayers.Geometry.Point(center.lon, center.lat), { │ │ │ │ - count: 1 │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - cluster.cluster = [feature]; │ │ │ │ - return cluster; │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ + this.layerStates = []; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Cluster" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Strategy/BBOX.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 │ │ │ │ - * @requires OpenLayers/Filter/Spatial.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Strategy.BBOX │ │ │ │ - * A simple strategy that reads new features when the viewport invalidates │ │ │ │ - * some bounds. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Strategy> │ │ │ │ - */ │ │ │ │ -OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Property: bounds │ │ │ │ - * {<OpenLayers.Bounds>} The current data bounds (in the same projection │ │ │ │ - * as the layer - not always the same projection as the map). │ │ │ │ - */ │ │ │ │ - bounds: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: resolution │ │ │ │ - * {Float} The current data resolution. │ │ │ │ + * APIMethod: destroy │ │ │ │ */ │ │ │ │ - resolution: null, │ │ │ │ + destroy: function() { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: ratio │ │ │ │ - * {Float} The ratio of the data bounds to the viewport bounds (in each │ │ │ │ - * dimension). Default is 2. │ │ │ │ - */ │ │ │ │ - ratio: 2, │ │ │ │ + //clear out layers info and unregister their events │ │ │ │ + this.clearLayersArray("base"); │ │ │ │ + this.clearLayersArray("data"); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: resFactor │ │ │ │ - * {Float} Optional factor used to determine when previously requested │ │ │ │ - * features are invalid. If set, the resFactor will be compared to the │ │ │ │ - * resolution of the previous request to the current map resolution. │ │ │ │ - * If resFactor > (old / new) and 1/resFactor < (old / new). If you │ │ │ │ - * set a resFactor of 1, data will be requested every time the │ │ │ │ - * resolution changes. If you set a resFactor of 3, data will be │ │ │ │ - * requested if the old resolution is 3 times the new, or if the new is │ │ │ │ - * 3 times the old. If the old bounds do not contain the new bounds │ │ │ │ - * new data will always be requested (with or without considering │ │ │ │ - * resFactor). │ │ │ │ - */ │ │ │ │ - resFactor: null, │ │ │ │ + this.map.events.un({ │ │ │ │ + buttonclick: this.onButtonClick, │ │ │ │ + addlayer: this.redraw, │ │ │ │ + changelayer: this.redraw, │ │ │ │ + removelayer: this.redraw, │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: response │ │ │ │ - * {<OpenLayers.Protocol.Response>} The protocol response object returned │ │ │ │ - * by the layer protocol. │ │ │ │ - */ │ │ │ │ - response: null, │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Strategy.BBOX │ │ │ │ - * Create a new BBOX strategy. │ │ │ │ + * Method: setMap │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * Properties: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: activate │ │ │ │ - * Set up strategy with regard to reading new batches of remote data. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully activated. │ │ │ │ - */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - "moveend": this.update, │ │ │ │ - "refresh": this.update, │ │ │ │ - "visibilitychanged": this.update, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.update(); │ │ │ │ + this.map.events.on({ │ │ │ │ + addlayer: this.redraw, │ │ │ │ + changelayer: this.redraw, │ │ │ │ + removelayer: this.redraw, │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + if (this.outsideViewport) { │ │ │ │ + this.events.attachToElement(this.div); │ │ │ │ + this.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ + } else { │ │ │ │ + this.map.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Tear down strategy with regard to reading new batches of remote data. │ │ │ │ - * │ │ │ │ + * Method: draw │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} The strategy was successfully deactivated. │ │ │ │ + * {DOMElement} A reference to the DIV DOMElement containing the │ │ │ │ + * switcher tabs. │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.layer.events.un({ │ │ │ │ - "moveend": this.update, │ │ │ │ - "refresh": this.update, │ │ │ │ - "visibilitychanged": this.update, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this); │ │ │ │ + │ │ │ │ + // create layout divs │ │ │ │ + this.loadContents(); │ │ │ │ + │ │ │ │ + // set mode to minimize │ │ │ │ + if (!this.outsideViewport) { │ │ │ │ + this.minimizeControl(); │ │ │ │ } │ │ │ │ - return deactivated; │ │ │ │ + │ │ │ │ + // populate div with current info │ │ │ │ + this.redraw(); │ │ │ │ + │ │ │ │ + return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: update │ │ │ │ - * Callback function called on "moveend" or "refresh" layer events. │ │ │ │ + * Method: onButtonClick │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will determine │ │ │ │ - * the behaviour of this Strategy │ │ │ │ - * │ │ │ │ - * Valid options include: │ │ │ │ - * force - {Boolean} if true, new data must be unconditionally read. │ │ │ │ - * noAbort - {Boolean} if true, do not abort previous requests. │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - update: function(options) { │ │ │ │ - var mapBounds = this.getMapBounds(); │ │ │ │ - if (mapBounds !== null && ((options && options.force) || │ │ │ │ - (this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds)))) { │ │ │ │ - this.calculateBounds(mapBounds); │ │ │ │ - this.resolution = this.layer.map.getResolution(); │ │ │ │ - this.triggerRead(options); │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + var button = evt.buttonElement; │ │ │ │ + if (button === this.minimizeDiv) { │ │ │ │ + this.minimizeControl(); │ │ │ │ + } else if (button === this.maximizeDiv) { │ │ │ │ + this.maximizeControl(); │ │ │ │ + } else if (button._layerSwitcher === this.id) { │ │ │ │ + if (button["for"]) { │ │ │ │ + button = document.getElementById(button["for"]); │ │ │ │ + } │ │ │ │ + if (!button.disabled) { │ │ │ │ + if (button.type == "radio") { │ │ │ │ + button.checked = true; │ │ │ │ + this.map.setBaseLayer(this.map.getLayer(button._layer)); │ │ │ │ + } else { │ │ │ │ + button.checked = !button.checked; │ │ │ │ + this.updateMap(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getMapBounds │ │ │ │ - * Get the map bounds expressed in the same projection as this layer. │ │ │ │ + * Method: clearLayersArray │ │ │ │ + * User specifies either "base" or "data". we then clear all the │ │ │ │ + * corresponding listeners, the div, and reinitialize a new array. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} Map bounds in the projection of the layer. │ │ │ │ + * Parameters: │ │ │ │ + * layersType - {String} │ │ │ │ */ │ │ │ │ - getMapBounds: function() { │ │ │ │ - if (this.layer.map === null) { │ │ │ │ - return null; │ │ │ │ - } │ │ │ │ - var bounds = this.layer.map.getExtent(); │ │ │ │ - if (bounds && !this.layer.projection.equals( │ │ │ │ - this.layer.map.getProjectionObject())) { │ │ │ │ - bounds = bounds.clone().transform( │ │ │ │ - this.layer.map.getProjectionObject(), this.layer.projection │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return bounds; │ │ │ │ + clearLayersArray: function(layersType) { │ │ │ │ + this[layersType + "LayersDiv"].innerHTML = ""; │ │ │ │ + this[layersType + "Layers"] = []; │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: invalidBounds │ │ │ │ - * Determine whether the previously requested set of features is invalid. │ │ │ │ - * This occurs when the new map bounds do not contain the previously │ │ │ │ - * requested bounds. In addition, if <resFactor> is set, it will be │ │ │ │ - * considered. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be │ │ │ │ - * retrieved from the map object if not provided │ │ │ │ + * Method: checkRedraw │ │ │ │ + * Checks if the layer state has changed since the last redraw() call. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} │ │ │ │ + * {Boolean} The layer state changed since the last redraw() call. │ │ │ │ */ │ │ │ │ - invalidBounds: function(mapBounds) { │ │ │ │ - if (!mapBounds) { │ │ │ │ - mapBounds = this.getMapBounds(); │ │ │ │ - } │ │ │ │ - var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds); │ │ │ │ - if (!invalid && this.resFactor) { │ │ │ │ - var ratio = this.resolution / this.layer.map.getResolution(); │ │ │ │ - invalid = (ratio >= this.resFactor || ratio <= (1 / this.resFactor)); │ │ │ │ + checkRedraw: function() { │ │ │ │ + if (!this.layerStates.length || │ │ │ │ + (this.map.layers.length != this.layerStates.length)) { │ │ │ │ + return true; │ │ │ │ } │ │ │ │ - return invalid; │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: calculateBounds │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be │ │ │ │ - * retrieved from the map object if not provided │ │ │ │ - */ │ │ │ │ - calculateBounds: function(mapBounds) { │ │ │ │ - if (!mapBounds) { │ │ │ │ - mapBounds = this.getMapBounds(); │ │ │ │ + for (var i = 0, len = this.layerStates.length; i < len; i++) { │ │ │ │ + var layerState = this.layerStates[i]; │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + if ((layerState.name != layer.name) || │ │ │ │ + (layerState.inRange != layer.inRange) || │ │ │ │ + (layerState.id != layer.id) || │ │ │ │ + (layerState.visibility != layer.visibility)) { │ │ │ │ + return true; │ │ │ │ + } │ │ │ │ } │ │ │ │ - var center = mapBounds.getCenterLonLat(); │ │ │ │ - var dataWidth = mapBounds.getWidth() * this.ratio; │ │ │ │ - var dataHeight = mapBounds.getHeight() * this.ratio; │ │ │ │ - this.bounds = new OpenLayers.Bounds( │ │ │ │ - center.lon - (dataWidth / 2), │ │ │ │ - center.lat - (dataHeight / 2), │ │ │ │ - center.lon + (dataWidth / 2), │ │ │ │ - center.lat + (dataHeight / 2) │ │ │ │ - ); │ │ │ │ + │ │ │ │ + return false; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: triggerRead │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Additional options for the protocol's read method │ │ │ │ - * (optional) │ │ │ │ + * Method: redraw │ │ │ │ + * Goes through and takes the current state of the Map and rebuilds the │ │ │ │ + * control to display that state. Groups base layers into a │ │ │ │ + * radio-button group and lists each data layer with a checkbox. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Protocol.Response>} The protocol response object │ │ │ │ - * returned by the layer protocol. │ │ │ │ + * {DOMElement} A reference to the DIV DOMElement containing the control │ │ │ │ */ │ │ │ │ - triggerRead: function(options) { │ │ │ │ - if (this.response && !(options && options.noAbort === true)) { │ │ │ │ - this.layer.protocol.abort(this.response); │ │ │ │ - this.layer.events.triggerEvent("loadend"); │ │ │ │ + redraw: function() { │ │ │ │ + //if the state hasn't changed since last redraw, no need │ │ │ │ + // to do anything. Just return the existing div. │ │ │ │ + if (!this.checkRedraw()) { │ │ │ │ + return this.div; │ │ │ │ } │ │ │ │ - var evt = { │ │ │ │ - filter: this.createFilter() │ │ │ │ - }; │ │ │ │ - this.layer.events.triggerEvent("loadstart", evt); │ │ │ │ - this.response = this.layer.protocol.read( │ │ │ │ - OpenLayers.Util.applyDefaults({ │ │ │ │ - filter: evt.filter, │ │ │ │ - callback: this.merge, │ │ │ │ - scope: this │ │ │ │ - }, options)); │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: createFilter │ │ │ │ - * Creates a spatial BBOX filter. If the layer that this strategy belongs │ │ │ │ - * to has a filter property, this filter will be combined with the BBOX │ │ │ │ - * filter. │ │ │ │ - * │ │ │ │ - * Returns │ │ │ │ - * {<OpenLayers.Filter>} The filter object. │ │ │ │ - */ │ │ │ │ - createFilter: function() { │ │ │ │ - var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ - value: this.bounds, │ │ │ │ - projection: this.layer.projection │ │ │ │ - }); │ │ │ │ - if (this.layer.filter) { │ │ │ │ - filter = new OpenLayers.Filter.Logical({ │ │ │ │ - type: OpenLayers.Filter.Logical.AND, │ │ │ │ - filters: [this.layer.filter, filter] │ │ │ │ - }); │ │ │ │ + //clear out previous layers │ │ │ │ + this.clearLayersArray("base"); │ │ │ │ + this.clearLayersArray("data"); │ │ │ │ + │ │ │ │ + var containsOverlays = false; │ │ │ │ + var containsBaseLayers = false; │ │ │ │ + │ │ │ │ + // Save state -- for checking layer if the map state changed. │ │ │ │ + // We save this before redrawing, because in the process of redrawing │ │ │ │ + // we will trigger more visibility changes, and we want to not redraw │ │ │ │ + // and enter an infinite loop. │ │ │ │ + var len = this.map.layers.length; │ │ │ │ + this.layerStates = new Array(len); │ │ │ │ + for (var i = 0; i < len; i++) { │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + this.layerStates[i] = { │ │ │ │ + 'name': layer.name, │ │ │ │ + 'visibility': layer.visibility, │ │ │ │ + 'inRange': layer.inRange, │ │ │ │ + 'id': layer.id │ │ │ │ + }; │ │ │ │ } │ │ │ │ - return filter; │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: merge │ │ │ │ - * Given a list of features, determine which ones to add 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) { │ │ │ │ - this.layer.destroyFeatures(); │ │ │ │ - if (resp.success()) { │ │ │ │ - var features = resp.features; │ │ │ │ - if (features && features.length > 0) { │ │ │ │ - var remote = this.layer.projection; │ │ │ │ - var local = this.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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.layer.addFeatures(features); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.bounds = null; │ │ │ │ + var layers = this.map.layers.slice(); │ │ │ │ + if (!this.ascending) { │ │ │ │ + layers.reverse(); │ │ │ │ } │ │ │ │ - this.response = null; │ │ │ │ - this.layer.events.triggerEvent("loadend", { │ │ │ │ - response: resp │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + var layer = layers[i]; │ │ │ │ + var baseLayer = layer.isBaseLayer; │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.BBOX" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Strategy/Save.js │ │ │ │ - ====================================================================== */ │ │ │ │ + if (layer.displayInLayerSwitcher) { │ │ │ │ │ │ │ │ -/* 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. */ │ │ │ │ + if (baseLayer) { │ │ │ │ + containsBaseLayers = true; │ │ │ │ + } else { │ │ │ │ + containsOverlays = true; │ │ │ │ + } │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Strategy.js │ │ │ │ - */ │ │ │ │ + // only check a baselayer if it is *the* baselayer, check data │ │ │ │ + // layers if they are visible │ │ │ │ + var checked = (baseLayer) ? (layer == this.map.baseLayer) : │ │ │ │ + layer.getVisibility(); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Strategy.Save │ │ │ │ - * A strategy that commits newly created or modified features. By default │ │ │ │ - * the strategy waits for a call to <save> before persisting changes. By │ │ │ │ - * configuring the strategy with the <auto> option, changes can be saved │ │ │ │ - * automatically. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Strategy> │ │ │ │ - */ │ │ │ │ -OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + // create input element │ │ │ │ + var inputElem = document.createElement("input"), │ │ │ │ + // The input shall have an id attribute so we can use │ │ │ │ + // labels to interact with them. │ │ │ │ + inputId = OpenLayers.Util.createUniqueID( │ │ │ │ + this.id + "_input_" │ │ │ │ + ); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: events │ │ │ │ - * {<OpenLayers.Events>} An events object that handles all │ │ │ │ - * events on the strategy object. │ │ │ │ - * │ │ │ │ - * Register a listener for a particular event with the following syntax: │ │ │ │ - * (code) │ │ │ │ - * strategy.events.register(type, obj, listener); │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * Supported event types: │ │ │ │ - * start - Triggered before saving │ │ │ │ - * success - Triggered after a successful transaction │ │ │ │ - * fail - Triggered after a failed transaction │ │ │ │ - * │ │ │ │ - */ │ │ │ │ + inputElem.id = inputId; │ │ │ │ + inputElem.name = (baseLayer) ? this.id + "_baseLayers" : layer.name; │ │ │ │ + inputElem.type = (baseLayer) ? "radio" : "checkbox"; │ │ │ │ + inputElem.value = layer.name; │ │ │ │ + inputElem.checked = checked; │ │ │ │ + inputElem.defaultChecked = checked; │ │ │ │ + inputElem.className = "olButton"; │ │ │ │ + inputElem._layer = layer.id; │ │ │ │ + inputElem._layerSwitcher = this.id; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: events │ │ │ │ - * {<OpenLayers.Events>} Events instance for triggering this protocol │ │ │ │ - * events. │ │ │ │ - */ │ │ │ │ - events: null, │ │ │ │ + if (!baseLayer && !layer.inRange) { │ │ │ │ + inputElem.disabled = true; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: auto │ │ │ │ - * {Boolean | Number} Auto-save. Default is false. If true, features will be │ │ │ │ - * saved immediately after being added to the layer and with each │ │ │ │ - * modification or deletion. If auto is a number, features will be │ │ │ │ - * saved on an interval provided by the value (in seconds). │ │ │ │ - */ │ │ │ │ - auto: false, │ │ │ │ + // create span │ │ │ │ + var labelSpan = document.createElement("label"); │ │ │ │ + // this isn't the DOM attribute 'for', but an arbitrary name we │ │ │ │ + // use to find the appropriate input element in <onButtonClick> │ │ │ │ + labelSpan["for"] = inputElem.id; │ │ │ │ + OpenLayers.Element.addClass(labelSpan, "labelSpan olButton"); │ │ │ │ + labelSpan._layer = layer.id; │ │ │ │ + labelSpan._layerSwitcher = this.id; │ │ │ │ + if (!baseLayer && !layer.inRange) { │ │ │ │ + labelSpan.style.color = "gray"; │ │ │ │ + } │ │ │ │ + labelSpan.innerHTML = layer.name; │ │ │ │ + labelSpan.style.verticalAlign = (baseLayer) ? "bottom" : │ │ │ │ + "baseline"; │ │ │ │ + // create line break │ │ │ │ + var br = document.createElement("br"); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: timer │ │ │ │ - * {Number} The id of the timer. │ │ │ │ - */ │ │ │ │ - timer: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Strategy.Save │ │ │ │ - * Create a new Save strategy. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Strategy.prototype.initialize.apply(this, [options]); │ │ │ │ - this.events = new OpenLayers.Events(this); │ │ │ │ - }, │ │ │ │ + var groupArray = (baseLayer) ? this.baseLayers : │ │ │ │ + this.dataLayers; │ │ │ │ + groupArray.push({ │ │ │ │ + 'layer': layer, │ │ │ │ + 'inputElem': inputElem, │ │ │ │ + 'labelSpan': labelSpan │ │ │ │ + }); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully activated. │ │ │ │ - */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - if (this.auto) { │ │ │ │ - if (typeof this.auto === "number") { │ │ │ │ - this.timer = window.setInterval( │ │ │ │ - OpenLayers.Function.bind(this.save, this), │ │ │ │ - this.auto * 1000 │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - this.layer.events.on({ │ │ │ │ - "featureadded": this.triggerSave, │ │ │ │ - "afterfeaturemodified": this.triggerSave, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ + │ │ │ │ + var groupDiv = (baseLayer) ? this.baseLayersDiv : │ │ │ │ + this.dataLayersDiv; │ │ │ │ + groupDiv.appendChild(inputElem); │ │ │ │ + groupDiv.appendChild(labelSpan); │ │ │ │ + groupDiv.appendChild(br); │ │ │ │ } │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ + │ │ │ │ + // if no overlays, dont display the overlay label │ │ │ │ + this.dataLbl.style.display = (containsOverlays) ? "" : "none"; │ │ │ │ + │ │ │ │ + // if no baselayers, dont display the baselayer label │ │ │ │ + this.baseLbl.style.display = (containsBaseLayers) ? "" : "none"; │ │ │ │ + │ │ │ │ + return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ - * tear-down. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully deactivated. │ │ │ │ + * Method: updateMap │ │ │ │ + * Cycles through the loaded data and base layer input arrays and makes │ │ │ │ + * the necessary calls to the Map object such that that the map's │ │ │ │ + * visual state corresponds to what the user has selected in │ │ │ │ + * the control. │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - if (this.auto) { │ │ │ │ - if (typeof this.auto === "number") { │ │ │ │ - window.clearInterval(this.timer); │ │ │ │ - } else { │ │ │ │ - this.layer.events.un({ │ │ │ │ - "featureadded": this.triggerSave, │ │ │ │ - "afterfeaturemodified": this.triggerSave, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ + updateMap: function() { │ │ │ │ + │ │ │ │ + // set the newly selected base layer │ │ │ │ + for (var i = 0, len = this.baseLayers.length; i < len; i++) { │ │ │ │ + var layerEntry = this.baseLayers[i]; │ │ │ │ + if (layerEntry.inputElem.checked) { │ │ │ │ + this.map.setBaseLayer(layerEntry.layer, false); │ │ │ │ } │ │ │ │ } │ │ │ │ - return deactivated; │ │ │ │ + │ │ │ │ + // set the correct visibilities for the overlays │ │ │ │ + for (var i = 0, len = this.dataLayers.length; i < len; i++) { │ │ │ │ + var layerEntry = this.dataLayers[i]; │ │ │ │ + layerEntry.layer.setVisibility(layerEntry.inputElem.checked); │ │ │ │ + } │ │ │ │ + │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: triggerSave │ │ │ │ - * Registered as a listener. Calls save if a feature has insert, update, │ │ │ │ - * or delete state. │ │ │ │ + * Method: maximizeControl │ │ │ │ + * Set up the labels and divs for the control │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * event - {Object} The event this function is listening for. │ │ │ │ + * e - {Event} │ │ │ │ */ │ │ │ │ - triggerSave: function(event) { │ │ │ │ - var feature = event.feature; │ │ │ │ - if (feature.state === OpenLayers.State.INSERT || │ │ │ │ - feature.state === OpenLayers.State.UPDATE || │ │ │ │ - feature.state === OpenLayers.State.DELETE) { │ │ │ │ - this.save([event.feature]); │ │ │ │ + maximizeControl: function(e) { │ │ │ │ + │ │ │ │ + // set the div's width and height to empty values, so │ │ │ │ + // the div dimensions can be controlled by CSS │ │ │ │ + this.div.style.width = ""; │ │ │ │ + this.div.style.height = ""; │ │ │ │ + │ │ │ │ + this.showControls(false); │ │ │ │ + │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: save │ │ │ │ - * Tell the layer protocol to commit unsaved features. If the layer │ │ │ │ - * projection differs from the map projection, features will be │ │ │ │ - * transformed into the layer projection before being committed. │ │ │ │ + * Method: minimizeControl │ │ │ │ + * Hide all the contents of the control, shrink the size, │ │ │ │ + * add the maximize icon │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * features - {Array} Features to be saved. If null, then default is all │ │ │ │ - * features in the layer. Features are assumed to be in the map │ │ │ │ - * projection. │ │ │ │ + * e - {Event} │ │ │ │ */ │ │ │ │ - save: function(features) { │ │ │ │ - if (!features) { │ │ │ │ - features = this.layer.features; │ │ │ │ - } │ │ │ │ - this.events.triggerEvent("start", { │ │ │ │ - features: features │ │ │ │ - }); │ │ │ │ - var remote = this.layer.projection; │ │ │ │ - var local = this.layer.map.getProjectionObject(); │ │ │ │ - if (!local.equals(remote)) { │ │ │ │ - var len = features.length; │ │ │ │ - var clones = new Array(len); │ │ │ │ - var orig, clone; │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ - orig = features[i]; │ │ │ │ - clone = orig.clone(); │ │ │ │ - clone.fid = orig.fid; │ │ │ │ - clone.state = orig.state; │ │ │ │ - if (orig.url) { │ │ │ │ - clone.url = orig.url; │ │ │ │ - } │ │ │ │ - clone._original = orig; │ │ │ │ - clone.geometry.transform(local, remote); │ │ │ │ - clones[i] = clone; │ │ │ │ - } │ │ │ │ - features = clones; │ │ │ │ + minimizeControl: function(e) { │ │ │ │ + │ │ │ │ + // to minimize the control we set its div's width │ │ │ │ + // and height to 0px, we cannot just set "display" │ │ │ │ + // to "none" because it would hide the maximize │ │ │ │ + // div │ │ │ │ + this.div.style.width = "0px"; │ │ │ │ + this.div.style.height = "0px"; │ │ │ │ + │ │ │ │ + this.showControls(true); │ │ │ │ + │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ } │ │ │ │ - this.layer.protocol.commit(features, { │ │ │ │ - callback: this.onCommit, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onCommit │ │ │ │ - * Called after protocol commit. │ │ │ │ + * Method: showControls │ │ │ │ + * Hide/Show all LayerSwitcher controls depending on whether we are │ │ │ │ + * minimized or not │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * response - {<OpenLayers.Protocol.Response>} A response object. │ │ │ │ + * minimize - {Boolean} │ │ │ │ */ │ │ │ │ - onCommit: function(response) { │ │ │ │ - var evt = { │ │ │ │ - "response": response │ │ │ │ - }; │ │ │ │ - if (response.success()) { │ │ │ │ - var features = response.reqFeatures; │ │ │ │ - // deal with inserts, updates, and deletes │ │ │ │ - var state, feature; │ │ │ │ - var destroys = []; │ │ │ │ - var insertIds = response.insertIds || []; │ │ │ │ - var j = 0; │ │ │ │ - for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - // if projection was different, we may be dealing with clones │ │ │ │ - feature = feature._original || feature; │ │ │ │ - state = feature.state; │ │ │ │ - if (state) { │ │ │ │ - if (state == OpenLayers.State.DELETE) { │ │ │ │ - destroys.push(feature); │ │ │ │ - } else if (state == OpenLayers.State.INSERT) { │ │ │ │ - feature.fid = insertIds[j]; │ │ │ │ - ++j; │ │ │ │ - } │ │ │ │ - feature.state = null; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + showControls: function(minimize) { │ │ │ │ │ │ │ │ - if (destroys.length > 0) { │ │ │ │ - this.layer.destroyFeatures(destroys); │ │ │ │ - } │ │ │ │ + this.maximizeDiv.style.display = minimize ? "" : "none"; │ │ │ │ + this.minimizeDiv.style.display = minimize ? "none" : ""; │ │ │ │ │ │ │ │ - this.events.triggerEvent("success", evt); │ │ │ │ + this.layersDiv.style.display = minimize ? "none" : ""; │ │ │ │ + }, │ │ │ │ │ │ │ │ + /** │ │ │ │ + * Method: loadContents │ │ │ │ + * Set up the labels and divs for the control │ │ │ │ + */ │ │ │ │ + loadContents: function() { │ │ │ │ + │ │ │ │ + // layers list div │ │ │ │ + this.layersDiv = document.createElement("div"); │ │ │ │ + this.layersDiv.id = this.id + "_layersDiv"; │ │ │ │ + OpenLayers.Element.addClass(this.layersDiv, "layersDiv"); │ │ │ │ + │ │ │ │ + this.baseLbl = document.createElement("div"); │ │ │ │ + this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer"); │ │ │ │ + OpenLayers.Element.addClass(this.baseLbl, "baseLbl"); │ │ │ │ + │ │ │ │ + this.baseLayersDiv = document.createElement("div"); │ │ │ │ + OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv"); │ │ │ │ + │ │ │ │ + this.dataLbl = document.createElement("div"); │ │ │ │ + this.dataLbl.innerHTML = OpenLayers.i18n("Overlays"); │ │ │ │ + OpenLayers.Element.addClass(this.dataLbl, "dataLbl"); │ │ │ │ + │ │ │ │ + this.dataLayersDiv = document.createElement("div"); │ │ │ │ + OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv"); │ │ │ │ + │ │ │ │ + if (this.ascending) { │ │ │ │ + this.layersDiv.appendChild(this.baseLbl); │ │ │ │ + this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ + this.layersDiv.appendChild(this.dataLbl); │ │ │ │ + this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ } else { │ │ │ │ - this.events.triggerEvent("fail", evt); │ │ │ │ + this.layersDiv.appendChild(this.dataLbl); │ │ │ │ + this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ + this.layersDiv.appendChild(this.baseLbl); │ │ │ │ + this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ } │ │ │ │ + │ │ │ │ + this.div.appendChild(this.layersDiv); │ │ │ │ + │ │ │ │ + // maximize button div │ │ │ │ + var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png'); │ │ │ │ + this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ + "OpenLayers_Control_MaximizeDiv", │ │ │ │ + null, │ │ │ │ + null, │ │ │ │ + img, │ │ │ │ + "absolute"); │ │ │ │ + OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv olButton"); │ │ │ │ + this.maximizeDiv.style.display = "none"; │ │ │ │ + │ │ │ │ + this.div.appendChild(this.maximizeDiv); │ │ │ │ + │ │ │ │ + // minimize button div │ │ │ │ + var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png'); │ │ │ │ + this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ + "OpenLayers_Control_MinimizeDiv", │ │ │ │ + null, │ │ │ │ + null, │ │ │ │ + img, │ │ │ │ + "absolute"); │ │ │ │ + OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton"); │ │ │ │ + this.minimizeDiv.style.display = "none"; │ │ │ │ + │ │ │ │ + this.div.appendChild(this.minimizeDiv); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Save" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.LayerSwitcher" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Strategy/Fixed.js │ │ │ │ + OpenLayers/Control/ZoomOut.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 │ │ │ │ + * @requires OpenLayers/Control/Button.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Strategy.Fixed │ │ │ │ - * A simple strategy that requests features once and never requests new data. │ │ │ │ + * Class: OpenLayers.Control.ZoomOut │ │ │ │ + * The ZoomOut control is a button to decrease the zoom level of a map. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Strategy> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -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 │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ +OpenLayers.Control.ZoomOut = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: trigger │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + trigger: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.zoomOut(); │ │ │ │ } │ │ │ │ - layer.events.triggerEvent("loadend", { │ │ │ │ - response: resp │ │ │ │ - }); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Fixed" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomOut" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Strategy/Refresh.js │ │ │ │ + OpenLayers/Control/ZoomPanel.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 │ │ │ │ + * @requires OpenLayers/Control/Panel.js │ │ │ │ + * @requires OpenLayers/Control/ZoomIn.js │ │ │ │ + * @requires OpenLayers/Control/ZoomOut.js │ │ │ │ + * @requires OpenLayers/Control/ZoomToMaxExtent.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Strategy.Refresh │ │ │ │ - * A strategy that refreshes the layer. By default the strategy waits for a │ │ │ │ - * call to <refresh> before refreshing. By configuring the strategy with │ │ │ │ - * the <interval> option, refreshing can take place automatically. │ │ │ │ + * Class: OpenLayers.Control.ZoomPanel │ │ │ │ + * The ZoomPanel control is a compact collecton of 3 zoom controls: a │ │ │ │ + * <OpenLayers.Control.ZoomIn>, a <OpenLayers.Control.ZoomToMaxExtent>, and a │ │ │ │ + * <OpenLayers.Control.ZoomOut>. By default it is drawn in the upper left │ │ │ │ + * corner of the map. │ │ │ │ * │ │ │ │ + * Note: │ │ │ │ + * If you wish to use this class with the default images and you want │ │ │ │ + * it to look nice in ie6, you should add the following, conditionally │ │ │ │ + * added css stylesheet to your HTML file: │ │ │ │ + * │ │ │ │ + * (code) │ │ │ │ + * <!--[if lte IE 6]> │ │ │ │ + * <link rel="stylesheet" href="../theme/default/ie6-style.css" type="text/css" /> │ │ │ │ + * <![endif]--> │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Strategy> │ │ │ │ + * - <OpenLayers.Control.Panel> │ │ │ │ */ │ │ │ │ -OpenLayers.Strategy.Refresh = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: force │ │ │ │ - * {Boolean} Force a refresh on the layer. Default is false. │ │ │ │ - */ │ │ │ │ - force: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: interval │ │ │ │ - * {Number} Auto-refresh. Default is 0. If > 0, layer will be refreshed │ │ │ │ - * every N milliseconds. │ │ │ │ - */ │ │ │ │ - interval: 0, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: timer │ │ │ │ - * {Number} The id of the timer. │ │ │ │ - */ │ │ │ │ - timer: null, │ │ │ │ +OpenLayers.Control.ZoomPanel = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Strategy.Refresh │ │ │ │ - * Create a new Refresh strategy. │ │ │ │ + * Constructor: OpenLayers.Control.ZoomPanel │ │ │ │ + * Add the three zooming controls. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} True if the strategy was successfully activated. │ │ │ │ - */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - if (this.layer.visibility === true) { │ │ │ │ - this.start(); │ │ │ │ - } │ │ │ │ - this.layer.events.on({ │ │ │ │ - "visibilitychanged": this.reset, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - return activated; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ - * tear-down. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} True if the strategy was successfully deactivated. │ │ │ │ - */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.stop(); │ │ │ │ - this.layer.events.un({ │ │ │ │ - "visibilitychanged": this.reset, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - return deactivated; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: reset │ │ │ │ - * Start or cancel the refresh interval depending on the visibility of │ │ │ │ - * the layer. │ │ │ │ - */ │ │ │ │ - reset: function() { │ │ │ │ - if (this.layer.visibility === true) { │ │ │ │ - this.start(); │ │ │ │ - } else { │ │ │ │ - this.stop(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: start │ │ │ │ - * Start the refresh interval. │ │ │ │ - */ │ │ │ │ - start: function() { │ │ │ │ - if (this.interval && typeof this.interval === "number" && │ │ │ │ - this.interval > 0) { │ │ │ │ - │ │ │ │ - this.timer = window.setInterval( │ │ │ │ - OpenLayers.Function.bind(this.refresh, this), │ │ │ │ - this.interval); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: refresh │ │ │ │ - * Tell the strategy to refresh which will refresh the layer. │ │ │ │ - */ │ │ │ │ - refresh: function() { │ │ │ │ - if (this.layer && this.layer.refresh && │ │ │ │ - typeof this.layer.refresh == "function") { │ │ │ │ - │ │ │ │ - this.layer.refresh({ │ │ │ │ - force: this.force │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: stop │ │ │ │ - * Cancels the refresh interval. │ │ │ │ + * options - {Object} An optional object whose properties will be used │ │ │ │ + * to extend the control. │ │ │ │ */ │ │ │ │ - stop: function() { │ │ │ │ - if (this.timer !== null) { │ │ │ │ - window.clearInterval(this.timer); │ │ │ │ - this.timer = null; │ │ │ │ - } │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ + this.addControls([ │ │ │ │ + new OpenLayers.Control.ZoomIn(), │ │ │ │ + new OpenLayers.Control.ZoomToMaxExtent(), │ │ │ │ + new OpenLayers.Control.ZoomOut() │ │ │ │ + ]); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Refresh" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomPanel" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Strategy/Paging.js │ │ │ │ + OpenLayers/Control/CacheRead.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 │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Strategy.Paging │ │ │ │ - * Strategy for vector feature paging │ │ │ │ + * Class: OpenLayers.Control.CacheRead │ │ │ │ + * A control for using image tiles cached with <OpenLayers.Control.CacheWrite> │ │ │ │ + * from the browser's local storage. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Strategy> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: features │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} Cached features. │ │ │ │ - */ │ │ │ │ - features: null, │ │ │ │ +OpenLayers.Control.CacheRead = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: length │ │ │ │ - * {Integer} Number of features per page. Default is 10. │ │ │ │ + * APIProperty: fetchEvent │ │ │ │ + * {String} The layer event to listen to for replacing remote resource tile │ │ │ │ + * URLs with cached data URIs. Supported values are "tileerror" (try │ │ │ │ + * remote first, fall back to cached) and "tileloadstart" (try cache │ │ │ │ + * first, fall back to remote). Default is "tileloadstart". │ │ │ │ + * │ │ │ │ + * Note that "tileerror" will not work for CORS enabled images (see │ │ │ │ + * https://developer.mozilla.org/en/CORS_Enabled_Image), i.e. layers │ │ │ │ + * configured with a <OpenLayers.Tile.Image.crossOriginKeyword> in │ │ │ │ + * <OpenLayers.Layer.Grid.tileOptions>. │ │ │ │ */ │ │ │ │ - length: 10, │ │ │ │ + fetchEvent: "tileloadstart", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: num │ │ │ │ - * {Integer} The currently displayed page number. │ │ │ │ + * APIProperty: layers │ │ │ │ + * {Array(<OpenLayers.Layer.Grid>)}. Optional. If provided, only these │ │ │ │ + * layers will receive tiles from the cache. │ │ │ │ */ │ │ │ │ - num: null, │ │ │ │ + layers: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: paging │ │ │ │ - * {Boolean} The strategy is currently changing pages. │ │ │ │ + * APIProperty: autoActivate │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * true. │ │ │ │ */ │ │ │ │ - paging: false, │ │ │ │ + autoActivate: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Strategy.Paging │ │ │ │ - * Create a new paging strategy. │ │ │ │ + * Constructor: OpenLayers.Control.CacheRead │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * options - {Object} Object with API properties for this control │ │ │ │ */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ + * Set the map property for the control. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully activated. │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - "beforefeaturesadded": this.cacheFeatures, │ │ │ │ - scope: this │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + var i, layers = this.layers || map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.addLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ }); │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ - * tear-down. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully deactivated. │ │ │ │ - */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.layer.events.un({ │ │ │ │ - "beforefeaturesadded": this.cacheFeatures, │ │ │ │ + if (!this.layers) { │ │ │ │ + map.events.on({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ scope: this │ │ │ │ }); │ │ │ │ } │ │ │ │ - return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: cacheFeatures │ │ │ │ - * Cache features before they are added to the layer. │ │ │ │ + * Method: addLayer │ │ │ │ + * Adds a layer to the control. Once added, tiles requested for this layer │ │ │ │ + * will be cached. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * event - {Object} The event that this was listening for. This will come │ │ │ │ - * with a batch of features to be paged. │ │ │ │ - */ │ │ │ │ - cacheFeatures: function(event) { │ │ │ │ - if (!this.paging) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.features = event.features; │ │ │ │ - this.pageNext(event); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: clearCache │ │ │ │ - * Clear out the cached features. This destroys features, assuming │ │ │ │ - * nothing else has a reference. │ │ │ │ - */ │ │ │ │ - clearCache: function() { │ │ │ │ - if (this.features) { │ │ │ │ - for (var i = 0; i < this.features.length; ++i) { │ │ │ │ - this.features[i].destroy(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.features = null; │ │ │ │ - this.num = null; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: pageCount │ │ │ │ - * Get the total count of pages given the current cache of features. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} The page count. │ │ │ │ - */ │ │ │ │ - pageCount: function() { │ │ │ │ - var numFeatures = this.features ? this.features.length : 0; │ │ │ │ - return Math.ceil(numFeatures / this.length); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: pageNum │ │ │ │ - * Get the zero based page number. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} The current page number being displayed. │ │ │ │ + * evt - {Object} Object with a layer property referencing an │ │ │ │ + * <OpenLayers.Layer> instance │ │ │ │ */ │ │ │ │ - pageNum: function() { │ │ │ │ - return this.num; │ │ │ │ + addLayer: function(evt) { │ │ │ │ + evt.layer.events.register(this.fetchEvent, this, this.fetch); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: pageLength │ │ │ │ - * Gets or sets page length. │ │ │ │ + * Method: removeLayer │ │ │ │ + * Removes a layer from the control. Once removed, tiles requested for this │ │ │ │ + * layer will no longer be cached. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * newLength - {Integer} Optional length to be set. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} The length of a page (number of features per page). │ │ │ │ + * evt - {Object} Object with a layer property referencing an │ │ │ │ + * <OpenLayers.Layer> instance │ │ │ │ */ │ │ │ │ - pageLength: function(newLength) { │ │ │ │ - if (newLength && newLength > 0) { │ │ │ │ - this.length = newLength; │ │ │ │ - } │ │ │ │ - return this.length; │ │ │ │ + removeLayer: function(evt) { │ │ │ │ + evt.layer.events.unregister(this.fetchEvent, this, this.fetch); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: pageNext │ │ │ │ - * Display the next page of features. │ │ │ │ + * Method: fetch │ │ │ │ + * Listener to the <fetchEvent> event. Replaces a tile's url with a data │ │ │ │ + * URI from the cache. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} A new page was displayed. │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Object} Event object with a tile property. │ │ │ │ */ │ │ │ │ - pageNext: function(event) { │ │ │ │ - var changed = false; │ │ │ │ - if (this.features) { │ │ │ │ - if (this.num === null) { │ │ │ │ - this.num = -1; │ │ │ │ + fetch: function(evt) { │ │ │ │ + if (this.active && window.localStorage && │ │ │ │ + evt.tile instanceof OpenLayers.Tile.Image) { │ │ │ │ + var tile = evt.tile, │ │ │ │ + url = tile.url; │ │ │ │ + // deal with modified tile urls when both CacheWrite and CacheRead │ │ │ │ + // are active │ │ │ │ + if (!tile.layer.crossOriginKeyword && OpenLayers.ProxyHost && │ │ │ │ + url.indexOf(OpenLayers.ProxyHost) === 0) { │ │ │ │ + url = OpenLayers.Control.CacheWrite.urlMap[url]; │ │ │ │ } │ │ │ │ - var start = (this.num + 1) * this.length; │ │ │ │ - changed = this.page(start, event); │ │ │ │ - } │ │ │ │ - return changed; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: pagePrevious │ │ │ │ - * Display the previous page of features. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} A new page was displayed. │ │ │ │ - */ │ │ │ │ - pagePrevious: function() { │ │ │ │ - var changed = false; │ │ │ │ - if (this.features) { │ │ │ │ - if (this.num === null) { │ │ │ │ - this.num = this.pageCount(); │ │ │ │ + var dataURI = window.localStorage.getItem("olCache_" + url); │ │ │ │ + if (dataURI) { │ │ │ │ + tile.url = dataURI; │ │ │ │ + if (evt.type === "tileerror") { │ │ │ │ + tile.setImgSrc(dataURI); │ │ │ │ + } │ │ │ │ } │ │ │ │ - var start = (this.num - 1) * this.length; │ │ │ │ - changed = this.page(start); │ │ │ │ } │ │ │ │ - return changed; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: page │ │ │ │ - * Display the page starting at the given index from the cache. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} A new page was displayed. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - page: function(start, event) { │ │ │ │ - var changed = false; │ │ │ │ - if (this.features) { │ │ │ │ - if (start >= 0 && start < this.features.length) { │ │ │ │ - var num = Math.floor(start / this.length); │ │ │ │ - if (num != this.num) { │ │ │ │ - this.paging = true; │ │ │ │ - var features = this.features.slice(start, start + this.length); │ │ │ │ - this.layer.removeFeatures(this.layer.features); │ │ │ │ - this.num = num; │ │ │ │ - // modify the event if any │ │ │ │ - if (event && event.features) { │ │ │ │ - // this.was called by an event listener │ │ │ │ - event.features = features; │ │ │ │ - } else { │ │ │ │ - // this was called directly on the strategy │ │ │ │ - this.layer.addFeatures(features); │ │ │ │ - } │ │ │ │ - this.paging = false; │ │ │ │ - changed = true; │ │ │ │ - } │ │ │ │ + destroy: function() { │ │ │ │ + if (this.layers || this.map) { │ │ │ │ + var i, layers = this.layers || this.map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.removeLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ + }); │ │ │ │ } │ │ │ │ } │ │ │ │ - return changed; │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.un({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Paging" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.CacheRead" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Strategy/Filter.js │ │ │ │ + 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/Strategy.js │ │ │ │ - * @requires OpenLayers/Filter.js │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Strategy.Filter │ │ │ │ - * Strategy for limiting features that get added to a layer by │ │ │ │ - * evaluating a filter. The strategy maintains a cache of │ │ │ │ - * all features until removeFeatures is called on the layer. │ │ │ │ + * Class: OpenLayers.Control.DrawFeature │ │ │ │ + * The DrawFeature control draws point, line or polygon features on a vector │ │ │ │ + * layer when active. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Strategy> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Strategy.Filter = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: filter │ │ │ │ - * {<OpenLayers.Filter>} Filter for limiting features sent to the layer. │ │ │ │ - * Use the <setFilter> method to update this filter after construction. │ │ │ │ - */ │ │ │ │ - filter: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: cache │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} List of currently cached │ │ │ │ - * features. │ │ │ │ - */ │ │ │ │ - cache: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: caching │ │ │ │ - * {Boolean} The filter is currently caching features. │ │ │ │ - */ │ │ │ │ - caching: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Strategy.Filter │ │ │ │ - * Create a new filter strategy. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ - * By default, this strategy automatically activates itself when a layer │ │ │ │ - * is added to a map. │ │ │ │ - * │ │ │ │ - * 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.cache = []; │ │ │ │ - this.layer.events.on({ │ │ │ │ - "beforefeaturesadded": this.handleAdd, │ │ │ │ - "beforefeaturesremoved": this.handleRemove, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - return activated; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the strategy. Clear the feature cache. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} True if the strategy was successfully deactivated or false if │ │ │ │ - * the strategy was already inactive. │ │ │ │ - */ │ │ │ │ - deactivate: function() { │ │ │ │ - this.cache = null; │ │ │ │ - if (this.layer && this.layer.events) { │ │ │ │ - this.layer.events.un({ │ │ │ │ - "beforefeaturesadded": this.handleAdd, │ │ │ │ - "beforefeaturesremoved": this.handleRemove, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - return OpenLayers.Strategy.prototype.deactivate.apply(this, arguments); │ │ │ │ - }, │ │ │ │ +OpenLayers.Control.DrawFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handleAdd │ │ │ │ + * Property: layer │ │ │ │ + * {<OpenLayers.Layer.Vector>} │ │ │ │ */ │ │ │ │ - handleAdd: function(event) { │ │ │ │ - if (!this.caching && this.filter) { │ │ │ │ - var features = event.features; │ │ │ │ - event.features = []; │ │ │ │ - var feature; │ │ │ │ - for (var i = 0, ii = features.length; i < ii; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - if (this.filter.evaluate(feature)) { │ │ │ │ - event.features.push(feature); │ │ │ │ - } else { │ │ │ │ - this.cache.push(feature); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handleRemove │ │ │ │ + * Property: callbacks │ │ │ │ + * {Object} The functions that are sent to the handler for callback │ │ │ │ */ │ │ │ │ - handleRemove: function(event) { │ │ │ │ - if (!this.caching) { │ │ │ │ - this.cache = []; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + callbacks: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setFilter │ │ │ │ - * Update the filter for this strategy. This will re-evaluate │ │ │ │ - * any features on the layer and in the cache. Only features │ │ │ │ - * for which filter.evalute(feature) returns true will be │ │ │ │ - * added to the layer. Others will be cached by the strategy. │ │ │ │ + * APIProperty: events │ │ │ │ + * {<OpenLayers.Events>} Events instance for listeners and triggering │ │ │ │ + * control specific events. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * filter - {<OpenLayers.Filter>} A filter for evaluating features. │ │ │ │ - */ │ │ │ │ - setFilter: function(filter) { │ │ │ │ - this.filter = filter; │ │ │ │ - var previousCache = this.cache; │ │ │ │ - this.cache = []; │ │ │ │ - // look through layer for features to remove from layer │ │ │ │ - this.handleAdd({ │ │ │ │ - features: this.layer.features │ │ │ │ - }); │ │ │ │ - // cache now contains features to remove from layer │ │ │ │ - if (this.cache.length > 0) { │ │ │ │ - this.caching = true; │ │ │ │ - this.layer.removeFeatures(this.cache.slice()); │ │ │ │ - this.caching = false; │ │ │ │ - } │ │ │ │ - // now look through previous cache for features to add to layer │ │ │ │ - if (previousCache.length > 0) { │ │ │ │ - var event = { │ │ │ │ - features: previousCache │ │ │ │ - }; │ │ │ │ - this.handleAdd(event); │ │ │ │ - if (event.features.length > 0) { │ │ │ │ - // event has features to add to layer │ │ │ │ - this.caching = true; │ │ │ │ - this.layer.addFeatures(event.features); │ │ │ │ - this.caching = false; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Filter" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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). │ │ │ │ + * APIProperty: multi │ │ │ │ + * {Boolean} Cast features to multi-part geometries before passing to the │ │ │ │ + * layer. Default is false. │ │ │ │ */ │ │ │ │ - indices: null, │ │ │ │ + multi: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: featureAdded │ │ │ │ + * {Function} Called after each feature is added │ │ │ │ */ │ │ │ │ - compare: null, │ │ │ │ + featureAdded: function() {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: initialize │ │ │ │ - * Create a new indexer with │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * yOrdering - {Boolean} Whether to use y-ordering. │ │ │ │ + * APIProperty: handlerOptions │ │ │ │ + * {Object} Used to set non-default properties on the control's handler │ │ │ │ */ │ │ │ │ - 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)). │ │ │ │ + * Constructor: OpenLayers.Control.DrawFeature │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} │ │ │ │ + * handler - {<OpenLayers.Handler>} │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - │ │ │ │ - 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); │ │ │ │ + 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); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: remove │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} The node to be removed. │ │ │ │ + * Method: drawFeature │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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: clear │ │ │ │ - */ │ │ │ │ - clear: function() { │ │ │ │ - this.order = []; │ │ │ │ - this.indices = {}; │ │ │ │ - this.maxZIndex = 0; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: exists │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} The node to test for existence. │ │ │ │ + * APIMethod: insertXY │ │ │ │ + * Insert a point in the current sketch given x & y coordinates. │ │ │ │ * │ │ │ │ - * 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} │ │ │ │ + * x - {Number} The x-coordinate of the point. │ │ │ │ + * y - {Number} The y-coordinate of the point. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + insertXY: function(x, y) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertXY(x, y); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getNextElement │ │ │ │ - * Get the next element in the order stack. │ │ │ │ - * │ │ │ │ + * APIMethod: insertDeltaXY │ │ │ │ + * Insert a point given offsets from the previously inserted point. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * index - {Integer} The index of the current node in this.order. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} the node following the index passed in, or │ │ │ │ - * null. │ │ │ │ + * dx - {Number} The x-coordinate offset of the point. │ │ │ │ + * dy - {Number} The y-coordinate offset of the point. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + insertDeltaXY: function(dx, dy) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertDeltaXY(dx, dy); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - 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. │ │ │ │ - * │ │ │ │ + * APIMethod: insertDirectionLength │ │ │ │ + * Insert a point in the current sketch given a direction and a length. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * indexer - {<OpenLayers.ElementsIndexer>} │ │ │ │ - * newNode - {DOMElement} │ │ │ │ - * nextNode - {DOMElement} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} │ │ │ │ + * direction - {Number} Degrees clockwise from the positive x-axis. │ │ │ │ + * length - {Number} Distance from the previously drawn point. │ │ │ │ */ │ │ │ │ - Z_ORDER: function(indexer, newNode, nextNode) { │ │ │ │ - var newZIndex = indexer.getZIndex(newNode); │ │ │ │ - │ │ │ │ - var returnVal = 0; │ │ │ │ - if (nextNode) { │ │ │ │ - var nextZIndex = indexer.getZIndex(nextNode); │ │ │ │ - returnVal = newZIndex - nextZIndex; │ │ │ │ + insertDirectionLength: function(direction, length) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertDirectionLength(direction, length); │ │ │ │ } │ │ │ │ - │ │ │ │ - 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. │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * indexer - {<OpenLayers.ElementsIndexer>} │ │ │ │ - * newNode - {DOMElement} │ │ │ │ - * nextNode - {DOMElement} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} │ │ │ │ + * deflection - {Number} Degrees clockwise from the previous segment. │ │ │ │ + * length - {Number} Distance from the previously drawn point. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + insertDeflectionLength: function(deflection, length) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertDeflectionLength(deflection, length); │ │ │ │ } │ │ │ │ - │ │ │ │ - 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. │ │ │ │ + * APIMethod: undo │ │ │ │ + * Remove the most recently added point in the current sketch geometry. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} An edit was undone. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + undo: function() { │ │ │ │ + return this.handler.undo && this.handler.undo(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroy │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - │ │ │ │ - this.clear(); │ │ │ │ - │ │ │ │ - this.rendererRoot = null; │ │ │ │ - this.root = null; │ │ │ │ - this.xmlns = null; │ │ │ │ - │ │ │ │ - OpenLayers.Renderer.prototype.destroy.apply(this, arguments); │ │ │ │ + redo: function() { │ │ │ │ + return this.handler.redo && this.handler.redo(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clear │ │ │ │ - * Remove all the elements from the root │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ + finishSketch: function() { │ │ │ │ + this.handler.finishGeometry(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: cancel │ │ │ │ + * Cancel the current sketch. This removes the current sketch and keeps │ │ │ │ + * the drawing control active. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + cancel: function() { │ │ │ │ + this.handler.cancel(); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.DrawFeature" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/EditingToolbar.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - } │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - 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; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Control/Panel.js │ │ │ │ + * @requires OpenLayers/Control/Navigation.js │ │ │ │ + * @requires OpenLayers/Control/DrawFeature.js │ │ │ │ + * @requires OpenLayers/Handler/Point.js │ │ │ │ + * @requires OpenLayers/Handler/Path.js │ │ │ │ + * @requires OpenLayers/Handler/Polygon.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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)); │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.EditingToolbar │ │ │ │ + * The EditingToolbar is a panel of 4 controls to draw polygons, lines, │ │ │ │ + * points, or to navigate the map by panning. By default it appears in the │ │ │ │ + * upper right corner of the map. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control.Panel> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.EditingToolbar = OpenLayers.Class( │ │ │ │ + OpenLayers.Control.Panel, { │ │ │ │ │ │ │ │ - // 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; │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - var drawResult = this.drawGeometryNode(node, geometry, style); │ │ │ │ - if (drawResult === false) { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.EditingToolbar │ │ │ │ + * Create an editing toolbar for a given layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} │ │ │ │ + * options - {Object} │ │ │ │ + */ │ │ │ │ + initialize: function(layer, options) { │ │ │ │ + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ │ │ │ │ - node = drawResult.node; │ │ │ │ + this.addControls( │ │ │ │ + [new OpenLayers.Control.Navigation()] │ │ │ │ + ); │ │ │ │ + var controls = [ │ │ │ │ + new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Point, { │ │ │ │ + displayClass: 'olControlDrawFeaturePoint', │ │ │ │ + handlerOptions: { │ │ │ │ + citeCompliant: this.citeCompliant │ │ │ │ + } │ │ │ │ + }), │ │ │ │ + new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Path, { │ │ │ │ + displayClass: 'olControlDrawFeaturePath', │ │ │ │ + handlerOptions: { │ │ │ │ + citeCompliant: this.citeCompliant │ │ │ │ + } │ │ │ │ + }), │ │ │ │ + new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Polygon, { │ │ │ │ + displayClass: 'olControlDrawFeaturePolygon', │ │ │ │ + handlerOptions: { │ │ │ │ + citeCompliant: this.citeCompliant │ │ │ │ + } │ │ │ │ + }) │ │ │ │ + ]; │ │ │ │ + this.addControls(controls); │ │ │ │ + }, │ │ │ │ │ │ │ │ - // 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); │ │ │ │ + /** │ │ │ │ + * Method: draw │ │ │ │ + * calls the default draw, and then activates mouse defaults. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + draw: function() { │ │ │ │ + var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments); │ │ │ │ + if (this.defaultControl === null) { │ │ │ │ + this.defaultControl = this.controls[0]; │ │ │ │ } │ │ │ │ - } │ │ │ │ - │ │ │ │ - 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) {}, │ │ │ │ + return div; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.EditingToolbar" │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/OverviewMap.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/BaseTypes.js │ │ │ │ + * @requires OpenLayers/Events/buttonclick.js │ │ │ │ + * @requires OpenLayers/Map.js │ │ │ │ + * @requires OpenLayers/Handler/Click.js │ │ │ │ + * @requires OpenLayers/Handler/Drag.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.OverviewMap │ │ │ │ + * The OverMap control creates a small overview map, useful to display the │ │ │ │ + * extent of a zoomed map and your main map and provide additional │ │ │ │ + * navigation options to the User. By default the overview map is drawn in │ │ │ │ + * the lower right corner of the main map. Create a new overview map with the │ │ │ │ + * <OpenLayers.Control.OverviewMap> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Property: element │ │ │ │ + * {DOMElement} The DOM element that contains the overview map │ │ │ │ */ │ │ │ │ - drawRectangle: function(node, geometry) {}, │ │ │ │ + element: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * APIProperty: ovmap │ │ │ │ + * {<OpenLayers.Map>} A reference to the overview map itself. │ │ │ │ */ │ │ │ │ - drawCircle: function(node, geometry) {}, │ │ │ │ + ovmap: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: removeText │ │ │ │ - * Removes a label │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * featureId - {String} │ │ │ │ + * APIProperty: size │ │ │ │ + * {<OpenLayers.Size>} The overvew map size in pixels. Note that this is │ │ │ │ + * the size of the map itself - the element that contains the map (default │ │ │ │ + * class name olControlOverviewMapElement) may have padding or other style │ │ │ │ + * attributes added via CSS. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + size: { │ │ │ │ + w: 180, │ │ │ │ + h: 90 │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: layers │ │ │ │ + * {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map. │ │ │ │ + * If none are sent at construction, the base layer for the main map is used. │ │ │ │ */ │ │ │ │ - createNode: function(type, id) {}, │ │ │ │ + layers: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: moveRoot │ │ │ │ - * moves this renderer's root to a different renderer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * renderer - {<OpenLayers.Renderer>} target renderer for the moved root │ │ │ │ + * APIProperty: minRectSize │ │ │ │ + * {Integer} The minimum width or height (in pixels) of the extent │ │ │ │ + * rectangle on the overview map. When the extent rectangle reaches │ │ │ │ + * this size, it will be replaced depending on the value of the │ │ │ │ + * <minRectDisplayClass> property. Default is 15 pixels. │ │ │ │ */ │ │ │ │ - moveRoot: function(renderer) { │ │ │ │ - var root = this.root; │ │ │ │ - if (renderer.root.parentNode == this.rendererRoot) { │ │ │ │ - root = renderer.root; │ │ │ │ - } │ │ │ │ - root.parentNode.removeChild(root); │ │ │ │ - renderer.rendererRoot.appendChild(root); │ │ │ │ - }, │ │ │ │ + minRectSize: 15, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: minRectDisplayClass │ │ │ │ + * {String} Replacement style class name for the extent rectangle when │ │ │ │ + * <minRectSize> is reached. This string will be suffixed on to the │ │ │ │ + * displayClass. Default is "RectReplacement". │ │ │ │ + * │ │ │ │ + * Example CSS declaration: │ │ │ │ + * (code) │ │ │ │ + * .olControlOverviewMapRectReplacement { │ │ │ │ + * overflow: hidden; │ │ │ │ + * cursor: move; │ │ │ │ + * background-image: url("img/overview_replacement.gif"); │ │ │ │ + * background-repeat: no-repeat; │ │ │ │ + * background-position: center; │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ */ │ │ │ │ - getRenderLayerId: function() { │ │ │ │ - return this.root.parentNode.parentNode.id; │ │ │ │ - }, │ │ │ │ + minRectDisplayClass: "RectReplacement", │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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/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, { │ │ │ │ + * APIProperty: minRatio │ │ │ │ + * {Float} The ratio of the overview map resolution to the main map │ │ │ │ + * resolution at which to zoom farther out on the overview map. │ │ │ │ + */ │ │ │ │ + minRatio: 8, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: xmlns │ │ │ │ - * {String} │ │ │ │ + /** │ │ │ │ + * APIProperty: maxRatio │ │ │ │ + * {Float} The ratio of the overview map resolution to the main map │ │ │ │ + * resolution at which to zoom farther in on the overview map. │ │ │ │ */ │ │ │ │ - xmlns: "http://www.w3.org/2000/svg", │ │ │ │ + maxRatio: 32, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: xlinkns │ │ │ │ - * {String} │ │ │ │ + * APIProperty: mapOptions │ │ │ │ + * {Object} An object containing any non-default properties to be sent to │ │ │ │ + * the overview map's map constructor. These should include any │ │ │ │ + * non-default options that the main map was constructed with. │ │ │ │ */ │ │ │ │ - xlinkns: "http://www.w3.org/1999/xlink", │ │ │ │ + mapOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: autoPan │ │ │ │ + * {Boolean} Always pan the overview map, so the extent marker remains in │ │ │ │ + * the center. Default is false. If true, when you drag the extent │ │ │ │ + * marker, the overview map will update itself so the marker returns │ │ │ │ + * to the center. │ │ │ │ */ │ │ │ │ - MAX_PIXEL: 15000, │ │ │ │ + autoPan: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: translationParameters │ │ │ │ - * {Object} Hash with "x" and "y" properties │ │ │ │ + * Property: handlers │ │ │ │ + * {Object} │ │ │ │ */ │ │ │ │ - translationParameters: null, │ │ │ │ + handlers: 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]. │ │ │ │ + * Property: resolutionFactor │ │ │ │ + * {Object} │ │ │ │ */ │ │ │ │ - symbolMetrics: null, │ │ │ │ + resolutionFactor: 1, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Renderer.SVG │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * containerID - {String} │ │ │ │ + * APIProperty: maximized │ │ │ │ + * {Boolean} Start as maximized (visible). Defaults to false. │ │ │ │ */ │ │ │ │ - initialize: function(containerID) { │ │ │ │ - if (!this.supported()) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - OpenLayers.Renderer.Elements.prototype.initialize.apply(this, │ │ │ │ - arguments); │ │ │ │ - this.translationParameters = { │ │ │ │ - x: 0, │ │ │ │ - y: 0 │ │ │ │ - }; │ │ │ │ + maximized: false, │ │ │ │ │ │ │ │ - this.symbolMetrics = {}; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * APIProperty: maximizeTitle │ │ │ │ + * {String} This property is used for showing a tooltip over the │ │ │ │ + * maximize div. Defaults to "" (no title). │ │ │ │ + */ │ │ │ │ + maximizeTitle: "", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: supported │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the browser supports the SVG renderer │ │ │ │ + * APIProperty: minimizeTitle │ │ │ │ + * {String} This property is used for showing a tooltip over the │ │ │ │ + * minimize div. Defaults to "" (no title). │ │ │ │ */ │ │ │ │ - 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"))); │ │ │ │ - }, │ │ │ │ + minimizeTitle: "", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: inValidRange │ │ │ │ - * See #669 for more information │ │ │ │ + * Constructor: OpenLayers.Control.OverviewMap │ │ │ │ + * Create a new overview map │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * options - {Object} Properties of this object will be set on the overview │ │ │ │ + * map object. Note, to set options on the map object contained in this │ │ │ │ + * control, set <mapOptions> as one of the options properties. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + initialize: function(options) { │ │ │ │ + this.layers = []; │ │ │ │ + this.handlers = {}; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Deconstruct the control │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + destroy: function() { │ │ │ │ + if (!this.mapDiv) { // we've already been destroyed │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + if (this.handlers.click) { │ │ │ │ + this.handlers.click.destroy(); │ │ │ │ + } │ │ │ │ + if (this.handlers.drag) { │ │ │ │ + this.handlers.drag.destroy(); │ │ │ │ + } │ │ │ │ │ │ │ │ - // 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.ovmap && this.ovmap.viewPortDiv.removeChild(this.extentRectangle); │ │ │ │ + this.extentRectangle = null; │ │ │ │ │ │ │ │ - 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; │ │ │ │ + if (this.rectEvents) { │ │ │ │ + this.rectEvents.destroy(); │ │ │ │ + this.rectEvents = null; │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ + if (this.ovmap) { │ │ │ │ + this.ovmap.destroy(); │ │ │ │ + this.ovmap = null; │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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.element.removeChild(this.mapDiv); │ │ │ │ + this.mapDiv = null; │ │ │ │ │ │ │ │ - this.rendererRoot.setAttributeNS(null, "width", this.size.w); │ │ │ │ - this.rendererRoot.setAttributeNS(null, "height", this.size.h); │ │ │ │ - }, │ │ │ │ + this.div.removeChild(this.element); │ │ │ │ + this.element = null; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ + if (this.maximizeDiv) { │ │ │ │ + this.div.removeChild(this.maximizeDiv); │ │ │ │ + this.maximizeDiv = null; │ │ │ │ } │ │ │ │ - return nodeType; │ │ │ │ + │ │ │ │ + if (this.minimizeDiv) { │ │ │ │ + this.div.removeChild(this.minimizeDiv); │ │ │ │ + this.minimizeDiv = null; │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.map.events.un({ │ │ │ │ + buttonclick: this.onButtonClick, │ │ │ │ + moveend: this.update, │ │ │ │ + changebaselayer: this.baseLayerDraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: 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} │ │ │ │ + /** │ │ │ │ + * Method: draw │ │ │ │ + * Render the control in the browser. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (this.layers.length === 0) { │ │ │ │ + if (this.map.baseLayer) { │ │ │ │ + var layer = this.map.baseLayer.clone(); │ │ │ │ + this.layers = [layer]; │ │ │ │ } else { │ │ │ │ - var label = this.nodeFactory(null, "title"); │ │ │ │ - label.textContent = title; │ │ │ │ - node.appendChild(label); │ │ │ │ + this.map.events.register("changebaselayer", this, this.baseLayerDraw); │ │ │ │ + return this.div; │ │ │ │ } │ │ │ │ } │ │ │ │ │ │ │ │ - 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; │ │ │ │ + // create overview map DOM elements │ │ │ │ + this.element = document.createElement('div'); │ │ │ │ + this.element.className = this.displayClass + 'Element'; │ │ │ │ + this.element.style.display = 'none'; │ │ │ │ │ │ │ │ - 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; │ │ │ │ + this.mapDiv = document.createElement('div'); │ │ │ │ + this.mapDiv.style.width = this.size.w + 'px'; │ │ │ │ + this.mapDiv.style.height = this.size.h + 'px'; │ │ │ │ + this.mapDiv.style.position = 'relative'; │ │ │ │ + this.mapDiv.style.overflow = 'hidden'; │ │ │ │ + this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap'); │ │ │ │ │ │ │ │ - // 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); │ │ │ │ - } │ │ │ │ + this.extentRectangle = document.createElement('div'); │ │ │ │ + this.extentRectangle.style.position = 'absolute'; │ │ │ │ + this.extentRectangle.style.zIndex = 1000; //HACK │ │ │ │ + this.extentRectangle.className = this.displayClass + 'ExtentRectangle'; │ │ │ │ │ │ │ │ - // 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")); │ │ │ │ + this.element.appendChild(this.mapDiv); │ │ │ │ │ │ │ │ - node.setAttributeNS(null, "width", size); │ │ │ │ - node.setAttributeNS(null, "height", size); │ │ │ │ - node.setAttributeNS(null, "x", pos.x - offset); │ │ │ │ - node.setAttributeNS(null, "y", pos.y - offset); │ │ │ │ + this.div.appendChild(this.element); │ │ │ │ │ │ │ │ - // 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); │ │ │ │ + // Optionally add min/max buttons if the control will go in the │ │ │ │ + // map viewport. │ │ │ │ + if (!this.outsideViewport) { │ │ │ │ + this.div.className += " " + this.displayClass + 'Container'; │ │ │ │ + // maximize button div │ │ │ │ + var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png'); │ │ │ │ + this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ + this.displayClass + 'MaximizeButton', │ │ │ │ + null, │ │ │ │ + null, │ │ │ │ + img, │ │ │ │ + 'absolute'); │ │ │ │ + this.maximizeDiv.style.display = 'none'; │ │ │ │ + this.maximizeDiv.className = this.displayClass + 'MaximizeButton olButton'; │ │ │ │ + if (this.maximizeTitle) { │ │ │ │ + this.maximizeDiv.title = this.maximizeTitle; │ │ │ │ } │ │ │ │ + this.div.appendChild(this.maximizeDiv); │ │ │ │ │ │ │ │ - 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] + ")"); │ │ │ │ - } │ │ │ │ + // minimize button div │ │ │ │ + var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png'); │ │ │ │ + this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ + 'OpenLayers_Control_minimizeDiv', │ │ │ │ + null, │ │ │ │ + null, │ │ │ │ + img, │ │ │ │ + 'absolute'); │ │ │ │ + this.minimizeDiv.style.display = 'none'; │ │ │ │ + this.minimizeDiv.className = this.displayClass + 'MinimizeButton olButton'; │ │ │ │ + if (this.minimizeTitle) { │ │ │ │ + this.minimizeDiv.title = this.minimizeTitle; │ │ │ │ } │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (options.isFilled) { │ │ │ │ - node.setAttributeNS(null, "fill", style.fillColor); │ │ │ │ - node.setAttributeNS(null, "fill-opacity", style.fillOpacity); │ │ │ │ + this.div.appendChild(this.minimizeDiv); │ │ │ │ + this.minimizeControl(); │ │ │ │ } else { │ │ │ │ - node.setAttributeNS(null, "fill", "none"); │ │ │ │ + // show the overview map │ │ │ │ + this.element.style.display = ''; │ │ │ │ } │ │ │ │ - │ │ │ │ - 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 (this.map.getExtent()) { │ │ │ │ + this.update(); │ │ │ │ } │ │ │ │ │ │ │ │ - if (style.pointerEvents) { │ │ │ │ - node.setAttributeNS(null, "pointer-events", style.pointerEvents); │ │ │ │ - } │ │ │ │ + this.map.events.on({ │ │ │ │ + buttonclick: this.onButtonClick, │ │ │ │ + moveend: this.update, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ │ │ │ │ - if (style.cursor != null) { │ │ │ │ - node.setAttributeNS(null, "cursor", style.cursor); │ │ │ │ + if (this.maximized) { │ │ │ │ + this.maximizeControl(); │ │ │ │ } │ │ │ │ - │ │ │ │ - return node; │ │ │ │ + return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: dashStyle │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * style - {Object} │ │ │ │ - * widthFactor - {Number} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A SVG compliant 'stroke-dasharray' value │ │ │ │ + /** │ │ │ │ + * Method: baseLayerDraw │ │ │ │ + * Draw the base layer - called if unable to complete in the initial draw │ │ │ │ */ │ │ │ │ - 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, ","); │ │ │ │ - } │ │ │ │ + baseLayerDraw: function() { │ │ │ │ + this.draw(); │ │ │ │ + this.map.events.unregister("changebaselayer", this, this.baseLayerDraw); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: createNode │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: rectDrag │ │ │ │ + * Handle extent rectangle drag │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * type - {String} Kind of node to draw │ │ │ │ - * id - {String} Id for node │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A new node of the given type and id │ │ │ │ + * px - {<OpenLayers.Pixel>} The pixel location of the drag. │ │ │ │ */ │ │ │ │ - createNode: function(type, id) { │ │ │ │ - var node = document.createElementNS(this.xmlns, type); │ │ │ │ - if (id) { │ │ │ │ - node.setAttributeNS(null, "id", id); │ │ │ │ + rectDrag: function(px) { │ │ │ │ + var deltaX = this.handlers.drag.last.x - px.x; │ │ │ │ + var deltaY = this.handlers.drag.last.y - px.y; │ │ │ │ + if (deltaX != 0 || deltaY != 0) { │ │ │ │ + var rectTop = this.rectPxBounds.top; │ │ │ │ + var rectLeft = this.rectPxBounds.left; │ │ │ │ + var rectHeight = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ + var rectWidth = this.rectPxBounds.getWidth(); │ │ │ │ + // don't allow dragging off of parent element │ │ │ │ + var newTop = Math.max(0, (rectTop - deltaY)); │ │ │ │ + newTop = Math.min(newTop, │ │ │ │ + this.ovmap.size.h - this.hComp - rectHeight); │ │ │ │ + var newLeft = Math.max(0, (rectLeft - deltaX)); │ │ │ │ + newLeft = Math.min(newLeft, │ │ │ │ + this.ovmap.size.w - this.wComp - rectWidth); │ │ │ │ + this.setRectPxBounds(new OpenLayers.Bounds(newLeft, │ │ │ │ + newTop + rectHeight, │ │ │ │ + newLeft + rectWidth, │ │ │ │ + newTop)); │ │ │ │ } │ │ │ │ - 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 │ │ │ │ + * Method: mapDivClick │ │ │ │ + * Handle browser events │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {<OpenLayers.Event>} evt │ │ │ │ */ │ │ │ │ - createRenderRoot: function() { │ │ │ │ - var svg = this.nodeFactory(this.container.id + "_svgRoot", "svg"); │ │ │ │ - svg.style.display = "block"; │ │ │ │ - return svg; │ │ │ │ + mapDivClick: function(evt) { │ │ │ │ + var pxCenter = this.rectPxBounds.getCenterPixel(); │ │ │ │ + var deltaX = evt.xy.x - pxCenter.x; │ │ │ │ + var deltaY = evt.xy.y - pxCenter.y; │ │ │ │ + var top = this.rectPxBounds.top; │ │ │ │ + var left = this.rectPxBounds.left; │ │ │ │ + var height = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ + var width = this.rectPxBounds.getWidth(); │ │ │ │ + var newTop = Math.max(0, (top + deltaY)); │ │ │ │ + newTop = Math.min(newTop, this.ovmap.size.h - height); │ │ │ │ + var newLeft = Math.max(0, (left + deltaX)); │ │ │ │ + newLeft = Math.min(newLeft, this.ovmap.size.w - width); │ │ │ │ + this.setRectPxBounds(new OpenLayers.Bounds(newLeft, │ │ │ │ + newTop + height, │ │ │ │ + newLeft + width, │ │ │ │ + newTop)); │ │ │ │ + this.updateMapToRect(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createRoot │ │ │ │ - * │ │ │ │ + * Method: onButtonClick │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * suffix - {String} suffix to append to the id │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - createRoot: function(suffix) { │ │ │ │ - return this.nodeFactory(this.container.id + suffix, "g"); │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + if (evt.buttonElement === this.minimizeDiv) { │ │ │ │ + this.minimizeControl(); │ │ │ │ + } else if (evt.buttonElement === this.maximizeDiv) { │ │ │ │ + this.maximizeControl(); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createDefs │ │ │ │ + * Method: maximizeControl │ │ │ │ + * Unhide the control. Called when the control is in the map viewport. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} The element to which we'll add the symbol definitions │ │ │ │ + * Parameters: │ │ │ │ + * e - {<OpenLayers.Event>} │ │ │ │ */ │ │ │ │ - createDefs: function() { │ │ │ │ - var defs = this.nodeFactory(this.container.id + "_defs", "defs"); │ │ │ │ - this.rendererRoot.appendChild(defs); │ │ │ │ - return defs; │ │ │ │ + maximizeControl: function(e) { │ │ │ │ + this.element.style.display = ''; │ │ │ │ + this.showToggle(false); │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - /************************************** │ │ │ │ - * * │ │ │ │ - * GEOMETRY DRAWING FUNCTIONS * │ │ │ │ - * * │ │ │ │ - **************************************/ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: drawPoint │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * Method: minimizeControl │ │ │ │ + * Hide all the contents of the control, shrink the size, │ │ │ │ + * add the maximize icon │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} or false if the renderer could not draw the point │ │ │ │ + * Parameters: │ │ │ │ + * e - {<OpenLayers.Event>} │ │ │ │ */ │ │ │ │ - drawPoint: function(node, geometry) { │ │ │ │ - return this.drawCircle(node, geometry, 1); │ │ │ │ + minimizeControl: function(e) { │ │ │ │ + this.element.style.display = 'none'; │ │ │ │ + this.showToggle(true); │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Method: showToggle │ │ │ │ + * Hide/Show the toggle depending on whether the control is minimized │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * minimize - {Boolean} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + showToggle: function(minimize) { │ │ │ │ + if (this.maximizeDiv) { │ │ │ │ + this.maximizeDiv.style.display = minimize ? '' : 'none'; │ │ │ │ + } │ │ │ │ + if (this.minimizeDiv) { │ │ │ │ + this.minimizeDiv.style.display = minimize ? 'none' : ''; │ │ │ │ } │ │ │ │ - │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Method: update │ │ │ │ + * Update the overview map after layers move. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + update: function() { │ │ │ │ + if (this.ovmap == null) { │ │ │ │ + this.createMap(); │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ + if (this.autoPan || !this.isSuitableOverview()) { │ │ │ │ + this.updateOverview(); │ │ │ │ } │ │ │ │ + │ │ │ │ + // update extent rectangle │ │ │ │ + this.updateRectToMap(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Method: isSuitableOverview │ │ │ │ + * Determines if the overview map is suitable given the extent and │ │ │ │ + * resolution of the main map. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + isSuitableOverview: function() { │ │ │ │ + var mapExtent = this.map.getExtent(); │ │ │ │ + var maxExtent = this.map.getMaxExtent(); │ │ │ │ + var testExtent = new OpenLayers.Bounds( │ │ │ │ + Math.max(mapExtent.left, maxExtent.left), │ │ │ │ + Math.max(mapExtent.bottom, maxExtent.bottom), │ │ │ │ + Math.min(mapExtent.right, maxExtent.right), │ │ │ │ + Math.min(mapExtent.top, maxExtent.top)); │ │ │ │ + │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + testExtent = testExtent.transform( │ │ │ │ + this.map.getProjectionObject(), │ │ │ │ + this.ovmap.getProjectionObject()); │ │ │ │ } │ │ │ │ + │ │ │ │ + var resRatio = this.ovmap.getResolution() / this.map.getResolution(); │ │ │ │ + return ((resRatio > this.minRatio) && │ │ │ │ + (resRatio <= this.maxRatio) && │ │ │ │ + (this.ovmap.getExtent().containsBounds(testExtent))); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: 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 │ │ │ │ + * Method updateOverview │ │ │ │ + * Called by <update> if <isSuitableOverview> returns true │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + updateOverview: function() { │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ + var targetRes = this.ovmap.getResolution(); │ │ │ │ + var resRatio = targetRes / mapRes; │ │ │ │ + if (resRatio > this.maxRatio) { │ │ │ │ + // zoom in overview map │ │ │ │ + targetRes = this.minRatio * mapRes; │ │ │ │ + } else if (resRatio <= this.minRatio) { │ │ │ │ + // zoom out overview map │ │ │ │ + targetRes = this.maxRatio * mapRes; │ │ │ │ + } │ │ │ │ + var center; │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + center = this.map.center.clone(); │ │ │ │ + center.transform(this.map.getProjectionObject(), │ │ │ │ + this.ovmap.getProjectionObject()); │ │ │ │ } else { │ │ │ │ - return false; │ │ │ │ + center = this.map.center; │ │ │ │ } │ │ │ │ + this.ovmap.setCenter(center, this.ovmap.getZoomForResolution( │ │ │ │ + targetRes * this.resolutionFactor)); │ │ │ │ + this.updateRectToMap(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawText │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * featureId - {String} │ │ │ │ - * style - │ │ │ │ - * location - {<OpenLayers.Geometry.Point>} │ │ │ │ + * Method: createMap │ │ │ │ + * Construct the map that this control contains │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + createMap: function() { │ │ │ │ + // create the overview map │ │ │ │ + var options = OpenLayers.Util.extend({ │ │ │ │ + controls: [], │ │ │ │ + maxResolution: 'auto', │ │ │ │ + fallThrough: false │ │ │ │ + }, this.mapOptions); │ │ │ │ + this.ovmap = new OpenLayers.Map(this.mapDiv, options); │ │ │ │ + this.ovmap.viewPortDiv.appendChild(this.extentRectangle); │ │ │ │ │ │ │ │ - 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"); │ │ │ │ + // prevent ovmap from being destroyed when the page unloads, because │ │ │ │ + // the OverviewMap control has to do this (and does it). │ │ │ │ + OpenLayers.Event.stopObserving(window, 'unload', this.ovmap.unloadDestroy); │ │ │ │ │ │ │ │ - if (OpenLayers.IS_GECKO === true) { │ │ │ │ - label.setAttributeNS(null, "dominant-baseline", │ │ │ │ - OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]] || "central"); │ │ │ │ - } │ │ │ │ + this.ovmap.addLayers(this.layers); │ │ │ │ + this.ovmap.zoomToMaxExtent(); │ │ │ │ + // check extent rectangle border width │ │ │ │ + this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ + 'border-left-width')) + │ │ │ │ + parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ + 'border-right-width')); │ │ │ │ + this.wComp = (this.wComp) ? this.wComp : 2; │ │ │ │ + this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ + 'border-top-width')) + │ │ │ │ + parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ + 'border-bottom-width')); │ │ │ │ + this.hComp = (this.hComp) ? this.hComp : 2; │ │ │ │ │ │ │ │ - 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; │ │ │ │ + this.handlers.drag = new OpenLayers.Handler.Drag( │ │ │ │ + this, { │ │ │ │ + move: this.rectDrag, │ │ │ │ + done: this.updateMapToRect │ │ │ │ + }, { │ │ │ │ + map: this.ovmap │ │ │ │ } │ │ │ │ - if (OpenLayers.IS_GECKO === false) { │ │ │ │ - tspan.setAttributeNS(null, "baseline-shift", │ │ │ │ - OpenLayers.Renderer.SVG.LABEL_VSHIFT[align[1]] || "-35%"); │ │ │ │ + ); │ │ │ │ + this.handlers.click = new OpenLayers.Handler.Click( │ │ │ │ + this, { │ │ │ │ + "click": this.mapDivClick │ │ │ │ + }, { │ │ │ │ + "single": true, │ │ │ │ + "double": false, │ │ │ │ + "stopSingle": true, │ │ │ │ + "stopDouble": true, │ │ │ │ + "pixelTolerance": 1, │ │ │ │ + map: this.ovmap │ │ │ │ } │ │ │ │ - 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"); │ │ │ │ + ); │ │ │ │ + this.handlers.click.activate(); │ │ │ │ + │ │ │ │ + this.rectEvents = new OpenLayers.Events(this, this.extentRectangle, │ │ │ │ + null, true); │ │ │ │ + this.rectEvents.register("mouseover", this, function(e) { │ │ │ │ + if (!this.handlers.drag.active && !this.map.dragging) { │ │ │ │ + this.handlers.drag.activate(); │ │ │ │ } │ │ │ │ - tspan.textContent = (labelRows[i] === '') ? ' ' : labelRows[i]; │ │ │ │ - if (!tspan.parentNode) { │ │ │ │ - label.appendChild(tspan); │ │ │ │ + }); │ │ │ │ + this.rectEvents.register("mouseout", this, function(e) { │ │ │ │ + if (!this.handlers.drag.dragging) { │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ } │ │ │ │ - } │ │ │ │ + }); │ │ │ │ │ │ │ │ - if (!label.parentNode) { │ │ │ │ - this.textRoot.appendChild(label); │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + var sourceUnits = this.map.getProjectionObject().getUnits() || │ │ │ │ + this.map.units || this.map.baseLayer.units; │ │ │ │ + var targetUnits = this.ovmap.getProjectionObject().getUnits() || │ │ │ │ + this.ovmap.units || this.ovmap.baseLayer.units; │ │ │ │ + this.resolutionFactor = sourceUnits && targetUnits ? │ │ │ │ + OpenLayers.INCHES_PER_UNIT[sourceUnits] / │ │ │ │ + OpenLayers.INCHES_PER_UNIT[targetUnits] : 1; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: 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) │ │ │ │ + /** │ │ │ │ + * Method: updateRectToMap │ │ │ │ + * Updates the extent rectangle position and size to match the map extent │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + updateRectToMap: function() { │ │ │ │ + // If the projections differ we need to reproject │ │ │ │ + var bounds; │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + bounds = this.map.getExtent().transform( │ │ │ │ + this.map.getProjectionObject(), │ │ │ │ + this.ovmap.getProjectionObject()); │ │ │ │ + } else { │ │ │ │ + bounds = this.map.getExtent(); │ │ │ │ } │ │ │ │ + var pxBounds = this.getRectBoundsFromMapBounds(bounds); │ │ │ │ + if (pxBounds) { │ │ │ │ + this.setRectPxBounds(pxBounds); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - return { │ │ │ │ - path: strings.join(separator || ","), │ │ │ │ - complete: complete │ │ │ │ - }; │ │ │ │ + /** │ │ │ │ + * Method: updateMapToRect │ │ │ │ + * Updates the map extent to match the extent rectangle position and size │ │ │ │ + */ │ │ │ │ + updateMapToRect: function() { │ │ │ │ + var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds); │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + lonLatBounds = lonLatBounds.transform( │ │ │ │ + this.ovmap.getProjectionObject(), │ │ │ │ + this.map.getProjectionObject()); │ │ │ │ + } │ │ │ │ + this.map.panTo(lonLatBounds.getCenterLonLat()); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: 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. │ │ │ │ - * │ │ │ │ + * Method: setRectPxBounds │ │ │ │ + * Set extent rectangle pixel bounds. │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * pxBounds - {<OpenLayers.Bounds>} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + setRectPxBounds: function(pxBounds) { │ │ │ │ + var top = Math.max(pxBounds.top, 0); │ │ │ │ + var left = Math.max(pxBounds.left, 0); │ │ │ │ + var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()), │ │ │ │ + this.ovmap.size.h - this.hComp); │ │ │ │ + var right = Math.min(pxBounds.left + pxBounds.getWidth(), │ │ │ │ + this.ovmap.size.w - this.wComp); │ │ │ │ + var width = Math.max(right - left, 0); │ │ │ │ + var height = Math.max(bottom - top, 0); │ │ │ │ + if (width < this.minRectSize || height < this.minRectSize) { │ │ │ │ + this.extentRectangle.className = this.displayClass + │ │ │ │ + this.minRectDisplayClass; │ │ │ │ + var rLeft = left + (width / 2) - (this.minRectSize / 2); │ │ │ │ + var rTop = top + (height / 2) - (this.minRectSize / 2); │ │ │ │ + this.extentRectangle.style.top = Math.round(rTop) + 'px'; │ │ │ │ + this.extentRectangle.style.left = Math.round(rLeft) + 'px'; │ │ │ │ + this.extentRectangle.style.height = this.minRectSize + 'px'; │ │ │ │ + this.extentRectangle.style.width = this.minRectSize + 'px'; │ │ │ │ + } else { │ │ │ │ + this.extentRectangle.className = this.displayClass + │ │ │ │ + 'ExtentRectangle'; │ │ │ │ + this.extentRectangle.style.top = Math.round(top) + 'px'; │ │ │ │ + this.extentRectangle.style.left = Math.round(left) + 'px'; │ │ │ │ + this.extentRectangle.style.height = Math.round(height) + 'px'; │ │ │ │ + this.extentRectangle.style.width = Math.round(width) + 'px'; │ │ │ │ } │ │ │ │ - return x2 + "," + y2; │ │ │ │ + this.rectPxBounds = new OpenLayers.Bounds( │ │ │ │ + Math.round(left), Math.round(bottom), │ │ │ │ + Math.round(right), Math.round(top) │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getShortString │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: getRectBoundsFromMapBounds │ │ │ │ + * Get the rect bounds from the map bounds. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * point - {<OpenLayers.Geometry.Point>} │ │ │ │ - * │ │ │ │ + * lonLatBounds - {<OpenLayers.Bounds>} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {String} or false if point is outside the valid range │ │ │ │ + * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent │ │ │ │ + * translated into pixel bounds for the overview map │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + getRectBoundsFromMapBounds: function(lonLatBounds) { │ │ │ │ + var leftBottomPx = this.getOverviewPxFromLonLat({ │ │ │ │ + lon: lonLatBounds.left, │ │ │ │ + lat: lonLatBounds.bottom │ │ │ │ + }); │ │ │ │ + var rightTopPx = this.getOverviewPxFromLonLat({ │ │ │ │ + lon: lonLatBounds.right, │ │ │ │ + lat: lonLatBounds.top │ │ │ │ + }); │ │ │ │ + var bounds = null; │ │ │ │ + if (leftBottomPx && rightTopPx) { │ │ │ │ + bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y, │ │ │ │ + rightTopPx.x, rightTopPx.y); │ │ │ │ } │ │ │ │ + return bounds; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getPosition │ │ │ │ - * Finds the position of an svg node. │ │ │ │ - * │ │ │ │ + * Method: getMapBoundsFromRectBounds │ │ │ │ + * Get the map bounds from the rect bounds. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * │ │ │ │ + * pxBounds - {<OpenLayers.Bounds>} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} hash with x and y properties, representing the coordinates │ │ │ │ - * within the svg coordinate system │ │ │ │ + * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds │ │ │ │ + * translated into lon/lat bounds for the overview map │ │ │ │ */ │ │ │ │ - getPosition: function(node) { │ │ │ │ - return ({ │ │ │ │ - x: parseFloat(node.getAttributeNS(null, "cx")), │ │ │ │ - y: parseFloat(node.getAttributeNS(null, "cy")) │ │ │ │ + getMapBoundsFromRectBounds: function(pxBounds) { │ │ │ │ + var leftBottomLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ + x: pxBounds.left, │ │ │ │ + y: pxBounds.bottom │ │ │ │ + }); │ │ │ │ + var rightTopLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ + x: pxBounds.right, │ │ │ │ + y: pxBounds.top │ │ │ │ }); │ │ │ │ + return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat, │ │ │ │ + rightTopLonLat.lon, rightTopLonLat.lat); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: importSymbol │ │ │ │ - * add a new symbol definition from the rendererer's symbol hash │ │ │ │ - * │ │ │ │ + * Method: getLonLatFromOverviewPx │ │ │ │ + * Get a map location from a pixel location │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * graphicName - {String} name of the symbol to import │ │ │ │ - * │ │ │ │ + * overviewMapPx - {<OpenLayers.Pixel>|Object} OpenLayers.Pixel or │ │ │ │ + * an object with a │ │ │ │ + * 'x' and 'y' properties. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} - the imported symbol │ │ │ │ + * {Object} Location which is the passed-in overview map │ │ │ │ + * OpenLayers.Pixel, translated into lon/lat by the overview │ │ │ │ + * map. An object with a 'lon' and 'lat' properties. │ │ │ │ */ │ │ │ │ - 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(" ")); │ │ │ │ + getLonLatFromOverviewPx: function(overviewMapPx) { │ │ │ │ + var size = this.ovmap.size; │ │ │ │ + var res = this.ovmap.getResolution(); │ │ │ │ + var center = this.ovmap.getExtent().getCenterLonLat(); │ │ │ │ │ │ │ │ - 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 │ │ │ │ - ]; │ │ │ │ + var deltaX = overviewMapPx.x - (size.w / 2); │ │ │ │ + var deltaY = overviewMapPx.y - (size.h / 2); │ │ │ │ │ │ │ │ - this.defs.appendChild(symbolNode); │ │ │ │ - return symbolNode; │ │ │ │ + return { │ │ │ │ + lon: center.lon + deltaX * res, │ │ │ │ + lat: center.lat - deltaY * res │ │ │ │ + }; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getFeatureIdFromEvent │ │ │ │ - * │ │ │ │ + * Method: getOverviewPxFromLonLat │ │ │ │ + * Get a pixel location from a map location │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Object} An <OpenLayers.Event> object │ │ │ │ + * lonlat - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an │ │ │ │ + * object with a 'lon' and 'lat' properties. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} A feature id or undefined. │ │ │ │ + * {Object} Location which is the passed-in OpenLayers.LonLat, │ │ │ │ + * translated into overview map pixels │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + getOverviewPxFromLonLat: function(lonlat) { │ │ │ │ + var res = this.ovmap.getResolution(); │ │ │ │ + var extent = this.ovmap.getExtent(); │ │ │ │ + if (extent) { │ │ │ │ + return { │ │ │ │ + x: Math.round(1 / res * (lonlat.lon - extent.left)), │ │ │ │ + y: Math.round(1 / res * (extent.top - lonlat.lat)) │ │ │ │ + }; │ │ │ │ } │ │ │ │ - return featureId; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.SVG" │ │ │ │ + CLASS_NAME: 'OpenLayers.Control.OverviewMap' │ │ │ │ }); │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * 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/Renderer/Canvas.js │ │ │ │ + OpenLayers/Control/Measure.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 │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Renderer.Canvas │ │ │ │ - * A renderer based on the 2D 'canvas' drawing element. │ │ │ │ - * │ │ │ │ - * Inherits: │ │ │ │ - * - <OpenLayers.Renderer> │ │ │ │ + * Class: OpenLayers.Control.Measure │ │ │ │ + * Allows for drawing of features for measurements. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ +OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: hitDetection │ │ │ │ - * {Boolean} Allow for hit detection of features. Default is true. │ │ │ │ + * 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>): │ │ │ │ + * measure - Triggered when a measurement sketch is complete. Listeners │ │ │ │ + * will receive an event with measure, units, order, and geometry │ │ │ │ + * properties. │ │ │ │ + * measurepartial - Triggered when a new point is added to the │ │ │ │ + * measurement sketch or if the <immediate> property is true and the │ │ │ │ + * measurement sketch is modified. Listeners receive an event with measure, │ │ │ │ + * units, order, and geometry. │ │ │ │ */ │ │ │ │ - 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). │ │ │ │ + * APIProperty: handlerOptions │ │ │ │ + * {Object} Used to set non-default properties on the control's handler │ │ │ │ */ │ │ │ │ - hitOverflow: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: canvas │ │ │ │ - * {Canvas} The canvas context object. │ │ │ │ + * Property: callbacks │ │ │ │ + * {Object} The functions that are sent to the handler for callback │ │ │ │ */ │ │ │ │ - canvas: null, │ │ │ │ + callbacks: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: features │ │ │ │ - * {Object} Internal object of feature/style pairs for use in redrawing the layer. │ │ │ │ + * APIProperty: displaySystem │ │ │ │ + * {String} Display system for output measurements. Supported values │ │ │ │ + * are 'english', 'metric', and 'geographic'. Default is 'metric'. │ │ │ │ */ │ │ │ │ - features: null, │ │ │ │ + displaySystem: 'metric', │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: pendingRedraw │ │ │ │ - * {Boolean} The renderer needs a redraw call to render features added while │ │ │ │ - * the renderer was locked. │ │ │ │ + * APIProperty: geodesic │ │ │ │ + * {Boolean} Calculate geodesic metrics instead of planar metrics. This │ │ │ │ + * requires that geometries can be transformed into Geographic/WGS84 │ │ │ │ + * (if that is not already the map projection). Default is false. │ │ │ │ */ │ │ │ │ - pendingRedraw: false, │ │ │ │ + geodesic: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: cachedSymbolBounds │ │ │ │ - * {Object} Internal cache of calculated symbol extents. │ │ │ │ + * Property: displaySystemUnits │ │ │ │ + * {Object} Units for various measurement systems. Values are arrays │ │ │ │ + * of unit abbreviations (from OpenLayers.INCHES_PER_UNIT) in decreasing │ │ │ │ + * order of length. │ │ │ │ */ │ │ │ │ - cachedSymbolBounds: {}, │ │ │ │ + displaySystemUnits: { │ │ │ │ + geographic: ['dd'], │ │ │ │ + english: ['mi', 'ft', 'in'], │ │ │ │ + metric: ['km', 'm'] │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Renderer.Canvas │ │ │ │ + * Property: delay │ │ │ │ + * {Number} Number of milliseconds between clicks before the event is │ │ │ │ + * considered a double-click. The "measurepartial" event will not │ │ │ │ + * be triggered if the sketch is completed within this time. This │ │ │ │ + * is required for IE where creating a browser reflow (if a listener │ │ │ │ + * is modifying the DOM by displaying the measurement values) messes │ │ │ │ + * with the dblclick listener in the sketch handler. │ │ │ │ + */ │ │ │ │ + partialDelay: 300, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: delayedTrigger │ │ │ │ + * {Number} Timeout id of trigger for measurepartial. │ │ │ │ + */ │ │ │ │ + delayedTrigger: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: persist │ │ │ │ + * {Boolean} Keep the temporary measurement sketch drawn after the │ │ │ │ + * measurement is complete. The geometry will persist until a new │ │ │ │ + * measurement is started, the control is deactivated, or <cancel> is │ │ │ │ + * called. │ │ │ │ + */ │ │ │ │ + persist: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: immediate │ │ │ │ + * {Boolean} Activates the immediate measurement so that the "measurepartial" │ │ │ │ + * event is also fired once the measurement sketch is modified. │ │ │ │ + * Default is false. │ │ │ │ + */ │ │ │ │ + immediate: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.Measure │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * containerID - {<String>} │ │ │ │ - * options - {Object} Optional properties to be set on the renderer. │ │ │ │ + * handler - {<OpenLayers.Handler>} │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ + initialize: function(handler, options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + var callbacks = { │ │ │ │ + done: this.measureComplete, │ │ │ │ + point: this.measurePartial │ │ │ │ + }; │ │ │ │ + if (this.immediate) { │ │ │ │ + callbacks.modify = this.measureImmediate; │ │ │ │ } │ │ │ │ + this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks); │ │ │ │ + │ │ │ │ + // let the handler options override, so old code that passes 'persist' │ │ │ │ + // directly to the handler does not need an update │ │ │ │ + this.handlerOptions = OpenLayers.Util.extend({ │ │ │ │ + persist: this.persist │ │ │ │ + }, this.handlerOptions); │ │ │ │ + this.handler = new handler(this, this.callbacks, this.handlerOptions); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setExtent │ │ │ │ - * Set the visible part of the layer. │ │ │ │ + * APIMethod: deactivate │ │ │ │ + */ │ │ │ │ + deactivate: function() { │ │ │ │ + this.cancelDelay(); │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: cancel │ │ │ │ + * Stop the control from measuring. If <persist> is true, the temporary │ │ │ │ + * sketch will be erased. │ │ │ │ + */ │ │ │ │ + cancel: function() { │ │ │ │ + this.cancelDelay(); │ │ │ │ + this.handler.cancel(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setImmediate │ │ │ │ + * Sets the <immediate> property. Changes the activity of immediate │ │ │ │ + * measurement. │ │ │ │ + */ │ │ │ │ + setImmediate: function(immediate) { │ │ │ │ + this.immediate = immediate; │ │ │ │ + if (this.immediate) { │ │ │ │ + this.callbacks.modify = this.measureImmediate; │ │ │ │ + } else { │ │ │ │ + delete this.callbacks.modify; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: updateHandler │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * handler - {Function} One of the sketch handler constructors. │ │ │ │ + * options - {Object} Options for the handler. │ │ │ │ */ │ │ │ │ - setExtent: function() { │ │ │ │ - OpenLayers.Renderer.prototype.setExtent.apply(this, arguments); │ │ │ │ - // always redraw features │ │ │ │ - return false; │ │ │ │ + updateHandler: function(handler, options) { │ │ │ │ + var active = this.active; │ │ │ │ + if (active) { │ │ │ │ + this.deactivate(); │ │ │ │ + } │ │ │ │ + this.handler = new handler(this, this.callbacks, options); │ │ │ │ + if (active) { │ │ │ │ + this.activate(); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: measureComplete │ │ │ │ + * Called when the measurement sketch is done. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * featureId - {String} │ │ │ │ */ │ │ │ │ - eraseGeometry: function(geometry, featureId) { │ │ │ │ - this.eraseFeatures(this.features[featureId][0]); │ │ │ │ + measureComplete: function(geometry) { │ │ │ │ + this.cancelDelay(); │ │ │ │ + this.measure(geometry, "measure"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: supported │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the browser supports the renderer class │ │ │ │ + * Method: measurePartial │ │ │ │ + * Called each time a new point is added to the measurement sketch. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} The last point added. │ │ │ │ + * geometry - {<OpenLayers.Geometry>} The sketch geometry. │ │ │ │ */ │ │ │ │ - supported: function() { │ │ │ │ - return OpenLayers.CANVAS_SUPPORTED; │ │ │ │ + measurePartial: function(point, geometry) { │ │ │ │ + this.cancelDelay(); │ │ │ │ + geometry = geometry.clone(); │ │ │ │ + // when we're wating for a dblclick, we have to trigger measurepartial │ │ │ │ + // after some delay to deal with reflow issues in IE │ │ │ │ + if (this.handler.freehandMode(this.handler.evt)) { │ │ │ │ + // no dblclick in freehand mode │ │ │ │ + this.measure(geometry, "measurepartial"); │ │ │ │ + } else { │ │ │ │ + this.delayedTrigger = window.setTimeout( │ │ │ │ + OpenLayers.Function.bind(function() { │ │ │ │ + this.delayedTrigger = null; │ │ │ │ + this.measure(geometry, "measurepartial"); │ │ │ │ + }, this), │ │ │ │ + this.partialDelay │ │ │ │ + ); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setSize │ │ │ │ - * Sets the size of the drawing surface. │ │ │ │ + * Method: measureImmediate │ │ │ │ + * Called each time the measurement sketch is modified. │ │ │ │ * │ │ │ │ - * Once the size is updated, redraw the canvas. │ │ │ │ + * Parameters: │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} The point at the mouse position. │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The sketch feature. │ │ │ │ + * drawing - {Boolean} Indicates whether we're currently drawing. │ │ │ │ + */ │ │ │ │ + measureImmediate: function(point, feature, drawing) { │ │ │ │ + if (drawing && !this.handler.freehandMode(this.handler.evt)) { │ │ │ │ + this.cancelDelay(); │ │ │ │ + this.measure(feature.geometry, "measurepartial"); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: cancelDelay │ │ │ │ + * Cancels the delay measurement that measurePartial began. │ │ │ │ + */ │ │ │ │ + cancelDelay: function() { │ │ │ │ + if (this.delayedTrigger !== null) { │ │ │ │ + window.clearTimeout(this.delayedTrigger); │ │ │ │ + this.delayedTrigger = null; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: measure │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * size - {<OpenLayers.Size>} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * eventType - {String} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + measure: function(geometry, eventType) { │ │ │ │ + var stat, order; │ │ │ │ + if (geometry.CLASS_NAME.indexOf('LineString') > -1) { │ │ │ │ + stat = this.getBestLength(geometry); │ │ │ │ + order = 1; │ │ │ │ + } else { │ │ │ │ + stat = this.getBestArea(geometry); │ │ │ │ + order = 2; │ │ │ │ } │ │ │ │ + this.events.triggerEvent(eventType, { │ │ │ │ + measure: stat[0], │ │ │ │ + units: stat[1], │ │ │ │ + order: order, │ │ │ │ + geometry: geometry │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawFeature │ │ │ │ - * Draw the feature. Stores the feature in the features list, │ │ │ │ - * then redraws the layer. │ │ │ │ + * Method: getBestArea │ │ │ │ + * Based on the <displaySystem> returns the area of a geometry. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - * style - {<Object>} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * {Array([Float, String])} Returns a two item array containing the │ │ │ │ + * area and the units abbreviation. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ + getBestArea: function(geometry) { │ │ │ │ + var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ + var unit, area; │ │ │ │ + for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ + unit = units[i]; │ │ │ │ + area = this.getArea(geometry, unit); │ │ │ │ + if (area > 1) { │ │ │ │ + break; │ │ │ │ } │ │ │ │ + } │ │ │ │ + return [area, unit]; │ │ │ │ + }, │ │ │ │ │ │ │ │ - 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; │ │ │ │ + /** │ │ │ │ + * Method: getArea │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * units - {String} Unit abbreviation │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Float} The geometry area in the given units. │ │ │ │ + */ │ │ │ │ + getArea: function(geometry, units) { │ │ │ │ + var area, geomUnits; │ │ │ │ + if (this.geodesic) { │ │ │ │ + area = geometry.getGeodesicArea(this.map.getProjectionObject()); │ │ │ │ + geomUnits = "m"; │ │ │ │ + } else { │ │ │ │ + area = geometry.getArea(); │ │ │ │ + geomUnits = this.map.getUnits(); │ │ │ │ } │ │ │ │ - if (this.pendingRedraw && !this.locked) { │ │ │ │ - this.redraw(); │ │ │ │ - this.pendingRedraw = false; │ │ │ │ + var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ + if (inPerDisplayUnit) { │ │ │ │ + var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ + area *= Math.pow((inPerMapUnit / inPerDisplayUnit), 2); │ │ │ │ } │ │ │ │ - return rendered; │ │ │ │ + return area; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: drawGeometry │ │ │ │ - * Used when looping (in redraw) over the features; draws │ │ │ │ - * the canvas. │ │ │ │ + /** │ │ │ │ + * Method: getBestLength │ │ │ │ + * Based on the <displaySystem> returns the length of a geometry. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array([Float, String])} Returns a two item array containing the │ │ │ │ + * length and the units abbreviation. │ │ │ │ */ │ │ │ │ - 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: │ │ │ │ + getBestLength: function(geometry) { │ │ │ │ + var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ + var unit, length; │ │ │ │ + for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ + unit = units[i]; │ │ │ │ + length = this.getLength(geometry, unit); │ │ │ │ + if (length > 1) { │ │ │ │ break; │ │ │ │ + } │ │ │ │ } │ │ │ │ + return [length, unit]; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawExternalGraphic │ │ │ │ - * Called to draw External graphics. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ + * Method: getLength │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ - * featureId - {String} │ │ │ │ + * units - {String} Unit abbreviation │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Float} The geometry length in the given units. │ │ │ │ */ │ │ │ │ - drawExternalGraphic: function(geometry, style, featureId) { │ │ │ │ - var img = new Image(); │ │ │ │ - │ │ │ │ - var title = style.title || style.graphicTitle; │ │ │ │ - if (title) { │ │ │ │ - img.title = title; │ │ │ │ + getLength: function(geometry, units) { │ │ │ │ + var length, geomUnits; │ │ │ │ + if (this.geodesic) { │ │ │ │ + length = geometry.getGeodesicLength(this.map.getProjectionObject()); │ │ │ │ + geomUnits = "m"; │ │ │ │ + } else { │ │ │ │ + length = geometry.getLength(); │ │ │ │ + geomUnits = this.map.getUnits(); │ │ │ │ + } │ │ │ │ + var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ + if (inPerDisplayUnit) { │ │ │ │ + var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ + length *= (inPerMapUnit / inPerDisplayUnit); │ │ │ │ } │ │ │ │ + return length; │ │ │ │ + }, │ │ │ │ │ │ │ │ - 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); │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Measure" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/ModifyFeature.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ +/* 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 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }; │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Handler/Drag.js │ │ │ │ + * @requires OpenLayers/Handler/Keyboard.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - img.onload = OpenLayers.Function.bind(onLoad, this); │ │ │ │ - img.src = style.externalGraphic; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * 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, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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} │ │ │ │ + * APIProperty: documentDrag │ │ │ │ + * {Boolean} If set to true, dragging vertices will continue even if the │ │ │ │ + * mouse cursor leaves the map viewport. Default is false. │ │ │ │ */ │ │ │ │ - drawNamedSymbol: function(geometry, style, featureId) { │ │ │ │ - var x, y, cx, cy, i, symbolBounds, scaling, angle; │ │ │ │ - var unscaledStrokeWidth; │ │ │ │ - var deg2rad = Math.PI / 180.0; │ │ │ │ + documentDrag: false, │ │ │ │ │ │ │ │ - var symbol = OpenLayers.Renderer.symbol[style.graphicName]; │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - if (!symbol) { │ │ │ │ - throw new Error(style.graphicName + ' is not a valid symbol name'); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: clickout │ │ │ │ + * {Boolean} Unselect features when clicking outside any feature. │ │ │ │ + * Default is true. │ │ │ │ + */ │ │ │ │ + clickout: true, │ │ │ │ │ │ │ │ - if (!symbol.length || symbol.length < 2) return; │ │ │ │ + /** │ │ │ │ + * APIProperty: toggle │ │ │ │ + * {Boolean} Unselect a selected feature on click. │ │ │ │ + * Default is true. │ │ │ │ + */ │ │ │ │ + toggle: true, │ │ │ │ │ │ │ │ - var pt = this.getLocalXY(geometry); │ │ │ │ - var p0 = pt[0]; │ │ │ │ - var p1 = pt[1]; │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - if (isNaN(p0) || isNaN(p1)) return; │ │ │ │ + /** │ │ │ │ + * Property: layer │ │ │ │ + * {<OpenLayers.Layer.Vector>} │ │ │ │ + */ │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ - // Use rounded line caps │ │ │ │ - this.canvas.lineCap = "round"; │ │ │ │ - this.canvas.lineJoin = "round"; │ │ │ │ + /** │ │ │ │ + * Property: feature │ │ │ │ + * {<OpenLayers.Feature.Vector>} Feature currently available for modification. │ │ │ │ + */ │ │ │ │ + feature: null, │ │ │ │ │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.lineCap = "round"; │ │ │ │ - this.hitContext.lineJoin = "round"; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: vertex │ │ │ │ + * {<OpenLayers.Feature.Vector>} Vertex currently being modified. │ │ │ │ + */ │ │ │ │ + vertex: null, │ │ │ │ │ │ │ │ - // 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; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: vertices │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} Verticies currently available │ │ │ │ + * for dragging. │ │ │ │ + */ │ │ │ │ + vertices: null, │ │ │ │ │ │ │ │ - // 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(); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: virtualVertices │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} Virtual vertices in the middle │ │ │ │ + * of each edge. │ │ │ │ + */ │ │ │ │ + virtualVertices: null, │ │ │ │ │ │ │ │ - // Step 3: place symbol at the desired location │ │ │ │ - this.canvas.translate(p0, p1); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.translate(p0, p1); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: handlers │ │ │ │ + * {Object} │ │ │ │ + */ │ │ │ │ + handlers: null, │ │ │ │ │ │ │ │ - // 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - // // 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); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: virtualStyle │ │ │ │ + * {Object} A symbolizer to be used for virtual vertices. │ │ │ │ + */ │ │ │ │ + virtualStyle: null, │ │ │ │ │ │ │ │ - // 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); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - // 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; │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - 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(); │ │ │ │ + /** │ │ │ │ + * APIProperty: createVertices │ │ │ │ + * {Boolean} Create new vertices by dragging the virtual vertices │ │ │ │ + * in the middle of each edge. Default is true. │ │ │ │ + */ │ │ │ │ + createVertices: true, │ │ │ │ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: modified │ │ │ │ + * {Boolean} The currently selected feature has been modified. │ │ │ │ + */ │ │ │ │ + modified: false, │ │ │ │ │ │ │ │ - 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(); │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - 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); │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ } │ │ │ │ - this.hitContext.closePath(); │ │ │ │ - this.hitContext.stroke(); │ │ │ │ } │ │ │ │ + }; │ │ │ │ + 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, []); │ │ │ │ + }, │ │ │ │ │ │ │ │ - style.strokeWidth = unscaledStrokeWidth; │ │ │ │ - this.canvas.restore(); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.restore(); │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ } │ │ │ │ - this.setCanvasStyle("reset"); │ │ │ │ + return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setCanvasStyle │ │ │ │ - * Prepare the canvas for drawing by setting various global settings. │ │ │ │ + * Method: beforeSelectFeature │ │ │ │ + * Called before a feature is selected. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * type - {String} one of 'stroke', 'fill', or 'reset' │ │ │ │ - * style - {Object} Symbolizer hash │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature about to be selected. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + beforeSelectFeature: function(feature) { │ │ │ │ + return this.layer.events.triggerEvent( │ │ │ │ + "beforefeaturemodified", { │ │ │ │ + feature: feature │ │ │ │ + } │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: featureIdToHex │ │ │ │ - * Convert a feature ID string into an RGB hex string. │ │ │ │ + * 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: │ │ │ │ - * featureId - {String} Feature id │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {String} RGB hex string. │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The unselected feature. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - var hex = "000000" + id.toString(16); │ │ │ │ - var len = hex.length; │ │ │ │ - hex = "#" + hex.substring(len - 6, len); │ │ │ │ - return hex; │ │ │ │ + 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: setHitContextStyle │ │ │ │ - * Prepare the hit canvas for drawing by setting various global settings. │ │ │ │ + * 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: │ │ │ │ - * type - {String} one of 'stroke', 'fill', or 'reset' │ │ │ │ - * featureId - {String} The feature id. │ │ │ │ - * symbolizer - {<OpenLayers.Symbolizer>} The symbolizer. │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The point or vertex about to be │ │ │ │ + * dragged. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - this.hitContext.globalAlpha = 0; │ │ │ │ - this.hitContext.lineWidth = 1; │ │ │ │ + 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: drawPoint │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ - * featureId - {String} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ - } │ │ │ │ + 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: drawLineString │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ - * featureId - {String} │ │ │ │ + * Method: dragComplete │ │ │ │ + * Called by the drag handler when the feature dragging is complete. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged. │ │ │ │ */ │ │ │ │ - drawLineString: function(geometry, style, featureId) { │ │ │ │ - style = OpenLayers.Util.applyDefaults({ │ │ │ │ - fill: false │ │ │ │ - }, style); │ │ │ │ - this.drawLinearRing(geometry, style, featureId); │ │ │ │ + dragComplete: function(vertex) { │ │ │ │ + this.resetVertices(); │ │ │ │ + this.setFeatureState(); │ │ │ │ + this.onModification(this.feature); │ │ │ │ + this.layer.events.triggerEvent("featuremodified", { │ │ │ │ + feature: this.feature │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawLinearRing │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ - * featureId - {String} │ │ │ │ + * Method: setFeatureState │ │ │ │ + * Called when the feature is modified. If the current state is not │ │ │ │ + * INSERT or DELETE, the state is set to UPDATE. │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ } │ │ │ │ - this.setCanvasStyle("reset"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: renderPath │ │ │ │ - * Render a path with stroke and optional fill. │ │ │ │ + * Method: resetVertices │ │ │ │ */ │ │ │ │ - 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]); │ │ │ │ + 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 (type === "fill") { │ │ │ │ - context.fill(); │ │ │ │ - } else { │ │ │ │ - context.stroke(); │ │ │ │ + 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: drawPolygon │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ - * featureId - {String} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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"; │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ } │ │ │ │ - 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} │ │ │ │ + * Method: collectVertices │ │ │ │ + * Collect the vertices from the modifiable feature's geometry and push │ │ │ │ + * them on to the control's vertices array. │ │ │ │ */ │ │ │ │ - drawText: function(location, style) { │ │ │ │ - var pt = this.getLocalXY(location); │ │ │ │ + collectVertices: function() { │ │ │ │ + this.vertices = []; │ │ │ │ + this.virtualVertices = []; │ │ │ │ + var control = this; │ │ │ │ │ │ │ │ - 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(); │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - 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"); │ │ │ │ + collectComponentVertices.call(this, this.feature.geometry); │ │ │ │ + this.layer.addFeatures(this.virtualVertices, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + this.layer.addFeatures(this.vertices, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getLocalXY │ │ │ │ - * transform geographic xy into pixel xy │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * point - {<OpenLayers.Geometry.Point>} │ │ │ │ + * Method: collectDragHandle │ │ │ │ + * Collect the drag handle for the selected geometry. │ │ │ │ */ │ │ │ │ - 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]; │ │ │ │ + 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: clear │ │ │ │ - * Clear all vectors from the renderer. │ │ │ │ + * Method: collectRadiusHandle │ │ │ │ + * Collect the radius handle for the selected geometry. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + 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: getFeatureIdFromEvent │ │ │ │ - * Returns a feature id from an event on the renderer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ + * Method: setMap │ │ │ │ + * Set the map property for the control and all handlers. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} The control's map. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + setMap: function(map) { │ │ │ │ + this.handlers.drag.setMap(map); │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: eraseFeatures │ │ │ │ - * This is called by the layer to erase features; removes the feature from │ │ │ │ - * the list, then redraws the layer. │ │ │ │ + * Method: handleMapEvents │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ + * evt - {Object} │ │ │ │ */ │ │ │ │ - eraseFeatures: function(features) { │ │ │ │ - if (!(OpenLayers.Util.isArray(features))) { │ │ │ │ - features = [features]; │ │ │ │ - } │ │ │ │ - for (var i = 0; i < features.length; ++i) { │ │ │ │ - delete this.features[features[i].id]; │ │ │ │ + handleMapEvents: function(evt) { │ │ │ │ + if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ + this.moveLayerToTop(); │ │ │ │ } │ │ │ │ - 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. │ │ │ │ + * Method: moveLayerToTop │ │ │ │ + * Moves the layer for this handler to the top, so mouse events can reach │ │ │ │ + * it. │ │ │ │ */ │ │ │ │ - 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]); │ │ │ │ - } │ │ │ │ + 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.Renderer.Canvas" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ModifyFeature" │ │ │ │ }); │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Renderer.Canvas.LABEL_ALIGN │ │ │ │ - * {Object} │ │ │ │ + * Constant: RESHAPE │ │ │ │ + * {Integer} Constant used to make the control work in reshape mode │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.Canvas.LABEL_ALIGN = { │ │ │ │ - "l": "left", │ │ │ │ - "r": "right", │ │ │ │ - "t": "top", │ │ │ │ - "b": "bottom" │ │ │ │ -}; │ │ │ │ - │ │ │ │ +OpenLayers.Control.ModifyFeature.RESHAPE = 1; │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Renderer.Canvas.LABEL_FACTOR │ │ │ │ - * {Object} │ │ │ │ + * Constant: RESIZE │ │ │ │ + * {Integer} Constant used to make the control work in resize mode │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.Canvas.LABEL_FACTOR = { │ │ │ │ - "l": 0, │ │ │ │ - "r": -1, │ │ │ │ - "t": 0, │ │ │ │ - "b": -1 │ │ │ │ -}; │ │ │ │ - │ │ │ │ +OpenLayers.Control.ModifyFeature.RESIZE = 2; │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Constant: ROTATE │ │ │ │ + * {Integer} Constant used to make the control work in rotate mode │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.Canvas.drawImageScaleFactor = null; │ │ │ │ +OpenLayers.Control.ModifyFeature.ROTATE = 4; │ │ │ │ +/** │ │ │ │ + * Constant: DRAG │ │ │ │ + * {Integer} Constant used to make the control work in drag mode │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.ModifyFeature.DRAG = 8; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Renderer/VML.js │ │ │ │ + OpenLayers/Control/Split.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 │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Handler/Path.js │ │ │ │ + * @requires OpenLayers/Layer/Vector.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Renderer.VML │ │ │ │ - * Render vector features in browsers with VML capability. Construct a new │ │ │ │ - * VML renderer with the <OpenLayers.Renderer.VML> constructor. │ │ │ │ - * │ │ │ │ - * Note that for all calculations in this class, we use (num | 0) to truncate a │ │ │ │ - * float value to an integer. This is done because it seems that VML doesn't │ │ │ │ - * support float values. │ │ │ │ + * Class: OpenLayers.Control.Split │ │ │ │ + * Acts as a split feature agent while editing vector features. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Renderer.Elements> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ +OpenLayers.Control.Split = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: xmlns │ │ │ │ - * {String} XML Namespace URN │ │ │ │ + /** │ │ │ │ + * 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>): │ │ │ │ + * beforesplit - Triggered before a split occurs. Listeners receive an │ │ │ │ + * event object with *source* and *target* properties. │ │ │ │ + * split - Triggered when a split occurs. Listeners receive an event with │ │ │ │ + * an *original* property and a *features* property. The original │ │ │ │ + * is a reference to the target feature that the sketch or modified │ │ │ │ + * feature intersects. The features property is a list of all features │ │ │ │ + * that result from this single split. This event is triggered before │ │ │ │ + * the resulting features are added to the layer (while the layer still │ │ │ │ + * has a reference to the original). │ │ │ │ + * aftersplit - Triggered after all splits resulting from a single sketch │ │ │ │ + * or feature modification have occurred. The original features │ │ │ │ + * have been destroyed and features that result from the split │ │ │ │ + * have already been added to the layer. Listeners receive an event │ │ │ │ + * with a *source* and *features* property. The source references the │ │ │ │ + * sketch or modified feature used as a splitter. The features │ │ │ │ + * property is a list of all resulting features. │ │ │ │ */ │ │ │ │ - xmlns: "urn:schemas-microsoft-com:vml", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: symbolCache │ │ │ │ - * {DOMElement} node holding symbols. This hash is keyed by symbol name, │ │ │ │ - * and each value is a hash with a "path" and an "extent" property. │ │ │ │ + * APIProperty: layer │ │ │ │ + * {<OpenLayers.Layer.Vector>} The target layer with features to be split. │ │ │ │ + * Set at construction or after construction with <setLayer>. │ │ │ │ */ │ │ │ │ - symbolCache: {}, │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: offset │ │ │ │ - * {Object} Hash with "x" and "y" properties │ │ │ │ + * Property: source │ │ │ │ + * {<OpenLayers.Layer.Vector>} Optional source layer. Any newly created │ │ │ │ + * or modified features from this layer will be used to split features │ │ │ │ + * on the target layer. If not provided, a temporary sketch layer will │ │ │ │ + * be created. │ │ │ │ */ │ │ │ │ - offset: null, │ │ │ │ + source: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Renderer.VML │ │ │ │ - * Create a new VML renderer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * containerID - {String} The id for the element that contains the renderer │ │ │ │ + * Property: sourceOptions │ │ │ │ + * {Options} If a temporary sketch layer is created, these layer options │ │ │ │ + * will be applied. │ │ │ │ */ │ │ │ │ - initialize: function(containerID) { │ │ │ │ - if (!this.supported()) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - if (!document.namespaces.olv) { │ │ │ │ - document.namespaces.add("olv", this.xmlns); │ │ │ │ - var style = document.createStyleSheet(); │ │ │ │ - var shapes = ['shape', 'rect', 'oval', 'fill', 'stroke', 'imagedata', 'group', 'textbox']; │ │ │ │ - for (var i = 0, len = shapes.length; i < len; i++) { │ │ │ │ + sourceOptions: null, │ │ │ │ │ │ │ │ - style.addRule('olv\\:' + shapes[i], "behavior: url(#default#VML); " + │ │ │ │ - "position: absolute; display: inline-block;"); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: tolerance │ │ │ │ + * {Number} Distance between the calculated intersection and a vertex on │ │ │ │ + * the source geometry below which the existing vertex will be used │ │ │ │ + * for the split. Default is null. │ │ │ │ + */ │ │ │ │ + tolerance: null, │ │ │ │ │ │ │ │ - OpenLayers.Renderer.Elements.prototype.initialize.apply(this, │ │ │ │ - arguments); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * APIProperty: edge │ │ │ │ + * {Boolean} Allow splits given intersection of edges only. Default is │ │ │ │ + * true. If false, a vertex on the source must be within the │ │ │ │ + * <tolerance> distance of the calculated intersection for a split │ │ │ │ + * to occur. │ │ │ │ + */ │ │ │ │ + edge: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: supported │ │ │ │ - * Determine whether a browser supports this renderer. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The browser supports the VML renderer │ │ │ │ + * APIProperty: deferDelete │ │ │ │ + * {Boolean} Instead of removing features from the layer, set feature │ │ │ │ + * states of split features to DELETE. This assumes a save strategy │ │ │ │ + * or other component is in charge of removing features from the │ │ │ │ + * layer. Default is false. If false, split features will be │ │ │ │ + * immediately deleted from the layer. │ │ │ │ */ │ │ │ │ - supported: function() { │ │ │ │ - return !!(document.namespaces); │ │ │ │ - }, │ │ │ │ + deferDelete: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setExtent │ │ │ │ - * Set the renderer's extent │ │ │ │ - * │ │ │ │ - * 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. │ │ │ │ + * APIProperty: mutual │ │ │ │ + * {Boolean} If source and target layers are the same, split source │ │ │ │ + * features and target features where they intersect. Default is │ │ │ │ + * true. If false, only target features will be split. │ │ │ │ */ │ │ │ │ - setExtent: function(extent, resolutionChanged) { │ │ │ │ - var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments); │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ + mutual: true, │ │ │ │ │ │ │ │ - var left = (extent.left / resolution) | 0; │ │ │ │ - var top = (extent.top / resolution - this.size.h) | 0; │ │ │ │ - if (resolutionChanged || !this.offset) { │ │ │ │ - this.offset = { │ │ │ │ - x: left, │ │ │ │ - y: top │ │ │ │ - }; │ │ │ │ - left = 0; │ │ │ │ - top = 0; │ │ │ │ - } else { │ │ │ │ - left = left - this.offset.x; │ │ │ │ - top = top - this.offset.y; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: targetFilter │ │ │ │ + * {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ + * to determine if a feature from the target layer is eligible for │ │ │ │ + * splitting. │ │ │ │ + */ │ │ │ │ + targetFilter: null, │ │ │ │ │ │ │ │ + /** │ │ │ │ + * APIProperty: sourceFilter │ │ │ │ + * {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ + * to determine if a feature from the source layer is eligible for │ │ │ │ + * splitting. │ │ │ │ + */ │ │ │ │ + sourceFilter: null, │ │ │ │ │ │ │ │ - var org = (left - this.xOffset) + " " + top; │ │ │ │ - this.root.coordorigin = org; │ │ │ │ - var roots = [this.root, this.vectorRoot, this.textRoot]; │ │ │ │ - var root; │ │ │ │ - for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ - root = roots[i]; │ │ │ │ + /** │ │ │ │ + * Property: handler │ │ │ │ + * {<OpenLayers.Handler.Path>} The temporary sketch handler created if │ │ │ │ + * no source layer is provided. │ │ │ │ + */ │ │ │ │ + handler: null, │ │ │ │ │ │ │ │ - var size = this.size.w + " " + this.size.h; │ │ │ │ - root.coordsize = size; │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.Split │ │ │ │ + * Creates a new split control. A control is constructed with a target │ │ │ │ + * layer and an optional source layer. While the control is active, │ │ │ │ + * creating new features or modifying existing features on the source │ │ │ │ + * layer will result in splitting any eligible features on the target │ │ │ │ + * layer. If no source layer is provided, a temporary sketch layer will │ │ │ │ + * be created to create lines for splitting features on the target. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An object containing all configuration properties for │ │ │ │ + * the control. │ │ │ │ + * │ │ │ │ + * Valid options: │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} The target layer. Features from this │ │ │ │ + * layer will be split by new or modified features on the source layer │ │ │ │ + * or temporary sketch layer. │ │ │ │ + * source - {<OpenLayers.Layer.Vector>} Optional source layer. If provided │ │ │ │ + * newly created features or modified features will be used to split │ │ │ │ + * features on the target layer. If not provided, a temporary sketch │ │ │ │ + * layer will be created for drawing lines. │ │ │ │ + * tolerance - {Number} Optional value for the distance between a source │ │ │ │ + * vertex and the calculated intersection below which the split will │ │ │ │ + * occur at the vertex. │ │ │ │ + * edge - {Boolean} Allow splits given intersection of edges only. Default │ │ │ │ + * is true. If false, a vertex on the source must be within the │ │ │ │ + * <tolerance> distance of the calculated intersection for a split │ │ │ │ + * to occur. │ │ │ │ + * mutual - {Boolean} If source and target are the same, split source │ │ │ │ + * features and target features where they intersect. Default is │ │ │ │ + * true. If false, only target features will be split. │ │ │ │ + * targetFilter - {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ + * to determine if a feature from the target layer is eligible for │ │ │ │ + * splitting. │ │ │ │ + * sourceFilter - {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ + * to determine if a feature from the target layer is eligible for │ │ │ │ + * splitting. │ │ │ │ + */ │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.options = options || {}; // TODO: this could be done by the super │ │ │ │ │ │ │ │ + // set the source layer if provided │ │ │ │ + if (this.options.source) { │ │ │ │ + this.setSource(this.options.source); │ │ │ │ } │ │ │ │ - // flip the VML display Y axis upside down so it │ │ │ │ - // matches the display Y axis of the map │ │ │ │ - this.root.style.flip = "y"; │ │ │ │ - │ │ │ │ - return coordSysUnchanged; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: setSize │ │ │ │ - * Set the size of the drawing surface │ │ │ │ + * APIMethod: setSource │ │ │ │ + * Set the source layer for edits layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * size - {<OpenLayers.Size>} the size of the drawing surface │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} The new source layer layer. If │ │ │ │ + * null, a temporary sketch layer will be created. │ │ │ │ */ │ │ │ │ - setSize: function(size) { │ │ │ │ - OpenLayers.Renderer.prototype.setSize.apply(this, arguments); │ │ │ │ + setSource: function(layer) { │ │ │ │ + if (this.active) { │ │ │ │ + this.deactivate(); │ │ │ │ + if (this.handler) { │ │ │ │ + this.handler.destroy(); │ │ │ │ + delete this.handler; │ │ │ │ + } │ │ │ │ + this.source = layer; │ │ │ │ + this.activate(); │ │ │ │ + } else { │ │ │ │ + this.source = layer; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - // setting width and height on all roots to avoid flicker which we │ │ │ │ - // would get with 100% width and height on child roots │ │ │ │ - var roots = [ │ │ │ │ - this.rendererRoot, │ │ │ │ - this.root, │ │ │ │ - this.vectorRoot, │ │ │ │ - this.textRoot │ │ │ │ - ]; │ │ │ │ - var w = this.size.w + "px"; │ │ │ │ - var h = this.size.h + "px"; │ │ │ │ - var root; │ │ │ │ - for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ - root = roots[i]; │ │ │ │ - root.style.width = w; │ │ │ │ - root.style.height = h; │ │ │ │ + /** │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the control. Activating the control registers listeners for │ │ │ │ + * editing related events so that during feature creation and │ │ │ │ + * modification, features in the target will be considered for │ │ │ │ + * splitting. │ │ │ │ + */ │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + if (!this.source) { │ │ │ │ + if (!this.handler) { │ │ │ │ + this.handler = new OpenLayers.Handler.Path(this, { │ │ │ │ + done: function(geometry) { │ │ │ │ + this.onSketchComplete({ │ │ │ │ + feature: new OpenLayers.Feature.Vector(geometry) │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + }, { │ │ │ │ + layerOptions: this.sourceOptions │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + this.handler.activate(); │ │ │ │ + } else if (this.source.events) { │ │ │ │ + this.source.events.on({ │ │ │ │ + sketchcomplete: this.onSketchComplete, │ │ │ │ + afterfeaturemodified: this.afterFeatureModified, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ } │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getNodeType │ │ │ │ - * Get the node type for a geometry and style │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the control. Deactivating the control unregisters listeners │ │ │ │ + * so feature editing may proceed without engaging the split agent. │ │ │ │ + */ │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + if (this.source && this.source.events) { │ │ │ │ + this.source.events.un({ │ │ │ │ + sketchcomplete: this.onSketchComplete, │ │ │ │ + afterfeaturemodified: this.afterFeatureModified, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return deactivated; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: onSketchComplete │ │ │ │ + * Registered as a listener for the sketchcomplete event on the editable │ │ │ │ + * layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ + * event - {Object} The sketch complete event. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} The corresponding node type for the specified geometry │ │ │ │ + * {Boolean} Stop the sketch from being added to the layer (it has been │ │ │ │ + * split). │ │ │ │ */ │ │ │ │ - getNodeType: function(geometry, style) { │ │ │ │ - var nodeType = null; │ │ │ │ - switch (geometry.CLASS_NAME) { │ │ │ │ - case "OpenLayers.Geometry.Point": │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - nodeType = "olv:rect"; │ │ │ │ - } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ - nodeType = "olv:shape"; │ │ │ │ - } else { │ │ │ │ - nodeType = "olv:oval"; │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "OpenLayers.Geometry.Rectangle": │ │ │ │ - nodeType = "olv:rect"; │ │ │ │ - break; │ │ │ │ - case "OpenLayers.Geometry.LineString": │ │ │ │ - case "OpenLayers.Geometry.LinearRing": │ │ │ │ - case "OpenLayers.Geometry.Polygon": │ │ │ │ - case "OpenLayers.Geometry.Curve": │ │ │ │ - nodeType = "olv:shape"; │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - return nodeType; │ │ │ │ + onSketchComplete: function(event) { │ │ │ │ + this.feature = null; │ │ │ │ + return !this.considerSplit(event.feature); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setStyle │ │ │ │ - * Use to set all the style attributes to a VML node. │ │ │ │ + * Method: afterFeatureModified │ │ │ │ + * Registered as a listener for the afterfeaturemodified event on the │ │ │ │ + * editable layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} An VML element to decorate │ │ │ │ - * style - {Object} │ │ │ │ - * options - {Object} Currently supported options include │ │ │ │ - * 'isFilled' {Boolean} and │ │ │ │ - * 'isStroked' {Boolean} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * event - {Object} The after feature modified event. │ │ │ │ */ │ │ │ │ - setStyle: function(node, style, options, geometry) { │ │ │ │ - style = style || node._style; │ │ │ │ - options = options || node._options; │ │ │ │ - var fillColor = style.fillColor; │ │ │ │ - │ │ │ │ - var title = style.title || style.graphicTitle; │ │ │ │ - if (title) { │ │ │ │ - node.title = title; │ │ │ │ + afterFeatureModified: function(event) { │ │ │ │ + if (event.modified) { │ │ │ │ + var feature = event.feature; │ │ │ │ + if (typeof feature.geometry.split === "function") { │ │ │ │ + this.feature = event.feature; │ │ │ │ + this.considerSplit(event.feature); │ │ │ │ + } │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - options.isFilled = true; │ │ │ │ - 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 resolution = this.getResolution(); │ │ │ │ - var xOffset = (style.graphicXOffset != undefined) ? │ │ │ │ - style.graphicXOffset : -(0.5 * width); │ │ │ │ - var yOffset = (style.graphicYOffset != undefined) ? │ │ │ │ - style.graphicYOffset : -(0.5 * height); │ │ │ │ - │ │ │ │ - node.style.left = ((((geometry.x - this.featureDx) / resolution - this.offset.x) + xOffset) | 0) + "px"; │ │ │ │ - node.style.top = (((geometry.y / resolution - this.offset.y) - (yOffset + height)) | 0) + "px"; │ │ │ │ - node.style.width = width + "px"; │ │ │ │ - node.style.height = height + "px"; │ │ │ │ - node.style.flip = "y"; │ │ │ │ - │ │ │ │ - // modify fillColor and options for stroke styling below │ │ │ │ - fillColor = "none"; │ │ │ │ - options.isStroked = false; │ │ │ │ - } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ - var cache = this.importSymbol(style.graphicName); │ │ │ │ - node.path = cache.path; │ │ │ │ - node.coordorigin = cache.left + "," + cache.bottom; │ │ │ │ - var size = cache.size; │ │ │ │ - node.coordsize = size + "," + size; │ │ │ │ - this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ - node.style.flip = "y"; │ │ │ │ - } else { │ │ │ │ - this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ + /** │ │ │ │ + * Method: removeByGeometry │ │ │ │ + * Remove a feature from a list based on the given geometry. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * features - {Array(<OpenLayers.Feature.Vector>)} A list of features. │ │ │ │ + * geometry - {<OpenLayers.Geometry>} A geometry. │ │ │ │ + */ │ │ │ │ + removeByGeometry: function(features, geometry) { │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ + if (features[i].geometry === geometry) { │ │ │ │ + features.splice(i, 1); │ │ │ │ + break; │ │ │ │ } │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - // fill │ │ │ │ - if (options.isFilled) { │ │ │ │ - node.fillcolor = fillColor; │ │ │ │ + /** │ │ │ │ + * Method: isEligible │ │ │ │ + * Test if a target feature is eligible for splitting. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * target - {<OpenLayers.Feature.Vector>} The target feature. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The target is eligible for splitting. │ │ │ │ + */ │ │ │ │ + isEligible: function(target) { │ │ │ │ + if (!target.geometry) { │ │ │ │ + return false; │ │ │ │ } else { │ │ │ │ - node.filled = "false"; │ │ │ │ + return ( │ │ │ │ + target.state !== OpenLayers.State.DELETE │ │ │ │ + ) && ( │ │ │ │ + typeof target.geometry.split === "function" │ │ │ │ + ) && ( │ │ │ │ + this.feature !== target │ │ │ │ + ) && ( │ │ │ │ + !this.targetFilter || │ │ │ │ + this.targetFilter.evaluate(target.attributes) │ │ │ │ + ); │ │ │ │ } │ │ │ │ - var fills = node.getElementsByTagName("fill"); │ │ │ │ - var fill = (fills.length == 0) ? null : fills[0]; │ │ │ │ - if (!options.isFilled) { │ │ │ │ - if (fill) { │ │ │ │ - node.removeChild(fill); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (!fill) { │ │ │ │ - fill = this.createNode('olv:fill', node.id + "_fill"); │ │ │ │ - } │ │ │ │ - fill.opacity = style.fillOpacity; │ │ │ │ - │ │ │ │ - if (node._geometryClass === "OpenLayers.Geometry.Point" && │ │ │ │ - style.externalGraphic) { │ │ │ │ - │ │ │ │ - // override fillOpacity │ │ │ │ - if (style.graphicOpacity) { │ │ │ │ - fill.opacity = style.graphicOpacity; │ │ │ │ - } │ │ │ │ - │ │ │ │ - fill.src = style.externalGraphic; │ │ │ │ - fill.type = "frame"; │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ - fill.aspect = "atmost"; │ │ │ │ + /** │ │ │ │ + * Method: considerSplit │ │ │ │ + * Decide whether or not to split target features with the supplied │ │ │ │ + * feature. If <mutual> is true, both the source and target features │ │ │ │ + * will be split if eligible. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The newly created or modified │ │ │ │ + * feature. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The supplied feature was split (and destroyed). │ │ │ │ + */ │ │ │ │ + considerSplit: function(feature) { │ │ │ │ + var sourceSplit = false; │ │ │ │ + var targetSplit = false; │ │ │ │ + if (!this.sourceFilter || │ │ │ │ + this.sourceFilter.evaluate(feature.attributes)) { │ │ │ │ + var features = this.layer && this.layer.features || []; │ │ │ │ + var target, results, proceed; │ │ │ │ + var additions = [], │ │ │ │ + removals = []; │ │ │ │ + var mutual = (this.layer === this.source) && this.mutual; │ │ │ │ + var options = { │ │ │ │ + edge: this.edge, │ │ │ │ + tolerance: this.tolerance, │ │ │ │ + mutual: mutual │ │ │ │ + }; │ │ │ │ + var sourceParts = [feature.geometry]; │ │ │ │ + var targetFeature, targetParts; │ │ │ │ + var source, parts; │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ + targetFeature = features[i]; │ │ │ │ + if (this.isEligible(targetFeature)) { │ │ │ │ + targetParts = [targetFeature.geometry]; │ │ │ │ + // work through source geoms - this array may change │ │ │ │ + for (var j = 0; j < sourceParts.length; ++j) { │ │ │ │ + source = sourceParts[j]; │ │ │ │ + // work through target parts - this array may change │ │ │ │ + for (var k = 0; k < targetParts.length; ++k) { │ │ │ │ + target = targetParts[k]; │ │ │ │ + if (source.getBounds().intersectsBounds(target.getBounds())) { │ │ │ │ + results = source.split(target, options); │ │ │ │ + if (results) { │ │ │ │ + proceed = this.events.triggerEvent( │ │ │ │ + "beforesplit", { │ │ │ │ + source: feature, │ │ │ │ + target: targetFeature │ │ │ │ + } │ │ │ │ + ); │ │ │ │ + if (proceed !== false) { │ │ │ │ + if (mutual) { │ │ │ │ + parts = results[0]; │ │ │ │ + // handle parts that result from source splitting │ │ │ │ + if (parts.length > 1) { │ │ │ │ + // splice in new source parts │ │ │ │ + parts.unshift(j, 1); // add args for splice below │ │ │ │ + Array.prototype.splice.apply(sourceParts, parts); │ │ │ │ + j += parts.length - 3; │ │ │ │ + } │ │ │ │ + results = results[1]; │ │ │ │ + } │ │ │ │ + // handle parts that result from target splitting │ │ │ │ + if (results.length > 1) { │ │ │ │ + // splice in new target parts │ │ │ │ + results.unshift(k, 1); // add args for splice below │ │ │ │ + Array.prototype.splice.apply(targetParts, results); │ │ │ │ + k += results.length - 3; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (targetParts && targetParts.length > 1) { │ │ │ │ + this.geomsToFeatures(targetFeature, targetParts); │ │ │ │ + this.events.triggerEvent("split", { │ │ │ │ + original: targetFeature, │ │ │ │ + features: targetParts │ │ │ │ + }); │ │ │ │ + Array.prototype.push.apply(additions, targetParts); │ │ │ │ + removals.push(targetFeature); │ │ │ │ + targetSplit = true; │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ - if (fill.parentNode != node) { │ │ │ │ - node.appendChild(fill); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // additional rendering for rotated graphics or symbols │ │ │ │ - var rotation = style.rotation; │ │ │ │ - if ((rotation !== undefined || node._rotation !== undefined)) { │ │ │ │ - node._rotation = rotation; │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ - // make the fill fully transparent, because we now have │ │ │ │ - // the graphic as imagedata element. We cannot just remove │ │ │ │ - // the fill, because this is part of the hack described │ │ │ │ - // in graphicRotate │ │ │ │ - fill.opacity = 0; │ │ │ │ - } else if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ - node.style.rotation = rotation || 0; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // stroke │ │ │ │ - var strokes = node.getElementsByTagName("stroke"); │ │ │ │ - var stroke = (strokes.length == 0) ? null : strokes[0]; │ │ │ │ - if (!options.isStroked) { │ │ │ │ - node.stroked = false; │ │ │ │ - if (stroke) { │ │ │ │ - stroke.on = false; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (!stroke) { │ │ │ │ - stroke = this.createNode('olv:stroke', node.id + "_stroke"); │ │ │ │ - node.appendChild(stroke); │ │ │ │ + if (sourceParts && sourceParts.length > 1) { │ │ │ │ + this.geomsToFeatures(feature, sourceParts); │ │ │ │ + this.events.triggerEvent("split", { │ │ │ │ + original: feature, │ │ │ │ + features: sourceParts │ │ │ │ + }); │ │ │ │ + Array.prototype.push.apply(additions, sourceParts); │ │ │ │ + removals.push(feature); │ │ │ │ + sourceSplit = true; │ │ │ │ } │ │ │ │ - stroke.on = true; │ │ │ │ - stroke.color = style.strokeColor; │ │ │ │ - stroke.weight = style.strokeWidth + "px"; │ │ │ │ - stroke.opacity = style.strokeOpacity; │ │ │ │ - stroke.endcap = style.strokeLinecap == 'butt' ? 'flat' : │ │ │ │ - (style.strokeLinecap || 'round'); │ │ │ │ - if (style.strokeDashstyle) { │ │ │ │ - stroke.dashstyle = this.dashStyle(style); │ │ │ │ + if (sourceSplit || targetSplit) { │ │ │ │ + // remove and add feature events are suppressed │ │ │ │ + // listen for split event on this control instead │ │ │ │ + if (this.deferDelete) { │ │ │ │ + // Set state instead of removing. Take care to avoid │ │ │ │ + // setting delete for features that have not yet been │ │ │ │ + // inserted - those should be destroyed immediately. │ │ │ │ + var feat, destroys = []; │ │ │ │ + for (var i = 0, len = removals.length; i < len; ++i) { │ │ │ │ + feat = removals[i]; │ │ │ │ + if (feat.state === OpenLayers.State.INSERT) { │ │ │ │ + destroys.push(feat); │ │ │ │ + } else { │ │ │ │ + feat.state = OpenLayers.State.DELETE; │ │ │ │ + this.layer.drawFeature(feat); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.layer.destroyFeatures(destroys, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + for (var i = 0, len = additions.length; i < len; ++i) { │ │ │ │ + additions[i].state = OpenLayers.State.INSERT; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.layer.destroyFeatures(removals, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + this.layer.addFeatures(additions, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + this.events.triggerEvent("aftersplit", { │ │ │ │ + source: feature, │ │ │ │ + features: additions │ │ │ │ + }); │ │ │ │ } │ │ │ │ } │ │ │ │ + return sourceSplit; │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ - node.style.cursor = style.cursor; │ │ │ │ + /** │ │ │ │ + * Method: geomsToFeatures │ │ │ │ + * Create new features given a template feature and a list of geometries. │ │ │ │ + * The list of geometries is modified in place. The result will be │ │ │ │ + * a list of new features. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature to be cloned. │ │ │ │ + * geoms - {Array(<OpenLayers.Geometry>)} List of goemetries. This will │ │ │ │ + * become a list of new features. │ │ │ │ + */ │ │ │ │ + geomsToFeatures: function(feature, geoms) { │ │ │ │ + var clone = feature.clone(); │ │ │ │ + delete clone.geometry; │ │ │ │ + var newFeature; │ │ │ │ + for (var i = 0, len = geoms.length; i < len; ++i) { │ │ │ │ + // turn results list from geoms to features │ │ │ │ + newFeature = clone.clone(); │ │ │ │ + newFeature.geometry = geoms[i]; │ │ │ │ + newFeature.state = OpenLayers.State.INSERT; │ │ │ │ + geoms[i] = newFeature; │ │ │ │ } │ │ │ │ - return node; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: graphicRotate │ │ │ │ - * If a point is to be styled with externalGraphic and rotation, VML fills │ │ │ │ - * cannot be used to display the graphic, because rotation of graphic │ │ │ │ - * fills is not supported by the VML implementation of Internet Explorer. │ │ │ │ - * This method creates a olv:imagedata element inside the VML node, │ │ │ │ - * DXImageTransform.Matrix and BasicImage filters for rotation and │ │ │ │ - * opacity, and a 3-step hack to remove rendering artefacts from the │ │ │ │ - * graphic and preserve the ability of graphics to trigger events. │ │ │ │ - * Finally, OpenLayers methods are used to determine the correct │ │ │ │ - * insertion point of the rotated image, because DXImageTransform.Matrix │ │ │ │ - * does the rotation without the ability to specify a rotation center │ │ │ │ - * point. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * xOffset - {Number} rotation center relative to image, x coordinate │ │ │ │ - * yOffset - {Number} rotation center relative to image, y coordinate │ │ │ │ - * style - {Object} │ │ │ │ + * Method: destroy │ │ │ │ + * Clean up the control. │ │ │ │ */ │ │ │ │ - graphicRotate: function(node, xOffset, yOffset, style) { │ │ │ │ - var style = style || node._style; │ │ │ │ - var rotation = style.rotation || 0; │ │ │ │ + destroy: function() { │ │ │ │ + if (this.active) { │ │ │ │ + this.deactivate(); // TODO: this should be handled by the super │ │ │ │ + } │ │ │ │ + OpenLayers.Control.prototype.destroy.call(this); │ │ │ │ + }, │ │ │ │ │ │ │ │ - var aspectRatio, size; │ │ │ │ - if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ - // load the image to determine its size │ │ │ │ - var img = new Image(); │ │ │ │ - img.onreadystatechange = OpenLayers.Function.bind(function() { │ │ │ │ - if (img.readyState == "complete" || │ │ │ │ - img.readyState == "interactive") { │ │ │ │ - aspectRatio = img.width / img.height; │ │ │ │ - size = Math.max(style.pointRadius * 2, │ │ │ │ - style.graphicWidth || 0, │ │ │ │ - style.graphicHeight || 0); │ │ │ │ - xOffset = xOffset * aspectRatio; │ │ │ │ - style.graphicWidth = size * aspectRatio; │ │ │ │ - style.graphicHeight = size; │ │ │ │ - this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ - } │ │ │ │ - }, this); │ │ │ │ - img.src = style.externalGraphic; │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Split" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/NavigationHistory.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - // will be called again by the onreadystate handler │ │ │ │ - return; │ │ │ │ - } else { │ │ │ │ - size = Math.max(style.graphicWidth, style.graphicHeight); │ │ │ │ - aspectRatio = style.graphicWidth / style.graphicHeight; │ │ │ │ - } │ │ │ │ +/* 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 width = Math.round(style.graphicWidth || size * aspectRatio); │ │ │ │ - var height = Math.round(style.graphicHeight || size); │ │ │ │ - node.style.width = width + "px"; │ │ │ │ - node.style.height = height + "px"; │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Control/Button.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - // Three steps are required to remove artefacts for images with │ │ │ │ - // transparent backgrounds (resulting from using DXImageTransform │ │ │ │ - // filters on svg objects), while preserving awareness for browser │ │ │ │ - // events on images: │ │ │ │ - // - Use the fill as usual (like for unrotated images) to handle │ │ │ │ - // events │ │ │ │ - // - specify an imagedata element with the same src as the fill │ │ │ │ - // - style the imagedata element with an AlphaImageLoader filter │ │ │ │ - // with empty src │ │ │ │ - var image = document.getElementById(node.id + "_image"); │ │ │ │ - if (!image) { │ │ │ │ - image = this.createNode("olv:imagedata", node.id + "_image"); │ │ │ │ - node.appendChild(image); │ │ │ │ - } │ │ │ │ - image.style.width = width + "px"; │ │ │ │ - image.style.height = height + "px"; │ │ │ │ - image.src = style.externalGraphic; │ │ │ │ - image.style.filter = │ │ │ │ - "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + │ │ │ │ - "src='', sizingMethod='scale')"; │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.NavigationHistory │ │ │ │ + * A navigation history control. This is a meta-control, that creates two │ │ │ │ + * dependent controls: <previous> and <next>. Call the trigger method │ │ │ │ + * on the <previous> and <next> controls to restore previous and next │ │ │ │ + * history states. The previous and next controls will become active │ │ │ │ + * when there are available states to restore and will become deactive │ │ │ │ + * when there are no states to restore. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.NavigationHistory = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ - var rot = rotation * Math.PI / 180; │ │ │ │ - var sintheta = Math.sin(rot); │ │ │ │ - var costheta = Math.cos(rot); │ │ │ │ + /** │ │ │ │ + * Property: type │ │ │ │ + * {String} Note that this control is not intended to be added directly │ │ │ │ + * to a control panel. Instead, add the sub-controls previous and │ │ │ │ + * next. These sub-controls are button type controls that activate │ │ │ │ + * and deactivate themselves. If this parent control is added to │ │ │ │ + * a panel, it will act as a toggle. │ │ │ │ + */ │ │ │ │ + type: OpenLayers.Control.TYPE_TOGGLE, │ │ │ │ │ │ │ │ - // do the rotation on the image │ │ │ │ - var filter = │ │ │ │ - "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta + │ │ │ │ - ",M12=" + (-sintheta) + ",M21=" + sintheta + ",M22=" + costheta + │ │ │ │ - ",SizingMethod='auto expand')\n"; │ │ │ │ + /** │ │ │ │ + * APIProperty: previous │ │ │ │ + * {<OpenLayers.Control>} A button type control whose trigger method restores │ │ │ │ + * the previous state managed by this control. │ │ │ │ + */ │ │ │ │ + previous: null, │ │ │ │ │ │ │ │ - // set the opacity (needed for the imagedata) │ │ │ │ - var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ - if (opacity && opacity != 1) { │ │ │ │ - filter += │ │ │ │ - "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + │ │ │ │ - opacity + ")\n"; │ │ │ │ - } │ │ │ │ - node.style.filter = filter; │ │ │ │ + /** │ │ │ │ + * APIProperty: previousOptions │ │ │ │ + * {Object} Set this property on the options argument of the constructor │ │ │ │ + * to set optional properties on the <previous> control. │ │ │ │ + */ │ │ │ │ + previousOptions: null, │ │ │ │ │ │ │ │ - // do the rotation again on a box, so we know the insertion point │ │ │ │ - var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset); │ │ │ │ - var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry(); │ │ │ │ - imgBox.rotate(style.rotation, centerPoint); │ │ │ │ - var imgBounds = imgBox.getBounds(); │ │ │ │ + /** │ │ │ │ + * APIProperty: next │ │ │ │ + * {<OpenLayers.Control>} A button type control whose trigger method restores │ │ │ │ + * the next state managed by this control. │ │ │ │ + */ │ │ │ │ + next: null, │ │ │ │ │ │ │ │ - node.style.left = Math.round( │ │ │ │ - parseInt(node.style.left) + imgBounds.left) + "px"; │ │ │ │ - node.style.top = Math.round( │ │ │ │ - parseInt(node.style.top) - imgBounds.bottom) + "px"; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * APIProperty: nextOptions │ │ │ │ + * {Object} Set this property on the options argument of the constructor │ │ │ │ + * to set optional properties on the <next> control. │ │ │ │ + */ │ │ │ │ + nextOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: postDraw │ │ │ │ - * Does some node postprocessing to work around browser issues: │ │ │ │ - * - Some versions of Internet Explorer seem to be unable to set fillcolor │ │ │ │ - * and strokecolor to "none" correctly before the fill node is appended │ │ │ │ - * to a visible vml node. This method takes care of that and sets │ │ │ │ - * fillcolor and strokecolor again if needed. │ │ │ │ - * - In some cases, a node won't become visible after being drawn. Setting │ │ │ │ - * style.visibility to "visible" works around that. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ + * APIProperty: limit │ │ │ │ + * {Integer} Optional limit on the number of history items to retain. If │ │ │ │ + * null, there is no limit. Default is 50. │ │ │ │ */ │ │ │ │ - postDraw: function(node) { │ │ │ │ - node.style.visibility = "visible"; │ │ │ │ - var fillColor = node._style.fillColor; │ │ │ │ - var strokeColor = node._style.strokeColor; │ │ │ │ - if (fillColor == "none" && │ │ │ │ - node.fillcolor != fillColor) { │ │ │ │ - node.fillcolor = fillColor; │ │ │ │ - } │ │ │ │ - if (strokeColor == "none" && │ │ │ │ - node.strokecolor != strokeColor) { │ │ │ │ - node.strokecolor = strokeColor; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + limit: 50, │ │ │ │ │ │ │ │ + /** │ │ │ │ + * APIProperty: autoActivate │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * true. │ │ │ │ + */ │ │ │ │ + autoActivate: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setNodeDimension │ │ │ │ - * Get the geometry's bounds, convert it to our vml coordinate system, │ │ │ │ - * then set the node's position, size, and local coordinate system. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * Property: clearOnDeactivate │ │ │ │ + * {Boolean} Clear the history when the control is deactivated. Default │ │ │ │ + * is false. │ │ │ │ */ │ │ │ │ - setNodeDimension: function(node, geometry) { │ │ │ │ + clearOnDeactivate: false, │ │ │ │ │ │ │ │ - var bbox = geometry.getBounds(); │ │ │ │ - if (bbox) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ + /** │ │ │ │ + * Property: registry │ │ │ │ + * {Object} An object with keys corresponding to event types. Values │ │ │ │ + * are functions that return an object representing the current state. │ │ │ │ + */ │ │ │ │ + registry: null, │ │ │ │ │ │ │ │ - var scaledBox = │ │ │ │ - new OpenLayers.Bounds(((bbox.left - this.featureDx) / resolution - this.offset.x) | 0, │ │ │ │ - (bbox.bottom / resolution - this.offset.y) | 0, │ │ │ │ - ((bbox.right - this.featureDx) / resolution - this.offset.x) | 0, │ │ │ │ - (bbox.top / resolution - this.offset.y) | 0); │ │ │ │ + /** │ │ │ │ + * Property: nextStack │ │ │ │ + * {Array} Array of items in the history. │ │ │ │ + */ │ │ │ │ + nextStack: null, │ │ │ │ │ │ │ │ - // Set the internal coordinate system to draw the path │ │ │ │ - node.style.left = scaledBox.left + "px"; │ │ │ │ - node.style.top = scaledBox.top + "px"; │ │ │ │ - node.style.width = scaledBox.getWidth() + "px"; │ │ │ │ - node.style.height = scaledBox.getHeight() + "px"; │ │ │ │ + /** │ │ │ │ + * Property: previousStack │ │ │ │ + * {Array} List of items in the history. First item represents the current │ │ │ │ + * state. │ │ │ │ + */ │ │ │ │ + previousStack: null, │ │ │ │ │ │ │ │ - node.coordorigin = scaledBox.left + " " + scaledBox.top; │ │ │ │ - node.coordsize = scaledBox.getWidth() + " " + scaledBox.getHeight(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: listeners │ │ │ │ + * {Object} An object containing properties corresponding to event types. │ │ │ │ + * This object is used to configure the control and is modified on │ │ │ │ + * construction. │ │ │ │ + */ │ │ │ │ + listeners: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: dashStyle │ │ │ │ + /** │ │ │ │ + * Property: restoring │ │ │ │ + * {Boolean} Currently restoring a history state. This is set to true │ │ │ │ + * before calling restore and set to false after restore returns. │ │ │ │ + */ │ │ │ │ + restoring: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.NavigationHistory │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * style - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A VML compliant 'stroke-dasharray' value │ │ │ │ + * options - {Object} An optional object whose properties will be used │ │ │ │ + * to extend the control. │ │ │ │ */ │ │ │ │ - dashStyle: function(style) { │ │ │ │ - var dash = style.strokeDashstyle; │ │ │ │ - switch (dash) { │ │ │ │ - case 'solid': │ │ │ │ - case 'dot': │ │ │ │ - case 'dash': │ │ │ │ - case 'dashdot': │ │ │ │ - case 'longdash': │ │ │ │ - case 'longdashdot': │ │ │ │ - return dash; │ │ │ │ - default: │ │ │ │ - // very basic guessing of dash style patterns │ │ │ │ - var parts = dash.split(/[ ,]/); │ │ │ │ - if (parts.length == 2) { │ │ │ │ - if (1 * parts[0] >= 2 * parts[1]) { │ │ │ │ - return "longdash"; │ │ │ │ - } │ │ │ │ - return (parts[0] == 1 || parts[1] == 1) ? "dot" : "dash"; │ │ │ │ - } else if (parts.length == 4) { │ │ │ │ - return (1 * parts[0] >= 2 * parts[1]) ? "longdashdot" : │ │ │ │ - "dashdot"; │ │ │ │ - } │ │ │ │ - return "solid"; │ │ │ │ - } │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + │ │ │ │ + this.registry = OpenLayers.Util.extend({ │ │ │ │ + "moveend": this.getState │ │ │ │ + }, this.registry); │ │ │ │ + │ │ │ │ + var previousOptions = { │ │ │ │ + trigger: OpenLayers.Function.bind(this.previousTrigger, this), │ │ │ │ + displayClass: this.displayClass + " " + this.displayClass + "Previous" │ │ │ │ + }; │ │ │ │ + OpenLayers.Util.extend(previousOptions, this.previousOptions); │ │ │ │ + this.previous = new OpenLayers.Control.Button(previousOptions); │ │ │ │ + │ │ │ │ + var nextOptions = { │ │ │ │ + trigger: OpenLayers.Function.bind(this.nextTrigger, this), │ │ │ │ + displayClass: this.displayClass + " " + this.displayClass + "Next" │ │ │ │ + }; │ │ │ │ + OpenLayers.Util.extend(nextOptions, this.nextOptions); │ │ │ │ + this.next = new OpenLayers.Control.Button(nextOptions); │ │ │ │ + │ │ │ │ + this.clear(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createNode │ │ │ │ - * Create a new node │ │ │ │ + * Method: onPreviousChange │ │ │ │ + * Called when the previous history stack changes. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * type - {String} Kind of node to draw │ │ │ │ - * id - {String} Id for node │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A new node of the given type and id │ │ │ │ + * state - {Object} An object representing the state to be restored │ │ │ │ + * if previous is triggered again or null if no previous states remain. │ │ │ │ + * length - {Integer} The number of remaining previous states that can │ │ │ │ + * be restored. │ │ │ │ */ │ │ │ │ - createNode: function(type, id) { │ │ │ │ - var node = document.createElement(type); │ │ │ │ - if (id) { │ │ │ │ - node.id = id; │ │ │ │ + onPreviousChange: function(state, length) { │ │ │ │ + if (state && !this.previous.active) { │ │ │ │ + this.previous.activate(); │ │ │ │ + } else if (!state && this.previous.active) { │ │ │ │ + this.previous.deactivate(); │ │ │ │ } │ │ │ │ - │ │ │ │ - // IE hack to make elements unselectable, to prevent 'blue flash' │ │ │ │ - // while dragging vectors; #1410 │ │ │ │ - node.unselectable = 'on'; │ │ │ │ - node.onselectstart = OpenLayers.Function.False; │ │ │ │ - │ │ │ │ - return node; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: nodeTypeCompare │ │ │ │ - * Determine whether a node is of a given type │ │ │ │ + * Method: onNextChange │ │ │ │ + * Called when the next history stack changes. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} An VML element │ │ │ │ - * type - {String} Kind of node │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the specified node is of the specified type │ │ │ │ + * state - {Object} An object representing the state to be restored │ │ │ │ + * if next is triggered again or null if no next states remain. │ │ │ │ + * length - {Integer} The number of remaining next states that can │ │ │ │ + * be restored. │ │ │ │ */ │ │ │ │ - nodeTypeCompare: function(node, type) { │ │ │ │ - │ │ │ │ - //split type │ │ │ │ - var subType = type; │ │ │ │ - var splitIndex = subType.indexOf(":"); │ │ │ │ - if (splitIndex != -1) { │ │ │ │ - subType = subType.substr(splitIndex + 1); │ │ │ │ + onNextChange: function(state, length) { │ │ │ │ + if (state && !this.next.active) { │ │ │ │ + this.next.activate(); │ │ │ │ + } else if (!state && this.next.active) { │ │ │ │ + this.next.deactivate(); │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - //split nodeName │ │ │ │ - var nodeName = node.nodeName; │ │ │ │ - splitIndex = nodeName.indexOf(":"); │ │ │ │ - if (splitIndex != -1) { │ │ │ │ - nodeName = nodeName.substr(splitIndex + 1); │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Destroy the control. │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this); │ │ │ │ + this.previous.destroy(); │ │ │ │ + this.next.destroy(); │ │ │ │ + this.deactivate(); │ │ │ │ + for (var prop in this) { │ │ │ │ + this[prop] = null; │ │ │ │ } │ │ │ │ - │ │ │ │ - return (subType == nodeName); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: createRenderRoot │ │ │ │ - * Create the renderer root │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ + * Set the map property for the control and <previous> and <next> child │ │ │ │ + * controls. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} The specific render engine's root element │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - createRenderRoot: function() { │ │ │ │ - return this.nodeFactory(this.container.id + "_vmlRoot", "div"); │ │ │ │ + setMap: function(map) { │ │ │ │ + this.map = map; │ │ │ │ + this.next.setMap(map); │ │ │ │ + this.previous.setMap(map); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createRoot │ │ │ │ - * Create the main root element │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * suffix - {String} suffix to append to the id │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * Method: draw │ │ │ │ + * Called when the control is added to the map. │ │ │ │ */ │ │ │ │ - createRoot: function(suffix) { │ │ │ │ - return this.nodeFactory(this.container.id + suffix, "olv:group"); │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + this.next.draw(); │ │ │ │ + this.previous.draw(); │ │ │ │ }, │ │ │ │ │ │ │ │ - /************************************** │ │ │ │ - * * │ │ │ │ - * GEOMETRY DRAWING FUNCTIONS * │ │ │ │ - * * │ │ │ │ - **************************************/ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: drawPoint │ │ │ │ - * Render a point │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ + * Method: previousTrigger │ │ │ │ + * Restore the previous state. If no items are in the previous history │ │ │ │ + * stack, this has no effect. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} or false if the point could not be drawn │ │ │ │ + * {Object} Item representing state that was restored. Undefined if no │ │ │ │ + * items are in the previous history stack. │ │ │ │ */ │ │ │ │ - drawPoint: function(node, geometry) { │ │ │ │ - return this.drawCircle(node, geometry, 1); │ │ │ │ + previousTrigger: function() { │ │ │ │ + var current = this.previousStack.shift(); │ │ │ │ + var state = this.previousStack.shift(); │ │ │ │ + if (state != undefined) { │ │ │ │ + this.nextStack.unshift(current); │ │ │ │ + this.previousStack.unshift(state); │ │ │ │ + this.restoring = true; │ │ │ │ + this.restore(state); │ │ │ │ + this.restoring = false; │ │ │ │ + this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ + this.onPreviousChange( │ │ │ │ + this.previousStack[1], this.previousStack.length - 1 │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + this.previousStack.unshift(current); │ │ │ │ + } │ │ │ │ + return state; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawCircle │ │ │ │ - * Render a circle. │ │ │ │ - * Size and Center a circle given geometry (x,y center) and radius │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * radius - {float} │ │ │ │ - * │ │ │ │ + * APIMethod: nextTrigger │ │ │ │ + * Restore the next state. If no items are in the next history │ │ │ │ + * stack, this has no effect. The next history stack is populated │ │ │ │ + * as states are restored from the previous history stack. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} or false if the circle could not ne drawn │ │ │ │ + * {Object} Item representing state that was restored. Undefined if no │ │ │ │ + * items are in the next history stack. │ │ │ │ */ │ │ │ │ - drawCircle: function(node, geometry, radius) { │ │ │ │ - if (!isNaN(geometry.x) && !isNaN(geometry.y)) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - │ │ │ │ - node.style.left = ((((geometry.x - this.featureDx) / resolution - this.offset.x) | 0) - radius) + "px"; │ │ │ │ - node.style.top = (((geometry.y / resolution - this.offset.y) | 0) - radius) + "px"; │ │ │ │ - │ │ │ │ - var diameter = radius * 2; │ │ │ │ - │ │ │ │ - node.style.width = diameter + "px"; │ │ │ │ - node.style.height = diameter + "px"; │ │ │ │ - return node; │ │ │ │ + nextTrigger: function() { │ │ │ │ + var state = this.nextStack.shift(); │ │ │ │ + if (state != undefined) { │ │ │ │ + this.previousStack.unshift(state); │ │ │ │ + this.restoring = true; │ │ │ │ + this.restore(state); │ │ │ │ + this.restoring = false; │ │ │ │ + this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ + this.onPreviousChange( │ │ │ │ + this.previousStack[1], this.previousStack.length - 1 │ │ │ │ + ); │ │ │ │ } │ │ │ │ - return false; │ │ │ │ + return state; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: drawLineString │ │ │ │ - * Render a linestring. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * APIMethod: clear │ │ │ │ + * Clear history. │ │ │ │ */ │ │ │ │ - drawLineString: function(node, geometry) { │ │ │ │ - return this.drawLine(node, geometry, false); │ │ │ │ + clear: function() { │ │ │ │ + this.previousStack = []; │ │ │ │ + this.previous.deactivate(); │ │ │ │ + this.nextStack = []; │ │ │ │ + this.next.deactivate(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawLinearRing │ │ │ │ - * Render a linearring │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ + * Method: getState │ │ │ │ + * Get the current state and return it. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * {Object} An object representing the current state. │ │ │ │ */ │ │ │ │ - drawLinearRing: function(node, geometry) { │ │ │ │ - return this.drawLine(node, geometry, true); │ │ │ │ + getState: function() { │ │ │ │ + return { │ │ │ │ + center: this.map.getCenter(), │ │ │ │ + resolution: this.map.getResolution(), │ │ │ │ + projection: this.map.getProjectionObject(), │ │ │ │ + units: this.map.getProjectionObject().getUnits() || │ │ │ │ + this.map.units || this.map.baseLayer.units │ │ │ │ + }; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: DrawLine │ │ │ │ - * Render a line. │ │ │ │ - * │ │ │ │ + * Method: restore │ │ │ │ + * Update the state with the given object. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * closeLine - {Boolean} Close the line? (make it a ring?) │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * state - {Object} An object representing the state to restore. │ │ │ │ */ │ │ │ │ - drawLine: function(node, geometry, closeLine) { │ │ │ │ - │ │ │ │ - this.setNodeDimension(node, geometry); │ │ │ │ - │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var numComponents = geometry.components.length; │ │ │ │ - var parts = new Array(numComponents); │ │ │ │ - │ │ │ │ - var comp, x, y; │ │ │ │ - for (var i = 0; i < numComponents; i++) { │ │ │ │ - comp = geometry.components[i]; │ │ │ │ - x = ((comp.x - this.featureDx) / resolution - this.offset.x) | 0; │ │ │ │ - y = (comp.y / resolution - this.offset.y) | 0; │ │ │ │ - parts[i] = " " + x + "," + y + " l "; │ │ │ │ + restore: function(state) { │ │ │ │ + var center, zoom; │ │ │ │ + if (this.map.getProjectionObject() == state.projection) { │ │ │ │ + zoom = this.map.getZoomForResolution(state.resolution); │ │ │ │ + center = state.center; │ │ │ │ + } else { │ │ │ │ + center = state.center.clone(); │ │ │ │ + center.transform(state.projection, this.map.getProjectionObject()); │ │ │ │ + var sourceUnits = state.units; │ │ │ │ + var targetUnits = this.map.getProjectionObject().getUnits() || │ │ │ │ + this.map.units || this.map.baseLayer.units; │ │ │ │ + var resolutionFactor = sourceUnits && targetUnits ? │ │ │ │ + OpenLayers.INCHES_PER_UNIT[sourceUnits] / OpenLayers.INCHES_PER_UNIT[targetUnits] : 1; │ │ │ │ + zoom = this.map.getZoomForResolution(resolutionFactor * state.resolution); │ │ │ │ } │ │ │ │ - var end = (closeLine) ? " x e" : " e"; │ │ │ │ - node.path = "m" + parts.join("") + end; │ │ │ │ - return node; │ │ │ │ + this.map.setCenter(center, zoom); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawPolygon │ │ │ │ - * Render a polygon │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * Method: setListeners │ │ │ │ + * Sets functions to be registered in the listeners object. │ │ │ │ */ │ │ │ │ - drawPolygon: function(node, geometry) { │ │ │ │ - this.setNodeDimension(node, geometry); │ │ │ │ - │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - │ │ │ │ - var path = []; │ │ │ │ - var j, jj, points, area, first, second, i, ii, comp, pathComp, x, y; │ │ │ │ - for (j = 0, jj = geometry.components.length; j < jj; j++) { │ │ │ │ - path.push("m"); │ │ │ │ - points = geometry.components[j].components; │ │ │ │ - // we only close paths of interior rings with area │ │ │ │ - area = (j === 0); │ │ │ │ - first = null; │ │ │ │ - second = null; │ │ │ │ - for (i = 0, ii = points.length; i < ii; i++) { │ │ │ │ - comp = points[i]; │ │ │ │ - x = ((comp.x - this.featureDx) / resolution - this.offset.x) | 0; │ │ │ │ - y = (comp.y / resolution - this.offset.y) | 0; │ │ │ │ - pathComp = " " + x + "," + y; │ │ │ │ - path.push(pathComp); │ │ │ │ - if (i == 0) { │ │ │ │ - path.push(" l"); │ │ │ │ - } │ │ │ │ - if (!area) { │ │ │ │ - // IE improperly renders sub-paths that have no area. │ │ │ │ - // Instead of checking the area of every ring, we confirm │ │ │ │ - // the ring has at least three distinct points. This does │ │ │ │ - // not catch all non-zero area cases, but it greatly improves │ │ │ │ - // interior ring digitizing and is a minor performance hit │ │ │ │ - // when rendering rings with many points. │ │ │ │ - if (!first) { │ │ │ │ - first = pathComp; │ │ │ │ - } else if (first != pathComp) { │ │ │ │ - if (!second) { │ │ │ │ - second = pathComp; │ │ │ │ - } else if (second != pathComp) { │ │ │ │ - // stop looking │ │ │ │ - area = true; │ │ │ │ - } │ │ │ │ + setListeners: function() { │ │ │ │ + this.listeners = {}; │ │ │ │ + for (var type in this.registry) { │ │ │ │ + this.listeners[type] = OpenLayers.Function.bind(function() { │ │ │ │ + if (!this.restoring) { │ │ │ │ + var state = this.registry[type].apply(this, arguments); │ │ │ │ + this.previousStack.unshift(state); │ │ │ │ + if (this.previousStack.length > 1) { │ │ │ │ + this.onPreviousChange( │ │ │ │ + this.previousStack[1], this.previousStack.length - 1 │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (this.previousStack.length > (this.limit + 1)) { │ │ │ │ + this.previousStack.pop(); │ │ │ │ + } │ │ │ │ + if (this.nextStack.length > 0) { │ │ │ │ + this.nextStack = []; │ │ │ │ + this.onNextChange(null, 0); │ │ │ │ } │ │ │ │ } │ │ │ │ - } │ │ │ │ - path.push(area ? " x " : " "); │ │ │ │ + return true; │ │ │ │ + }, this); │ │ │ │ } │ │ │ │ - path.push("e"); │ │ │ │ - node.path = path.join(""); │ │ │ │ - return node; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawRectangle │ │ │ │ - * Render a rectangle │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the control. This registers any listeners. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - drawRectangle: function(node, geometry) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - │ │ │ │ - node.style.left = (((geometry.x - this.featureDx) / resolution - this.offset.x) | 0) + "px"; │ │ │ │ - node.style.top = ((geometry.y / resolution - this.offset.y) | 0) + "px"; │ │ │ │ - node.style.width = ((geometry.width / resolution) | 0) + "px"; │ │ │ │ - node.style.height = ((geometry.height / resolution) | 0) + "px"; │ │ │ │ - │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: drawText │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * featureId - {String} │ │ │ │ - * style - │ │ │ │ - * location - {<OpenLayers.Geometry.Point>} │ │ │ │ + * {Boolean} Control successfully activated. │ │ │ │ */ │ │ │ │ - drawText: function(featureId, style, location) { │ │ │ │ - var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect"); │ │ │ │ - var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox"); │ │ │ │ - │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - label.style.left = (((location.x - this.featureDx) / resolution - this.offset.x) | 0) + "px"; │ │ │ │ - label.style.top = ((location.y / resolution - this.offset.y) | 0) + "px"; │ │ │ │ - label.style.flip = "y"; │ │ │ │ - │ │ │ │ - textbox.innerText = style.label; │ │ │ │ - │ │ │ │ - if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ - textbox.style.cursor = style.cursor; │ │ │ │ - } │ │ │ │ - if (style.fontColor) { │ │ │ │ - textbox.style.color = style.fontColor; │ │ │ │ - } │ │ │ │ - if (style.fontOpacity) { │ │ │ │ - textbox.style.filter = 'alpha(opacity=' + (style.fontOpacity * 100) + ')'; │ │ │ │ - } │ │ │ │ - if (style.fontFamily) { │ │ │ │ - textbox.style.fontFamily = style.fontFamily; │ │ │ │ - } │ │ │ │ - if (style.fontSize) { │ │ │ │ - textbox.style.fontSize = style.fontSize; │ │ │ │ - } │ │ │ │ - if (style.fontWeight) { │ │ │ │ - textbox.style.fontWeight = style.fontWeight; │ │ │ │ - } │ │ │ │ - if (style.fontStyle) { │ │ │ │ - textbox.style.fontStyle = style.fontStyle; │ │ │ │ - } │ │ │ │ - if (style.labelSelect === true) { │ │ │ │ - label._featureId = featureId; │ │ │ │ - textbox._featureId = featureId; │ │ │ │ - textbox._geometry = location; │ │ │ │ - textbox._geometryClass = location.CLASS_NAME; │ │ │ │ - } │ │ │ │ - textbox.style.whiteSpace = "nowrap"; │ │ │ │ - // fun with IE: IE7 in standards compliant mode does not display any │ │ │ │ - // text with a left inset of 0. So we set this to 1px and subtract one │ │ │ │ - // pixel later when we set label.style.left │ │ │ │ - textbox.inset = "1px,0px,0px,0px"; │ │ │ │ - │ │ │ │ - if (!label.parentNode) { │ │ │ │ - label.appendChild(textbox); │ │ │ │ - this.textRoot.appendChild(label); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var align = style.labelAlign || "cm"; │ │ │ │ - if (align.length == 1) { │ │ │ │ - align += "m"; │ │ │ │ + activate: function() { │ │ │ │ + var activated = false; │ │ │ │ + if (this.map) { │ │ │ │ + if (OpenLayers.Control.prototype.activate.apply(this)) { │ │ │ │ + if (this.listeners == null) { │ │ │ │ + this.setListeners(); │ │ │ │ + } │ │ │ │ + for (var type in this.listeners) { │ │ │ │ + this.map.events.register(type, this, this.listeners[type]); │ │ │ │ + } │ │ │ │ + activated = true; │ │ │ │ + if (this.previousStack.length == 0) { │ │ │ │ + this.initStack(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - var xshift = textbox.clientWidth * │ │ │ │ - (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0, 1)]); │ │ │ │ - var yshift = textbox.clientHeight * │ │ │ │ - (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1, 1)]); │ │ │ │ - label.style.left = parseInt(label.style.left) - xshift - 1 + "px"; │ │ │ │ - label.style.top = parseInt(label.style.top) + yshift + "px"; │ │ │ │ - │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: moveRoot │ │ │ │ - * moves this renderer's root to a different renderer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * renderer - {<OpenLayers.Renderer>} target renderer for the moved root │ │ │ │ - * root - {DOMElement} optional root node. To be used when this renderer │ │ │ │ - * holds roots from multiple layers to tell this method which one to │ │ │ │ - * detach │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} true if successful, false otherwise │ │ │ │ + * Method: initStack │ │ │ │ + * Called after the control is activated if the previous history stack is │ │ │ │ + * empty. │ │ │ │ */ │ │ │ │ - moveRoot: function(renderer) { │ │ │ │ - var layer = this.map.getLayer(renderer.container.id); │ │ │ │ - if (layer instanceof OpenLayers.Layer.Vector.RootContainer) { │ │ │ │ - layer = this.map.getLayer(this.container.id); │ │ │ │ + initStack: function() { │ │ │ │ + if (this.map.getCenter()) { │ │ │ │ + this.listeners.moveend(); │ │ │ │ } │ │ │ │ - layer && layer.renderer.clear(); │ │ │ │ - OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments); │ │ │ │ - layer && layer.redraw(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: importSymbol │ │ │ │ - * add a new symbol definition from the rendererer's symbol hash │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * graphicName - {String} name of the symbol to import │ │ │ │ - * │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the control. This unregisters any listeners. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} - hash of {DOMElement} "symbol" and {Number} "size" │ │ │ │ + * {Boolean} Control successfully deactivated. │ │ │ │ */ │ │ │ │ - importSymbol: function(graphicName) { │ │ │ │ - var id = this.container.id + "-" + graphicName; │ │ │ │ - │ │ │ │ - // check if symbol already exists in the cache │ │ │ │ - var cache = this.symbolCache[id]; │ │ │ │ - if (cache) { │ │ │ │ - return cache; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var symbol = OpenLayers.Renderer.symbol[graphicName]; │ │ │ │ - if (!symbol) { │ │ │ │ - throw new Error(graphicName + ' is not a valid symbol name'); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var symbolExtent = new OpenLayers.Bounds( │ │ │ │ - Number.MAX_VALUE, Number.MAX_VALUE, 0, 0); │ │ │ │ - │ │ │ │ - var pathitems = ["m"]; │ │ │ │ - for (var i = 0; i < symbol.length; i = i + 2) { │ │ │ │ - var x = symbol[i]; │ │ │ │ - var 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); │ │ │ │ - │ │ │ │ - pathitems.push(x); │ │ │ │ - pathitems.push(y); │ │ │ │ - if (i == 0) { │ │ │ │ - pathitems.push("l"); │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = false; │ │ │ │ + if (this.map) { │ │ │ │ + if (OpenLayers.Control.prototype.deactivate.apply(this)) { │ │ │ │ + for (var type in this.listeners) { │ │ │ │ + this.map.events.unregister( │ │ │ │ + type, this, this.listeners[type] │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (this.clearOnDeactivate) { │ │ │ │ + this.clear(); │ │ │ │ + } │ │ │ │ + deactivated = true; │ │ │ │ } │ │ │ │ } │ │ │ │ - pathitems.push("x e"); │ │ │ │ - var path = pathitems.join(" "); │ │ │ │ - │ │ │ │ - var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2; │ │ │ │ - if (diff > 0) { │ │ │ │ - symbolExtent.bottom = symbolExtent.bottom - diff; │ │ │ │ - symbolExtent.top = symbolExtent.top + diff; │ │ │ │ - } else { │ │ │ │ - symbolExtent.left = symbolExtent.left + diff; │ │ │ │ - symbolExtent.right = symbolExtent.right - diff; │ │ │ │ - } │ │ │ │ - │ │ │ │ - cache = { │ │ │ │ - path: path, │ │ │ │ - size: symbolExtent.getWidth(), // equals getHeight() now │ │ │ │ - left: symbolExtent.left, │ │ │ │ - bottom: symbolExtent.bottom │ │ │ │ - }; │ │ │ │ - this.symbolCache[id] = cache; │ │ │ │ - │ │ │ │ - return cache; │ │ │ │ + return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.VML" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.NavigationHistory" │ │ │ │ }); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Renderer.VML.LABEL_SHIFT │ │ │ │ - * {Object} │ │ │ │ - */ │ │ │ │ -OpenLayers.Renderer.VML.LABEL_SHIFT = { │ │ │ │ - "l": 0, │ │ │ │ - "c": .5, │ │ │ │ - "r": 1, │ │ │ │ - "t": 0, │ │ │ │ - "m": .5, │ │ │ │ - "b": 1 │ │ │ │ -}; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Marker/Box.js │ │ │ │ + OpenLayers/Control/CacheWrite.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/Marker.js │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ + * @requires OpenLayers/Console.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Marker.Box │ │ │ │ + * Class: OpenLayers.Control.CacheWrite │ │ │ │ + * A control for caching image tiles in the browser's local storage. The │ │ │ │ + * <OpenLayers.Control.CacheRead> control is used to fetch and use the cached │ │ │ │ + * tile images. │ │ │ │ + * │ │ │ │ + * Note: Before using this control on any layer that is not your own, make sure │ │ │ │ + * that the terms of service of the tile provider allow local storage of tiles. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Marker> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, { │ │ │ │ +OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: bounds │ │ │ │ - * {<OpenLayers.Bounds>} │ │ │ │ + * APIProperty: events │ │ │ │ + * {<OpenLayers.Events>} Events instance for listeners and triggering │ │ │ │ + * control specific events. │ │ │ │ + * │ │ │ │ + * To register events in the constructor, configure <eventListeners>. │ │ │ │ + * │ │ │ │ + * 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>): │ │ │ │ + * cachefull - Triggered when the cache is full. Listeners receive an │ │ │ │ + * object with a tile property as first argument. The tile references │ │ │ │ + * the tile that couldn't be cached. │ │ │ │ */ │ │ │ │ - bounds: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: div │ │ │ │ - * {DOMElement} │ │ │ │ + /** │ │ │ │ + * APIProperty: eventListeners │ │ │ │ + * {Object} Object with event listeners, keyed by event name. An optional │ │ │ │ + * scope property defines the scope that listeners will be executed in. │ │ │ │ */ │ │ │ │ - div: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Marker.Box │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - * borderColor - {String} │ │ │ │ - * borderWidth - {int} │ │ │ │ + /** │ │ │ │ + * APIProperty: layers │ │ │ │ + * {Array(<OpenLayers.Layer.Grid>)}. Optional. If provided, caching │ │ │ │ + * will be enabled for these layers only, otherwise for all cacheable │ │ │ │ + * layers. │ │ │ │ */ │ │ │ │ - initialize: function(bounds, borderColor, borderWidth) { │ │ │ │ - this.bounds = bounds; │ │ │ │ - this.div = OpenLayers.Util.createDiv(); │ │ │ │ - this.div.style.overflow = 'hidden'; │ │ │ │ - this.events = new OpenLayers.Events(this, this.div); │ │ │ │ - this.setBorder(borderColor, borderWidth); │ │ │ │ - }, │ │ │ │ + layers: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroy │ │ │ │ + * APIProperty: imageFormat │ │ │ │ + * {String} The image format used for caching. The default is "image/png". │ │ │ │ + * Supported formats depend on the user agent. If an unsupported │ │ │ │ + * <imageFormat> is provided, "image/png" will be used. For aerial │ │ │ │ + * imagery, "image/jpeg" is recommended. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ + imageFormat: "image/png", │ │ │ │ │ │ │ │ - this.bounds = null; │ │ │ │ - this.div = null; │ │ │ │ + /** │ │ │ │ + * Property: quotaRegEx │ │ │ │ + * {RegExp} │ │ │ │ + */ │ │ │ │ + quotaRegEx: (/quota/i), │ │ │ │ │ │ │ │ - OpenLayers.Marker.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.CacheWrite │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} Object with API properties for this control. │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setBorder │ │ │ │ - * Allow the user to change the box's color and border width │ │ │ │ + * Method: setMap │ │ │ │ + * Set the map property for the control. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * color - {String} Default is "red" │ │ │ │ - * width - {int} Default is 2 │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - setBorder: function(color, width) { │ │ │ │ - if (!color) { │ │ │ │ - color = "red"; │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + var i, layers = this.layers || map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.addLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ + }); │ │ │ │ } │ │ │ │ - if (!width) { │ │ │ │ - width = 2; │ │ │ │ + if (!this.layers) { │ │ │ │ + map.events.on({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ } │ │ │ │ - this.div.style.border = width + "px solid " + color; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: addLayer │ │ │ │ + * Adds a layer to the control. Once added, tiles requested for this layer │ │ │ │ + * will be cached. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * px - {<OpenLayers.Pixel>} │ │ │ │ - * sz - {<OpenLayers.Size>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A new DOM Image with this marker's icon set at the │ │ │ │ - * location passed-in │ │ │ │ + * evt - {Object} Object with a layer property referencing an │ │ │ │ + * <OpenLayers.Layer> instance │ │ │ │ */ │ │ │ │ - draw: function(px, sz) { │ │ │ │ - OpenLayers.Util.modifyDOMElement(this.div, null, px, sz); │ │ │ │ - return this.div; │ │ │ │ + addLayer: function(evt) { │ │ │ │ + evt.layer.events.on({ │ │ │ │ + tileloadstart: this.makeSameOrigin, │ │ │ │ + tileloaded: this.onTileLoaded, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onScreen │ │ │ │ - * │ │ │ │ - * Rreturn: │ │ │ │ - * {Boolean} Whether or not the marker is currently visible on screen. │ │ │ │ + * Method: removeLayer │ │ │ │ + * Removes a layer from the control. Once removed, tiles requested for this │ │ │ │ + * layer will no longer be cached. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Object} Object with a layer property referencing an │ │ │ │ + * <OpenLayers.Layer> instance │ │ │ │ */ │ │ │ │ - onScreen: function() { │ │ │ │ - var onScreen = false; │ │ │ │ - if (this.map) { │ │ │ │ - var screenBounds = this.map.getExtent(); │ │ │ │ - onScreen = screenBounds.containsBounds(this.bounds, true, true); │ │ │ │ - } │ │ │ │ - return onScreen; │ │ │ │ + removeLayer: function(evt) { │ │ │ │ + evt.layer.events.un({ │ │ │ │ + tileloadstart: this.makeSameOrigin, │ │ │ │ + tileloaded: this.onTileLoaded, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: display │ │ │ │ - * Hide or show the icon │ │ │ │ - * │ │ │ │ + * Method: makeSameOrigin │ │ │ │ + * If the tile does not have CORS image loading enabled and is from a │ │ │ │ + * different origin, use OpenLayers.ProxyHost to make it a same origin url. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * display - {Boolean} │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ */ │ │ │ │ - display: function(display) { │ │ │ │ - this.div.style.display = (display) ? "" : "none"; │ │ │ │ + makeSameOrigin: function(evt) { │ │ │ │ + if (this.active) { │ │ │ │ + var tile = evt.tile; │ │ │ │ + if (tile instanceof OpenLayers.Tile.Image && │ │ │ │ + !tile.crossOriginKeyword && │ │ │ │ + tile.url.substr(0, 5) !== "data:") { │ │ │ │ + var sameOriginUrl = OpenLayers.Request.makeSameOrigin( │ │ │ │ + tile.url, OpenLayers.ProxyHost │ │ │ │ + ); │ │ │ │ + OpenLayers.Control.CacheWrite.urlMap[sameOriginUrl] = tile.url; │ │ │ │ + tile.url = sameOriginUrl; │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Marker.Box" │ │ │ │ -}); │ │ │ │ - │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/QueryStringFilter.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/Console.js │ │ │ │ - * @requires OpenLayers/Format.js │ │ │ │ - * @requires OpenLayers/Filter/Spatial.js │ │ │ │ - * @requires OpenLayers/Filter/Comparison.js │ │ │ │ - * @requires OpenLayers/Filter/Logical.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.QueryStringFilter │ │ │ │ - * Parser for reading a query string and creating a simple filter. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.QueryStringFilter = (function() { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Map the OpenLayers.Filter.Comparison types to the operation strings of │ │ │ │ - * the protocol. │ │ │ │ + /** │ │ │ │ + * Method: onTileLoaded │ │ │ │ + * Decides whether a tile can be cached and calls the cache method. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - var cmpToStr = {}; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.EQUAL_TO] = "eq"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.NOT_EQUAL_TO] = "ne"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN] = "lt"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO] = "lte"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN] = "gt"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO] = "gte"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.LIKE] = "ilike"; │ │ │ │ + onTileLoaded: function(evt) { │ │ │ │ + if (this.active && !evt.aborted && │ │ │ │ + evt.tile instanceof OpenLayers.Tile.Image && │ │ │ │ + evt.tile.url.substr(0, 5) !== 'data:') { │ │ │ │ + this.cache({ │ │ │ │ + tile: evt.tile │ │ │ │ + }); │ │ │ │ + delete OpenLayers.Control.CacheWrite.urlMap[evt.tile.url]; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Function: regex2value │ │ │ │ - * Convert the value from a regular expression string to a LIKE/ILIKE │ │ │ │ - * string known to the web service. │ │ │ │ + * Method: cache │ │ │ │ + * Adds a tile to the cache. When the cache is full, the "cachefull" event │ │ │ │ + * is triggered. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * value - {String} The regex string. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} The converted string. │ │ │ │ + * obj - {Object} Object with a tile property, tile being the │ │ │ │ + * <OpenLayers.Tile.Image> with the data to add to the cache │ │ │ │ */ │ │ │ │ - function regex2value(value) { │ │ │ │ - │ │ │ │ - // highly sensitive!! Do not change this without running the │ │ │ │ - // Protocol/HTTP.html unit tests │ │ │ │ - │ │ │ │ - // convert % to \% │ │ │ │ - value = value.replace(/%/g, "\\%"); │ │ │ │ - │ │ │ │ - // convert \\. to \\_ (\\.* occurences converted later) │ │ │ │ - value = value.replace(/\\\\\.(\*)?/g, function($0, $1) { │ │ │ │ - return $1 ? $0 : "\\\\_"; │ │ │ │ - }); │ │ │ │ - │ │ │ │ - // convert \\.* to \\% │ │ │ │ - value = value.replace(/\\\\\.\*/g, "\\\\%"); │ │ │ │ - │ │ │ │ - // convert . to _ (\. and .* occurences converted later) │ │ │ │ - value = value.replace(/(\\)?\.(\*)?/g, function($0, $1, $2) { │ │ │ │ - return $1 || $2 ? $0 : "_"; │ │ │ │ - }); │ │ │ │ - │ │ │ │ - // convert .* to % (\.* occurnces converted later) │ │ │ │ - value = value.replace(/(\\)?\.\*/g, function($0, $1) { │ │ │ │ - return $1 ? $0 : "%"; │ │ │ │ - }); │ │ │ │ + cache: function(obj) { │ │ │ │ + if (window.localStorage) { │ │ │ │ + var tile = obj.tile; │ │ │ │ + try { │ │ │ │ + var canvasContext = tile.getCanvasContext(); │ │ │ │ + if (canvasContext) { │ │ │ │ + var urlMap = OpenLayers.Control.CacheWrite.urlMap; │ │ │ │ + var url = urlMap[tile.url] || tile.url; │ │ │ │ + window.localStorage.setItem( │ │ │ │ + "olCache_" + url, │ │ │ │ + canvasContext.canvas.toDataURL(this.imageFormat) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } catch (e) { │ │ │ │ + // local storage full or CORS violation │ │ │ │ + var reason = e.name || e.message; │ │ │ │ + if (reason && this.quotaRegEx.test(reason)) { │ │ │ │ + this.events.triggerEvent("cachefull", { │ │ │ │ + tile: tile │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + OpenLayers.Console.error(e.toString()); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - // convert \. to . │ │ │ │ - value = value.replace(/\\\./g, "."); │ │ │ │ + /** │ │ │ │ + * 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.layers || this.map) { │ │ │ │ + var i, layers = this.layers || this.map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.removeLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.un({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ - // replace \* with * (watching out for \\*) │ │ │ │ - value = value.replace(/(\\)?\\\*/g, function($0, $1) { │ │ │ │ - return $1 ? $0 : "*"; │ │ │ │ - }); │ │ │ │ + CLASS_NAME: "OpenLayers.Control.CacheWrite" │ │ │ │ +}); │ │ │ │ │ │ │ │ - return value; │ │ │ │ +/** │ │ │ │ + * APIFunction: OpenLayers.Control.CacheWrite.clearCache │ │ │ │ + * Clears all tiles cached with <OpenLayers.Control.CacheWrite> from the cache. │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.CacheWrite.clearCache = function() { │ │ │ │ + if (!window.localStorage) { │ │ │ │ + return; │ │ │ │ } │ │ │ │ + var i, key; │ │ │ │ + for (i = window.localStorage.length - 1; i >= 0; --i) { │ │ │ │ + key = window.localStorage.key(i); │ │ │ │ + if (key.substr(0, 8) === "olCache_") { │ │ │ │ + window.localStorage.removeItem(key); │ │ │ │ + } │ │ │ │ + } │ │ │ │ +}; │ │ │ │ │ │ │ │ - return OpenLayers.Class(OpenLayers.Format, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Serialize an <OpenLayers.Filter> objects using the "simple" filter syntax for │ │ │ │ - * query string parameters. This function must be called as a method of │ │ │ │ - * a protocol instance. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * filter - {<OpenLayers.Filter>} filter to convert. │ │ │ │ - * params - {Object} The parameters object. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} The resulting parameters object. │ │ │ │ - */ │ │ │ │ - write: function(filter, params) { │ │ │ │ - params = params || {}; │ │ │ │ - var className = filter.CLASS_NAME; │ │ │ │ - var filterType = className.substring(className.lastIndexOf(".") + 1); │ │ │ │ - switch (filterType) { │ │ │ │ - case "Spatial": │ │ │ │ - switch (filter.type) { │ │ │ │ - case OpenLayers.Filter.Spatial.BBOX: │ │ │ │ - params.bbox = filter.value.toArray(); │ │ │ │ - if (this.srsInBBOX && filter.projection) { │ │ │ │ - params.bbox.push(filter.projection.getCode()); │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case OpenLayers.Filter.Spatial.DWITHIN: │ │ │ │ - params.tolerance = filter.distance; │ │ │ │ - // no break here │ │ │ │ - case OpenLayers.Filter.Spatial.WITHIN: │ │ │ │ - params.lon = filter.value.x; │ │ │ │ - params.lat = filter.value.y; │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - OpenLayers.Console.warn( │ │ │ │ - "Unknown spatial filter type " + filter.type); │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "Comparison": │ │ │ │ - var op = cmpToStr[filter.type]; │ │ │ │ - if (op !== undefined) { │ │ │ │ - var value = filter.value; │ │ │ │ - if (filter.type == OpenLayers.Filter.Comparison.LIKE) { │ │ │ │ - value = regex2value(value); │ │ │ │ - if (this.wildcarded) { │ │ │ │ - value = "%" + value + "%"; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - params[filter.property + "__" + op] = value; │ │ │ │ - params.queryable = params.queryable || []; │ │ │ │ - params.queryable.push(filter.property); │ │ │ │ - } else { │ │ │ │ - OpenLayers.Console.warn( │ │ │ │ - "Unknown comparison filter type " + filter.type); │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "Logical": │ │ │ │ - if (filter.type === OpenLayers.Filter.Logical.AND) { │ │ │ │ - for (var i = 0, len = filter.filters.length; i < len; i++) { │ │ │ │ - params = this.write(filter.filters[i], params); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Console.warn( │ │ │ │ - "Unsupported logical filter type " + filter.type); │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - OpenLayers.Console.warn("Unknown filter type " + filterType); │ │ │ │ - } │ │ │ │ - return params; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.QueryStringFilter" │ │ │ │ - │ │ │ │ - }); │ │ │ │ +/** │ │ │ │ + * Property: OpenLayers.Control.CacheWrite.urlMap │ │ │ │ + * {Object} Mapping of same origin urls to cache url keys. Entries will be │ │ │ │ + * deleted as soon as a tile was cached. │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.CacheWrite.urlMap = {}; │ │ │ │ │ │ │ │ │ │ │ │ -})(); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Format/WFSDescribeFeatureType.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 │ │ │ │ @@ -70780,512 +73054,14 @@ │ │ │ │ return schema; │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.WFSDescribeFeatureType" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/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/Format/GML.js │ │ │ │ - * @requires OpenLayers/Console.js │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WFS │ │ │ │ - * Read/Write WFS. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.GML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WFS = OpenLayers.Class(OpenLayers.Format.GML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: layer │ │ │ │ - * {<OpenLayers.Layer>} │ │ │ │ - */ │ │ │ │ - layer: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: wfsns │ │ │ │ - * {String} │ │ │ │ - */ │ │ │ │ - wfsns: "http://www.opengis.net/wfs", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: ogcns │ │ │ │ - * {String} │ │ │ │ - */ │ │ │ │ - ogcns: "http://www.opengis.net/ogc", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WFS │ │ │ │ - * Create a WFS-T formatter. This requires a layer: that layer should │ │ │ │ - * have two properties: geometry_column and typename. The parser │ │ │ │ - * for this format is subclassed entirely from GML: There is a writer │ │ │ │ - * only, which uses most of the code from the GML layer, and wraps │ │ │ │ - * it in transactional elements. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ - * layer - {<OpenLayers.Layer>} │ │ │ │ - */ │ │ │ │ - initialize: function(options, layer) { │ │ │ │ - OpenLayers.Format.GML.prototype.initialize.apply(this, [options]); │ │ │ │ - this.layer = layer; │ │ │ │ - if (this.layer.featureNS) { │ │ │ │ - this.featureNS = this.layer.featureNS; │ │ │ │ - } │ │ │ │ - if (this.layer.options.geometry_column) { │ │ │ │ - this.geometryName = this.layer.options.geometry_column; │ │ │ │ - } │ │ │ │ - if (this.layer.options.typename) { │ │ │ │ - this.featureName = this.layer.options.typename; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: write │ │ │ │ - * Takes a feature list, and generates a WFS-T Transaction │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ - */ │ │ │ │ - write: function(features) { │ │ │ │ - │ │ │ │ - var transaction = this.createElementNS(this.wfsns, 'wfs:Transaction'); │ │ │ │ - transaction.setAttribute("version", "1.0.0"); │ │ │ │ - transaction.setAttribute("service", "WFS"); │ │ │ │ - for (var i = 0; i < features.length; i++) { │ │ │ │ - switch (features[i].state) { │ │ │ │ - case OpenLayers.State.INSERT: │ │ │ │ - transaction.appendChild(this.insert(features[i])); │ │ │ │ - break; │ │ │ │ - case OpenLayers.State.UPDATE: │ │ │ │ - transaction.appendChild(this.update(features[i])); │ │ │ │ - break; │ │ │ │ - case OpenLayers.State.DELETE: │ │ │ │ - transaction.appendChild(this.remove(features[i])); │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [transaction]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: createFeatureXML │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - createFeatureXML: function(feature) { │ │ │ │ - var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ - var geomContainer = this.createElementNS(this.featureNS, "feature:" + this.geometryName); │ │ │ │ - geomContainer.appendChild(geometryNode); │ │ │ │ - var featureContainer = this.createElementNS(this.featureNS, "feature:" + this.featureName); │ │ │ │ - featureContainer.appendChild(geomContainer); │ │ │ │ - for (var attr in feature.attributes) { │ │ │ │ - var attrText = this.createTextNode(feature.attributes[attr]); │ │ │ │ - var nodename = attr; │ │ │ │ - if (attr.search(":") != -1) { │ │ │ │ - nodename = attr.split(":")[1]; │ │ │ │ - } │ │ │ │ - var attrContainer = this.createElementNS(this.featureNS, "feature:" + nodename); │ │ │ │ - attrContainer.appendChild(attrText); │ │ │ │ - featureContainer.appendChild(attrContainer); │ │ │ │ - } │ │ │ │ - return featureContainer; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: insert │ │ │ │ - * Takes a feature, and generates a WFS-T Transaction "Insert" │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - insert: function(feature) { │ │ │ │ - var insertNode = this.createElementNS(this.wfsns, 'wfs:Insert'); │ │ │ │ - insertNode.appendChild(this.createFeatureXML(feature)); │ │ │ │ - return insertNode; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: update │ │ │ │ - * Takes a feature, and generates a WFS-T Transaction "Update" │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - update: function(feature) { │ │ │ │ - if (!feature.fid) { │ │ │ │ - OpenLayers.Console.userError(OpenLayers.i18n("noFID")); │ │ │ │ - } │ │ │ │ - var updateNode = this.createElementNS(this.wfsns, 'wfs:Update'); │ │ │ │ - updateNode.setAttribute("typeName", this.featurePrefix + ':' + this.featureName); │ │ │ │ - updateNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ - │ │ │ │ - var propertyNode = this.createElementNS(this.wfsns, 'wfs:Property'); │ │ │ │ - var nameNode = this.createElementNS(this.wfsns, 'wfs:Name'); │ │ │ │ - │ │ │ │ - var txtNode = this.createTextNode(this.geometryName); │ │ │ │ - nameNode.appendChild(txtNode); │ │ │ │ - propertyNode.appendChild(nameNode); │ │ │ │ - │ │ │ │ - var valueNode = this.createElementNS(this.wfsns, 'wfs:Value'); │ │ │ │ - │ │ │ │ - var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ - │ │ │ │ - if (feature.layer) { │ │ │ │ - geometryNode.setAttribute( │ │ │ │ - "srsName", feature.layer.projection.getCode() │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - │ │ │ │ - valueNode.appendChild(geometryNode); │ │ │ │ - │ │ │ │ - propertyNode.appendChild(valueNode); │ │ │ │ - updateNode.appendChild(propertyNode); │ │ │ │ - │ │ │ │ - // add in attributes │ │ │ │ - for (var propName in feature.attributes) { │ │ │ │ - propertyNode = this.createElementNS(this.wfsns, 'wfs:Property'); │ │ │ │ - nameNode = this.createElementNS(this.wfsns, 'wfs:Name'); │ │ │ │ - nameNode.appendChild(this.createTextNode(propName)); │ │ │ │ - propertyNode.appendChild(nameNode); │ │ │ │ - valueNode = this.createElementNS(this.wfsns, 'wfs:Value'); │ │ │ │ - valueNode.appendChild(this.createTextNode(feature.attributes[propName])); │ │ │ │ - propertyNode.appendChild(valueNode); │ │ │ │ - updateNode.appendChild(propertyNode); │ │ │ │ - } │ │ │ │ - │ │ │ │ - │ │ │ │ - var filterNode = this.createElementNS(this.ogcns, 'ogc:Filter'); │ │ │ │ - var filterIdNode = this.createElementNS(this.ogcns, 'ogc:FeatureId'); │ │ │ │ - filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ - filterNode.appendChild(filterIdNode); │ │ │ │ - updateNode.appendChild(filterNode); │ │ │ │ - │ │ │ │ - return updateNode; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: remove │ │ │ │ - * Takes a feature, and generates a WFS-T Transaction "Delete" │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - remove: function(feature) { │ │ │ │ - if (!feature.fid) { │ │ │ │ - OpenLayers.Console.userError(OpenLayers.i18n("noFID")); │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ - var deleteNode = this.createElementNS(this.wfsns, 'wfs:Delete'); │ │ │ │ - deleteNode.setAttribute("typeName", this.featurePrefix + ':' + this.featureName); │ │ │ │ - deleteNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ - │ │ │ │ - var filterNode = this.createElementNS(this.ogcns, 'ogc:Filter'); │ │ │ │ - var filterIdNode = this.createElementNS(this.ogcns, 'ogc:FeatureId'); │ │ │ │ - filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ - filterNode.appendChild(filterIdNode); │ │ │ │ - deleteNode.appendChild(filterNode); │ │ │ │ - │ │ │ │ - return deleteNode; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Remove ciruclar ref to layer │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - this.layer = null; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFS" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMTSCapabilities.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 │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMTSCapabilities │ │ │ │ - * Read WMTS Capabilities. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMTSCapabilities = 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", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: yx │ │ │ │ - * {Object} Members in the yx object are used to determine if a CRS URN │ │ │ │ - * corresponds to a CRS with y,x axis order. Member names are CRS URNs │ │ │ │ - * and values are boolean. By default, the following CRS URN are │ │ │ │ - * assumed to correspond to a CRS with y,x axis order: │ │ │ │ - * │ │ │ │ - * * urn:ogc:def:crs:EPSG::4326 │ │ │ │ - */ │ │ │ │ - yx: { │ │ │ │ - "urn:ogc:def:crs:EPSG::4326": true │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WMTSCapabilities │ │ │ │ - * Create a new parser for WMTS capabilities. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return information about │ │ │ │ - * the service (offering and observedProperty mostly). │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} Info about the WMTS Capabilities │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: createLayer │ │ │ │ - * Create a WMTS layer given a capabilities object. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * capabilities - {Object} The object returned from a <read> call to this │ │ │ │ - * format. │ │ │ │ - * config - {Object} Configuration properties for the layer. Defaults for │ │ │ │ - * the layer will apply if not provided. │ │ │ │ - * │ │ │ │ - * Required config properties: │ │ │ │ - * layer - {String} The layer identifier. │ │ │ │ - * │ │ │ │ - * Optional config properties: │ │ │ │ - * matrixSet - {String} The matrix set identifier, required if there is │ │ │ │ - * more than one matrix set in the layer capabilities. │ │ │ │ - * style - {String} The name of the style │ │ │ │ - * format - {String} Image format for the layer. Default is the first │ │ │ │ - * format returned in the GetCapabilities response. │ │ │ │ - * param - {Object} The dimensions values eg: {"Year": "2012"} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.WMTS>} A properly configured WMTS layer. Throws an │ │ │ │ - * error if an incomplete config is provided. Returns undefined if no │ │ │ │ - * layer could be created with the provided config. │ │ │ │ - */ │ │ │ │ - createLayer: function(capabilities, config) { │ │ │ │ - var layer; │ │ │ │ - │ │ │ │ - // confirm required properties are supplied in config │ │ │ │ - if (!('layer' in config)) { │ │ │ │ - throw new Error("Missing property 'layer' in configuration."); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var contents = capabilities.contents; │ │ │ │ - │ │ │ │ - // find the layer definition with the given identifier │ │ │ │ - var layers = contents.layers; │ │ │ │ - var layerDef; │ │ │ │ - for (var i = 0, ii = contents.layers.length; i < ii; ++i) { │ │ │ │ - if (contents.layers[i].identifier === config.layer) { │ │ │ │ - layerDef = contents.layers[i]; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (!layerDef) { │ │ │ │ - throw new Error("Layer not found"); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var format = config.format; │ │ │ │ - if (!format && layerDef.formats && layerDef.formats.length) { │ │ │ │ - format = layerDef.formats[0]; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // find the matrixSet definition │ │ │ │ - var matrixSet; │ │ │ │ - if (config.matrixSet) { │ │ │ │ - matrixSet = contents.tileMatrixSets[config.matrixSet]; │ │ │ │ - } else if (layerDef.tileMatrixSetLinks.length >= 1) { │ │ │ │ - matrixSet = contents.tileMatrixSets[ │ │ │ │ - layerDef.tileMatrixSetLinks[0].tileMatrixSet]; │ │ │ │ - } │ │ │ │ - if (!matrixSet) { │ │ │ │ - throw new Error("matrixSet not found"); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // get the default style for the layer │ │ │ │ - var style; │ │ │ │ - for (var i = 0, ii = layerDef.styles.length; i < ii; ++i) { │ │ │ │ - style = layerDef.styles[i]; │ │ │ │ - if (style.isDefault) { │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - var requestEncoding = config.requestEncoding; │ │ │ │ - if (!requestEncoding) { │ │ │ │ - requestEncoding = "KVP"; │ │ │ │ - if (capabilities.operationsMetadata.GetTile.dcp.http) { │ │ │ │ - var http = capabilities.operationsMetadata.GetTile.dcp.http; │ │ │ │ - // Get first get method │ │ │ │ - if (http.get[0].constraints) { │ │ │ │ - var constraints = http.get[0].constraints; │ │ │ │ - var allowedValues = constraints.GetEncoding.allowedValues; │ │ │ │ - │ │ │ │ - // The OGC documentation is not clear if we should use │ │ │ │ - // REST or RESTful, ArcGis use RESTful, │ │ │ │ - // and OpenLayers use REST. │ │ │ │ - if (!allowedValues.KVP && │ │ │ │ - (allowedValues.REST || allowedValues.RESTful)) { │ │ │ │ - requestEncoding = "REST"; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - var dimensions = []; │ │ │ │ - var params = config.params || {}; │ │ │ │ - // to don't overwrite the changes in the applyDefaults │ │ │ │ - delete config.params; │ │ │ │ - for (var id = 0, ld = layerDef.dimensions.length; id < ld; id++) { │ │ │ │ - var dimension = layerDef.dimensions[id]; │ │ │ │ - dimensions.push(dimension.identifier); │ │ │ │ - if (!params.hasOwnProperty(dimension.identifier)) { │ │ │ │ - params[dimension.identifier] = dimension['default']; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - var projection = config.projection || matrixSet.supportedCRS.replace( │ │ │ │ - /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, "$1:$3"); │ │ │ │ - var units = config.units || │ │ │ │ - (projection === "EPSG:4326" ? "degrees" : "m"); │ │ │ │ - │ │ │ │ - var resolutions = []; │ │ │ │ - for (var mid in matrixSet.matrixIds) { │ │ │ │ - if (matrixSet.matrixIds.hasOwnProperty(mid)) { │ │ │ │ - resolutions.push( │ │ │ │ - matrixSet.matrixIds[mid].scaleDenominator * 0.28E-3 / │ │ │ │ - OpenLayers.METERS_PER_INCH / │ │ │ │ - OpenLayers.INCHES_PER_UNIT[units]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - var url; │ │ │ │ - if (requestEncoding === "REST" && layerDef.resourceUrls) { │ │ │ │ - url = []; │ │ │ │ - var resourceUrls = layerDef.resourceUrls, │ │ │ │ - resourceUrl; │ │ │ │ - for (var t = 0, tt = layerDef.resourceUrls.length; t < tt; ++t) { │ │ │ │ - resourceUrl = layerDef.resourceUrls[t]; │ │ │ │ - if (resourceUrl.format === format && resourceUrl.resourceType === "tile") { │ │ │ │ - url.push(resourceUrl.template); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - var httpGet = capabilities.operationsMetadata.GetTile.dcp.http.get; │ │ │ │ - url = []; │ │ │ │ - var constraint; │ │ │ │ - for (var i = 0, ii = httpGet.length; i < ii; i++) { │ │ │ │ - constraint = httpGet[i].constraints; │ │ │ │ - if (!constraint || (constraint && constraint.GetEncoding.allowedValues[requestEncoding])) { │ │ │ │ - url.push(httpGet[i].url); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return new OpenLayers.Layer.WMTS( │ │ │ │ - OpenLayers.Util.applyDefaults(config, { │ │ │ │ - url: url, │ │ │ │ - requestEncoding: requestEncoding, │ │ │ │ - name: layerDef.title, │ │ │ │ - style: style.identifier, │ │ │ │ - format: format, │ │ │ │ - matrixIds: matrixSet.matrixIds, │ │ │ │ - matrixSet: matrixSet.identifier, │ │ │ │ - projection: projection, │ │ │ │ - units: units, │ │ │ │ - resolutions: config.isBaseLayer === false ? undefined : resolutions, │ │ │ │ - serverResolutions: resolutions, │ │ │ │ - tileFullExtent: matrixSet.bounds, │ │ │ │ - dimensions: dimensions, │ │ │ │ - params: params │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMTSCapabilities" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/CSWGetRecords.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.CSWGetRecords │ │ │ │ - * Default version is 2.0.2. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Format>} A CSWGetRecords format of the given version. │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.CSWGetRecords = function(options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults( │ │ │ │ - options, OpenLayers.Format.CSWGetRecords.DEFAULTS │ │ │ │ - ); │ │ │ │ - var cls = OpenLayers.Format.CSWGetRecords["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (!cls) { │ │ │ │ - throw "Unsupported CSWGetRecords version: " + options.version; │ │ │ │ - } │ │ │ │ - return new cls(options); │ │ │ │ -}; │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: DEFAULTS │ │ │ │ - * {Object} Default properties for the CSWGetRecords format. │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.CSWGetRecords.DEFAULTS = { │ │ │ │ - "version": "2.0.2" │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ OpenLayers/Format/Context.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. */ │ │ │ │ @@ -71618,538 +73394,1267 @@ │ │ │ │ "WCS": "urn:ogc:serviceType:WCS", │ │ │ │ "GML": "urn:ogc:serviceType:GML", │ │ │ │ "SLD": "urn:ogc:serviceType:SLD", │ │ │ │ "FES": "urn:ogc:serviceType:FES", │ │ │ │ "KML": "urn:ogc:serviceType:KML" │ │ │ │ }; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/SOSGetFeatureOfInterest.js │ │ │ │ + OpenLayers/Format/WMC.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/v3.js │ │ │ │ + * @requires OpenLayers/Format/Context.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.SOSGetFeatureOfInterest │ │ │ │ - * Read and write SOS GetFeatureOfInterest. This is used to get to │ │ │ │ - * the location of the features (stations). The stations can have 1 or more │ │ │ │ - * sensors. │ │ │ │ + * Class: OpenLayers.Format.WMC │ │ │ │ + * Read and write Web Map Context documents. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ + * - <OpenLayers.Format.Context> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.SOSGetFeatureOfInterest = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.XML, { │ │ │ │ +OpenLayers.Format.WMC = OpenLayers.Class(OpenLayers.Format.Context, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: VERSION │ │ │ │ - * {String} 1.0.0 │ │ │ │ - */ │ │ │ │ - VERSION: "1.0.0", │ │ │ │ + /** │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "1.1.0". │ │ │ │ + */ │ │ │ │ + defaultVersion: "1.1.0", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - sos: "http://www.opengis.net/sos/1.0", │ │ │ │ - gml: "http://www.opengis.net/gml", │ │ │ │ - sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMC │ │ │ │ + * Create a new parser for Web Map Context documents. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} Schema location │ │ │ │ - */ │ │ │ │ - schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosAll.xsd", │ │ │ │ + /** │ │ │ │ + * Method: layerToContext │ │ │ │ + * Create a layer context object given a wms layer object. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.WMS>} The layer. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} A layer context object. │ │ │ │ + */ │ │ │ │ + layerToContext: function(layer) { │ │ │ │ + var parser = this.getParser(); │ │ │ │ + var layerContext = { │ │ │ │ + queryable: layer.queryable, │ │ │ │ + visibility: layer.visibility, │ │ │ │ + name: layer.params["LAYERS"], │ │ │ │ + title: layer.name, │ │ │ │ + "abstract": layer.metadata["abstract"], │ │ │ │ + dataURL: layer.metadata.dataURL, │ │ │ │ + metadataURL: layer.metadataURL, │ │ │ │ + server: { │ │ │ │ + version: layer.params["VERSION"], │ │ │ │ + url: layer.url │ │ │ │ + }, │ │ │ │ + maxExtent: layer.maxExtent, │ │ │ │ + transparent: layer.params["TRANSPARENT"], │ │ │ │ + numZoomLevels: layer.numZoomLevels, │ │ │ │ + units: layer.units, │ │ │ │ + isBaseLayer: layer.isBaseLayer, │ │ │ │ + opacity: layer.opacity == 1 ? undefined : layer.opacity, │ │ │ │ + displayInLayerSwitcher: layer.displayInLayerSwitcher, │ │ │ │ + singleTile: layer.singleTile, │ │ │ │ + tileSize: (layer.singleTile || !layer.tileSize) ? │ │ │ │ + undefined : { │ │ │ │ + width: layer.tileSize.w, │ │ │ │ + height: layer.tileSize.h │ │ │ │ + }, │ │ │ │ + minScale: (layer.options.resolutions || │ │ │ │ + layer.options.scales || │ │ │ │ + layer.options.maxResolution || │ │ │ │ + layer.options.minScale) ? │ │ │ │ + layer.minScale : undefined, │ │ │ │ + maxScale: (layer.options.resolutions || │ │ │ │ + layer.options.scales || │ │ │ │ + layer.options.minResolution || │ │ │ │ + layer.options.maxScale) ? │ │ │ │ + layer.maxScale : undefined, │ │ │ │ + formats: [], │ │ │ │ + styles: [], │ │ │ │ + srs: layer.srs, │ │ │ │ + dimensions: layer.dimensions │ │ │ │ + }; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ - */ │ │ │ │ - defaultPrefix: "sos", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ - */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ - }, │ │ │ │ + if (layer.metadata.servertitle) { │ │ │ │ + layerContext.server.title = layer.metadata.servertitle; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.SOSGetFeatureOfInterest │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ + if (layer.metadata.formats && layer.metadata.formats.length > 0) { │ │ │ │ + for (var i = 0, len = layer.metadata.formats.length; i < len; i++) { │ │ │ │ + var format = layer.metadata.formats[i]; │ │ │ │ + layerContext.formats.push({ │ │ │ │ + value: format.value, │ │ │ │ + current: (format.value == layer.params["FORMAT"]) │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + layerContext.formats.push({ │ │ │ │ + value: layer.params["FORMAT"], │ │ │ │ + current: true │ │ │ │ + }); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Parse a GetFeatureOfInterest response and return an array 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]); │ │ │ │ + if (layer.metadata.styles && layer.metadata.styles.length > 0) { │ │ │ │ + for (var i = 0, len = layer.metadata.styles.length; i < len; i++) { │ │ │ │ + var style = layer.metadata.styles[i]; │ │ │ │ + if ((style.href == layer.params["SLD"]) || │ │ │ │ + (style.body == layer.params["SLD_BODY"]) || │ │ │ │ + (style.name == layer.params["STYLES"])) { │ │ │ │ + style.current = true; │ │ │ │ + } else { │ │ │ │ + style.current = false; │ │ │ │ + } │ │ │ │ + layerContext.styles.push(style); │ │ │ │ } │ │ │ │ - if (data && data.nodeType == 9) { │ │ │ │ - data = data.documentElement; │ │ │ │ + } else { │ │ │ │ + layerContext.styles.push({ │ │ │ │ + href: layer.params["SLD"], │ │ │ │ + body: layer.params["SLD_BODY"], │ │ │ │ + name: layer.params["STYLES"] || parser.defaultStyleName, │ │ │ │ + title: parser.defaultStyleTitle, │ │ │ │ + current: true │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return layerContext; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: toContext │ │ │ │ + * Create a context object free from layer given a map or a │ │ │ │ + * context object. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {<OpenLayers.Map> | Object} The map or context. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} A context object. │ │ │ │ + */ │ │ │ │ + toContext: function(obj) { │ │ │ │ + var context = {}; │ │ │ │ + var layers = obj.layers; │ │ │ │ + if (obj.CLASS_NAME == "OpenLayers.Map") { │ │ │ │ + var metadata = obj.metadata || {}; │ │ │ │ + context.size = obj.getSize(); │ │ │ │ + context.bounds = obj.getExtent(); │ │ │ │ + context.projection = obj.projection; │ │ │ │ + context.title = obj.title; │ │ │ │ + context.keywords = metadata.keywords; │ │ │ │ + context["abstract"] = metadata["abstract"]; │ │ │ │ + context.logo = metadata.logo; │ │ │ │ + context.descriptionURL = metadata.descriptionURL; │ │ │ │ + context.contactInformation = metadata.contactInformation; │ │ │ │ + context.maxExtent = obj.maxExtent; │ │ │ │ + } else { │ │ │ │ + // copy all obj properties except the "layers" property │ │ │ │ + OpenLayers.Util.applyDefaults(context, obj); │ │ │ │ + if (context.layers != undefined) { │ │ │ │ + delete(context.layers); │ │ │ │ } │ │ │ │ + } │ │ │ │ │ │ │ │ - var info = { │ │ │ │ - features: [] │ │ │ │ - }; │ │ │ │ - this.readNode(data, info); │ │ │ │ + if (context.layersContext == undefined) { │ │ │ │ + context.layersContext = []; │ │ │ │ + } │ │ │ │ │ │ │ │ - var features = []; │ │ │ │ - for (var i = 0, len = info.features.length; i < len; i++) { │ │ │ │ - var container = info.features[i]; │ │ │ │ - // reproject features if needed │ │ │ │ - if (this.internalProjection && this.externalProjection && │ │ │ │ - container.components[0]) { │ │ │ │ - container.components[0].transform( │ │ │ │ - this.externalProjection, this.internalProjection │ │ │ │ - ); │ │ │ │ + // let's convert layers into layersContext object (if any) │ │ │ │ + if (layers != undefined && OpenLayers.Util.isArray(layers)) { │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + var layer = layers[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.WMS) { │ │ │ │ + context.layersContext.push(this.layerToContext(layer)); │ │ │ │ } │ │ │ │ - var feature = new OpenLayers.Feature.Vector( │ │ │ │ - container.components[0], container.attributes); │ │ │ │ - features.push(feature); │ │ │ │ } │ │ │ │ - return features; │ │ │ │ - }, │ │ │ │ + } │ │ │ │ + return context; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMC" │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WCSCapabilities.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 │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WCSCapabilities │ │ │ │ + * Read WCS Capabilities. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WCSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "1.1.0". │ │ │ │ + */ │ │ │ │ + defaultVersion: "1.1.0", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WCSCapabilities │ │ │ │ + * Create a new parser for WCS capabilities. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return a list of coverages. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array} List of named coverages. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities" │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/QueryStringFilter.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/Console.js │ │ │ │ + * @requires OpenLayers/Format.js │ │ │ │ + * @requires OpenLayers/Filter/Spatial.js │ │ │ │ + * @requires OpenLayers/Filter/Comparison.js │ │ │ │ + * @requires OpenLayers/Filter/Logical.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.QueryStringFilter │ │ │ │ + * Parser for reading a query string and creating a simple filter. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.QueryStringFilter = (function() { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Map the OpenLayers.Filter.Comparison types to the operation strings of │ │ │ │ + * the protocol. │ │ │ │ + */ │ │ │ │ + var cmpToStr = {}; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.EQUAL_TO] = "eq"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.NOT_EQUAL_TO] = "ne"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN] = "lt"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO] = "lte"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN] = "gt"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO] = "gte"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.LIKE] = "ilike"; │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Function: regex2value │ │ │ │ + * Convert the value from a regular expression string to a LIKE/ILIKE │ │ │ │ + * string known to the web service. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * value - {String} The regex string. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} The converted string. │ │ │ │ + */ │ │ │ │ + function regex2value(value) { │ │ │ │ + │ │ │ │ + // highly sensitive!! Do not change this without running the │ │ │ │ + // Protocol/HTTP.html unit tests │ │ │ │ + │ │ │ │ + // convert % to \% │ │ │ │ + value = value.replace(/%/g, "\\%"); │ │ │ │ + │ │ │ │ + // convert \\. to \\_ (\\.* occurences converted later) │ │ │ │ + value = value.replace(/\\\\\.(\*)?/g, function($0, $1) { │ │ │ │ + return $1 ? $0 : "\\\\_"; │ │ │ │ + }); │ │ │ │ + │ │ │ │ + // convert \\.* to \\% │ │ │ │ + value = value.replace(/\\\\\.\*/g, "\\\\%"); │ │ │ │ + │ │ │ │ + // convert . to _ (\. and .* occurences converted later) │ │ │ │ + value = value.replace(/(\\)?\.(\*)?/g, function($0, $1, $2) { │ │ │ │ + return $1 || $2 ? $0 : "_"; │ │ │ │ + }); │ │ │ │ + │ │ │ │ + // convert .* to % (\.* occurnces converted later) │ │ │ │ + value = value.replace(/(\\)?\.\*/g, function($0, $1) { │ │ │ │ + return $1 ? $0 : "%"; │ │ │ │ + }); │ │ │ │ + │ │ │ │ + // convert \. to . │ │ │ │ + value = value.replace(/\\\./g, "."); │ │ │ │ + │ │ │ │ + // replace \* with * (watching out for \\*) │ │ │ │ + value = value.replace(/(\\)?\\\*/g, function($0, $1) { │ │ │ │ + return $1 ? $0 : "*"; │ │ │ │ + }); │ │ │ │ + │ │ │ │ + return value; │ │ │ │ + } │ │ │ │ + │ │ │ │ + return OpenLayers.Class(OpenLayers.Format, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - readers: { │ │ │ │ - "sa": { │ │ │ │ - "SamplingPoint": function(node, obj) { │ │ │ │ - // sampling point can also be without a featureMember if │ │ │ │ - // there is only 1 │ │ │ │ - if (!obj.attributes) { │ │ │ │ - var feature = { │ │ │ │ - attributes: {} │ │ │ │ - }; │ │ │ │ - obj.features.push(feature); │ │ │ │ - obj = feature; │ │ │ │ - } │ │ │ │ - obj.attributes.id = this.getAttributeNS(node, │ │ │ │ - this.namespaces.gml, "id"); │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "position": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "gml": OpenLayers.Util.applyDefaults({ │ │ │ │ - "FeatureCollection": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "featureMember": function(node, obj) { │ │ │ │ - var feature = { │ │ │ │ - attributes: {} │ │ │ │ - }; │ │ │ │ - obj.features.push(feature); │ │ │ │ - this.readChildNodes(node, feature); │ │ │ │ - }, │ │ │ │ - "name": function(node, obj) { │ │ │ │ - obj.attributes.name = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "pos": function(node, obj) { │ │ │ │ - // we need to parse the srsName to get to the │ │ │ │ - // externalProjection, that's why we cannot use │ │ │ │ - // GML v3 for this │ │ │ │ - if (!this.externalProjection) { │ │ │ │ - this.externalProjection = new OpenLayers.Projection( │ │ │ │ - node.getAttribute("srsName")); │ │ │ │ - } │ │ │ │ - OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply( │ │ │ │ - this, [node, obj]); │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.GML.v3.prototype.readers.gml) │ │ │ │ - }, │ │ │ │ + wildcarded: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - writers: { │ │ │ │ - "sos": { │ │ │ │ - "GetFeatureOfInterest": function(options) { │ │ │ │ - var node = this.createElementNSPlus("GetFeatureOfInterest", { │ │ │ │ - attributes: { │ │ │ │ - version: this.VERSION, │ │ │ │ - service: 'SOS', │ │ │ │ - "xsi:schemaLocation": this.schemaLocation │ │ │ │ + srsInBBOX: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: write │ │ │ │ + * Serialize an <OpenLayers.Filter> objects using the "simple" filter syntax for │ │ │ │ + * query string parameters. This function must be called as a method of │ │ │ │ + * a protocol instance. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * filter - {<OpenLayers.Filter>} filter to convert. │ │ │ │ + * params - {Object} The parameters object. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} The resulting parameters object. │ │ │ │ + */ │ │ │ │ + write: function(filter, params) { │ │ │ │ + params = params || {}; │ │ │ │ + var className = filter.CLASS_NAME; │ │ │ │ + var filterType = className.substring(className.lastIndexOf(".") + 1); │ │ │ │ + switch (filterType) { │ │ │ │ + case "Spatial": │ │ │ │ + switch (filter.type) { │ │ │ │ + case OpenLayers.Filter.Spatial.BBOX: │ │ │ │ + params.bbox = filter.value.toArray(); │ │ │ │ + if (this.srsInBBOX && filter.projection) { │ │ │ │ + params.bbox.push(filter.projection.getCode()); │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case OpenLayers.Filter.Spatial.DWITHIN: │ │ │ │ + params.tolerance = filter.distance; │ │ │ │ + // no break here │ │ │ │ + case OpenLayers.Filter.Spatial.WITHIN: │ │ │ │ + params.lon = filter.value.x; │ │ │ │ + params.lat = filter.value.y; │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + OpenLayers.Console.warn( │ │ │ │ + "Unknown spatial filter type " + filter.type); │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case "Comparison": │ │ │ │ + var op = cmpToStr[filter.type]; │ │ │ │ + if (op !== undefined) { │ │ │ │ + var value = filter.value; │ │ │ │ + if (filter.type == OpenLayers.Filter.Comparison.LIKE) { │ │ │ │ + value = regex2value(value); │ │ │ │ + if (this.wildcarded) { │ │ │ │ + value = "%" + value + "%"; │ │ │ │ + } │ │ │ │ } │ │ │ │ - }); │ │ │ │ - for (var i = 0, len = options.fois.length; i < len; i++) { │ │ │ │ - this.writeNode("FeatureOfInterestId", { │ │ │ │ - foi: options.fois[i] │ │ │ │ - }, node); │ │ │ │ + params[filter.property + "__" + op] = value; │ │ │ │ + params.queryable = params.queryable || []; │ │ │ │ + params.queryable.push(filter.property); │ │ │ │ + } else { │ │ │ │ + OpenLayers.Console.warn( │ │ │ │ + "Unknown comparison filter type " + filter.type); │ │ │ │ } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "FeatureOfInterestId": function(options) { │ │ │ │ - var node = this.createElementNSPlus("FeatureOfInterestId", { │ │ │ │ - value: options.foi │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ - } │ │ │ │ + break; │ │ │ │ + case "Logical": │ │ │ │ + if (filter.type === OpenLayers.Filter.Logical.AND) { │ │ │ │ + for (var i = 0, len = filter.filters.length; i < len; i++) { │ │ │ │ + params = this.write(filter.filters[i], params); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Console.warn( │ │ │ │ + "Unsupported logical filter type " + filter.type); │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + OpenLayers.Console.warn("Unknown filter type " + filterType); │ │ │ │ } │ │ │ │ + return params; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SOSGetFeatureOfInterest" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.QueryStringFilter" │ │ │ │ │ │ │ │ }); │ │ │ │ + │ │ │ │ + │ │ │ │ +})(); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/SOSGetObservation.js │ │ │ │ + OpenLayers/Format/Atom.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/SOSGetFeatureOfInterest.js │ │ │ │ + * @requires OpenLayers/Format/GML/v3.js │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.SOSGetObservation │ │ │ │ - * Read and write SOS GetObersation (to get the actual values from a sensor) │ │ │ │ - * version 1.0.0 │ │ │ │ + * Class: OpenLayers.Format.Atom │ │ │ │ + * Read/write Atom feeds. Create a new instance with the │ │ │ │ + * <OpenLayers.Format.AtomFeed> constructor. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.SOSGetObservation = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ +OpenLayers.Format.Atom = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ /** │ │ │ │ * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + * {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: { │ │ │ │ - ows: "http://www.opengis.net/ows", │ │ │ │ - gml: "http://www.opengis.net/gml", │ │ │ │ - sos: "http://www.opengis.net/sos/1.0", │ │ │ │ - ogc: "http://www.opengis.net/ogc", │ │ │ │ - om: "http://www.opengis.net/om/1.0", │ │ │ │ - sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + atom: "http://www.w3.org/2005/Atom", │ │ │ │ + georss: "http://www.georss.org/georss" │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ + * APIProperty: feedTitle │ │ │ │ + * {String} Atom feed elements require a title. Default is "untitled". │ │ │ │ */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ - }, │ │ │ │ + feedTitle: "untitled", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: VERSION │ │ │ │ - * {String} 1.0.0 │ │ │ │ + * APIProperty: defaultEntryTitle │ │ │ │ + * {String} Atom entry elements require a title. In cases where one is │ │ │ │ + * not provided in the feature attributes, this will be used. Default │ │ │ │ + * is "untitled". │ │ │ │ */ │ │ │ │ - VERSION: "1.0.0", │ │ │ │ + defaultEntryTitle: "untitled", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} Schema location │ │ │ │ + * Property: gmlParse │ │ │ │ + * {Object} GML Format object for parsing features │ │ │ │ + * Non-API and only created if necessary │ │ │ │ */ │ │ │ │ - schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosGetObservation.xsd", │ │ │ │ + gmlParser: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ + * APIProperty: xy │ │ │ │ + * {Boolean} Order of the GML coordinate: true:(x,y) or false:(y,x) │ │ │ │ + * For GeoRSS the default is (y,x), therefore: false │ │ │ │ */ │ │ │ │ - defaultPrefix: "sos", │ │ │ │ + xy: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.SOSGetObservation │ │ │ │ + * Constructor: OpenLayers.Format.AtomEntry │ │ │ │ + * Create a new parser for Atom. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be set on │ │ │ │ * this instance. │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: read │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * APIMethod: read │ │ │ │ + * Return a list of features from an Atom feed or entry document. │ │ │ │ + │ │ │ │ + * Parameters: │ │ │ │ + * doc - {Element} or {String} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} An object containing the measurements │ │ │ │ + * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ */ │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - } │ │ │ │ - if (data && data.nodeType == 9) { │ │ │ │ - data = data.documentElement; │ │ │ │ + read: function(doc) { │ │ │ │ + if (typeof doc == "string") { │ │ │ │ + doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]); │ │ │ │ } │ │ │ │ - var info = { │ │ │ │ - measurements: [], │ │ │ │ - observations: [] │ │ │ │ - }; │ │ │ │ - this.readNode(data, info); │ │ │ │ - return info; │ │ │ │ + return this.parseFeatures(doc); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: write │ │ │ │ + * APIMethod: write │ │ │ │ + * Serialize or more feature nodes to Atom documents. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object. │ │ │ │ + * features - {<OpenLayers.Feature.Vector>} or Array({<OpenLayers.Feature.Vector>}) │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} An SOS GetObservation request XML string. │ │ │ │ + * {String} an Atom entry document if passed one feature node, or a feed │ │ │ │ + * document if passed an array of feature nodes. │ │ │ │ */ │ │ │ │ - write: function(options) { │ │ │ │ - var node = this.writeNode("sos:GetObservation", options); │ │ │ │ - node.setAttribute("xmlns:om", this.namespaces.om); │ │ │ │ - node.setAttribute("xmlns:ogc", this.namespaces.ogc); │ │ │ │ - this.setAttributeNS( │ │ │ │ - node, this.namespaces.xsi, │ │ │ │ - "xsi:schemaLocation", this.schemaLocation │ │ │ │ - ); │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [node]); │ │ │ │ + write: function(features) { │ │ │ │ + var doc; │ │ │ │ + if (OpenLayers.Util.isArray(features)) { │ │ │ │ + doc = this.createElementNSPlus("atom:feed"); │ │ │ │ + doc.appendChild( │ │ │ │ + this.createElementNSPlus("atom:title", { │ │ │ │ + value: this.feedTitle │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + for (var i = 0, ii = features.length; i < ii; i++) { │ │ │ │ + doc.appendChild(this.buildEntryNode(features[i])); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + doc = this.buildEntryNode(features); │ │ │ │ + } │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [doc]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: buildContentNode │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * content - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} an Atom content node. │ │ │ │ + * │ │ │ │ + * TODO: types other than text. │ │ │ │ */ │ │ │ │ - readers: { │ │ │ │ - "om": { │ │ │ │ - "ObservationCollection": function(node, obj) { │ │ │ │ - obj.id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "member": function(node, observationCollection) { │ │ │ │ - this.readChildNodes(node, observationCollection); │ │ │ │ - }, │ │ │ │ - "Measurement": function(node, observationCollection) { │ │ │ │ - var measurement = {}; │ │ │ │ - observationCollection.measurements.push(measurement); │ │ │ │ - this.readChildNodes(node, measurement); │ │ │ │ - }, │ │ │ │ - "Observation": function(node, observationCollection) { │ │ │ │ - var observation = {}; │ │ │ │ - observationCollection.observations.push(observation); │ │ │ │ - this.readChildNodes(node, observation); │ │ │ │ - }, │ │ │ │ - "samplingTime": function(node, measurement) { │ │ │ │ - var samplingTime = {}; │ │ │ │ - measurement.samplingTime = samplingTime; │ │ │ │ - this.readChildNodes(node, samplingTime); │ │ │ │ - }, │ │ │ │ - "observedProperty": function(node, measurement) { │ │ │ │ - measurement.observedProperty = │ │ │ │ - this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ - this.readChildNodes(node, measurement); │ │ │ │ - }, │ │ │ │ - "procedure": function(node, measurement) { │ │ │ │ - measurement.procedure = │ │ │ │ - this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ - this.readChildNodes(node, measurement); │ │ │ │ - }, │ │ │ │ - "featureOfInterest": function(node, observation) { │ │ │ │ - var foi = { │ │ │ │ - features: [] │ │ │ │ - }; │ │ │ │ - observation.fois = []; │ │ │ │ - observation.fois.push(foi); │ │ │ │ - this.readChildNodes(node, foi); │ │ │ │ - // postprocessing to get actual features │ │ │ │ - var features = []; │ │ │ │ - for (var i = 0, len = foi.features.length; i < len; i++) { │ │ │ │ - var feature = foi.features[i]; │ │ │ │ - features.push(new OpenLayers.Feature.Vector( │ │ │ │ - feature.components[0], feature.attributes)); │ │ │ │ - } │ │ │ │ - foi.features = features; │ │ │ │ - }, │ │ │ │ - "result": function(node, measurement) { │ │ │ │ - var result = {}; │ │ │ │ - measurement.result = result; │ │ │ │ - if (this.getChildValue(node) !== '') { │ │ │ │ - result.value = this.getChildValue(node); │ │ │ │ - result.uom = node.getAttribute("uom"); │ │ │ │ - } else { │ │ │ │ - this.readChildNodes(node, result); │ │ │ │ + buildContentNode: function(content) { │ │ │ │ + var node = this.createElementNSPlus("atom:content", { │ │ │ │ + attributes: { │ │ │ │ + type: content.type || null │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (content.src) { │ │ │ │ + node.setAttribute("src", content.src); │ │ │ │ + } else { │ │ │ │ + if (content.type == "text" || content.type == null) { │ │ │ │ + node.appendChild( │ │ │ │ + this.createTextNode(content.value) │ │ │ │ + ); │ │ │ │ + } else if (content.type == "html") { │ │ │ │ + if (typeof content.value != "string") { │ │ │ │ + throw "HTML content must be in form of an escaped string"; │ │ │ │ } │ │ │ │ + node.appendChild( │ │ │ │ + this.createTextNode(content.value) │ │ │ │ + ); │ │ │ │ + } else if (content.type == "xhtml") { │ │ │ │ + node.appendChild(content.value); │ │ │ │ + } else if (content.type == "xhtml" || │ │ │ │ + content.type.match(/(\+|\/)xml$/)) { │ │ │ │ + node.appendChild(content.value); │ │ │ │ + } else { // MUST be a valid Base64 encoding │ │ │ │ + node.appendChild( │ │ │ │ + this.createTextNode(content.value) │ │ │ │ + ); │ │ │ │ } │ │ │ │ - }, │ │ │ │ - "sa": OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.sa, │ │ │ │ - "gml": OpenLayers.Util.applyDefaults({ │ │ │ │ - "TimeInstant": function(node, samplingTime) { │ │ │ │ - var timeInstant = {}; │ │ │ │ - samplingTime.timeInstant = timeInstant; │ │ │ │ - this.readChildNodes(node, timeInstant); │ │ │ │ - }, │ │ │ │ - "timePosition": function(node, timeInstant) { │ │ │ │ - timeInstant.timePosition = this.getChildValue(node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: buildEntryNode │ │ │ │ + * Build an Atom entry node from a feature object. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} an Atom entry node. │ │ │ │ + * │ │ │ │ + * These entries are geared for publication using AtomPub. │ │ │ │ + * │ │ │ │ + * TODO: support extension elements │ │ │ │ + */ │ │ │ │ + buildEntryNode: function(feature) { │ │ │ │ + var attrib = feature.attributes; │ │ │ │ + var atomAttrib = attrib.atom || {}; │ │ │ │ + var entryNode = this.createElementNSPlus("atom:entry"); │ │ │ │ + │ │ │ │ + // atom:author │ │ │ │ + if (atomAttrib.authors) { │ │ │ │ + var authors = OpenLayers.Util.isArray(atomAttrib.authors) ? │ │ │ │ + atomAttrib.authors : [atomAttrib.authors]; │ │ │ │ + for (var i = 0, ii = authors.length; i < ii; i++) { │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.buildPersonConstructNode( │ │ │ │ + "author", authors[i] │ │ │ │ + ) │ │ │ │ + ); │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.gml) │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atom:category │ │ │ │ + if (atomAttrib.categories) { │ │ │ │ + var categories = OpenLayers.Util.isArray(atomAttrib.categories) ? │ │ │ │ + atomAttrib.categories : [atomAttrib.categories]; │ │ │ │ + var category; │ │ │ │ + for (var i = 0, ii = categories.length; i < ii; i++) { │ │ │ │ + category = categories[i]; │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:category", { │ │ │ │ + attributes: { │ │ │ │ + term: category.term, │ │ │ │ + scheme: category.scheme || null, │ │ │ │ + label: category.label || null │ │ │ │ + } │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atom:content │ │ │ │ + if (atomAttrib.content) { │ │ │ │ + entryNode.appendChild(this.buildContentNode(atomAttrib.content)); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atom:contributor │ │ │ │ + if (atomAttrib.contributors) { │ │ │ │ + var contributors = OpenLayers.Util.isArray(atomAttrib.contributors) ? │ │ │ │ + atomAttrib.contributors : [atomAttrib.contributors]; │ │ │ │ + for (var i = 0, ii = contributors.length; i < ii; i++) { │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.buildPersonConstructNode( │ │ │ │ + "contributor", │ │ │ │ + contributors[i] │ │ │ │ + ) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atom:id │ │ │ │ + if (feature.fid) { │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:id", { │ │ │ │ + value: feature.fid │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atom:link │ │ │ │ + if (atomAttrib.links) { │ │ │ │ + var links = OpenLayers.Util.isArray(atomAttrib.links) ? │ │ │ │ + atomAttrib.links : [atomAttrib.links]; │ │ │ │ + var link; │ │ │ │ + for (var i = 0, ii = links.length; i < ii; i++) { │ │ │ │ + link = links[i]; │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:link", { │ │ │ │ + attributes: { │ │ │ │ + href: link.href, │ │ │ │ + rel: link.rel || null, │ │ │ │ + type: link.type || null, │ │ │ │ + hreflang: link.hreflang || null, │ │ │ │ + title: link.title || null, │ │ │ │ + length: link.length || null │ │ │ │ + } │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atom:published │ │ │ │ + if (atomAttrib.published) { │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:published", { │ │ │ │ + value: atomAttrib.published │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atom:rights │ │ │ │ + if (atomAttrib.rights) { │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:rights", { │ │ │ │ + value: atomAttrib.rights │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atom:source not implemented │ │ │ │ + │ │ │ │ + // atom:summary │ │ │ │ + if (atomAttrib.summary || attrib.description) { │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:summary", { │ │ │ │ + value: atomAttrib.summary || attrib.description │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atom:title │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:title", { │ │ │ │ + value: atomAttrib.title || attrib.title || this.defaultEntryTitle │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + │ │ │ │ + // atom:updated │ │ │ │ + if (atomAttrib.updated) { │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:updated", { │ │ │ │ + value: atomAttrib.updated │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // georss:where │ │ │ │ + if (feature.geometry) { │ │ │ │ + var whereNode = this.createElementNSPlus("georss:where"); │ │ │ │ + whereNode.appendChild( │ │ │ │ + this.buildGeometryNode(feature.geometry) │ │ │ │ + ); │ │ │ │ + entryNode.appendChild(whereNode); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return entryNode; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: initGmlParser │ │ │ │ + * Creates a GML parser. │ │ │ │ */ │ │ │ │ - writers: { │ │ │ │ - "sos": { │ │ │ │ - "GetObservation": function(options) { │ │ │ │ - var node = this.createElementNSPlus("GetObservation", { │ │ │ │ - attributes: { │ │ │ │ - version: this.VERSION, │ │ │ │ - service: 'SOS' │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.writeNode("offering", options, node); │ │ │ │ - if (options.eventTime) { │ │ │ │ - this.writeNode("eventTime", options, node); │ │ │ │ - } │ │ │ │ - for (var procedure in options.procedures) { │ │ │ │ - this.writeNode("procedure", options.procedures[procedure], node); │ │ │ │ - } │ │ │ │ - for (var observedProperty in options.observedProperties) { │ │ │ │ - this.writeNode("observedProperty", options.observedProperties[observedProperty], node); │ │ │ │ + initGmlParser: function() { │ │ │ │ + this.gmlParser = new OpenLayers.Format.GML.v3({ │ │ │ │ + xy: this.xy, │ │ │ │ + featureNS: "http://example.com#feature", │ │ │ │ + internalProjection: this.internalProjection, │ │ │ │ + externalProjection: this.externalProjection │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: buildGeometryNode │ │ │ │ + * builds a GeoRSS node with a given geometry │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A gml node. │ │ │ │ + */ │ │ │ │ + buildGeometryNode: function(geometry) { │ │ │ │ + if (!this.gmlParser) { │ │ │ │ + this.initGmlParser(); │ │ │ │ + } │ │ │ │ + var node = this.gmlParser.writeNode("feature:_geometry", geometry); │ │ │ │ + return node.firstChild; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: buildPersonConstructNode │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} │ │ │ │ + * value - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} an Atom person construct node. │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * >>> buildPersonConstructNode("author", {name: "John Smith"}) │ │ │ │ + * {<author><name>John Smith</name></author>} │ │ │ │ + * │ │ │ │ + * TODO: how to specify extension elements? Add to the oNames array? │ │ │ │ + */ │ │ │ │ + buildPersonConstructNode: function(name, value) { │ │ │ │ + var oNames = ["uri", "email"]; │ │ │ │ + var personNode = this.createElementNSPlus("atom:" + name); │ │ │ │ + personNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:name", { │ │ │ │ + value: value.name │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + for (var i = 0, ii = oNames.length; i < ii; i++) { │ │ │ │ + if (value[oNames[i]]) { │ │ │ │ + personNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:" + oNames[i], { │ │ │ │ + value: value[oNames[i]] │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return personNode; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getFirstChildValue │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * nsuri - {String} Child node namespace uri ("*" for any). │ │ │ │ + * name - {String} Child node name. │ │ │ │ + * def - {String} Optional string default to return if no child found. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} The value of the first child with the given tag name. Returns │ │ │ │ + * default value or empty string if none found. │ │ │ │ + */ │ │ │ │ + getFirstChildValue: function(node, nsuri, name, def) { │ │ │ │ + var value; │ │ │ │ + var nodes = this.getElementsByTagNameNS(node, nsuri, name); │ │ │ │ + if (nodes && nodes.length > 0) { │ │ │ │ + value = this.getChildValue(nodes[0], def); │ │ │ │ + } else { │ │ │ │ + value = def; │ │ │ │ + } │ │ │ │ + return value; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseFeature │ │ │ │ + * Parse feature from an Atom entry node.. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} An Atom entry or feed node. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Feature.Vector>} │ │ │ │ + */ │ │ │ │ + parseFeature: function(node) { │ │ │ │ + var atomAttrib = {}; │ │ │ │ + var value = null; │ │ │ │ + var nodes = null; │ │ │ │ + var attval = null; │ │ │ │ + var atomns = this.namespaces.atom; │ │ │ │ + │ │ │ │ + // atomAuthor* │ │ │ │ + this.parsePersonConstructs(node, "author", atomAttrib); │ │ │ │ + │ │ │ │ + // atomCategory* │ │ │ │ + nodes = this.getElementsByTagNameNS(node, atomns, "category"); │ │ │ │ + if (nodes.length > 0) { │ │ │ │ + atomAttrib.categories = []; │ │ │ │ + } │ │ │ │ + for (var i = 0, ii = nodes.length; i < ii; i++) { │ │ │ │ + value = {}; │ │ │ │ + value.term = nodes[i].getAttribute("term"); │ │ │ │ + attval = nodes[i].getAttribute("scheme"); │ │ │ │ + if (attval) { │ │ │ │ + value.scheme = attval; │ │ │ │ + } │ │ │ │ + attval = nodes[i].getAttribute("label"); │ │ │ │ + if (attval) { │ │ │ │ + value.label = attval; │ │ │ │ + } │ │ │ │ + atomAttrib.categories.push(value); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atomContent? │ │ │ │ + nodes = this.getElementsByTagNameNS(node, atomns, "content"); │ │ │ │ + if (nodes.length > 0) { │ │ │ │ + value = {}; │ │ │ │ + attval = nodes[0].getAttribute("type"); │ │ │ │ + if (attval) { │ │ │ │ + value.type = attval; │ │ │ │ + } │ │ │ │ + attval = nodes[0].getAttribute("src"); │ │ │ │ + if (attval) { │ │ │ │ + value.src = attval; │ │ │ │ + } else { │ │ │ │ + if (value.type == "text" || │ │ │ │ + value.type == "html" || │ │ │ │ + value.type == null) { │ │ │ │ + value.value = this.getFirstChildValue( │ │ │ │ + node, │ │ │ │ + atomns, │ │ │ │ + "content", │ │ │ │ + null │ │ │ │ + ); │ │ │ │ + } else if (value.type == "xhtml" || │ │ │ │ + value.type.match(/(\+|\/)xml$/)) { │ │ │ │ + value.value = this.getChildEl(nodes[0]); │ │ │ │ + } else { // MUST be base64 encoded │ │ │ │ + value.value = this.getFirstChildValue( │ │ │ │ + node, │ │ │ │ + atomns, │ │ │ │ + "content", │ │ │ │ + null │ │ │ │ + ); │ │ │ │ } │ │ │ │ - if (options.foi) { │ │ │ │ - this.writeNode("featureOfInterest", options.foi, node); │ │ │ │ + atomAttrib.content = value; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atomContributor* │ │ │ │ + this.parsePersonConstructs(node, "contributor", atomAttrib); │ │ │ │ + │ │ │ │ + // atomId │ │ │ │ + atomAttrib.id = this.getFirstChildValue(node, atomns, "id", null); │ │ │ │ + │ │ │ │ + // atomLink* │ │ │ │ + nodes = this.getElementsByTagNameNS(node, atomns, "link"); │ │ │ │ + if (nodes.length > 0) { │ │ │ │ + atomAttrib.links = new Array(nodes.length); │ │ │ │ + } │ │ │ │ + var oAtts = ["rel", "type", "hreflang", "title", "length"]; │ │ │ │ + for (var i = 0, ii = nodes.length; i < ii; i++) { │ │ │ │ + value = {}; │ │ │ │ + value.href = nodes[i].getAttribute("href"); │ │ │ │ + for (var j = 0, jj = oAtts.length; j < jj; j++) { │ │ │ │ + attval = nodes[i].getAttribute(oAtts[j]); │ │ │ │ + if (attval) { │ │ │ │ + value[oAtts[j]] = attval; │ │ │ │ } │ │ │ │ - this.writeNode("responseFormat", options, node); │ │ │ │ - if (options.resultModel) { │ │ │ │ - this.writeNode("resultModel", options, node); │ │ │ │ + } │ │ │ │ + atomAttrib.links[i] = value; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atomPublished? │ │ │ │ + value = this.getFirstChildValue(node, atomns, "published", null); │ │ │ │ + if (value) { │ │ │ │ + atomAttrib.published = value; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atomRights? │ │ │ │ + value = this.getFirstChildValue(node, atomns, "rights", null); │ │ │ │ + if (value) { │ │ │ │ + atomAttrib.rights = value; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atomSource? -- not implemented │ │ │ │ + │ │ │ │ + // atomSummary? │ │ │ │ + value = this.getFirstChildValue(node, atomns, "summary", null); │ │ │ │ + if (value) { │ │ │ │ + atomAttrib.summary = value; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atomTitle │ │ │ │ + atomAttrib.title = this.getFirstChildValue( │ │ │ │ + node, atomns, "title", null │ │ │ │ + ); │ │ │ │ + │ │ │ │ + // atomUpdated │ │ │ │ + atomAttrib.updated = this.getFirstChildValue( │ │ │ │ + node, atomns, "updated", null │ │ │ │ + ); │ │ │ │ + │ │ │ │ + var featureAttrib = { │ │ │ │ + title: atomAttrib.title, │ │ │ │ + description: atomAttrib.summary, │ │ │ │ + atom: atomAttrib │ │ │ │ + }; │ │ │ │ + var geometry = this.parseLocations(node)[0]; │ │ │ │ + var feature = new OpenLayers.Feature.Vector(geometry, featureAttrib); │ │ │ │ + feature.fid = atomAttrib.id; │ │ │ │ + return feature; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseFeatures │ │ │ │ + * Return features from an Atom entry or feed. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} An Atom entry or feed node. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ + */ │ │ │ │ + parseFeatures: function(node) { │ │ │ │ + var features = []; │ │ │ │ + var entries = this.getElementsByTagNameNS( │ │ │ │ + node, this.namespaces.atom, "entry" │ │ │ │ + ); │ │ │ │ + if (entries.length == 0) { │ │ │ │ + entries = [node]; │ │ │ │ + } │ │ │ │ + for (var i = 0, ii = entries.length; i < ii; i++) { │ │ │ │ + features.push(this.parseFeature(entries[i])); │ │ │ │ + } │ │ │ │ + return features; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseLocations │ │ │ │ + * Parse the locations from an Atom entry or feed. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} An Atom entry or feed node. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * Array({<OpenLayers.Geometry>}) │ │ │ │ + */ │ │ │ │ + parseLocations: function(node) { │ │ │ │ + var georssns = this.namespaces.georss; │ │ │ │ + │ │ │ │ + var locations = { │ │ │ │ + components: [] │ │ │ │ + }; │ │ │ │ + var where = this.getElementsByTagNameNS(node, georssns, "where"); │ │ │ │ + if (where && where.length > 0) { │ │ │ │ + if (!this.gmlParser) { │ │ │ │ + this.initGmlParser(); │ │ │ │ + } │ │ │ │ + for (var i = 0, ii = where.length; i < ii; i++) { │ │ │ │ + this.gmlParser.readChildNodes(where[i], locations); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + var components = locations.components; │ │ │ │ + var point = this.getElementsByTagNameNS(node, georssns, "point"); │ │ │ │ + if (point && point.length > 0) { │ │ │ │ + for (var i = 0, ii = point.length; i < ii; i++) { │ │ │ │ + var xy = OpenLayers.String.trim( │ │ │ │ + point[i].firstChild.nodeValue │ │ │ │ + ).split(/\s+/); │ │ │ │ + if (xy.length != 2) { │ │ │ │ + xy = OpenLayers.String.trim( │ │ │ │ + point[i].firstChild.nodeValue │ │ │ │ + ).split(/\s*,\s*/); │ │ │ │ } │ │ │ │ - if (options.responseMode) { │ │ │ │ - this.writeNode("responseMode", options, node); │ │ │ │ + components.push(new OpenLayers.Geometry.Point(xy[1], xy[0])); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + var line = this.getElementsByTagNameNS(node, georssns, "line"); │ │ │ │ + if (line && line.length > 0) { │ │ │ │ + var coords; │ │ │ │ + var p; │ │ │ │ + var points; │ │ │ │ + for (var i = 0, ii = line.length; i < ii; i++) { │ │ │ │ + coords = OpenLayers.String.trim( │ │ │ │ + line[i].firstChild.nodeValue │ │ │ │ + ).split(/\s+/); │ │ │ │ + points = []; │ │ │ │ + for (var j = 0, jj = coords.length; j < jj; j += 2) { │ │ │ │ + p = new OpenLayers.Geometry.Point(coords[j + 1], coords[j]); │ │ │ │ + points.push(p); │ │ │ │ } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "featureOfInterest": function(foi) { │ │ │ │ - var node = this.createElementNSPlus("featureOfInterest"); │ │ │ │ - this.writeNode("ObjectID", foi.objectId, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ObjectID": function(options) { │ │ │ │ - return this.createElementNSPlus("ObjectID", { │ │ │ │ - value: options │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "responseFormat": function(options) { │ │ │ │ - return this.createElementNSPlus("responseFormat", { │ │ │ │ - value: options.responseFormat │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "procedure": function(procedure) { │ │ │ │ - return this.createElementNSPlus("procedure", { │ │ │ │ - value: procedure │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "offering": function(options) { │ │ │ │ - return this.createElementNSPlus("offering", { │ │ │ │ - value: options.offering │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "observedProperty": function(observedProperty) { │ │ │ │ - return this.createElementNSPlus("observedProperty", { │ │ │ │ - value: observedProperty │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "eventTime": function(options) { │ │ │ │ - var node = this.createElementNSPlus("eventTime"); │ │ │ │ - if (options.eventTime === 'latest') { │ │ │ │ - this.writeNode("ogc:TM_Equals", options, node); │ │ │ │ + components.push( │ │ │ │ + new OpenLayers.Geometry.LineString(points) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + var polygon = this.getElementsByTagNameNS(node, georssns, "polygon"); │ │ │ │ + if (polygon && polygon.length > 0) { │ │ │ │ + var coords; │ │ │ │ + var p; │ │ │ │ + var points; │ │ │ │ + for (var i = 0, ii = polygon.length; i < ii; i++) { │ │ │ │ + coords = OpenLayers.String.trim( │ │ │ │ + polygon[i].firstChild.nodeValue │ │ │ │ + ).split(/\s+/); │ │ │ │ + points = []; │ │ │ │ + for (var j = 0, jj = coords.length; j < jj; j += 2) { │ │ │ │ + p = new OpenLayers.Geometry.Point(coords[j + 1], coords[j]); │ │ │ │ + points.push(p); │ │ │ │ } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "resultModel": function(options) { │ │ │ │ - return this.createElementNSPlus("resultModel", { │ │ │ │ - value: options.resultModel │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "responseMode": function(options) { │ │ │ │ - return this.createElementNSPlus("responseMode", { │ │ │ │ - value: options.responseMode │ │ │ │ - }); │ │ │ │ + components.push( │ │ │ │ + new OpenLayers.Geometry.Polygon( │ │ │ │ + [new OpenLayers.Geometry.LinearRing(points)] │ │ │ │ + ) │ │ │ │ + ); │ │ │ │ } │ │ │ │ - }, │ │ │ │ - "ogc": { │ │ │ │ - "TM_Equals": function(options) { │ │ │ │ - var node = this.createElementNSPlus("ogc:TM_Equals"); │ │ │ │ - this.writeNode("ogc:PropertyName", { │ │ │ │ - property: "urn:ogc:data:time:iso8601" │ │ │ │ - }, node); │ │ │ │ - if (options.eventTime === 'latest') { │ │ │ │ - this.writeNode("gml:TimeInstant", { │ │ │ │ - value: 'latest' │ │ │ │ - }, node); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + for (var i = 0, ii = components.length; i < ii; i++) { │ │ │ │ + if (components[i]) { │ │ │ │ + components[i].transform( │ │ │ │ + this.externalProjection, │ │ │ │ + this.internalProjection │ │ │ │ + ); │ │ │ │ } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "PropertyName": function(options) { │ │ │ │ - return this.createElementNSPlus("ogc:PropertyName", { │ │ │ │ - value: options.property │ │ │ │ - }); │ │ │ │ } │ │ │ │ - }, │ │ │ │ - "gml": { │ │ │ │ - "TimeInstant": function(options) { │ │ │ │ - var node = this.createElementNSPlus("gml:TimeInstant"); │ │ │ │ - this.writeNode("gml:timePosition", options, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "timePosition": function(options) { │ │ │ │ - var node = this.createElementNSPlus("gml:timePosition", { │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ + } │ │ │ │ + │ │ │ │ + return components; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parsePersonConstruct │ │ │ │ + * Parse Atom person constructs from an Atom entry node. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} An Atom entry or feed node. │ │ │ │ + * name - {String} Construcy name ("author" or "contributor") │ │ │ │ + * data = {Object} Object in which to put parsed persons. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * An {Object}. │ │ │ │ + */ │ │ │ │ + parsePersonConstructs: function(node, name, data) { │ │ │ │ + var persons = []; │ │ │ │ + var atomns = this.namespaces.atom; │ │ │ │ + var nodes = this.getElementsByTagNameNS(node, atomns, name); │ │ │ │ + var oAtts = ["uri", "email"]; │ │ │ │ + for (var i = 0, ii = nodes.length; i < ii; i++) { │ │ │ │ + var value = {}; │ │ │ │ + value.name = this.getFirstChildValue( │ │ │ │ + nodes[i], │ │ │ │ + atomns, │ │ │ │ + "name", │ │ │ │ + null │ │ │ │ + ); │ │ │ │ + for (var j = 0, jj = oAtts.length; j < jj; j++) { │ │ │ │ + var attval = this.getFirstChildValue( │ │ │ │ + nodes[i], │ │ │ │ + atomns, │ │ │ │ + oAtts[j], │ │ │ │ + null); │ │ │ │ + if (attval) { │ │ │ │ + value[oAtts[j]] = attval; │ │ │ │ + } │ │ │ │ } │ │ │ │ + persons.push(value); │ │ │ │ + } │ │ │ │ + if (persons.length > 0) { │ │ │ │ + data[name + "s"] = persons; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SOSGetObservation" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.Atom" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WMSDescribeLayer.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 │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WMSDescribeLayer │ │ │ │ + * Read SLD WMS DescribeLayer response │ │ │ │ + * DescribeLayer is meant to couple WMS to WFS and WCS │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WMSDescribeLayer = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "1.1.1". │ │ │ │ + */ │ │ │ │ + defaultVersion: "1.1.1", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMSDescribeLayer │ │ │ │ + * Create a new parser for WMS DescribeLayer responses. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read DescribeLayer data from a string, and return the response. │ │ │ │ + * The OGC currently defines 2 formats which are allowed for output, │ │ │ │ + * so we need to parse these 2 types │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array} Array of {<LayerDescription>} objects which have: │ │ │ │ + * - {String} owsType: WFS/WCS │ │ │ │ + * - {String} owsURL: the online resource │ │ │ │ + * - {String} typeName: the name of the typename on the service │ │ │ │ + */ │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer" │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/SOSCapabilities.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 │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.SOSCapabilities │ │ │ │ + * Read SOS Capabilities. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.SOSCapabilities = 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", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.SOSCapabilities │ │ │ │ + * Create a new parser for SOS Capabilities. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return information about │ │ │ │ + * the service (offering and observedProperty mostly). │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} Info about the SOS │ │ │ │ + */ │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SOSCapabilities" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Format/WMSCapabilities.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ @@ -72197,20 +74702,1055 @@ │ │ │ │ /** │ │ │ │ * APIMethod: read │ │ │ │ * Read capabilities data from a string, and return a list of layers. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * data - {String} or {DOMElement} data to read/parse. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Array} List of named layers. │ │ │ │ + * Returns: │ │ │ │ + * {Array} List of named layers. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities" │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/EncodedPolyline.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 │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.EncodedPolyline │ │ │ │ + * Class for reading and writing encoded polylines. Create a new instance │ │ │ │ + * with the <OpenLayers.Format.EncodedPolyline> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: geometryType │ │ │ │ + * {String} Geometry type to output. One of: linestring (default), │ │ │ │ + * linearring, point, multipoint or polygon. If the geometryType is │ │ │ │ + * point, only the first point of the string is returned. │ │ │ │ + */ │ │ │ │ + geometryType: "linestring", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.EncodedPolyline │ │ │ │ + * Create a new parser for encoded polylines │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Format.EncodedPolyline>} A new encoded polylines parser. │ │ │ │ + */ │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.prototype.initialize.apply(this, [options]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Deserialize an encoded polyline string and return a vector feature. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * encoded - {String} An encoded polyline string │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Feature.Vector>} A vector feature with a linestring. │ │ │ │ + */ │ │ │ │ + read: function(encoded) { │ │ │ │ + var geomType; │ │ │ │ + if (this.geometryType == "linestring") │ │ │ │ + geomType = OpenLayers.Geometry.LineString; │ │ │ │ + else if (this.geometryType == "linearring") │ │ │ │ + geomType = OpenLayers.Geometry.LinearRing; │ │ │ │ + else if (this.geometryType == "multipoint") │ │ │ │ + geomType = OpenLayers.Geometry.MultiPoint; │ │ │ │ + else if (this.geometryType != "point" && this.geometryType != "polygon") │ │ │ │ + return null; │ │ │ │ + │ │ │ │ + var flatPoints = this.decodeDeltas(encoded, 2); │ │ │ │ + var flatPointsLength = flatPoints.length; │ │ │ │ + │ │ │ │ + var pointGeometries = []; │ │ │ │ + for (var i = 0; i + 1 < flatPointsLength;) { │ │ │ │ + var y = flatPoints[i++], │ │ │ │ + x = flatPoints[i++]; │ │ │ │ + pointGeometries.push(new OpenLayers.Geometry.Point(x, y)); │ │ │ │ + } │ │ │ │ + │ │ │ │ + │ │ │ │ + if (this.geometryType == "point") │ │ │ │ + return new OpenLayers.Feature.Vector( │ │ │ │ + pointGeometries[0] │ │ │ │ + ); │ │ │ │ + │ │ │ │ + if (this.geometryType == "polygon") │ │ │ │ + return new OpenLayers.Feature.Vector( │ │ │ │ + new OpenLayers.Geometry.Polygon([ │ │ │ │ + new OpenLayers.Geometry.LinearRing(pointGeometries) │ │ │ │ + ]) │ │ │ │ + ); │ │ │ │ + │ │ │ │ + return new OpenLayers.Feature.Vector( │ │ │ │ + new geomType(pointGeometries) │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: decode │ │ │ │ + * Deserialize an encoded string and return an array of n-dimensional │ │ │ │ + * points. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * encoded - {String} An encoded string │ │ │ │ + * dims - {int} The dimension of the points that are returned │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array(Array(int))} An array containing n-dimensional arrays of │ │ │ │ + * coordinates. │ │ │ │ + */ │ │ │ │ + decode: function(encoded, dims, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var flatPoints = this.decodeDeltas(encoded, dims, factor); │ │ │ │ + var flatPointsLength = flatPoints.length; │ │ │ │ + │ │ │ │ + var points = []; │ │ │ │ + for (var i = 0; i + (dims - 1) < flatPointsLength;) { │ │ │ │ + var point = []; │ │ │ │ + │ │ │ │ + for (var dim = 0; dim < dims; ++dim) { │ │ │ │ + point.push(flatPoints[i++]) │ │ │ │ + } │ │ │ │ + │ │ │ │ + points.push(point); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return points; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: write │ │ │ │ + * Serialize a feature or array of features into a WKT string. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * features - {<OpenLayers.Feature.Vector>|Array} A feature or array of │ │ │ │ + * features │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} The WKT string representation of the input geometries │ │ │ │ + */ │ │ │ │ + write: function(features) { │ │ │ │ + var feature; │ │ │ │ + if (features.constructor == Array) │ │ │ │ + feature = features[0]; │ │ │ │ + else │ │ │ │ + feature = features; │ │ │ │ + │ │ │ │ + var geometry = feature.geometry; │ │ │ │ + var type = geometry.CLASS_NAME.split('.')[2].toLowerCase(); │ │ │ │ + │ │ │ │ + var pointGeometries; │ │ │ │ + if (type == "point") │ │ │ │ + pointGeometries = new Array(geometry); │ │ │ │ + else if (type == "linestring" || │ │ │ │ + type == "linearring" || │ │ │ │ + type == "multipoint") │ │ │ │ + pointGeometries = geometry.components; │ │ │ │ + else if (type == "polygon") │ │ │ │ + pointGeometries = geometry.components[0].components; │ │ │ │ + else │ │ │ │ + return null; │ │ │ │ + │ │ │ │ + var flatPoints = []; │ │ │ │ + │ │ │ │ + var pointGeometriesLength = pointGeometries.length; │ │ │ │ + for (var i = 0; i < pointGeometriesLength; ++i) { │ │ │ │ + var pointGeometry = pointGeometries[i]; │ │ │ │ + flatPoints.push(pointGeometry.y); │ │ │ │ + flatPoints.push(pointGeometry.x); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return this.encodeDeltas(flatPoints, 2); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: encode │ │ │ │ + * Serialize an array of n-dimensional points and return an encoded string │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * points - {Array(Array(int))} An array containing n-dimensional │ │ │ │ + * arrays of coordinates │ │ │ │ + * dims - {int} The dimension of the points that should be read │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} An encoded string │ │ │ │ + */ │ │ │ │ + encode: function(points, dims, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var flatPoints = []; │ │ │ │ + │ │ │ │ + var pointsLength = points.length; │ │ │ │ + for (var i = 0; i < pointsLength; ++i) { │ │ │ │ + var point = points[i]; │ │ │ │ + │ │ │ │ + for (var dim = 0; dim < dims; ++dim) { │ │ │ │ + flatPoints.push(point[dim]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + return this.encodeDeltas(flatPoints, dims, factor); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: encodeDeltas │ │ │ │ + * Encode a list of n-dimensional points and return an encoded string │ │ │ │ + * │ │ │ │ + * Attention: This function will modify the passed array! │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * numbers - {Array.<number>} A list of n-dimensional points. │ │ │ │ + * dimension - {number} The dimension of the points in the list. │ │ │ │ + * opt_factor - {number=} The factor by which the numbers will be │ │ │ │ + * multiplied. The remaining decimal places will get rounded away. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {string} The encoded string. │ │ │ │ + */ │ │ │ │ + encodeDeltas: function(numbers, dimension, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var d; │ │ │ │ + │ │ │ │ + var lastNumbers = new Array(dimension); │ │ │ │ + for (d = 0; d < dimension; ++d) { │ │ │ │ + lastNumbers[d] = 0; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength;) { │ │ │ │ + for (d = 0; d < dimension; ++d, ++i) { │ │ │ │ + var num = numbers[i]; │ │ │ │ + var delta = num - lastNumbers[d]; │ │ │ │ + lastNumbers[d] = num; │ │ │ │ + │ │ │ │ + numbers[i] = delta; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + return this.encodeFloats(numbers, factor); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: decodeDeltas │ │ │ │ + * Decode a list of n-dimensional points from an encoded string │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * encoded - {string} An encoded string. │ │ │ │ + * dimension - {number} The dimension of the points in the encoded string. │ │ │ │ + * opt_factor - {number=} The factor by which the resulting numbers will │ │ │ │ + * be divided. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array.<number>} A list of n-dimensional points. │ │ │ │ + */ │ │ │ │ + decodeDeltas: function(encoded, dimension, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var d; │ │ │ │ + │ │ │ │ + var lastNumbers = new Array(dimension); │ │ │ │ + for (d = 0; d < dimension; ++d) { │ │ │ │ + lastNumbers[d] = 0; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var numbers = this.decodeFloats(encoded, factor); │ │ │ │ + │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength;) { │ │ │ │ + for (d = 0; d < dimension; ++d, ++i) { │ │ │ │ + lastNumbers[d] += numbers[i]; │ │ │ │ + │ │ │ │ + numbers[i] = lastNumbers[d]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + return numbers; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: encodeFloats │ │ │ │ + * Encode a list of floating point numbers and return an encoded string │ │ │ │ + * │ │ │ │ + * Attention: This function will modify the passed array! │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * numbers - {Array.<number>} A list of floating point numbers. │ │ │ │ + * opt_factor - {number=} The factor by which the numbers will be │ │ │ │ + * multiplied. The remaining decimal places will get rounded away. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {string} The encoded string. │ │ │ │ + */ │ │ │ │ + encodeFloats: function(numbers, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength; ++i) { │ │ │ │ + numbers[i] = Math.round(numbers[i] * factor); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return this.encodeSignedIntegers(numbers); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: decodeFloats │ │ │ │ + * Decode a list of floating point numbers from an encoded string │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * encoded - {string} An encoded string. │ │ │ │ + * opt_factor - {number=} The factor by which the result will be divided. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array.<number>} A list of floating point numbers. │ │ │ │ + */ │ │ │ │ + decodeFloats: function(encoded, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + │ │ │ │ + var numbers = this.decodeSignedIntegers(encoded); │ │ │ │ + │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength; ++i) { │ │ │ │ + numbers[i] /= factor; │ │ │ │ + } │ │ │ │ + │ │ │ │ + return numbers; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: encodeSignedIntegers │ │ │ │ + * Encode a list of signed integers and return an encoded string │ │ │ │ + * │ │ │ │ + * Attention: This function will modify the passed array! │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * numbers - {Array.<number>} A list of signed integers. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {string} The encoded string. │ │ │ │ + */ │ │ │ │ + encodeSignedIntegers: function(numbers) { │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength; ++i) { │ │ │ │ + var num = numbers[i]; │ │ │ │ + │ │ │ │ + var signedNum = num << 1; │ │ │ │ + if (num < 0) { │ │ │ │ + signedNum = ~(signedNum); │ │ │ │ + } │ │ │ │ + │ │ │ │ + numbers[i] = signedNum; │ │ │ │ + } │ │ │ │ + │ │ │ │ + return this.encodeUnsignedIntegers(numbers); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: decodeSignedIntegers │ │ │ │ + * Decode a list of signed integers from an encoded string │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * encoded - {string} An encoded string. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array.<number>} A list of signed integers. │ │ │ │ + */ │ │ │ │ + decodeSignedIntegers: function(encoded) { │ │ │ │ + var numbers = this.decodeUnsignedIntegers(encoded); │ │ │ │ + │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength; ++i) { │ │ │ │ + var num = numbers[i]; │ │ │ │ + numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return numbers; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: encodeUnsignedIntegers │ │ │ │ + * Encode a list of unsigned integers and return an encoded string │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * numbers - {Array.<number>} A list of unsigned integers. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {string} The encoded string. │ │ │ │ + */ │ │ │ │ + encodeUnsignedIntegers: function(numbers) { │ │ │ │ + var encoded = ''; │ │ │ │ + │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength; ++i) { │ │ │ │ + encoded += this.encodeUnsignedInteger(numbers[i]); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return encoded; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: decodeUnsignedIntegers │ │ │ │ + * Decode a list of unsigned integers from an encoded string │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * encoded - {string} An encoded string. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array.<number>} A list of unsigned integers. │ │ │ │ + */ │ │ │ │ + decodeUnsignedIntegers: function(encoded) { │ │ │ │ + var numbers = []; │ │ │ │ + │ │ │ │ + var current = 0; │ │ │ │ + var shift = 0; │ │ │ │ + │ │ │ │ + var encodedLength = encoded.length; │ │ │ │ + for (var i = 0; i < encodedLength; ++i) { │ │ │ │ + var b = encoded.charCodeAt(i) - 63; │ │ │ │ + │ │ │ │ + current |= (b & 0x1f) << shift; │ │ │ │ + │ │ │ │ + if (b < 0x20) { │ │ │ │ + numbers.push(current); │ │ │ │ + current = 0; │ │ │ │ + shift = 0; │ │ │ │ + } else { │ │ │ │ + shift += 5; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + return numbers; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: encodeFloat │ │ │ │ + * Encode one single floating point number and return an encoded string │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * num - {number} Floating point number that should be encoded. │ │ │ │ + * opt_factor - {number=} The factor by which num will be multiplied. │ │ │ │ + * The remaining decimal places will get rounded away. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {string} The encoded string. │ │ │ │ + */ │ │ │ │ + encodeFloat: function(num, opt_factor) { │ │ │ │ + num = Math.round(num * (opt_factor || 1e5)); │ │ │ │ + return this.encodeSignedInteger(num); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: decodeFloat │ │ │ │ + * Decode one single floating point number from an encoded string │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * encoded - {string} An encoded string. │ │ │ │ + * opt_factor - {number=} The factor by which the result will be divided. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {number} The decoded floating point number. │ │ │ │ + */ │ │ │ │ + decodeFloat: function(encoded, opt_factor) { │ │ │ │ + var result = this.decodeSignedInteger(encoded); │ │ │ │ + return result / (opt_factor || 1e5); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: encodeSignedInteger │ │ │ │ + * Encode one single signed integer and return an encoded string │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * num - {number} Signed integer that should be encoded. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {string} The encoded string. │ │ │ │ + */ │ │ │ │ + encodeSignedInteger: function(num) { │ │ │ │ + var signedNum = num << 1; │ │ │ │ + if (num < 0) { │ │ │ │ + signedNum = ~(signedNum); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return this.encodeUnsignedInteger(signedNum); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: decodeSignedInteger │ │ │ │ + * Decode one single signed integer from an encoded string │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * encoded - {string} An encoded string. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {number} The decoded signed integer. │ │ │ │ + */ │ │ │ │ + decodeSignedInteger: function(encoded) { │ │ │ │ + var result = this.decodeUnsignedInteger(encoded); │ │ │ │ + return ((result & 1) ? ~(result >> 1) : (result >> 1)); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: encodeUnsignedInteger │ │ │ │ + * Encode one single unsigned integer and return an encoded string │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * num - {number} Unsigned integer that should be encoded. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {string} The encoded string. │ │ │ │ + */ │ │ │ │ + encodeUnsignedInteger: function(num) { │ │ │ │ + var value, encoded = ''; │ │ │ │ + while (num >= 0x20) { │ │ │ │ + value = (0x20 | (num & 0x1f)) + 63; │ │ │ │ + encoded += (String.fromCharCode(value)); │ │ │ │ + num >>= 5; │ │ │ │ + } │ │ │ │ + value = num + 63; │ │ │ │ + encoded += (String.fromCharCode(value)); │ │ │ │ + return encoded; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: decodeUnsignedInteger │ │ │ │ + * Decode one single unsigned integer from an encoded string │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * encoded - {string} An encoded string. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {number} The decoded unsigned integer. │ │ │ │ + */ │ │ │ │ + decodeUnsignedInteger: function(encoded) { │ │ │ │ + var result = 0; │ │ │ │ + var shift = 0; │ │ │ │ + │ │ │ │ + var encodedLength = encoded.length; │ │ │ │ + for (var i = 0; i < encodedLength; ++i) { │ │ │ │ + var b = encoded.charCodeAt(i) - 63; │ │ │ │ + │ │ │ │ + result |= (b & 0x1f) << shift; │ │ │ │ + │ │ │ │ + if (b < 0x20) │ │ │ │ + break; │ │ │ │ + │ │ │ │ + shift += 5; │ │ │ │ + } │ │ │ │ + │ │ │ │ + return result; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.EncodedPolyline" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/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/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/Projection.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.OSM │ │ │ │ + * OSM parser. Create a new instance with the │ │ │ │ + * <OpenLayers.Format.OSM> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.OSM = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: checkTags │ │ │ │ + * {Boolean} Should tags be checked to determine whether something │ │ │ │ + * should be treated as a seperate node. Will slow down parsing. │ │ │ │ + * Default is false. │ │ │ │ + */ │ │ │ │ + checkTags: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: interestingTagsExclude │ │ │ │ + * {Array} List of tags to exclude from 'interesting' checks on nodes. │ │ │ │ + * Must be set when creating the format. Will only be used if checkTags │ │ │ │ + * is set. │ │ │ │ + */ │ │ │ │ + interestingTagsExclude: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: areaTags │ │ │ │ + * {Array} List of tags indicating that something is an area. │ │ │ │ + * Must be set when creating the format. Will only be used if │ │ │ │ + * checkTags is true. │ │ │ │ + */ │ │ │ │ + areaTags: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.OSM │ │ │ │ + * Create a new parser for OSM. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + initialize: function(options) { │ │ │ │ + var layer_defaults = { │ │ │ │ + 'interestingTagsExclude': ['source', 'source_ref', │ │ │ │ + 'source:ref', 'history', 'attribution', 'created_by' │ │ │ │ + ], │ │ │ │ + 'areaTags': ['area', 'building', 'leisure', 'tourism', 'ruins', │ │ │ │ + 'historic', 'landuse', 'military', 'natural', 'sport' │ │ │ │ + ] │ │ │ │ + }; │ │ │ │ + │ │ │ │ + layer_defaults = OpenLayers.Util.extend(layer_defaults, options); │ │ │ │ + │ │ │ │ + var interesting = {}; │ │ │ │ + for (var i = 0; i < layer_defaults.interestingTagsExclude.length; i++) { │ │ │ │ + interesting[layer_defaults.interestingTagsExclude[i]] = true; │ │ │ │ + } │ │ │ │ + layer_defaults.interestingTagsExclude = interesting; │ │ │ │ + │ │ │ │ + var area = {}; │ │ │ │ + for (var i = 0; i < layer_defaults.areaTags.length; i++) { │ │ │ │ + area[layer_defaults.areaTags[i]] = true; │ │ │ │ + } │ │ │ │ + layer_defaults.areaTags = area; │ │ │ │ + │ │ │ │ + // OSM coordinates are always in longlat WGS84 │ │ │ │ + this.externalProjection = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ + │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [layer_defaults]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Return a list of features from a OSM doc │ │ │ │ + │ │ │ │ + * Parameters: │ │ │ │ + * doc - {Element} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ + */ │ │ │ │ + read: function(doc) { │ │ │ │ + if (typeof doc == "string") { │ │ │ │ + doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var nodes = this.getNodes(doc); │ │ │ │ + var ways = this.getWays(doc); │ │ │ │ + │ │ │ │ + // Geoms will contain at least ways.length entries. │ │ │ │ + var feat_list = new Array(ways.length); │ │ │ │ + │ │ │ │ + for (var i = 0; i < ways.length; i++) { │ │ │ │ + // We know the minimal of this one ahead of time. (Could be -1 │ │ │ │ + // due to areas/polygons) │ │ │ │ + var point_list = new Array(ways[i].nodes.length); │ │ │ │ + │ │ │ │ + var poly = this.isWayArea(ways[i]) ? 1 : 0; │ │ │ │ + for (var j = 0; j < ways[i].nodes.length; j++) { │ │ │ │ + var node = nodes[ways[i].nodes[j]]; │ │ │ │ + │ │ │ │ + var point = new OpenLayers.Geometry.Point(node.lon, node.lat); │ │ │ │ + │ │ │ │ + // Since OSM is topological, we stash the node ID internally. │ │ │ │ + point.osm_id = parseInt(ways[i].nodes[j]); │ │ │ │ + point_list[j] = point; │ │ │ │ + │ │ │ │ + // We don't display nodes if they're used inside other │ │ │ │ + // elements. │ │ │ │ + node.used = true; │ │ │ │ + } │ │ │ │ + var geometry = null; │ │ │ │ + if (poly) { │ │ │ │ + geometry = new OpenLayers.Geometry.Polygon( │ │ │ │ + new OpenLayers.Geometry.LinearRing(point_list)); │ │ │ │ + } else { │ │ │ │ + geometry = new OpenLayers.Geometry.LineString(point_list); │ │ │ │ + } │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + geometry.transform(this.externalProjection, │ │ │ │ + this.internalProjection); │ │ │ │ + } │ │ │ │ + var feat = new OpenLayers.Feature.Vector(geometry, │ │ │ │ + ways[i].tags); │ │ │ │ + feat.osm_id = parseInt(ways[i].id); │ │ │ │ + feat.fid = "way." + feat.osm_id; │ │ │ │ + feat_list[i] = feat; │ │ │ │ + } │ │ │ │ + for (var node_id in nodes) { │ │ │ │ + var node = nodes[node_id]; │ │ │ │ + if (!node.used || this.checkTags) { │ │ │ │ + var tags = null; │ │ │ │ + │ │ │ │ + if (this.checkTags) { │ │ │ │ + var result = this.getTags(node.node, true); │ │ │ │ + if (node.used && !result[1]) { │ │ │ │ + continue; │ │ │ │ + } │ │ │ │ + tags = result[0]; │ │ │ │ + } else { │ │ │ │ + tags = this.getTags(node.node); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var feat = new OpenLayers.Feature.Vector( │ │ │ │ + new OpenLayers.Geometry.Point(node['lon'], node['lat']), │ │ │ │ + tags); │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + feat.geometry.transform(this.externalProjection, │ │ │ │ + this.internalProjection); │ │ │ │ + } │ │ │ │ + feat.osm_id = parseInt(node_id); │ │ │ │ + feat.fid = "node." + feat.osm_id; │ │ │ │ + feat_list.push(feat); │ │ │ │ + } │ │ │ │ + // Memory cleanup │ │ │ │ + node.node = null; │ │ │ │ + } │ │ │ │ + return feat_list; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getNodes │ │ │ │ + * Return the node items from a doc. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * doc - {DOMElement} node to parse tags from │ │ │ │ + */ │ │ │ │ + getNodes: function(doc) { │ │ │ │ + var node_list = doc.getElementsByTagName("node"); │ │ │ │ + var nodes = {}; │ │ │ │ + for (var i = 0; i < node_list.length; i++) { │ │ │ │ + var node = node_list[i]; │ │ │ │ + var id = node.getAttribute("id"); │ │ │ │ + nodes[id] = { │ │ │ │ + 'lat': node.getAttribute("lat"), │ │ │ │ + 'lon': node.getAttribute("lon"), │ │ │ │ + 'node': node │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + return nodes; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getWays │ │ │ │ + * Return the way items from a doc. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * doc - {DOMElement} node to parse tags from │ │ │ │ + */ │ │ │ │ + getWays: function(doc) { │ │ │ │ + var way_list = doc.getElementsByTagName("way"); │ │ │ │ + var return_ways = []; │ │ │ │ + for (var i = 0; i < way_list.length; i++) { │ │ │ │ + var way = way_list[i]; │ │ │ │ + var way_object = { │ │ │ │ + id: way.getAttribute("id") │ │ │ │ + }; │ │ │ │ + │ │ │ │ + way_object.tags = this.getTags(way); │ │ │ │ + │ │ │ │ + var node_list = way.getElementsByTagName("nd"); │ │ │ │ + │ │ │ │ + way_object.nodes = new Array(node_list.length); │ │ │ │ + │ │ │ │ + for (var j = 0; j < node_list.length; j++) { │ │ │ │ + way_object.nodes[j] = node_list[j].getAttribute("ref"); │ │ │ │ + } │ │ │ │ + return_ways.push(way_object); │ │ │ │ + } │ │ │ │ + return return_ways; │ │ │ │ + │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getTags │ │ │ │ + * Return the tags list attached to a specific DOM element. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * dom_node - {DOMElement} node to parse tags from │ │ │ │ + * interesting_tags - {Boolean} whether the return from this function should │ │ │ │ + * return a boolean indicating that it has 'interesting tags' -- │ │ │ │ + * tags like attribution and source are ignored. (To change the list │ │ │ │ + * of tags, see interestingTagsExclude) │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * tags - {Object} hash of tags │ │ │ │ + * interesting - {Boolean} if interesting_tags is passed, returns │ │ │ │ + * whether there are any interesting tags on this element. │ │ │ │ + */ │ │ │ │ + getTags: function(dom_node, interesting_tags) { │ │ │ │ + var tag_list = dom_node.getElementsByTagName("tag"); │ │ │ │ + var tags = {}; │ │ │ │ + var interesting = false; │ │ │ │ + for (var j = 0; j < tag_list.length; j++) { │ │ │ │ + var key = tag_list[j].getAttribute("k"); │ │ │ │ + tags[key] = tag_list[j].getAttribute("v"); │ │ │ │ + if (interesting_tags) { │ │ │ │ + if (!this.interestingTagsExclude[key]) { │ │ │ │ + interesting = true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return interesting_tags ? [tags, interesting] : tags; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: isWayArea │ │ │ │ + * Given a way object from getWays, check whether the tags and geometry │ │ │ │ + * indicate something is an area. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} │ │ │ │ + */ │ │ │ │ + isWayArea: function(way) { │ │ │ │ + var poly_shaped = false; │ │ │ │ + var poly_tags = false; │ │ │ │ + │ │ │ │ + if (way.nodes[0] == way.nodes[way.nodes.length - 1]) { │ │ │ │ + poly_shaped = true; │ │ │ │ + } │ │ │ │ + if (this.checkTags) { │ │ │ │ + for (var key in way.tags) { │ │ │ │ + if (this.areaTags[key]) { │ │ │ │ + poly_tags = true; │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return poly_shaped && (this.checkTags ? poly_tags : true); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: write │ │ │ │ + * Takes a list of features, returns a serialized OSM format file for use │ │ │ │ + * in tools like JOSM. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ + */ │ │ │ │ + write: function(features) { │ │ │ │ + if (!(OpenLayers.Util.isArray(features))) { │ │ │ │ + features = [features]; │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.osm_id = 1; │ │ │ │ + this.created_nodes = {}; │ │ │ │ + var root_node = this.createElementNS(null, "osm"); │ │ │ │ + root_node.setAttribute("version", "0.5"); │ │ │ │ + root_node.setAttribute("generator", "OpenLayers " + OpenLayers.VERSION_NUMBER); │ │ │ │ + │ │ │ │ + // Loop backwards, because the deserializer puts nodes last, and │ │ │ │ + // we want them first if possible │ │ │ │ + for (var i = features.length - 1; i >= 0; i--) { │ │ │ │ + var nodes = this.createFeatureNodes(features[i]); │ │ │ │ + for (var j = 0; j < nodes.length; j++) { │ │ │ │ + root_node.appendChild(nodes[j]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [root_node]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: createFeatureNodes │ │ │ │ + * Takes a feature, returns a list of nodes from size 0->n. │ │ │ │ + * Will include all pieces of the serialization that are required which │ │ │ │ + * have not already been created. Calls out to createXML based on geometry │ │ │ │ + * type. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + */ │ │ │ │ + createFeatureNodes: function(feature) { │ │ │ │ + var nodes = []; │ │ │ │ + var className = feature.geometry.CLASS_NAME; │ │ │ │ + var type = className.substring(className.lastIndexOf(".") + 1); │ │ │ │ + type = type.toLowerCase(); │ │ │ │ + var builder = this.createXML[type]; │ │ │ │ + if (builder) { │ │ │ │ + nodes = builder.apply(this, [feature]); │ │ │ │ + } │ │ │ │ + return nodes; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: createXML │ │ │ │ + * Takes a feature, returns a list of nodes from size 0->n. │ │ │ │ + * Will include all pieces of the serialization that are required which │ │ │ │ + * have not already been created. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + */ │ │ │ │ + createXML: { │ │ │ │ + 'point': function(point) { │ │ │ │ + var id = null; │ │ │ │ + var geometry = point.geometry ? point.geometry : point; │ │ │ │ + │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + geometry = geometry.clone(); │ │ │ │ + geometry.transform(this.internalProjection, │ │ │ │ + this.externalProjection); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var already_exists = false; // We don't return anything if the node │ │ │ │ + // has already been created │ │ │ │ + if (point.osm_id) { │ │ │ │ + id = point.osm_id; │ │ │ │ + if (this.created_nodes[id]) { │ │ │ │ + already_exists = true; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + id = -this.osm_id; │ │ │ │ + this.osm_id++; │ │ │ │ + } │ │ │ │ + if (already_exists) { │ │ │ │ + node = this.created_nodes[id]; │ │ │ │ + } else { │ │ │ │ + var node = this.createElementNS(null, "node"); │ │ │ │ + } │ │ │ │ + this.created_nodes[id] = node; │ │ │ │ + node.setAttribute("id", id); │ │ │ │ + node.setAttribute("lon", geometry.x); │ │ │ │ + node.setAttribute("lat", geometry.y); │ │ │ │ + if (point.attributes) { │ │ │ │ + this.serializeTags(point, node); │ │ │ │ + } │ │ │ │ + this.setState(point, node); │ │ │ │ + return already_exists ? [] : [node]; │ │ │ │ + }, │ │ │ │ + linestring: function(feature) { │ │ │ │ + var id; │ │ │ │ + var nodes = []; │ │ │ │ + var geometry = feature.geometry; │ │ │ │ + if (feature.osm_id) { │ │ │ │ + id = feature.osm_id; │ │ │ │ + } else { │ │ │ │ + id = -this.osm_id; │ │ │ │ + this.osm_id++; │ │ │ │ + } │ │ │ │ + var way = this.createElementNS(null, "way"); │ │ │ │ + way.setAttribute("id", id); │ │ │ │ + for (var i = 0; i < geometry.components.length; i++) { │ │ │ │ + var node = this.createXML['point'].apply(this, [geometry.components[i]]); │ │ │ │ + if (node.length) { │ │ │ │ + node = node[0]; │ │ │ │ + var node_ref = node.getAttribute("id"); │ │ │ │ + nodes.push(node); │ │ │ │ + } else { │ │ │ │ + node_ref = geometry.components[i].osm_id; │ │ │ │ + node = this.created_nodes[node_ref]; │ │ │ │ + } │ │ │ │ + this.setState(feature, node); │ │ │ │ + var nd_dom = this.createElementNS(null, "nd"); │ │ │ │ + nd_dom.setAttribute("ref", node_ref); │ │ │ │ + way.appendChild(nd_dom); │ │ │ │ + } │ │ │ │ + this.serializeTags(feature, way); │ │ │ │ + nodes.push(way); │ │ │ │ + │ │ │ │ + return nodes; │ │ │ │ + }, │ │ │ │ + polygon: function(feature) { │ │ │ │ + var attrs = OpenLayers.Util.extend({ │ │ │ │ + 'area': 'yes' │ │ │ │ + }, feature.attributes); │ │ │ │ + var feat = new OpenLayers.Feature.Vector(feature.geometry.components[0], attrs); │ │ │ │ + feat.osm_id = feature.osm_id; │ │ │ │ + return this.createXML['linestring'].apply(this, [feat]); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: serializeTags │ │ │ │ + * Given a feature, serialize the attributes onto the given node. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * node - {DOMNode} │ │ │ │ + */ │ │ │ │ + serializeTags: function(feature, node) { │ │ │ │ + for (var key in feature.attributes) { │ │ │ │ + var tag = this.createElementNS(null, "tag"); │ │ │ │ + tag.setAttribute("k", key); │ │ │ │ + tag.setAttribute("v", feature.attributes[key]); │ │ │ │ + node.appendChild(tag); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setState │ │ │ │ + * OpenStreetMap has a convention that 'state' is stored for modification or deletion. │ │ │ │ + * This allows the file to be uploaded via JOSM or the bulk uploader tool. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * node - {DOMNode} │ │ │ │ */ │ │ │ │ + setState: function(feature, node) { │ │ │ │ + if (feature.state) { │ │ │ │ + var state = null; │ │ │ │ + switch (feature.state) { │ │ │ │ + case OpenLayers.State.UPDATE: │ │ │ │ + state = "modify"; │ │ │ │ + case OpenLayers.State.DELETE: │ │ │ │ + state = "delete"; │ │ │ │ + } │ │ │ │ + if (state) { │ │ │ │ + node.setAttribute("action", state); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities" │ │ │ │ - │ │ │ │ + CLASS_NAME: "OpenLayers.Format.OSM" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Format/CQL.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ @@ -72661,1535 +76201,728 @@ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.CQL" │ │ │ │ │ │ │ │ }); │ │ │ │ })(); │ │ │ │ │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WMC.js │ │ │ │ + OpenLayers/Format/XLS.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/Context.js │ │ │ │ + * @requires OpenLayers/Format/XML/VersionedOGC.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WMC │ │ │ │ - * Read and write Web Map Context documents. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.XLS │ │ │ │ + * Read/Write XLS (OpenLS). Create a new instance with the <OpenLayers.Format.XLS> │ │ │ │ + * constructor. Currently only implemented for Location Utility Services, more │ │ │ │ + * specifically only for Geocoding. No support for Reverse Geocoding as yet. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.Context> │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WMC = OpenLayers.Class(OpenLayers.Format.Context, { │ │ │ │ +OpenLayers.Format.XLS = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ │ │ │ │ /** │ │ │ │ * APIProperty: defaultVersion │ │ │ │ * {String} Version number to assume if none found. Default is "1.1.0". │ │ │ │ */ │ │ │ │ defaultVersion: "1.1.0", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WMC │ │ │ │ - * Create a new parser for Web Map Context documents. │ │ │ │ + * APIProperty: stringifyOutput │ │ │ │ + * {Boolean} If true, write will return a string otherwise a DOMElement. │ │ │ │ + * Default is true. │ │ │ │ + */ │ │ │ │ + stringifyOutput: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.XLS │ │ │ │ + * Create a new parser for XLS. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be set on │ │ │ │ * this instance. │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: layerToContext │ │ │ │ - * Create a layer context object given a wms layer object. │ │ │ │ + * APIMethod: write │ │ │ │ + * Write out an XLS request. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.WMS>} The layer. │ │ │ │ + * request - {Object} An object representing the LUS request. │ │ │ │ + * options - {Object} Optional configuration object. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} A layer context object. │ │ │ │ + * {String} An XLS document string. │ │ │ │ */ │ │ │ │ - layerToContext: function(layer) { │ │ │ │ - var parser = this.getParser(); │ │ │ │ - var layerContext = { │ │ │ │ - queryable: layer.queryable, │ │ │ │ - visibility: layer.visibility, │ │ │ │ - name: layer.params["LAYERS"], │ │ │ │ - title: layer.name, │ │ │ │ - "abstract": layer.metadata["abstract"], │ │ │ │ - dataURL: layer.metadata.dataURL, │ │ │ │ - metadataURL: layer.metadataURL, │ │ │ │ - server: { │ │ │ │ - version: layer.params["VERSION"], │ │ │ │ - url: layer.url │ │ │ │ - }, │ │ │ │ - maxExtent: layer.maxExtent, │ │ │ │ - transparent: layer.params["TRANSPARENT"], │ │ │ │ - numZoomLevels: layer.numZoomLevels, │ │ │ │ - units: layer.units, │ │ │ │ - isBaseLayer: layer.isBaseLayer, │ │ │ │ - opacity: layer.opacity == 1 ? undefined : layer.opacity, │ │ │ │ - displayInLayerSwitcher: layer.displayInLayerSwitcher, │ │ │ │ - singleTile: layer.singleTile, │ │ │ │ - tileSize: (layer.singleTile || !layer.tileSize) ? │ │ │ │ - undefined : { │ │ │ │ - width: layer.tileSize.w, │ │ │ │ - height: layer.tileSize.h │ │ │ │ - }, │ │ │ │ - minScale: (layer.options.resolutions || │ │ │ │ - layer.options.scales || │ │ │ │ - layer.options.maxResolution || │ │ │ │ - layer.options.minScale) ? │ │ │ │ - layer.minScale : undefined, │ │ │ │ - maxScale: (layer.options.resolutions || │ │ │ │ - layer.options.scales || │ │ │ │ - layer.options.minResolution || │ │ │ │ - layer.options.maxScale) ? │ │ │ │ - layer.maxScale : undefined, │ │ │ │ - formats: [], │ │ │ │ - styles: [], │ │ │ │ - srs: layer.srs, │ │ │ │ - dimensions: layer.dimensions │ │ │ │ - }; │ │ │ │ - │ │ │ │ - │ │ │ │ - if (layer.metadata.servertitle) { │ │ │ │ - layerContext.server.title = layer.metadata.servertitle; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (layer.metadata.formats && layer.metadata.formats.length > 0) { │ │ │ │ - for (var i = 0, len = layer.metadata.formats.length; i < len; i++) { │ │ │ │ - var format = layer.metadata.formats[i]; │ │ │ │ - layerContext.formats.push({ │ │ │ │ - value: format.value, │ │ │ │ - current: (format.value == layer.params["FORMAT"]) │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - layerContext.formats.push({ │ │ │ │ - value: layer.params["FORMAT"], │ │ │ │ - current: true │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (layer.metadata.styles && layer.metadata.styles.length > 0) { │ │ │ │ - for (var i = 0, len = layer.metadata.styles.length; i < len; i++) { │ │ │ │ - var style = layer.metadata.styles[i]; │ │ │ │ - if ((style.href == layer.params["SLD"]) || │ │ │ │ - (style.body == layer.params["SLD_BODY"]) || │ │ │ │ - (style.name == layer.params["STYLES"])) { │ │ │ │ - style.current = true; │ │ │ │ - } else { │ │ │ │ - style.current = false; │ │ │ │ - } │ │ │ │ - layerContext.styles.push(style); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - layerContext.styles.push({ │ │ │ │ - href: layer.params["SLD"], │ │ │ │ - body: layer.params["SLD_BODY"], │ │ │ │ - name: layer.params["STYLES"] || parser.defaultStyleName, │ │ │ │ - title: parser.defaultStyleTitle, │ │ │ │ - current: true │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - │ │ │ │ - return layerContext; │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: toContext │ │ │ │ - * Create a context object free from layer given a map or a │ │ │ │ - * context object. │ │ │ │ + * APIMethod: read │ │ │ │ + * Read an XLS doc and return an object representing the result. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * obj - {<OpenLayers.Map> | Object} The map or context. │ │ │ │ + * data - {String | DOMElement} Data to read. │ │ │ │ + * options - {Object} Options for the reader. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} A context object. │ │ │ │ + * {Object} An object representing the GeocodeResponse. │ │ │ │ */ │ │ │ │ - toContext: function(obj) { │ │ │ │ - var context = {}; │ │ │ │ - var layers = obj.layers; │ │ │ │ - if (obj.CLASS_NAME == "OpenLayers.Map") { │ │ │ │ - var metadata = obj.metadata || {}; │ │ │ │ - context.size = obj.getSize(); │ │ │ │ - context.bounds = obj.getExtent(); │ │ │ │ - context.projection = obj.projection; │ │ │ │ - context.title = obj.title; │ │ │ │ - context.keywords = metadata.keywords; │ │ │ │ - context["abstract"] = metadata["abstract"]; │ │ │ │ - context.logo = metadata.logo; │ │ │ │ - context.descriptionURL = metadata.descriptionURL; │ │ │ │ - context.contactInformation = metadata.contactInformation; │ │ │ │ - context.maxExtent = obj.maxExtent; │ │ │ │ - } else { │ │ │ │ - // copy all obj properties except the "layers" property │ │ │ │ - OpenLayers.Util.applyDefaults(context, obj); │ │ │ │ - if (context.layers != undefined) { │ │ │ │ - delete(context.layers); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (context.layersContext == undefined) { │ │ │ │ - context.layersContext = []; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // let's convert layers into layersContext object (if any) │ │ │ │ - if (layers != undefined && OpenLayers.Util.isArray(layers)) { │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - var layer = layers[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.WMS) { │ │ │ │ - context.layersContext.push(this.layerToContext(layer)); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return context; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMC" │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Format.XLS" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WPSCapabilities.js │ │ │ │ + OpenLayers/Format/OWSContext.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/Format/Context.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WPSCapabilities │ │ │ │ - * Read WPS Capabilities. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.OWSContext │ │ │ │ + * Read and write OWS Context documents. OWS Context documents are a │ │ │ │ + * preliminary OGC (Open Geospatial Consortium) standard for storing the │ │ │ │ + * state of a web mapping application. In a way it is the successor to │ │ │ │ + * Web Map Context (WMC), since it is more generic and more types of layers │ │ │ │ + * can be stored. Also, nesting of layers is supported since version 0.3.1. │ │ │ │ + * For more information see: http://www.ogcnetwork.net/context │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ + * - <OpenLayers.Format.Context> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WPSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ +OpenLayers.Format.OWSContext = OpenLayers.Class(OpenLayers.Format.Context, { │ │ │ │ │ │ │ │ /** │ │ │ │ * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "1.0.0". │ │ │ │ + * {String} Version number to assume if none found. Default is "0.3.1". │ │ │ │ */ │ │ │ │ - defaultVersion: "1.0.0", │ │ │ │ + defaultVersion: "0.3.1", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WPSCapabilities │ │ │ │ - * Create a new parser for WPS Capabilities. │ │ │ │ + * Constructor: OpenLayers.Format.OWSContext │ │ │ │ + * Create a new parser for OWS Context documents. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be set on │ │ │ │ * this instance. │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return information about │ │ │ │ - * the service. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * 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: │ │ │ │ - * {Object} Info about the WPS │ │ │ │ + * {String} The version to use. │ │ │ │ */ │ │ │ │ + getVersion: function(root, options) { │ │ │ │ + var version = OpenLayers.Format.XML.VersionedOGC.prototype.getVersion.apply( │ │ │ │ + this, arguments); │ │ │ │ + // 0.3.1 is backwards compatible with 0.3.0 │ │ │ │ + if (version === "0.3.0") { │ │ │ │ + version = this.defaultVersion; │ │ │ │ + } │ │ │ │ + return version; │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WPSCapabilities" │ │ │ │ + /** │ │ │ │ + * Method: toContext │ │ │ │ + * Create a context object free from layer given a map or a │ │ │ │ + * context object. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {<OpenLayers.Map> | Object} The map or context. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} A context object. │ │ │ │ + */ │ │ │ │ + toContext: function(obj) { │ │ │ │ + var context = {}; │ │ │ │ + if (obj.CLASS_NAME == "OpenLayers.Map") { │ │ │ │ + context.bounds = obj.getExtent(); │ │ │ │ + context.maxExtent = obj.maxExtent; │ │ │ │ + context.projection = obj.projection; │ │ │ │ + context.size = obj.getSize(); │ │ │ │ + context.layers = obj.layers; │ │ │ │ + } │ │ │ │ + return context; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.OWSContext" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/EncodedPolyline.js │ │ │ │ + OpenLayers/Format/SOSGetObservation.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 │ │ │ │ - * @requires OpenLayers/Feature/Vector.js │ │ │ │ + * @requires OpenLayers/Format/XML.js │ │ │ │ + * @requires OpenLayers/Format/SOSGetFeatureOfInterest.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.EncodedPolyline │ │ │ │ - * Class for reading and writing encoded polylines. Create a new instance │ │ │ │ - * with the <OpenLayers.Format.EncodedPolyline> constructor. │ │ │ │ + * Class: OpenLayers.Format.SOSGetObservation │ │ │ │ + * Read and write SOS GetObersation (to get the actual values from a sensor) │ │ │ │ + * version 1.0.0 │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format> │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: geometryType │ │ │ │ - * {String} Geometry type to output. One of: linestring (default), │ │ │ │ - * linearring, point, multipoint or polygon. If the geometryType is │ │ │ │ - * point, only the first point of the string is returned. │ │ │ │ - */ │ │ │ │ - geometryType: "linestring", │ │ │ │ +OpenLayers.Format.SOSGetObservation = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.EncodedPolyline │ │ │ │ - * Create a new parser for encoded polylines │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Format.EncodedPolyline>} A new encoded polylines parser. │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.prototype.initialize.apply(this, [options]); │ │ │ │ + namespaces: { │ │ │ │ + ows: "http://www.opengis.net/ows", │ │ │ │ + gml: "http://www.opengis.net/gml", │ │ │ │ + sos: "http://www.opengis.net/sos/1.0", │ │ │ │ + ogc: "http://www.opengis.net/ogc", │ │ │ │ + om: "http://www.opengis.net/om/1.0", │ │ │ │ + sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Deserialize an encoded polyline string and return a vector feature. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * encoded - {String} An encoded polyline string │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} A vector feature with a linestring. │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ */ │ │ │ │ - read: function(encoded) { │ │ │ │ - var geomType; │ │ │ │ - if (this.geometryType == "linestring") │ │ │ │ - geomType = OpenLayers.Geometry.LineString; │ │ │ │ - else if (this.geometryType == "linearring") │ │ │ │ - geomType = OpenLayers.Geometry.LinearRing; │ │ │ │ - else if (this.geometryType == "multipoint") │ │ │ │ - geomType = OpenLayers.Geometry.MultiPoint; │ │ │ │ - else if (this.geometryType != "point" && this.geometryType != "polygon") │ │ │ │ - return null; │ │ │ │ - │ │ │ │ - var flatPoints = this.decodeDeltas(encoded, 2); │ │ │ │ - var flatPointsLength = flatPoints.length; │ │ │ │ - │ │ │ │ - var pointGeometries = []; │ │ │ │ - for (var i = 0; i + 1 < flatPointsLength;) { │ │ │ │ - var y = flatPoints[i++], │ │ │ │ - x = flatPoints[i++]; │ │ │ │ - pointGeometries.push(new OpenLayers.Geometry.Point(x, y)); │ │ │ │ - } │ │ │ │ - │ │ │ │ - │ │ │ │ - if (this.geometryType == "point") │ │ │ │ - return new OpenLayers.Feature.Vector( │ │ │ │ - pointGeometries[0] │ │ │ │ - ); │ │ │ │ - │ │ │ │ - if (this.geometryType == "polygon") │ │ │ │ - return new OpenLayers.Feature.Vector( │ │ │ │ - new OpenLayers.Geometry.Polygon([ │ │ │ │ - new OpenLayers.Geometry.LinearRing(pointGeometries) │ │ │ │ - ]) │ │ │ │ - ); │ │ │ │ - │ │ │ │ - return new OpenLayers.Feature.Vector( │ │ │ │ - new geomType(pointGeometries) │ │ │ │ - ); │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: decode │ │ │ │ - * Deserialize an encoded string and return an array of n-dimensional │ │ │ │ - * points. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * encoded - {String} An encoded string │ │ │ │ - * dims - {int} The dimension of the points that are returned │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array(Array(int))} An array containing n-dimensional arrays of │ │ │ │ - * coordinates. │ │ │ │ + * Constant: VERSION │ │ │ │ + * {String} 1.0.0 │ │ │ │ */ │ │ │ │ - decode: function(encoded, dims, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var flatPoints = this.decodeDeltas(encoded, dims, factor); │ │ │ │ - var flatPointsLength = flatPoints.length; │ │ │ │ - │ │ │ │ - var points = []; │ │ │ │ - for (var i = 0; i + (dims - 1) < flatPointsLength;) { │ │ │ │ - var point = []; │ │ │ │ - │ │ │ │ - for (var dim = 0; dim < dims; ++dim) { │ │ │ │ - point.push(flatPoints[i++]) │ │ │ │ - } │ │ │ │ - │ │ │ │ - points.push(point); │ │ │ │ - } │ │ │ │ - │ │ │ │ - return points; │ │ │ │ - }, │ │ │ │ + VERSION: "1.0.0", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Serialize a feature or array of features into a WKT string. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * features - {<OpenLayers.Feature.Vector>|Array} A feature or array of │ │ │ │ - * features │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} The WKT string representation of the input geometries │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} Schema location │ │ │ │ */ │ │ │ │ - write: function(features) { │ │ │ │ - var feature; │ │ │ │ - if (features.constructor == Array) │ │ │ │ - feature = features[0]; │ │ │ │ - else │ │ │ │ - feature = features; │ │ │ │ - │ │ │ │ - var geometry = feature.geometry; │ │ │ │ - var type = geometry.CLASS_NAME.split('.')[2].toLowerCase(); │ │ │ │ - │ │ │ │ - var pointGeometries; │ │ │ │ - if (type == "point") │ │ │ │ - pointGeometries = new Array(geometry); │ │ │ │ - else if (type == "linestring" || │ │ │ │ - type == "linearring" || │ │ │ │ - type == "multipoint") │ │ │ │ - pointGeometries = geometry.components; │ │ │ │ - else if (type == "polygon") │ │ │ │ - pointGeometries = geometry.components[0].components; │ │ │ │ - else │ │ │ │ - return null; │ │ │ │ - │ │ │ │ - var flatPoints = []; │ │ │ │ - │ │ │ │ - var pointGeometriesLength = pointGeometries.length; │ │ │ │ - for (var i = 0; i < pointGeometriesLength; ++i) { │ │ │ │ - var pointGeometry = pointGeometries[i]; │ │ │ │ - flatPoints.push(pointGeometry.y); │ │ │ │ - flatPoints.push(pointGeometry.x); │ │ │ │ - } │ │ │ │ - │ │ │ │ - return this.encodeDeltas(flatPoints, 2); │ │ │ │ - }, │ │ │ │ + schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosGetObservation.xsd", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: encode │ │ │ │ - * Serialize an array of n-dimensional points and return an encoded string │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * points - {Array(Array(int))} An array containing n-dimensional │ │ │ │ - * arrays of coordinates │ │ │ │ - * dims - {int} The dimension of the points that should be read │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} An encoded string │ │ │ │ + * Property: defaultPrefix │ │ │ │ */ │ │ │ │ - encode: function(points, dims, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var flatPoints = []; │ │ │ │ - │ │ │ │ - var pointsLength = points.length; │ │ │ │ - for (var i = 0; i < pointsLength; ++i) { │ │ │ │ - var point = points[i]; │ │ │ │ - │ │ │ │ - for (var dim = 0; dim < dims; ++dim) { │ │ │ │ - flatPoints.push(point[dim]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return this.encodeDeltas(flatPoints, dims, factor); │ │ │ │ - }, │ │ │ │ + defaultPrefix: "sos", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: encodeDeltas │ │ │ │ - * Encode a list of n-dimensional points and return an encoded string │ │ │ │ - * │ │ │ │ - * Attention: This function will modify the passed array! │ │ │ │ + * Constructor: OpenLayers.Format.SOSGetObservation │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * numbers - {Array.<number>} A list of n-dimensional points. │ │ │ │ - * dimension - {number} The dimension of the points in the list. │ │ │ │ - * opt_factor - {number=} The factor by which the numbers will be │ │ │ │ - * multiplied. The remaining decimal places will get rounded away. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {string} The encoded string. │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ */ │ │ │ │ - encodeDeltas: function(numbers, dimension, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var d; │ │ │ │ - │ │ │ │ - var lastNumbers = new Array(dimension); │ │ │ │ - for (d = 0; d < dimension; ++d) { │ │ │ │ - lastNumbers[d] = 0; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength;) { │ │ │ │ - for (d = 0; d < dimension; ++d, ++i) { │ │ │ │ - var num = numbers[i]; │ │ │ │ - var delta = num - lastNumbers[d]; │ │ │ │ - lastNumbers[d] = num; │ │ │ │ - │ │ │ │ - numbers[i] = delta; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return this.encodeFloats(numbers, factor); │ │ │ │ - }, │ │ │ │ - │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: decodeDeltas │ │ │ │ - * Decode a list of n-dimensional points from an encoded string │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * encoded - {string} An encoded string. │ │ │ │ - * dimension - {number} The dimension of the points in the encoded string. │ │ │ │ - * opt_factor - {number=} The factor by which the resulting numbers will │ │ │ │ - * be divided. │ │ │ │ + * Method: read │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Array.<number>} A list of n-dimensional points. │ │ │ │ + * {Object} An object containing the measurements │ │ │ │ */ │ │ │ │ - decodeDeltas: function(encoded, dimension, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var d; │ │ │ │ - │ │ │ │ - var lastNumbers = new Array(dimension); │ │ │ │ - for (d = 0; d < dimension; ++d) { │ │ │ │ - lastNumbers[d] = 0; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var numbers = this.decodeFloats(encoded, factor); │ │ │ │ - │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength;) { │ │ │ │ - for (d = 0; d < dimension; ++d, ++i) { │ │ │ │ - lastNumbers[d] += numbers[i]; │ │ │ │ - │ │ │ │ - numbers[i] = lastNumbers[d]; │ │ │ │ - } │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ } │ │ │ │ - │ │ │ │ - return numbers; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: encodeFloats │ │ │ │ - * Encode a list of floating point numbers and return an encoded string │ │ │ │ - * │ │ │ │ - * Attention: This function will modify the passed array! │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * numbers - {Array.<number>} A list of floating point numbers. │ │ │ │ - * opt_factor - {number=} The factor by which the numbers will be │ │ │ │ - * multiplied. The remaining decimal places will get rounded away. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {string} The encoded string. │ │ │ │ - */ │ │ │ │ - encodeFloats: function(numbers, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength; ++i) { │ │ │ │ - numbers[i] = Math.round(numbers[i] * factor); │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement; │ │ │ │ } │ │ │ │ - │ │ │ │ - return this.encodeSignedIntegers(numbers); │ │ │ │ + var info = { │ │ │ │ + measurements: [], │ │ │ │ + observations: [] │ │ │ │ + }; │ │ │ │ + this.readNode(data, info); │ │ │ │ + return info; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: decodeFloats │ │ │ │ - * Decode a list of floating point numbers from an encoded string │ │ │ │ + * Method: write │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * encoded - {string} An encoded string. │ │ │ │ - * opt_factor - {number=} The factor by which the result will be divided. │ │ │ │ + * options - {Object} Optional object. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Array.<number>} A list of floating point numbers. │ │ │ │ + * {String} An SOS GetObservation request XML string. │ │ │ │ */ │ │ │ │ - decodeFloats: function(encoded, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - │ │ │ │ - var numbers = this.decodeSignedIntegers(encoded); │ │ │ │ - │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength; ++i) { │ │ │ │ - numbers[i] /= factor; │ │ │ │ - } │ │ │ │ - │ │ │ │ - return numbers; │ │ │ │ + write: function(options) { │ │ │ │ + var node = this.writeNode("sos:GetObservation", options); │ │ │ │ + node.setAttribute("xmlns:om", this.namespaces.om); │ │ │ │ + node.setAttribute("xmlns:ogc", this.namespaces.ogc); │ │ │ │ + this.setAttributeNS( │ │ │ │ + node, this.namespaces.xsi, │ │ │ │ + "xsi:schemaLocation", this.schemaLocation │ │ │ │ + ); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [node]); │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: encodeSignedIntegers │ │ │ │ - * Encode a list of signed integers and return an encoded string │ │ │ │ - * │ │ │ │ - * Attention: This function will modify the passed array! │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * numbers - {Array.<number>} A list of signed integers. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {string} The encoded string. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - encodeSignedIntegers: function(numbers) { │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength; ++i) { │ │ │ │ - var num = numbers[i]; │ │ │ │ - │ │ │ │ - var signedNum = num << 1; │ │ │ │ - if (num < 0) { │ │ │ │ - signedNum = ~(signedNum); │ │ │ │ + readers: { │ │ │ │ + "om": { │ │ │ │ + "ObservationCollection": function(node, obj) { │ │ │ │ + obj.id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "member": function(node, observationCollection) { │ │ │ │ + this.readChildNodes(node, observationCollection); │ │ │ │ + }, │ │ │ │ + "Measurement": function(node, observationCollection) { │ │ │ │ + var measurement = {}; │ │ │ │ + observationCollection.measurements.push(measurement); │ │ │ │ + this.readChildNodes(node, measurement); │ │ │ │ + }, │ │ │ │ + "Observation": function(node, observationCollection) { │ │ │ │ + var observation = {}; │ │ │ │ + observationCollection.observations.push(observation); │ │ │ │ + this.readChildNodes(node, observation); │ │ │ │ + }, │ │ │ │ + "samplingTime": function(node, measurement) { │ │ │ │ + var samplingTime = {}; │ │ │ │ + measurement.samplingTime = samplingTime; │ │ │ │ + this.readChildNodes(node, samplingTime); │ │ │ │ + }, │ │ │ │ + "observedProperty": function(node, measurement) { │ │ │ │ + measurement.observedProperty = │ │ │ │ + this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ + this.readChildNodes(node, measurement); │ │ │ │ + }, │ │ │ │ + "procedure": function(node, measurement) { │ │ │ │ + measurement.procedure = │ │ │ │ + this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ + this.readChildNodes(node, measurement); │ │ │ │ + }, │ │ │ │ + "featureOfInterest": function(node, observation) { │ │ │ │ + var foi = { │ │ │ │ + features: [] │ │ │ │ + }; │ │ │ │ + observation.fois = []; │ │ │ │ + observation.fois.push(foi); │ │ │ │ + this.readChildNodes(node, foi); │ │ │ │ + // postprocessing to get actual features │ │ │ │ + var features = []; │ │ │ │ + for (var i = 0, len = foi.features.length; i < len; i++) { │ │ │ │ + var feature = foi.features[i]; │ │ │ │ + features.push(new OpenLayers.Feature.Vector( │ │ │ │ + feature.components[0], feature.attributes)); │ │ │ │ + } │ │ │ │ + foi.features = features; │ │ │ │ + }, │ │ │ │ + "result": function(node, measurement) { │ │ │ │ + var result = {}; │ │ │ │ + measurement.result = result; │ │ │ │ + if (this.getChildValue(node) !== '') { │ │ │ │ + result.value = this.getChildValue(node); │ │ │ │ + result.uom = node.getAttribute("uom"); │ │ │ │ + } else { │ │ │ │ + this.readChildNodes(node, result); │ │ │ │ + } │ │ │ │ } │ │ │ │ - │ │ │ │ - numbers[i] = signedNum; │ │ │ │ - } │ │ │ │ - │ │ │ │ - return this.encodeUnsignedIntegers(numbers); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: decodeSignedIntegers │ │ │ │ - * Decode a list of signed integers from an encoded string │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * encoded - {string} An encoded string. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array.<number>} A list of signed integers. │ │ │ │ - */ │ │ │ │ - decodeSignedIntegers: function(encoded) { │ │ │ │ - var numbers = this.decodeUnsignedIntegers(encoded); │ │ │ │ - │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength; ++i) { │ │ │ │ - var num = numbers[i]; │ │ │ │ - numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1); │ │ │ │ - } │ │ │ │ - │ │ │ │ - return numbers; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: encodeUnsignedIntegers │ │ │ │ - * Encode a list of unsigned integers and return an encoded string │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * numbers - {Array.<number>} A list of unsigned integers. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {string} The encoded string. │ │ │ │ - */ │ │ │ │ - encodeUnsignedIntegers: function(numbers) { │ │ │ │ - var encoded = ''; │ │ │ │ - │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength; ++i) { │ │ │ │ - encoded += this.encodeUnsignedInteger(numbers[i]); │ │ │ │ - } │ │ │ │ - │ │ │ │ - return encoded; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: decodeUnsignedIntegers │ │ │ │ - * Decode a list of unsigned integers from an encoded string │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * encoded - {string} An encoded string. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array.<number>} A list of unsigned integers. │ │ │ │ - */ │ │ │ │ - decodeUnsignedIntegers: function(encoded) { │ │ │ │ - var numbers = []; │ │ │ │ - │ │ │ │ - var current = 0; │ │ │ │ - var shift = 0; │ │ │ │ - │ │ │ │ - var encodedLength = encoded.length; │ │ │ │ - for (var i = 0; i < encodedLength; ++i) { │ │ │ │ - var b = encoded.charCodeAt(i) - 63; │ │ │ │ - │ │ │ │ - current |= (b & 0x1f) << shift; │ │ │ │ - │ │ │ │ - if (b < 0x20) { │ │ │ │ - numbers.push(current); │ │ │ │ - current = 0; │ │ │ │ - shift = 0; │ │ │ │ - } else { │ │ │ │ - shift += 5; │ │ │ │ + }, │ │ │ │ + "sa": OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.sa, │ │ │ │ + "gml": OpenLayers.Util.applyDefaults({ │ │ │ │ + "TimeInstant": function(node, samplingTime) { │ │ │ │ + var timeInstant = {}; │ │ │ │ + samplingTime.timeInstant = timeInstant; │ │ │ │ + this.readChildNodes(node, timeInstant); │ │ │ │ + }, │ │ │ │ + "timePosition": function(node, timeInstant) { │ │ │ │ + timeInstant.timePosition = this.getChildValue(node); │ │ │ │ } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return numbers; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: encodeFloat │ │ │ │ - * Encode one single floating point number and return an encoded string │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * num - {number} Floating point number that should be encoded. │ │ │ │ - * opt_factor - {number=} The factor by which num will be multiplied. │ │ │ │ - * The remaining decimal places will get rounded away. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {string} The encoded string. │ │ │ │ - */ │ │ │ │ - encodeFloat: function(num, opt_factor) { │ │ │ │ - num = Math.round(num * (opt_factor || 1e5)); │ │ │ │ - return this.encodeSignedInteger(num); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: decodeFloat │ │ │ │ - * Decode one single floating point number from an encoded string │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * encoded - {string} An encoded string. │ │ │ │ - * opt_factor - {number=} The factor by which the result will be divided. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {number} The decoded floating point number. │ │ │ │ - */ │ │ │ │ - decodeFloat: function(encoded, opt_factor) { │ │ │ │ - var result = this.decodeSignedInteger(encoded); │ │ │ │ - return result / (opt_factor || 1e5); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: encodeSignedInteger │ │ │ │ - * Encode one single signed integer and return an encoded string │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * num - {number} Signed integer that should be encoded. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {string} The encoded string. │ │ │ │ - */ │ │ │ │ - encodeSignedInteger: function(num) { │ │ │ │ - var signedNum = num << 1; │ │ │ │ - if (num < 0) { │ │ │ │ - signedNum = ~(signedNum); │ │ │ │ - } │ │ │ │ - │ │ │ │ - return this.encodeUnsignedInteger(signedNum); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: decodeSignedInteger │ │ │ │ - * Decode one single signed integer from an encoded string │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * encoded - {string} An encoded string. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {number} The decoded signed integer. │ │ │ │ - */ │ │ │ │ - decodeSignedInteger: function(encoded) { │ │ │ │ - var result = this.decodeUnsignedInteger(encoded); │ │ │ │ - return ((result & 1) ? ~(result >> 1) : (result >> 1)); │ │ │ │ + }, OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.gml) │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: encodeUnsignedInteger │ │ │ │ - * Encode one single unsigned integer and return an encoded string │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * num - {number} Unsigned integer that should be encoded. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {string} The encoded string. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - encodeUnsignedInteger: function(num) { │ │ │ │ - var value, encoded = ''; │ │ │ │ - while (num >= 0x20) { │ │ │ │ - value = (0x20 | (num & 0x1f)) + 63; │ │ │ │ - encoded += (String.fromCharCode(value)); │ │ │ │ - num >>= 5; │ │ │ │ + writers: { │ │ │ │ + "sos": { │ │ │ │ + "GetObservation": function(options) { │ │ │ │ + var node = this.createElementNSPlus("GetObservation", { │ │ │ │ + attributes: { │ │ │ │ + version: this.VERSION, │ │ │ │ + service: 'SOS' │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.writeNode("offering", options, node); │ │ │ │ + if (options.eventTime) { │ │ │ │ + this.writeNode("eventTime", options, node); │ │ │ │ + } │ │ │ │ + for (var procedure in options.procedures) { │ │ │ │ + this.writeNode("procedure", options.procedures[procedure], node); │ │ │ │ + } │ │ │ │ + for (var observedProperty in options.observedProperties) { │ │ │ │ + this.writeNode("observedProperty", options.observedProperties[observedProperty], node); │ │ │ │ + } │ │ │ │ + if (options.foi) { │ │ │ │ + this.writeNode("featureOfInterest", options.foi, node); │ │ │ │ + } │ │ │ │ + this.writeNode("responseFormat", options, node); │ │ │ │ + if (options.resultModel) { │ │ │ │ + this.writeNode("resultModel", options, node); │ │ │ │ + } │ │ │ │ + if (options.responseMode) { │ │ │ │ + this.writeNode("responseMode", options, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "featureOfInterest": function(foi) { │ │ │ │ + var node = this.createElementNSPlus("featureOfInterest"); │ │ │ │ + this.writeNode("ObjectID", foi.objectId, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ObjectID": function(options) { │ │ │ │ + return this.createElementNSPlus("ObjectID", { │ │ │ │ + value: options │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "responseFormat": function(options) { │ │ │ │ + return this.createElementNSPlus("responseFormat", { │ │ │ │ + value: options.responseFormat │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "procedure": function(procedure) { │ │ │ │ + return this.createElementNSPlus("procedure", { │ │ │ │ + value: procedure │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "offering": function(options) { │ │ │ │ + return this.createElementNSPlus("offering", { │ │ │ │ + value: options.offering │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "observedProperty": function(observedProperty) { │ │ │ │ + return this.createElementNSPlus("observedProperty", { │ │ │ │ + value: observedProperty │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "eventTime": function(options) { │ │ │ │ + var node = this.createElementNSPlus("eventTime"); │ │ │ │ + if (options.eventTime === 'latest') { │ │ │ │ + this.writeNode("ogc:TM_Equals", options, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "resultModel": function(options) { │ │ │ │ + return this.createElementNSPlus("resultModel", { │ │ │ │ + value: options.resultModel │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "responseMode": function(options) { │ │ │ │ + return this.createElementNSPlus("responseMode", { │ │ │ │ + value: options.responseMode │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "ogc": { │ │ │ │ + "TM_Equals": function(options) { │ │ │ │ + var node = this.createElementNSPlus("ogc:TM_Equals"); │ │ │ │ + this.writeNode("ogc:PropertyName", { │ │ │ │ + property: "urn:ogc:data:time:iso8601" │ │ │ │ + }, node); │ │ │ │ + if (options.eventTime === 'latest') { │ │ │ │ + this.writeNode("gml:TimeInstant", { │ │ │ │ + value: 'latest' │ │ │ │ + }, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "PropertyName": function(options) { │ │ │ │ + return this.createElementNSPlus("ogc:PropertyName", { │ │ │ │ + value: options.property │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "gml": { │ │ │ │ + "TimeInstant": function(options) { │ │ │ │ + var node = this.createElementNSPlus("gml:TimeInstant"); │ │ │ │ + this.writeNode("gml:timePosition", options, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "timePosition": function(options) { │ │ │ │ + var node = this.createElementNSPlus("gml:timePosition", { │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + } │ │ │ │ } │ │ │ │ - value = num + 63; │ │ │ │ - encoded += (String.fromCharCode(value)); │ │ │ │ - return encoded; │ │ │ │ }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SOSGetObservation" │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: decodeUnsignedInteger │ │ │ │ - * Decode one single unsigned integer from an encoded string │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * encoded - {string} An encoded string. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {number} The decoded unsigned integer. │ │ │ │ - */ │ │ │ │ - decodeUnsignedInteger: function(encoded) { │ │ │ │ - var result = 0; │ │ │ │ - var shift = 0; │ │ │ │ - │ │ │ │ - var encodedLength = encoded.length; │ │ │ │ - for (var i = 0; i < encodedLength; ++i) { │ │ │ │ - var b = encoded.charCodeAt(i) - 63; │ │ │ │ - │ │ │ │ - result |= (b & 0x1f) << shift; │ │ │ │ - │ │ │ │ - if (b < 0x20) │ │ │ │ - break; │ │ │ │ - │ │ │ │ - shift += 5; │ │ │ │ - } │ │ │ │ - │ │ │ │ - return result; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.EncodedPolyline" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/Atom.js │ │ │ │ + OpenLayers/Format/WMTSCapabilities.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/v3.js │ │ │ │ - * @requires OpenLayers/Feature/Vector.js │ │ │ │ + * @requires OpenLayers/Format/XML/VersionedOGC.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.Atom │ │ │ │ - * Read/write Atom feeds. Create a new instance with the │ │ │ │ - * <OpenLayers.Format.AtomFeed> constructor. │ │ │ │ + * Class: OpenLayers.Format.WMTSCapabilities │ │ │ │ + * Read WMTS Capabilities. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.Atom = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - atom: "http://www.w3.org/2005/Atom", │ │ │ │ - georss: "http://www.georss.org/georss" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: feedTitle │ │ │ │ - * {String} Atom feed elements require a title. Default is "untitled". │ │ │ │ - */ │ │ │ │ - feedTitle: "untitled", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: defaultEntryTitle │ │ │ │ - * {String} Atom entry elements require a title. In cases where one is │ │ │ │ - * not provided in the feature attributes, this will be used. Default │ │ │ │ - * is "untitled". │ │ │ │ - */ │ │ │ │ - defaultEntryTitle: "untitled", │ │ │ │ +OpenLayers.Format.WMTSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: gmlParse │ │ │ │ - * {Object} GML Format object for parsing features │ │ │ │ - * Non-API and only created if necessary │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "1.0.0". │ │ │ │ */ │ │ │ │ - gmlParser: null, │ │ │ │ + defaultVersion: "1.0.0", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: xy │ │ │ │ - * {Boolean} Order of the GML coordinate: true:(x,y) or false:(y,x) │ │ │ │ - * For GeoRSS the default is (y,x), therefore: false │ │ │ │ + * APIProperty: yx │ │ │ │ + * {Object} Members in the yx object are used to determine if a CRS URN │ │ │ │ + * corresponds to a CRS with y,x axis order. Member names are CRS URNs │ │ │ │ + * and values are boolean. By default, the following CRS URN are │ │ │ │ + * assumed to correspond to a CRS with y,x axis order: │ │ │ │ + * │ │ │ │ + * * urn:ogc:def:crs:EPSG::4326 │ │ │ │ */ │ │ │ │ - xy: false, │ │ │ │ + yx: { │ │ │ │ + "urn:ogc:def:crs:EPSG::4326": true │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.AtomEntry │ │ │ │ - * Create a new parser for Atom. │ │ │ │ + * Constructor: OpenLayers.Format.WMTSCapabilities │ │ │ │ + * Create a new parser for WMTS capabilities. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be set on │ │ │ │ * this instance. │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: read │ │ │ │ - * Return a list of features from an Atom feed or entry document. │ │ │ │ - │ │ │ │ - * Parameters: │ │ │ │ - * doc - {Element} or {String} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ - */ │ │ │ │ - read: function(doc) { │ │ │ │ - if (typeof doc == "string") { │ │ │ │ - doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]); │ │ │ │ - } │ │ │ │ - return this.parseFeatures(doc); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Serialize or more feature nodes to Atom documents. │ │ │ │ + * Read capabilities data from a string, and return information about │ │ │ │ + * the service (offering and observedProperty mostly). │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * features - {<OpenLayers.Feature.Vector>} or Array({<OpenLayers.Feature.Vector>}) │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} an Atom entry document if passed one feature node, or a feed │ │ │ │ - * document if passed an array of feature nodes. │ │ │ │ + * {Object} Info about the WMTS Capabilities │ │ │ │ */ │ │ │ │ - write: function(features) { │ │ │ │ - var doc; │ │ │ │ - if (OpenLayers.Util.isArray(features)) { │ │ │ │ - doc = this.createElementNSPlus("atom:feed"); │ │ │ │ - doc.appendChild( │ │ │ │ - this.createElementNSPlus("atom:title", { │ │ │ │ - value: this.feedTitle │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - for (var i = 0, ii = features.length; i < ii; i++) { │ │ │ │ - doc.appendChild(this.buildEntryNode(features[i])); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - doc = this.buildEntryNode(features); │ │ │ │ - } │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [doc]); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: buildContentNode │ │ │ │ + * APIMethod: createLayer │ │ │ │ + * Create a WMTS layer given a capabilities object. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * content - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} an Atom content node. │ │ │ │ + * capabilities - {Object} The object returned from a <read> call to this │ │ │ │ + * format. │ │ │ │ + * config - {Object} Configuration properties for the layer. Defaults for │ │ │ │ + * the layer will apply if not provided. │ │ │ │ * │ │ │ │ - * TODO: types other than text. │ │ │ │ - */ │ │ │ │ - buildContentNode: function(content) { │ │ │ │ - var node = this.createElementNSPlus("atom:content", { │ │ │ │ - attributes: { │ │ │ │ - type: content.type || null │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (content.src) { │ │ │ │ - node.setAttribute("src", content.src); │ │ │ │ - } else { │ │ │ │ - if (content.type == "text" || content.type == null) { │ │ │ │ - node.appendChild( │ │ │ │ - this.createTextNode(content.value) │ │ │ │ - ); │ │ │ │ - } else if (content.type == "html") { │ │ │ │ - if (typeof content.value != "string") { │ │ │ │ - throw "HTML content must be in form of an escaped string"; │ │ │ │ - } │ │ │ │ - node.appendChild( │ │ │ │ - this.createTextNode(content.value) │ │ │ │ - ); │ │ │ │ - } else if (content.type == "xhtml") { │ │ │ │ - node.appendChild(content.value); │ │ │ │ - } else if (content.type == "xhtml" || │ │ │ │ - content.type.match(/(\+|\/)xml$/)) { │ │ │ │ - node.appendChild(content.value); │ │ │ │ - } else { // MUST be a valid Base64 encoding │ │ │ │ - node.appendChild( │ │ │ │ - this.createTextNode(content.value) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: buildEntryNode │ │ │ │ - * Build an Atom entry node from a feature object. │ │ │ │ + * Required config properties: │ │ │ │ + * layer - {String} The layer identifier. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * Optional config properties: │ │ │ │ + * matrixSet - {String} The matrix set identifier, required if there is │ │ │ │ + * more than one matrix set in the layer capabilities. │ │ │ │ + * style - {String} The name of the style │ │ │ │ + * format - {String} Image format for the layer. Default is the first │ │ │ │ + * format returned in the GetCapabilities response. │ │ │ │ + * param - {Object} The dimensions values eg: {"Year": "2012"} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} an Atom entry node. │ │ │ │ - * │ │ │ │ - * These entries are geared for publication using AtomPub. │ │ │ │ - * │ │ │ │ - * TODO: support extension elements │ │ │ │ + * {<OpenLayers.Layer.WMTS>} A properly configured WMTS layer. Throws an │ │ │ │ + * error if an incomplete config is provided. Returns undefined if no │ │ │ │ + * layer could be created with the provided config. │ │ │ │ */ │ │ │ │ - buildEntryNode: function(feature) { │ │ │ │ - var attrib = feature.attributes; │ │ │ │ - var atomAttrib = attrib.atom || {}; │ │ │ │ - var entryNode = this.createElementNSPlus("atom:entry"); │ │ │ │ - │ │ │ │ - // atom:author │ │ │ │ - if (atomAttrib.authors) { │ │ │ │ - var authors = OpenLayers.Util.isArray(atomAttrib.authors) ? │ │ │ │ - atomAttrib.authors : [atomAttrib.authors]; │ │ │ │ - for (var i = 0, ii = authors.length; i < ii; i++) { │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.buildPersonConstructNode( │ │ │ │ - "author", authors[i] │ │ │ │ - ) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atom:category │ │ │ │ - if (atomAttrib.categories) { │ │ │ │ - var categories = OpenLayers.Util.isArray(atomAttrib.categories) ? │ │ │ │ - atomAttrib.categories : [atomAttrib.categories]; │ │ │ │ - var category; │ │ │ │ - for (var i = 0, ii = categories.length; i < ii; i++) { │ │ │ │ - category = categories[i]; │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:category", { │ │ │ │ - attributes: { │ │ │ │ - term: category.term, │ │ │ │ - scheme: category.scheme || null, │ │ │ │ - label: category.label || null │ │ │ │ - } │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atom:content │ │ │ │ - if (atomAttrib.content) { │ │ │ │ - entryNode.appendChild(this.buildContentNode(atomAttrib.content)); │ │ │ │ - } │ │ │ │ + createLayer: function(capabilities, config) { │ │ │ │ + var layer; │ │ │ │ │ │ │ │ - // atom:contributor │ │ │ │ - if (atomAttrib.contributors) { │ │ │ │ - var contributors = OpenLayers.Util.isArray(atomAttrib.contributors) ? │ │ │ │ - atomAttrib.contributors : [atomAttrib.contributors]; │ │ │ │ - for (var i = 0, ii = contributors.length; i < ii; i++) { │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.buildPersonConstructNode( │ │ │ │ - "contributor", │ │ │ │ - contributors[i] │ │ │ │ - ) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + // confirm required properties are supplied in config │ │ │ │ + if (!('layer' in config)) { │ │ │ │ + throw new Error("Missing property 'layer' in configuration."); │ │ │ │ } │ │ │ │ │ │ │ │ - // atom:id │ │ │ │ - if (feature.fid) { │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:id", { │ │ │ │ - value: feature.fid │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + var contents = capabilities.contents; │ │ │ │ │ │ │ │ - // atom:link │ │ │ │ - if (atomAttrib.links) { │ │ │ │ - var links = OpenLayers.Util.isArray(atomAttrib.links) ? │ │ │ │ - atomAttrib.links : [atomAttrib.links]; │ │ │ │ - var link; │ │ │ │ - for (var i = 0, ii = links.length; i < ii; i++) { │ │ │ │ - link = links[i]; │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:link", { │ │ │ │ - attributes: { │ │ │ │ - href: link.href, │ │ │ │ - rel: link.rel || null, │ │ │ │ - type: link.type || null, │ │ │ │ - hreflang: link.hreflang || null, │ │ │ │ - title: link.title || null, │ │ │ │ - length: link.length || null │ │ │ │ - } │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ + // find the layer definition with the given identifier │ │ │ │ + var layers = contents.layers; │ │ │ │ + var layerDef; │ │ │ │ + for (var i = 0, ii = contents.layers.length; i < ii; ++i) { │ │ │ │ + if (contents.layers[i].identifier === config.layer) { │ │ │ │ + layerDef = contents.layers[i]; │ │ │ │ + break; │ │ │ │ } │ │ │ │ } │ │ │ │ - │ │ │ │ - // atom:published │ │ │ │ - if (atomAttrib.published) { │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:published", { │ │ │ │ - value: atomAttrib.published │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atom:rights │ │ │ │ - if (atomAttrib.rights) { │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:rights", { │ │ │ │ - value: atomAttrib.rights │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atom:source not implemented │ │ │ │ - │ │ │ │ - // atom:summary │ │ │ │ - if (atomAttrib.summary || attrib.description) { │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:summary", { │ │ │ │ - value: atomAttrib.summary || attrib.description │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atom:title │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:title", { │ │ │ │ - value: atomAttrib.title || attrib.title || this.defaultEntryTitle │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - │ │ │ │ - // atom:updated │ │ │ │ - if (atomAttrib.updated) { │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:updated", { │ │ │ │ - value: atomAttrib.updated │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // georss:where │ │ │ │ - if (feature.geometry) { │ │ │ │ - var whereNode = this.createElementNSPlus("georss:where"); │ │ │ │ - whereNode.appendChild( │ │ │ │ - this.buildGeometryNode(feature.geometry) │ │ │ │ - ); │ │ │ │ - entryNode.appendChild(whereNode); │ │ │ │ - } │ │ │ │ - │ │ │ │ - return entryNode; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: initGmlParser │ │ │ │ - * Creates a GML parser. │ │ │ │ - */ │ │ │ │ - initGmlParser: function() { │ │ │ │ - this.gmlParser = new OpenLayers.Format.GML.v3({ │ │ │ │ - xy: this.xy, │ │ │ │ - featureNS: "http://example.com#feature", │ │ │ │ - internalProjection: this.internalProjection, │ │ │ │ - externalProjection: this.externalProjection │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: buildGeometryNode │ │ │ │ - * builds a GeoRSS node with a given geometry │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A gml node. │ │ │ │ - */ │ │ │ │ - buildGeometryNode: function(geometry) { │ │ │ │ - if (!this.gmlParser) { │ │ │ │ - this.initGmlParser(); │ │ │ │ - } │ │ │ │ - var node = this.gmlParser.writeNode("feature:_geometry", geometry); │ │ │ │ - return node.firstChild; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: buildPersonConstructNode │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * value - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} an Atom person construct node. │ │ │ │ - * │ │ │ │ - * Example: │ │ │ │ - * >>> buildPersonConstructNode("author", {name: "John Smith"}) │ │ │ │ - * {<author><name>John Smith</name></author>} │ │ │ │ - * │ │ │ │ - * TODO: how to specify extension elements? Add to the oNames array? │ │ │ │ - */ │ │ │ │ - buildPersonConstructNode: function(name, value) { │ │ │ │ - var oNames = ["uri", "email"]; │ │ │ │ - var personNode = this.createElementNSPlus("atom:" + name); │ │ │ │ - personNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:name", { │ │ │ │ - value: value.name │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - for (var i = 0, ii = oNames.length; i < ii; i++) { │ │ │ │ - if (value[oNames[i]]) { │ │ │ │ - personNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:" + oNames[i], { │ │ │ │ - value: value[oNames[i]] │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + if (!layerDef) { │ │ │ │ + throw new Error("Layer not found"); │ │ │ │ } │ │ │ │ - return personNode; │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getFirstChildValue │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * nsuri - {String} Child node namespace uri ("*" for any). │ │ │ │ - * name - {String} Child node name. │ │ │ │ - * def - {String} Optional string default to return if no child found. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} The value of the first child with the given tag name. Returns │ │ │ │ - * default value or empty string if none found. │ │ │ │ - */ │ │ │ │ - getFirstChildValue: function(node, nsuri, name, def) { │ │ │ │ - var value; │ │ │ │ - var nodes = this.getElementsByTagNameNS(node, nsuri, name); │ │ │ │ - if (nodes && nodes.length > 0) { │ │ │ │ - value = this.getChildValue(nodes[0], def); │ │ │ │ - } else { │ │ │ │ - value = def; │ │ │ │ + var format = config.format; │ │ │ │ + if (!format && layerDef.formats && layerDef.formats.length) { │ │ │ │ + format = layerDef.formats[0]; │ │ │ │ } │ │ │ │ - return value; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: parseFeature │ │ │ │ - * Parse feature from an Atom entry node.. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} An Atom entry or feed node. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - parseFeature: function(node) { │ │ │ │ - var atomAttrib = {}; │ │ │ │ - var value = null; │ │ │ │ - var nodes = null; │ │ │ │ - var attval = null; │ │ │ │ - var atomns = this.namespaces.atom; │ │ │ │ - │ │ │ │ - // atomAuthor* │ │ │ │ - this.parsePersonConstructs(node, "author", atomAttrib); │ │ │ │ │ │ │ │ - // atomCategory* │ │ │ │ - nodes = this.getElementsByTagNameNS(node, atomns, "category"); │ │ │ │ - if (nodes.length > 0) { │ │ │ │ - atomAttrib.categories = []; │ │ │ │ + // find the matrixSet definition │ │ │ │ + var matrixSet; │ │ │ │ + if (config.matrixSet) { │ │ │ │ + matrixSet = contents.tileMatrixSets[config.matrixSet]; │ │ │ │ + } else if (layerDef.tileMatrixSetLinks.length >= 1) { │ │ │ │ + matrixSet = contents.tileMatrixSets[ │ │ │ │ + layerDef.tileMatrixSetLinks[0].tileMatrixSet]; │ │ │ │ } │ │ │ │ - for (var i = 0, ii = nodes.length; i < ii; i++) { │ │ │ │ - value = {}; │ │ │ │ - value.term = nodes[i].getAttribute("term"); │ │ │ │ - attval = nodes[i].getAttribute("scheme"); │ │ │ │ - if (attval) { │ │ │ │ - value.scheme = attval; │ │ │ │ - } │ │ │ │ - attval = nodes[i].getAttribute("label"); │ │ │ │ - if (attval) { │ │ │ │ - value.label = attval; │ │ │ │ - } │ │ │ │ - atomAttrib.categories.push(value); │ │ │ │ + if (!matrixSet) { │ │ │ │ + throw new Error("matrixSet not found"); │ │ │ │ } │ │ │ │ │ │ │ │ - // atomContent? │ │ │ │ - nodes = this.getElementsByTagNameNS(node, atomns, "content"); │ │ │ │ - if (nodes.length > 0) { │ │ │ │ - value = {}; │ │ │ │ - attval = nodes[0].getAttribute("type"); │ │ │ │ - if (attval) { │ │ │ │ - value.type = attval; │ │ │ │ - } │ │ │ │ - attval = nodes[0].getAttribute("src"); │ │ │ │ - if (attval) { │ │ │ │ - value.src = attval; │ │ │ │ - } else { │ │ │ │ - if (value.type == "text" || │ │ │ │ - value.type == "html" || │ │ │ │ - value.type == null) { │ │ │ │ - value.value = this.getFirstChildValue( │ │ │ │ - node, │ │ │ │ - atomns, │ │ │ │ - "content", │ │ │ │ - null │ │ │ │ - ); │ │ │ │ - } else if (value.type == "xhtml" || │ │ │ │ - value.type.match(/(\+|\/)xml$/)) { │ │ │ │ - value.value = this.getChildEl(nodes[0]); │ │ │ │ - } else { // MUST be base64 encoded │ │ │ │ - value.value = this.getFirstChildValue( │ │ │ │ - node, │ │ │ │ - atomns, │ │ │ │ - "content", │ │ │ │ - null │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - atomAttrib.content = value; │ │ │ │ + // get the default style for the layer │ │ │ │ + var style; │ │ │ │ + for (var i = 0, ii = layerDef.styles.length; i < ii; ++i) { │ │ │ │ + style = layerDef.styles[i]; │ │ │ │ + if (style.isDefault) { │ │ │ │ + break; │ │ │ │ } │ │ │ │ } │ │ │ │ │ │ │ │ - // atomContributor* │ │ │ │ - this.parsePersonConstructs(node, "contributor", atomAttrib); │ │ │ │ - │ │ │ │ - // atomId │ │ │ │ - atomAttrib.id = this.getFirstChildValue(node, atomns, "id", null); │ │ │ │ + var requestEncoding = config.requestEncoding; │ │ │ │ + if (!requestEncoding) { │ │ │ │ + requestEncoding = "KVP"; │ │ │ │ + if (capabilities.operationsMetadata.GetTile.dcp.http) { │ │ │ │ + var http = capabilities.operationsMetadata.GetTile.dcp.http; │ │ │ │ + // Get first get method │ │ │ │ + if (http.get[0].constraints) { │ │ │ │ + var constraints = http.get[0].constraints; │ │ │ │ + var allowedValues = constraints.GetEncoding.allowedValues; │ │ │ │ │ │ │ │ - // atomLink* │ │ │ │ - nodes = this.getElementsByTagNameNS(node, atomns, "link"); │ │ │ │ - if (nodes.length > 0) { │ │ │ │ - atomAttrib.links = new Array(nodes.length); │ │ │ │ - } │ │ │ │ - var oAtts = ["rel", "type", "hreflang", "title", "length"]; │ │ │ │ - for (var i = 0, ii = nodes.length; i < ii; i++) { │ │ │ │ - value = {}; │ │ │ │ - value.href = nodes[i].getAttribute("href"); │ │ │ │ - for (var j = 0, jj = oAtts.length; j < jj; j++) { │ │ │ │ - attval = nodes[i].getAttribute(oAtts[j]); │ │ │ │ - if (attval) { │ │ │ │ - value[oAtts[j]] = attval; │ │ │ │ + // The OGC documentation is not clear if we should use │ │ │ │ + // REST or RESTful, ArcGis use RESTful, │ │ │ │ + // and OpenLayers use REST. │ │ │ │ + if (!allowedValues.KVP && │ │ │ │ + (allowedValues.REST || allowedValues.RESTful)) { │ │ │ │ + requestEncoding = "REST"; │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ - atomAttrib.links[i] = value; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atomPublished? │ │ │ │ - value = this.getFirstChildValue(node, atomns, "published", null); │ │ │ │ - if (value) { │ │ │ │ - atomAttrib.published = value; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atomRights? │ │ │ │ - value = this.getFirstChildValue(node, atomns, "rights", null); │ │ │ │ - if (value) { │ │ │ │ - atomAttrib.rights = value; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atomSource? -- not implemented │ │ │ │ - │ │ │ │ - // atomSummary? │ │ │ │ - value = this.getFirstChildValue(node, atomns, "summary", null); │ │ │ │ - if (value) { │ │ │ │ - atomAttrib.summary = value; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atomTitle │ │ │ │ - atomAttrib.title = this.getFirstChildValue( │ │ │ │ - node, atomns, "title", null │ │ │ │ - ); │ │ │ │ - │ │ │ │ - // atomUpdated │ │ │ │ - atomAttrib.updated = this.getFirstChildValue( │ │ │ │ - node, atomns, "updated", null │ │ │ │ - ); │ │ │ │ - │ │ │ │ - var featureAttrib = { │ │ │ │ - title: atomAttrib.title, │ │ │ │ - description: atomAttrib.summary, │ │ │ │ - atom: atomAttrib │ │ │ │ - }; │ │ │ │ - var geometry = this.parseLocations(node)[0]; │ │ │ │ - var feature = new OpenLayers.Feature.Vector(geometry, featureAttrib); │ │ │ │ - feature.fid = atomAttrib.id; │ │ │ │ - return feature; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: parseFeatures │ │ │ │ - * Return features from an Atom entry or feed. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} An Atom entry or feed node. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ - */ │ │ │ │ - parseFeatures: function(node) { │ │ │ │ - var features = []; │ │ │ │ - var entries = this.getElementsByTagNameNS( │ │ │ │ - node, this.namespaces.atom, "entry" │ │ │ │ - ); │ │ │ │ - if (entries.length == 0) { │ │ │ │ - entries = [node]; │ │ │ │ - } │ │ │ │ - for (var i = 0, ii = entries.length; i < ii; i++) { │ │ │ │ - features.push(this.parseFeature(entries[i])); │ │ │ │ } │ │ │ │ - return features; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: parseLocations │ │ │ │ - * Parse the locations from an Atom entry or feed. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} An Atom entry or feed node. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * Array({<OpenLayers.Geometry>}) │ │ │ │ - */ │ │ │ │ - parseLocations: function(node) { │ │ │ │ - var georssns = this.namespaces.georss; │ │ │ │ │ │ │ │ - var locations = { │ │ │ │ - components: [] │ │ │ │ - }; │ │ │ │ - var where = this.getElementsByTagNameNS(node, georssns, "where"); │ │ │ │ - if (where && where.length > 0) { │ │ │ │ - if (!this.gmlParser) { │ │ │ │ - this.initGmlParser(); │ │ │ │ - } │ │ │ │ - for (var i = 0, ii = where.length; i < ii; i++) { │ │ │ │ - this.gmlParser.readChildNodes(where[i], locations); │ │ │ │ + var dimensions = []; │ │ │ │ + var params = config.params || {}; │ │ │ │ + // to don't overwrite the changes in the applyDefaults │ │ │ │ + delete config.params; │ │ │ │ + for (var id = 0, ld = layerDef.dimensions.length; id < ld; id++) { │ │ │ │ + var dimension = layerDef.dimensions[id]; │ │ │ │ + dimensions.push(dimension.identifier); │ │ │ │ + if (!params.hasOwnProperty(dimension.identifier)) { │ │ │ │ + params[dimension.identifier] = dimension['default']; │ │ │ │ } │ │ │ │ } │ │ │ │ │ │ │ │ - var components = locations.components; │ │ │ │ - var point = this.getElementsByTagNameNS(node, georssns, "point"); │ │ │ │ - if (point && point.length > 0) { │ │ │ │ - for (var i = 0, ii = point.length; i < ii; i++) { │ │ │ │ - var xy = OpenLayers.String.trim( │ │ │ │ - point[i].firstChild.nodeValue │ │ │ │ - ).split(/\s+/); │ │ │ │ - if (xy.length != 2) { │ │ │ │ - xy = OpenLayers.String.trim( │ │ │ │ - point[i].firstChild.nodeValue │ │ │ │ - ).split(/\s*,\s*/); │ │ │ │ - } │ │ │ │ - components.push(new OpenLayers.Geometry.Point(xy[1], xy[0])); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + var projection = config.projection || matrixSet.supportedCRS.replace( │ │ │ │ + /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, "$1:$3"); │ │ │ │ + var units = config.units || │ │ │ │ + (projection === "EPSG:4326" ? "degrees" : "m"); │ │ │ │ │ │ │ │ - var line = this.getElementsByTagNameNS(node, georssns, "line"); │ │ │ │ - if (line && line.length > 0) { │ │ │ │ - var coords; │ │ │ │ - var p; │ │ │ │ - var points; │ │ │ │ - for (var i = 0, ii = line.length; i < ii; i++) { │ │ │ │ - coords = OpenLayers.String.trim( │ │ │ │ - line[i].firstChild.nodeValue │ │ │ │ - ).split(/\s+/); │ │ │ │ - points = []; │ │ │ │ - for (var j = 0, jj = coords.length; j < jj; j += 2) { │ │ │ │ - p = new OpenLayers.Geometry.Point(coords[j + 1], coords[j]); │ │ │ │ - points.push(p); │ │ │ │ - } │ │ │ │ - components.push( │ │ │ │ - new OpenLayers.Geometry.LineString(points) │ │ │ │ - ); │ │ │ │ + var resolutions = []; │ │ │ │ + for (var mid in matrixSet.matrixIds) { │ │ │ │ + if (matrixSet.matrixIds.hasOwnProperty(mid)) { │ │ │ │ + resolutions.push( │ │ │ │ + matrixSet.matrixIds[mid].scaleDenominator * 0.28E-3 / │ │ │ │ + OpenLayers.METERS_PER_INCH / │ │ │ │ + OpenLayers.INCHES_PER_UNIT[units]); │ │ │ │ } │ │ │ │ } │ │ │ │ │ │ │ │ - var polygon = this.getElementsByTagNameNS(node, georssns, "polygon"); │ │ │ │ - if (polygon && polygon.length > 0) { │ │ │ │ - var coords; │ │ │ │ - var p; │ │ │ │ - var points; │ │ │ │ - for (var i = 0, ii = polygon.length; i < ii; i++) { │ │ │ │ - coords = OpenLayers.String.trim( │ │ │ │ - polygon[i].firstChild.nodeValue │ │ │ │ - ).split(/\s+/); │ │ │ │ - points = []; │ │ │ │ - for (var j = 0, jj = coords.length; j < jj; j += 2) { │ │ │ │ - p = new OpenLayers.Geometry.Point(coords[j + 1], coords[j]); │ │ │ │ - points.push(p); │ │ │ │ + var url; │ │ │ │ + if (requestEncoding === "REST" && layerDef.resourceUrls) { │ │ │ │ + url = []; │ │ │ │ + var resourceUrls = layerDef.resourceUrls, │ │ │ │ + resourceUrl; │ │ │ │ + for (var t = 0, tt = layerDef.resourceUrls.length; t < tt; ++t) { │ │ │ │ + resourceUrl = layerDef.resourceUrls[t]; │ │ │ │ + if (resourceUrl.format === format && resourceUrl.resourceType === "tile") { │ │ │ │ + url.push(resourceUrl.template); │ │ │ │ } │ │ │ │ - components.push( │ │ │ │ - new OpenLayers.Geometry.Polygon( │ │ │ │ - [new OpenLayers.Geometry.LinearRing(points)] │ │ │ │ - ) │ │ │ │ - ); │ │ │ │ } │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - for (var i = 0, ii = components.length; i < ii; i++) { │ │ │ │ - if (components[i]) { │ │ │ │ - components[i].transform( │ │ │ │ - this.externalProjection, │ │ │ │ - this.internalProjection │ │ │ │ - ); │ │ │ │ + } else { │ │ │ │ + var httpGet = capabilities.operationsMetadata.GetTile.dcp.http.get; │ │ │ │ + url = []; │ │ │ │ + var constraint; │ │ │ │ + for (var i = 0, ii = httpGet.length; i < ii; i++) { │ │ │ │ + constraint = httpGet[i].constraints; │ │ │ │ + if (!constraint || (constraint && constraint.GetEncoding.allowedValues[requestEncoding])) { │ │ │ │ + url.push(httpGet[i].url); │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ │ │ │ │ - return components; │ │ │ │ + return new OpenLayers.Layer.WMTS( │ │ │ │ + OpenLayers.Util.applyDefaults(config, { │ │ │ │ + url: url, │ │ │ │ + requestEncoding: requestEncoding, │ │ │ │ + name: layerDef.title, │ │ │ │ + style: style.identifier, │ │ │ │ + format: format, │ │ │ │ + matrixIds: matrixSet.matrixIds, │ │ │ │ + matrixSet: matrixSet.identifier, │ │ │ │ + projection: projection, │ │ │ │ + units: units, │ │ │ │ + resolutions: config.isBaseLayer === false ? undefined : resolutions, │ │ │ │ + serverResolutions: resolutions, │ │ │ │ + tileFullExtent: matrixSet.bounds, │ │ │ │ + dimensions: dimensions, │ │ │ │ + params: params │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: parsePersonConstruct │ │ │ │ - * Parse Atom person constructs from an Atom entry node. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} An Atom entry or feed node. │ │ │ │ - * name - {String} Construcy name ("author" or "contributor") │ │ │ │ - * data = {Object} Object in which to put parsed persons. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * An {Object}. │ │ │ │ - */ │ │ │ │ - parsePersonConstructs: function(node, name, data) { │ │ │ │ - var persons = []; │ │ │ │ - var atomns = this.namespaces.atom; │ │ │ │ - var nodes = this.getElementsByTagNameNS(node, atomns, name); │ │ │ │ - var oAtts = ["uri", "email"]; │ │ │ │ - for (var i = 0, ii = nodes.length; i < ii; i++) { │ │ │ │ - var value = {}; │ │ │ │ - value.name = this.getFirstChildValue( │ │ │ │ - nodes[i], │ │ │ │ - atomns, │ │ │ │ - "name", │ │ │ │ - null │ │ │ │ - ); │ │ │ │ - for (var j = 0, jj = oAtts.length; j < jj; j++) { │ │ │ │ - var attval = this.getFirstChildValue( │ │ │ │ - nodes[i], │ │ │ │ - atomns, │ │ │ │ - oAtts[j], │ │ │ │ - null); │ │ │ │ - if (attval) { │ │ │ │ - value[oAtts[j]] = attval; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - persons.push(value); │ │ │ │ - } │ │ │ │ - if (persons.length > 0) { │ │ │ │ - data[name + "s"] = persons; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMTSCapabilities" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.Atom" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Format/GeoRSS.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ @@ -74602,14 +77335,65 @@ │ │ │ │ } │ │ │ │ return this.createTextNode(path); │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.GeoRSS" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ + OpenLayers/Format/WFSCapabilities.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 │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WFSCapabilities │ │ │ │ + * Read WFS Capabilities. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WFSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "1.1.0". │ │ │ │ + */ │ │ │ │ + defaultVersion: "1.1.0", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WFSCapabilities │ │ │ │ + * Create a new parser for WFS capabilities. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return a list of layers. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array} List of named layers. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities" │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ OpenLayers/Format/CSWGetDomain.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. */ │ │ │ │ @@ -74640,487 +77424,14 @@ │ │ │ │ * Constant: DEFAULTS │ │ │ │ * {Object} Default properties for the CSWGetDomain format. │ │ │ │ */ │ │ │ │ OpenLayers.Format.CSWGetDomain.DEFAULTS = { │ │ │ │ "version": "2.0.2" │ │ │ │ }; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/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/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/Projection.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.OSM │ │ │ │ - * OSM parser. Create a new instance with the │ │ │ │ - * <OpenLayers.Format.OSM> constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.OSM = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: checkTags │ │ │ │ - * {Boolean} Should tags be checked to determine whether something │ │ │ │ - * should be treated as a seperate node. Will slow down parsing. │ │ │ │ - * Default is false. │ │ │ │ - */ │ │ │ │ - checkTags: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: interestingTagsExclude │ │ │ │ - * {Array} List of tags to exclude from 'interesting' checks on nodes. │ │ │ │ - * Must be set when creating the format. Will only be used if checkTags │ │ │ │ - * is set. │ │ │ │ - */ │ │ │ │ - interestingTagsExclude: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: areaTags │ │ │ │ - * {Array} List of tags indicating that something is an area. │ │ │ │ - * Must be set when creating the format. Will only be used if │ │ │ │ - * checkTags is true. │ │ │ │ - */ │ │ │ │ - areaTags: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.OSM │ │ │ │ - * Create a new parser for OSM. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - var layer_defaults = { │ │ │ │ - 'interestingTagsExclude': ['source', 'source_ref', │ │ │ │ - 'source:ref', 'history', 'attribution', 'created_by' │ │ │ │ - ], │ │ │ │ - 'areaTags': ['area', 'building', 'leisure', 'tourism', 'ruins', │ │ │ │ - 'historic', 'landuse', 'military', 'natural', 'sport' │ │ │ │ - ] │ │ │ │ - }; │ │ │ │ - │ │ │ │ - layer_defaults = OpenLayers.Util.extend(layer_defaults, options); │ │ │ │ - │ │ │ │ - var interesting = {}; │ │ │ │ - for (var i = 0; i < layer_defaults.interestingTagsExclude.length; i++) { │ │ │ │ - interesting[layer_defaults.interestingTagsExclude[i]] = true; │ │ │ │ - } │ │ │ │ - layer_defaults.interestingTagsExclude = interesting; │ │ │ │ - │ │ │ │ - var area = {}; │ │ │ │ - for (var i = 0; i < layer_defaults.areaTags.length; i++) { │ │ │ │ - area[layer_defaults.areaTags[i]] = true; │ │ │ │ - } │ │ │ │ - layer_defaults.areaTags = area; │ │ │ │ - │ │ │ │ - // OSM coordinates are always in longlat WGS84 │ │ │ │ - this.externalProjection = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ - │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [layer_defaults]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Return a list of features from a OSM doc │ │ │ │ - │ │ │ │ - * Parameters: │ │ │ │ - * doc - {Element} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ - */ │ │ │ │ - read: function(doc) { │ │ │ │ - if (typeof doc == "string") { │ │ │ │ - doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var nodes = this.getNodes(doc); │ │ │ │ - var ways = this.getWays(doc); │ │ │ │ - │ │ │ │ - // Geoms will contain at least ways.length entries. │ │ │ │ - var feat_list = new Array(ways.length); │ │ │ │ - │ │ │ │ - for (var i = 0; i < ways.length; i++) { │ │ │ │ - // We know the minimal of this one ahead of time. (Could be -1 │ │ │ │ - // due to areas/polygons) │ │ │ │ - var point_list = new Array(ways[i].nodes.length); │ │ │ │ - │ │ │ │ - var poly = this.isWayArea(ways[i]) ? 1 : 0; │ │ │ │ - for (var j = 0; j < ways[i].nodes.length; j++) { │ │ │ │ - var node = nodes[ways[i].nodes[j]]; │ │ │ │ - │ │ │ │ - var point = new OpenLayers.Geometry.Point(node.lon, node.lat); │ │ │ │ - │ │ │ │ - // Since OSM is topological, we stash the node ID internally. │ │ │ │ - point.osm_id = parseInt(ways[i].nodes[j]); │ │ │ │ - point_list[j] = point; │ │ │ │ - │ │ │ │ - // We don't display nodes if they're used inside other │ │ │ │ - // elements. │ │ │ │ - node.used = true; │ │ │ │ - } │ │ │ │ - var geometry = null; │ │ │ │ - if (poly) { │ │ │ │ - geometry = new OpenLayers.Geometry.Polygon( │ │ │ │ - new OpenLayers.Geometry.LinearRing(point_list)); │ │ │ │ - } else { │ │ │ │ - geometry = new OpenLayers.Geometry.LineString(point_list); │ │ │ │ - } │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - geometry.transform(this.externalProjection, │ │ │ │ - this.internalProjection); │ │ │ │ - } │ │ │ │ - var feat = new OpenLayers.Feature.Vector(geometry, │ │ │ │ - ways[i].tags); │ │ │ │ - feat.osm_id = parseInt(ways[i].id); │ │ │ │ - feat.fid = "way." + feat.osm_id; │ │ │ │ - feat_list[i] = feat; │ │ │ │ - } │ │ │ │ - for (var node_id in nodes) { │ │ │ │ - var node = nodes[node_id]; │ │ │ │ - if (!node.used || this.checkTags) { │ │ │ │ - var tags = null; │ │ │ │ - │ │ │ │ - if (this.checkTags) { │ │ │ │ - var result = this.getTags(node.node, true); │ │ │ │ - if (node.used && !result[1]) { │ │ │ │ - continue; │ │ │ │ - } │ │ │ │ - tags = result[0]; │ │ │ │ - } else { │ │ │ │ - tags = this.getTags(node.node); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var feat = new OpenLayers.Feature.Vector( │ │ │ │ - new OpenLayers.Geometry.Point(node['lon'], node['lat']), │ │ │ │ - tags); │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - feat.geometry.transform(this.externalProjection, │ │ │ │ - this.internalProjection); │ │ │ │ - } │ │ │ │ - feat.osm_id = parseInt(node_id); │ │ │ │ - feat.fid = "node." + feat.osm_id; │ │ │ │ - feat_list.push(feat); │ │ │ │ - } │ │ │ │ - // Memory cleanup │ │ │ │ - node.node = null; │ │ │ │ - } │ │ │ │ - return feat_list; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getNodes │ │ │ │ - * Return the node items from a doc. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * doc - {DOMElement} node to parse tags from │ │ │ │ - */ │ │ │ │ - getNodes: function(doc) { │ │ │ │ - var node_list = doc.getElementsByTagName("node"); │ │ │ │ - var nodes = {}; │ │ │ │ - for (var i = 0; i < node_list.length; i++) { │ │ │ │ - var node = node_list[i]; │ │ │ │ - var id = node.getAttribute("id"); │ │ │ │ - nodes[id] = { │ │ │ │ - 'lat': node.getAttribute("lat"), │ │ │ │ - 'lon': node.getAttribute("lon"), │ │ │ │ - 'node': node │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - return nodes; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getWays │ │ │ │ - * Return the way items from a doc. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * doc - {DOMElement} node to parse tags from │ │ │ │ - */ │ │ │ │ - getWays: function(doc) { │ │ │ │ - var way_list = doc.getElementsByTagName("way"); │ │ │ │ - var return_ways = []; │ │ │ │ - for (var i = 0; i < way_list.length; i++) { │ │ │ │ - var way = way_list[i]; │ │ │ │ - var way_object = { │ │ │ │ - id: way.getAttribute("id") │ │ │ │ - }; │ │ │ │ - │ │ │ │ - way_object.tags = this.getTags(way); │ │ │ │ - │ │ │ │ - var node_list = way.getElementsByTagName("nd"); │ │ │ │ - │ │ │ │ - way_object.nodes = new Array(node_list.length); │ │ │ │ - │ │ │ │ - for (var j = 0; j < node_list.length; j++) { │ │ │ │ - way_object.nodes[j] = node_list[j].getAttribute("ref"); │ │ │ │ - } │ │ │ │ - return_ways.push(way_object); │ │ │ │ - } │ │ │ │ - return return_ways; │ │ │ │ - │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getTags │ │ │ │ - * Return the tags list attached to a specific DOM element. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * dom_node - {DOMElement} node to parse tags from │ │ │ │ - * interesting_tags - {Boolean} whether the return from this function should │ │ │ │ - * return a boolean indicating that it has 'interesting tags' -- │ │ │ │ - * tags like attribution and source are ignored. (To change the list │ │ │ │ - * of tags, see interestingTagsExclude) │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * tags - {Object} hash of tags │ │ │ │ - * interesting - {Boolean} if interesting_tags is passed, returns │ │ │ │ - * whether there are any interesting tags on this element. │ │ │ │ - */ │ │ │ │ - getTags: function(dom_node, interesting_tags) { │ │ │ │ - var tag_list = dom_node.getElementsByTagName("tag"); │ │ │ │ - var tags = {}; │ │ │ │ - var interesting = false; │ │ │ │ - for (var j = 0; j < tag_list.length; j++) { │ │ │ │ - var key = tag_list[j].getAttribute("k"); │ │ │ │ - tags[key] = tag_list[j].getAttribute("v"); │ │ │ │ - if (interesting_tags) { │ │ │ │ - if (!this.interestingTagsExclude[key]) { │ │ │ │ - interesting = true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return interesting_tags ? [tags, interesting] : tags; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: isWayArea │ │ │ │ - * Given a way object from getWays, check whether the tags and geometry │ │ │ │ - * indicate something is an area. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - isWayArea: function(way) { │ │ │ │ - var poly_shaped = false; │ │ │ │ - var poly_tags = false; │ │ │ │ - │ │ │ │ - if (way.nodes[0] == way.nodes[way.nodes.length - 1]) { │ │ │ │ - poly_shaped = true; │ │ │ │ - } │ │ │ │ - if (this.checkTags) { │ │ │ │ - for (var key in way.tags) { │ │ │ │ - if (this.areaTags[key]) { │ │ │ │ - poly_tags = true; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return poly_shaped && (this.checkTags ? poly_tags : true); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Takes a list of features, returns a serialized OSM format file for use │ │ │ │ - * in tools like JOSM. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ - */ │ │ │ │ - write: function(features) { │ │ │ │ - if (!(OpenLayers.Util.isArray(features))) { │ │ │ │ - features = [features]; │ │ │ │ - } │ │ │ │ - │ │ │ │ - this.osm_id = 1; │ │ │ │ - this.created_nodes = {}; │ │ │ │ - var root_node = this.createElementNS(null, "osm"); │ │ │ │ - root_node.setAttribute("version", "0.5"); │ │ │ │ - root_node.setAttribute("generator", "OpenLayers " + OpenLayers.VERSION_NUMBER); │ │ │ │ - │ │ │ │ - // Loop backwards, because the deserializer puts nodes last, and │ │ │ │ - // we want them first if possible │ │ │ │ - for (var i = features.length - 1; i >= 0; i--) { │ │ │ │ - var nodes = this.createFeatureNodes(features[i]); │ │ │ │ - for (var j = 0; j < nodes.length; j++) { │ │ │ │ - root_node.appendChild(nodes[j]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [root_node]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: createFeatureNodes │ │ │ │ - * Takes a feature, returns a list of nodes from size 0->n. │ │ │ │ - * Will include all pieces of the serialization that are required which │ │ │ │ - * have not already been created. Calls out to createXML based on geometry │ │ │ │ - * type. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - createFeatureNodes: function(feature) { │ │ │ │ - var nodes = []; │ │ │ │ - var className = feature.geometry.CLASS_NAME; │ │ │ │ - var type = className.substring(className.lastIndexOf(".") + 1); │ │ │ │ - type = type.toLowerCase(); │ │ │ │ - var builder = this.createXML[type]; │ │ │ │ - if (builder) { │ │ │ │ - nodes = builder.apply(this, [feature]); │ │ │ │ - } │ │ │ │ - return nodes; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: createXML │ │ │ │ - * Takes a feature, returns a list of nodes from size 0->n. │ │ │ │ - * Will include all pieces of the serialization that are required which │ │ │ │ - * have not already been created. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - createXML: { │ │ │ │ - 'point': function(point) { │ │ │ │ - var id = null; │ │ │ │ - var geometry = point.geometry ? point.geometry : point; │ │ │ │ - │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - geometry = geometry.clone(); │ │ │ │ - geometry.transform(this.internalProjection, │ │ │ │ - this.externalProjection); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var already_exists = false; // We don't return anything if the node │ │ │ │ - // has already been created │ │ │ │ - if (point.osm_id) { │ │ │ │ - id = point.osm_id; │ │ │ │ - if (this.created_nodes[id]) { │ │ │ │ - already_exists = true; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - id = -this.osm_id; │ │ │ │ - this.osm_id++; │ │ │ │ - } │ │ │ │ - if (already_exists) { │ │ │ │ - node = this.created_nodes[id]; │ │ │ │ - } else { │ │ │ │ - var node = this.createElementNS(null, "node"); │ │ │ │ - } │ │ │ │ - this.created_nodes[id] = node; │ │ │ │ - node.setAttribute("id", id); │ │ │ │ - node.setAttribute("lon", geometry.x); │ │ │ │ - node.setAttribute("lat", geometry.y); │ │ │ │ - if (point.attributes) { │ │ │ │ - this.serializeTags(point, node); │ │ │ │ - } │ │ │ │ - this.setState(point, node); │ │ │ │ - return already_exists ? [] : [node]; │ │ │ │ - }, │ │ │ │ - linestring: function(feature) { │ │ │ │ - var id; │ │ │ │ - var nodes = []; │ │ │ │ - var geometry = feature.geometry; │ │ │ │ - if (feature.osm_id) { │ │ │ │ - id = feature.osm_id; │ │ │ │ - } else { │ │ │ │ - id = -this.osm_id; │ │ │ │ - this.osm_id++; │ │ │ │ - } │ │ │ │ - var way = this.createElementNS(null, "way"); │ │ │ │ - way.setAttribute("id", id); │ │ │ │ - for (var i = 0; i < geometry.components.length; i++) { │ │ │ │ - var node = this.createXML['point'].apply(this, [geometry.components[i]]); │ │ │ │ - if (node.length) { │ │ │ │ - node = node[0]; │ │ │ │ - var node_ref = node.getAttribute("id"); │ │ │ │ - nodes.push(node); │ │ │ │ - } else { │ │ │ │ - node_ref = geometry.components[i].osm_id; │ │ │ │ - node = this.created_nodes[node_ref]; │ │ │ │ - } │ │ │ │ - this.setState(feature, node); │ │ │ │ - var nd_dom = this.createElementNS(null, "nd"); │ │ │ │ - nd_dom.setAttribute("ref", node_ref); │ │ │ │ - way.appendChild(nd_dom); │ │ │ │ - } │ │ │ │ - this.serializeTags(feature, way); │ │ │ │ - nodes.push(way); │ │ │ │ - │ │ │ │ - return nodes; │ │ │ │ - }, │ │ │ │ - polygon: function(feature) { │ │ │ │ - var attrs = OpenLayers.Util.extend({ │ │ │ │ - 'area': 'yes' │ │ │ │ - }, feature.attributes); │ │ │ │ - var feat = new OpenLayers.Feature.Vector(feature.geometry.components[0], attrs); │ │ │ │ - feat.osm_id = feature.osm_id; │ │ │ │ - return this.createXML['linestring'].apply(this, [feat]); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: serializeTags │ │ │ │ - * Given a feature, serialize the attributes onto the given node. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - * node - {DOMNode} │ │ │ │ - */ │ │ │ │ - serializeTags: function(feature, node) { │ │ │ │ - for (var key in feature.attributes) { │ │ │ │ - var tag = this.createElementNS(null, "tag"); │ │ │ │ - tag.setAttribute("k", key); │ │ │ │ - tag.setAttribute("v", feature.attributes[key]); │ │ │ │ - node.appendChild(tag); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setState │ │ │ │ - * OpenStreetMap has a convention that 'state' is stored for modification or deletion. │ │ │ │ - * This allows the file to be uploaded via JOSM or the bulk uploader tool. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - * node - {DOMNode} │ │ │ │ - */ │ │ │ │ - setState: function(feature, node) { │ │ │ │ - if (feature.state) { │ │ │ │ - var state = null; │ │ │ │ - switch (feature.state) { │ │ │ │ - case OpenLayers.State.UPDATE: │ │ │ │ - state = "modify"; │ │ │ │ - case OpenLayers.State.DELETE: │ │ │ │ - state = "delete"; │ │ │ │ - } │ │ │ │ - if (state) { │ │ │ │ - node.setAttribute("action", state); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.OSM" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ OpenLayers/Format/GPX.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. */ │ │ │ │ @@ -75503,204 +77814,241 @@ │ │ │ │ node.appendChild(desc); │ │ │ │ // TBD - deal with remaining (non name/description) attributes. │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.GPX" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WCSCapabilities.js │ │ │ │ + OpenLayers/Format/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/Format/XML/VersionedOGC.js │ │ │ │ + * @requires OpenLayers/Format/GML.js │ │ │ │ + * @requires OpenLayers/Console.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WCSCapabilities │ │ │ │ - * Read WCS Capabilities. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.WFS │ │ │ │ + * Read/Write WFS. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ + * - <OpenLayers.Format.GML> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WCSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ +OpenLayers.Format.WFS = OpenLayers.Class(OpenLayers.Format.GML, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: layer │ │ │ │ + * {<OpenLayers.Layer>} │ │ │ │ + */ │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "1.1.0". │ │ │ │ + * APIProperty: wfsns │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - defaultVersion: "1.1.0", │ │ │ │ + wfsns: "http://www.opengis.net/wfs", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WCSCapabilities │ │ │ │ - * Create a new parser for WCS capabilities. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * Property: ogcns │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ + ogcns: "http://www.opengis.net/ogc", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return a list of coverages. │ │ │ │ + * Constructor: OpenLayers.Format.WFS │ │ │ │ + * Create a WFS-T formatter. This requires a layer: that layer should │ │ │ │ + * have two properties: geometry_column and typename. The parser │ │ │ │ + * for this format is subclassed entirely from GML: There is a writer │ │ │ │ + * only, which uses most of the code from the GML layer, and wraps │ │ │ │ + * it in transactional elements. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} List of named coverages. │ │ │ │ + * options - {Object} │ │ │ │ + * layer - {<OpenLayers.Layer>} │ │ │ │ */ │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/OWSContext.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/Context.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.OWSContext │ │ │ │ - * Read and write OWS Context documents. OWS Context documents are a │ │ │ │ - * preliminary OGC (Open Geospatial Consortium) standard for storing the │ │ │ │ - * state of a web mapping application. In a way it is the successor to │ │ │ │ - * Web Map Context (WMC), since it is more generic and more types of layers │ │ │ │ - * can be stored. Also, nesting of layers is supported since version 0.3.1. │ │ │ │ - * For more information see: http://www.ogcnetwork.net/context │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.Context> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.OWSContext = OpenLayers.Class(OpenLayers.Format.Context, { │ │ │ │ + initialize: function(options, layer) { │ │ │ │ + OpenLayers.Format.GML.prototype.initialize.apply(this, [options]); │ │ │ │ + this.layer = layer; │ │ │ │ + if (this.layer.featureNS) { │ │ │ │ + this.featureNS = this.layer.featureNS; │ │ │ │ + } │ │ │ │ + if (this.layer.options.geometry_column) { │ │ │ │ + this.geometryName = this.layer.options.geometry_column; │ │ │ │ + } │ │ │ │ + if (this.layer.options.typename) { │ │ │ │ + this.featureName = this.layer.options.typename; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "0.3.1". │ │ │ │ + * Method: write │ │ │ │ + * Takes a feature list, and generates a WFS-T Transaction │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ */ │ │ │ │ - defaultVersion: "0.3.1", │ │ │ │ + write: function(features) { │ │ │ │ + │ │ │ │ + var transaction = this.createElementNS(this.wfsns, 'wfs:Transaction'); │ │ │ │ + transaction.setAttribute("version", "1.0.0"); │ │ │ │ + transaction.setAttribute("service", "WFS"); │ │ │ │ + for (var i = 0; i < features.length; i++) { │ │ │ │ + switch (features[i].state) { │ │ │ │ + case OpenLayers.State.INSERT: │ │ │ │ + transaction.appendChild(this.insert(features[i])); │ │ │ │ + break; │ │ │ │ + case OpenLayers.State.UPDATE: │ │ │ │ + transaction.appendChild(this.update(features[i])); │ │ │ │ + break; │ │ │ │ + case OpenLayers.State.DELETE: │ │ │ │ + transaction.appendChild(this.remove(features[i])); │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [transaction]); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.OWSContext │ │ │ │ - * Create a new parser for OWS Context documents. │ │ │ │ + * Method: createFeatureXML │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ */ │ │ │ │ + createFeatureXML: function(feature) { │ │ │ │ + var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ + var geomContainer = this.createElementNS(this.featureNS, "feature:" + this.geometryName); │ │ │ │ + geomContainer.appendChild(geometryNode); │ │ │ │ + var featureContainer = this.createElementNS(this.featureNS, "feature:" + this.featureName); │ │ │ │ + featureContainer.appendChild(geomContainer); │ │ │ │ + for (var attr in feature.attributes) { │ │ │ │ + var attrText = this.createTextNode(feature.attributes[attr]); │ │ │ │ + var nodename = attr; │ │ │ │ + if (attr.search(":") != -1) { │ │ │ │ + nodename = attr.split(":")[1]; │ │ │ │ + } │ │ │ │ + var attrContainer = this.createElementNS(this.featureNS, "feature:" + nodename); │ │ │ │ + attrContainer.appendChild(attrText); │ │ │ │ + featureContainer.appendChild(attrContainer); │ │ │ │ + } │ │ │ │ + return featureContainer; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: insert │ │ │ │ + * Takes a feature, and generates a WFS-T Transaction "Insert" │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {String} The version to use. │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ */ │ │ │ │ - getVersion: function(root, options) { │ │ │ │ - var version = OpenLayers.Format.XML.VersionedOGC.prototype.getVersion.apply( │ │ │ │ - this, arguments); │ │ │ │ - // 0.3.1 is backwards compatible with 0.3.0 │ │ │ │ - if (version === "0.3.0") { │ │ │ │ - version = this.defaultVersion; │ │ │ │ - } │ │ │ │ - return version; │ │ │ │ + insert: function(feature) { │ │ │ │ + var insertNode = this.createElementNS(this.wfsns, 'wfs:Insert'); │ │ │ │ + insertNode.appendChild(this.createFeatureXML(feature)); │ │ │ │ + return insertNode; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: toContext │ │ │ │ - * Create a context object free from layer given a map or a │ │ │ │ - * context object. │ │ │ │ + * Method: update │ │ │ │ + * Takes a feature, and generates a WFS-T Transaction "Update" │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * obj - {<OpenLayers.Map> | Object} The map or context. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} A context object. │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ */ │ │ │ │ - toContext: function(obj) { │ │ │ │ - var context = {}; │ │ │ │ - if (obj.CLASS_NAME == "OpenLayers.Map") { │ │ │ │ - context.bounds = obj.getExtent(); │ │ │ │ - context.maxExtent = obj.maxExtent; │ │ │ │ - context.projection = obj.projection; │ │ │ │ - context.size = obj.getSize(); │ │ │ │ - context.layers = obj.layers; │ │ │ │ + update: function(feature) { │ │ │ │ + if (!feature.fid) { │ │ │ │ + OpenLayers.Console.userError(OpenLayers.i18n("noFID")); │ │ │ │ } │ │ │ │ - return context; │ │ │ │ - }, │ │ │ │ + var updateNode = this.createElementNS(this.wfsns, 'wfs:Update'); │ │ │ │ + updateNode.setAttribute("typeName", this.featurePrefix + ':' + this.featureName); │ │ │ │ + updateNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.OWSContext" │ │ │ │ + var propertyNode = this.createElementNS(this.wfsns, 'wfs:Property'); │ │ │ │ + var nameNode = this.createElementNS(this.wfsns, 'wfs:Name'); │ │ │ │ │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WFSCapabilities.js │ │ │ │ - ====================================================================== */ │ │ │ │ + var txtNode = this.createTextNode(this.geometryName); │ │ │ │ + nameNode.appendChild(txtNode); │ │ │ │ + propertyNode.appendChild(nameNode); │ │ │ │ │ │ │ │ -/* 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 valueNode = this.createElementNS(this.wfsns, 'wfs:Value'); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Format/XML/VersionedOGC.js │ │ │ │ - */ │ │ │ │ + var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WFSCapabilities │ │ │ │ - * Read WFS Capabilities. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WFSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + if (feature.layer) { │ │ │ │ + geometryNode.setAttribute( │ │ │ │ + "srsName", feature.layer.projection.getCode() │ │ │ │ + ); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "1.1.0". │ │ │ │ - */ │ │ │ │ - defaultVersion: "1.1.0", │ │ │ │ + valueNode.appendChild(geometryNode); │ │ │ │ + │ │ │ │ + propertyNode.appendChild(valueNode); │ │ │ │ + updateNode.appendChild(propertyNode); │ │ │ │ + │ │ │ │ + // add in attributes │ │ │ │ + for (var propName in feature.attributes) { │ │ │ │ + propertyNode = this.createElementNS(this.wfsns, 'wfs:Property'); │ │ │ │ + nameNode = this.createElementNS(this.wfsns, 'wfs:Name'); │ │ │ │ + nameNode.appendChild(this.createTextNode(propName)); │ │ │ │ + propertyNode.appendChild(nameNode); │ │ │ │ + valueNode = this.createElementNS(this.wfsns, 'wfs:Value'); │ │ │ │ + valueNode.appendChild(this.createTextNode(feature.attributes[propName])); │ │ │ │ + propertyNode.appendChild(valueNode); │ │ │ │ + updateNode.appendChild(propertyNode); │ │ │ │ + } │ │ │ │ + │ │ │ │ + │ │ │ │ + var filterNode = this.createElementNS(this.ogcns, 'ogc:Filter'); │ │ │ │ + var filterIdNode = this.createElementNS(this.ogcns, 'ogc:FeatureId'); │ │ │ │ + filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ + filterNode.appendChild(filterIdNode); │ │ │ │ + updateNode.appendChild(filterNode); │ │ │ │ + │ │ │ │ + return updateNode; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WFSCapabilities │ │ │ │ - * Create a new parser for WFS capabilities. │ │ │ │ + * Method: remove │ │ │ │ + * Takes a feature, and generates a WFS-T Transaction "Delete" │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ */ │ │ │ │ + remove: function(feature) { │ │ │ │ + if (!feature.fid) { │ │ │ │ + OpenLayers.Console.userError(OpenLayers.i18n("noFID")); │ │ │ │ + return false; │ │ │ │ + } │ │ │ │ + var deleteNode = this.createElementNS(this.wfsns, 'wfs:Delete'); │ │ │ │ + deleteNode.setAttribute("typeName", this.featurePrefix + ':' + this.featureName); │ │ │ │ + deleteNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ + │ │ │ │ + var filterNode = this.createElementNS(this.ogcns, 'ogc:Filter'); │ │ │ │ + var filterIdNode = this.createElementNS(this.ogcns, 'ogc:FeatureId'); │ │ │ │ + filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ + filterNode.appendChild(filterIdNode); │ │ │ │ + deleteNode.appendChild(filterNode); │ │ │ │ + │ │ │ │ + return deleteNode; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return a list of layers. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} List of named layers. │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Remove ciruclar ref to layer │ │ │ │ */ │ │ │ │ + destroy: function() { │ │ │ │ + this.layer = null; │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities" │ │ │ │ - │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFS" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ 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. │ │ │ │ @@ -76967,2957 +79315,658 @@ │ │ │ │ } │ │ │ │ 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/Format/WMSDescribeLayer.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 │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSDescribeLayer │ │ │ │ - * Read SLD WMS DescribeLayer response │ │ │ │ - * DescribeLayer is meant to couple WMS to WFS and WCS │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSDescribeLayer = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "1.1.1". │ │ │ │ - */ │ │ │ │ - defaultVersion: "1.1.1", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WMSDescribeLayer │ │ │ │ - * Create a new parser for WMS DescribeLayer responses. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read DescribeLayer data from a string, and return the response. │ │ │ │ - * The OGC currently defines 2 formats which are allowed for output, │ │ │ │ - * so we need to parse these 2 types │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} Array of {<LayerDescription>} objects which have: │ │ │ │ - * - {String} owsType: WFS/WCS │ │ │ │ - * - {String} owsURL: the online resource │ │ │ │ - * - {String} typeName: the name of the typename on the service │ │ │ │ - */ │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/XLS.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 │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.XLS │ │ │ │ - * Read/Write XLS (OpenLS). Create a new instance with the <OpenLayers.Format.XLS> │ │ │ │ - * constructor. Currently only implemented for Location Utility Services, more │ │ │ │ - * specifically only for Geocoding. No support for Reverse Geocoding as yet. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.XLS = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "1.1.0". │ │ │ │ - */ │ │ │ │ - defaultVersion: "1.1.0", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: stringifyOutput │ │ │ │ - * {Boolean} If true, write will return a string otherwise a DOMElement. │ │ │ │ - * Default is true. │ │ │ │ - */ │ │ │ │ - stringifyOutput: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.XLS │ │ │ │ - * Create a new parser for XLS. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Write out an XLS request. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * request - {Object} An object representing the LUS request. │ │ │ │ - * options - {Object} Optional configuration object. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} An XLS document string. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read an XLS doc and return an object representing the result. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String | DOMElement} Data to read. │ │ │ │ - * options - {Object} Options for the reader. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An object representing the GeocodeResponse. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.XLS" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/SOSCapabilities.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 │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.SOSCapabilities │ │ │ │ - * Read SOS Capabilities. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.SOSCapabilities = 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", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.SOSCapabilities │ │ │ │ - * Create a new parser for SOS Capabilities. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return information about │ │ │ │ - * the service (offering and observedProperty mostly). │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} Info about the SOS │ │ │ │ - */ │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SOSCapabilities" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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/Format/ArcXML/Features.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/ArcXML.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.ArcXML.Features │ │ │ │ - * Read/Write ArcXML features. Create a new instance with the │ │ │ │ - * <OpenLayers.Format.ArcXML.Features> constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.ArcXML.Features = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.ArcXML.Features │ │ │ │ - * Create a new parser/writer for ArcXML Features. Create an instance of this class │ │ │ │ - * to get a set of features from an ArcXML response. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read data from a string of ArcXML, and return a set of OpenLayers features. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} A collection of features. │ │ │ │ - */ │ │ │ │ - read: function(data) { │ │ │ │ - var axl = new OpenLayers.Format.ArcXML(); │ │ │ │ - var parsed = axl.read(data); │ │ │ │ - │ │ │ │ - return parsed.features.feature; │ │ │ │ - } │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSDescribeLayer/v1_1.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/WMSDescribeLayer.js │ │ │ │ - * @requires OpenLayers/Format/OGCExceptionReport.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSDescribeLayer.v1_1_1 │ │ │ │ - * Read SLD WMS DescribeLayer response for WMS 1.1.X │ │ │ │ - * WMS 1.1.X is tightly coupled to SLD 1.0.0 │ │ │ │ - * │ │ │ │ - * Example DescribeLayer request: │ │ │ │ - * http://demo.opengeo.org/geoserver/wms?request=DescribeLayer&version=1.1.1&layers=topp:states │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMSDescribeLayer> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSDescribeLayer.v1_1_1 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WMSDescribeLayer, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WMSDescribeLayer │ │ │ │ - * Create a new parser for WMS DescribeLayer responses. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.WMSDescribeLayer.prototype.initialize.apply(this, │ │ │ │ - [options]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read DescribeLayer data from a string, and return the response. │ │ │ │ - * The OGC defines 2 formats which are allowed for output, │ │ │ │ - * so we need to parse these 2 types for version 1.1.X │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} Object with a layerDescriptions property, which holds an Array │ │ │ │ - * of {<LayerDescription>} objects which have: │ │ │ │ - * - {String} owsType: WFS/WCS │ │ │ │ - * - {String} owsURL: the online resource │ │ │ │ - * - {String} typeName: the name of the typename on the owsType service │ │ │ │ - * - {String} layerName: the name of the WMS layer we did a lookup for │ │ │ │ - */ │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - } │ │ │ │ - var root = data.documentElement; │ │ │ │ - var children = root.childNodes; │ │ │ │ - var describelayer = { │ │ │ │ - layerDescriptions: [] │ │ │ │ - }; │ │ │ │ - var childNode, nodeName; │ │ │ │ - for (var i = 0; i < children.length; ++i) { │ │ │ │ - childNode = children[i]; │ │ │ │ - nodeName = childNode.nodeName; │ │ │ │ - if (nodeName == 'LayerDescription') { │ │ │ │ - var layerName = childNode.getAttribute('name'); │ │ │ │ - var owsType = ''; │ │ │ │ - var owsURL = ''; │ │ │ │ - var typeName = ''; │ │ │ │ - // check for owsType and owsURL attributes │ │ │ │ - if (childNode.getAttribute('owsType')) { │ │ │ │ - owsType = childNode.getAttribute('owsType'); │ │ │ │ - owsURL = childNode.getAttribute('owsURL'); │ │ │ │ - } else { │ │ │ │ - // look for wfs or wcs attribute │ │ │ │ - if (childNode.getAttribute('wfs') != '') { │ │ │ │ - owsType = 'WFS'; │ │ │ │ - owsURL = childNode.getAttribute('wfs'); │ │ │ │ - } else if (childNode.getAttribute('wcs') != '') { │ │ │ │ - owsType = 'WCS'; │ │ │ │ - owsURL = childNode.getAttribute('wcs'); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - // look for Query child │ │ │ │ - var query = childNode.getElementsByTagName('Query'); │ │ │ │ - if (query.length > 0) { │ │ │ │ - typeName = query[0].getAttribute('typeName'); │ │ │ │ - if (!typeName) { │ │ │ │ - // because of Ionic bug │ │ │ │ - typeName = query[0].getAttribute('typename'); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var layerDescription = { │ │ │ │ - layerName: layerName, │ │ │ │ - owsType: owsType, │ │ │ │ - owsURL: owsURL, │ │ │ │ - typeName: typeName │ │ │ │ - }; │ │ │ │ - describelayer.layerDescriptions.push(layerDescription); │ │ │ │ - │ │ │ │ - //TODO do this in deprecated.js instead: │ │ │ │ - // array style index for backwards compatibility │ │ │ │ - describelayer.length = describelayer.layerDescriptions.length; │ │ │ │ - describelayer[describelayer.length - 1] = layerDescription; │ │ │ │ - │ │ │ │ - } else if (nodeName == 'ServiceException') { │ │ │ │ - // an exception must have occurred, so parse it │ │ │ │ - var parser = new OpenLayers.Format.OGCExceptionReport(); │ │ │ │ - return { │ │ │ │ - error: parser.read(data) │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return describelayer; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer.v1_1_1" │ │ │ │ - │ │ │ │ - }); │ │ │ │ - │ │ │ │ -// Version alias - workaround for http://trac.osgeo.org/mapserver/ticket/2257 │ │ │ │ -OpenLayers.Format.WMSDescribeLayer.v1_1_0 = │ │ │ │ - OpenLayers.Format.WMSDescribeLayer.v1_1_1; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSCapabilities/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/WMSCapabilities.js │ │ │ │ - * @requires OpenLayers/Format/OGCExceptionReport.js │ │ │ │ - * @requires OpenLayers/Format/XML.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSCapabilities.v1 │ │ │ │ - * Abstract class not to be instantiated directly. Creates │ │ │ │ - * the common parts for both WMS 1.1.X and WMS 1.3.X. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - wms: "http://www.opengis.net/wms", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ - */ │ │ │ │ - defaultPrefix: "wms", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WMSCapabilities.v1 │ │ │ │ - * Create an instance of one of the subclasses. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return a list of layers. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} List of named layers. │ │ │ │ - */ │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - } │ │ │ │ - var raw = data; │ │ │ │ - if (data && data.nodeType == 9) { │ │ │ │ - data = data.documentElement; │ │ │ │ - } │ │ │ │ - var capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - if (capabilities.service === undefined) { │ │ │ │ - // an exception must have occurred, so parse it │ │ │ │ - var parser = new OpenLayers.Format.OGCExceptionReport(); │ │ │ │ - capabilities.error = parser.read(raw); │ │ │ │ - } │ │ │ │ - return capabilities; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "wms": { │ │ │ │ - "Service": function(node, obj) { │ │ │ │ - obj.service = {}; │ │ │ │ - this.readChildNodes(node, obj.service); │ │ │ │ - }, │ │ │ │ - "Name": function(node, obj) { │ │ │ │ - obj.name = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Title": function(node, obj) { │ │ │ │ - obj.title = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Abstract": function(node, obj) { │ │ │ │ - obj["abstract"] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "BoundingBox": function(node, obj) { │ │ │ │ - var bbox = {}; │ │ │ │ - bbox.bbox = [ │ │ │ │ - parseFloat(node.getAttribute("minx")), │ │ │ │ - parseFloat(node.getAttribute("miny")), │ │ │ │ - parseFloat(node.getAttribute("maxx")), │ │ │ │ - parseFloat(node.getAttribute("maxy")) │ │ │ │ - ]; │ │ │ │ - var res = { │ │ │ │ - x: parseFloat(node.getAttribute("resx")), │ │ │ │ - y: parseFloat(node.getAttribute("resy")) │ │ │ │ - }; │ │ │ │ - │ │ │ │ - if (!(isNaN(res.x) && isNaN(res.y))) { │ │ │ │ - bbox.res = res; │ │ │ │ - } │ │ │ │ - // return the bbox so that descendant classes can set the │ │ │ │ - // CRS and SRS and add it to the obj │ │ │ │ - return bbox; │ │ │ │ - }, │ │ │ │ - "OnlineResource": function(node, obj) { │ │ │ │ - obj.href = this.getAttributeNS(node, this.namespaces.xlink, │ │ │ │ - "href"); │ │ │ │ - }, │ │ │ │ - "ContactInformation": function(node, obj) { │ │ │ │ - obj.contactInformation = {}; │ │ │ │ - this.readChildNodes(node, obj.contactInformation); │ │ │ │ - }, │ │ │ │ - "ContactPersonPrimary": function(node, obj) { │ │ │ │ - obj.personPrimary = {}; │ │ │ │ - this.readChildNodes(node, obj.personPrimary); │ │ │ │ - }, │ │ │ │ - "ContactPerson": function(node, obj) { │ │ │ │ - obj.person = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ContactOrganization": function(node, obj) { │ │ │ │ - obj.organization = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ContactPosition": function(node, obj) { │ │ │ │ - obj.position = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ContactAddress": function(node, obj) { │ │ │ │ - obj.contactAddress = {}; │ │ │ │ - this.readChildNodes(node, obj.contactAddress); │ │ │ │ - }, │ │ │ │ - "AddressType": function(node, obj) { │ │ │ │ - obj.type = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Address": function(node, obj) { │ │ │ │ - obj.address = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "City": function(node, obj) { │ │ │ │ - obj.city = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "StateOrProvince": function(node, obj) { │ │ │ │ - obj.stateOrProvince = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "PostCode": function(node, obj) { │ │ │ │ - obj.postcode = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Country": function(node, obj) { │ │ │ │ - obj.country = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ContactVoiceTelephone": function(node, obj) { │ │ │ │ - obj.phone = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ContactFacsimileTelephone": function(node, obj) { │ │ │ │ - obj.fax = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ContactElectronicMailAddress": function(node, obj) { │ │ │ │ - obj.email = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Fees": function(node, obj) { │ │ │ │ - var fees = this.getChildValue(node); │ │ │ │ - if (fees && fees.toLowerCase() != "none") { │ │ │ │ - obj.fees = fees; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "AccessConstraints": function(node, obj) { │ │ │ │ - var constraints = this.getChildValue(node); │ │ │ │ - if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ - obj.accessConstraints = constraints; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Capability": function(node, obj) { │ │ │ │ - obj.capability = { │ │ │ │ - nestedLayers: [], │ │ │ │ - layers: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.capability); │ │ │ │ - }, │ │ │ │ - "Request": function(node, obj) { │ │ │ │ - obj.request = {}; │ │ │ │ - this.readChildNodes(node, obj.request); │ │ │ │ - }, │ │ │ │ - "GetCapabilities": function(node, obj) { │ │ │ │ - obj.getcapabilities = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getcapabilities); │ │ │ │ - }, │ │ │ │ - "Format": function(node, obj) { │ │ │ │ - if (OpenLayers.Util.isArray(obj.formats)) { │ │ │ │ - obj.formats.push(this.getChildValue(node)); │ │ │ │ - } else { │ │ │ │ - obj.format = this.getChildValue(node); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "DCPType": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "HTTP": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "Get": function(node, obj) { │ │ │ │ - obj.get = {}; │ │ │ │ - this.readChildNodes(node, obj.get); │ │ │ │ - // backwards compatibility │ │ │ │ - if (!obj.href) { │ │ │ │ - obj.href = obj.get.href; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Post": function(node, obj) { │ │ │ │ - obj.post = {}; │ │ │ │ - this.readChildNodes(node, obj.post); │ │ │ │ - // backwards compatibility │ │ │ │ - if (!obj.href) { │ │ │ │ - obj.href = obj.get.href; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "GetMap": function(node, obj) { │ │ │ │ - obj.getmap = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getmap); │ │ │ │ - }, │ │ │ │ - "GetFeatureInfo": function(node, obj) { │ │ │ │ - obj.getfeatureinfo = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getfeatureinfo); │ │ │ │ - }, │ │ │ │ - "Exception": function(node, obj) { │ │ │ │ - obj.exception = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.exception); │ │ │ │ - }, │ │ │ │ - "Layer": function(node, obj) { │ │ │ │ - var parentLayer, capability; │ │ │ │ - if (obj.capability) { │ │ │ │ - capability = obj.capability; │ │ │ │ - parentLayer = obj; │ │ │ │ - } else { │ │ │ │ - capability = obj; │ │ │ │ - } │ │ │ │ - var attrNode = node.getAttributeNode("queryable"); │ │ │ │ - var queryable = (attrNode && attrNode.specified) ? │ │ │ │ - node.getAttribute("queryable") : null; │ │ │ │ - attrNode = node.getAttributeNode("cascaded"); │ │ │ │ - var cascaded = (attrNode && attrNode.specified) ? │ │ │ │ - node.getAttribute("cascaded") : null; │ │ │ │ - attrNode = node.getAttributeNode("opaque"); │ │ │ │ - var opaque = (attrNode && attrNode.specified) ? │ │ │ │ - node.getAttribute('opaque') : null; │ │ │ │ - var noSubsets = node.getAttribute('noSubsets'); │ │ │ │ - var fixedWidth = node.getAttribute('fixedWidth'); │ │ │ │ - var fixedHeight = node.getAttribute('fixedHeight'); │ │ │ │ - var parent = parentLayer || {}, │ │ │ │ - extend = OpenLayers.Util.extend; │ │ │ │ - var layer = { │ │ │ │ - nestedLayers: [], │ │ │ │ - styles: parentLayer ? [].concat(parentLayer.styles) : [], │ │ │ │ - srs: parentLayer ? extend({}, parent.srs) : {}, │ │ │ │ - metadataURLs: [], │ │ │ │ - bbox: parentLayer ? extend({}, parent.bbox) : {}, │ │ │ │ - llbbox: parent.llbbox, │ │ │ │ - dimensions: parentLayer ? extend({}, parent.dimensions) : {}, │ │ │ │ - authorityURLs: parentLayer ? extend({}, parent.authorityURLs) : {}, │ │ │ │ - identifiers: {}, │ │ │ │ - keywords: [], │ │ │ │ - queryable: (queryable && queryable !== "") ? │ │ │ │ - (queryable === "1" || queryable === "true") : (parent.queryable || false), │ │ │ │ - cascaded: (cascaded !== null) ? parseInt(cascaded) : (parent.cascaded || 0), │ │ │ │ - opaque: opaque ? │ │ │ │ - (opaque === "1" || opaque === "true") : (parent.opaque || false), │ │ │ │ - noSubsets: (noSubsets !== null) ? │ │ │ │ - (noSubsets === "1" || noSubsets === "true") : (parent.noSubsets || false), │ │ │ │ - fixedWidth: (fixedWidth != null) ? │ │ │ │ - parseInt(fixedWidth) : (parent.fixedWidth || 0), │ │ │ │ - fixedHeight: (fixedHeight != null) ? │ │ │ │ - parseInt(fixedHeight) : (parent.fixedHeight || 0), │ │ │ │ - minScale: parent.minScale, │ │ │ │ - maxScale: parent.maxScale, │ │ │ │ - attribution: parent.attribution │ │ │ │ - }; │ │ │ │ - obj.nestedLayers.push(layer); │ │ │ │ - layer.capability = capability; │ │ │ │ - this.readChildNodes(node, layer); │ │ │ │ - delete layer.capability; │ │ │ │ - if (layer.name) { │ │ │ │ - var parts = layer.name.split(":"), │ │ │ │ - request = capability.request, │ │ │ │ - gfi = request.getfeatureinfo; │ │ │ │ - if (parts.length > 0) { │ │ │ │ - layer.prefix = parts[0]; │ │ │ │ - } │ │ │ │ - capability.layers.push(layer); │ │ │ │ - if (layer.formats === undefined) { │ │ │ │ - layer.formats = request.getmap.formats; │ │ │ │ - } │ │ │ │ - if (layer.infoFormats === undefined && gfi) { │ │ │ │ - layer.infoFormats = gfi.formats; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Attribution": function(node, obj) { │ │ │ │ - obj.attribution = {}; │ │ │ │ - this.readChildNodes(node, obj.attribution); │ │ │ │ - }, │ │ │ │ - "LogoURL": function(node, obj) { │ │ │ │ - obj.logo = { │ │ │ │ - width: node.getAttribute("width"), │ │ │ │ - height: node.getAttribute("height") │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.logo); │ │ │ │ - }, │ │ │ │ - "Style": function(node, obj) { │ │ │ │ - var style = {}; │ │ │ │ - obj.styles.push(style); │ │ │ │ - this.readChildNodes(node, style); │ │ │ │ - }, │ │ │ │ - "LegendURL": function(node, obj) { │ │ │ │ - var legend = { │ │ │ │ - width: node.getAttribute("width"), │ │ │ │ - height: node.getAttribute("height") │ │ │ │ - }; │ │ │ │ - obj.legend = legend; │ │ │ │ - this.readChildNodes(node, legend); │ │ │ │ - }, │ │ │ │ - "MetadataURL": function(node, obj) { │ │ │ │ - var metadataURL = { │ │ │ │ - type: node.getAttribute("type") │ │ │ │ - }; │ │ │ │ - obj.metadataURLs.push(metadataURL); │ │ │ │ - this.readChildNodes(node, metadataURL); │ │ │ │ - }, │ │ │ │ - "DataURL": function(node, obj) { │ │ │ │ - obj.dataURL = {}; │ │ │ │ - this.readChildNodes(node, obj.dataURL); │ │ │ │ - }, │ │ │ │ - "FeatureListURL": function(node, obj) { │ │ │ │ - obj.featureListURL = {}; │ │ │ │ - this.readChildNodes(node, obj.featureListURL); │ │ │ │ - }, │ │ │ │ - "AuthorityURL": function(node, obj) { │ │ │ │ - var name = node.getAttribute("name"); │ │ │ │ - var authority = {}; │ │ │ │ - this.readChildNodes(node, authority); │ │ │ │ - obj.authorityURLs[name] = authority.href; │ │ │ │ - }, │ │ │ │ - "Identifier": function(node, obj) { │ │ │ │ - var authority = node.getAttribute("authority"); │ │ │ │ - obj.identifiers[authority] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "KeywordList": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "SRS": function(node, obj) { │ │ │ │ - obj.srs[this.getChildValue(node)] = true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSCapabilities/v1_1.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/WMSCapabilities/v1.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSCapabilities.v1_1 │ │ │ │ - * Abstract class not to be instantiated directly. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMSCapabilities.v1> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ - "WMT_MS_Capabilities": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "Keyword": function(node, obj) { │ │ │ │ - if (obj.keywords) { │ │ │ │ - obj.keywords.push(this.getChildValue(node)); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "DescribeLayer": function(node, obj) { │ │ │ │ - obj.describelayer = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.describelayer); │ │ │ │ - }, │ │ │ │ - "GetLegendGraphic": function(node, obj) { │ │ │ │ - obj.getlegendgraphic = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getlegendgraphic); │ │ │ │ - }, │ │ │ │ - "GetStyles": function(node, obj) { │ │ │ │ - obj.getstyles = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getstyles); │ │ │ │ - }, │ │ │ │ - "PutStyles": function(node, obj) { │ │ │ │ - obj.putstyles = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.putstyles); │ │ │ │ - }, │ │ │ │ - "UserDefinedSymbolization": function(node, obj) { │ │ │ │ - var userSymbols = { │ │ │ │ - supportSLD: parseInt(node.getAttribute("SupportSLD")) == 1, │ │ │ │ - userLayer: parseInt(node.getAttribute("UserLayer")) == 1, │ │ │ │ - userStyle: parseInt(node.getAttribute("UserStyle")) == 1, │ │ │ │ - remoteWFS: parseInt(node.getAttribute("RemoteWFS")) == 1 │ │ │ │ - }; │ │ │ │ - obj.userSymbols = userSymbols; │ │ │ │ - }, │ │ │ │ - "LatLonBoundingBox": function(node, obj) { │ │ │ │ - obj.llbbox = [ │ │ │ │ - parseFloat(node.getAttribute("minx")), │ │ │ │ - parseFloat(node.getAttribute("miny")), │ │ │ │ - parseFloat(node.getAttribute("maxx")), │ │ │ │ - parseFloat(node.getAttribute("maxy")) │ │ │ │ - ]; │ │ │ │ - }, │ │ │ │ - "BoundingBox": function(node, obj) { │ │ │ │ - var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ - bbox.srs = node.getAttribute("SRS"); │ │ │ │ - obj.bbox[bbox.srs] = bbox; │ │ │ │ - }, │ │ │ │ - "ScaleHint": function(node, obj) { │ │ │ │ - var min = node.getAttribute("min"); │ │ │ │ - var max = node.getAttribute("max"); │ │ │ │ - var rad2 = Math.pow(2, 0.5); │ │ │ │ - var ipm = OpenLayers.INCHES_PER_UNIT["m"]; │ │ │ │ - if (min != 0) { │ │ │ │ - obj.maxScale = parseFloat( │ │ │ │ - ((min / rad2) * ipm * │ │ │ │ - OpenLayers.DOTS_PER_INCH).toPrecision(13) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (max != Number.POSITIVE_INFINITY) { │ │ │ │ - obj.minScale = parseFloat( │ │ │ │ - ((max / rad2) * ipm * │ │ │ │ - OpenLayers.DOTS_PER_INCH).toPrecision(13) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Dimension": function(node, obj) { │ │ │ │ - var name = node.getAttribute("name").toLowerCase(); │ │ │ │ - var dim = { │ │ │ │ - name: name, │ │ │ │ - units: node.getAttribute("units"), │ │ │ │ - unitsymbol: node.getAttribute("unitSymbol") │ │ │ │ - }; │ │ │ │ - obj.dimensions[dim.name] = dim; │ │ │ │ - }, │ │ │ │ - "Extent": function(node, obj) { │ │ │ │ - var name = node.getAttribute("name").toLowerCase(); │ │ │ │ - if (name in obj["dimensions"]) { │ │ │ │ - var extent = obj.dimensions[name]; │ │ │ │ - extent.nearestVal = │ │ │ │ - node.getAttribute("nearestValue") === "1"; │ │ │ │ - extent.multipleVal = │ │ │ │ - node.getAttribute("multipleValues") === "1"; │ │ │ │ - extent.current = node.getAttribute("current") === "1"; │ │ │ │ - extent["default"] = node.getAttribute("default") || ""; │ │ │ │ - var values = this.getChildValue(node); │ │ │ │ - extent.values = values.split(","); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSCapabilities/v1_3.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/WMSCapabilities/v1.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSCapabilities/v1_3 │ │ │ │ - * Abstract base class for WMS Capabilities version 1.3.X. │ │ │ │ - * SLD 1.1.0 adds in the extra operations DescribeLayer and GetLegendGraphic, │ │ │ │ - * see: http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMSCapabilities.v1> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_3 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ - "WMS_Capabilities": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "LayerLimit": function(node, obj) { │ │ │ │ - obj.layerLimit = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "MaxWidth": function(node, obj) { │ │ │ │ - obj.maxWidth = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "MaxHeight": function(node, obj) { │ │ │ │ - obj.maxHeight = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "BoundingBox": function(node, obj) { │ │ │ │ - var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ - bbox.srs = node.getAttribute("CRS"); │ │ │ │ - obj.bbox[bbox.srs] = bbox; │ │ │ │ - }, │ │ │ │ - "CRS": function(node, obj) { │ │ │ │ - // CRS is the synonym of SRS │ │ │ │ - this.readers.wms.SRS.apply(this, [node, obj]); │ │ │ │ - }, │ │ │ │ - "EX_GeographicBoundingBox": function(node, obj) { │ │ │ │ - // replacement of LatLonBoundingBox │ │ │ │ - obj.llbbox = []; │ │ │ │ - this.readChildNodes(node, obj.llbbox); │ │ │ │ - │ │ │ │ - }, │ │ │ │ - "westBoundLongitude": function(node, obj) { │ │ │ │ - obj[0] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "eastBoundLongitude": function(node, obj) { │ │ │ │ - obj[2] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "southBoundLatitude": function(node, obj) { │ │ │ │ - obj[1] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "northBoundLatitude": function(node, obj) { │ │ │ │ - obj[3] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "MinScaleDenominator": function(node, obj) { │ │ │ │ - obj.maxScale = parseFloat(this.getChildValue(node)).toPrecision(16); │ │ │ │ - }, │ │ │ │ - "MaxScaleDenominator": function(node, obj) { │ │ │ │ - obj.minScale = parseFloat(this.getChildValue(node)).toPrecision(16); │ │ │ │ - }, │ │ │ │ - "Dimension": function(node, obj) { │ │ │ │ - // dimension has extra attributes: default, multipleValues, │ │ │ │ - // nearestValue, current which used to be part of Extent. It now │ │ │ │ - // also contains the values. │ │ │ │ - var name = node.getAttribute("name").toLowerCase(); │ │ │ │ - var dim = { │ │ │ │ - name: name, │ │ │ │ - units: node.getAttribute("units"), │ │ │ │ - unitsymbol: node.getAttribute("unitSymbol"), │ │ │ │ - nearestVal: node.getAttribute("nearestValue") === "1", │ │ │ │ - multipleVal: node.getAttribute("multipleValues") === "1", │ │ │ │ - "default": node.getAttribute("default") || "", │ │ │ │ - current: node.getAttribute("current") === "1", │ │ │ │ - values: this.getChildValue(node).split(",") │ │ │ │ - │ │ │ │ - }; │ │ │ │ - // Theoretically there can be more dimensions with the same │ │ │ │ - // name, but with a different unit. Until we meet such a case, │ │ │ │ - // let's just keep the same structure as the WMS 1.1 │ │ │ │ - // GetCapabilities parser uses. We will store the last │ │ │ │ - // one encountered. │ │ │ │ - obj.dimensions[dim.name] = dim; │ │ │ │ - }, │ │ │ │ - "Keyword": function(node, obj) { │ │ │ │ - // TODO: should we change the structure of keyword in v1.js? │ │ │ │ - // Make it an object with a value instead of a string? │ │ │ │ - var keyword = { │ │ │ │ - value: this.getChildValue(node), │ │ │ │ - vocabulary: node.getAttribute("vocabulary") │ │ │ │ - }; │ │ │ │ - if (obj.keywords) { │ │ │ │ - obj.keywords.push(keyword); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]), │ │ │ │ - "sld": { │ │ │ │ - "UserDefinedSymbolization": function(node, obj) { │ │ │ │ - this.readers.wms.UserDefinedSymbolization.apply(this, [node, obj]); │ │ │ │ - // add the two extra attributes │ │ │ │ - obj.userSymbols.inlineFeature = parseInt(node.getAttribute("InlineFeature")) == 1; │ │ │ │ - obj.userSymbols.remoteWCS = parseInt(node.getAttribute("RemoteWCS")) == 1; │ │ │ │ - }, │ │ │ │ - "DescribeLayer": function(node, obj) { │ │ │ │ - this.readers.wms.DescribeLayer.apply(this, [node, obj]); │ │ │ │ - }, │ │ │ │ - "GetLegendGraphic": function(node, obj) { │ │ │ │ - this.readers.wms.GetLegendGraphic.apply(this, [node, obj]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSCapabilities/v1_3_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/WMSCapabilities/v1_3.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSCapabilities/v1_3_0 │ │ │ │ - * Read WMS Capabilities version 1.3.0. │ │ │ │ - * SLD 1.1.0 adds in the extra operations DescribeLayer and GetLegendGraphic, │ │ │ │ - * see: http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMSCapabilities.v1_3> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_3_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WMSCapabilities.v1_3, { │ │ │ │ + * based on geometry type. │ │ │ │ + */ │ │ │ │ + buildGeometry: { │ │ │ │ + // TBD: Anybody care about namespace aliases here (these nodes have │ │ │ │ + // no prefixes)? │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: version │ │ │ │ - * {String} The specific parser version. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - version: "1.3.0", │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3_0" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSCapabilities/v1_1_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/WMSCapabilities/v1_1.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSCapabilities/v1_1_0 │ │ │ │ - * Read WMS Capabilities version 1.1.0. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMSCapabilities.v1_1> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ + point: function(geometry) { │ │ │ │ + var kml = this.createElementNS(this.kmlns, "Point"); │ │ │ │ + kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ + return kml; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: version │ │ │ │ - * {String} The specific parser version. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - version: "1.1.0", │ │ │ │ + multipoint: function(geometry) { │ │ │ │ + return this.buildGeometry.collection.apply(this, [geometry]); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_0 │ │ │ │ - * Create a new parser for WMS capabilities version 1.1.0. │ │ │ │ + * Method: buildGeometry.linestring │ │ │ │ + * Given an OpenLayers linestring geometry, create a KML linestring. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - readers: { │ │ │ │ - "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ - "SRS": function(node, obj) { │ │ │ │ - var srs = this.getChildValue(node); │ │ │ │ - var values = srs.split(/ +/); │ │ │ │ - for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ - obj.srs[values[i]] = true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ + multilinestring: function(geometry) { │ │ │ │ + return this.buildGeometry.collection.apply(this, [geometry]); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_0" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSCapabilities/v1_1_1.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/WMSCapabilities/v1_1.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSCapabilities/v1_1_1 │ │ │ │ - * Read WMS Capabilities version 1.1.1. │ │ │ │ - * │ │ │ │ - * Note on <ScaleHint> parsing: If the 'min' attribute is set to "0", no │ │ │ │ - * maxScale will be set on the layer object. If the 'max' attribute is set to │ │ │ │ - * "Infinity", no minScale will be set. This makes it easy to create proper │ │ │ │ - * {<OpenLayers.Layer.WMS>} configurations directly from the layer object │ │ │ │ - * literals returned by this format, because no minScale/maxScale modifications │ │ │ │ - * need to be made. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMSCapabilities.v1_1> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1_1 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: version │ │ │ │ - * {String} The specific parser version. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - version: "1.1.1", │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_1 │ │ │ │ - * Create a new parser for WMS capabilities version 1.1.1. │ │ │ │ + * Method: buildGeometry.multipolygon │ │ │ │ + * Given an OpenLayers multipolygon geometry, create a KML │ │ │ │ + * GeometryCollection. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * geometry - {<OpenLayers.Geometry.Point>} A multipolygon geometry. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A KML GeometryCollection node. │ │ │ │ */ │ │ │ │ + multipolygon: function(geometry) { │ │ │ │ + return this.buildGeometry.collection.apply(this, [geometry]); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - readers: { │ │ │ │ - "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ - "SRS": function(node, obj) { │ │ │ │ - obj.srs[this.getChildValue(node)] = true; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ - }, │ │ │ │ + } │ │ │ │ + return kml; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1" │ │ │ │ + /** │ │ │ │ + * 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/Format/WMSCapabilities/v1_1_1_WMSC.js │ │ │ │ + OpenLayers/Format/WPSCapabilities.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/WMSCapabilities/v1_1_1.js │ │ │ │ + * @requires OpenLayers/Format/XML/VersionedOGC.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WMSCapabilities/v1_1_1_WMSC │ │ │ │ - * Read WMS-C Capabilities version 1.1.1. │ │ │ │ + * Class: OpenLayers.Format.WPSCapabilities │ │ │ │ + * Read WPS Capabilities. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMSCapabilities.v1_1_1> │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WMSCapabilities.v1_1_1, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} The specific parser version. │ │ │ │ - */ │ │ │ │ - version: "1.1.1", │ │ │ │ +OpenLayers.Format.WPSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: profile │ │ │ │ - * {String} The specific profile │ │ │ │ - */ │ │ │ │ - profile: "WMSC", │ │ │ │ + /** │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "1.0.0". │ │ │ │ + */ │ │ │ │ + defaultVersion: "1.0.0", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_1 │ │ │ │ - * Create a new parser for WMS-C capabilities version 1.1.1. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WPSCapabilities │ │ │ │ + * Create a new parser for WPS Capabilities. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ - "VendorSpecificCapabilities": function(node, obj) { │ │ │ │ - obj.vendorSpecific = { │ │ │ │ - tileSets: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.vendorSpecific); │ │ │ │ - }, │ │ │ │ - "TileSet": function(node, vendorSpecific) { │ │ │ │ - var tileset = { │ │ │ │ - srs: {}, │ │ │ │ - bbox: {}, │ │ │ │ - resolutions: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, tileset); │ │ │ │ - vendorSpecific.tileSets.push(tileset); │ │ │ │ - }, │ │ │ │ - "Resolutions": function(node, tileset) { │ │ │ │ - var res = this.getChildValue(node).split(" "); │ │ │ │ - for (var i = 0, len = res.length; i < len; i++) { │ │ │ │ - if (res[i] != "") { │ │ │ │ - tileset.resolutions.push(parseFloat(res[i])); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Width": function(node, tileset) { │ │ │ │ - tileset.width = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "Height": function(node, tileset) { │ │ │ │ - tileset.height = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "Layers": function(node, tileset) { │ │ │ │ - tileset.layers = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Styles": function(node, tileset) { │ │ │ │ - tileset.styles = this.getChildValue(node); │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1_1_1.prototype.readers["wms"]) │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return information about │ │ │ │ + * the service. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} Info about the WPS │ │ │ │ + */ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WPSCapabilities" │ │ │ │ │ │ │ │ - }); │ │ │ │ +}); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WPSCapabilities/v1_0_0.js │ │ │ │ + OpenLayers/Format/WCSCapabilities/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/WPSCapabilities.js │ │ │ │ - * @requires OpenLayers/Format/OWSCommon/v1_1_0.js │ │ │ │ + * @requires OpenLayers/Format/WCSCapabilities.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WPSCapabilities.v1_0_0 │ │ │ │ - * Read WPS Capabilities version 1.0.0. │ │ │ │ + * Class: OpenLayers.Format.WCSCapabilities.v1 │ │ │ │ + * Abstract class not to be instantiated directly. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WPSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ +OpenLayers.Format.WCSCapabilities.v1 = OpenLayers.Class( │ │ │ │ OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - ows: "http://www.opengis.net/ows/1.1", │ │ │ │ - wps: "http://www.opengis.net/wps/1.0.0", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ - */ │ │ │ │ regExes: { │ │ │ │ trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ + splitSpace: (/\s+/) │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WPSCapabilities.v1_0_0 │ │ │ │ - * Create a new parser for WPS capabilities version 1.0.0. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * Property: defaultPrefix │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ - }, │ │ │ │ + defaultPrefix: "wcs", │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return info about the WPS. │ │ │ │ + * Read capabilities data from a string, and return a list of coverages. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * data - {String} or {DOMElement} data to read/parse. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} Information about the WPS service. │ │ │ │ + * {Array} List of named coverages. │ │ │ │ */ │ │ │ │ read: function(data) { │ │ │ │ if (typeof data == "string") { │ │ │ │ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ } │ │ │ │ + var raw = data; │ │ │ │ if (data && data.nodeType == 9) { │ │ │ │ data = data.documentElement; │ │ │ │ } │ │ │ │ var capabilities = {}; │ │ │ │ this.readNode(data, capabilities); │ │ │ │ return capabilities; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "wps": { │ │ │ │ - "Capabilities": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "ProcessOfferings": function(node, obj) { │ │ │ │ - obj.processOfferings = {}; │ │ │ │ - this.readChildNodes(node, obj.processOfferings); │ │ │ │ - }, │ │ │ │ - "Process": function(node, processOfferings) { │ │ │ │ - var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); │ │ │ │ - var process = { │ │ │ │ - processVersion: processVersion │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, process); │ │ │ │ - processOfferings[process.identifier] = process; │ │ │ │ - }, │ │ │ │ - "Languages": function(node, obj) { │ │ │ │ - obj.languages = []; │ │ │ │ - this.readChildNodes(node, obj.languages); │ │ │ │ - }, │ │ │ │ - "Default": function(node, languages) { │ │ │ │ - var language = { │ │ │ │ - isDefault: true │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, language); │ │ │ │ - languages.push(language); │ │ │ │ - }, │ │ │ │ - "Supported": function(node, languages) { │ │ │ │ - var language = {}; │ │ │ │ - this.readChildNodes(node, language); │ │ │ │ - languages.push(language); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WPSCapabilities.v1_0_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/CSWGetRecords/v2_0_2.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/CSWGetRecords.js │ │ │ │ - * @requires OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ - * @requires OpenLayers/Format/Filter/v1_1_0.js │ │ │ │ - * @requires OpenLayers/Format/OWSCommon/v1_0_0.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.CSWGetRecords.v2_0_2 │ │ │ │ - * A format for creating CSWGetRecords v2.0.2 transactions. │ │ │ │ - * Create a new instance with the │ │ │ │ - * <OpenLayers.Format.CSWGetRecords.v2_0_2> constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.CSWGetRecords.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - csw: "http://www.opengis.net/cat/csw/2.0.2", │ │ │ │ - dc: "http://purl.org/dc/elements/1.1/", │ │ │ │ - dct: "http://purl.org/dc/terms/", │ │ │ │ - gmd: "http://www.isotc211.org/2005/gmd", │ │ │ │ - geonet: "http://www.fao.org/geonetwork", │ │ │ │ - ogc: "http://www.opengis.net/ogc", │ │ │ │ - ows: "http://www.opengis.net/ows", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ - * {String} The default prefix (used by Format.XML). │ │ │ │ - */ │ │ │ │ - defaultPrefix: "csw", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} CSW version number. │ │ │ │ - */ │ │ │ │ - version: "2.0.2", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} http://www.opengis.net/cat/csw/2.0.2 │ │ │ │ - * http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd │ │ │ │ - */ │ │ │ │ - schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: requestId │ │ │ │ - * {String} Value of the requestId attribute of the GetRecords element. │ │ │ │ - */ │ │ │ │ - requestId: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: resultType │ │ │ │ - * {String} Value of the resultType attribute of the GetRecords element, │ │ │ │ - * specifies the result type in the GetRecords response, "hits" is │ │ │ │ - * the default. │ │ │ │ - */ │ │ │ │ - resultType: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: outputFormat │ │ │ │ - * {String} Value of the outputFormat attribute of the GetRecords element, │ │ │ │ - * specifies the format of the GetRecords response, │ │ │ │ - * "application/xml" is the default. │ │ │ │ - */ │ │ │ │ - outputFormat: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: outputSchema │ │ │ │ - * {String} Value of the outputSchema attribute of the GetRecords element, │ │ │ │ - * specifies the schema of the GetRecords response. │ │ │ │ - */ │ │ │ │ - outputSchema: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: startPosition │ │ │ │ - * {String} Value of the startPosition attribute of the GetRecords element, │ │ │ │ - * specifies the start position (offset+1) for the GetRecords response, │ │ │ │ - * 1 is the default. │ │ │ │ - */ │ │ │ │ - startPosition: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: maxRecords │ │ │ │ - * {String} Value of the maxRecords attribute of the GetRecords element, │ │ │ │ - * specifies the maximum number of records in the GetRecords response, │ │ │ │ - * 10 is the default. │ │ │ │ - */ │ │ │ │ - maxRecords: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: DistributedSearch │ │ │ │ - * {String} Value of the csw:DistributedSearch element, used when writing │ │ │ │ - * a csw:GetRecords document. │ │ │ │ - */ │ │ │ │ - DistributedSearch: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: ResponseHandler │ │ │ │ - * {Array({String})} Values of the csw:ResponseHandler elements, used when │ │ │ │ - * writting a csw:GetRecords document. │ │ │ │ - */ │ │ │ │ - ResponseHandler: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: Query │ │ │ │ - * {String} Value of the csw:Query element, used when writing a csw:GetRecords │ │ │ │ - * document. │ │ │ │ - */ │ │ │ │ - Query: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ - */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.CSWGetRecords.v2_0_2 │ │ │ │ - * A class for parsing and generating CSWGetRecords v2.0.2 transactions. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ - * │ │ │ │ - * Valid options properties (documented as class properties): │ │ │ │ - * - requestId │ │ │ │ - * - resultType │ │ │ │ - * - outputFormat │ │ │ │ - * - outputSchema │ │ │ │ - * - startPosition │ │ │ │ - * - maxRecords │ │ │ │ - * - DistributedSearch │ │ │ │ - * - ResponseHandler │ │ │ │ - * - Query │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Parse the response from a GetRecords request. │ │ │ │ - */ │ │ │ │ - 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 obj = {}; │ │ │ │ - this.readNode(data, obj); │ │ │ │ - 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: { │ │ │ │ - "csw": { │ │ │ │ - "GetRecordsResponse": function(node, obj) { │ │ │ │ - obj.records = []; │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - var version = this.getAttributeNS(node, "", 'version'); │ │ │ │ - if (version != "") { │ │ │ │ - obj.version = version; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "RequestId": function(node, obj) { │ │ │ │ - obj.RequestId = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "SearchStatus": function(node, obj) { │ │ │ │ - obj.SearchStatus = {}; │ │ │ │ - var timestamp = this.getAttributeNS(node, "", 'timestamp'); │ │ │ │ - if (timestamp != "") { │ │ │ │ - obj.SearchStatus.timestamp = timestamp; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "SearchResults": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var SearchResults = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - if ((attrs[i].name == "numberOfRecordsMatched") || │ │ │ │ - (attrs[i].name == "numberOfRecordsReturned") || │ │ │ │ - (attrs[i].name == "nextRecord")) { │ │ │ │ - SearchResults[attrs[i].name] = parseInt(attrs[i].nodeValue); │ │ │ │ - } else { │ │ │ │ - SearchResults[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - obj.SearchResults = SearchResults; │ │ │ │ - }, │ │ │ │ - "SummaryRecord": function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "SummaryRecord" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record); │ │ │ │ - }, │ │ │ │ - "BriefRecord": function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "BriefRecord" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record); │ │ │ │ - }, │ │ │ │ - "DCMIRecord": function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "DCMIRecord" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record); │ │ │ │ - }, │ │ │ │ - "Record": function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "Record" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record); │ │ │ │ - }, │ │ │ │ - "*": function(node, obj) { │ │ │ │ - var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ - obj[name] = this.getChildValue(node); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "geonet": { │ │ │ │ - "info": function(node, obj) { │ │ │ │ - var gninfo = {}; │ │ │ │ - this.readChildNodes(node, gninfo); │ │ │ │ - obj.gninfo = gninfo; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "dc": { │ │ │ │ - // audience, contributor, coverage, creator, date, description, format, │ │ │ │ - // identifier, language, provenance, publisher, relation, rights, │ │ │ │ - // rightsHolder, source, subject, title, type, URI │ │ │ │ - "*": function(node, obj) { │ │ │ │ - var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ - if (!(OpenLayers.Util.isArray(obj[name]))) { │ │ │ │ - obj[name] = []; │ │ │ │ - } │ │ │ │ - var dc_element = {}; │ │ │ │ - var attrs = node.attributes; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - dc_element[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ - } │ │ │ │ - dc_element.value = this.getChildValue(node); │ │ │ │ - if (dc_element.value != "") { │ │ │ │ - obj[name].push(dc_element); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "dct": { │ │ │ │ - // abstract, modified, spatial │ │ │ │ - "*": function(node, obj) { │ │ │ │ - var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ - if (!(OpenLayers.Util.isArray(obj[name]))) { │ │ │ │ - obj[name] = []; │ │ │ │ - } │ │ │ │ - obj[name].push(this.getChildValue(node)); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "ows": OpenLayers.Util.applyDefaults({ │ │ │ │ - "BoundingBox": function(node, obj) { │ │ │ │ - if (obj.bounds) { │ │ │ │ - obj.BoundingBox = [{ │ │ │ │ - crs: obj.projection, │ │ │ │ - value: [ │ │ │ │ - obj.bounds.left, │ │ │ │ - obj.bounds.bottom, │ │ │ │ - obj.bounds.right, │ │ │ │ - obj.bounds.top │ │ │ │ - ] │ │ │ │ - }]; │ │ │ │ - delete obj.projection; │ │ │ │ - delete obj.bounds; │ │ │ │ - } │ │ │ │ - OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]["BoundingBox"].apply( │ │ │ │ - this, arguments); │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: write │ │ │ │ - * Given an configuration js object, write a CSWGetRecords request. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} A object mapping the request. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A serialized CSWGetRecords request. │ │ │ │ - */ │ │ │ │ - write: function(options) { │ │ │ │ - var node = this.writeNode("csw:GetRecords", options); │ │ │ │ - node.setAttribute("xmlns:gmd", this.namespaces.gmd); │ │ │ │ - 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: { │ │ │ │ - "csw": { │ │ │ │ - "GetRecords": function(options) { │ │ │ │ - if (!options) { │ │ │ │ - options = {}; │ │ │ │ - } │ │ │ │ - var node = this.createElementNSPlus("csw:GetRecords", { │ │ │ │ - attributes: { │ │ │ │ - service: "CSW", │ │ │ │ - version: this.version, │ │ │ │ - requestId: options.requestId || this.requestId, │ │ │ │ - resultType: options.resultType || this.resultType, │ │ │ │ - outputFormat: options.outputFormat || this.outputFormat, │ │ │ │ - outputSchema: options.outputSchema || this.outputSchema, │ │ │ │ - startPosition: options.startPosition || this.startPosition, │ │ │ │ - maxRecords: options.maxRecords || this.maxRecords │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (options.DistributedSearch || this.DistributedSearch) { │ │ │ │ - this.writeNode( │ │ │ │ - "csw:DistributedSearch", │ │ │ │ - options.DistributedSearch || this.DistributedSearch, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - var ResponseHandler = options.ResponseHandler || this.ResponseHandler; │ │ │ │ - if (OpenLayers.Util.isArray(ResponseHandler) && ResponseHandler.length > 0) { │ │ │ │ - // ResponseHandler must be a non-empty array │ │ │ │ - for (var i = 0, len = ResponseHandler.length; i < len; i++) { │ │ │ │ - this.writeNode( │ │ │ │ - "csw:ResponseHandler", │ │ │ │ - ResponseHandler[i], │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.writeNode("Query", options.Query || this.Query, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "DistributedSearch": function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:DistributedSearch", { │ │ │ │ - attributes: { │ │ │ │ - hopCount: options.hopCount │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ResponseHandler": function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:ResponseHandler", { │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Query": function(options) { │ │ │ │ - if (!options) { │ │ │ │ - options = {}; │ │ │ │ - } │ │ │ │ - var node = this.createElementNSPlus("csw:Query", { │ │ │ │ - attributes: { │ │ │ │ - typeNames: options.typeNames || "csw:Record" │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - var ElementName = options.ElementName; │ │ │ │ - if (OpenLayers.Util.isArray(ElementName) && ElementName.length > 0) { │ │ │ │ - // ElementName must be a non-empty array │ │ │ │ - for (var i = 0, len = ElementName.length; i < len; i++) { │ │ │ │ - this.writeNode( │ │ │ │ - "csw:ElementName", │ │ │ │ - ElementName[i], │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.writeNode( │ │ │ │ - "csw:ElementSetName", │ │ │ │ - options.ElementSetName || { │ │ │ │ - value: 'summary' │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (options.Constraint) { │ │ │ │ - this.writeNode( │ │ │ │ - "csw:Constraint", │ │ │ │ - options.Constraint, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (options.SortBy) { │ │ │ │ - this.writeNode( │ │ │ │ - "ogc:SortBy", │ │ │ │ - options.SortBy, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ElementName": function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:ElementName", { │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ElementSetName": function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:ElementSetName", { │ │ │ │ - attributes: { │ │ │ │ - typeNames: options.typeNames │ │ │ │ - }, │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Constraint": function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:Constraint", { │ │ │ │ - attributes: { │ │ │ │ - version: options.version │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (options.Filter) { │ │ │ │ - var format = new OpenLayers.Format.Filter({ │ │ │ │ - version: options.version │ │ │ │ - }); │ │ │ │ - node.appendChild(format.write(options.Filter)); │ │ │ │ - } else if (options.CqlText) { │ │ │ │ - var child = this.createElementNSPlus("CqlText", { │ │ │ │ - value: options.CqlText.value │ │ │ │ - }); │ │ │ │ - node.appendChild(child); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "ogc": OpenLayers.Format.Filter.v1_1_0.prototype.writers["ogc"] │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.CSWGetRecords.v2_0_2" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/SLD/v1_0_0_GeoServer.js │ │ │ │ + OpenLayers/Format/WCSCapabilities/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/SLD/v1_0_0.js │ │ │ │ + * @requires OpenLayers/Format/WCSCapabilities/v1.js │ │ │ │ + * @requires OpenLayers/Format/GML/v3.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.SLD/v1_0_0_GeoServer │ │ │ │ - * Read and write SLD version 1.0.0 with GeoServer-specific enhanced options. │ │ │ │ - * See http://svn.osgeo.org/geotools/trunk/modules/extension/xsd/xsd-sld/src/main/resources/org/geotools/sld/bindings/StyledLayerDescriptor.xsd │ │ │ │ - * for more information. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.WCSCapabilities/v1_0_0 │ │ │ │ + * Read WCS Capabilities version 1.0.0. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.SLD.v1_0_0> │ │ │ │ + * - <OpenLayers.Format.WCSCapabilities.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.SLD.v1_0_0, { │ │ │ │ +OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: version │ │ │ │ - * {String} The specific parser version. │ │ │ │ + * Constructor: OpenLayers.Format.WCSCapabilities.v1_0_0 │ │ │ │ + * Create a new parser for WCS capabilities version 1.0.0. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ */ │ │ │ │ - version: "1.0.0", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: profile │ │ │ │ - * {String} The specific profile │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ - profile: "GeoServer", │ │ │ │ + namespaces: { │ │ │ │ + wcs: "http://www.opengis.net/wcs", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ + ows: "http://www.opengis.net/ows" │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.SLD.v1_0_0_GeoServer │ │ │ │ - * Create a new parser for GeoServer-enhanced SLD version 1.0.0. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * Property: errorProperty │ │ │ │ + * {String} Which property of the returned object to check for in order to │ │ │ │ + * determine whether or not parsing has failed. In the case that the │ │ │ │ + * errorProperty is undefined on the returned object, the document will be │ │ │ │ + * run through an OGCExceptionReport parser. │ │ │ │ */ │ │ │ │ + errorProperty: "service", │ │ │ │ │ │ │ │ /** │ │ │ │ * 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: OpenLayers.Util.applyDefaults({ │ │ │ │ - "sld": OpenLayers.Util.applyDefaults({ │ │ │ │ - "Priority": function(node, obj) { │ │ │ │ - var value = this.readers.ogc._expression.call(this, node); │ │ │ │ - if (value) { │ │ │ │ - obj.priority = value; │ │ │ │ - } │ │ │ │ + readers: { │ │ │ │ + "wcs": { │ │ │ │ + "WCS_Capabilities": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ }, │ │ │ │ - "VendorOption": function(node, obj) { │ │ │ │ - if (!obj.vendorOptions) { │ │ │ │ - obj.vendorOptions = {}; │ │ │ │ - } │ │ │ │ - obj.vendorOptions[node.getAttribute("name")] = this.getChildValue(node); │ │ │ │ + "Service": function(node, obj) { │ │ │ │ + obj.service = {}; │ │ │ │ + this.readChildNodes(node, obj.service); │ │ │ │ }, │ │ │ │ - "TextSymbolizer": function(node, rule) { │ │ │ │ - OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld.TextSymbolizer.apply(this, arguments); │ │ │ │ - var symbolizer = this.multipleSymbolizers ? rule.symbolizers[rule.symbolizers.length - 1] : rule.symbolizer["Text"]; │ │ │ │ - if (symbolizer.graphic === undefined) { │ │ │ │ - symbolizer.graphic = false; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.readers["sld"]) │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.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: OpenLayers.Util.applyDefaults({ │ │ │ │ - "sld": OpenLayers.Util.applyDefaults({ │ │ │ │ - "Priority": function(priority) { │ │ │ │ - return this.writers.sld._OGCExpression.call( │ │ │ │ - this, "sld:Priority", priority │ │ │ │ - ); │ │ │ │ + "name": function(node, service) { │ │ │ │ + service.name = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "VendorOption": function(option) { │ │ │ │ - return this.createElementNSPlus("sld:VendorOption", { │ │ │ │ - attributes: { │ │ │ │ - name: option.name │ │ │ │ - }, │ │ │ │ - value: option.value │ │ │ │ - }); │ │ │ │ + "label": function(node, service) { │ │ │ │ + service.label = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "TextSymbolizer": function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["TextSymbolizer"].apply(this, arguments); │ │ │ │ - if (symbolizer.graphic !== false && (symbolizer.externalGraphic || symbolizer.graphicName)) { │ │ │ │ - this.writeNode("Graphic", symbolizer, node); │ │ │ │ - } │ │ │ │ - if ("priority" in symbolizer) { │ │ │ │ - this.writeNode("Priority", symbolizer.priority, node); │ │ │ │ - } │ │ │ │ - return this.addVendorOptions(node, symbolizer); │ │ │ │ + "keywords": function(node, service) { │ │ │ │ + service.keywords = []; │ │ │ │ + this.readChildNodes(node, service.keywords); │ │ │ │ }, │ │ │ │ - "PointSymbolizer": function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["PointSymbolizer"].apply(this, arguments); │ │ │ │ - return this.addVendorOptions(node, symbolizer); │ │ │ │ + "keyword": function(node, keywords) { │ │ │ │ + // Append the keyword to the keywords list │ │ │ │ + keywords.push(this.getChildValue(node)); │ │ │ │ }, │ │ │ │ - "LineSymbolizer": function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["LineSymbolizer"].apply(this, arguments); │ │ │ │ - return this.addVendorOptions(node, symbolizer); │ │ │ │ + "responsibleParty": function(node, service) { │ │ │ │ + service.responsibleParty = {}; │ │ │ │ + this.readChildNodes(node, service.responsibleParty); │ │ │ │ }, │ │ │ │ - "PolygonSymbolizer": function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["PolygonSymbolizer"].apply(this, arguments); │ │ │ │ - return this.addVendorOptions(node, symbolizer); │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.writers["sld"]) │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.writers), │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: addVendorOptions │ │ │ │ - * Add in the VendorOption tags and return the node again. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} A DOM node. │ │ │ │ - * symbolizer - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A DOM node. │ │ │ │ - */ │ │ │ │ - addVendorOptions: function(node, symbolizer) { │ │ │ │ - var options = symbolizer.vendorOptions; │ │ │ │ - if (options) { │ │ │ │ - for (var key in symbolizer.vendorOptions) { │ │ │ │ - this.writeNode("VendorOption", { │ │ │ │ - name: key, │ │ │ │ - value: symbolizer.vendorOptions[key] │ │ │ │ - }, node); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0_GeoServer" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/CSWGetDomain/v2_0_2.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/CSWGetDomain.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.CSWGetDomain.v2_0_2 │ │ │ │ - * A format for creating CSWGetDomain v2.0.2 transactions. │ │ │ │ - * Create a new instance with the │ │ │ │ - * <OpenLayers.Format.CSWGetDomain.v2_0_2> constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.CSWGetDomain.v2_0_2 = 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", │ │ │ │ - csw: "http://www.opengis.net/cat/csw/2.0.2" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ - * {String} The default prefix (used by Format.XML). │ │ │ │ - */ │ │ │ │ - defaultPrefix: "csw", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} CSW version number. │ │ │ │ - */ │ │ │ │ - version: "2.0.2", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} http://www.opengis.net/cat/csw/2.0.2 │ │ │ │ - * http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd │ │ │ │ - */ │ │ │ │ - schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: PropertyName │ │ │ │ - * {String} Value of the csw:PropertyName element, used when │ │ │ │ - * writing a GetDomain document. │ │ │ │ - */ │ │ │ │ - PropertyName: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: ParameterName │ │ │ │ - * {String} Value of the csw:ParameterName element, used when │ │ │ │ - * writing a GetDomain document. │ │ │ │ - */ │ │ │ │ - ParameterName: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.CSWGetDomain.v2_0_2 │ │ │ │ - * A class for parsing and generating CSWGetDomain v2.0.2 transactions. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ - * │ │ │ │ - * Valid options properties: │ │ │ │ - * - PropertyName │ │ │ │ - * - ParameterName │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Parse the response from a GetDomain request. │ │ │ │ - */ │ │ │ │ - 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 obj = {}; │ │ │ │ - this.readNode(data, obj); │ │ │ │ - return obj; │ │ │ │ - }, │ │ │ │ + "individualName": function(node, responsibleParty) { │ │ │ │ + responsibleParty.individualName = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "organisationName": function(node, responsibleParty) { │ │ │ │ + responsibleParty.organisationName = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "positionName": function(node, responsibleParty) { │ │ │ │ + responsibleParty.positionName = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "contactInfo": function(node, responsibleParty) { │ │ │ │ + responsibleParty.contactInfo = {}; │ │ │ │ + this.readChildNodes(node, responsibleParty.contactInfo); │ │ │ │ + }, │ │ │ │ + "phone": function(node, contactInfo) { │ │ │ │ + contactInfo.phone = {}; │ │ │ │ + this.readChildNodes(node, contactInfo.phone); │ │ │ │ + }, │ │ │ │ + "voice": function(node, phone) { │ │ │ │ + phone.voice = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "facsimile": function(node, phone) { │ │ │ │ + phone.facsimile = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "address": function(node, contactInfo) { │ │ │ │ + contactInfo.address = {}; │ │ │ │ + this.readChildNodes(node, contactInfo.address); │ │ │ │ + }, │ │ │ │ + "deliveryPoint": function(node, address) { │ │ │ │ + address.deliveryPoint = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "city": function(node, address) { │ │ │ │ + address.city = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "postalCode": function(node, address) { │ │ │ │ + address.postalCode = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "country": function(node, address) { │ │ │ │ + address.country = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "electronicMailAddress": function(node, address) { │ │ │ │ + address.electronicMailAddress = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "fees": function(node, service) { │ │ │ │ + service.fees = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "accessConstraints": function(node, service) { │ │ │ │ + service.accessConstraints = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ContentMetadata": function(node, obj) { │ │ │ │ + obj.contentMetadata = []; │ │ │ │ + this.readChildNodes(node, obj.contentMetadata); │ │ │ │ + }, │ │ │ │ + "CoverageOfferingBrief": function(node, contentMetadata) { │ │ │ │ + var coverageOfferingBrief = {}; │ │ │ │ + this.readChildNodes(node, coverageOfferingBrief); │ │ │ │ + contentMetadata.push(coverageOfferingBrief); │ │ │ │ + }, │ │ │ │ + "name": function(node, coverageOfferingBrief) { │ │ │ │ + coverageOfferingBrief.name = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "label": function(node, coverageOfferingBrief) { │ │ │ │ + coverageOfferingBrief.label = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "lonLatEnvelope": function(node, coverageOfferingBrief) { │ │ │ │ + var nodeList = this.getElementsByTagNameNS(node, "http://www.opengis.net/gml", "pos"); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "csw": { │ │ │ │ - "GetDomainResponse": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "DomainValues": function(node, obj) { │ │ │ │ - if (!(OpenLayers.Util.isArray(obj.DomainValues))) { │ │ │ │ - obj.DomainValues = []; │ │ │ │ - } │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var domainValue = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - domainValue[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ - } │ │ │ │ - this.readChildNodes(node, domainValue); │ │ │ │ - obj.DomainValues.push(domainValue); │ │ │ │ - }, │ │ │ │ - "PropertyName": function(node, obj) { │ │ │ │ - obj.PropertyName = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ParameterName": function(node, obj) { │ │ │ │ - obj.ParameterName = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ListOfValues": function(node, obj) { │ │ │ │ - if (!(OpenLayers.Util.isArray(obj.ListOfValues))) { │ │ │ │ - obj.ListOfValues = []; │ │ │ │ - } │ │ │ │ - this.readChildNodes(node, obj.ListOfValues); │ │ │ │ - }, │ │ │ │ - "Value": function(node, obj) { │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var value = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - value[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ - } │ │ │ │ - value.value = this.getChildValue(node); │ │ │ │ - obj.push({ │ │ │ │ - Value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "ConceptualScheme": function(node, obj) { │ │ │ │ - obj.ConceptualScheme = {}; │ │ │ │ - this.readChildNodes(node, obj.ConceptualScheme); │ │ │ │ - }, │ │ │ │ - "Name": function(node, obj) { │ │ │ │ - obj.Name = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Document": function(node, obj) { │ │ │ │ - obj.Document = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Authority": function(node, obj) { │ │ │ │ - obj.Authority = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "RangeOfValues": function(node, obj) { │ │ │ │ - obj.RangeOfValues = {}; │ │ │ │ - this.readChildNodes(node, obj.RangeOfValues); │ │ │ │ - }, │ │ │ │ - "MinValue": function(node, obj) { │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var value = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - value[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ - } │ │ │ │ - value.value = this.getChildValue(node); │ │ │ │ - obj.MinValue = value; │ │ │ │ - }, │ │ │ │ - "MaxValue": function(node, obj) { │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var value = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - value[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ - } │ │ │ │ - value.value = this.getChildValue(node); │ │ │ │ - obj.MaxValue = value; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + // We expect two nodes here, to create the corners of a bounding box │ │ │ │ + if (nodeList.length == 2) { │ │ │ │ + var min = {}; │ │ │ │ + var max = {}; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Given an configuration js object, write a CSWGetDomain request. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} A object mapping the request. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A serialized CSWGetDomain request. │ │ │ │ - */ │ │ │ │ - write: function(options) { │ │ │ │ - var node = this.writeNode("csw:GetDomain", options); │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [node]); │ │ │ │ - }, │ │ │ │ + OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[0], min]); │ │ │ │ + OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[1], max]); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "csw": { │ │ │ │ - "GetDomain": function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:GetDomain", { │ │ │ │ - attributes: { │ │ │ │ - service: "CSW", │ │ │ │ - version: this.version │ │ │ │ + coverageOfferingBrief.lonLatEnvelope = {}; │ │ │ │ + coverageOfferingBrief.lonLatEnvelope.srsName = node.getAttribute("srsName"); │ │ │ │ + coverageOfferingBrief.lonLatEnvelope.min = min.points[0]; │ │ │ │ + coverageOfferingBrief.lonLatEnvelope.max = max.points[0]; │ │ │ │ } │ │ │ │ - }); │ │ │ │ - if (options.PropertyName || this.PropertyName) { │ │ │ │ - this.writeNode( │ │ │ │ - "csw:PropertyName", │ │ │ │ - options.PropertyName || this.PropertyName, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } else if (options.ParameterName || this.ParameterName) { │ │ │ │ - this.writeNode( │ │ │ │ - "csw:ParameterName", │ │ │ │ - options.ParameterName || this.ParameterName, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ } │ │ │ │ - this.readChildNodes(node, options); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "PropertyName": function(value) { │ │ │ │ - var node = this.createElementNSPlus("csw:PropertyName", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ParameterName": function(value) { │ │ │ │ - var node = this.createElementNSPlus("csw:ParameterName", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.CSWGetDomain.v2_0_2" │ │ │ │ -}); │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_0_0" │ │ │ │ + │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WMTSCapabilities/v1_0_0.js │ │ │ │ + OpenLayers/Format/WCSCapabilities/v1_1_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/WMTSCapabilities.js │ │ │ │ + * @requires OpenLayers/Format/WCSCapabilities/v1.js │ │ │ │ * @requires OpenLayers/Format/OWSCommon/v1_1_0.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WMTSCapabilities.v1_0_0 │ │ │ │ - * Read WMTS Capabilities version 1.0.0. │ │ │ │ + * Class: OpenLayers.Format.WCSCapabilities/v1_1_0 │ │ │ │ + * Read WCS Capabilities version 1.1.0. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMTSCapabilities> │ │ │ │ + * - <OpenLayers.Format.WCSCapabilities.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WMTSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.OWSCommon.v1_1_0, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} The parser version ("1.0.0"). │ │ │ │ - */ │ │ │ │ - version: "1.0.0", │ │ │ │ +OpenLayers.Format.WCSCapabilities.v1_1_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ │ │ │ │ /** │ │ │ │ * Property: namespaces │ │ │ │ * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ namespaces: { │ │ │ │ - ows: "http://www.opengis.net/ows/1.1", │ │ │ │ - wmts: "http://www.opengis.net/wmts/1.0", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink" │ │ │ │ + wcs: "http://www.opengis.net/wcs/1.1", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ + ows: "http://www.opengis.net/ows/1.1" │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: yx │ │ │ │ - * {Object} Members in the yx object are used to determine if a CRS URN │ │ │ │ - * corresponds to a CRS with y,x axis order. Member names are CRS URNs │ │ │ │ - * and values are boolean. Defaults come from the │ │ │ │ - * <OpenLayers.Format.WMTSCapabilities> prototype. │ │ │ │ - */ │ │ │ │ - yx: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ - * {String} The default namespace alias for creating element nodes. │ │ │ │ + * APIProperty: errorProperty │ │ │ │ + * {String} Which property of the returned object to check for in order to │ │ │ │ + * determine whether or not parsing has failed. In the case that the │ │ │ │ + * errorProperty is undefined on the returned object, the document will be │ │ │ │ + * run through an OGCExceptionReport parser. │ │ │ │ */ │ │ │ │ - defaultPrefix: "wmts", │ │ │ │ + errorProperty: "operationsMetadata", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WMTSCapabilities.v1_0_0 │ │ │ │ - * Create a new parser for WMTS capabilities version 1.0.0. │ │ │ │ + * Constructor: OpenLayers.Format.WCSCapabilities.v1_1_0 │ │ │ │ + * Create a new parser for WCS capabilities version 1.1.0. │ │ │ │ * │ │ │ │ * 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]); │ │ │ │ - this.options = options; │ │ │ │ - var yx = OpenLayers.Util.extend({}, OpenLayers.Format.WMTSCapabilities.prototype.yx); │ │ │ │ - this.yx = OpenLayers.Util.extend(yx, this.yx); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return info about the WMTS. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} Information about the SOS service. │ │ │ │ - */ │ │ │ │ - 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 capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - capabilities.version = this.version; │ │ │ │ - return capabilities; │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ * 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: { │ │ │ │ - "wmts": { │ │ │ │ + "wcs": OpenLayers.Util.applyDefaults({ │ │ │ │ + // In 1.0.0, this was WCS_Capabilties, in 1.1.0, it's Capabilities │ │ │ │ "Capabilities": function(node, obj) { │ │ │ │ this.readChildNodes(node, obj); │ │ │ │ }, │ │ │ │ - "Contents": function(node, obj) { │ │ │ │ - obj.contents = {}; │ │ │ │ - obj.contents.layers = []; │ │ │ │ - obj.contents.tileMatrixSets = {}; │ │ │ │ - this.readChildNodes(node, obj.contents); │ │ │ │ - }, │ │ │ │ - "Layer": function(node, obj) { │ │ │ │ - var layer = { │ │ │ │ - styles: [], │ │ │ │ - formats: [], │ │ │ │ - dimensions: [], │ │ │ │ - tileMatrixSetLinks: [] │ │ │ │ - }; │ │ │ │ - layer.layers = []; │ │ │ │ - this.readChildNodes(node, layer); │ │ │ │ - obj.layers.push(layer); │ │ │ │ - }, │ │ │ │ - "Style": function(node, obj) { │ │ │ │ - var style = {}; │ │ │ │ - style.isDefault = (node.getAttribute("isDefault") === "true"); │ │ │ │ - this.readChildNodes(node, style); │ │ │ │ - obj.styles.push(style); │ │ │ │ - }, │ │ │ │ - "Format": function(node, obj) { │ │ │ │ - obj.formats.push(this.getChildValue(node)); │ │ │ │ + "Contents": function(node, request) { │ │ │ │ + request.contentMetadata = []; │ │ │ │ + this.readChildNodes(node, request.contentMetadata); │ │ │ │ }, │ │ │ │ - "TileMatrixSetLink": function(node, obj) { │ │ │ │ - var tileMatrixSetLink = {}; │ │ │ │ - this.readChildNodes(node, tileMatrixSetLink); │ │ │ │ - obj.tileMatrixSetLinks.push(tileMatrixSetLink); │ │ │ │ + "CoverageSummary": function(node, contentMetadata) { │ │ │ │ + var coverageSummary = {}; │ │ │ │ + // Read the summary: │ │ │ │ + this.readChildNodes(node, coverageSummary); │ │ │ │ + │ │ │ │ + // Add it to the contentMetadata array: │ │ │ │ + contentMetadata.push(coverageSummary); │ │ │ │ }, │ │ │ │ - "TileMatrixSet": function(node, obj) { │ │ │ │ - // node could be child of wmts:Contents or wmts:TileMatrixSetLink │ │ │ │ - // duck type wmts:Contents by looking for layers │ │ │ │ - if (obj.layers) { │ │ │ │ - // TileMatrixSet as object type in schema │ │ │ │ - var tileMatrixSet = { │ │ │ │ - matrixIds: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, tileMatrixSet); │ │ │ │ - obj.tileMatrixSets[tileMatrixSet.identifier] = tileMatrixSet; │ │ │ │ - } else { │ │ │ │ - // TileMatrixSet as string type in schema │ │ │ │ - obj.tileMatrixSet = this.getChildValue(node); │ │ │ │ - } │ │ │ │ + "Identifier": function(node, coverageSummary) { │ │ │ │ + coverageSummary.identifier = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "TileMatrix": function(node, obj) { │ │ │ │ - var tileMatrix = { │ │ │ │ - supportedCRS: obj.supportedCRS │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, tileMatrix); │ │ │ │ - obj.matrixIds.push(tileMatrix); │ │ │ │ + "Title": function(node, coverageSummary) { │ │ │ │ + coverageSummary.title = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "ScaleDenominator": function(node, obj) { │ │ │ │ - obj.scaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ + "Abstract": function(node, coverageSummary) { │ │ │ │ + coverageSummary["abstract"] = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "TopLeftCorner": function(node, obj) { │ │ │ │ - var topLeftCorner = this.getChildValue(node); │ │ │ │ - var coords = topLeftCorner.split(" "); │ │ │ │ - // decide on axis order for the given CRS │ │ │ │ - var yx; │ │ │ │ - if (obj.supportedCRS) { │ │ │ │ - // extract out version from URN │ │ │ │ - var crs = obj.supportedCRS.replace( │ │ │ │ - /urn:ogc:def:crs:(\w+):.+:(\w+)$/, │ │ │ │ - "urn:ogc:def:crs:$1::$2" │ │ │ │ - ); │ │ │ │ - yx = !!this.yx[crs]; │ │ │ │ - } │ │ │ │ - if (yx) { │ │ │ │ - obj.topLeftCorner = new OpenLayers.LonLat( │ │ │ │ - coords[1], coords[0] │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - obj.topLeftCorner = new OpenLayers.LonLat( │ │ │ │ - coords[0], coords[1] │ │ │ │ - ); │ │ │ │ + "SupportedCRS": function(node, coverageSummary) { │ │ │ │ + var crs = this.getChildValue(node); │ │ │ │ + if (crs) { │ │ │ │ + if (!coverageSummary.supportedCRS) { │ │ │ │ + coverageSummary.supportedCRS = []; │ │ │ │ + } │ │ │ │ + coverageSummary.supportedCRS.push(crs); │ │ │ │ } │ │ │ │ }, │ │ │ │ - "TileWidth": function(node, obj) { │ │ │ │ - obj.tileWidth = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "TileHeight": function(node, obj) { │ │ │ │ - obj.tileHeight = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "MatrixWidth": function(node, obj) { │ │ │ │ - obj.matrixWidth = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "MatrixHeight": function(node, obj) { │ │ │ │ - obj.matrixHeight = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "ResourceURL": function(node, obj) { │ │ │ │ - obj.resourceUrl = obj.resourceUrl || {}; │ │ │ │ - var resourceType = node.getAttribute("resourceType"); │ │ │ │ - if (!obj.resourceUrls) { │ │ │ │ - obj.resourceUrls = []; │ │ │ │ + "SupportedFormat": function(node, coverageSummary) { │ │ │ │ + var format = this.getChildValue(node); │ │ │ │ + if (format) { │ │ │ │ + if (!coverageSummary.supportedFormat) { │ │ │ │ + coverageSummary.supportedFormat = []; │ │ │ │ + } │ │ │ │ + coverageSummary.supportedFormat.push(format); │ │ │ │ } │ │ │ │ - var resourceUrl = obj.resourceUrl[resourceType] = { │ │ │ │ - format: node.getAttribute("format"), │ │ │ │ - template: node.getAttribute("template"), │ │ │ │ - resourceType: resourceType │ │ │ │ - }; │ │ │ │ - obj.resourceUrls.push(resourceUrl); │ │ │ │ - }, │ │ │ │ - // not used for now, can be added in the future though │ │ │ │ - /*"Themes": function(node, obj) { │ │ │ │ - obj.themes = []; │ │ │ │ - this.readChildNodes(node, obj.themes); │ │ │ │ - }, │ │ │ │ - "Theme": function(node, obj) { │ │ │ │ - var theme = {}; │ │ │ │ - this.readChildNodes(node, theme); │ │ │ │ - obj.push(theme); │ │ │ │ - },*/ │ │ │ │ - "WSDL": function(node, obj) { │ │ │ │ - obj.wsdl = {}; │ │ │ │ - obj.wsdl.href = node.getAttribute("xlink:href"); │ │ │ │ - // TODO: other attributes of <WSDL> element │ │ │ │ - }, │ │ │ │ - "ServiceMetadataURL": function(node, obj) { │ │ │ │ - obj.serviceMetadataUrl = {}; │ │ │ │ - obj.serviceMetadataUrl.href = node.getAttribute("xlink:href"); │ │ │ │ - // TODO: other attributes of <ServiceMetadataURL> element │ │ │ │ - }, │ │ │ │ - "LegendURL": function(node, obj) { │ │ │ │ - obj.legend = {}; │ │ │ │ - obj.legend.href = node.getAttribute("xlink:href"); │ │ │ │ - obj.legend.format = node.getAttribute("format"); │ │ │ │ - }, │ │ │ │ - "Dimension": function(node, obj) { │ │ │ │ - var dimension = { │ │ │ │ - values: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, dimension); │ │ │ │ - obj.dimensions.push(dimension); │ │ │ │ - }, │ │ │ │ - "Default": function(node, obj) { │ │ │ │ - obj["default"] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Value": function(node, obj) { │ │ │ │ - obj.values.push(this.getChildValue(node)); │ │ │ │ } │ │ │ │ - }, │ │ │ │ + }, OpenLayers.Format.WCSCapabilities.v1.prototype.readers["wcs"]), │ │ │ │ "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMTSCapabilities.v1_0_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_1_0" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Format/WMC/v1.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ @@ -81186,143 +81235,101 @@ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.WMC.v1" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WMC/v1_1_0.js │ │ │ │ + OpenLayers/Format/WMC/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/WMC/v1.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WMC.v1_1_0 │ │ │ │ - * Read and write WMC version 1.1.0. │ │ │ │ - * │ │ │ │ - * Differences between 1.1.0 and 1.0.0: │ │ │ │ - * - 1.1.0 Layers have optional sld:MinScaleDenominator and │ │ │ │ - * sld:MaxScaleDenominator │ │ │ │ + * Class: OpenLayers.Format.WMC.v1_0_0 │ │ │ │ + * Read and write WMC version 1.0.0. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Format.WMC.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WMC.v1_1_0 = OpenLayers.Class( │ │ │ │ +OpenLayers.Format.WMC.v1_0_0 = OpenLayers.Class( │ │ │ │ OpenLayers.Format.WMC.v1, { │ │ │ │ │ │ │ │ /** │ │ │ │ * Constant: VERSION │ │ │ │ - * {String} 1.1.0 │ │ │ │ + * {String} 1.0.0 │ │ │ │ */ │ │ │ │ - VERSION: "1.1.0", │ │ │ │ + VERSION: "1.0.0", │ │ │ │ │ │ │ │ /** │ │ │ │ * Property: schemaLocation │ │ │ │ * {String} http://www.opengis.net/context │ │ │ │ - * http://schemas.opengis.net/context/1.1.0/context.xsd │ │ │ │ + * http://schemas.opengis.net/context/1.0.0/context.xsd │ │ │ │ */ │ │ │ │ - schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.1.0/context.xsd", │ │ │ │ + schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.0.0/context.xsd", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WMC.v1_1_0 │ │ │ │ + * Constructor: OpenLayers.Format.WMC.v1_0_0 │ │ │ │ * Instances of this class are not created directly. Use the │ │ │ │ * <OpenLayers.Format.WMC> constructor instead. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be set on │ │ │ │ * this instance. │ │ │ │ */ │ │ │ │ initialize: function(options) { │ │ │ │ OpenLayers.Format.WMC.v1.prototype.initialize.apply( │ │ │ │ this, [options] │ │ │ │ ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: read_sld_MinScaleDenominator │ │ │ │ - * Read a sld:MinScaleDenominator node. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layerContext - {Object} An object representing a layer. │ │ │ │ - * node - {Element} An element node. │ │ │ │ - */ │ │ │ │ - read_sld_MinScaleDenominator: function(layerContext, node) { │ │ │ │ - var minScaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ - if (minScaleDenominator > 0) { │ │ │ │ - layerContext.maxScale = minScaleDenominator; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: read_sld_MaxScaleDenominator │ │ │ │ - * Read a sld:MaxScaleDenominator node. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layerContext - {Object} An object representing a layer. │ │ │ │ - * node - {Element} An element node. │ │ │ │ - */ │ │ │ │ - read_sld_MaxScaleDenominator: function(layerContext, node) { │ │ │ │ - layerContext.minScale = parseFloat(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ * Method: read_wmc_SRS │ │ │ │ */ │ │ │ │ read_wmc_SRS: function(layerContext, node) { │ │ │ │ - if (!("srs" in layerContext)) { │ │ │ │ - layerContext.srs = {}; │ │ │ │ + var srs = this.getChildValue(node); │ │ │ │ + if (typeof layerContext.projections != "object") { │ │ │ │ + layerContext.projections = {}; │ │ │ │ + } │ │ │ │ + var values = srs.split(/ +/); │ │ │ │ + for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ + layerContext.projections[values[i]] = true; │ │ │ │ } │ │ │ │ - layerContext.srs[this.getChildValue(node)] = true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * Method: write_wmc_Layer │ │ │ │ * Create a Layer node given a layer context object. This method adds │ │ │ │ - * elements specific to version 1.1.0. │ │ │ │ + * elements specific to version 1.0.0. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * context - {Object} A layer context object.} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ * {Element} A WMC Layer element node. │ │ │ │ */ │ │ │ │ write_wmc_Layer: function(context) { │ │ │ │ var node = OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply( │ │ │ │ this, [context] │ │ │ │ ); │ │ │ │ │ │ │ │ - // min/max scale denominator elements go before the 4th element in v1 │ │ │ │ - if (context.maxScale) { │ │ │ │ - var minSD = this.createElementNS( │ │ │ │ - this.namespaces.sld, "sld:MinScaleDenominator" │ │ │ │ - ); │ │ │ │ - minSD.appendChild(this.createTextNode(context.maxScale.toPrecision(16))); │ │ │ │ - node.appendChild(minSD); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (context.minScale) { │ │ │ │ - var maxSD = this.createElementNS( │ │ │ │ - this.namespaces.sld, "sld:MaxScaleDenominator" │ │ │ │ - ); │ │ │ │ - maxSD.appendChild(this.createTextNode(context.minScale.toPrecision(16))); │ │ │ │ - node.appendChild(maxSD); │ │ │ │ - } │ │ │ │ - │ │ │ │ // optional SRS element(s) │ │ │ │ if (context.srs) { │ │ │ │ + var projections = []; │ │ │ │ for (var name in context.srs) { │ │ │ │ - node.appendChild(this.createElementDefaultNS("SRS", name)); │ │ │ │ + projections.push(name); │ │ │ │ } │ │ │ │ + node.appendChild(this.createElementDefaultNS("SRS", projections.join(" "))); │ │ │ │ } │ │ │ │ │ │ │ │ // optional FormatList element │ │ │ │ node.appendChild(this.write_wmc_FormatList(context)); │ │ │ │ │ │ │ │ // optional StyleList element │ │ │ │ node.appendChild(this.write_wmc_StyleList(context)); │ │ │ │ @@ -81330,110 +81337,149 @@ │ │ │ │ // optional DimensionList element │ │ │ │ if (context.dimensions) { │ │ │ │ node.appendChild(this.write_wmc_DimensionList(context)); │ │ │ │ } │ │ │ │ │ │ │ │ // OpenLayers specific properties go in an Extension element │ │ │ │ node.appendChild(this.write_wmc_LayerExtension(context)); │ │ │ │ - │ │ │ │ - return node; │ │ │ │ - │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMC.v1_1_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMC.v1_0_0" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WMC/v1_0_0.js │ │ │ │ + OpenLayers/Format/WMC/v1_1_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/WMC/v1.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WMC.v1_0_0 │ │ │ │ - * Read and write WMC version 1.0.0. │ │ │ │ + * Class: OpenLayers.Format.WMC.v1_1_0 │ │ │ │ + * Read and write WMC version 1.1.0. │ │ │ │ + * │ │ │ │ + * Differences between 1.1.0 and 1.0.0: │ │ │ │ + * - 1.1.0 Layers have optional sld:MinScaleDenominator and │ │ │ │ + * sld:MaxScaleDenominator │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Format.WMC.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WMC.v1_0_0 = OpenLayers.Class( │ │ │ │ +OpenLayers.Format.WMC.v1_1_0 = OpenLayers.Class( │ │ │ │ OpenLayers.Format.WMC.v1, { │ │ │ │ │ │ │ │ /** │ │ │ │ * Constant: VERSION │ │ │ │ - * {String} 1.0.0 │ │ │ │ + * {String} 1.1.0 │ │ │ │ */ │ │ │ │ - VERSION: "1.0.0", │ │ │ │ + VERSION: "1.1.0", │ │ │ │ │ │ │ │ /** │ │ │ │ * Property: schemaLocation │ │ │ │ * {String} http://www.opengis.net/context │ │ │ │ - * http://schemas.opengis.net/context/1.0.0/context.xsd │ │ │ │ + * http://schemas.opengis.net/context/1.1.0/context.xsd │ │ │ │ */ │ │ │ │ - schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.0.0/context.xsd", │ │ │ │ + schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.1.0/context.xsd", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WMC.v1_0_0 │ │ │ │ + * Constructor: OpenLayers.Format.WMC.v1_1_0 │ │ │ │ * Instances of this class are not created directly. Use the │ │ │ │ * <OpenLayers.Format.WMC> constructor instead. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be set on │ │ │ │ * this instance. │ │ │ │ */ │ │ │ │ initialize: function(options) { │ │ │ │ OpenLayers.Format.WMC.v1.prototype.initialize.apply( │ │ │ │ this, [options] │ │ │ │ ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ + * Method: read_sld_MinScaleDenominator │ │ │ │ + * Read a sld:MinScaleDenominator node. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layerContext - {Object} An object representing a layer. │ │ │ │ + * node - {Element} An element node. │ │ │ │ + */ │ │ │ │ + read_sld_MinScaleDenominator: function(layerContext, node) { │ │ │ │ + var minScaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ + if (minScaleDenominator > 0) { │ │ │ │ + layerContext.maxScale = minScaleDenominator; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: read_sld_MaxScaleDenominator │ │ │ │ + * Read a sld:MaxScaleDenominator node. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layerContext - {Object} An object representing a layer. │ │ │ │ + * node - {Element} An element node. │ │ │ │ + */ │ │ │ │ + read_sld_MaxScaleDenominator: function(layerContext, node) { │ │ │ │ + layerContext.minScale = parseFloat(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ * Method: read_wmc_SRS │ │ │ │ */ │ │ │ │ read_wmc_SRS: function(layerContext, node) { │ │ │ │ - var srs = this.getChildValue(node); │ │ │ │ - if (typeof layerContext.projections != "object") { │ │ │ │ - layerContext.projections = {}; │ │ │ │ - } │ │ │ │ - var values = srs.split(/ +/); │ │ │ │ - for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ - layerContext.projections[values[i]] = true; │ │ │ │ + if (!("srs" in layerContext)) { │ │ │ │ + layerContext.srs = {}; │ │ │ │ } │ │ │ │ + layerContext.srs[this.getChildValue(node)] = true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * Method: write_wmc_Layer │ │ │ │ * Create a Layer node given a layer context object. This method adds │ │ │ │ - * elements specific to version 1.0.0. │ │ │ │ + * elements specific to version 1.1.0. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * context - {Object} A layer context object.} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ * {Element} A WMC Layer element node. │ │ │ │ */ │ │ │ │ write_wmc_Layer: function(context) { │ │ │ │ var node = OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply( │ │ │ │ this, [context] │ │ │ │ ); │ │ │ │ │ │ │ │ + // min/max scale denominator elements go before the 4th element in v1 │ │ │ │ + if (context.maxScale) { │ │ │ │ + var minSD = this.createElementNS( │ │ │ │ + this.namespaces.sld, "sld:MinScaleDenominator" │ │ │ │ + ); │ │ │ │ + minSD.appendChild(this.createTextNode(context.maxScale.toPrecision(16))); │ │ │ │ + node.appendChild(minSD); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (context.minScale) { │ │ │ │ + var maxSD = this.createElementNS( │ │ │ │ + this.namespaces.sld, "sld:MaxScaleDenominator" │ │ │ │ + ); │ │ │ │ + maxSD.appendChild(this.createTextNode(context.minScale.toPrecision(16))); │ │ │ │ + node.appendChild(maxSD); │ │ │ │ + } │ │ │ │ + │ │ │ │ // optional SRS element(s) │ │ │ │ if (context.srs) { │ │ │ │ - var projections = []; │ │ │ │ for (var name in context.srs) { │ │ │ │ - projections.push(name); │ │ │ │ + node.appendChild(this.createElementDefaultNS("SRS", name)); │ │ │ │ } │ │ │ │ - node.appendChild(this.createElementDefaultNS("SRS", projections.join(" "))); │ │ │ │ } │ │ │ │ │ │ │ │ // optional FormatList element │ │ │ │ node.appendChild(this.write_wmc_FormatList(context)); │ │ │ │ │ │ │ │ // optional StyleList element │ │ │ │ node.appendChild(this.write_wmc_StyleList(context)); │ │ │ │ @@ -81441,682 +81487,20 @@ │ │ │ │ // optional DimensionList element │ │ │ │ if (context.dimensions) { │ │ │ │ node.appendChild(this.write_wmc_DimensionList(context)); │ │ │ │ } │ │ │ │ │ │ │ │ // OpenLayers specific properties go in an Extension element │ │ │ │ node.appendChild(this.write_wmc_LayerExtension(context)); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMC.v1_0_0" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WCSCapabilities/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/WCSCapabilities.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WCSCapabilities.v1 │ │ │ │ - * Abstract class not to be instantiated directly. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WCSCapabilities.v1 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - splitSpace: (/\s+/) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ - */ │ │ │ │ - defaultPrefix: "wcs", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return a list of coverages. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} List of named coverages. │ │ │ │ - */ │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - } │ │ │ │ - var raw = data; │ │ │ │ - if (data && data.nodeType == 9) { │ │ │ │ - data = data.documentElement; │ │ │ │ - } │ │ │ │ - var capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - return capabilities; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WCSCapabilities/v1_1_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/WCSCapabilities/v1.js │ │ │ │ - * @requires OpenLayers/Format/OWSCommon/v1_1_0.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WCSCapabilities/v1_1_0 │ │ │ │ - * Read WCS Capabilities version 1.1.0. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WCSCapabilities.v1> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WCSCapabilities.v1_1_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - wcs: "http://www.opengis.net/wcs/1.1", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ - ows: "http://www.opengis.net/ows/1.1" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: errorProperty │ │ │ │ - * {String} Which property of the returned object to check for in order to │ │ │ │ - * determine whether or not parsing has failed. In the case that the │ │ │ │ - * errorProperty is undefined on the returned object, the document will be │ │ │ │ - * run through an OGCExceptionReport parser. │ │ │ │ - */ │ │ │ │ - errorProperty: "operationsMetadata", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WCSCapabilities.v1_1_0 │ │ │ │ - * Create a new parser for WCS capabilities version 1.1.0. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "wcs": OpenLayers.Util.applyDefaults({ │ │ │ │ - // In 1.0.0, this was WCS_Capabilties, in 1.1.0, it's Capabilities │ │ │ │ - "Capabilities": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "Contents": function(node, request) { │ │ │ │ - request.contentMetadata = []; │ │ │ │ - this.readChildNodes(node, request.contentMetadata); │ │ │ │ - }, │ │ │ │ - "CoverageSummary": function(node, contentMetadata) { │ │ │ │ - var coverageSummary = {}; │ │ │ │ - // Read the summary: │ │ │ │ - this.readChildNodes(node, coverageSummary); │ │ │ │ - │ │ │ │ - // Add it to the contentMetadata array: │ │ │ │ - contentMetadata.push(coverageSummary); │ │ │ │ - }, │ │ │ │ - "Identifier": function(node, coverageSummary) { │ │ │ │ - coverageSummary.identifier = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Title": function(node, coverageSummary) { │ │ │ │ - coverageSummary.title = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Abstract": function(node, coverageSummary) { │ │ │ │ - coverageSummary["abstract"] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "SupportedCRS": function(node, coverageSummary) { │ │ │ │ - var crs = this.getChildValue(node); │ │ │ │ - if (crs) { │ │ │ │ - if (!coverageSummary.supportedCRS) { │ │ │ │ - coverageSummary.supportedCRS = []; │ │ │ │ - } │ │ │ │ - coverageSummary.supportedCRS.push(crs); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "SupportedFormat": function(node, coverageSummary) { │ │ │ │ - var format = this.getChildValue(node); │ │ │ │ - if (format) { │ │ │ │ - if (!coverageSummary.supportedFormat) { │ │ │ │ - coverageSummary.supportedFormat = []; │ │ │ │ - } │ │ │ │ - coverageSummary.supportedFormat.push(format); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WCSCapabilities.v1.prototype.readers["wcs"]), │ │ │ │ - "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_1_0" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WCSCapabilities/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/WCSCapabilities/v1.js │ │ │ │ - * @requires OpenLayers/Format/GML/v3.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WCSCapabilities/v1_0_0 │ │ │ │ - * Read WCS Capabilities version 1.0.0. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WCSCapabilities.v1> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WCSCapabilities.v1_0_0 │ │ │ │ - * Create a new parser for WCS capabilities version 1.0.0. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - wcs: "http://www.opengis.net/wcs", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ - ows: "http://www.opengis.net/ows" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: errorProperty │ │ │ │ - * {String} Which property of the returned object to check for in order to │ │ │ │ - * determine whether or not parsing has failed. In the case that the │ │ │ │ - * errorProperty is undefined on the returned object, the document will be │ │ │ │ - * run through an OGCExceptionReport parser. │ │ │ │ - */ │ │ │ │ - errorProperty: "service", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "wcs": { │ │ │ │ - "WCS_Capabilities": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "Service": function(node, obj) { │ │ │ │ - obj.service = {}; │ │ │ │ - this.readChildNodes(node, obj.service); │ │ │ │ - }, │ │ │ │ - "name": function(node, service) { │ │ │ │ - service.name = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "label": function(node, service) { │ │ │ │ - service.label = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "keywords": function(node, service) { │ │ │ │ - service.keywords = []; │ │ │ │ - this.readChildNodes(node, service.keywords); │ │ │ │ - }, │ │ │ │ - "keyword": function(node, keywords) { │ │ │ │ - // Append the keyword to the keywords list │ │ │ │ - keywords.push(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "responsibleParty": function(node, service) { │ │ │ │ - service.responsibleParty = {}; │ │ │ │ - this.readChildNodes(node, service.responsibleParty); │ │ │ │ - }, │ │ │ │ - "individualName": function(node, responsibleParty) { │ │ │ │ - responsibleParty.individualName = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "organisationName": function(node, responsibleParty) { │ │ │ │ - responsibleParty.organisationName = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "positionName": function(node, responsibleParty) { │ │ │ │ - responsibleParty.positionName = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "contactInfo": function(node, responsibleParty) { │ │ │ │ - responsibleParty.contactInfo = {}; │ │ │ │ - this.readChildNodes(node, responsibleParty.contactInfo); │ │ │ │ - }, │ │ │ │ - "phone": function(node, contactInfo) { │ │ │ │ - contactInfo.phone = {}; │ │ │ │ - this.readChildNodes(node, contactInfo.phone); │ │ │ │ - }, │ │ │ │ - "voice": function(node, phone) { │ │ │ │ - phone.voice = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "facsimile": function(node, phone) { │ │ │ │ - phone.facsimile = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "address": function(node, contactInfo) { │ │ │ │ - contactInfo.address = {}; │ │ │ │ - this.readChildNodes(node, contactInfo.address); │ │ │ │ - }, │ │ │ │ - "deliveryPoint": function(node, address) { │ │ │ │ - address.deliveryPoint = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "city": function(node, address) { │ │ │ │ - address.city = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "postalCode": function(node, address) { │ │ │ │ - address.postalCode = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "country": function(node, address) { │ │ │ │ - address.country = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "electronicMailAddress": function(node, address) { │ │ │ │ - address.electronicMailAddress = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "fees": function(node, service) { │ │ │ │ - service.fees = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "accessConstraints": function(node, service) { │ │ │ │ - service.accessConstraints = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ContentMetadata": function(node, obj) { │ │ │ │ - obj.contentMetadata = []; │ │ │ │ - this.readChildNodes(node, obj.contentMetadata); │ │ │ │ - }, │ │ │ │ - "CoverageOfferingBrief": function(node, contentMetadata) { │ │ │ │ - var coverageOfferingBrief = {}; │ │ │ │ - this.readChildNodes(node, coverageOfferingBrief); │ │ │ │ - contentMetadata.push(coverageOfferingBrief); │ │ │ │ - }, │ │ │ │ - "name": function(node, coverageOfferingBrief) { │ │ │ │ - coverageOfferingBrief.name = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "label": function(node, coverageOfferingBrief) { │ │ │ │ - coverageOfferingBrief.label = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "lonLatEnvelope": function(node, coverageOfferingBrief) { │ │ │ │ - var nodeList = this.getElementsByTagNameNS(node, "http://www.opengis.net/gml", "pos"); │ │ │ │ - │ │ │ │ - // We expect two nodes here, to create the corners of a bounding box │ │ │ │ - if (nodeList.length == 2) { │ │ │ │ - var min = {}; │ │ │ │ - var max = {}; │ │ │ │ - │ │ │ │ - OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[0], min]); │ │ │ │ - OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[1], max]); │ │ │ │ - │ │ │ │ - coverageOfferingBrief.lonLatEnvelope = {}; │ │ │ │ - coverageOfferingBrief.lonLatEnvelope.srsName = node.getAttribute("srsName"); │ │ │ │ - coverageOfferingBrief.lonLatEnvelope.min = min.points[0]; │ │ │ │ - coverageOfferingBrief.lonLatEnvelope.max = max.points[0]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_0_0" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WFSCapabilities/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/WFSCapabilities.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WFSCapabilities.v1 │ │ │ │ - * Abstract class not to be instantiated directly. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WFSCapabilities.v1 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - wfs: "http://www.opengis.net/wfs", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ - ows: "http://www.opengis.net/ows" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: errorProperty │ │ │ │ - * {String} Which property of the returned object to check for in order to │ │ │ │ - * determine whether or not parsing has failed. In the case that the │ │ │ │ - * errorProperty is undefined on the returned object, the document will be │ │ │ │ - * run through an OGCExceptionReport parser. │ │ │ │ - */ │ │ │ │ - errorProperty: "featureTypeList", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ - */ │ │ │ │ - defaultPrefix: "wfs", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WFSCapabilities.v1_1 │ │ │ │ - * Create an instance of one of the subclasses. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return a list of layers. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} List of named layers. │ │ │ │ - */ │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - } │ │ │ │ - var raw = data; │ │ │ │ - if (data && data.nodeType == 9) { │ │ │ │ - data = data.documentElement; │ │ │ │ - } │ │ │ │ - var capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - return capabilities; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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": { │ │ │ │ - "WFS_Capabilities": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "FeatureTypeList": function(node, request) { │ │ │ │ - request.featureTypeList = { │ │ │ │ - featureTypes: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, request.featureTypeList); │ │ │ │ - }, │ │ │ │ - "FeatureType": function(node, featureTypeList) { │ │ │ │ - var featureType = {}; │ │ │ │ - this.readChildNodes(node, featureType); │ │ │ │ - featureTypeList.featureTypes.push(featureType); │ │ │ │ - }, │ │ │ │ - "Name": function(node, obj) { │ │ │ │ - var name = this.getChildValue(node); │ │ │ │ - if (name) { │ │ │ │ - var parts = name.split(":"); │ │ │ │ - obj.name = parts.pop(); │ │ │ │ - if (parts.length > 0) { │ │ │ │ - obj.featureNS = this.lookupNamespaceURI(node, parts[0]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Title": function(node, obj) { │ │ │ │ - var title = this.getChildValue(node); │ │ │ │ - if (title) { │ │ │ │ - obj.title = title; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Abstract": function(node, obj) { │ │ │ │ - var abst = this.getChildValue(node); │ │ │ │ - if (abst) { │ │ │ │ - obj["abstract"] = abst; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WFSCapabilities/v1_1_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/WFSCapabilities/v1.js │ │ │ │ - * @requires OpenLayers/Format/OWSCommon/v1.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WFSCapabilities/v1_1_0 │ │ │ │ - * Read WFS Capabilities version 1.1.0. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WFSCapabilities> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WFSCapabilities.v1_1_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ - */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WFSCapabilities.v1_1_0 │ │ │ │ - * Create a new parser for WFS capabilities version 1.1.0. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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({ │ │ │ │ - "DefaultSRS": function(node, obj) { │ │ │ │ - var defaultSRS = this.getChildValue(node); │ │ │ │ - if (defaultSRS) { │ │ │ │ - obj.srs = defaultSRS; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]), │ │ │ │ - "ows": OpenLayers.Format.OWSCommon.v1.prototype.readers.ows │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_1_0" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WFSCapabilities/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/WFSCapabilities/v1.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WFSCapabilities/v1_0_0 │ │ │ │ - * Read WFS Capabilities version 1.0.0. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WFSCapabilities.v1> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WFSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WFSCapabilities.v1_0_0 │ │ │ │ - * Create a new parser for WFS capabilities version 1.0.0. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ + return node; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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({ │ │ │ │ - "Service": function(node, capabilities) { │ │ │ │ - capabilities.service = {}; │ │ │ │ - this.readChildNodes(node, capabilities.service); │ │ │ │ - }, │ │ │ │ - "Fees": function(node, service) { │ │ │ │ - var fees = this.getChildValue(node); │ │ │ │ - if (fees && fees.toLowerCase() != "none") { │ │ │ │ - service.fees = fees; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "AccessConstraints": function(node, service) { │ │ │ │ - var constraints = this.getChildValue(node); │ │ │ │ - if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ - service.accessConstraints = constraints; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "OnlineResource": function(node, service) { │ │ │ │ - var onlineResource = this.getChildValue(node); │ │ │ │ - if (onlineResource && onlineResource.toLowerCase() != "none") { │ │ │ │ - service.onlineResource = onlineResource; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Keywords": function(node, service) { │ │ │ │ - var keywords = this.getChildValue(node); │ │ │ │ - if (keywords && keywords.toLowerCase() != "none") { │ │ │ │ - service.keywords = keywords.split(', '); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Capability": function(node, capabilities) { │ │ │ │ - capabilities.capability = {}; │ │ │ │ - this.readChildNodes(node, capabilities.capability); │ │ │ │ - }, │ │ │ │ - "Request": function(node, obj) { │ │ │ │ - obj.request = {}; │ │ │ │ - this.readChildNodes(node, obj.request); │ │ │ │ - }, │ │ │ │ - "GetFeature": function(node, request) { │ │ │ │ - request.getfeature = { │ │ │ │ - href: {}, // DCPType │ │ │ │ - formats: [] // ResultFormat │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, request.getfeature); │ │ │ │ - }, │ │ │ │ - "ResultFormat": function(node, obj) { │ │ │ │ - var children = node.childNodes; │ │ │ │ - var childNode; │ │ │ │ - for (var i = 0; i < children.length; i++) { │ │ │ │ - childNode = children[i]; │ │ │ │ - if (childNode.nodeType == 1) { │ │ │ │ - obj.formats.push(childNode.nodeName); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "DCPType": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "HTTP": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj.href); │ │ │ │ - }, │ │ │ │ - "Get": function(node, obj) { │ │ │ │ - obj.get = node.getAttribute("onlineResource"); │ │ │ │ - }, │ │ │ │ - "Post": function(node, obj) { │ │ │ │ - obj.post = node.getAttribute("onlineResource"); │ │ │ │ - }, │ │ │ │ - "SRS": function(node, obj) { │ │ │ │ - var srs = this.getChildValue(node); │ │ │ │ - if (srs) { │ │ │ │ - obj.srs = srs; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]) │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_0_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMC.v1_1_0" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Format/SOSCapabilities/v1_0_0.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ @@ -82274,636 +81658,14 @@ │ │ │ │ "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.SOSCapabilities.v1_0_0" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/OWSContext/v0_3_1.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/KML.js │ │ │ │ - * @requires OpenLayers/Format/GML.js │ │ │ │ - * @requires OpenLayers/Format/GML/v2.js │ │ │ │ - * @requires OpenLayers/Format/SLD/v1_0_0.js │ │ │ │ - * @requires OpenLayers/Format/OWSContext.js │ │ │ │ - * @requires OpenLayers/Format/OWSCommon/v1_0_0.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.OWSContext.v0_3_1 │ │ │ │ - * Read and write OWSContext version 0.3.1. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.OWSContext.v0_3_1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - owc: "http://www.opengis.net/ows-context", │ │ │ │ - gml: "http://www.opengis.net/gml", │ │ │ │ - kml: "http://www.opengis.net/kml/2.2", │ │ │ │ - ogc: "http://www.opengis.net/ogc", │ │ │ │ - ows: "http://www.opengis.net/ows", │ │ │ │ - sld: "http://www.opengis.net/sld", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constant: VERSION │ │ │ │ - * {String} 0.3.1 │ │ │ │ - */ │ │ │ │ - VERSION: "0.3.1", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} Schema location │ │ │ │ - */ │ │ │ │ - schemaLocation: "http://www.opengis.net/ows-context http://www.ogcnetwork.net/schemas/owc/0.3.1/owsContext.xsd", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ - * {String} Default namespace prefix to use. │ │ │ │ - */ │ │ │ │ - defaultPrefix: "owc", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ - */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: featureNS │ │ │ │ - * {String} The namespace uri to use for writing InlineGeometry │ │ │ │ - */ │ │ │ │ - featureNS: "http://mapserver.gis.umn.edu/mapserver", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: featureType │ │ │ │ - * {String} The name to use as the feature type when writing out │ │ │ │ - * InlineGeometry │ │ │ │ - */ │ │ │ │ - featureType: 'vector', │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: geometryName │ │ │ │ - * {String} The name to use for the geometry attribute when writing out │ │ │ │ - * InlineGeometry │ │ │ │ - */ │ │ │ │ - geometryName: 'geometry', │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: nestingLayerLookup │ │ │ │ - * {Object} Hashtable lookup for nesting layer nodes. Used while writing │ │ │ │ - * the OWS context document. It is necessary to keep track of the │ │ │ │ - * nestingPaths for which nesting layer nodes have already been │ │ │ │ - * created, so (nesting) layer nodes are added to those nodes. │ │ │ │ - * │ │ │ │ - * For example: │ │ │ │ - * │ │ │ │ - * If there are three layers with nestingPaths: │ │ │ │ - * layer1.metadata.nestingPath = "a/b/" │ │ │ │ - * layer2.metadata.nestingPath = "a/b/" │ │ │ │ - * layer2.metadata.nestingPath = "a/c" │ │ │ │ - * │ │ │ │ - * then a nesting layer node "a" should be created once and added │ │ │ │ - * to the resource list, a nesting layer node "b" should be created │ │ │ │ - * once and added under "a", and a nesting layer node "c" should be │ │ │ │ - * created and added under "a". The lookup paths for these nodes │ │ │ │ - * will be "a", "a/b", and "a/c" respectively. │ │ │ │ - */ │ │ │ │ - nestingLayerLookup: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.OWSContext.v0_3_1 │ │ │ │ - * Instances of this class are not created directly. Use the │ │ │ │ - * <OpenLayers.Format.OWSContext> 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]); │ │ │ │ - OpenLayers.Format.GML.v2.prototype.setGeometryTypes.call(this); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setNestingPath │ │ │ │ - * Set the nestingPath property of the layer depending on the position │ │ │ │ - * of the layer in hierarchy of layers. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * l - {Object} An object that may have a layersContext array property. │ │ │ │ - * │ │ │ │ - */ │ │ │ │ - setNestingPath: function(l) { │ │ │ │ - if (l.layersContext) { │ │ │ │ - for (var i = 0, len = l.layersContext.length; i < len; i++) { │ │ │ │ - var layerContext = l.layersContext[i]; │ │ │ │ - var nPath = []; │ │ │ │ - var nTitle = l.title || ""; │ │ │ │ - if (l.metadata && l.metadata.nestingPath) { │ │ │ │ - nPath = l.metadata.nestingPath.slice(); │ │ │ │ - } │ │ │ │ - if (nTitle != "") { │ │ │ │ - nPath.push(nTitle); │ │ │ │ - } │ │ │ │ - layerContext.metadata.nestingPath = nPath; │ │ │ │ - if (layerContext.layersContext) { │ │ │ │ - this.setNestingPath(layerContext); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Function: decomposeNestingPath │ │ │ │ - * Takes a nestingPath like "a/b/c" and decomposes it into subpaths: │ │ │ │ - * "a", "a/b", "a/b/c" │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * nPath - {Array} the nesting path │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * Array({String}) Array with subpaths, or empty array if there is nothing │ │ │ │ - * to decompose │ │ │ │ - */ │ │ │ │ - decomposeNestingPath: function(nPath) { │ │ │ │ - var a = []; │ │ │ │ - if (OpenLayers.Util.isArray(nPath)) { │ │ │ │ - var path = nPath.slice(); │ │ │ │ - while (path.length > 0) { │ │ │ │ - a.push(path.slice()); │ │ │ │ - path.pop(); │ │ │ │ - } │ │ │ │ - a.reverse(); │ │ │ │ - } │ │ │ │ - return a; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read OWS context data from a string or DOMElement, and return a list │ │ │ │ - * of layers. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} The context object with a flat layer list as a property named │ │ │ │ - * layersContext. │ │ │ │ - */ │ │ │ │ - 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 context = {}; │ │ │ │ - this.readNode(data, context); │ │ │ │ - // since an OWSContext can be nested we need to go through this │ │ │ │ - // structure recursively │ │ │ │ - this.setNestingPath({ │ │ │ │ - layersContext: context.layersContext │ │ │ │ - }); │ │ │ │ - // after nesting path has been set, create a flat list of layers │ │ │ │ - var layers = []; │ │ │ │ - this.processLayer(layers, context); │ │ │ │ - delete context.layersContext; │ │ │ │ - context.layersContext = layers; │ │ │ │ - return context; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: processLayer │ │ │ │ - * Recursive function to get back a flat list of layers from the hierarchic │ │ │ │ - * layer structure. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layerArray - {Array({Object})} Array of layerContext objects │ │ │ │ - * layer - {Object} layerContext object │ │ │ │ - */ │ │ │ │ - processLayer: function(layerArray, layer) { │ │ │ │ - if (layer.layersContext) { │ │ │ │ - for (var i = 0, len = layer.layersContext.length; i < len; i++) { │ │ │ │ - var l = layer.layersContext[i]; │ │ │ │ - layerArray.push(l); │ │ │ │ - if (l.layersContext) { │ │ │ │ - this.processLayer(layerArray, l); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: write │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * context - {Object} An object representing the map context. │ │ │ │ - * options - {Object} Optional object. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} An OWS Context document string. │ │ │ │ - */ │ │ │ │ - write: function(context, options) { │ │ │ │ - var name = "OWSContext"; │ │ │ │ - this.nestingLayerLookup = {}; //start with empty lookup │ │ │ │ - options = options || {}; │ │ │ │ - OpenLayers.Util.applyDefaults(options, context); │ │ │ │ - var root = this.writeNode(name, options); │ │ │ │ - this.nestingLayerLookup = null; //clear lookup │ │ │ │ - this.setAttributeNS( │ │ │ │ - root, this.namespaces["xsi"], │ │ │ │ - "xsi:schemaLocation", this.schemaLocation │ │ │ │ - ); │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [root]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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": { │ │ │ │ - "Document": function(node, obj) { │ │ │ │ - obj.features = new OpenLayers.Format.KML({ │ │ │ │ - kmlns: this.namespaces.kml, │ │ │ │ - extractStyles: true │ │ │ │ - }).read(node); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "owc": { │ │ │ │ - "OWSContext": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "General": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "ResourceList": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "Layer": function(node, obj) { │ │ │ │ - var layerContext = { │ │ │ │ - metadata: {}, │ │ │ │ - visibility: (node.getAttribute("hidden") != "1"), │ │ │ │ - queryable: (node.getAttribute("queryable") == "1"), │ │ │ │ - opacity: ((node.getAttribute("opacity") != null) ? │ │ │ │ - parseFloat(node.getAttribute("opacity")) : null), │ │ │ │ - name: node.getAttribute("name"), │ │ │ │ - /* A category layer is a dummy layer meant for creating │ │ │ │ - hierarchies. It is not a physical layer in the │ │ │ │ - OpenLayers sense. The assumption we make here is that │ │ │ │ - category layers do not have a name attribute */ │ │ │ │ - categoryLayer: (node.getAttribute("name") == null), │ │ │ │ - formats: [], │ │ │ │ - styles: [] │ │ │ │ - }; │ │ │ │ - if (!obj.layersContext) { │ │ │ │ - obj.layersContext = []; │ │ │ │ - } │ │ │ │ - obj.layersContext.push(layerContext); │ │ │ │ - this.readChildNodes(node, layerContext); │ │ │ │ - }, │ │ │ │ - "InlineGeometry": function(node, obj) { │ │ │ │ - obj.features = []; │ │ │ │ - var elements = this.getElementsByTagNameNS(node, │ │ │ │ - this.namespaces.gml, "featureMember"); │ │ │ │ - var el; │ │ │ │ - if (elements.length >= 1) { │ │ │ │ - el = elements[0]; │ │ │ │ - } │ │ │ │ - if (el && el.firstChild) { │ │ │ │ - var featurenode = (el.firstChild.nextSibling) ? │ │ │ │ - el.firstChild.nextSibling : el.firstChild; │ │ │ │ - this.setNamespace("feature", featurenode.namespaceURI); │ │ │ │ - this.featureType = featurenode.localName || │ │ │ │ - featurenode.nodeName.split(":").pop(); │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Server": function(node, obj) { │ │ │ │ - // when having multiple Server types, we prefer WMS │ │ │ │ - if ((!obj.service && !obj.version) || │ │ │ │ - (obj.service != │ │ │ │ - OpenLayers.Format.Context.serviceTypes.WMS)) { │ │ │ │ - obj.service = node.getAttribute("service"); │ │ │ │ - obj.version = node.getAttribute("version"); │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Name": function(node, obj) { │ │ │ │ - obj.name = this.getChildValue(node); │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "Title": function(node, obj) { │ │ │ │ - obj.title = this.getChildValue(node); │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "StyleList": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj.styles); │ │ │ │ - }, │ │ │ │ - "Style": function(node, obj) { │ │ │ │ - var style = {}; │ │ │ │ - obj.push(style); │ │ │ │ - this.readChildNodes(node, style); │ │ │ │ - }, │ │ │ │ - "LegendURL": function(node, obj) { │ │ │ │ - var legend = {}; │ │ │ │ - obj.legend = legend; │ │ │ │ - this.readChildNodes(node, legend); │ │ │ │ - }, │ │ │ │ - "OnlineResource": function(node, obj) { │ │ │ │ - obj.url = this.getAttributeNS(node, this.namespaces.xlink, │ │ │ │ - "href"); │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "ows": OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows, │ │ │ │ - "gml": OpenLayers.Format.GML.v2.prototype.readers.gml, │ │ │ │ - "sld": OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld, │ │ │ │ - "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: { │ │ │ │ - "owc": { │ │ │ │ - "OWSContext": function(options) { │ │ │ │ - var node = this.createElementNSPlus("OWSContext", { │ │ │ │ - attributes: { │ │ │ │ - version: this.VERSION, │ │ │ │ - id: options.id || OpenLayers.Util.createUniqueID("OpenLayers_OWSContext_") │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.writeNode("General", options, node); │ │ │ │ - this.writeNode("ResourceList", options, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "General": function(options) { │ │ │ │ - var node = this.createElementNSPlus("General"); │ │ │ │ - this.writeNode("ows:BoundingBox", options, node); │ │ │ │ - this.writeNode("ows:Title", options.title || 'OpenLayers OWSContext', node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ResourceList": function(options) { │ │ │ │ - var node = this.createElementNSPlus("ResourceList"); │ │ │ │ - for (var i = 0, len = options.layers.length; i < len; i++) { │ │ │ │ - var layer = options.layers[i]; │ │ │ │ - var decomposedPath = this.decomposeNestingPath(layer.metadata.nestingPath); │ │ │ │ - this.writeNode("_Layer", { │ │ │ │ - layer: layer, │ │ │ │ - subPaths: decomposedPath │ │ │ │ - }, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Server": function(options) { │ │ │ │ - var node = this.createElementNSPlus("Server", { │ │ │ │ - attributes: { │ │ │ │ - version: options.version, │ │ │ │ - service: options.service │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.writeNode("OnlineResource", options, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "OnlineResource": function(options) { │ │ │ │ - var node = this.createElementNSPlus("OnlineResource", { │ │ │ │ - attributes: { │ │ │ │ - "xlink:href": options.url │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "InlineGeometry": function(layer) { │ │ │ │ - var node = this.createElementNSPlus("InlineGeometry"), │ │ │ │ - dataExtent = layer.getDataExtent(); │ │ │ │ - if (dataExtent !== null) { │ │ │ │ - this.writeNode("gml:boundedBy", dataExtent, node); │ │ │ │ - } │ │ │ │ - for (var i = 0, len = layer.features.length; i < len; i++) { │ │ │ │ - this.writeNode("gml:featureMember", layer.features[i], node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "StyleList": function(styles) { │ │ │ │ - var node = this.createElementNSPlus("StyleList"); │ │ │ │ - for (var i = 0, len = styles.length; i < len; i++) { │ │ │ │ - this.writeNode("Style", styles[i], node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Style": function(style) { │ │ │ │ - var node = this.createElementNSPlus("Style"); │ │ │ │ - this.writeNode("Name", style, node); │ │ │ │ - this.writeNode("Title", style, node); │ │ │ │ - if (style.legend) { │ │ │ │ - this.writeNode("LegendURL", style, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Name": function(obj) { │ │ │ │ - var node = this.createElementNSPlus("Name", { │ │ │ │ - value: obj.name │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Title": function(obj) { │ │ │ │ - var node = this.createElementNSPlus("Title", { │ │ │ │ - value: obj.title │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "LegendURL": function(style) { │ │ │ │ - var node = this.createElementNSPlus("LegendURL"); │ │ │ │ - this.writeNode("OnlineResource", style.legend, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "_WMS": function(layer) { │ │ │ │ - var node = this.createElementNSPlus("Layer", { │ │ │ │ - attributes: { │ │ │ │ - name: layer.params.LAYERS, │ │ │ │ - queryable: layer.queryable ? "1" : "0", │ │ │ │ - hidden: layer.visibility ? "0" : "1", │ │ │ │ - opacity: layer.hasOwnProperty("opacity") ? layer.opacity : null │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.writeNode("ows:Title", layer.name, node); │ │ │ │ - this.writeNode("ows:OutputFormat", layer.params.FORMAT, node); │ │ │ │ - this.writeNode("Server", { │ │ │ │ - service: OpenLayers.Format.Context.serviceTypes.WMS, │ │ │ │ - version: layer.params.VERSION, │ │ │ │ - url: layer.url │ │ │ │ - }, node); │ │ │ │ - if (layer.metadata.styles && layer.metadata.styles.length > 0) { │ │ │ │ - this.writeNode("StyleList", layer.metadata.styles, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "_Layer": function(options) { │ │ │ │ - var layer, subPaths, node, title; │ │ │ │ - layer = options.layer; │ │ │ │ - subPaths = options.subPaths; │ │ │ │ - node = null; │ │ │ │ - title = null; │ │ │ │ - // subPaths is an array of an array │ │ │ │ - // recursively calling _Layer writer eats up subPaths, until a │ │ │ │ - // real writer is called and nodes are returned. │ │ │ │ - if (subPaths.length > 0) { │ │ │ │ - var path = subPaths[0].join("/"); │ │ │ │ - var index = path.lastIndexOf("/"); │ │ │ │ - node = this.nestingLayerLookup[path]; │ │ │ │ - title = (index > 0) ? path.substring(index + 1, path.length) : path; │ │ │ │ - if (!node) { │ │ │ │ - // category layer │ │ │ │ - node = this.createElementNSPlus("Layer"); │ │ │ │ - this.writeNode("ows:Title", title, node); │ │ │ │ - this.nestingLayerLookup[path] = node; │ │ │ │ - } │ │ │ │ - options.subPaths.shift(); //remove a path after each call │ │ │ │ - this.writeNode("_Layer", options, node); │ │ │ │ - return node; │ │ │ │ - } else { │ │ │ │ - // write out the actual layer │ │ │ │ - if (layer instanceof OpenLayers.Layer.WMS) { │ │ │ │ - node = this.writeNode("_WMS", layer); │ │ │ │ - } else if (layer instanceof OpenLayers.Layer.Vector) { │ │ │ │ - if (layer.protocol instanceof OpenLayers.Protocol.WFS.v1) { │ │ │ │ - node = this.writeNode("_WFS", layer); │ │ │ │ - } else if (layer.protocol instanceof OpenLayers.Protocol.HTTP) { │ │ │ │ - if (layer.protocol.format instanceof OpenLayers.Format.GML) { │ │ │ │ - layer.protocol.format.version = "2.1.2"; │ │ │ │ - node = this.writeNode("_GML", layer); │ │ │ │ - } else if (layer.protocol.format instanceof OpenLayers.Format.KML) { │ │ │ │ - layer.protocol.format.version = "2.2"; │ │ │ │ - node = this.writeNode("_KML", layer); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - // write out as inline GML since we have no idea │ │ │ │ - // about the original Format │ │ │ │ - this.setNamespace("feature", this.featureNS); │ │ │ │ - node = this.writeNode("_InlineGeometry", layer); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (layer.options.maxScale) { │ │ │ │ - this.writeNode("sld:MinScaleDenominator", │ │ │ │ - layer.options.maxScale, node); │ │ │ │ - } │ │ │ │ - if (layer.options.minScale) { │ │ │ │ - this.writeNode("sld:MaxScaleDenominator", │ │ │ │ - layer.options.minScale, node); │ │ │ │ - } │ │ │ │ - this.nestingLayerLookup[layer.name] = node; │ │ │ │ - return node; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "_WFS": function(layer) { │ │ │ │ - var node = this.createElementNSPlus("Layer", { │ │ │ │ - attributes: { │ │ │ │ - name: layer.protocol.featurePrefix + ":" + layer.protocol.featureType, │ │ │ │ - hidden: layer.visibility ? "0" : "1" │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.writeNode("ows:Title", layer.name, node); │ │ │ │ - this.writeNode("Server", { │ │ │ │ - service: OpenLayers.Format.Context.serviceTypes.WFS, │ │ │ │ - version: layer.protocol.version, │ │ │ │ - url: layer.protocol.url │ │ │ │ - }, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "_InlineGeometry": function(layer) { │ │ │ │ - var node = this.createElementNSPlus("Layer", { │ │ │ │ - attributes: { │ │ │ │ - name: this.featureType, │ │ │ │ - hidden: layer.visibility ? "0" : "1" │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.writeNode("ows:Title", layer.name, node); │ │ │ │ - this.writeNode("InlineGeometry", layer, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "_GML": function(layer) { │ │ │ │ - var node = this.createElementNSPlus("Layer"); │ │ │ │ - this.writeNode("ows:Title", layer.name, node); │ │ │ │ - this.writeNode("Server", { │ │ │ │ - service: OpenLayers.Format.Context.serviceTypes.GML, │ │ │ │ - url: layer.protocol.url, │ │ │ │ - version: layer.protocol.format.version │ │ │ │ - }, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "_KML": function(layer) { │ │ │ │ - var node = this.createElementNSPlus("Layer"); │ │ │ │ - this.writeNode("ows:Title", layer.name, node); │ │ │ │ - this.writeNode("Server", { │ │ │ │ - service: OpenLayers.Format.Context.serviceTypes.KML, │ │ │ │ - version: layer.protocol.format.version, │ │ │ │ - url: layer.protocol.url │ │ │ │ - }, node); │ │ │ │ - return node; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "gml": OpenLayers.Util.applyDefaults({ │ │ │ │ - "boundedBy": function(bounds) { │ │ │ │ - var node = this.createElementNSPlus("gml:boundedBy"); │ │ │ │ - this.writeNode("gml:Box", bounds, node); │ │ │ │ - return node; │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.GML.v2.prototype.writers.gml), │ │ │ │ - "ows": OpenLayers.Format.OWSCommon.v1_0_0.prototype.writers.ows, │ │ │ │ - "sld": OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld, │ │ │ │ - "feature": OpenLayers.Format.GML.v2.prototype.writers.feature │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.OWSContext.v0_3_1" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ OpenLayers/Format/XLS/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. */ │ │ │ │ @@ -83259,2235 +82021,2816 @@ │ │ │ │ CLASS_NAME: "OpenLayers.Format.XLS.v1_1_0" │ │ │ │ │ │ │ │ }); │ │ │ │ │ │ │ │ // Support non standard implementation │ │ │ │ OpenLayers.Format.XLS.v1_1 = OpenLayers.Format.XLS.v1_1_0; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Tile/Image/IFrame.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/Image.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Tile.Image.IFrame │ │ │ │ - * Mixin for tiles that use form-encoded POST requests to get images from │ │ │ │ - * remote services. Images will be loaded using HTTP-POST into an IFrame. │ │ │ │ - * │ │ │ │ - * This mixin will be applied to <OpenLayers.Tile.Image> instances │ │ │ │ - * configured with <OpenLayers.Tile.Image.maxGetUrlLength> set. │ │ │ │ - */ │ │ │ │ -OpenLayers.Tile.Image.IFrame = { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: useIFrame │ │ │ │ - * {Boolean} true if we are currently using an IFrame to render POST │ │ │ │ - * responses, false if we are using an img element to render GET responses. │ │ │ │ - */ │ │ │ │ - useIFrame: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: blankImageUrl │ │ │ │ - * {String} Using a data scheme url is not supported by all browsers, but │ │ │ │ - * we don't care because we either set it as css backgroundImage, or the │ │ │ │ - * image's display style is set to "none" when we use it. │ │ │ │ - */ │ │ │ │ - blankImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * Set useIFrame in the instance, and operate the image/iframe switch. │ │ │ │ - * Then call Tile.Image.draw. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - draw: function() { │ │ │ │ - var draw = OpenLayers.Tile.Image.prototype.shouldDraw.call(this); │ │ │ │ - if (draw) { │ │ │ │ - │ │ │ │ - // this.url isn't set to the currect value yet, so we call getURL │ │ │ │ - // on the layer and store the result in a local variable │ │ │ │ - var url = this.layer.getURL(this.bounds); │ │ │ │ - │ │ │ │ - var usedIFrame = this.useIFrame; │ │ │ │ - this.useIFrame = this.maxGetUrlLength !== null && │ │ │ │ - !this.layer.async && │ │ │ │ - url.length > this.maxGetUrlLength; │ │ │ │ - │ │ │ │ - var fromIFrame = usedIFrame && !this.useIFrame; │ │ │ │ - var toIFrame = !usedIFrame && this.useIFrame; │ │ │ │ - │ │ │ │ - if (fromIFrame || toIFrame) { │ │ │ │ - │ │ │ │ - // Switching between GET (image) and POST (iframe). │ │ │ │ - │ │ │ │ - // We remove the imgDiv (really either an image or an iframe) │ │ │ │ - // from the frame and set it to null to make sure initImage │ │ │ │ - // will call getImage. │ │ │ │ - │ │ │ │ - if (this.imgDiv && this.imgDiv.parentNode === this.frame) { │ │ │ │ - this.frame.removeChild(this.imgDiv); │ │ │ │ - } │ │ │ │ - this.imgDiv = null; │ │ │ │ - │ │ │ │ - // And if we had an iframe we also remove the event pane. │ │ │ │ - │ │ │ │ - if (fromIFrame) { │ │ │ │ - this.frame.removeChild(this.frame.firstChild); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return OpenLayers.Tile.Image.prototype.draw.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getImage │ │ │ │ - * Creates the content for the frame on the tile. │ │ │ │ - */ │ │ │ │ - getImage: function() { │ │ │ │ - if (this.useIFrame === true) { │ │ │ │ - if (!this.frame.childNodes.length) { │ │ │ │ - var eventPane = document.createElement("div"), │ │ │ │ - style = eventPane.style; │ │ │ │ - style.position = "absolute"; │ │ │ │ - style.width = "100%"; │ │ │ │ - style.height = "100%"; │ │ │ │ - style.zIndex = 1; │ │ │ │ - style.backgroundImage = "url(" + this.blankImageUrl + ")"; │ │ │ │ - this.frame.appendChild(eventPane); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var id = this.id + '_iFrame', │ │ │ │ - iframe; │ │ │ │ - if (parseFloat(navigator.appVersion.split("MSIE")[1]) < 9) { │ │ │ │ - // Older IE versions do not set the name attribute of an iFrame │ │ │ │ - // properly via DOM manipulation, so we need to do it on our own with │ │ │ │ - // this hack. │ │ │ │ - iframe = document.createElement('<iframe name="' + id + '">'); │ │ │ │ - │ │ │ │ - // IFrames in older IE versions are not transparent, if you set │ │ │ │ - // the backgroundColor transparent. This is a workaround to get │ │ │ │ - // transparent iframes. │ │ │ │ - iframe.style.backgroundColor = '#FFFFFF'; │ │ │ │ - iframe.style.filter = 'chroma(color=#FFFFFF)'; │ │ │ │ - } else { │ │ │ │ - iframe = document.createElement('iframe'); │ │ │ │ - iframe.style.backgroundColor = 'transparent'; │ │ │ │ - │ │ │ │ - // iframe.name needs to be an unique id, otherwise it │ │ │ │ - // could happen that other iframes are overwritten. │ │ │ │ - iframe.name = id; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // some special properties to avoid scaling the images and scrollbars │ │ │ │ - // in the iframe │ │ │ │ - iframe.scrolling = 'no'; │ │ │ │ - iframe.marginWidth = '0px'; │ │ │ │ - iframe.marginHeight = '0px'; │ │ │ │ - iframe.frameBorder = '0'; │ │ │ │ - │ │ │ │ - iframe.style.position = "absolute"; │ │ │ │ - iframe.style.width = "100%"; │ │ │ │ - iframe.style.height = "100%"; │ │ │ │ - │ │ │ │ - if (this.layer.opacity < 1) { │ │ │ │ - OpenLayers.Util.modifyDOMElement(iframe, null, null, null, │ │ │ │ - null, null, null, this.layer.opacity); │ │ │ │ - } │ │ │ │ - this.frame.appendChild(iframe); │ │ │ │ - this.imgDiv = iframe; │ │ │ │ - return iframe; │ │ │ │ - } else { │ │ │ │ - return OpenLayers.Tile.Image.prototype.getImage.apply(this, arguments); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: createRequestForm │ │ │ │ - * Create the html <form> element with width, height, bbox and all │ │ │ │ - * parameters specified in the layer params. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} The form element which sends the HTTP-POST request to the │ │ │ │ - * WMS. │ │ │ │ - */ │ │ │ │ - createRequestForm: function() { │ │ │ │ - // creation of the form element │ │ │ │ - var form = document.createElement('form'); │ │ │ │ - form.method = 'POST'; │ │ │ │ - var cacheId = this.layer.params["_OLSALT"]; │ │ │ │ - cacheId = (cacheId ? cacheId + "_" : "") + this.bounds.toBBOX(); │ │ │ │ - form.action = OpenLayers.Util.urlAppend(this.layer.url, cacheId); │ │ │ │ - form.target = this.id + '_iFrame'; │ │ │ │ - │ │ │ │ - // adding all parameters in layer params as hidden fields to the html │ │ │ │ - // form element │ │ │ │ - var imageSize = this.layer.getImageSize(), │ │ │ │ - params = OpenLayers.Util.getParameters(this.url), │ │ │ │ - field; │ │ │ │ - │ │ │ │ - for (var par in params) { │ │ │ │ - field = document.createElement('input'); │ │ │ │ - field.type = 'hidden'; │ │ │ │ - field.name = par; │ │ │ │ - field.value = params[par]; │ │ │ │ - form.appendChild(field); │ │ │ │ - } │ │ │ │ - │ │ │ │ - return form; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setImgSrc │ │ │ │ - * Sets the source for the tile image │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * url - {String} │ │ │ │ - */ │ │ │ │ - setImgSrc: function(url) { │ │ │ │ - if (this.useIFrame === true) { │ │ │ │ - if (url) { │ │ │ │ - var form = this.createRequestForm(); │ │ │ │ - this.frame.appendChild(form); │ │ │ │ - form.submit(); │ │ │ │ - this.frame.removeChild(form); │ │ │ │ - } else if (this.imgDiv.parentNode === this.frame) { │ │ │ │ - // we don't reuse iframes to avoid caching issues │ │ │ │ - this.frame.removeChild(this.imgDiv); │ │ │ │ - this.imgDiv = null; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Tile.Image.prototype.setImgSrc.apply(this, arguments); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: onImageLoad │ │ │ │ - * Handler for the image onload event │ │ │ │ - */ │ │ │ │ - onImageLoad: function() { │ │ │ │ - //TODO de-uglify opacity handling │ │ │ │ - OpenLayers.Tile.Image.prototype.onImageLoad.apply(this, arguments); │ │ │ │ - if (this.useIFrame === true) { │ │ │ │ - this.imgDiv.style.opacity = 1; │ │ │ │ - this.frame.style.opacity = this.layer.opacity; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: createBackBuffer │ │ │ │ - * Override createBackBuffer to do nothing when we use an iframe. Moving an │ │ │ │ - * iframe from one element to another makes it necessary to reload the iframe │ │ │ │ - * because its content is lost. So we just give up. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - createBackBuffer: function() { │ │ │ │ - var backBuffer; │ │ │ │ - if (this.useIFrame === false) { │ │ │ │ - backBuffer = OpenLayers.Tile.Image.prototype.createBackBuffer.call(this); │ │ │ │ - } │ │ │ │ - return backBuffer; │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - 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/Protocol/Script.js │ │ │ │ + OpenLayers/Format/CSWGetDomain/v2_0_2.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/Feature/Vector.js │ │ │ │ - * @requires OpenLayers/Format/GeoJSON.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * if application uses the query string, for example, for BBOX parameters, │ │ │ │ - * OpenLayers/Format/QueryStringFilter.js should be included in the build config file │ │ │ │ + * @requires OpenLayers/Format/XML.js │ │ │ │ + * @requires OpenLayers/Format/CSWGetDomain.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.Script │ │ │ │ - * A basic Script protocol for vector layers. Create a new instance with the │ │ │ │ - * <OpenLayers.Protocol.Script> constructor. A script protocol is used to │ │ │ │ - * get around the same origin policy. It works with services that return │ │ │ │ - * JSONP - that is, JSON wrapped in a client-specified callback. The │ │ │ │ - * protocol handles fetching and parsing of feature data and sends parsed │ │ │ │ - * features to the <callback> configured with the protocol. The protocol │ │ │ │ - * expects features serialized as GeoJSON by default, but can be configured │ │ │ │ - * to work with other formats by setting the <format> property. │ │ │ │ + * Class: OpenLayers.Format.CSWGetDomain.v2_0_2 │ │ │ │ + * A format for creating CSWGetDomain v2.0.2 transactions. │ │ │ │ + * Create a new instance with the │ │ │ │ + * <OpenLayers.Format.CSWGetDomain.v2_0_2> constructor. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol> │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol.Script = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: url │ │ │ │ - * {String} Service URL. The service is expected to return serialized │ │ │ │ - * features wrapped in a named callback (where the callback name is │ │ │ │ - * generated by this protocol). │ │ │ │ - * Read-only, set through the options passed to the constructor. │ │ │ │ - */ │ │ │ │ - url: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: params │ │ │ │ - * {Object} Query string parameters to be appended to the URL. │ │ │ │ - * Read-only, set through the options passed to the constructor. │ │ │ │ - * Example: {maxFeatures: 50} │ │ │ │ - */ │ │ │ │ - params: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: callback │ │ │ │ - * {Object} Function to be called when the <read> operation completes. │ │ │ │ - */ │ │ │ │ - callback: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: callbackTemplate │ │ │ │ - * {String} Template for creating a unique callback function name │ │ │ │ - * for the registry. Should include ${id}. The ${id} variable will be │ │ │ │ - * replaced with a string identifier prefixed with a "c" (e.g. c1, c2). │ │ │ │ - * Default is "OpenLayers.Protocol.Script.registry.${id}". │ │ │ │ - */ │ │ │ │ - callbackTemplate: "OpenLayers.Protocol.Script.registry.${id}", │ │ │ │ +OpenLayers.Format.CSWGetDomain.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: callbackKey │ │ │ │ - * {String} The name of the query string parameter that the service │ │ │ │ - * recognizes as the callback identifier. Default is "callback". │ │ │ │ - * This key is used to generate the URL for the script. For example │ │ │ │ - * setting <callbackKey> to "myCallback" would result in a URL like │ │ │ │ - * http://example.com/?myCallback=... │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ - callbackKey: "callback", │ │ │ │ + namespaces: { │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ + csw: "http://www.opengis.net/cat/csw/2.0.2" │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: callbackPrefix │ │ │ │ - * {String} Where a service requires that the callback query string │ │ │ │ - * parameter value is prefixed by some string, this value may be set. │ │ │ │ - * For example, setting <callbackPrefix> to "foo:" would result in a │ │ │ │ - * URL like http://example.com/?callback=foo:... Default is "". │ │ │ │ + * Property: defaultPrefix │ │ │ │ + * {String} The default prefix (used by Format.XML). │ │ │ │ */ │ │ │ │ - callbackPrefix: "", │ │ │ │ + defaultPrefix: "csw", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: scope │ │ │ │ - * {Object} Optional ``this`` object for the callback. Read-only, set │ │ │ │ - * through the options passed to the constructor. │ │ │ │ + * Property: version │ │ │ │ + * {String} CSW version number. │ │ │ │ */ │ │ │ │ - scope: null, │ │ │ │ + version: "2.0.2", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: format │ │ │ │ - * {<OpenLayers.Format>} Format for parsing features. Default is an │ │ │ │ - * <OpenLayers.Format.GeoJSON> format. If an alternative is provided, │ │ │ │ - * the format's read method must take an object and return an array │ │ │ │ - * of features. │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} http://www.opengis.net/cat/csw/2.0.2 │ │ │ │ + * http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd │ │ │ │ */ │ │ │ │ - format: null, │ │ │ │ + schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: pendingRequests │ │ │ │ - * {Object} References all pending requests. Property names are script │ │ │ │ - * identifiers and property values are script elements. │ │ │ │ + * APIProperty: PropertyName │ │ │ │ + * {String} Value of the csw:PropertyName element, used when │ │ │ │ + * writing a GetDomain document. │ │ │ │ */ │ │ │ │ - pendingRequests: null, │ │ │ │ + PropertyName: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: srsInBBOX │ │ │ │ - * {Boolean} Include the SRS identifier in BBOX query string parameter. │ │ │ │ - * Setting this property has no effect if a custom filterToParams method │ │ │ │ - * is provided. 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 │ │ │ │ + * APIProperty: ParameterName │ │ │ │ + * {String} Value of the csw:ParameterName element, used when │ │ │ │ + * writing a GetDomain document. │ │ │ │ */ │ │ │ │ - srsInBBOX: false, │ │ │ │ + ParameterName: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Protocol.Script │ │ │ │ - * A class for giving layers generic Script protocol. │ │ │ │ + * Constructor: OpenLayers.Format.CSWGetDomain.v2_0_2 │ │ │ │ + * A class for parsing and generating CSWGetDomain v2.0.2 transactions. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} Optional object whose properties will be set on the │ │ │ │ * instance. │ │ │ │ * │ │ │ │ - * Valid options include: │ │ │ │ - * url - {String} │ │ │ │ - * params - {Object} │ │ │ │ - * callback - {Function} │ │ │ │ - * scope - {Object} │ │ │ │ + * Valid options properties: │ │ │ │ + * - PropertyName │ │ │ │ + * - ParameterName │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - this.params = {}; │ │ │ │ - this.pendingRequests = {}; │ │ │ │ - OpenLayers.Protocol.prototype.initialize.apply(this, arguments); │ │ │ │ - if (!this.format) { │ │ │ │ - this.format = new OpenLayers.Format.GeoJSON(); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (!this.filterToParams && OpenLayers.Format.QueryStringFilter) { │ │ │ │ - var format = new OpenLayers.Format.QueryStringFilter({ │ │ │ │ - srsInBBOX: this.srsInBBOX │ │ │ │ - }); │ │ │ │ - this.filterToParams = function(filter, params) { │ │ │ │ - return format.write(filter, params); │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ * 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. │ │ │ │ - * filter - {<OpenLayers.Filter>} Filter to get serialized as a │ │ │ │ - * query string. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Protocol.Response>} A response object, whose "priv" property │ │ │ │ - * references the injected script. 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. │ │ │ │ + * Parse the response from a GetDomain request. │ │ │ │ */ │ │ │ │ - read: function(options) { │ │ │ │ - OpenLayers.Protocol.prototype.read.apply(this, arguments); │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ - options.params = OpenLayers.Util.applyDefaults( │ │ │ │ - options.params, this.options.params │ │ │ │ - ); │ │ │ │ - if (options.filter && this.filterToParams) { │ │ │ │ - options.params = this.filterToParams( │ │ │ │ - options.filter, options.params │ │ │ │ - ); │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ } │ │ │ │ - var response = new OpenLayers.Protocol.Response({ │ │ │ │ - requestType: "read" │ │ │ │ - }); │ │ │ │ - var request = this.createRequest( │ │ │ │ - options.url, │ │ │ │ - options.params, │ │ │ │ - OpenLayers.Function.bind(function(data) { │ │ │ │ - response.data = data; │ │ │ │ - this.handleRead(response, options); │ │ │ │ - }, this) │ │ │ │ - ); │ │ │ │ - response.priv = request; │ │ │ │ - return response; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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, any filter will not be serialized. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * filter - {<OpenLayers.Filter>} filter to convert. │ │ │ │ - * params - {Object} The parameters object. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} The resulting parameters object. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: createRequest │ │ │ │ - * Issues a request for features by creating injecting a script in the │ │ │ │ - * document head. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * url - {String} Service URL. │ │ │ │ - * params - {Object} Query string parameters. │ │ │ │ - * callback - {Function} Callback to be called with resulting data. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {HTMLScriptElement} The script pending execution. │ │ │ │ - */ │ │ │ │ - createRequest: function(url, params, callback) { │ │ │ │ - var id = OpenLayers.Protocol.Script.register(callback); │ │ │ │ - var name = OpenLayers.String.format(this.callbackTemplate, { │ │ │ │ - id: id │ │ │ │ - }); │ │ │ │ - params = OpenLayers.Util.extend({}, params); │ │ │ │ - params[this.callbackKey] = this.callbackPrefix + name; │ │ │ │ - url = OpenLayers.Util.urlAppend( │ │ │ │ - url, OpenLayers.Util.getParameterString(params) │ │ │ │ - ); │ │ │ │ - var script = document.createElement("script"); │ │ │ │ - script.type = "text/javascript"; │ │ │ │ - script.src = url; │ │ │ │ - script.id = "OpenLayers_Protocol_Script_" + id; │ │ │ │ - this.pendingRequests[script.id] = script; │ │ │ │ - var head = document.getElementsByTagName("head")[0]; │ │ │ │ - head.appendChild(script); │ │ │ │ - return script; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: destroyRequest │ │ │ │ - * Remove a script node associated with a response from the document. Also │ │ │ │ - * unregisters the callback and removes the script from the │ │ │ │ - * <pendingRequests> object. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * script - {HTMLScriptElement} │ │ │ │ - */ │ │ │ │ - destroyRequest: function(script) { │ │ │ │ - OpenLayers.Protocol.Script.unregister(script.id.split("_").pop()); │ │ │ │ - delete this.pendingRequests[script.id]; │ │ │ │ - if (script.parentNode) { │ │ │ │ - script.parentNode.removeChild(script); │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement; │ │ │ │ } │ │ │ │ + var obj = {}; │ │ │ │ + this.readNode(data, obj); │ │ │ │ + return obj; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handleRead │ │ │ │ - * Individual callbacks are created for read, create and update, should │ │ │ │ - * a subclass need to override each one separately. │ │ │ │ - * │ │ │ │ - * 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) { │ │ │ │ - this.handleResponse(response, options); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: handleResponse │ │ │ │ - * Called by CRUD specific handlers. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * response - {<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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - handleResponse: function(response, options) { │ │ │ │ - if (options.callback) { │ │ │ │ - if (response.data) { │ │ │ │ - response.features = this.parseFeatures(response.data); │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ - } else { │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ + readers: { │ │ │ │ + "csw": { │ │ │ │ + "GetDomainResponse": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "DomainValues": function(node, obj) { │ │ │ │ + if (!(OpenLayers.Util.isArray(obj.DomainValues))) { │ │ │ │ + obj.DomainValues = []; │ │ │ │ + } │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var domainValue = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + domainValue[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ + } │ │ │ │ + this.readChildNodes(node, domainValue); │ │ │ │ + obj.DomainValues.push(domainValue); │ │ │ │ + }, │ │ │ │ + "PropertyName": function(node, obj) { │ │ │ │ + obj.PropertyName = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ParameterName": function(node, obj) { │ │ │ │ + obj.ParameterName = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ListOfValues": function(node, obj) { │ │ │ │ + if (!(OpenLayers.Util.isArray(obj.ListOfValues))) { │ │ │ │ + obj.ListOfValues = []; │ │ │ │ + } │ │ │ │ + this.readChildNodes(node, obj.ListOfValues); │ │ │ │ + }, │ │ │ │ + "Value": function(node, obj) { │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var value = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + value[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ + } │ │ │ │ + value.value = this.getChildValue(node); │ │ │ │ + obj.push({ │ │ │ │ + Value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "ConceptualScheme": function(node, obj) { │ │ │ │ + obj.ConceptualScheme = {}; │ │ │ │ + this.readChildNodes(node, obj.ConceptualScheme); │ │ │ │ + }, │ │ │ │ + "Name": function(node, obj) { │ │ │ │ + obj.Name = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Document": function(node, obj) { │ │ │ │ + obj.Document = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Authority": function(node, obj) { │ │ │ │ + obj.Authority = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "RangeOfValues": function(node, obj) { │ │ │ │ + obj.RangeOfValues = {}; │ │ │ │ + this.readChildNodes(node, obj.RangeOfValues); │ │ │ │ + }, │ │ │ │ + "MinValue": function(node, obj) { │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var value = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + value[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ + } │ │ │ │ + value.value = this.getChildValue(node); │ │ │ │ + obj.MinValue = value; │ │ │ │ + }, │ │ │ │ + "MaxValue": function(node, obj) { │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var value = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + value[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ + } │ │ │ │ + value.value = this.getChildValue(node); │ │ │ │ + obj.MaxValue = value; │ │ │ │ } │ │ │ │ - this.destroyRequest(response.priv); │ │ │ │ - options.callback.call(options.scope, response); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseFeatures │ │ │ │ - * Read Script response body and return features. │ │ │ │ + * APIMethod: write │ │ │ │ + * Given an configuration js object, write a CSWGetDomain request. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * data - {Object} The data sent to the callback function by the server. │ │ │ │ + * options - {Object} A object mapping the request. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Array({<OpenLayers.Feature.Vector>})} or │ │ │ │ - * {<OpenLayers.Feature.Vector>} Array of features or a single feature. │ │ │ │ + * {String} A serialized CSWGetDomain request. │ │ │ │ */ │ │ │ │ - parseFeatures: function(data) { │ │ │ │ - return this.format.read(data); │ │ │ │ + write: function(options) { │ │ │ │ + var node = this.writeNode("csw:GetDomain", options); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [node]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: abort │ │ │ │ - * Abort an ongoing request. If no response is provided, all pending │ │ │ │ - * requests will be aborted. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * response - {<OpenLayers.Protocol.Response>} The response object returned │ │ │ │ - * from a <read> request. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - abort: function(response) { │ │ │ │ - if (response) { │ │ │ │ - this.destroyRequest(response.priv); │ │ │ │ - } else { │ │ │ │ - for (var key in this.pendingRequests) { │ │ │ │ - this.destroyRequest(this.pendingRequests[key]); │ │ │ │ + writers: { │ │ │ │ + "csw": { │ │ │ │ + "GetDomain": function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:GetDomain", { │ │ │ │ + attributes: { │ │ │ │ + service: "CSW", │ │ │ │ + version: this.version │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (options.PropertyName || this.PropertyName) { │ │ │ │ + this.writeNode( │ │ │ │ + "csw:PropertyName", │ │ │ │ + options.PropertyName || this.PropertyName, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } else if (options.ParameterName || this.ParameterName) { │ │ │ │ + this.writeNode( │ │ │ │ + "csw:ParameterName", │ │ │ │ + options.ParameterName || this.ParameterName, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + this.readChildNodes(node, options); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "PropertyName": function(value) { │ │ │ │ + var node = this.createElementNSPlus("csw:PropertyName", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ParameterName": function(value) { │ │ │ │ + var node = this.createElementNSPlus("csw:ParameterName", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Clean up the protocol. │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - this.abort(); │ │ │ │ - delete this.params; │ │ │ │ - delete this.format; │ │ │ │ - OpenLayers.Protocol.prototype.destroy.apply(this); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.Script" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.CSWGetDomain.v2_0_2" │ │ │ │ }); │ │ │ │ - │ │ │ │ -(function() { │ │ │ │ - var o = OpenLayers.Protocol.Script; │ │ │ │ - var counter = 0; │ │ │ │ - o.registry = {}; │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Function: OpenLayers.Protocol.Script.register │ │ │ │ - * Register a callback for a newly created script. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * callback - {Function} The callback to be executed when the newly added │ │ │ │ - * script loads. This callback will be called with a single argument │ │ │ │ - * that is the JSON returned by the service. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Number} An identifier for retrieving the registered callback. │ │ │ │ - */ │ │ │ │ - o.register = function(callback) { │ │ │ │ - var id = "c" + (++counter); │ │ │ │ - o.registry[id] = function() { │ │ │ │ - callback.apply(this, arguments); │ │ │ │ - }; │ │ │ │ - return id; │ │ │ │ - }; │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Function: OpenLayers.Protocol.Script.unregister │ │ │ │ - * Unregister a callback previously registered with the register function. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * id - {Number} The identifer returned by the register function. │ │ │ │ - */ │ │ │ │ - o.unregister = function(id) { │ │ │ │ - delete o.registry[id]; │ │ │ │ - }; │ │ │ │ -})(); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Protocol/CSW.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.CSW │ │ │ │ - * Used to create a versioned CSW protocol. Default version is 2.0.2. │ │ │ │ - */ │ │ │ │ -OpenLayers.Protocol.CSW = function(options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults( │ │ │ │ - options, OpenLayers.Protocol.CSW.DEFAULTS │ │ │ │ - ); │ │ │ │ - var cls = OpenLayers.Protocol.CSW["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (!cls) { │ │ │ │ - throw "Unsupported CSW version: " + options.version; │ │ │ │ - } │ │ │ │ - return new cls(options); │ │ │ │ -}; │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Protocol.CSW.DEFAULTS │ │ │ │ - */ │ │ │ │ -OpenLayers.Protocol.CSW.DEFAULTS = { │ │ │ │ - "version": "2.0.2" │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Protocol/SOS.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 │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Function: OpenLayers.Protocol.SOS │ │ │ │ - * Used to create a versioned SOS protocol. Default version is 1.0.0. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Protocol>} An SOS protocol for the given version. │ │ │ │ - */ │ │ │ │ -OpenLayers.Protocol.SOS = function(options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults( │ │ │ │ - options, OpenLayers.Protocol.SOS.DEFAULTS │ │ │ │ - ); │ │ │ │ - var cls = OpenLayers.Protocol.SOS["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (!cls) { │ │ │ │ - throw "Unsupported SOS version: " + options.version; │ │ │ │ - } │ │ │ │ - return new cls(options); │ │ │ │ -}; │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Protocol.SOS.DEFAULTS │ │ │ │ - */ │ │ │ │ -OpenLayers.Protocol.SOS.DEFAULTS = { │ │ │ │ - "version": "1.0.0" │ │ │ │ -}; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/HTTP.js │ │ │ │ + OpenLayers/Format/OWSContext/v0_3_1.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 │ │ │ │ + * @requires OpenLayers/Format/XML.js │ │ │ │ + * @requires OpenLayers/Format/KML.js │ │ │ │ + * @requires OpenLayers/Format/GML.js │ │ │ │ + * @requires OpenLayers/Format/GML/v2.js │ │ │ │ + * @requires OpenLayers/Format/SLD/v1_0_0.js │ │ │ │ + * @requires OpenLayers/Format/OWSContext.js │ │ │ │ + * @requires OpenLayers/Format/OWSCommon/v1_0_0.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.HTTP │ │ │ │ - * A basic HTTP protocol for vector layers. Create a new instance with the │ │ │ │ - * <OpenLayers.Protocol.HTTP> constructor. │ │ │ │ + * Class: OpenLayers.Format.OWSContext.v0_3_1 │ │ │ │ + * Read and write OWSContext version 0.3.1. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol> │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ +OpenLayers.Format.OWSContext.v0_3_1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: url │ │ │ │ - * {String} Service URL, read-only, set through the options │ │ │ │ - * passed to constructor. │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ - url: null, │ │ │ │ + namespaces: { │ │ │ │ + owc: "http://www.opengis.net/ows-context", │ │ │ │ + gml: "http://www.opengis.net/gml", │ │ │ │ + kml: "http://www.opengis.net/kml/2.2", │ │ │ │ + ogc: "http://www.opengis.net/ogc", │ │ │ │ + ows: "http://www.opengis.net/ows", │ │ │ │ + sld: "http://www.opengis.net/sld", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: headers │ │ │ │ - * {Object} HTTP request headers, read-only, set through the options │ │ │ │ - * passed to the constructor, │ │ │ │ - * Example: {'Content-Type': 'plain/text'} │ │ │ │ + * Constant: VERSION │ │ │ │ + * {String} 0.3.1 │ │ │ │ */ │ │ │ │ - headers: null, │ │ │ │ + VERSION: "0.3.1", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: params │ │ │ │ - * {Object} Parameters of GET requests, read-only, set through the options │ │ │ │ - * passed to the constructor, │ │ │ │ - * Example: {'bbox': '5,5,5,5'} │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} Schema location │ │ │ │ */ │ │ │ │ - params: null, │ │ │ │ + schemaLocation: "http://www.opengis.net/ows-context http://www.ogcnetwork.net/schemas/owc/0.3.1/owsContext.xsd", │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: defaultPrefix │ │ │ │ + * {String} Default namespace prefix to use. │ │ │ │ */ │ │ │ │ - callback: null, │ │ │ │ + defaultPrefix: "owc", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: scope │ │ │ │ - * {Object} Callback execution scope, read-only, set through the │ │ │ │ - * options passed to the constructor. │ │ │ │ + * APIProperty: extractAttributes │ │ │ │ + * {Boolean} Extract attributes from GML. Default is true. │ │ │ │ */ │ │ │ │ - scope: null, │ │ │ │ + extractAttributes: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: readWithPOST │ │ │ │ - * {Boolean} true if read operations are done with POST requests │ │ │ │ - * instead of GET, defaults to false. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - readWithPOST: false, │ │ │ │ + xy: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: updateWithPOST │ │ │ │ - * {Boolean} true if update operations are done with POST requests │ │ │ │ - * defaults to false. │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ */ │ │ │ │ - updateWithPOST: false, │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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(). │ │ │ │ + * Property: featureNS │ │ │ │ + * {String} The namespace uri to use for writing InlineGeometry │ │ │ │ */ │ │ │ │ - deleteWithPOST: false, │ │ │ │ + featureNS: "http://mapserver.gis.umn.edu/mapserver", │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: featureType │ │ │ │ + * {String} The name to use as the feature type when writing out │ │ │ │ + * InlineGeometry │ │ │ │ */ │ │ │ │ - wildcarded: false, │ │ │ │ + featureType: 'vector', │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Property: geometryName │ │ │ │ + * {String} The name to use for the geometry attribute when writing out │ │ │ │ + * InlineGeometry │ │ │ │ */ │ │ │ │ - srsInBBOX: false, │ │ │ │ + geometryName: 'geometry', │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: nestingLayerLookup │ │ │ │ + * {Object} Hashtable lookup for nesting layer nodes. Used while writing │ │ │ │ + * the OWS context document. It is necessary to keep track of the │ │ │ │ + * nestingPaths for which nesting layer nodes have already been │ │ │ │ + * created, so (nesting) layer nodes are added to those nodes. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * For example: │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * filter - {<OpenLayers.Filter>} filter to convert. │ │ │ │ - * params - {Object} The parameters object. │ │ │ │ + * If there are three layers with nestingPaths: │ │ │ │ + * layer1.metadata.nestingPath = "a/b/" │ │ │ │ + * layer2.metadata.nestingPath = "a/b/" │ │ │ │ + * layer2.metadata.nestingPath = "a/c" │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Object} The resulting parameters object. │ │ │ │ + * then a nesting layer node "a" should be created once and added │ │ │ │ + * to the resource list, a nesting layer node "b" should be created │ │ │ │ + * once and added under "a", and a nesting layer node "c" should be │ │ │ │ + * created and added under "a". The lookup paths for these nodes │ │ │ │ + * will be "a", "a/b", and "a/c" respectively. │ │ │ │ */ │ │ │ │ + nestingLayerLookup: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Construct a request for reading new features. │ │ │ │ + * Constructor: OpenLayers.Format.OWSContext.v0_3_1 │ │ │ │ + * Instances of this class are not created directly. Use the │ │ │ │ + * <OpenLayers.Format.OWSContext> constructor instead. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ + OpenLayers.Format.GML.v2.prototype.setGeometryTypes.call(this); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handleRead │ │ │ │ - * Individual callbacks are created for read, create and update, should │ │ │ │ - * a subclass need to override each one separately. │ │ │ │ + * Method: setNestingPath │ │ │ │ + * Set the nestingPath property of the layer depending on the position │ │ │ │ + * of the layer in hierarchy of layers. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * resp - {<OpenLayers.Protocol.Response>} The response object to pass to │ │ │ │ - * the user callback. │ │ │ │ - * options - {Object} The user options passed to the read call. │ │ │ │ + * l - {Object} An object that may have a layersContext array property. │ │ │ │ + * │ │ │ │ */ │ │ │ │ - handleRead: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options); │ │ │ │ + setNestingPath: function(l) { │ │ │ │ + if (l.layersContext) { │ │ │ │ + for (var i = 0, len = l.layersContext.length; i < len; i++) { │ │ │ │ + var layerContext = l.layersContext[i]; │ │ │ │ + var nPath = []; │ │ │ │ + var nTitle = l.title || ""; │ │ │ │ + if (l.metadata && l.metadata.nestingPath) { │ │ │ │ + nPath = l.metadata.nestingPath.slice(); │ │ │ │ + } │ │ │ │ + if (nTitle != "") { │ │ │ │ + nPath.push(nTitle); │ │ │ │ + } │ │ │ │ + layerContext.metadata.nestingPath = nPath; │ │ │ │ + if (layerContext.layersContext) { │ │ │ │ + this.setNestingPath(layerContext); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: create │ │ │ │ - * Construct a request for writing newly created features. │ │ │ │ + * Function: decomposeNestingPath │ │ │ │ + * Takes a nestingPath like "a/b/c" and decomposes it into subpaths: │ │ │ │ + * "a", "a/b", "a/b/c" │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * nPath - {Array} the nesting path │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * Array({String}) Array with subpaths, or empty array if there is nothing │ │ │ │ + * to decompose │ │ │ │ */ │ │ │ │ - handleCreate: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options); │ │ │ │ + decomposeNestingPath: function(nPath) { │ │ │ │ + var a = []; │ │ │ │ + if (OpenLayers.Util.isArray(nPath)) { │ │ │ │ + var path = nPath.slice(); │ │ │ │ + while (path.length > 0) { │ │ │ │ + a.push(path.slice()); │ │ │ │ + path.pop(); │ │ │ │ + } │ │ │ │ + a.reverse(); │ │ │ │ + } │ │ │ │ + return a; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: read │ │ │ │ + * Read OWS context data from a string or DOMElement, and return a list │ │ │ │ + * of layers. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * {Object} The context object with a flat layer list as a property named │ │ │ │ + * layersContext. │ │ │ │ */ │ │ │ │ - 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) │ │ │ │ + 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 context = {}; │ │ │ │ + this.readNode(data, context); │ │ │ │ + // since an OWSContext can be nested we need to go through this │ │ │ │ + // structure recursively │ │ │ │ + this.setNestingPath({ │ │ │ │ + layersContext: context.layersContext │ │ │ │ }); │ │ │ │ - │ │ │ │ - return resp; │ │ │ │ + // after nesting path has been set, create a flat list of layers │ │ │ │ + var layers = []; │ │ │ │ + this.processLayer(layers, context); │ │ │ │ + delete context.layersContext; │ │ │ │ + context.layersContext = layers; │ │ │ │ + return context; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handleUpdate │ │ │ │ - * Called the the request issued by <update> is complete. May be overridden │ │ │ │ - * by subclasses. │ │ │ │ + * Method: processLayer │ │ │ │ + * Recursive function to get back a flat list of layers from the hierarchic │ │ │ │ + * layer structure. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * resp - {<OpenLayers.Protocol.Response>} The response object to pass to │ │ │ │ - * any user callback. │ │ │ │ - * options - {Object} The user options passed to the update call. │ │ │ │ + * layerArray - {Array({Object})} Array of layerContext objects │ │ │ │ + * layer - {Object} layerContext object │ │ │ │ */ │ │ │ │ - handleUpdate: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options); │ │ │ │ + processLayer: function(layerArray, layer) { │ │ │ │ + if (layer.layersContext) { │ │ │ │ + for (var i = 0, len = layer.layersContext.length; i < len; i++) { │ │ │ │ + var l = layer.layersContext[i]; │ │ │ │ + layerArray.push(l); │ │ │ │ + if (l.layersContext) { │ │ │ │ + this.processLayer(layerArray, l); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: delete │ │ │ │ - * Construct a request deleting a removed feature. │ │ │ │ + * APIMethod: write │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - * options - {Object} Optional object for configuring the request. │ │ │ │ - * This object is modified and should not be reused. │ │ │ │ + * context - {Object} An object representing the map context. │ │ │ │ + * options - {Object} Optional object. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * {String} An OWS Context document string. │ │ │ │ */ │ │ │ │ - "delete": function(feature, options) { │ │ │ │ + write: function(context, options) { │ │ │ │ + var name = "OWSContext"; │ │ │ │ + this.nestingLayerLookup = {}; //start with empty lookup │ │ │ │ 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; │ │ │ │ + OpenLayers.Util.applyDefaults(options, context); │ │ │ │ + var root = this.writeNode(name, options); │ │ │ │ + this.nestingLayerLookup = null; //clear lookup │ │ │ │ + this.setAttributeNS( │ │ │ │ + root, this.namespaces["xsi"], │ │ │ │ + "xsi:schemaLocation", this.schemaLocation │ │ │ │ + ); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [root]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - handleDelete: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options); │ │ │ │ + readers: { │ │ │ │ + "kml": { │ │ │ │ + "Document": function(node, obj) { │ │ │ │ + obj.features = new OpenLayers.Format.KML({ │ │ │ │ + kmlns: this.namespaces.kml, │ │ │ │ + extractStyles: true │ │ │ │ + }).read(node); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "owc": { │ │ │ │ + "OWSContext": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "General": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "ResourceList": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "Layer": function(node, obj) { │ │ │ │ + var layerContext = { │ │ │ │ + metadata: {}, │ │ │ │ + visibility: (node.getAttribute("hidden") != "1"), │ │ │ │ + queryable: (node.getAttribute("queryable") == "1"), │ │ │ │ + opacity: ((node.getAttribute("opacity") != null) ? │ │ │ │ + parseFloat(node.getAttribute("opacity")) : null), │ │ │ │ + name: node.getAttribute("name"), │ │ │ │ + /* A category layer is a dummy layer meant for creating │ │ │ │ + hierarchies. It is not a physical layer in the │ │ │ │ + OpenLayers sense. The assumption we make here is that │ │ │ │ + category layers do not have a name attribute */ │ │ │ │ + categoryLayer: (node.getAttribute("name") == null), │ │ │ │ + formats: [], │ │ │ │ + styles: [] │ │ │ │ + }; │ │ │ │ + if (!obj.layersContext) { │ │ │ │ + obj.layersContext = []; │ │ │ │ + } │ │ │ │ + obj.layersContext.push(layerContext); │ │ │ │ + this.readChildNodes(node, layerContext); │ │ │ │ + }, │ │ │ │ + "InlineGeometry": function(node, obj) { │ │ │ │ + obj.features = []; │ │ │ │ + var elements = this.getElementsByTagNameNS(node, │ │ │ │ + this.namespaces.gml, "featureMember"); │ │ │ │ + var el; │ │ │ │ + if (elements.length >= 1) { │ │ │ │ + el = elements[0]; │ │ │ │ + } │ │ │ │ + if (el && el.firstChild) { │ │ │ │ + var featurenode = (el.firstChild.nextSibling) ? │ │ │ │ + el.firstChild.nextSibling : el.firstChild; │ │ │ │ + this.setNamespace("feature", featurenode.namespaceURI); │ │ │ │ + this.featureType = featurenode.localName || │ │ │ │ + featurenode.nodeName.split(":").pop(); │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Server": function(node, obj) { │ │ │ │ + // when having multiple Server types, we prefer WMS │ │ │ │ + if ((!obj.service && !obj.version) || │ │ │ │ + (obj.service != │ │ │ │ + OpenLayers.Format.Context.serviceTypes.WMS)) { │ │ │ │ + obj.service = node.getAttribute("service"); │ │ │ │ + obj.version = node.getAttribute("version"); │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Name": function(node, obj) { │ │ │ │ + obj.name = this.getChildValue(node); │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "Title": function(node, obj) { │ │ │ │ + obj.title = this.getChildValue(node); │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "StyleList": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj.styles); │ │ │ │ + }, │ │ │ │ + "Style": function(node, obj) { │ │ │ │ + var style = {}; │ │ │ │ + obj.push(style); │ │ │ │ + this.readChildNodes(node, style); │ │ │ │ + }, │ │ │ │ + "LegendURL": function(node, obj) { │ │ │ │ + var legend = {}; │ │ │ │ + obj.legend = legend; │ │ │ │ + this.readChildNodes(node, legend); │ │ │ │ + }, │ │ │ │ + "OnlineResource": function(node, obj) { │ │ │ │ + obj.url = this.getAttributeNS(node, this.namespaces.xlink, │ │ │ │ + "href"); │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "ows": OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows, │ │ │ │ + "gml": OpenLayers.Format.GML.v2.prototype.readers.gml, │ │ │ │ + "sld": OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld, │ │ │ │ + "feature": OpenLayers.Format.GML.v2.prototype.readers.feature │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + writers: { │ │ │ │ + "owc": { │ │ │ │ + "OWSContext": function(options) { │ │ │ │ + var node = this.createElementNSPlus("OWSContext", { │ │ │ │ + attributes: { │ │ │ │ + version: this.VERSION, │ │ │ │ + id: options.id || OpenLayers.Util.createUniqueID("OpenLayers_OWSContext_") │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.writeNode("General", options, node); │ │ │ │ + this.writeNode("ResourceList", options, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "General": function(options) { │ │ │ │ + var node = this.createElementNSPlus("General"); │ │ │ │ + this.writeNode("ows:BoundingBox", options, node); │ │ │ │ + this.writeNode("ows:Title", options.title || 'OpenLayers OWSContext', node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ResourceList": function(options) { │ │ │ │ + var node = this.createElementNSPlus("ResourceList"); │ │ │ │ + for (var i = 0, len = options.layers.length; i < len; i++) { │ │ │ │ + var layer = options.layers[i]; │ │ │ │ + var decomposedPath = this.decomposeNestingPath(layer.metadata.nestingPath); │ │ │ │ + this.writeNode("_Layer", { │ │ │ │ + layer: layer, │ │ │ │ + subPaths: decomposedPath │ │ │ │ + }, node); │ │ │ │ } │ │ │ │ - resp.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ - } else { │ │ │ │ - // failure │ │ │ │ - resp.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Server": function(options) { │ │ │ │ + var node = this.createElementNSPlus("Server", { │ │ │ │ + attributes: { │ │ │ │ + version: options.version, │ │ │ │ + service: options.service │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.writeNode("OnlineResource", options, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "OnlineResource": function(options) { │ │ │ │ + var node = this.createElementNSPlus("OnlineResource", { │ │ │ │ + attributes: { │ │ │ │ + "xlink:href": options.url │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "InlineGeometry": function(layer) { │ │ │ │ + var node = this.createElementNSPlus("InlineGeometry"), │ │ │ │ + dataExtent = layer.getDataExtent(); │ │ │ │ + if (dataExtent !== null) { │ │ │ │ + this.writeNode("gml:boundedBy", dataExtent, node); │ │ │ │ + } │ │ │ │ + for (var i = 0, len = layer.features.length; i < len; i++) { │ │ │ │ + this.writeNode("gml:featureMember", layer.features[i], node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "StyleList": function(styles) { │ │ │ │ + var node = this.createElementNSPlus("StyleList"); │ │ │ │ + for (var i = 0, len = styles.length; i < len; i++) { │ │ │ │ + this.writeNode("Style", styles[i], node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Style": function(style) { │ │ │ │ + var node = this.createElementNSPlus("Style"); │ │ │ │ + this.writeNode("Name", style, node); │ │ │ │ + this.writeNode("Title", style, node); │ │ │ │ + if (style.legend) { │ │ │ │ + this.writeNode("LegendURL", style, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Name": function(obj) { │ │ │ │ + var node = this.createElementNSPlus("Name", { │ │ │ │ + value: obj.name │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Title": function(obj) { │ │ │ │ + var node = this.createElementNSPlus("Title", { │ │ │ │ + value: obj.title │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "LegendURL": function(style) { │ │ │ │ + var node = this.createElementNSPlus("LegendURL"); │ │ │ │ + this.writeNode("OnlineResource", style.legend, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "_WMS": function(layer) { │ │ │ │ + var node = this.createElementNSPlus("Layer", { │ │ │ │ + attributes: { │ │ │ │ + name: layer.params.LAYERS, │ │ │ │ + queryable: layer.queryable ? "1" : "0", │ │ │ │ + hidden: layer.visibility ? "0" : "1", │ │ │ │ + opacity: layer.hasOwnProperty("opacity") ? layer.opacity : null │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.writeNode("ows:Title", layer.name, node); │ │ │ │ + this.writeNode("ows:OutputFormat", layer.params.FORMAT, node); │ │ │ │ + this.writeNode("Server", { │ │ │ │ + service: OpenLayers.Format.Context.serviceTypes.WMS, │ │ │ │ + version: layer.params.VERSION, │ │ │ │ + url: layer.url │ │ │ │ + }, node); │ │ │ │ + if (layer.metadata.styles && layer.metadata.styles.length > 0) { │ │ │ │ + this.writeNode("StyleList", layer.metadata.styles, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "_Layer": function(options) { │ │ │ │ + var layer, subPaths, node, title; │ │ │ │ + layer = options.layer; │ │ │ │ + subPaths = options.subPaths; │ │ │ │ + node = null; │ │ │ │ + title = null; │ │ │ │ + // subPaths is an array of an array │ │ │ │ + // recursively calling _Layer writer eats up subPaths, until a │ │ │ │ + // real writer is called and nodes are returned. │ │ │ │ + if (subPaths.length > 0) { │ │ │ │ + var path = subPaths[0].join("/"); │ │ │ │ + var index = path.lastIndexOf("/"); │ │ │ │ + node = this.nestingLayerLookup[path]; │ │ │ │ + title = (index > 0) ? path.substring(index + 1, path.length) : path; │ │ │ │ + if (!node) { │ │ │ │ + // category layer │ │ │ │ + node = this.createElementNSPlus("Layer"); │ │ │ │ + this.writeNode("ows:Title", title, node); │ │ │ │ + this.nestingLayerLookup[path] = node; │ │ │ │ + } │ │ │ │ + options.subPaths.shift(); //remove a path after each call │ │ │ │ + this.writeNode("_Layer", options, node); │ │ │ │ + return node; │ │ │ │ + } else { │ │ │ │ + // write out the actual layer │ │ │ │ + if (layer instanceof OpenLayers.Layer.WMS) { │ │ │ │ + node = this.writeNode("_WMS", layer); │ │ │ │ + } else if (layer instanceof OpenLayers.Layer.Vector) { │ │ │ │ + if (layer.protocol instanceof OpenLayers.Protocol.WFS.v1) { │ │ │ │ + node = this.writeNode("_WFS", layer); │ │ │ │ + } else if (layer.protocol instanceof OpenLayers.Protocol.HTTP) { │ │ │ │ + if (layer.protocol.format instanceof OpenLayers.Format.GML) { │ │ │ │ + layer.protocol.format.version = "2.1.2"; │ │ │ │ + node = this.writeNode("_GML", layer); │ │ │ │ + } else if (layer.protocol.format instanceof OpenLayers.Format.KML) { │ │ │ │ + layer.protocol.format.version = "2.2"; │ │ │ │ + node = this.writeNode("_KML", layer); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + // write out as inline GML since we have no idea │ │ │ │ + // about the original Format │ │ │ │ + this.setNamespace("feature", this.featureNS); │ │ │ │ + node = this.writeNode("_InlineGeometry", layer); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (layer.options.maxScale) { │ │ │ │ + this.writeNode("sld:MinScaleDenominator", │ │ │ │ + layer.options.maxScale, node); │ │ │ │ + } │ │ │ │ + if (layer.options.minScale) { │ │ │ │ + this.writeNode("sld:MaxScaleDenominator", │ │ │ │ + layer.options.minScale, node); │ │ │ │ + } │ │ │ │ + this.nestingLayerLookup[layer.name] = node; │ │ │ │ + return node; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "_WFS": function(layer) { │ │ │ │ + var node = this.createElementNSPlus("Layer", { │ │ │ │ + attributes: { │ │ │ │ + name: layer.protocol.featurePrefix + ":" + layer.protocol.featureType, │ │ │ │ + hidden: layer.visibility ? "0" : "1" │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.writeNode("ows:Title", layer.name, node); │ │ │ │ + this.writeNode("Server", { │ │ │ │ + service: OpenLayers.Format.Context.serviceTypes.WFS, │ │ │ │ + version: layer.protocol.version, │ │ │ │ + url: layer.protocol.url │ │ │ │ + }, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "_InlineGeometry": function(layer) { │ │ │ │ + var node = this.createElementNSPlus("Layer", { │ │ │ │ + attributes: { │ │ │ │ + name: this.featureType, │ │ │ │ + hidden: layer.visibility ? "0" : "1" │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.writeNode("ows:Title", layer.name, node); │ │ │ │ + this.writeNode("InlineGeometry", layer, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "_GML": function(layer) { │ │ │ │ + var node = this.createElementNSPlus("Layer"); │ │ │ │ + this.writeNode("ows:Title", layer.name, node); │ │ │ │ + this.writeNode("Server", { │ │ │ │ + service: OpenLayers.Format.Context.serviceTypes.GML, │ │ │ │ + url: layer.protocol.url, │ │ │ │ + version: layer.protocol.format.version │ │ │ │ + }, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "_KML": function(layer) { │ │ │ │ + var node = this.createElementNSPlus("Layer"); │ │ │ │ + this.writeNode("ows:Title", layer.name, node); │ │ │ │ + this.writeNode("Server", { │ │ │ │ + service: OpenLayers.Format.Context.serviceTypes.KML, │ │ │ │ + version: layer.protocol.format.version, │ │ │ │ + url: layer.protocol.url │ │ │ │ + }, node); │ │ │ │ + return node; │ │ │ │ } │ │ │ │ - options.callback.call(options.scope, resp); │ │ │ │ - } │ │ │ │ + }, │ │ │ │ + "gml": OpenLayers.Util.applyDefaults({ │ │ │ │ + "boundedBy": function(bounds) { │ │ │ │ + var node = this.createElementNSPlus("gml:boundedBy"); │ │ │ │ + this.writeNode("gml:Box", bounds, node); │ │ │ │ + return node; │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.GML.v2.prototype.writers.gml), │ │ │ │ + "ows": OpenLayers.Format.OWSCommon.v1_0_0.prototype.writers.ows, │ │ │ │ + "sld": OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld, │ │ │ │ + "feature": OpenLayers.Format.GML.v2.prototype.writers.feature │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.OWSContext.v0_3_1" │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WPSCapabilities/v1_0_0.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - // 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; │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - // 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 │ │ │ │ - }); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/WPSCapabilities.js │ │ │ │ + * @requires OpenLayers/Format/OWSCommon/v1_1_0.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - 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; │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WPSCapabilities.v1_0_0 │ │ │ │ + * Read WPS Capabilities version 1.0.0. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WPSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.XML, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + */ │ │ │ │ + namespaces: { │ │ │ │ + ows: "http://www.opengis.net/ows/1.1", │ │ │ │ + wps: "http://www.opengis.net/wps/1.0.0", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink" │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ + */ │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WPSCapabilities.v1_0_0 │ │ │ │ + * Create a new parser for WPS capabilities version 1.0.0. │ │ │ │ + * │ │ │ │ + * 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]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return info about the WPS. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} Information about the WPS service. │ │ │ │ + */ │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ } │ │ │ │ - finalResponse.insertIds = fids; │ │ │ │ - callback.apply(this, [response]); │ │ │ │ - } │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement; │ │ │ │ + } │ │ │ │ + var capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + return capabilities; │ │ │ │ + }, │ │ │ │ │ │ │ │ - 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]); │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wps": { │ │ │ │ + "Capabilities": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "ProcessOfferings": function(node, obj) { │ │ │ │ + obj.processOfferings = {}; │ │ │ │ + this.readChildNodes(node, obj.processOfferings); │ │ │ │ + }, │ │ │ │ + "Process": function(node, processOfferings) { │ │ │ │ + var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); │ │ │ │ + var process = { │ │ │ │ + processVersion: processVersion │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, process); │ │ │ │ + processOfferings[process.identifier] = process; │ │ │ │ + }, │ │ │ │ + "Languages": function(node, obj) { │ │ │ │ + obj.languages = []; │ │ │ │ + this.readChildNodes(node, obj.languages); │ │ │ │ + }, │ │ │ │ + "Default": function(node, languages) { │ │ │ │ + var language = { │ │ │ │ + isDefault: true │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, language); │ │ │ │ + languages.push(language); │ │ │ │ + }, │ │ │ │ + "Supported": function(node, languages) { │ │ │ │ + var language = {}; │ │ │ │ + this.readChildNodes(node, language); │ │ │ │ + languages.push(language); │ │ │ │ } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + }, │ │ │ │ + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ + }, │ │ │ │ │ │ │ │ - // 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; │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WPSCapabilities.v1_0_0" │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WFSCapabilities/v1.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.HTTP" │ │ │ │ -}); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/WFSCapabilities.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WFSCapabilities.v1 │ │ │ │ + * Abstract class not to be instantiated directly. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WFSCapabilities.v1 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.XML, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + */ │ │ │ │ + namespaces: { │ │ │ │ + wfs: "http://www.opengis.net/wfs", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ + ows: "http://www.opengis.net/ows" │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: errorProperty │ │ │ │ + * {String} Which property of the returned object to check for in order to │ │ │ │ + * determine whether or not parsing has failed. In the case that the │ │ │ │ + * errorProperty is undefined on the returned object, the document will be │ │ │ │ + * run through an OGCExceptionReport parser. │ │ │ │ + */ │ │ │ │ + errorProperty: "featureTypeList", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: defaultPrefix │ │ │ │ + */ │ │ │ │ + defaultPrefix: "wfs", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WFSCapabilities.v1_1 │ │ │ │ + * Create an instance of one of the subclasses. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return a list of layers. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array} List of named layers. │ │ │ │ + */ │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ + } │ │ │ │ + var raw = data; │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement; │ │ │ │ + } │ │ │ │ + var capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + return capabilities; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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": { │ │ │ │ + "WFS_Capabilities": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "FeatureTypeList": function(node, request) { │ │ │ │ + request.featureTypeList = { │ │ │ │ + featureTypes: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, request.featureTypeList); │ │ │ │ + }, │ │ │ │ + "FeatureType": function(node, featureTypeList) { │ │ │ │ + var featureType = {}; │ │ │ │ + this.readChildNodes(node, featureType); │ │ │ │ + featureTypeList.featureTypes.push(featureType); │ │ │ │ + }, │ │ │ │ + "Name": function(node, obj) { │ │ │ │ + var name = this.getChildValue(node); │ │ │ │ + if (name) { │ │ │ │ + var parts = name.split(":"); │ │ │ │ + obj.name = parts.pop(); │ │ │ │ + if (parts.length > 0) { │ │ │ │ + obj.featureNS = this.lookupNamespaceURI(node, parts[0]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Title": function(node, obj) { │ │ │ │ + var title = this.getChildValue(node); │ │ │ │ + if (title) { │ │ │ │ + obj.title = title; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Abstract": function(node, obj) { │ │ │ │ + var abst = this.getChildValue(node); │ │ │ │ + if (abst) { │ │ │ │ + obj["abstract"] = abst; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1" │ │ │ │ + │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/CSW/v2_0_2.js │ │ │ │ + OpenLayers/Format/WFSCapabilities/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/CSW.js │ │ │ │ - * @requires OpenLayers/Format/CSWGetRecords/v2_0_2.js │ │ │ │ + * @requires OpenLayers/Format/WFSCapabilities/v1.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.CSW.v2_0_2 │ │ │ │ - * CS-W (Catalogue services for the Web) version 2.0.2 protocol. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.WFSCapabilities/v1_0_0 │ │ │ │ + * Read WFS Capabilities version 1.0.0. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol> │ │ │ │ + * - <OpenLayers.Format.WFSCapabilities.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol.CSW.v2_0_2 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ +OpenLayers.Format.WFSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WFSCapabilities.v1_0_0 │ │ │ │ + * Create a new parser for WFS capabilities version 1.0.0. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Protocol.CSW.v2_0_2 │ │ │ │ - * A class for CSW version 2.0.2 protocol management. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ - if (!options.format) { │ │ │ │ - this.format = new OpenLayers.Format.CSWGetRecords.v2_0_2(OpenLayers.Util.extend({}, this.formatOptions)); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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({ │ │ │ │ + "Service": function(node, capabilities) { │ │ │ │ + capabilities.service = {}; │ │ │ │ + this.readChildNodes(node, capabilities.service); │ │ │ │ + }, │ │ │ │ + "Fees": function(node, service) { │ │ │ │ + var fees = this.getChildValue(node); │ │ │ │ + if (fees && fees.toLowerCase() != "none") { │ │ │ │ + service.fees = fees; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "AccessConstraints": function(node, service) { │ │ │ │ + var constraints = this.getChildValue(node); │ │ │ │ + if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ + service.accessConstraints = constraints; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "OnlineResource": function(node, service) { │ │ │ │ + var onlineResource = this.getChildValue(node); │ │ │ │ + if (onlineResource && onlineResource.toLowerCase() != "none") { │ │ │ │ + service.onlineResource = onlineResource; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Keywords": function(node, service) { │ │ │ │ + var keywords = this.getChildValue(node); │ │ │ │ + if (keywords && keywords.toLowerCase() != "none") { │ │ │ │ + service.keywords = keywords.split(', '); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Capability": function(node, capabilities) { │ │ │ │ + capabilities.capability = {}; │ │ │ │ + this.readChildNodes(node, capabilities.capability); │ │ │ │ + }, │ │ │ │ + "Request": function(node, obj) { │ │ │ │ + obj.request = {}; │ │ │ │ + this.readChildNodes(node, obj.request); │ │ │ │ + }, │ │ │ │ + "GetFeature": function(node, request) { │ │ │ │ + request.getfeature = { │ │ │ │ + href: {}, // DCPType │ │ │ │ + formats: [] // ResultFormat │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, request.getfeature); │ │ │ │ + }, │ │ │ │ + "ResultFormat": function(node, obj) { │ │ │ │ + var children = node.childNodes; │ │ │ │ + var childNode; │ │ │ │ + for (var i = 0; i < children.length; i++) { │ │ │ │ + childNode = children[i]; │ │ │ │ + if (childNode.nodeType == 1) { │ │ │ │ + obj.formats.push(childNode.nodeName); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "DCPType": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "HTTP": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj.href); │ │ │ │ + }, │ │ │ │ + "Get": function(node, obj) { │ │ │ │ + obj.get = node.getAttribute("onlineResource"); │ │ │ │ + }, │ │ │ │ + "Post": function(node, obj) { │ │ │ │ + obj.post = node.getAttribute("onlineResource"); │ │ │ │ + }, │ │ │ │ + "SRS": function(node, obj) { │ │ │ │ + var srs = this.getChildValue(node); │ │ │ │ + if (srs) { │ │ │ │ + obj.srs = srs; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]) │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_0_0" │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: read │ │ │ │ - * Construct a request for reading new records from the Catalogue. │ │ │ │ - */ │ │ │ │ - read: function(options) { │ │ │ │ - options = OpenLayers.Util.extend({}, options); │ │ │ │ - OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ - var response = new OpenLayers.Protocol.Response({ │ │ │ │ - requestType: "read" │ │ │ │ - }); │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WFSCapabilities/v1_1_0.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - var data = this.format.write(options.params || options); │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - response.priv = OpenLayers.Request.POST({ │ │ │ │ - url: options.url, │ │ │ │ - callback: this.createCallback(this.handleRead, response, options), │ │ │ │ - params: options.params, │ │ │ │ - headers: options.headers, │ │ │ │ - data: data │ │ │ │ - }); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/WFSCapabilities/v1.js │ │ │ │ + * @requires OpenLayers/Format/OWSCommon/v1.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - return response; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WFSCapabilities/v1_1_0 │ │ │ │ + * Read WFS Capabilities version 1.1.0. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.WFSCapabilities> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WFSCapabilities.v1_1_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: handleRead │ │ │ │ - * Deal with response from the read request. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * response - {<OpenLayers.Protocol.Response>} The response object to pass │ │ │ │ - * to the user callback. │ │ │ │ - * This response is given a code property, and optionally a data property. │ │ │ │ - * The latter represents the CSW records as returned by the call to │ │ │ │ - * the CSW format read method. │ │ │ │ - * options - {Object} The user options passed to the read call. │ │ │ │ - */ │ │ │ │ - handleRead: function(response, options) { │ │ │ │ - if (options.callback) { │ │ │ │ - var request = response.priv; │ │ │ │ - if (request.status >= 200 && request.status < 300) { │ │ │ │ - // success │ │ │ │ - response.data = this.parseData(request); │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ - } else { │ │ │ │ - // failure │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ - } │ │ │ │ - options.callback.call(options.scope, response); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ + */ │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: parseData │ │ │ │ - * Read HTTP response body and return records │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * request - {XMLHttpRequest} The request object │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} The CSW records as returned by the call to the format read method. │ │ │ │ - */ │ │ │ │ - parseData: 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); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WFSCapabilities.v1_1_0 │ │ │ │ + * Create a new parser for WFS capabilities version 1.1.0. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.CSW.v2_0_2" │ │ │ │ + /** │ │ │ │ + * 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({ │ │ │ │ + "DefaultSRS": function(node, obj) { │ │ │ │ + var defaultSRS = this.getChildValue(node); │ │ │ │ + if (defaultSRS) { │ │ │ │ + obj.srs = defaultSRS; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]), │ │ │ │ + "ows": OpenLayers.Format.OWSCommon.v1.prototype.readers.ows │ │ │ │ + }, │ │ │ │ │ │ │ │ -}); │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_1_0" │ │ │ │ + │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/SOS/v1_0_0.js │ │ │ │ + OpenLayers/Format/SLD/v1_0_0_GeoServer.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/SOS.js │ │ │ │ - * @requires OpenLayers/Format/SOSGetFeatureOfInterest.js │ │ │ │ + * @requires OpenLayers/Format/SLD/v1_0_0.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.SOS.v1_0_0 │ │ │ │ - * An SOS v1.0.0 Protocol for vector layers. Create a new instance with the │ │ │ │ - * <OpenLayers.Protocol.SOS.v1_0_0> constructor. │ │ │ │ + * Class: OpenLayers.Format.SLD/v1_0_0_GeoServer │ │ │ │ + * Read and write SLD version 1.0.0 with GeoServer-specific enhanced options. │ │ │ │ + * See http://svn.osgeo.org/geotools/trunk/modules/extension/xsd/xsd-sld/src/main/resources/org/geotools/sld/bindings/StyledLayerDescriptor.xsd │ │ │ │ + * for more information. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol> │ │ │ │ + * - <OpenLayers.Format.SLD.v1_0_0> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol.SOS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ +OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.SLD.v1_0_0, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: fois │ │ │ │ - * {Array(String)} Array of features of interest (foi) │ │ │ │ - */ │ │ │ │ - fois: null, │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} The specific parser version. │ │ │ │ + */ │ │ │ │ + version: "1.0.0", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: profile │ │ │ │ + * {String} The specific profile │ │ │ │ + */ │ │ │ │ + profile: "GeoServer", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Protocol.SOS │ │ │ │ - * A class for giving layers an SOS 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). │ │ │ │ - * fois - {Array} The features of interest (required). │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ - if (!options.format) { │ │ │ │ - this.format = new OpenLayers.Format.SOSGetFeatureOfInterest( │ │ │ │ - this.formatOptions); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.SLD.v1_0_0_GeoServer │ │ │ │ + * Create a new parser for GeoServer-enhanced SLD version 1.0.0. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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: OpenLayers.Util.applyDefaults({ │ │ │ │ + "sld": OpenLayers.Util.applyDefaults({ │ │ │ │ + "Priority": function(node, obj) { │ │ │ │ + var value = this.readers.ogc._expression.call(this, node); │ │ │ │ + if (value) { │ │ │ │ + obj.priority = value; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "VendorOption": function(node, obj) { │ │ │ │ + if (!obj.vendorOptions) { │ │ │ │ + obj.vendorOptions = {}; │ │ │ │ + } │ │ │ │ + obj.vendorOptions[node.getAttribute("name")] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "TextSymbolizer": function(node, rule) { │ │ │ │ + OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld.TextSymbolizer.apply(this, arguments); │ │ │ │ + var symbolizer = this.multipleSymbolizers ? rule.symbolizers[rule.symbolizers.length - 1] : rule.symbolizer["Text"]; │ │ │ │ + if (symbolizer.graphic === undefined) { │ │ │ │ + symbolizer.graphic = false; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.readers["sld"]) │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.readers), │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Construct a request for reading new sensor positions. This is done by │ │ │ │ - * issuing one GetFeatureOfInterest request. │ │ │ │ - */ │ │ │ │ - read: function(options) { │ │ │ │ - options = OpenLayers.Util.extend({}, options); │ │ │ │ - OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ - var response = new OpenLayers.Protocol.Response({ │ │ │ │ - requestType: "read" │ │ │ │ - }); │ │ │ │ - var format = this.format; │ │ │ │ - var data = OpenLayers.Format.XML.prototype.write.apply(format, │ │ │ │ - [format.writeNode("sos:GetFeatureOfInterest", { │ │ │ │ - fois: this.fois │ │ │ │ - })] │ │ │ │ - ); │ │ │ │ - response.priv = OpenLayers.Request.POST({ │ │ │ │ - url: options.url, │ │ │ │ - callback: this.createCallback(this.handleRead, response, options), │ │ │ │ - data: data │ │ │ │ - }); │ │ │ │ - return response; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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: OpenLayers.Util.applyDefaults({ │ │ │ │ + "sld": OpenLayers.Util.applyDefaults({ │ │ │ │ + "Priority": function(priority) { │ │ │ │ + return this.writers.sld._OGCExpression.call( │ │ │ │ + this, "sld:Priority", priority │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "VendorOption": function(option) { │ │ │ │ + return this.createElementNSPlus("sld:VendorOption", { │ │ │ │ + attributes: { │ │ │ │ + name: option.name │ │ │ │ + }, │ │ │ │ + value: option.value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "TextSymbolizer": function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["TextSymbolizer"].apply(this, arguments); │ │ │ │ + if (symbolizer.graphic !== false && (symbolizer.externalGraphic || symbolizer.graphicName)) { │ │ │ │ + this.writeNode("Graphic", symbolizer, node); │ │ │ │ + } │ │ │ │ + if ("priority" in symbolizer) { │ │ │ │ + this.writeNode("Priority", symbolizer.priority, node); │ │ │ │ + } │ │ │ │ + return this.addVendorOptions(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "PointSymbolizer": function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["PointSymbolizer"].apply(this, arguments); │ │ │ │ + return this.addVendorOptions(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "LineSymbolizer": function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["LineSymbolizer"].apply(this, arguments); │ │ │ │ + return this.addVendorOptions(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "PolygonSymbolizer": function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["PolygonSymbolizer"].apply(this, arguments); │ │ │ │ + return this.addVendorOptions(node, symbolizer); │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.writers["sld"]) │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.writers), │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) { │ │ │ │ - if (options.callback) { │ │ │ │ - var request = response.priv; │ │ │ │ - if (request.status >= 200 && request.status < 300) { │ │ │ │ - // success │ │ │ │ - response.features = this.parseFeatures(request); │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ - } else { │ │ │ │ - // failure │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ + /** │ │ │ │ + * Method: addVendorOptions │ │ │ │ + * Add in the VendorOption tags and return the node again. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} A DOM node. │ │ │ │ + * symbolizer - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A DOM node. │ │ │ │ + */ │ │ │ │ + addVendorOptions: function(node, symbolizer) { │ │ │ │ + var options = symbolizer.vendorOptions; │ │ │ │ + if (options) { │ │ │ │ + for (var key in symbolizer.vendorOptions) { │ │ │ │ + this.writeNode("VendorOption", { │ │ │ │ + name: key, │ │ │ │ + value: symbolizer.vendorOptions[key] │ │ │ │ + }, node); │ │ │ │ + } │ │ │ │ } │ │ │ │ - options.callback.call(options.scope, response); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: parseFeatures │ │ │ │ - * Read HTTP response body and return features │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * request - {XMLHttpRequest} The request object │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array({<OpenLayers.Feature.Vector>})} Array of features │ │ │ │ - */ │ │ │ │ - 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); │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0_GeoServer" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.SOS.v1_0_0" │ │ │ │ -}); │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/WFS/v1.js │ │ │ │ + OpenLayers/Format/WMSDescribeLayer/v1_1.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 │ │ │ │ + * @requires OpenLayers/Format/WMSDescribeLayer.js │ │ │ │ + * @requires OpenLayers/Format/OGCExceptionReport.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.WFS.v1 │ │ │ │ - * Abstract class for for v1.0.0 and v1.1.0 protocol. │ │ │ │ + * Class: OpenLayers.Format.WMSDescribeLayer.v1_1_1 │ │ │ │ + * Read SLD WMS DescribeLayer response for WMS 1.1.X │ │ │ │ + * WMS 1.1.X is tightly coupled to SLD 1.0.0 │ │ │ │ + * │ │ │ │ + * Example DescribeLayer request: │ │ │ │ + * http://demo.opengeo.org/geoserver/wms?request=DescribeLayer&version=1.1.1&layers=topp:states │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol> │ │ │ │ + * - <OpenLayers.Format.WMSDescribeLayer> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ +OpenLayers.Format.WMSDescribeLayer.v1_1_1 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WMSDescribeLayer, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} WFS version number. │ │ │ │ - */ │ │ │ │ - version: null, │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMSDescribeLayer │ │ │ │ + * Create a new parser for WMS DescribeLayer responses. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.WMSDescribeLayer.prototype.initialize.apply(this, │ │ │ │ + [options]); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: srsName │ │ │ │ - * {String} Name of spatial reference system. Default is "EPSG:4326". │ │ │ │ - */ │ │ │ │ - srsName: "EPSG:4326", │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read DescribeLayer data from a string, and return the response. │ │ │ │ + * The OGC defines 2 formats which are allowed for output, │ │ │ │ + * so we need to parse these 2 types for version 1.1.X │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} Object with a layerDescriptions property, which holds an Array │ │ │ │ + * of {<LayerDescription>} objects which have: │ │ │ │ + * - {String} owsType: WFS/WCS │ │ │ │ + * - {String} owsURL: the online resource │ │ │ │ + * - {String} typeName: the name of the typename on the owsType service │ │ │ │ + * - {String} layerName: the name of the WMS layer we did a lookup for │ │ │ │ + */ │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ + } │ │ │ │ + var root = data.documentElement; │ │ │ │ + var children = root.childNodes; │ │ │ │ + var describelayer = { │ │ │ │ + layerDescriptions: [] │ │ │ │ + }; │ │ │ │ + var childNode, nodeName; │ │ │ │ + for (var i = 0; i < children.length; ++i) { │ │ │ │ + childNode = children[i]; │ │ │ │ + nodeName = childNode.nodeName; │ │ │ │ + if (nodeName == 'LayerDescription') { │ │ │ │ + var layerName = childNode.getAttribute('name'); │ │ │ │ + var owsType = ''; │ │ │ │ + var owsURL = ''; │ │ │ │ + var typeName = ''; │ │ │ │ + // check for owsType and owsURL attributes │ │ │ │ + if (childNode.getAttribute('owsType')) { │ │ │ │ + owsType = childNode.getAttribute('owsType'); │ │ │ │ + owsURL = childNode.getAttribute('owsURL'); │ │ │ │ + } else { │ │ │ │ + // look for wfs or wcs attribute │ │ │ │ + if (childNode.getAttribute('wfs') != '') { │ │ │ │ + owsType = 'WFS'; │ │ │ │ + owsURL = childNode.getAttribute('wfs'); │ │ │ │ + } else if (childNode.getAttribute('wcs') != '') { │ │ │ │ + owsType = 'WCS'; │ │ │ │ + owsURL = childNode.getAttribute('wcs'); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + // look for Query child │ │ │ │ + var query = childNode.getElementsByTagName('Query'); │ │ │ │ + if (query.length > 0) { │ │ │ │ + typeName = query[0].getAttribute('typeName'); │ │ │ │ + if (!typeName) { │ │ │ │ + // because of Ionic bug │ │ │ │ + typeName = query[0].getAttribute('typename'); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var layerDescription = { │ │ │ │ + layerName: layerName, │ │ │ │ + owsType: owsType, │ │ │ │ + owsURL: owsURL, │ │ │ │ + typeName: typeName │ │ │ │ + }; │ │ │ │ + describelayer.layerDescriptions.push(layerDescription); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: featureType │ │ │ │ - * {String} Local feature typeName. │ │ │ │ - */ │ │ │ │ - featureType: null, │ │ │ │ + //TODO do this in deprecated.js instead: │ │ │ │ + // array style index for backwards compatibility │ │ │ │ + describelayer.length = describelayer.layerDescriptions.length; │ │ │ │ + describelayer[describelayer.length - 1] = layerDescription; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: featureNS │ │ │ │ - * {String} Feature namespace. │ │ │ │ - */ │ │ │ │ - featureNS: null, │ │ │ │ + } else if (nodeName == 'ServiceException') { │ │ │ │ + // an exception must have occurred, so parse it │ │ │ │ + var parser = new OpenLayers.Format.OGCExceptionReport(); │ │ │ │ + return { │ │ │ │ + error: parser.read(data) │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return describelayer; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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", │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer.v1_1_1" │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ +// Version alias - workaround for http://trac.osgeo.org/mapserver/ticket/2257 │ │ │ │ +OpenLayers.Format.WMSDescribeLayer.v1_1_0 = │ │ │ │ + OpenLayers.Format.WMSDescribeLayer.v1_1_1; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WMTSCapabilities/v1_0_0.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: featurePrefix │ │ │ │ - * {String} Namespace alias for feature type. Default is "feature". │ │ │ │ - */ │ │ │ │ - featurePrefix: "feature", │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/WMTSCapabilities.js │ │ │ │ + * @requires OpenLayers/Format/OWSCommon/v1_1_0.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WMTSCapabilities.v1_0_0 │ │ │ │ + * Read WMTS Capabilities version 1.0.0. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.WMTSCapabilities> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WMTSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.OWSCommon.v1_1_0, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: readOptions │ │ │ │ - * {Object} Optional object to pass to format's read. │ │ │ │ - */ │ │ │ │ - readOptions: null, │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} The parser version ("1.0.0"). │ │ │ │ + */ │ │ │ │ + version: "1.0.0", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + */ │ │ │ │ + namespaces: { │ │ │ │ + ows: "http://www.opengis.net/ows/1.1", │ │ │ │ + wmts: "http://www.opengis.net/wmts/1.0", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink" │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: yx │ │ │ │ + * {Object} Members in the yx object are used to determine if a CRS URN │ │ │ │ + * corresponds to a CRS with y,x axis order. Member names are CRS URNs │ │ │ │ + * and values are boolean. Defaults come from the │ │ │ │ + * <OpenLayers.Format.WMTSCapabilities> prototype. │ │ │ │ + */ │ │ │ │ + yx: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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" │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * Property: defaultPrefix │ │ │ │ + * {String} The default namespace alias for creating element nodes. │ │ │ │ + */ │ │ │ │ + defaultPrefix: "wmts", │ │ │ │ │ │ │ │ - var data = OpenLayers.Format.XML.prototype.write.apply( │ │ │ │ - this.format, [this.format.writeNode("wfs:GetFeature", options)] │ │ │ │ - ); │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMTSCapabilities.v1_0_0 │ │ │ │ + * Create a new parser for WMTS capabilities version 1.0.0. │ │ │ │ + * │ │ │ │ + * 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]); │ │ │ │ + this.options = options; │ │ │ │ + var yx = OpenLayers.Util.extend({}, OpenLayers.Format.WMTSCapabilities.prototype.yx); │ │ │ │ + this.yx = OpenLayers.Util.extend(yx, this.yx); │ │ │ │ + }, │ │ │ │ │ │ │ │ - response.priv = OpenLayers.Request.POST({ │ │ │ │ - url: options.url, │ │ │ │ - callback: this.createCallback(this.handleRead, response, options), │ │ │ │ - params: options.params, │ │ │ │ - headers: options.headers, │ │ │ │ - data: data │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return info about the WMTS. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} Information about the SOS service. │ │ │ │ + */ │ │ │ │ + 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 capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + capabilities.version = this.version; │ │ │ │ + return capabilities; │ │ │ │ + }, │ │ │ │ │ │ │ │ - return response; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wmts": { │ │ │ │ + "Capabilities": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "Contents": function(node, obj) { │ │ │ │ + obj.contents = {}; │ │ │ │ + obj.contents.layers = []; │ │ │ │ + obj.contents.tileMatrixSets = {}; │ │ │ │ + this.readChildNodes(node, obj.contents); │ │ │ │ + }, │ │ │ │ + "Layer": function(node, obj) { │ │ │ │ + var layer = { │ │ │ │ + styles: [], │ │ │ │ + formats: [], │ │ │ │ + dimensions: [], │ │ │ │ + tileMatrixSetLinks: [] │ │ │ │ + }; │ │ │ │ + layer.layers = []; │ │ │ │ + this.readChildNodes(node, layer); │ │ │ │ + obj.layers.push(layer); │ │ │ │ + }, │ │ │ │ + "Style": function(node, obj) { │ │ │ │ + var style = {}; │ │ │ │ + style.isDefault = (node.getAttribute("isDefault") === "true"); │ │ │ │ + this.readChildNodes(node, style); │ │ │ │ + obj.styles.push(style); │ │ │ │ + }, │ │ │ │ + "Format": function(node, obj) { │ │ │ │ + obj.formats.push(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "TileMatrixSetLink": function(node, obj) { │ │ │ │ + var tileMatrixSetLink = {}; │ │ │ │ + this.readChildNodes(node, tileMatrixSetLink); │ │ │ │ + obj.tileMatrixSetLinks.push(tileMatrixSetLink); │ │ │ │ + }, │ │ │ │ + "TileMatrixSet": function(node, obj) { │ │ │ │ + // node could be child of wmts:Contents or wmts:TileMatrixSetLink │ │ │ │ + // duck type wmts:Contents by looking for layers │ │ │ │ + if (obj.layers) { │ │ │ │ + // TileMatrixSet as object type in schema │ │ │ │ + var tileMatrixSet = { │ │ │ │ + matrixIds: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, tileMatrixSet); │ │ │ │ + obj.tileMatrixSets[tileMatrixSet.identifier] = tileMatrixSet; │ │ │ │ + } else { │ │ │ │ + // TileMatrixSet as string type in schema │ │ │ │ + obj.tileMatrixSet = this.getChildValue(node); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "TileMatrix": function(node, obj) { │ │ │ │ + var tileMatrix = { │ │ │ │ + supportedCRS: obj.supportedCRS │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, tileMatrix); │ │ │ │ + obj.matrixIds.push(tileMatrix); │ │ │ │ + }, │ │ │ │ + "ScaleDenominator": function(node, obj) { │ │ │ │ + obj.scaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "TopLeftCorner": function(node, obj) { │ │ │ │ + var topLeftCorner = this.getChildValue(node); │ │ │ │ + var coords = topLeftCorner.split(" "); │ │ │ │ + // decide on axis order for the given CRS │ │ │ │ + var yx; │ │ │ │ + if (obj.supportedCRS) { │ │ │ │ + // extract out version from URN │ │ │ │ + var crs = obj.supportedCRS.replace( │ │ │ │ + /urn:ogc:def:crs:(\w+):.+:(\w+)$/, │ │ │ │ + "urn:ogc:def:crs:$1::$2" │ │ │ │ + ); │ │ │ │ + yx = !!this.yx[crs]; │ │ │ │ + } │ │ │ │ + if (yx) { │ │ │ │ + obj.topLeftCorner = new OpenLayers.LonLat( │ │ │ │ + coords[1], coords[0] │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + obj.topLeftCorner = new OpenLayers.LonLat( │ │ │ │ + coords[0], coords[1] │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "TileWidth": function(node, obj) { │ │ │ │ + obj.tileWidth = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "TileHeight": function(node, obj) { │ │ │ │ + obj.tileHeight = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "MatrixWidth": function(node, obj) { │ │ │ │ + obj.matrixWidth = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "MatrixHeight": function(node, obj) { │ │ │ │ + obj.matrixHeight = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "ResourceURL": function(node, obj) { │ │ │ │ + obj.resourceUrl = obj.resourceUrl || {}; │ │ │ │ + var resourceType = node.getAttribute("resourceType"); │ │ │ │ + if (!obj.resourceUrls) { │ │ │ │ + obj.resourceUrls = []; │ │ │ │ + } │ │ │ │ + var resourceUrl = obj.resourceUrl[resourceType] = { │ │ │ │ + format: node.getAttribute("format"), │ │ │ │ + template: node.getAttribute("template"), │ │ │ │ + resourceType: resourceType │ │ │ │ + }; │ │ │ │ + obj.resourceUrls.push(resourceUrl); │ │ │ │ + }, │ │ │ │ + // not used for now, can be added in the future though │ │ │ │ + /*"Themes": function(node, obj) { │ │ │ │ + obj.themes = []; │ │ │ │ + this.readChildNodes(node, obj.themes); │ │ │ │ + }, │ │ │ │ + "Theme": function(node, obj) { │ │ │ │ + var theme = {}; │ │ │ │ + this.readChildNodes(node, theme); │ │ │ │ + obj.push(theme); │ │ │ │ + },*/ │ │ │ │ + "WSDL": function(node, obj) { │ │ │ │ + obj.wsdl = {}; │ │ │ │ + obj.wsdl.href = node.getAttribute("xlink:href"); │ │ │ │ + // TODO: other attributes of <WSDL> element │ │ │ │ + }, │ │ │ │ + "ServiceMetadataURL": function(node, obj) { │ │ │ │ + obj.serviceMetadataUrl = {}; │ │ │ │ + obj.serviceMetadataUrl.href = node.getAttribute("xlink:href"); │ │ │ │ + // TODO: other attributes of <ServiceMetadataURL> element │ │ │ │ + }, │ │ │ │ + "LegendURL": function(node, obj) { │ │ │ │ + obj.legend = {}; │ │ │ │ + obj.legend.href = node.getAttribute("xlink:href"); │ │ │ │ + obj.legend.format = node.getAttribute("format"); │ │ │ │ + }, │ │ │ │ + "Dimension": function(node, obj) { │ │ │ │ + var dimension = { │ │ │ │ + values: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, dimension); │ │ │ │ + obj.dimensions.push(dimension); │ │ │ │ + }, │ │ │ │ + "Default": function(node, obj) { │ │ │ │ + obj["default"] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Value": function(node, obj) { │ │ │ │ + obj.values.push(this.getChildValue(node)); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMTSCapabilities.v1_0_0" │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - }, │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WMSCapabilities/v1.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - 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); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/WMSCapabilities.js │ │ │ │ + * @requires OpenLayers/Format/OGCExceptionReport.js │ │ │ │ + * @requires OpenLayers/Format/XML.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WMSCapabilities.v1 │ │ │ │ + * Abstract class not to be instantiated directly. Creates │ │ │ │ + * the common parts for both WMS 1.1.X and WMS 1.3.X. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.XML, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + */ │ │ │ │ + namespaces: { │ │ │ │ + wms: "http://www.opengis.net/wms", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: defaultPrefix │ │ │ │ + */ │ │ │ │ + defaultPrefix: "wms", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMSCapabilities.v1 │ │ │ │ + * Create an instance of one of the subclasses. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return a list of layers. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array} List of named layers. │ │ │ │ + */ │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ + } │ │ │ │ + var raw = data; │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement; │ │ │ │ + } │ │ │ │ + var capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + if (capabilities.service === undefined) { │ │ │ │ + // an exception must have occurred, so parse it │ │ │ │ + var parser = new OpenLayers.Format.OGCExceptionReport(); │ │ │ │ + capabilities.error = parser.read(raw); │ │ │ │ + } │ │ │ │ + return capabilities; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wms": { │ │ │ │ + "Service": function(node, obj) { │ │ │ │ + obj.service = {}; │ │ │ │ + this.readChildNodes(node, obj.service); │ │ │ │ + }, │ │ │ │ + "Name": function(node, obj) { │ │ │ │ + obj.name = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Title": function(node, obj) { │ │ │ │ + obj.title = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Abstract": function(node, obj) { │ │ │ │ + obj["abstract"] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "BoundingBox": function(node, obj) { │ │ │ │ + var bbox = {}; │ │ │ │ + bbox.bbox = [ │ │ │ │ + parseFloat(node.getAttribute("minx")), │ │ │ │ + parseFloat(node.getAttribute("miny")), │ │ │ │ + parseFloat(node.getAttribute("maxx")), │ │ │ │ + parseFloat(node.getAttribute("maxy")) │ │ │ │ + ]; │ │ │ │ + var res = { │ │ │ │ + x: parseFloat(node.getAttribute("resx")), │ │ │ │ + y: parseFloat(node.getAttribute("resy")) │ │ │ │ + }; │ │ │ │ + │ │ │ │ + if (!(isNaN(res.x) && isNaN(res.y))) { │ │ │ │ + bbox.res = res; │ │ │ │ + } │ │ │ │ + // return the bbox so that descendant classes can set the │ │ │ │ + // CRS and SRS and add it to the obj │ │ │ │ + return bbox; │ │ │ │ + }, │ │ │ │ + "OnlineResource": function(node, obj) { │ │ │ │ + obj.href = this.getAttributeNS(node, this.namespaces.xlink, │ │ │ │ + "href"); │ │ │ │ + }, │ │ │ │ + "ContactInformation": function(node, obj) { │ │ │ │ + obj.contactInformation = {}; │ │ │ │ + this.readChildNodes(node, obj.contactInformation); │ │ │ │ + }, │ │ │ │ + "ContactPersonPrimary": function(node, obj) { │ │ │ │ + obj.personPrimary = {}; │ │ │ │ + this.readChildNodes(node, obj.personPrimary); │ │ │ │ + }, │ │ │ │ + "ContactPerson": function(node, obj) { │ │ │ │ + obj.person = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ContactOrganization": function(node, obj) { │ │ │ │ + obj.organization = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ContactPosition": function(node, obj) { │ │ │ │ + obj.position = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ContactAddress": function(node, obj) { │ │ │ │ + obj.contactAddress = {}; │ │ │ │ + this.readChildNodes(node, obj.contactAddress); │ │ │ │ + }, │ │ │ │ + "AddressType": function(node, obj) { │ │ │ │ + obj.type = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Address": function(node, obj) { │ │ │ │ + obj.address = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "City": function(node, obj) { │ │ │ │ + obj.city = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "StateOrProvince": function(node, obj) { │ │ │ │ + obj.stateOrProvince = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "PostCode": function(node, obj) { │ │ │ │ + obj.postcode = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Country": function(node, obj) { │ │ │ │ + obj.country = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ContactVoiceTelephone": function(node, obj) { │ │ │ │ + obj.phone = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ContactFacsimileTelephone": function(node, obj) { │ │ │ │ + obj.fax = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ContactElectronicMailAddress": function(node, obj) { │ │ │ │ + obj.email = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Fees": function(node, obj) { │ │ │ │ + var fees = this.getChildValue(node); │ │ │ │ + if (fees && fees.toLowerCase() != "none") { │ │ │ │ + obj.fees = fees; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "AccessConstraints": function(node, obj) { │ │ │ │ + var constraints = this.getChildValue(node); │ │ │ │ + if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ + obj.accessConstraints = constraints; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Capability": function(node, obj) { │ │ │ │ + obj.capability = { │ │ │ │ + nestedLayers: [], │ │ │ │ + layers: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.capability); │ │ │ │ + }, │ │ │ │ + "Request": function(node, obj) { │ │ │ │ + obj.request = {}; │ │ │ │ + this.readChildNodes(node, obj.request); │ │ │ │ + }, │ │ │ │ + "GetCapabilities": function(node, obj) { │ │ │ │ + obj.getcapabilities = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getcapabilities); │ │ │ │ + }, │ │ │ │ + "Format": function(node, obj) { │ │ │ │ + if (OpenLayers.Util.isArray(obj.formats)) { │ │ │ │ + obj.formats.push(this.getChildValue(node)); │ │ │ │ } else { │ │ │ │ - response.features = result; │ │ │ │ + obj.format = this.getChildValue(node); │ │ │ │ } │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ - } else { │ │ │ │ - // failure (service exception) │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ - response.error = result; │ │ │ │ + }, │ │ │ │ + "DCPType": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "HTTP": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "Get": function(node, obj) { │ │ │ │ + obj.get = {}; │ │ │ │ + this.readChildNodes(node, obj.get); │ │ │ │ + // backwards compatibility │ │ │ │ + if (!obj.href) { │ │ │ │ + obj.href = obj.get.href; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Post": function(node, obj) { │ │ │ │ + obj.post = {}; │ │ │ │ + this.readChildNodes(node, obj.post); │ │ │ │ + // backwards compatibility │ │ │ │ + if (!obj.href) { │ │ │ │ + obj.href = obj.get.href; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "GetMap": function(node, obj) { │ │ │ │ + obj.getmap = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getmap); │ │ │ │ + }, │ │ │ │ + "GetFeatureInfo": function(node, obj) { │ │ │ │ + obj.getfeatureinfo = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getfeatureinfo); │ │ │ │ + }, │ │ │ │ + "Exception": function(node, obj) { │ │ │ │ + obj.exception = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.exception); │ │ │ │ + }, │ │ │ │ + "Layer": function(node, obj) { │ │ │ │ + var parentLayer, capability; │ │ │ │ + if (obj.capability) { │ │ │ │ + capability = obj.capability; │ │ │ │ + parentLayer = obj; │ │ │ │ + } else { │ │ │ │ + capability = obj; │ │ │ │ + } │ │ │ │ + var attrNode = node.getAttributeNode("queryable"); │ │ │ │ + var queryable = (attrNode && attrNode.specified) ? │ │ │ │ + node.getAttribute("queryable") : null; │ │ │ │ + attrNode = node.getAttributeNode("cascaded"); │ │ │ │ + var cascaded = (attrNode && attrNode.specified) ? │ │ │ │ + node.getAttribute("cascaded") : null; │ │ │ │ + attrNode = node.getAttributeNode("opaque"); │ │ │ │ + var opaque = (attrNode && attrNode.specified) ? │ │ │ │ + node.getAttribute('opaque') : null; │ │ │ │ + var noSubsets = node.getAttribute('noSubsets'); │ │ │ │ + var fixedWidth = node.getAttribute('fixedWidth'); │ │ │ │ + var fixedHeight = node.getAttribute('fixedHeight'); │ │ │ │ + var parent = parentLayer || {}, │ │ │ │ + extend = OpenLayers.Util.extend; │ │ │ │ + var layer = { │ │ │ │ + nestedLayers: [], │ │ │ │ + styles: parentLayer ? [].concat(parentLayer.styles) : [], │ │ │ │ + srs: parentLayer ? extend({}, parent.srs) : {}, │ │ │ │ + metadataURLs: [], │ │ │ │ + bbox: parentLayer ? extend({}, parent.bbox) : {}, │ │ │ │ + llbbox: parent.llbbox, │ │ │ │ + dimensions: parentLayer ? extend({}, parent.dimensions) : {}, │ │ │ │ + authorityURLs: parentLayer ? extend({}, parent.authorityURLs) : {}, │ │ │ │ + identifiers: {}, │ │ │ │ + keywords: [], │ │ │ │ + queryable: (queryable && queryable !== "") ? │ │ │ │ + (queryable === "1" || queryable === "true") : (parent.queryable || false), │ │ │ │ + cascaded: (cascaded !== null) ? parseInt(cascaded) : (parent.cascaded || 0), │ │ │ │ + opaque: opaque ? │ │ │ │ + (opaque === "1" || opaque === "true") : (parent.opaque || false), │ │ │ │ + noSubsets: (noSubsets !== null) ? │ │ │ │ + (noSubsets === "1" || noSubsets === "true") : (parent.noSubsets || false), │ │ │ │ + fixedWidth: (fixedWidth != null) ? │ │ │ │ + parseInt(fixedWidth) : (parent.fixedWidth || 0), │ │ │ │ + fixedHeight: (fixedHeight != null) ? │ │ │ │ + parseInt(fixedHeight) : (parent.fixedHeight || 0), │ │ │ │ + minScale: parent.minScale, │ │ │ │ + maxScale: parent.maxScale, │ │ │ │ + attribution: parent.attribution │ │ │ │ + }; │ │ │ │ + obj.nestedLayers.push(layer); │ │ │ │ + layer.capability = capability; │ │ │ │ + this.readChildNodes(node, layer); │ │ │ │ + delete layer.capability; │ │ │ │ + if (layer.name) { │ │ │ │ + var parts = layer.name.split(":"), │ │ │ │ + request = capability.request, │ │ │ │ + gfi = request.getfeatureinfo; │ │ │ │ + if (parts.length > 0) { │ │ │ │ + layer.prefix = parts[0]; │ │ │ │ + } │ │ │ │ + capability.layers.push(layer); │ │ │ │ + if (layer.formats === undefined) { │ │ │ │ + layer.formats = request.getmap.formats; │ │ │ │ + } │ │ │ │ + if (layer.infoFormats === undefined && gfi) { │ │ │ │ + layer.infoFormats = gfi.formats; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Attribution": function(node, obj) { │ │ │ │ + obj.attribution = {}; │ │ │ │ + this.readChildNodes(node, obj.attribution); │ │ │ │ + }, │ │ │ │ + "LogoURL": function(node, obj) { │ │ │ │ + obj.logo = { │ │ │ │ + width: node.getAttribute("width"), │ │ │ │ + height: node.getAttribute("height") │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.logo); │ │ │ │ + }, │ │ │ │ + "Style": function(node, obj) { │ │ │ │ + var style = {}; │ │ │ │ + obj.styles.push(style); │ │ │ │ + this.readChildNodes(node, style); │ │ │ │ + }, │ │ │ │ + "LegendURL": function(node, obj) { │ │ │ │ + var legend = { │ │ │ │ + width: node.getAttribute("width"), │ │ │ │ + height: node.getAttribute("height") │ │ │ │ + }; │ │ │ │ + obj.legend = legend; │ │ │ │ + this.readChildNodes(node, legend); │ │ │ │ + }, │ │ │ │ + "MetadataURL": function(node, obj) { │ │ │ │ + var metadataURL = { │ │ │ │ + type: node.getAttribute("type") │ │ │ │ + }; │ │ │ │ + obj.metadataURLs.push(metadataURL); │ │ │ │ + this.readChildNodes(node, metadataURL); │ │ │ │ + }, │ │ │ │ + "DataURL": function(node, obj) { │ │ │ │ + obj.dataURL = {}; │ │ │ │ + this.readChildNodes(node, obj.dataURL); │ │ │ │ + }, │ │ │ │ + "FeatureListURL": function(node, obj) { │ │ │ │ + obj.featureListURL = {}; │ │ │ │ + this.readChildNodes(node, obj.featureListURL); │ │ │ │ + }, │ │ │ │ + "AuthorityURL": function(node, obj) { │ │ │ │ + var name = node.getAttribute("name"); │ │ │ │ + var authority = {}; │ │ │ │ + this.readChildNodes(node, authority); │ │ │ │ + obj.authorityURLs[name] = authority.href; │ │ │ │ + }, │ │ │ │ + "Identifier": function(node, obj) { │ │ │ │ + var authority = node.getAttribute("authority"); │ │ │ │ + obj.identifiers[authority] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "KeywordList": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "SRS": function(node, obj) { │ │ │ │ + obj.srs[this.getChildValue(node)] = true; │ │ │ │ } │ │ │ │ - } 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; │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1" │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) { │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WMSCapabilities/v1_1.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - options = OpenLayers.Util.extend({}, options); │ │ │ │ - OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ +/* 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 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) │ │ │ │ - }); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/WMSCapabilities/v1.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - return response; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WMSCapabilities.v1_1 │ │ │ │ + * Abstract class not to be instantiated directly. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.WMSCapabilities.v1> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ + "WMT_MS_Capabilities": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "Keyword": function(node, obj) { │ │ │ │ + if (obj.keywords) { │ │ │ │ + obj.keywords.push(this.getChildValue(node)); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "DescribeLayer": function(node, obj) { │ │ │ │ + obj.describelayer = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.describelayer); │ │ │ │ + }, │ │ │ │ + "GetLegendGraphic": function(node, obj) { │ │ │ │ + obj.getlegendgraphic = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getlegendgraphic); │ │ │ │ + }, │ │ │ │ + "GetStyles": function(node, obj) { │ │ │ │ + obj.getstyles = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getstyles); │ │ │ │ + }, │ │ │ │ + "PutStyles": function(node, obj) { │ │ │ │ + obj.putstyles = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.putstyles); │ │ │ │ + }, │ │ │ │ + "UserDefinedSymbolization": function(node, obj) { │ │ │ │ + var userSymbols = { │ │ │ │ + supportSLD: parseInt(node.getAttribute("SupportSLD")) == 1, │ │ │ │ + userLayer: parseInt(node.getAttribute("UserLayer")) == 1, │ │ │ │ + userStyle: parseInt(node.getAttribute("UserStyle")) == 1, │ │ │ │ + remoteWFS: parseInt(node.getAttribute("RemoteWFS")) == 1 │ │ │ │ + }; │ │ │ │ + obj.userSymbols = userSymbols; │ │ │ │ + }, │ │ │ │ + "LatLonBoundingBox": function(node, obj) { │ │ │ │ + obj.llbbox = [ │ │ │ │ + parseFloat(node.getAttribute("minx")), │ │ │ │ + parseFloat(node.getAttribute("miny")), │ │ │ │ + parseFloat(node.getAttribute("maxx")), │ │ │ │ + parseFloat(node.getAttribute("maxy")) │ │ │ │ + ]; │ │ │ │ + }, │ │ │ │ + "BoundingBox": function(node, obj) { │ │ │ │ + var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ + bbox.srs = node.getAttribute("SRS"); │ │ │ │ + obj.bbox[bbox.srs] = bbox; │ │ │ │ + }, │ │ │ │ + "ScaleHint": function(node, obj) { │ │ │ │ + var min = node.getAttribute("min"); │ │ │ │ + var max = node.getAttribute("max"); │ │ │ │ + var rad2 = Math.pow(2, 0.5); │ │ │ │ + var ipm = OpenLayers.INCHES_PER_UNIT["m"]; │ │ │ │ + if (min != 0) { │ │ │ │ + obj.maxScale = parseFloat( │ │ │ │ + ((min / rad2) * ipm * │ │ │ │ + OpenLayers.DOTS_PER_INCH).toPrecision(13) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (max != Number.POSITIVE_INFINITY) { │ │ │ │ + obj.minScale = parseFloat( │ │ │ │ + ((max / rad2) * ipm * │ │ │ │ + OpenLayers.DOTS_PER_INCH).toPrecision(13) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Dimension": function(node, obj) { │ │ │ │ + var name = node.getAttribute("name").toLowerCase(); │ │ │ │ + var dim = { │ │ │ │ + name: name, │ │ │ │ + units: node.getAttribute("units"), │ │ │ │ + unitsymbol: node.getAttribute("unitSymbol") │ │ │ │ + }; │ │ │ │ + obj.dimensions[dim.name] = dim; │ │ │ │ + }, │ │ │ │ + "Extent": function(node, obj) { │ │ │ │ + var name = node.getAttribute("name").toLowerCase(); │ │ │ │ + if (name in obj["dimensions"]) { │ │ │ │ + var extent = obj.dimensions[name]; │ │ │ │ + extent.nearestVal = │ │ │ │ + node.getAttribute("nearestValue") === "1"; │ │ │ │ + extent.multipleVal = │ │ │ │ + node.getAttribute("multipleValues") === "1"; │ │ │ │ + extent.current = node.getAttribute("current") === "1"; │ │ │ │ + extent["default"] = node.getAttribute("default") || ""; │ │ │ │ + var values = this.getChildValue(node); │ │ │ │ + extent.values = values.split(","); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]) │ │ │ │ + }, │ │ │ │ │ │ │ │ - // ensure that we have an xml doc │ │ │ │ - var data = request.responseXML; │ │ │ │ - if (!data || !data.documentElement) { │ │ │ │ - data = request.responseText; │ │ │ │ - } │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1" │ │ │ │ │ │ │ │ - var obj = this.format.read(data) || {}; │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WMSCapabilities/v1_1_1.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/WMSCapabilities/v1_1.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - var response = new OpenLayers.Protocol.Response({ │ │ │ │ - requestType: "commit" │ │ │ │ - }); │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WMSCapabilities/v1_1_1 │ │ │ │ + * Read WMS Capabilities version 1.1.1. │ │ │ │ + * │ │ │ │ + * Note on <ScaleHint> parsing: If the 'min' attribute is set to "0", no │ │ │ │ + * maxScale will be set on the layer object. If the 'max' attribute is set to │ │ │ │ + * "Infinity", no minScale will be set. This makes it easy to create proper │ │ │ │ + * {<OpenLayers.Layer.WMS>} configurations directly from the layer object │ │ │ │ + * literals returned by this format, because no minScale/maxScale modifications │ │ │ │ + * need to be made. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.WMSCapabilities.v1_1> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1_1 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ │ │ │ │ - var root = this.format.createElementNSPlus("wfs:Transaction", { │ │ │ │ - attributes: { │ │ │ │ - service: "WFS", │ │ │ │ - version: this.version │ │ │ │ - } │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} The specific parser version. │ │ │ │ + */ │ │ │ │ + version: "1.1.1", │ │ │ │ │ │ │ │ - var deleteNode = this.format.createElementNSPlus("wfs:Delete", { │ │ │ │ - attributes: { │ │ │ │ - typeName: (options.featureNS ? this.featurePrefix + ":" : "") + │ │ │ │ - options.featureType │ │ │ │ - } │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_1 │ │ │ │ + * Create a new parser for WMS capabilities version 1.1.1. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (options.featureNS) { │ │ │ │ - deleteNode.setAttribute("xmlns:" + this.featurePrefix, options.featureNS); │ │ │ │ - } │ │ │ │ - var filterNode = this.format.writeNode("ogc:Filter", 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: { │ │ │ │ + "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ + "SRS": function(node, obj) { │ │ │ │ + obj.srs[this.getChildValue(node)] = true; │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ + }, │ │ │ │ │ │ │ │ - deleteNode.appendChild(filterNode); │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1" │ │ │ │ │ │ │ │ - root.appendChild(deleteNode); │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WMSCapabilities/v1_1_1_WMSC.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - var data = OpenLayers.Format.XML.prototype.write.apply( │ │ │ │ - this.format, [root] │ │ │ │ - ); │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - return OpenLayers.Request.POST({ │ │ │ │ - url: this.url, │ │ │ │ - callback: options.callback || function() {}, │ │ │ │ - data: data │ │ │ │ - }); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/WMSCapabilities/v1_1_1.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WMSCapabilities/v1_1_1_WMSC │ │ │ │ + * Read WMS-C Capabilities version 1.1.1. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.WMSCapabilities.v1_1_1> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WMSCapabilities.v1_1_1, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} The specific parser version. │ │ │ │ + */ │ │ │ │ + version: "1.1.1", │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.WFS.v1" │ │ │ │ -}); │ │ │ │ + /** │ │ │ │ + * Property: profile │ │ │ │ + * {String} The specific profile │ │ │ │ + */ │ │ │ │ + profile: "WMSC", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_1 │ │ │ │ + * Create a new parser for WMS-C capabilities version 1.1.1. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ + "VendorSpecificCapabilities": function(node, obj) { │ │ │ │ + obj.vendorSpecific = { │ │ │ │ + tileSets: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.vendorSpecific); │ │ │ │ + }, │ │ │ │ + "TileSet": function(node, vendorSpecific) { │ │ │ │ + var tileset = { │ │ │ │ + srs: {}, │ │ │ │ + bbox: {}, │ │ │ │ + resolutions: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, tileset); │ │ │ │ + vendorSpecific.tileSets.push(tileset); │ │ │ │ + }, │ │ │ │ + "Resolutions": function(node, tileset) { │ │ │ │ + var res = this.getChildValue(node).split(" "); │ │ │ │ + for (var i = 0, len = res.length; i < len; i++) { │ │ │ │ + if (res[i] != "") { │ │ │ │ + tileset.resolutions.push(parseFloat(res[i])); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Width": function(node, tileset) { │ │ │ │ + tileset.width = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "Height": function(node, tileset) { │ │ │ │ + tileset.height = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "Layers": function(node, tileset) { │ │ │ │ + tileset.layers = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Styles": function(node, tileset) { │ │ │ │ + tileset.styles = this.getChildValue(node); │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1_1_1.prototype.readers["wms"]) │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC" │ │ │ │ + │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/WFS/v1_1_0.js │ │ │ │ + OpenLayers/Format/WMSCapabilities/v1_3.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_1_0.js │ │ │ │ + * @requires OpenLayers/Format/WMSCapabilities/v1.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.WFS.v1_1_0 │ │ │ │ - * A WFS v1.1.0 protocol for vector layers. Create a new instance with the │ │ │ │ - * <OpenLayers.Protocol.WFS.v1_1_0> constructor. │ │ │ │ - * │ │ │ │ - * Differences from the v1.0.0 protocol: │ │ │ │ - * - uses Filter Encoding 1.1.0 instead of 1.0.0 │ │ │ │ - * - uses GML 3 instead of 2 if no format is provided │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.WMSCapabilities/v1_3 │ │ │ │ + * Abstract base class for WMS Capabilities version 1.3.X. │ │ │ │ + * SLD 1.1.0 adds in the extra operations DescribeLayer and GetLegendGraphic, │ │ │ │ + * see: http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol.WFS.v1> │ │ │ │ + * - <OpenLayers.Format.WMSCapabilities.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol.WFS.v1_1_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_3 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} WFS version number. │ │ │ │ - */ │ │ │ │ - version: "1.1.0", │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ + "WMS_Capabilities": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "LayerLimit": function(node, obj) { │ │ │ │ + obj.layerLimit = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "MaxWidth": function(node, obj) { │ │ │ │ + obj.maxWidth = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "MaxHeight": function(node, obj) { │ │ │ │ + obj.maxHeight = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "BoundingBox": function(node, obj) { │ │ │ │ + var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ + bbox.srs = node.getAttribute("CRS"); │ │ │ │ + obj.bbox[bbox.srs] = bbox; │ │ │ │ + }, │ │ │ │ + "CRS": function(node, obj) { │ │ │ │ + // CRS is the synonym of SRS │ │ │ │ + this.readers.wms.SRS.apply(this, [node, obj]); │ │ │ │ + }, │ │ │ │ + "EX_GeographicBoundingBox": function(node, obj) { │ │ │ │ + // replacement of LatLonBoundingBox │ │ │ │ + obj.llbbox = []; │ │ │ │ + this.readChildNodes(node, obj.llbbox); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Protocol.WFS.v1_1_0 │ │ │ │ - * A class for giving layers WFS v1.1.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'. │ │ │ │ - * outputFormat - {String} Optional output format to use for WFS GetFeature │ │ │ │ - * requests. This can be any format advertized by the WFS's │ │ │ │ - * GetCapabilities response. If set, an appropriate readFormat also │ │ │ │ - * has to be provided, unless outputFormat is GML3, GML2 or JSON. │ │ │ │ - * readFormat - {<OpenLayers.Format>} An appropriate format parser if │ │ │ │ - * outputFormat is none of GML3, GML2 or JSON. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Protocol.WFS.v1.prototype.initialize.apply(this, arguments); │ │ │ │ - if (this.outputFormat && !this.readFormat) { │ │ │ │ - if (this.outputFormat.toLowerCase() == "gml2") { │ │ │ │ - this.readFormat = new OpenLayers.Format.GML.v2({ │ │ │ │ - featureType: this.featureType, │ │ │ │ - featureNS: this.featureNS, │ │ │ │ - geometryName: this.geometryName │ │ │ │ - }); │ │ │ │ - } else if (this.outputFormat.toLowerCase() == "json") { │ │ │ │ - this.readFormat = new OpenLayers.Format.GeoJSON(); │ │ │ │ + }, │ │ │ │ + "westBoundLongitude": function(node, obj) { │ │ │ │ + obj[0] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "eastBoundLongitude": function(node, obj) { │ │ │ │ + obj[2] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "southBoundLatitude": function(node, obj) { │ │ │ │ + obj[1] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "northBoundLatitude": function(node, obj) { │ │ │ │ + obj[3] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "MinScaleDenominator": function(node, obj) { │ │ │ │ + obj.maxScale = parseFloat(this.getChildValue(node)).toPrecision(16); │ │ │ │ + }, │ │ │ │ + "MaxScaleDenominator": function(node, obj) { │ │ │ │ + obj.minScale = parseFloat(this.getChildValue(node)).toPrecision(16); │ │ │ │ + }, │ │ │ │ + "Dimension": function(node, obj) { │ │ │ │ + // dimension has extra attributes: default, multipleValues, │ │ │ │ + // nearestValue, current which used to be part of Extent. It now │ │ │ │ + // also contains the values. │ │ │ │ + var name = node.getAttribute("name").toLowerCase(); │ │ │ │ + var dim = { │ │ │ │ + name: name, │ │ │ │ + units: node.getAttribute("units"), │ │ │ │ + unitsymbol: node.getAttribute("unitSymbol"), │ │ │ │ + nearestVal: node.getAttribute("nearestValue") === "1", │ │ │ │ + multipleVal: node.getAttribute("multipleValues") === "1", │ │ │ │ + "default": node.getAttribute("default") || "", │ │ │ │ + current: node.getAttribute("current") === "1", │ │ │ │ + values: this.getChildValue(node).split(",") │ │ │ │ + │ │ │ │ + }; │ │ │ │ + // Theoretically there can be more dimensions with the same │ │ │ │ + // name, but with a different unit. Until we meet such a case, │ │ │ │ + // let's just keep the same structure as the WMS 1.1 │ │ │ │ + // GetCapabilities parser uses. We will store the last │ │ │ │ + // one encountered. │ │ │ │ + obj.dimensions[dim.name] = dim; │ │ │ │ + }, │ │ │ │ + "Keyword": function(node, obj) { │ │ │ │ + // TODO: should we change the structure of keyword in v1.js? │ │ │ │ + // Make it an object with a value instead of a string? │ │ │ │ + var keyword = { │ │ │ │ + value: this.getChildValue(node), │ │ │ │ + vocabulary: node.getAttribute("vocabulary") │ │ │ │ + }; │ │ │ │ + if (obj.keywords) { │ │ │ │ + obj.keywords.push(keyword); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]), │ │ │ │ + "sld": { │ │ │ │ + "UserDefinedSymbolization": function(node, obj) { │ │ │ │ + this.readers.wms.UserDefinedSymbolization.apply(this, [node, obj]); │ │ │ │ + // add the two extra attributes │ │ │ │ + obj.userSymbols.inlineFeature = parseInt(node.getAttribute("InlineFeature")) == 1; │ │ │ │ + obj.userSymbols.remoteWCS = parseInt(node.getAttribute("RemoteWCS")) == 1; │ │ │ │ + }, │ │ │ │ + "DescribeLayer": function(node, obj) { │ │ │ │ + this.readers.wms.DescribeLayer.apply(this, [node, obj]); │ │ │ │ + }, │ │ │ │ + "GetLegendGraphic": function(node, obj) { │ │ │ │ + this.readers.wms.GetLegendGraphic.apply(this, [node, obj]); │ │ │ │ + } │ │ │ │ } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.WFS.v1_1_0" │ │ │ │ -}); │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3" │ │ │ │ + │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/WFS/v1_0_0.js │ │ │ │ + OpenLayers/Format/WMSCapabilities/v1_3_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 │ │ │ │ + * @requires OpenLayers/Format/WMSCapabilities/v1_3.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. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.WMSCapabilities/v1_3_0 │ │ │ │ + * Read WMS Capabilities version 1.3.0. │ │ │ │ + * SLD 1.1.0 adds in the extra operations DescribeLayer and GetLegendGraphic, │ │ │ │ + * see: http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol.WFS.v1> │ │ │ │ + * - <OpenLayers.Format.WMSCapabilities.v1_3> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol.WFS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_3_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WMSCapabilities.v1_3, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} The specific parser version. │ │ │ │ + */ │ │ │ │ + version: "1.3.0", │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3_0" │ │ │ │ + │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WMSCapabilities/v1_1_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/WMSCapabilities/v1_1.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WMSCapabilities/v1_1_0 │ │ │ │ + * Read WMS Capabilities version 1.1.0. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.WMSCapabilities.v1_1> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} The specific parser version. │ │ │ │ + */ │ │ │ │ + version: "1.1.0", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_0 │ │ │ │ + * Create a new parser for WMS capabilities version 1.1.0. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ + "SRS": function(node, obj) { │ │ │ │ + var srs = this.getChildValue(node); │ │ │ │ + var values = srs.split(/ +/); │ │ │ │ + for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ + obj.srs[values[i]] = true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_0" │ │ │ │ + │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/ArcXML/Features.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/ArcXML.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.ArcXML.Features │ │ │ │ + * Read/Write ArcXML features. Create a new instance with the │ │ │ │ + * <OpenLayers.Format.ArcXML.Features> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.ArcXML.Features = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: version │ │ │ │ - * {String} WFS version number. │ │ │ │ + * Constructor: OpenLayers.Format.ArcXML.Features │ │ │ │ + * Create a new parser/writer for ArcXML Features. Create an instance of this class │ │ │ │ + * to get a set of features from an ArcXML response. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ */ │ │ │ │ - version: "1.0.0", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Protocol.WFS.v1_0_0 │ │ │ │ - * A class for giving layers WFS v1.0.0 protocol. │ │ │ │ - * │ │ │ │ + * APIMethod: read │ │ │ │ + * Read data from a string of ArcXML, and return a set of OpenLayers features. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ * │ │ │ │ - * 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'. │ │ │ │ + * Returns: │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} A collection of features. │ │ │ │ */ │ │ │ │ + read: function(data) { │ │ │ │ + var axl = new OpenLayers.Format.ArcXML(); │ │ │ │ + var parsed = axl.read(data); │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.WFS.v1_0_0" │ │ │ │ + return parsed.features.feature; │ │ │ │ + } │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Events/featureclick.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ @@ -86585,8 +85928,665 @@ │ │ │ │ │ │ │ │ this.imageSrc = OpenLayers.Util.getImageLocation('cloud-popup-relative.png'); │ │ │ │ OpenLayers.Popup.Framed.prototype.initialize.apply(this, arguments); │ │ │ │ this.contentDiv.className = this.contentDisplayClass; │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Popup.FramedCloud" │ │ │ │ - }); │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + Rico/license.js │ │ │ │ + ====================================================================== */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * @license Apache 2 │ │ │ │ + * │ │ │ │ + * Contains portions of Rico <http://openrico.org/> │ │ │ │ + * │ │ │ │ + * Copyright 2005 Sabre Airline Solutions │ │ │ │ + * │ │ │ │ + * 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. │ │ │ │ + */ │ │ │ │ +/* ====================================================================== │ │ │ │ + Rico/Color.js │ │ │ │ + ====================================================================== */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * @requires Rico/license.js │ │ │ │ + * @requires OpenLayers/Console.js │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ + * @requires OpenLayers/BaseTypes/Element.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ + │ │ │ │ +/* │ │ │ │ + * This file has been edited substantially from the Rico-released version by │ │ │ │ + * the OpenLayers development team. │ │ │ │ + */ │ │ │ │ + │ │ │ │ +OpenLayers.Console.warn("OpenLayers.Rico is deprecated"); │ │ │ │ + │ │ │ │ +OpenLayers.Rico = OpenLayers.Rico || {}; │ │ │ │ +OpenLayers.Rico.Color = OpenLayers.Class({ │ │ │ │ + │ │ │ │ + initialize: function(red, green, blue) { │ │ │ │ + this.rgb = { │ │ │ │ + r: red, │ │ │ │ + g: green, │ │ │ │ + b: blue │ │ │ │ + }; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + setRed: function(r) { │ │ │ │ + this.rgb.r = r; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + setGreen: function(g) { │ │ │ │ + this.rgb.g = g; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + setBlue: function(b) { │ │ │ │ + this.rgb.b = b; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + setHue: function(h) { │ │ │ │ + │ │ │ │ + // get an HSB model, and set the new hue... │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ + hsb.h = h; │ │ │ │ + │ │ │ │ + // convert back to RGB... │ │ │ │ + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + setSaturation: function(s) { │ │ │ │ + // get an HSB model, and set the new hue... │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ + hsb.s = s; │ │ │ │ + │ │ │ │ + // convert back to RGB and set values... │ │ │ │ + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + setBrightness: function(b) { │ │ │ │ + // get an HSB model, and set the new hue... │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ + hsb.b = b; │ │ │ │ + │ │ │ │ + // convert back to RGB and set values... │ │ │ │ + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + darken: function(percent) { │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent, 0)); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + brighten: function(percent) { │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent, 1)); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + blend: function(other) { │ │ │ │ + this.rgb.r = Math.floor((this.rgb.r + other.rgb.r) / 2); │ │ │ │ + this.rgb.g = Math.floor((this.rgb.g + other.rgb.g) / 2); │ │ │ │ + this.rgb.b = Math.floor((this.rgb.b + other.rgb.b) / 2); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + isBright: function() { │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ + return this.asHSB().b > 0.5; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + isDark: function() { │ │ │ │ + return !this.isBright(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + asRGB: function() { │ │ │ │ + return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")"; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + asHex: function() { │ │ │ │ + return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + asHSB: function() { │ │ │ │ + return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + toString: function() { │ │ │ │ + return this.asHex(); │ │ │ │ + } │ │ │ │ + │ │ │ │ +}); │ │ │ │ + │ │ │ │ +OpenLayers.Rico.Color.createFromHex = function(hexCode) { │ │ │ │ + if (hexCode.length == 4) { │ │ │ │ + var shortHexCode = hexCode; │ │ │ │ + var hexCode = '#'; │ │ │ │ + for (var i = 1; i < 4; i++) { │ │ │ │ + hexCode += (shortHexCode.charAt(i) + │ │ │ │ + shortHexCode.charAt(i)); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (hexCode.indexOf('#') == 0) { │ │ │ │ + hexCode = hexCode.substring(1); │ │ │ │ + } │ │ │ │ + var red = hexCode.substring(0, 2); │ │ │ │ + var green = hexCode.substring(2, 4); │ │ │ │ + var blue = hexCode.substring(4, 6); │ │ │ │ + return new OpenLayers.Rico.Color(parseInt(red, 16), parseInt(green, 16), parseInt(blue, 16)); │ │ │ │ +}; │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Factory method for creating a color from the background of │ │ │ │ + * an HTML element. │ │ │ │ + */ │ │ │ │ +OpenLayers.Rico.Color.createColorFromBackground = function(elem) { │ │ │ │ + │ │ │ │ + var actualColor = │ │ │ │ + OpenLayers.Element.getStyle(OpenLayers.Util.getElement(elem), │ │ │ │ + "backgroundColor"); │ │ │ │ + │ │ │ │ + if (actualColor == "transparent" && elem.parentNode) { │ │ │ │ + return OpenLayers.Rico.Color.createColorFromBackground(elem.parentNode); │ │ │ │ + } │ │ │ │ + if (actualColor == null) { │ │ │ │ + return new OpenLayers.Rico.Color(255, 255, 255); │ │ │ │ + } │ │ │ │ + if (actualColor.indexOf("rgb(") == 0) { │ │ │ │ + var colors = actualColor.substring(4, actualColor.length - 1); │ │ │ │ + var colorArray = colors.split(","); │ │ │ │ + return new OpenLayers.Rico.Color(parseInt(colorArray[0]), │ │ │ │ + parseInt(colorArray[1]), │ │ │ │ + parseInt(colorArray[2])); │ │ │ │ + │ │ │ │ + } else if (actualColor.indexOf("#") == 0) { │ │ │ │ + return OpenLayers.Rico.Color.createFromHex(actualColor); │ │ │ │ + } else { │ │ │ │ + return new OpenLayers.Rico.Color(255, 255, 255); │ │ │ │ + } │ │ │ │ +}; │ │ │ │ + │ │ │ │ +OpenLayers.Rico.Color.HSBtoRGB = function(hue, saturation, brightness) { │ │ │ │ + │ │ │ │ + var red = 0; │ │ │ │ + var green = 0; │ │ │ │ + var blue = 0; │ │ │ │ + │ │ │ │ + if (saturation == 0) { │ │ │ │ + red = parseInt(brightness * 255.0 + 0.5); │ │ │ │ + green = red; │ │ │ │ + blue = red; │ │ │ │ + } else { │ │ │ │ + var h = (hue - Math.floor(hue)) * 6.0; │ │ │ │ + var f = h - Math.floor(h); │ │ │ │ + var p = brightness * (1.0 - saturation); │ │ │ │ + var q = brightness * (1.0 - saturation * f); │ │ │ │ + var t = brightness * (1.0 - (saturation * (1.0 - f))); │ │ │ │ + │ │ │ │ + switch (parseInt(h)) { │ │ │ │ + case 0: │ │ │ │ + red = (brightness * 255.0 + 0.5); │ │ │ │ + green = (t * 255.0 + 0.5); │ │ │ │ + blue = (p * 255.0 + 0.5); │ │ │ │ + break; │ │ │ │ + case 1: │ │ │ │ + red = (q * 255.0 + 0.5); │ │ │ │ + green = (brightness * 255.0 + 0.5); │ │ │ │ + blue = (p * 255.0 + 0.5); │ │ │ │ + break; │ │ │ │ + case 2: │ │ │ │ + red = (p * 255.0 + 0.5); │ │ │ │ + green = (brightness * 255.0 + 0.5); │ │ │ │ + blue = (t * 255.0 + 0.5); │ │ │ │ + break; │ │ │ │ + case 3: │ │ │ │ + red = (p * 255.0 + 0.5); │ │ │ │ + green = (q * 255.0 + 0.5); │ │ │ │ + blue = (brightness * 255.0 + 0.5); │ │ │ │ + break; │ │ │ │ + case 4: │ │ │ │ + red = (t * 255.0 + 0.5); │ │ │ │ + green = (p * 255.0 + 0.5); │ │ │ │ + blue = (brightness * 255.0 + 0.5); │ │ │ │ + break; │ │ │ │ + case 5: │ │ │ │ + red = (brightness * 255.0 + 0.5); │ │ │ │ + green = (p * 255.0 + 0.5); │ │ │ │ + blue = (q * 255.0 + 0.5); │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + return { │ │ │ │ + r: parseInt(red), │ │ │ │ + g: parseInt(green), │ │ │ │ + b: parseInt(blue) │ │ │ │ + }; │ │ │ │ +}; │ │ │ │ + │ │ │ │ +OpenLayers.Rico.Color.RGBtoHSB = function(r, g, b) { │ │ │ │ + │ │ │ │ + var hue; │ │ │ │ + var saturation; │ │ │ │ + var brightness; │ │ │ │ + │ │ │ │ + var cmax = (r > g) ? r : g; │ │ │ │ + if (b > cmax) { │ │ │ │ + cmax = b; │ │ │ │ + } │ │ │ │ + var cmin = (r < g) ? r : g; │ │ │ │ + if (b < cmin) { │ │ │ │ + cmin = b; │ │ │ │ + } │ │ │ │ + brightness = cmax / 255.0; │ │ │ │ + if (cmax != 0) { │ │ │ │ + saturation = (cmax - cmin) / cmax; │ │ │ │ + } else { │ │ │ │ + saturation = 0; │ │ │ │ + } │ │ │ │ + if (saturation == 0) { │ │ │ │ + hue = 0; │ │ │ │ + } else { │ │ │ │ + var redc = (cmax - r) / (cmax - cmin); │ │ │ │ + var greenc = (cmax - g) / (cmax - cmin); │ │ │ │ + var bluec = (cmax - b) / (cmax - cmin); │ │ │ │ + │ │ │ │ + if (r == cmax) { │ │ │ │ + hue = bluec - greenc; │ │ │ │ + } else if (g == cmax) { │ │ │ │ + hue = 2.0 + redc - bluec; │ │ │ │ + } else { │ │ │ │ + hue = 4.0 + greenc - redc; │ │ │ │ + } │ │ │ │ + hue = hue / 6.0; │ │ │ │ + if (hue < 0) { │ │ │ │ + hue = hue + 1.0; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + return { │ │ │ │ + h: hue, │ │ │ │ + s: saturation, │ │ │ │ + b: brightness │ │ │ │ + }; │ │ │ │ +}; │ │ │ │ + │ │ │ │ +/* ====================================================================== │ │ │ │ + Rico/Corner.js │ │ │ │ + ====================================================================== */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Console.js │ │ │ │ + * @requires Rico/Color.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ + │ │ │ │ +/* │ │ │ │ + * This file has been edited substantially from the Rico-released │ │ │ │ + * version by the OpenLayers development team. │ │ │ │ + * │ │ │ │ + * Copyright 2005 Sabre Airline Solutions │ │ │ │ + * │ │ │ │ + * 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. │ │ │ │ + * │ │ │ │ + */ │ │ │ │ + │ │ │ │ +OpenLayers.Console.warn("OpenLayers.Rico is deprecated"); │ │ │ │ + │ │ │ │ +OpenLayers.Rico = OpenLayers.Rico || {}; │ │ │ │ +OpenLayers.Rico.Corner = { │ │ │ │ + │ │ │ │ + round: function(e, options) { │ │ │ │ + e = OpenLayers.Util.getElement(e); │ │ │ │ + this._setOptions(options); │ │ │ │ + │ │ │ │ + var color = this.options.color; │ │ │ │ + if (this.options.color == "fromElement") { │ │ │ │ + color = this._background(e); │ │ │ │ + } │ │ │ │ + var bgColor = this.options.bgColor; │ │ │ │ + if (this.options.bgColor == "fromParent") { │ │ │ │ + bgColor = this._background(e.offsetParent); │ │ │ │ + } │ │ │ │ + this._roundCornersImpl(e, color, bgColor); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** This is a helper function to change the background │ │ │ │ + * color of <div> that has had Rico rounded corners added. │ │ │ │ + * │ │ │ │ + * It seems we cannot just set the background color for the │ │ │ │ + * outer <div> so each <span> element used to create the │ │ │ │ + * corners must have its background color set individually. │ │ │ │ + * │ │ │ │ + * @param {DOM} theDiv - A child of the outer <div> that was │ │ │ │ + * supplied to the `round` method. │ │ │ │ + * │ │ │ │ + * @param {String} newColor - The new background color to use. │ │ │ │ + */ │ │ │ │ + changeColor: function(theDiv, newColor) { │ │ │ │ + │ │ │ │ + theDiv.style.backgroundColor = newColor; │ │ │ │ + │ │ │ │ + var spanElements = theDiv.parentNode.getElementsByTagName("span"); │ │ │ │ + │ │ │ │ + for (var currIdx = 0; currIdx < spanElements.length; currIdx++) { │ │ │ │ + spanElements[currIdx].style.backgroundColor = newColor; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** This is a helper function to change the background │ │ │ │ + * opacity of <div> that has had Rico rounded corners added. │ │ │ │ + * │ │ │ │ + * See changeColor (above) for algorithm explanation │ │ │ │ + * │ │ │ │ + * @param {DOM} theDiv A child of the outer <div> that was │ │ │ │ + * supplied to the `round` method. │ │ │ │ + * │ │ │ │ + * @param {int} newOpacity The new opacity to use (0-1). │ │ │ │ + */ │ │ │ │ + changeOpacity: function(theDiv, newOpacity) { │ │ │ │ + │ │ │ │ + var mozillaOpacity = newOpacity; │ │ │ │ + var ieOpacity = 'alpha(opacity=' + newOpacity * 100 + ')'; │ │ │ │ + │ │ │ │ + theDiv.style.opacity = mozillaOpacity; │ │ │ │ + theDiv.style.filter = ieOpacity; │ │ │ │ + │ │ │ │ + var spanElements = theDiv.parentNode.getElementsByTagName("span"); │ │ │ │ + │ │ │ │ + for (var currIdx = 0; currIdx < spanElements.length; currIdx++) { │ │ │ │ + spanElements[currIdx].style.opacity = mozillaOpacity; │ │ │ │ + spanElements[currIdx].style.filter = ieOpacity; │ │ │ │ + } │ │ │ │ + │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** this function takes care of redoing the rico cornering │ │ │ │ + * │ │ │ │ + * you can't just call updateRicoCorners() again and pass it a │ │ │ │ + * new options string. you have to first remove the divs that │ │ │ │ + * rico puts on top and below the content div. │ │ │ │ + * │ │ │ │ + * @param {DOM} theDiv - A child of the outer <div> that was │ │ │ │ + * supplied to the `round` method. │ │ │ │ + * │ │ │ │ + * @param {Object} options - list of options │ │ │ │ + */ │ │ │ │ + reRound: function(theDiv, options) { │ │ │ │ + │ │ │ │ + var topRico = theDiv.parentNode.childNodes[0]; │ │ │ │ + //theDiv would be theDiv.parentNode.childNodes[1] │ │ │ │ + var bottomRico = theDiv.parentNode.childNodes[2]; │ │ │ │ + │ │ │ │ + theDiv.parentNode.removeChild(topRico); │ │ │ │ + theDiv.parentNode.removeChild(bottomRico); │ │ │ │ + │ │ │ │ + this.round(theDiv.parentNode, options); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + _roundCornersImpl: function(e, color, bgColor) { │ │ │ │ + if (this.options.border) { │ │ │ │ + this._renderBorder(e, bgColor); │ │ │ │ + } │ │ │ │ + if (this._isTopRounded()) { │ │ │ │ + this._roundTopCorners(e, color, bgColor); │ │ │ │ + } │ │ │ │ + if (this._isBottomRounded()) { │ │ │ │ + this._roundBottomCorners(e, color, bgColor); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + _renderBorder: function(el, bgColor) { │ │ │ │ + var borderValue = "1px solid " + this._borderColor(bgColor); │ │ │ │ + var borderL = "border-left: " + borderValue; │ │ │ │ + var borderR = "border-right: " + borderValue; │ │ │ │ + var style = "style='" + borderL + ";" + borderR + "'"; │ │ │ │ + el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>"; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + _roundTopCorners: function(el, color, bgColor) { │ │ │ │ + var corner = this._createCorner(bgColor); │ │ │ │ + for (var i = 0; i < this.options.numSlices; i++) { │ │ │ │ + corner.appendChild(this._createCornerSlice(color, bgColor, i, "top")); │ │ │ │ + } │ │ │ │ + el.style.paddingTop = 0; │ │ │ │ + el.insertBefore(corner, el.firstChild); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + _roundBottomCorners: function(el, color, bgColor) { │ │ │ │ + var corner = this._createCorner(bgColor); │ │ │ │ + for (var i = (this.options.numSlices - 1); i >= 0; i--) { │ │ │ │ + corner.appendChild(this._createCornerSlice(color, bgColor, i, "bottom")); │ │ │ │ + } │ │ │ │ + el.style.paddingBottom = 0; │ │ │ │ + el.appendChild(corner); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + _createCorner: function(bgColor) { │ │ │ │ + var corner = document.createElement("div"); │ │ │ │ + corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor); │ │ │ │ + return corner; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + _createCornerSlice: function(color, bgColor, n, position) { │ │ │ │ + var slice = document.createElement("span"); │ │ │ │ + │ │ │ │ + var inStyle = slice.style; │ │ │ │ + inStyle.backgroundColor = color; │ │ │ │ + inStyle.display = "block"; │ │ │ │ + inStyle.height = "1px"; │ │ │ │ + inStyle.overflow = "hidden"; │ │ │ │ + inStyle.fontSize = "1px"; │ │ │ │ + │ │ │ │ + var borderColor = this._borderColor(color, bgColor); │ │ │ │ + if (this.options.border && n == 0) { │ │ │ │ + inStyle.borderTopStyle = "solid"; │ │ │ │ + inStyle.borderTopWidth = "1px"; │ │ │ │ + inStyle.borderLeftWidth = "0px"; │ │ │ │ + inStyle.borderRightWidth = "0px"; │ │ │ │ + inStyle.borderBottomWidth = "0px"; │ │ │ │ + inStyle.height = "0px"; // assumes css compliant box model │ │ │ │ + inStyle.borderColor = borderColor; │ │ │ │ + } else if (borderColor) { │ │ │ │ + inStyle.borderColor = borderColor; │ │ │ │ + inStyle.borderStyle = "solid"; │ │ │ │ + inStyle.borderWidth = "0px 1px"; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (!this.options.compact && (n == (this.options.numSlices - 1))) { │ │ │ │ + inStyle.height = "2px"; │ │ │ │ + } │ │ │ │ + this._setMargin(slice, n, position); │ │ │ │ + this._setBorder(slice, n, position); │ │ │ │ + return slice; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + _setOptions: function(options) { │ │ │ │ + this.options = { │ │ │ │ + corners: "all", │ │ │ │ + color: "fromElement", │ │ │ │ + bgColor: "fromParent", │ │ │ │ + blend: true, │ │ │ │ + border: false, │ │ │ │ + compact: false │ │ │ │ + }; │ │ │ │ + OpenLayers.Util.extend(this.options, options || {}); │ │ │ │ + │ │ │ │ + this.options.numSlices = this.options.compact ? 2 : 4; │ │ │ │ + if (this._isTransparent()) { │ │ │ │ + this.options.blend = false; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + _whichSideTop: function() { │ │ │ │ + if (this._hasString(this.options.corners, "all", "top")) { │ │ │ │ + return ""; │ │ │ │ + } │ │ │ │ + if (this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0) { │ │ │ │ + return ""; │ │ │ │ + } │ │ │ │ + if (this.options.corners.indexOf("tl") >= 0) { │ │ │ │ + return "left"; │ │ │ │ + } else if (this.options.corners.indexOf("tr") >= 0) { │ │ │ │ + return "right"; │ │ │ │ + } │ │ │ │ + return ""; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + _whichSideBottom: function() { │ │ │ │ + if (this._hasString(this.options.corners, "all", "bottom")) { │ │ │ │ + return ""; │ │ │ │ + } │ │ │ │ + if (this.options.corners.indexOf("bl") >= 0 && this.options.corners.indexOf("br") >= 0) { │ │ │ │ + return ""; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.options.corners.indexOf("bl") >= 0) { │ │ │ │ + return "left"; │ │ │ │ + } else if (this.options.corners.indexOf("br") >= 0) { │ │ │ │ + return "right"; │ │ │ │ + } │ │ │ │ + return ""; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + _borderColor: function(color, bgColor) { │ │ │ │ + if (color == "transparent") { │ │ │ │ + return bgColor; │ │ │ │ + } else if (this.options.border) { │ │ │ │ + return this.options.border; │ │ │ │ + } else if (this.options.blend) { │ │ │ │ + return this._blend(bgColor, color); │ │ │ │ + } else { │ │ │ │ + return ""; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + _setMargin: function(el, n, corners) { │ │ │ │ + var marginSize = this._marginSize(n); │ │ │ │ + var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); │ │ │ │ + │ │ │ │ + if (whichSide == "left") { │ │ │ │ + el.style.marginLeft = marginSize + "px"; │ │ │ │ + el.style.marginRight = "0px"; │ │ │ │ + } else if (whichSide == "right") { │ │ │ │ + el.style.marginRight = marginSize + "px"; │ │ │ │ + el.style.marginLeft = "0px"; │ │ │ │ + } else { │ │ │ │ + el.style.marginLeft = marginSize + "px"; │ │ │ │ + el.style.marginRight = marginSize + "px"; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + _setBorder: function(el, n, corners) { │ │ │ │ + var borderSize = this._borderSize(n); │ │ │ │ + var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); │ │ │ │ + if (whichSide == "left") { │ │ │ │ + el.style.borderLeftWidth = borderSize + "px"; │ │ │ │ + el.style.borderRightWidth = "0px"; │ │ │ │ + } else if (whichSide == "right") { │ │ │ │ + el.style.borderRightWidth = borderSize + "px"; │ │ │ │ + el.style.borderLeftWidth = "0px"; │ │ │ │ + } else { │ │ │ │ + el.style.borderLeftWidth = borderSize + "px"; │ │ │ │ + el.style.borderRightWidth = borderSize + "px"; │ │ │ │ + } │ │ │ │ + if (this.options.border != false) { │ │ │ │ + el.style.borderLeftWidth = borderSize + "px"; │ │ │ │ + el.style.borderRightWidth = borderSize + "px"; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + _marginSize: function(n) { │ │ │ │ + if (this._isTransparent()) { │ │ │ │ + return 0; │ │ │ │ + } │ │ │ │ + var marginSizes = [5, 3, 2, 1]; │ │ │ │ + var blendedMarginSizes = [3, 2, 1, 0]; │ │ │ │ + var compactMarginSizes = [2, 1]; │ │ │ │ + var smBlendedMarginSizes = [1, 0]; │ │ │ │ + │ │ │ │ + if (this.options.compact && this.options.blend) { │ │ │ │ + return smBlendedMarginSizes[n]; │ │ │ │ + } else if (this.options.compact) { │ │ │ │ + return compactMarginSizes[n]; │ │ │ │ + } else if (this.options.blend) { │ │ │ │ + return blendedMarginSizes[n]; │ │ │ │ + } else { │ │ │ │ + return marginSizes[n]; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + _borderSize: function(n) { │ │ │ │ + var transparentBorderSizes = [5, 3, 2, 1]; │ │ │ │ + var blendedBorderSizes = [2, 1, 1, 1]; │ │ │ │ + var compactBorderSizes = [1, 0]; │ │ │ │ + var actualBorderSizes = [0, 2, 0, 0]; │ │ │ │ + │ │ │ │ + if (this.options.compact && (this.options.blend || this._isTransparent())) { │ │ │ │ + return 1; │ │ │ │ + } else if (this.options.compact) { │ │ │ │ + return compactBorderSizes[n]; │ │ │ │ + } else if (this.options.blend) { │ │ │ │ + return blendedBorderSizes[n]; │ │ │ │ + } else if (this.options.border) { │ │ │ │ + return actualBorderSizes[n]; │ │ │ │ + } else if (this._isTransparent()) { │ │ │ │ + return transparentBorderSizes[n]; │ │ │ │ + } │ │ │ │ + return 0; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + _hasString: function(str) { │ │ │ │ + for (var i = 1; i < arguments.length; i++) │ │ │ │ + if (str.indexOf(arguments[i]) >= 0) { │ │ │ │ + return true; │ │ │ │ + } return false; │ │ │ │ + }, │ │ │ │ + _blend: function(c1, c2) { │ │ │ │ + var cc1 = OpenLayers.Rico.Color.createFromHex(c1); │ │ │ │ + cc1.blend(OpenLayers.Rico.Color.createFromHex(c2)); │ │ │ │ + return cc1; │ │ │ │ + }, │ │ │ │ + _background: function(el) { │ │ │ │ + try { │ │ │ │ + return OpenLayers.Rico.Color.createColorFromBackground(el).asHex(); │ │ │ │ + } catch (err) { │ │ │ │ + return "#ffffff"; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + _isTransparent: function() { │ │ │ │ + return this.options.color == "transparent"; │ │ │ │ + }, │ │ │ │ + _isTopRounded: function() { │ │ │ │ + return this._hasString(this.options.corners, "all", "top", "tl", "tr"); │ │ │ │ + }, │ │ │ │ + _isBottomRounded: function() { │ │ │ │ + return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); │ │ │ │ + }, │ │ │ │ + _hasSingleTextChild: function(el) { │ │ │ │ + return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; │ │ │ │ + } │ │ │ │ +}; │ │ ├── ./usr/share/javascript/openlayers/OpenLayers.light.js │ │ │ ├── js-beautify {} │ │ │ │ @@ -4426,1450 +4426,14 @@ │ │ │ │ } else { │ │ │ │ str += coordinate < 0 ? OpenLayers.i18n("S") : OpenLayers.i18n("N"); │ │ │ │ } │ │ │ │ return str; │ │ │ │ }; │ │ │ │ │ │ │ │ /* ====================================================================== │ │ │ │ - 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/Rule.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.Rule │ │ │ │ - * This class represents an SLD Rule, as being used for rule-based SLD styling. │ │ │ │ - */ │ │ │ │ -OpenLayers.Rule = OpenLayers.Class({ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: id │ │ │ │ - * {String} A unique id for this session. │ │ │ │ - */ │ │ │ │ - id: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: name │ │ │ │ - * {String} name of this rule │ │ │ │ - */ │ │ │ │ - name: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: title │ │ │ │ - * {String} Title of this rule (set if included in SLD) │ │ │ │ - */ │ │ │ │ - title: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: description │ │ │ │ - * {String} Description of this rule (set if abstract is included in SLD) │ │ │ │ - */ │ │ │ │ - description: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: context │ │ │ │ - * {Object} An optional object with properties that the rule should be │ │ │ │ - * evaluated against. If no context is specified, feature.attributes will │ │ │ │ - * be used. │ │ │ │ - */ │ │ │ │ - context: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: filter │ │ │ │ - * {<OpenLayers.Filter>} Optional filter for the rule. │ │ │ │ - */ │ │ │ │ - filter: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: elseFilter │ │ │ │ - * {Boolean} Determines whether this rule is only to be applied only if │ │ │ │ - * no other rules match (ElseFilter according to the SLD specification). │ │ │ │ - * Default is false. For instances of OpenLayers.Rule, if elseFilter is │ │ │ │ - * false, the rule will always apply. For subclasses, the else property is │ │ │ │ - * ignored. │ │ │ │ - */ │ │ │ │ - elseFilter: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: symbolizer │ │ │ │ - * {Object} Symbolizer or hash of symbolizers for this rule. If hash of │ │ │ │ - * symbolizers, keys are one or more of ["Point", "Line", "Polygon"]. The │ │ │ │ - * latter if useful if it is required to style e.g. vertices of a line │ │ │ │ - * with a point symbolizer. Note, however, that this is not implemented │ │ │ │ - * yet in OpenLayers, but it is the way how symbolizers are defined in │ │ │ │ - * SLD. │ │ │ │ - */ │ │ │ │ - symbolizer: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: symbolizers │ │ │ │ - * {Array} Collection of symbolizers associated with this rule. If │ │ │ │ - * provided at construction, the symbolizers array has precedence │ │ │ │ - * over the deprecated symbolizer property. Note that multiple │ │ │ │ - * symbolizers are not currently supported by the vector renderers. │ │ │ │ - * Rules with multiple symbolizers are currently only useful for │ │ │ │ - * maintaining elements in an SLD document. │ │ │ │ - */ │ │ │ │ - symbolizers: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: minScaleDenominator │ │ │ │ - * {Number} or {String} minimum scale at which to draw the feature. │ │ │ │ - * In the case of a String, this can be a combination of text and │ │ │ │ - * propertyNames in the form "literal ${propertyName}" │ │ │ │ - */ │ │ │ │ - minScaleDenominator: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: maxScaleDenominator │ │ │ │ - * {Number} or {String} maximum scale at which to draw the feature. │ │ │ │ - * In the case of a String, this can be a combination of text and │ │ │ │ - * propertyNames in the form "literal ${propertyName}" │ │ │ │ - */ │ │ │ │ - maxScaleDenominator: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Rule │ │ │ │ - * Creates a Rule. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object with properties to set on the │ │ │ │ - * rule │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Rule>} │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - this.symbolizer = {}; │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - if (this.symbolizers) { │ │ │ │ - delete this.symbolizer; │ │ │ │ - } │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * nullify references to prevent circular references and memory leaks │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - for (var i in this.symbolizer) { │ │ │ │ - this.symbolizer[i] = null; │ │ │ │ - } │ │ │ │ - this.symbolizer = null; │ │ │ │ - delete this.symbolizers; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: evaluate │ │ │ │ - * evaluates this rule for a specific feature │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature>} feature to apply the rule to. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} true if the rule applies, false if it does not. │ │ │ │ - * This rule is the default rule and always returns true. │ │ │ │ - */ │ │ │ │ - evaluate: function(feature) { │ │ │ │ - var context = this.getContext(feature); │ │ │ │ - var applies = true; │ │ │ │ - │ │ │ │ - if (this.minScaleDenominator || this.maxScaleDenominator) { │ │ │ │ - var scale = feature.layer.map.getScale(); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // check if within minScale/maxScale bounds │ │ │ │ - if (this.minScaleDenominator) { │ │ │ │ - applies = scale >= OpenLayers.Style.createLiteral( │ │ │ │ - this.minScaleDenominator, context); │ │ │ │ - } │ │ │ │ - if (applies && this.maxScaleDenominator) { │ │ │ │ - applies = scale < OpenLayers.Style.createLiteral( │ │ │ │ - this.maxScaleDenominator, context); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // check if optional filter applies │ │ │ │ - if (applies && this.filter) { │ │ │ │ - // feature id filters get the feature, others get the context │ │ │ │ - if (this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") { │ │ │ │ - applies = this.filter.evaluate(feature); │ │ │ │ - } else { │ │ │ │ - applies = this.filter.evaluate(context); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return applies; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getContext │ │ │ │ - * Gets the context for evaluating this rule │ │ │ │ - * │ │ │ │ - * Paramters: │ │ │ │ - * feature - {<OpenLayers.Feature>} feature to take the context from if │ │ │ │ - * none is specified. │ │ │ │ - */ │ │ │ │ - getContext: function(feature) { │ │ │ │ - var context = this.context; │ │ │ │ - if (!context) { │ │ │ │ - context = feature.attributes || feature.data; │ │ │ │ - } │ │ │ │ - if (typeof this.context == "function") { │ │ │ │ - context = this.context(feature); │ │ │ │ - } │ │ │ │ - return context; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Clones this rule. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Rule>} Clone of this rule. │ │ │ │ - */ │ │ │ │ - clone: function() { │ │ │ │ - var options = OpenLayers.Util.extend({}, this); │ │ │ │ - if (this.symbolizers) { │ │ │ │ - // clone symbolizers │ │ │ │ - var len = this.symbolizers.length; │ │ │ │ - options.symbolizers = new Array(len); │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ - options.symbolizers[i] = this.symbolizers[i].clone(); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - // clone symbolizer │ │ │ │ - options.symbolizer = {}; │ │ │ │ - var value, type; │ │ │ │ - for (var key in this.symbolizer) { │ │ │ │ - value = this.symbolizer[key]; │ │ │ │ - type = typeof value; │ │ │ │ - if (type === "object") { │ │ │ │ - options.symbolizer[key] = OpenLayers.Util.extend({}, value); │ │ │ │ - } else if (type === "string") { │ │ │ │ - options.symbolizer[key] = value; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - // clone filter │ │ │ │ - options.filter = this.filter && this.filter.clone(); │ │ │ │ - // clone context │ │ │ │ - options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ - return new OpenLayers.Rule(options); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Rule" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ 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. */ │ │ │ │ @@ -10893,179 +9457,14 @@ │ │ │ │ OpenLayers.Map.TILE_WIDTH = 256; │ │ │ │ /** │ │ │ │ * Constant: TILE_HEIGHT │ │ │ │ * {Integer} 256 Default tile height (unless otherwise specified) │ │ │ │ */ │ │ │ │ OpenLayers.Map.TILE_HEIGHT = 256; │ │ │ │ /* ====================================================================== │ │ │ │ - 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/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. */ │ │ │ │ @@ -11246,1725 +9645,8016 @@ │ │ │ │ OpenLayers.Function.bind(timerCallback, this) │ │ │ │ ); │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Kinetic" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer.js │ │ │ │ + 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/Map.js │ │ │ │ - * @requires OpenLayers/Projection.js │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer │ │ │ │ + * Class: OpenLayers.Feature │ │ │ │ + * Features are combinations of geography and attributes. The OpenLayers.Feature │ │ │ │ + * class specifically combines a marker and a lonlat. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer = OpenLayers.Class({ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: id │ │ │ │ - * {String} │ │ │ │ - */ │ │ │ │ - id: null, │ │ │ │ +OpenLayers.Feature = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: name │ │ │ │ - * {String} │ │ │ │ + * Property: layer │ │ │ │ + * {<OpenLayers.Layer>} │ │ │ │ */ │ │ │ │ - name: null, │ │ │ │ + layer: 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. │ │ │ │ + * Property: id │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - alwaysInRange: null, │ │ │ │ + id: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: RESOLUTION_PROPERTIES │ │ │ │ - * {Array} The properties that are used for calculating resolutions │ │ │ │ - * information. │ │ │ │ + /** │ │ │ │ + * Property: lonlat │ │ │ │ + * {<OpenLayers.LonLat>} │ │ │ │ */ │ │ │ │ - RESOLUTION_PROPERTIES: [ │ │ │ │ - 'scales', 'resolutions', │ │ │ │ - 'maxScale', 'minScale', │ │ │ │ - 'maxResolution', 'minResolution', │ │ │ │ - 'numZoomLevels', 'maxZoomLevel' │ │ │ │ - ], │ │ │ │ + lonlat: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * Property: data │ │ │ │ + * {Object} │ │ │ │ */ │ │ │ │ - events: null, │ │ │ │ + data: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: map │ │ │ │ - * {<OpenLayers.Map>} This variable is set when the layer is added to │ │ │ │ - * the map, via the accessor function setMap(). │ │ │ │ + /** │ │ │ │ + * Property: marker │ │ │ │ + * {<OpenLayers.Marker>} │ │ │ │ */ │ │ │ │ - map: null, │ │ │ │ + marker: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} Whether or not the layer is a base layer. This should be set │ │ │ │ - * individually by all subclasses. Default is false │ │ │ │ + * APIProperty: popupClass │ │ │ │ + * {<OpenLayers.Class>} The class which will be used to instantiate │ │ │ │ + * a new Popup. Default is <OpenLayers.Popup.Anchored>. │ │ │ │ */ │ │ │ │ - isBaseLayer: false, │ │ │ │ + popupClass: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: alpha │ │ │ │ - * {Boolean} The layer's images have an alpha channel. Default is false. │ │ │ │ + /** │ │ │ │ + * Property: popup │ │ │ │ + * {<OpenLayers.Popup>} │ │ │ │ */ │ │ │ │ - alpha: false, │ │ │ │ + popup: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: displayInLayerSwitcher │ │ │ │ - * {Boolean} Display the layer's name in the layer switcher. Default is │ │ │ │ - * true. │ │ │ │ + * Constructor: OpenLayers.Feature │ │ │ │ + * Constructor for features. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer>} │ │ │ │ + * lonlat - {<OpenLayers.LonLat>} │ │ │ │ + * data - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Feature>} │ │ │ │ */ │ │ │ │ - displayInLayerSwitcher: true, │ │ │ │ + initialize: function(layer, lonlat, data) { │ │ │ │ + this.layer = layer; │ │ │ │ + this.lonlat = lonlat; │ │ │ │ + this.data = (data != null) ? data : {}; │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: visibility │ │ │ │ - * {Boolean} The layer should be displayed in the map. Default is true. │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ */ │ │ │ │ - visibility: true, │ │ │ │ + destroy: function() { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: attribution │ │ │ │ - * {String} Attribution string, displayed when an │ │ │ │ - * <OpenLayers.Control.Attribution> has been added to the map. │ │ │ │ - */ │ │ │ │ - attribution: null, │ │ │ │ + //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); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Propery: imageSize │ │ │ │ - * {<OpenLayers.Size>} For layers with a gutter, the image is larger than │ │ │ │ - * the tile by twice the gutter in each dimension. │ │ │ │ + * Method: onScreen │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the feature is currently visible on screen │ │ │ │ + * (based on its 'lonlat' property) │ │ │ │ */ │ │ │ │ - imageSize: null, │ │ │ │ + onScreen: function() { │ │ │ │ │ │ │ │ - // OPTIONS │ │ │ │ + var onScreen = false; │ │ │ │ + if ((this.layer != null) && (this.layer.map != null)) { │ │ │ │ + var screenBounds = this.layer.map.getExtent(); │ │ │ │ + onScreen = screenBounds.containsLonLat(this.lonlat); │ │ │ │ + } │ │ │ │ + return onScreen; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + * 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 │ │ │ │ + * │ │ │ │ */ │ │ │ │ - eventListeners: null, │ │ │ │ + createMarker: function() { │ │ │ │ + │ │ │ │ + if (this.lonlat != null) { │ │ │ │ + this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon); │ │ │ │ + } │ │ │ │ + return this.marker; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: destroyMarker │ │ │ │ + * Destroys marker. │ │ │ │ + * If user overrides the createMarker() function, s/he should be able │ │ │ │ + * to also specify an alternative function for destroying it │ │ │ │ */ │ │ │ │ - gutter: 0, │ │ │ │ + destroyMarker: function() { │ │ │ │ + this.marker.destroy(); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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 │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * 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>. │ │ │ │ * │ │ │ │ */ │ │ │ │ - projection: null, │ │ │ │ + createPopup: function(closeBox) { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + this.popup.feature = this; │ │ │ │ + } │ │ │ │ + return this.popup; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - maxExtent: null, │ │ │ │ + destroyPopup: function() { │ │ │ │ + if (this.popup) { │ │ │ │ + this.popup.feature = null; │ │ │ │ + this.popup.destroy(); │ │ │ │ + this.popup = 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, │ │ │ │ + CLASS_NAME: "OpenLayers.Feature" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Feature/Vector.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ +/* 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} │ │ │ │ */ │ │ │ │ - maxResolution: null, │ │ │ │ + fid: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: minResolution │ │ │ │ - * {Float} │ │ │ │ + /** │ │ │ │ + * APIProperty: geometry │ │ │ │ + * {<OpenLayers.Geometry>} │ │ │ │ */ │ │ │ │ - minResolution: null, │ │ │ │ + geometry: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: numZoomLevels │ │ │ │ - * {Integer} │ │ │ │ + /** │ │ │ │ + * APIProperty: attributes │ │ │ │ + * {Object} This object holds arbitrary, serializable properties that │ │ │ │ + * describe the feature. │ │ │ │ */ │ │ │ │ - numZoomLevels: null, │ │ │ │ + attributes: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: minScale │ │ │ │ - * {Float} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - minScale: null, │ │ │ │ + bounds: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: maxScale │ │ │ │ - * {Float} │ │ │ │ + /** │ │ │ │ + * Property: state │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - maxScale: null, │ │ │ │ + state: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: displayOutsideMaxExtent │ │ │ │ - * {Boolean} Request map tiles that are completely outside of the max │ │ │ │ - * extent for this layer. Defaults to false. │ │ │ │ + /** │ │ │ │ + * APIProperty: style │ │ │ │ + * {Object} │ │ │ │ */ │ │ │ │ - displayOutsideMaxExtent: false, │ │ │ │ + style: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: url │ │ │ │ + * {String} If this property is set it will be taken into account by │ │ │ │ + * {<OpenLayers.HTTP>} when upadting or deleting the feature. │ │ │ │ */ │ │ │ │ - wrapDateLine: false, │ │ │ │ + url: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: metadata │ │ │ │ - * {Object} This object can be used to store additional information on a │ │ │ │ - * layer object. │ │ │ │ + * Property: renderIntent │ │ │ │ + * {String} rendering intent currently being used │ │ │ │ */ │ │ │ │ - metadata: null, │ │ │ │ + renderIntent: "default", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer │ │ │ │ + * 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 │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} The layer name │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ + * (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. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + 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 │ │ │ │ - * 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. │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ */ │ │ │ │ - destroy: function(setNewBaseLayer) { │ │ │ │ - if (setNewBaseLayer == null) { │ │ │ │ - setNewBaseLayer = true; │ │ │ │ - } │ │ │ │ - if (this.map != null) { │ │ │ │ - this.map.removeLayer(this, setNewBaseLayer); │ │ │ │ + destroy: function() { │ │ │ │ + if (this.layer) { │ │ │ │ + this.layer.removeFeatures(this); │ │ │ │ + this.layer = null; │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + this.geometry = null; │ │ │ │ + this.modified = null; │ │ │ │ + OpenLayers.Feature.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * Method: clone │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * obj - {<OpenLayers.Layer>} The layer to be cloned │ │ │ │ + * Create a clone of this vector feature. Does not set any non-standard │ │ │ │ + * properties. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Layer>} An exact clone of this <OpenLayers.Layer> │ │ │ │ + * {<OpenLayers.Feature.Vector>} An exact clone of this vector feature. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + clone: function() { │ │ │ │ + return new OpenLayers.Feature.Vector( │ │ │ │ + this.geometry ? this.geometry.clone() : null, │ │ │ │ + this.attributes, │ │ │ │ + this.style); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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: │ │ │ │ - * {Object} the <options> of the layer, representing the current state. │ │ │ │ + * {Boolean} The feature is currently visible on screen (optionally │ │ │ │ + * based on its bounds if boundsOnly is true). │ │ │ │ */ │ │ │ │ - getOptions: function() { │ │ │ │ - var options = {}; │ │ │ │ - for (var o in this.options) { │ │ │ │ - options[o] = this[o]; │ │ │ │ + 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 options; │ │ │ │ + return onScreen; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: setName │ │ │ │ - * Sets the new layer name for this layer. Can trigger a changelayer event │ │ │ │ - * on the map. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * newName - {String} The new name. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - setName: function(newName) { │ │ │ │ - if (newName != this.name) { │ │ │ │ - this.name = newName; │ │ │ │ - if (this.map != null) { │ │ │ │ - this.map.events.triggerEvent("changelayer", { │ │ │ │ - layer: this, │ │ │ │ - property: "name" │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 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()); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: addOptions │ │ │ │ + * Method: createMarker │ │ │ │ + * HACK - we need to decide if all vector features should be able to │ │ │ │ + * create markers │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Marker>} For now just returns null │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + createMarker: function() { │ │ │ │ + return null; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: onMapResize │ │ │ │ - * This function can be implemented by subclasses │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - onMapResize: function() { │ │ │ │ - //this function can be implemented by subclasses │ │ │ │ + destroyMarker: function() { │ │ │ │ + // pass │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: redraw │ │ │ │ - * Redraws the layer. Returns true if the layer was redrawn, false if not. │ │ │ │ - * │ │ │ │ + * Method: createPopup │ │ │ │ + * HACK - we need to decide if all vector features should be able to │ │ │ │ + * create popups │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} The layer was redrawn. │ │ │ │ + * {<OpenLayers.Popup>} For now just returns null │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + createPopup: function() { │ │ │ │ + return null; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: moveTo │ │ │ │ + * Method: atPoint │ │ │ │ + * Determins whether the feature intersects with the specified location. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to │ │ │ │ - * do some init work in that case. │ │ │ │ - * dragging - {Boolean} │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - var display = this.visibility; │ │ │ │ - if (!this.isBaseLayer) { │ │ │ │ - display = display && this.inRange; │ │ │ │ + atPoint: function(lonlat, toleranceLon, toleranceLat) { │ │ │ │ + var atPoint = false; │ │ │ │ + if (this.geometry) { │ │ │ │ + atPoint = this.geometry.atPoint(lonlat, toleranceLon, │ │ │ │ + toleranceLat); │ │ │ │ } │ │ │ │ - this.display(display); │ │ │ │ + return atPoint; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: destroyPopup │ │ │ │ + * HACK - we need to decide if all vector features should be able to │ │ │ │ + * delete popups │ │ │ │ */ │ │ │ │ - moveByPx: function(dx, dy) {}, │ │ │ │ + destroyPopup: function() { │ │ │ │ + // pass │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + * Method: move │ │ │ │ + * Moves the feature and redraws it at its new location │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * location - {<OpenLayers.LonLat> or <OpenLayers.Pixel>} the │ │ │ │ + * location to which to move the feature. │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - if (this.map == null) { │ │ │ │ + move: function(location) { │ │ │ │ │ │ │ │ - this.map = map; │ │ │ │ + if (!this.layer || !this.geometry.move) { │ │ │ │ + //do nothing if no layer or immoveable geometry │ │ │ │ + return undefined; │ │ │ │ + } │ │ │ │ │ │ │ │ - // 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; │ │ │ │ + var pixel; │ │ │ │ + if (location.CLASS_NAME == "OpenLayers.LonLat") { │ │ │ │ + pixel = this.layer.getViewPortPxFromLonLat(location); │ │ │ │ + } else { │ │ │ │ + pixel = location; │ │ │ │ + } │ │ │ │ │ │ │ │ - this.projection = this.projection || this.map.projection; │ │ │ │ - if (typeof this.projection == "string") { │ │ │ │ - this.projection = new OpenLayers.Projection(this.projection); │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - // 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; │ │ │ │ + CLASS_NAME: "OpenLayers.Feature.Vector" │ │ │ │ +}); │ │ │ │ │ │ │ │ - this.initResolutions(); │ │ │ │ │ │ │ │ - if (!this.isBaseLayer) { │ │ │ │ - this.inRange = this.calculateInRange(); │ │ │ │ - var show = ((this.visibility) && (this.inRange)); │ │ │ │ - this.div.style.display = show ? "" : "none"; │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * 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 │ │ │ │ │ │ │ │ - // deal with gutters │ │ │ │ - this.setTileSize(); │ │ │ │ - } │ │ │ │ }, │ │ │ │ + '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({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: id │ │ │ │ + * {String} A unique id for this session. │ │ │ │ */ │ │ │ │ - afterAdd: function() {}, │ │ │ │ + id: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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>} │ │ │ │ + * APIProperty: name │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - removeMap: function(map) { │ │ │ │ - //to be overridden by subclasses │ │ │ │ - }, │ │ │ │ + name: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: title │ │ │ │ + * {String} Title of this style (set if included in SLD) │ │ │ │ */ │ │ │ │ - getImageSize: function(bounds) { │ │ │ │ - return (this.imageSize || this.tileSize); │ │ │ │ - }, │ │ │ │ + title: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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>} │ │ │ │ + * Property: description │ │ │ │ + * {String} Description of this style (set if abstract is included in SLD) │ │ │ │ */ │ │ │ │ - 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)); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + description: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getVisibility │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The layer should be displayed (if in range). │ │ │ │ + * APIProperty: layerName │ │ │ │ + * {<String>} name of the layer that this style belongs to, usually │ │ │ │ + * according to the NamedLayer attribute of an SLD document. │ │ │ │ */ │ │ │ │ - getVisibility: function() { │ │ │ │ - return this.visibility; │ │ │ │ - }, │ │ │ │ + layerName: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) │ │ │ │ + /** │ │ │ │ + * APIProperty: isDefault │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + isDefault: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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} │ │ │ │ + * Property: rules │ │ │ │ + * {Array(<OpenLayers.Rule>)} │ │ │ │ */ │ │ │ │ - display: function(display) { │ │ │ │ - if (display != (this.div.style.display != "none")) { │ │ │ │ - this.div.style.display = (display && this.calculateInRange()) ? "block" : "none"; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + rules: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - calculateInRange: function() { │ │ │ │ - var inRange = false; │ │ │ │ + context: null, │ │ │ │ │ │ │ │ - if (this.alwaysInRange) { │ │ │ │ - inRange = true; │ │ │ │ - } else { │ │ │ │ - if (this.map) { │ │ │ │ - var resolution = this.map.getResolution(); │ │ │ │ - inRange = ((resolution >= this.minResolution) && │ │ │ │ - (resolution <= this.maxResolution)); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return inRange; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: setIsBaseLayer │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * isBaseLayer - {Boolean} │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - setIsBaseLayer: function(isBaseLayer) { │ │ │ │ - if (isBaseLayer != this.isBaseLayer) { │ │ │ │ - this.isBaseLayer = isBaseLayer; │ │ │ │ - if (this.map != null) { │ │ │ │ - this.map.events.triggerEvent("changebaselayer", { │ │ │ │ - layer: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 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, │ │ │ │ │ │ │ │ - /********************************************************/ │ │ │ │ - /* */ │ │ │ │ - /* 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. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * 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 │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Style>} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + initialize: function(style, options) { │ │ │ │ │ │ │ │ - // 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); │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + this.rules = []; │ │ │ │ + if (options && options.rules) { │ │ │ │ + this.addRules(options.rules); │ │ │ │ } │ │ │ │ │ │ │ │ - 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]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + // 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.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); │ │ │ │ - } │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: resolutionsFromScales │ │ │ │ - * Derive resolutions from scales. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * scales - {Array(Number)} Scales │ │ │ │ - * │ │ │ │ - * Returns │ │ │ │ - * {Array(Number)} Resolutions │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + destroy: function() { │ │ │ │ + for (var i = 0, len = this.rules.length; i < len; i++) { │ │ │ │ + this.rules[i].destroy(); │ │ │ │ + this.rules[i] = null; │ │ │ │ } │ │ │ │ - return resolutions; │ │ │ │ + this.rules = null; │ │ │ │ + this.defaultStyle = null; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: calculateResolutions │ │ │ │ - * Calculate resolutions based on the provided properties. │ │ │ │ - * │ │ │ │ + * Method: createSymbolizer │ │ │ │ + * creates a style by applying all feature-dependent rules to the base │ │ │ │ + * style. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * props - {Object} Properties │ │ │ │ - * │ │ │ │ + * feature - {<OpenLayers.Feature>} feature to evaluate rules for │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Array({Number})} Array of resolutions. │ │ │ │ + * {Object} symbolizer hash │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + createSymbolizer: function(feature) { │ │ │ │ + var style = this.defaultsPerSymbolizer ? {} : this.createLiterals( │ │ │ │ + OpenLayers.Util.extend({}, this.defaultStyle), feature); │ │ │ │ │ │ │ │ - // 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); │ │ │ │ - } │ │ │ │ + var rules = this.rules; │ │ │ │ │ │ │ │ - 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 │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + 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); │ │ │ │ │ │ │ │ - // 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; │ │ │ │ + if (applies) { │ │ │ │ + if (rule instanceof OpenLayers.Rule && rule.elseFilter) { │ │ │ │ + elseRules.push(rule); │ │ │ │ + } else { │ │ │ │ + appliedRules = true; │ │ │ │ + this.applySymbolizer(rule, style, feature); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ │ │ │ │ - // are we able to calculate resolutions? │ │ │ │ - if (typeof numZoomLevels !== "number" || numZoomLevels <= 0 || │ │ │ │ - (typeof maxResolution !== "number" && │ │ │ │ - typeof minResolution !== "number")) { │ │ │ │ - return; │ │ │ │ + // 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); │ │ │ │ + } │ │ │ │ } │ │ │ │ │ │ │ │ - // 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)) │ │ │ │ - ); │ │ │ │ + // don't display if there were rules but none applied │ │ │ │ + if (rules.length > 0 && appliedRules == false) { │ │ │ │ + style.display = "none"; │ │ │ │ } │ │ │ │ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + if (style.label != null && typeof style.label !== "string") { │ │ │ │ + style.label = String(style.label); │ │ │ │ } │ │ │ │ │ │ │ │ - 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(); │ │ │ │ + return style; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getZoomForExtent │ │ │ │ - * │ │ │ │ + * Method: applySymbolizer │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * rule - {<OpenLayers.Rule>} │ │ │ │ + * style - {Object} │ │ │ │ + * feature - {<OpenLayer.Feature.Vector>} │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * {Object} A style with new symbolizer applied. │ │ │ │ */ │ │ │ │ - getZoomForExtent: function(extent, closest) { │ │ │ │ - var viewSize = this.map.getSize(); │ │ │ │ - var idealResolution = Math.max(extent.getWidth() / viewSize.w, │ │ │ │ - extent.getHeight() / viewSize.h); │ │ │ │ + applySymbolizer: function(rule, style, feature) { │ │ │ │ + var symbolizerPrefix = feature.geometry ? │ │ │ │ + this.getSymbolizerPrefix(feature.geometry) : │ │ │ │ + OpenLayers.Style.SYMBOLIZER_PREFIXES[0]; │ │ │ │ │ │ │ │ - return this.getZoomForResolution(idealResolution, closest); │ │ │ │ - }, │ │ │ │ + var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 │ │ │ │ + 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); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getResolutionForZoom │ │ │ │ + * Method: createLiterals │ │ │ │ + * creates literals for all style properties that have an entry in │ │ │ │ + * <this.propertyStyles>. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * zoom - {Float} │ │ │ │ + * style - {Object} style to create literals for. Will be modified │ │ │ │ + * inline. │ │ │ │ + * feature - {Object} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Float} A suitable resolution for the specified zoom. │ │ │ │ + * {Object} the modified style │ │ │ │ */ │ │ │ │ - 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)]; │ │ │ │ + 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 resolution; │ │ │ │ + return style; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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: │ │ │ │ - * {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. │ │ │ │ + * {Object} hash of property names that need createLiteral parsing. The │ │ │ │ + * name of the property is the key, and the value is true; │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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 { │ │ │ │ - if (this.resolutions[i] < resolution) { │ │ │ │ - break; │ │ │ │ - } │ │ │ │ + // symbolizer is a hash of style properties │ │ │ │ + this.addPropertyStyles(propertyStyles, symbolizer); │ │ │ │ + break; │ │ │ │ } │ │ │ │ } │ │ │ │ - zoom = Math.max(0, i - 1); │ │ │ │ } │ │ │ │ - return zoom; │ │ │ │ + return propertyStyles; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getLonLatFromViewPortPx │ │ │ │ + * Method: addPropertyStyles │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * viewPortPx - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or │ │ │ │ - * an object with a 'x' │ │ │ │ - * and 'y' properties. │ │ │ │ - * │ │ │ │ + * propertyStyles - {Object} hash to add new property styles to. Will be │ │ │ │ + * modified inline │ │ │ │ + * symbolizer - {Object} search this symbolizer for property styles │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in │ │ │ │ - * view port <OpenLayers.Pixel>, translated into lon/lat by the layer. │ │ │ │ + * {Object} propertyStyles hash │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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 lonlat; │ │ │ │ + return propertyStyles; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getViewPortPxFromLonLat │ │ │ │ - * Returns a pixel location given a map location. This method will return │ │ │ │ - * fractional pixel values. │ │ │ │ + * APIMethod: addRules │ │ │ │ + * Adds rules to this style. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * rules - {Array(<OpenLayers.Rule>)} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + addRules: function(rules) { │ │ │ │ + Array.prototype.push.apply(this.rules, rules); │ │ │ │ + this.propertyStyles = this.findPropertyStyles(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setOpacity │ │ │ │ - * Sets the opacity for the entire layer (all images) │ │ │ │ + * APIMethod: setDefaultStyle │ │ │ │ + * Sets the default style for this style object. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * opacity - {Float} │ │ │ │ + * style - {Object} Hash of style properties │ │ │ │ */ │ │ │ │ - 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" │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + setDefaultStyle: function(style) { │ │ │ │ + this.defaultStyle = style; │ │ │ │ + this.propertyStyles = this.findPropertyStyles(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getZIndex │ │ │ │ + * Method: getSymbolizerPrefix │ │ │ │ + * Returns the correct symbolizer prefix according to the │ │ │ │ + * geometry type of the passed geometry │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} the z-index of this layer │ │ │ │ - */ │ │ │ │ - getZIndex: function() { │ │ │ │ - return this.div.style.zIndex; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setZIndex │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * zIndex - {Integer} │ │ │ │ + * Returns: │ │ │ │ + * {String} key of the according symbolizer │ │ │ │ */ │ │ │ │ - setZIndex: function(zIndex) { │ │ │ │ - this.div.style.zIndex = zIndex; │ │ │ │ + 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]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: clone │ │ │ │ + * Clones this style. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Style>} Clone of this style. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - │ │ │ │ + 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()); │ │ │ │ + } │ │ │ │ } │ │ │ │ - return bounds; │ │ │ │ + // 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.Layer" │ │ │ │ + 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/Layer/HTTPRequest.js │ │ │ │ + OpenLayers/Rule.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/BaseTypes/Class.js │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ + * @requires OpenLayers/Style.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.HTTPRequest │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer> │ │ │ │ + * Class: OpenLayers.Rule │ │ │ │ + * This class represents an SLD Rule, as being used for rule-based SLD styling. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ +OpenLayers.Rule = OpenLayers.Class({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * Property: id │ │ │ │ + * {String} A unique id for this session. │ │ │ │ */ │ │ │ │ - URL_HASH_FACTOR: (Math.sqrt(5) - 1) / 2, │ │ │ │ + id: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: url │ │ │ │ - * {Array(String) or String} This is either an array of url strings or │ │ │ │ - * a single url string. │ │ │ │ + /** │ │ │ │ + * APIProperty: name │ │ │ │ + * {String} name of this rule │ │ │ │ */ │ │ │ │ - url: null, │ │ │ │ + name: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: params │ │ │ │ - * {Object} Hashtable of key/value parameters │ │ │ │ + /** │ │ │ │ + * Property: title │ │ │ │ + * {String} Title of this rule (set if included in SLD) │ │ │ │ */ │ │ │ │ - params: null, │ │ │ │ + title: 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. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Property: description │ │ │ │ + * {String} Description of this rule (set if abstract is included in SLD) │ │ │ │ */ │ │ │ │ - reproject: false, │ │ │ │ + description: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Property: context │ │ │ │ + * {Object} An optional object with properties that the rule should be │ │ │ │ + * evaluated against. If no context is specified, feature.attributes will │ │ │ │ + * be used. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + context: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ + * Property: filter │ │ │ │ + * {<OpenLayers.Filter>} Optional filter for the rule. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - this.url = null; │ │ │ │ - this.params = null; │ │ │ │ - OpenLayers.Layer.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + filter: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * obj - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.HTTPRequest>} An exact clone of this │ │ │ │ - * <OpenLayers.Layer.HTTPRequest> │ │ │ │ + * Property: elseFilter │ │ │ │ + * {Boolean} Determines whether this rule is only to be applied only if │ │ │ │ + * no other rules match (ElseFilter according to the SLD specification). │ │ │ │ + * Default is false. For instances of OpenLayers.Rule, if elseFilter is │ │ │ │ + * false, the rule will always apply. For subclasses, the else property is │ │ │ │ + * ignored. │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ + elseFilter: false, │ │ │ │ │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.HTTPRequest(this.name, │ │ │ │ - this.url, │ │ │ │ - this.params, │ │ │ │ - this.getOptions()); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: symbolizer │ │ │ │ + * {Object} Symbolizer or hash of symbolizers for this rule. If hash of │ │ │ │ + * symbolizers, keys are one or more of ["Point", "Line", "Polygon"]. The │ │ │ │ + * latter if useful if it is required to style e.g. vertices of a line │ │ │ │ + * with a point symbolizer. Note, however, that this is not implemented │ │ │ │ + * yet in OpenLayers, but it is the way how symbolizers are defined in │ │ │ │ + * SLD. │ │ │ │ + */ │ │ │ │ + symbolizer: null, │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]); │ │ │ │ + /** │ │ │ │ + * Property: symbolizers │ │ │ │ + * {Array} Collection of symbolizers associated with this rule. If │ │ │ │ + * provided at construction, the symbolizers array has precedence │ │ │ │ + * over the deprecated symbolizer property. Note that multiple │ │ │ │ + * symbolizers are not currently supported by the vector renderers. │ │ │ │ + * Rules with multiple symbolizers are currently only useful for │ │ │ │ + * maintaining elements in an SLD document. │ │ │ │ + */ │ │ │ │ + symbolizers: null, │ │ │ │ │ │ │ │ - // copy/set any non-init, non-simple values here │ │ │ │ + /** │ │ │ │ + * APIProperty: minScaleDenominator │ │ │ │ + * {Number} or {String} minimum scale at which to draw the feature. │ │ │ │ + * In the case of a String, this can be a combination of text and │ │ │ │ + * propertyNames in the form "literal ${propertyName}" │ │ │ │ + */ │ │ │ │ + minScaleDenominator: null, │ │ │ │ │ │ │ │ - return obj; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * APIProperty: maxScaleDenominator │ │ │ │ + * {Number} or {String} maximum scale at which to draw the feature. │ │ │ │ + * In the case of a String, this can be a combination of text and │ │ │ │ + * propertyNames in the form "literal ${propertyName}" │ │ │ │ + */ │ │ │ │ + maxScaleDenominator: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setUrl │ │ │ │ - * │ │ │ │ + * Constructor: OpenLayers.Rule │ │ │ │ + * Creates a Rule. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * newUrl - {String} │ │ │ │ - */ │ │ │ │ - setUrl: function(newUrl) { │ │ │ │ - this.url = newUrl; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: mergeNewParams │ │ │ │ + * options - {Object} An optional object with properties to set on the │ │ │ │ + * rule │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * newParams - {Object} │ │ │ │ - * │ │ │ │ * Returns: │ │ │ │ - * redrawn: {Boolean} whether the layer was actually redrawn. │ │ │ │ + * {<OpenLayers.Rule>} │ │ │ │ */ │ │ │ │ - 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" │ │ │ │ - }); │ │ │ │ + initialize: function(options) { │ │ │ │ + this.symbolizer = {}; │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + if (this.symbolizers) { │ │ │ │ + delete this.symbolizer; │ │ │ │ } │ │ │ │ - return ret; │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ */ │ │ │ │ - redraw: function(force) { │ │ │ │ - if (force) { │ │ │ │ - return this.mergeNewParams({ │ │ │ │ - "_olSalt": Math.random() │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - return OpenLayers.Layer.prototype.redraw.apply(this, []); │ │ │ │ + destroy: function() { │ │ │ │ + for (var i in this.symbolizer) { │ │ │ │ + this.symbolizer[i] = null; │ │ │ │ } │ │ │ │ + this.symbolizer = null; │ │ │ │ + delete this.symbolizers; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + * APIMethod: evaluate │ │ │ │ + * evaluates this rule for a specific feature │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * paramString - {String} │ │ │ │ - * urls - {Array(String)} │ │ │ │ + * feature - {<OpenLayers.Feature>} feature to apply the rule to. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} An entry from the urls array, deterministically selected based │ │ │ │ - * on the paramString. │ │ │ │ + * {Boolean} true if the rule applies, false if it does not. │ │ │ │ + * This rule is the default rule and always returns true. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + evaluate: function(feature) { │ │ │ │ + var context = this.getContext(feature); │ │ │ │ + var applies = true; │ │ │ │ + │ │ │ │ + if (this.minScaleDenominator || this.maxScaleDenominator) { │ │ │ │ + var scale = feature.layer.map.getScale(); │ │ │ │ } │ │ │ │ - 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) { │ │ │ │ + // check if within minScale/maxScale bounds │ │ │ │ + if (this.minScaleDenominator) { │ │ │ │ + applies = scale >= OpenLayers.Style.createLiteral( │ │ │ │ + this.minScaleDenominator, context); │ │ │ │ + } │ │ │ │ + if (applies && this.maxScaleDenominator) { │ │ │ │ + applies = scale < OpenLayers.Style.createLiteral( │ │ │ │ + this.maxScaleDenominator, context); │ │ │ │ + } │ │ │ │ │ │ │ │ - // if not altUrl passed in, use layer's url │ │ │ │ - var url = altUrl || this.url; │ │ │ │ + // check if optional filter applies │ │ │ │ + if (applies && this.filter) { │ │ │ │ + // feature id filters get the feature, others get the context │ │ │ │ + if (this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") { │ │ │ │ + applies = this.filter.evaluate(feature); │ │ │ │ + } else { │ │ │ │ + applies = this.filter.evaluate(context); │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - // 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); │ │ │ │ + return applies; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // 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); │ │ │ │ + /** │ │ │ │ + * Method: getContext │ │ │ │ + * Gets the context for evaluating this rule │ │ │ │ + * │ │ │ │ + * Paramters: │ │ │ │ + * feature - {<OpenLayers.Feature>} feature to take the context from if │ │ │ │ + * none is specified. │ │ │ │ + */ │ │ │ │ + getContext: function(feature) { │ │ │ │ + var context = this.context; │ │ │ │ + if (!context) { │ │ │ │ + context = feature.attributes || feature.data; │ │ │ │ + } │ │ │ │ + if (typeof this.context == "function") { │ │ │ │ + context = this.context(feature); │ │ │ │ } │ │ │ │ + return context; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // 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]; │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * Clones this rule. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Rule>} Clone of this rule. │ │ │ │ + */ │ │ │ │ + clone: function() { │ │ │ │ + var options = OpenLayers.Util.extend({}, this); │ │ │ │ + if (this.symbolizers) { │ │ │ │ + // clone symbolizers │ │ │ │ + var len = this.symbolizers.length; │ │ │ │ + options.symbolizers = new Array(len); │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ + options.symbolizers[i] = this.symbolizers[i].clone(); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + // clone symbolizer │ │ │ │ + options.symbolizer = {}; │ │ │ │ + var value, type; │ │ │ │ + for (var key in this.symbolizer) { │ │ │ │ + value = this.symbolizer[key]; │ │ │ │ + type = typeof value; │ │ │ │ + if (type === "object") { │ │ │ │ + options.symbolizer[key] = OpenLayers.Util.extend({}, value); │ │ │ │ + } else if (type === "string") { │ │ │ │ + options.symbolizer[key] = value; │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ - paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ - │ │ │ │ - return OpenLayers.Util.urlAppend(url, paramsString); │ │ │ │ + // clone filter │ │ │ │ + options.filter = this.filter && this.filter.clone(); │ │ │ │ + // clone context │ │ │ │ + options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ + return new OpenLayers.Rule(options); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.HTTPRequest" │ │ │ │ + CLASS_NAME: "OpenLayers.Rule" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Tile.js │ │ │ │ + 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/Util.js │ │ │ │ + * @requires OpenLayers/Style.js │ │ │ │ + * @requires OpenLayers/Feature/Vector.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 │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.StyleMap │ │ │ │ */ │ │ │ │ -OpenLayers.Tile = OpenLayers.Class({ │ │ │ │ +OpenLayers.StyleMap = 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. │ │ │ │ + * Property: styles │ │ │ │ + * {Object} Hash of {<OpenLayers.Style>}, keyed by names of well known │ │ │ │ + * rendering intents (e.g. "default", "temporary", "select", "delete"). │ │ │ │ */ │ │ │ │ - events: null, │ │ │ │ + styles: 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) │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - eventListeners: null, │ │ │ │ + extendDefault: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: id │ │ │ │ - * {String} null │ │ │ │ - */ │ │ │ │ - id: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: layer │ │ │ │ - * {<OpenLayers.Layer>} layer the tile is attached to │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - layer: null, │ │ │ │ + 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"]) │ │ │ │ + }; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: url │ │ │ │ - * {String} url of the request. │ │ │ │ - * │ │ │ │ + // 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/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/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/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/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/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/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/Renderer/VML.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.VML │ │ │ │ + * Render vector features in browsers with VML capability. Construct a new │ │ │ │ + * VML renderer with the <OpenLayers.Renderer.VML> constructor. │ │ │ │ + * │ │ │ │ + * Note that for all calculations in this class, we use (num | 0) to truncate a │ │ │ │ + * float value to an integer. This is done because it seems that VML doesn't │ │ │ │ + * support float values. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Renderer.Elements> │ │ │ │ + */ │ │ │ │ +OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: xmlns │ │ │ │ + * {String} XML Namespace URN │ │ │ │ + */ │ │ │ │ + xmlns: "urn:schemas-microsoft-com:vml", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: symbolCache │ │ │ │ + * {DOMElement} node holding symbols. This hash is keyed by symbol name, │ │ │ │ + * and each value is a hash with a "path" and an "extent" property. │ │ │ │ + */ │ │ │ │ + symbolCache: {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: offset │ │ │ │ + * {Object} Hash with "x" and "y" properties │ │ │ │ + */ │ │ │ │ + offset: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Renderer.VML │ │ │ │ + * Create a new VML renderer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * containerID - {String} The id for the element that contains the renderer │ │ │ │ + */ │ │ │ │ + initialize: function(containerID) { │ │ │ │ + if (!this.supported()) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + if (!document.namespaces.olv) { │ │ │ │ + document.namespaces.add("olv", this.xmlns); │ │ │ │ + var style = document.createStyleSheet(); │ │ │ │ + var shapes = ['shape', 'rect', 'oval', 'fill', 'stroke', 'imagedata', 'group', 'textbox']; │ │ │ │ + for (var i = 0, len = shapes.length; i < len; i++) { │ │ │ │ + │ │ │ │ + style.addRule('olv\\:' + shapes[i], "behavior: url(#default#VML); " + │ │ │ │ + "position: absolute; display: inline-block;"); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + OpenLayers.Renderer.Elements.prototype.initialize.apply(this, │ │ │ │ + arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: supported │ │ │ │ + * Determine whether a browser supports this renderer. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The browser supports the VML renderer │ │ │ │ + */ │ │ │ │ + supported: function() { │ │ │ │ + return !!(document.namespaces); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setExtent │ │ │ │ + * Set the renderer's extent │ │ │ │ + * │ │ │ │ + * 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. │ │ │ │ + */ │ │ │ │ + setExtent: function(extent, resolutionChanged) { │ │ │ │ + var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + │ │ │ │ + var left = (extent.left / resolution) | 0; │ │ │ │ + var top = (extent.top / resolution - this.size.h) | 0; │ │ │ │ + if (resolutionChanged || !this.offset) { │ │ │ │ + this.offset = { │ │ │ │ + x: left, │ │ │ │ + y: top │ │ │ │ + }; │ │ │ │ + left = 0; │ │ │ │ + top = 0; │ │ │ │ + } else { │ │ │ │ + left = left - this.offset.x; │ │ │ │ + top = top - this.offset.y; │ │ │ │ + } │ │ │ │ + │ │ │ │ + │ │ │ │ + var org = (left - this.xOffset) + " " + top; │ │ │ │ + this.root.coordorigin = org; │ │ │ │ + var roots = [this.root, this.vectorRoot, this.textRoot]; │ │ │ │ + var root; │ │ │ │ + for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ + root = roots[i]; │ │ │ │ + │ │ │ │ + var size = this.size.w + " " + this.size.h; │ │ │ │ + root.coordsize = size; │ │ │ │ + │ │ │ │ + } │ │ │ │ + // flip the VML display Y axis upside down so it │ │ │ │ + // matches the display Y axis of the map │ │ │ │ + this.root.style.flip = "y"; │ │ │ │ + │ │ │ │ + return coordSysUnchanged; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setSize │ │ │ │ + * Set 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); │ │ │ │ + │ │ │ │ + // setting width and height on all roots to avoid flicker which we │ │ │ │ + // would get with 100% width and height on child roots │ │ │ │ + var roots = [ │ │ │ │ + this.rendererRoot, │ │ │ │ + this.root, │ │ │ │ + this.vectorRoot, │ │ │ │ + this.textRoot │ │ │ │ + ]; │ │ │ │ + var w = this.size.w + "px"; │ │ │ │ + var h = this.size.h + "px"; │ │ │ │ + var root; │ │ │ │ + for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ + root = roots[i]; │ │ │ │ + root.style.width = w; │ │ │ │ + root.style.height = h; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getNodeType │ │ │ │ + * Get the node type for a geometry and style │ │ │ │ + * │ │ │ │ + * 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 = "olv:rect"; │ │ │ │ + } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ + nodeType = "olv:shape"; │ │ │ │ + } else { │ │ │ │ + nodeType = "olv:oval"; │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case "OpenLayers.Geometry.Rectangle": │ │ │ │ + nodeType = "olv:rect"; │ │ │ │ + break; │ │ │ │ + case "OpenLayers.Geometry.LineString": │ │ │ │ + case "OpenLayers.Geometry.LinearRing": │ │ │ │ + case "OpenLayers.Geometry.Polygon": │ │ │ │ + case "OpenLayers.Geometry.Curve": │ │ │ │ + nodeType = "olv:shape"; │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + return nodeType; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setStyle │ │ │ │ + * Use to set all the style attributes to a VML node. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} An VML element to decorate │ │ │ │ + * style - {Object} │ │ │ │ + * options - {Object} Currently supported options include │ │ │ │ + * 'isFilled' {Boolean} and │ │ │ │ + * 'isStroked' {Boolean} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + */ │ │ │ │ + setStyle: function(node, style, options, geometry) { │ │ │ │ + style = style || node._style; │ │ │ │ + options = options || node._options; │ │ │ │ + var fillColor = style.fillColor; │ │ │ │ + │ │ │ │ + var title = style.title || style.graphicTitle; │ │ │ │ + if (title) { │ │ │ │ + node.title = title; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + options.isFilled = true; │ │ │ │ + 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 resolution = this.getResolution(); │ │ │ │ + var xOffset = (style.graphicXOffset != undefined) ? │ │ │ │ + style.graphicXOffset : -(0.5 * width); │ │ │ │ + var yOffset = (style.graphicYOffset != undefined) ? │ │ │ │ + style.graphicYOffset : -(0.5 * height); │ │ │ │ + │ │ │ │ + node.style.left = ((((geometry.x - this.featureDx) / resolution - this.offset.x) + xOffset) | 0) + "px"; │ │ │ │ + node.style.top = (((geometry.y / resolution - this.offset.y) - (yOffset + height)) | 0) + "px"; │ │ │ │ + node.style.width = width + "px"; │ │ │ │ + node.style.height = height + "px"; │ │ │ │ + node.style.flip = "y"; │ │ │ │ + │ │ │ │ + // modify fillColor and options for stroke styling below │ │ │ │ + fillColor = "none"; │ │ │ │ + options.isStroked = false; │ │ │ │ + } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ + var cache = this.importSymbol(style.graphicName); │ │ │ │ + node.path = cache.path; │ │ │ │ + node.coordorigin = cache.left + "," + cache.bottom; │ │ │ │ + var size = cache.size; │ │ │ │ + node.coordsize = size + "," + size; │ │ │ │ + this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ + node.style.flip = "y"; │ │ │ │ + } else { │ │ │ │ + this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // fill │ │ │ │ + if (options.isFilled) { │ │ │ │ + node.fillcolor = fillColor; │ │ │ │ + } else { │ │ │ │ + node.filled = "false"; │ │ │ │ + } │ │ │ │ + var fills = node.getElementsByTagName("fill"); │ │ │ │ + var fill = (fills.length == 0) ? null : fills[0]; │ │ │ │ + if (!options.isFilled) { │ │ │ │ + if (fill) { │ │ │ │ + node.removeChild(fill); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (!fill) { │ │ │ │ + fill = this.createNode('olv:fill', node.id + "_fill"); │ │ │ │ + } │ │ │ │ + fill.opacity = style.fillOpacity; │ │ │ │ + │ │ │ │ + if (node._geometryClass === "OpenLayers.Geometry.Point" && │ │ │ │ + style.externalGraphic) { │ │ │ │ + │ │ │ │ + // override fillOpacity │ │ │ │ + if (style.graphicOpacity) { │ │ │ │ + fill.opacity = style.graphicOpacity; │ │ │ │ + } │ │ │ │ + │ │ │ │ + fill.src = style.externalGraphic; │ │ │ │ + fill.type = "frame"; │ │ │ │ + │ │ │ │ + if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ + fill.aspect = "atmost"; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (fill.parentNode != node) { │ │ │ │ + node.appendChild(fill); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // additional rendering for rotated graphics or symbols │ │ │ │ + var rotation = style.rotation; │ │ │ │ + if ((rotation !== undefined || node._rotation !== undefined)) { │ │ │ │ + node._rotation = rotation; │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ + // make the fill fully transparent, because we now have │ │ │ │ + // the graphic as imagedata element. We cannot just remove │ │ │ │ + // the fill, because this is part of the hack described │ │ │ │ + // in graphicRotate │ │ │ │ + fill.opacity = 0; │ │ │ │ + } else if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ + node.style.rotation = rotation || 0; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // stroke │ │ │ │ + var strokes = node.getElementsByTagName("stroke"); │ │ │ │ + var stroke = (strokes.length == 0) ? null : strokes[0]; │ │ │ │ + if (!options.isStroked) { │ │ │ │ + node.stroked = false; │ │ │ │ + if (stroke) { │ │ │ │ + stroke.on = false; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (!stroke) { │ │ │ │ + stroke = this.createNode('olv:stroke', node.id + "_stroke"); │ │ │ │ + node.appendChild(stroke); │ │ │ │ + } │ │ │ │ + stroke.on = true; │ │ │ │ + stroke.color = style.strokeColor; │ │ │ │ + stroke.weight = style.strokeWidth + "px"; │ │ │ │ + stroke.opacity = style.strokeOpacity; │ │ │ │ + stroke.endcap = style.strokeLinecap == 'butt' ? 'flat' : │ │ │ │ + (style.strokeLinecap || 'round'); │ │ │ │ + if (style.strokeDashstyle) { │ │ │ │ + stroke.dashstyle = this.dashStyle(style); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ + node.style.cursor = style.cursor; │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: graphicRotate │ │ │ │ + * If a point is to be styled with externalGraphic and rotation, VML fills │ │ │ │ + * cannot be used to display the graphic, because rotation of graphic │ │ │ │ + * fills is not supported by the VML implementation of Internet Explorer. │ │ │ │ + * This method creates a olv:imagedata element inside the VML node, │ │ │ │ + * DXImageTransform.Matrix and BasicImage filters for rotation and │ │ │ │ + * opacity, and a 3-step hack to remove rendering artefacts from the │ │ │ │ + * graphic and preserve the ability of graphics to trigger events. │ │ │ │ + * Finally, OpenLayers methods are used to determine the correct │ │ │ │ + * insertion point of the rotated image, because DXImageTransform.Matrix │ │ │ │ + * does the rotation without the ability to specify a rotation center │ │ │ │ + * point. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * xOffset - {Number} rotation center relative to image, x coordinate │ │ │ │ + * yOffset - {Number} rotation center relative to image, y coordinate │ │ │ │ + * style - {Object} │ │ │ │ + */ │ │ │ │ + graphicRotate: function(node, xOffset, yOffset, style) { │ │ │ │ + var style = style || node._style; │ │ │ │ + var rotation = style.rotation || 0; │ │ │ │ + │ │ │ │ + var aspectRatio, size; │ │ │ │ + if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ + // load the image to determine its size │ │ │ │ + var img = new Image(); │ │ │ │ + img.onreadystatechange = OpenLayers.Function.bind(function() { │ │ │ │ + if (img.readyState == "complete" || │ │ │ │ + img.readyState == "interactive") { │ │ │ │ + aspectRatio = img.width / img.height; │ │ │ │ + size = Math.max(style.pointRadius * 2, │ │ │ │ + style.graphicWidth || 0, │ │ │ │ + style.graphicHeight || 0); │ │ │ │ + xOffset = xOffset * aspectRatio; │ │ │ │ + style.graphicWidth = size * aspectRatio; │ │ │ │ + style.graphicHeight = size; │ │ │ │ + this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ + } │ │ │ │ + }, this); │ │ │ │ + img.src = style.externalGraphic; │ │ │ │ + │ │ │ │ + // will be called again by the onreadystate handler │ │ │ │ + return; │ │ │ │ + } else { │ │ │ │ + size = Math.max(style.graphicWidth, style.graphicHeight); │ │ │ │ + aspectRatio = style.graphicWidth / style.graphicHeight; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var width = Math.round(style.graphicWidth || size * aspectRatio); │ │ │ │ + var height = Math.round(style.graphicHeight || size); │ │ │ │ + node.style.width = width + "px"; │ │ │ │ + node.style.height = height + "px"; │ │ │ │ + │ │ │ │ + // Three steps are required to remove artefacts for images with │ │ │ │ + // transparent backgrounds (resulting from using DXImageTransform │ │ │ │ + // filters on svg objects), while preserving awareness for browser │ │ │ │ + // events on images: │ │ │ │ + // - Use the fill as usual (like for unrotated images) to handle │ │ │ │ + // events │ │ │ │ + // - specify an imagedata element with the same src as the fill │ │ │ │ + // - style the imagedata element with an AlphaImageLoader filter │ │ │ │ + // with empty src │ │ │ │ + var image = document.getElementById(node.id + "_image"); │ │ │ │ + if (!image) { │ │ │ │ + image = this.createNode("olv:imagedata", node.id + "_image"); │ │ │ │ + node.appendChild(image); │ │ │ │ + } │ │ │ │ + image.style.width = width + "px"; │ │ │ │ + image.style.height = height + "px"; │ │ │ │ + image.src = style.externalGraphic; │ │ │ │ + image.style.filter = │ │ │ │ + "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + │ │ │ │ + "src='', sizingMethod='scale')"; │ │ │ │ + │ │ │ │ + var rot = rotation * Math.PI / 180; │ │ │ │ + var sintheta = Math.sin(rot); │ │ │ │ + var costheta = Math.cos(rot); │ │ │ │ + │ │ │ │ + // do the rotation on the image │ │ │ │ + var filter = │ │ │ │ + "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta + │ │ │ │ + ",M12=" + (-sintheta) + ",M21=" + sintheta + ",M22=" + costheta + │ │ │ │ + ",SizingMethod='auto expand')\n"; │ │ │ │ + │ │ │ │ + // set the opacity (needed for the imagedata) │ │ │ │ + var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ + if (opacity && opacity != 1) { │ │ │ │ + filter += │ │ │ │ + "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + │ │ │ │ + opacity + ")\n"; │ │ │ │ + } │ │ │ │ + node.style.filter = filter; │ │ │ │ + │ │ │ │ + // do the rotation again on a box, so we know the insertion point │ │ │ │ + var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset); │ │ │ │ + var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry(); │ │ │ │ + imgBox.rotate(style.rotation, centerPoint); │ │ │ │ + var imgBounds = imgBox.getBounds(); │ │ │ │ + │ │ │ │ + node.style.left = Math.round( │ │ │ │ + parseInt(node.style.left) + imgBounds.left) + "px"; │ │ │ │ + node.style.top = Math.round( │ │ │ │ + parseInt(node.style.top) - imgBounds.bottom) + "px"; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: postDraw │ │ │ │ + * Does some node postprocessing to work around browser issues: │ │ │ │ + * - Some versions of Internet Explorer seem to be unable to set fillcolor │ │ │ │ + * and strokecolor to "none" correctly before the fill node is appended │ │ │ │ + * to a visible vml node. This method takes care of that and sets │ │ │ │ + * fillcolor and strokecolor again if needed. │ │ │ │ + * - In some cases, a node won't become visible after being drawn. Setting │ │ │ │ + * style.visibility to "visible" works around that. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + */ │ │ │ │ + postDraw: function(node) { │ │ │ │ + node.style.visibility = "visible"; │ │ │ │ + var fillColor = node._style.fillColor; │ │ │ │ + var strokeColor = node._style.strokeColor; │ │ │ │ + if (fillColor == "none" && │ │ │ │ + node.fillcolor != fillColor) { │ │ │ │ + node.fillcolor = fillColor; │ │ │ │ + } │ │ │ │ + if (strokeColor == "none" && │ │ │ │ + node.strokecolor != strokeColor) { │ │ │ │ + node.strokecolor = strokeColor; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setNodeDimension │ │ │ │ + * Get the geometry's bounds, convert it to our vml coordinate system, │ │ │ │ + * then set the node's position, size, and local coordinate system. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + */ │ │ │ │ + setNodeDimension: function(node, geometry) { │ │ │ │ + │ │ │ │ + var bbox = geometry.getBounds(); │ │ │ │ + if (bbox) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + │ │ │ │ + var scaledBox = │ │ │ │ + new OpenLayers.Bounds(((bbox.left - this.featureDx) / resolution - this.offset.x) | 0, │ │ │ │ + (bbox.bottom / resolution - this.offset.y) | 0, │ │ │ │ + ((bbox.right - this.featureDx) / resolution - this.offset.x) | 0, │ │ │ │ + (bbox.top / resolution - this.offset.y) | 0); │ │ │ │ + │ │ │ │ + // Set the internal coordinate system to draw the path │ │ │ │ + node.style.left = scaledBox.left + "px"; │ │ │ │ + node.style.top = scaledBox.top + "px"; │ │ │ │ + node.style.width = scaledBox.getWidth() + "px"; │ │ │ │ + node.style.height = scaledBox.getHeight() + "px"; │ │ │ │ + │ │ │ │ + node.coordorigin = scaledBox.left + " " + scaledBox.top; │ │ │ │ + node.coordsize = scaledBox.getWidth() + " " + scaledBox.getHeight(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: dashStyle │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * style - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A VML compliant 'stroke-dasharray' value │ │ │ │ + */ │ │ │ │ + dashStyle: function(style) { │ │ │ │ + var dash = style.strokeDashstyle; │ │ │ │ + switch (dash) { │ │ │ │ + case 'solid': │ │ │ │ + case 'dot': │ │ │ │ + case 'dash': │ │ │ │ + case 'dashdot': │ │ │ │ + case 'longdash': │ │ │ │ + case 'longdashdot': │ │ │ │ + return dash; │ │ │ │ + default: │ │ │ │ + // very basic guessing of dash style patterns │ │ │ │ + var parts = dash.split(/[ ,]/); │ │ │ │ + if (parts.length == 2) { │ │ │ │ + if (1 * parts[0] >= 2 * parts[1]) { │ │ │ │ + return "longdash"; │ │ │ │ + } │ │ │ │ + return (parts[0] == 1 || parts[1] == 1) ? "dot" : "dash"; │ │ │ │ + } else if (parts.length == 4) { │ │ │ │ + return (1 * parts[0] >= 2 * parts[1]) ? "longdashdot" : │ │ │ │ + "dashdot"; │ │ │ │ + } │ │ │ │ + return "solid"; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: createNode │ │ │ │ + * Create a new node │ │ │ │ + * │ │ │ │ + * 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.createElement(type); │ │ │ │ + if (id) { │ │ │ │ + node.id = id; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // IE hack to make elements unselectable, to prevent 'blue flash' │ │ │ │ + // while dragging vectors; #1410 │ │ │ │ + node.unselectable = 'on'; │ │ │ │ + node.onselectstart = OpenLayers.Function.False; │ │ │ │ + │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: nodeTypeCompare │ │ │ │ + * Determine whether a node is of a given type │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} An VML element │ │ │ │ + * type - {String} Kind of node │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the specified node is of the specified type │ │ │ │ + */ │ │ │ │ + nodeTypeCompare: function(node, type) { │ │ │ │ + │ │ │ │ + //split type │ │ │ │ + var subType = type; │ │ │ │ + var splitIndex = subType.indexOf(":"); │ │ │ │ + if (splitIndex != -1) { │ │ │ │ + subType = subType.substr(splitIndex + 1); │ │ │ │ + } │ │ │ │ + │ │ │ │ + //split nodeName │ │ │ │ + var nodeName = node.nodeName; │ │ │ │ + splitIndex = nodeName.indexOf(":"); │ │ │ │ + if (splitIndex != -1) { │ │ │ │ + nodeName = nodeName.substr(splitIndex + 1); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return (subType == nodeName); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: createRenderRoot │ │ │ │ + * Create the renderer root │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} The specific render engine's root element │ │ │ │ + */ │ │ │ │ + createRenderRoot: function() { │ │ │ │ + return this.nodeFactory(this.container.id + "_vmlRoot", "div"); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: createRoot │ │ │ │ + * Create the main root element │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * suffix - {String} suffix to append to the id │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + createRoot: function(suffix) { │ │ │ │ + return this.nodeFactory(this.container.id + suffix, "olv:group"); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /************************************** │ │ │ │ + * * │ │ │ │ + * GEOMETRY DRAWING FUNCTIONS * │ │ │ │ + * * │ │ │ │ + **************************************/ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: drawPoint │ │ │ │ + * Render a point │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} or false if the point could not be drawn │ │ │ │ + */ │ │ │ │ + drawPoint: function(node, geometry) { │ │ │ │ + return this.drawCircle(node, geometry, 1); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: drawCircle │ │ │ │ + * Render a circle. │ │ │ │ + * Size and Center a circle given geometry (x,y center) and radius │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * radius - {float} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} or false if the circle could not ne drawn │ │ │ │ + */ │ │ │ │ + drawCircle: function(node, geometry, radius) { │ │ │ │ + if (!isNaN(geometry.x) && !isNaN(geometry.y)) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + │ │ │ │ + node.style.left = ((((geometry.x - this.featureDx) / resolution - this.offset.x) | 0) - radius) + "px"; │ │ │ │ + node.style.top = (((geometry.y / resolution - this.offset.y) | 0) - radius) + "px"; │ │ │ │ + │ │ │ │ + var diameter = radius * 2; │ │ │ │ + │ │ │ │ + node.style.width = diameter + "px"; │ │ │ │ + node.style.height = diameter + "px"; │ │ │ │ + return node; │ │ │ │ + } │ │ │ │ + return false; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: drawLineString │ │ │ │ + * Render a linestring. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + drawLineString: function(node, geometry) { │ │ │ │ + return this.drawLine(node, geometry, false); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: drawLinearRing │ │ │ │ + * Render a linearring │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + drawLinearRing: function(node, geometry) { │ │ │ │ + return this.drawLine(node, geometry, true); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: DrawLine │ │ │ │ + * Render a line. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * closeLine - {Boolean} Close the line? (make it a ring?) │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + drawLine: function(node, geometry, closeLine) { │ │ │ │ + │ │ │ │ + this.setNodeDimension(node, geometry); │ │ │ │ + │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var numComponents = geometry.components.length; │ │ │ │ + var parts = new Array(numComponents); │ │ │ │ + │ │ │ │ + var comp, x, y; │ │ │ │ + for (var i = 0; i < numComponents; i++) { │ │ │ │ + comp = geometry.components[i]; │ │ │ │ + x = ((comp.x - this.featureDx) / resolution - this.offset.x) | 0; │ │ │ │ + y = (comp.y / resolution - this.offset.y) | 0; │ │ │ │ + parts[i] = " " + x + "," + y + " l "; │ │ │ │ + } │ │ │ │ + var end = (closeLine) ? " x e" : " e"; │ │ │ │ + node.path = "m" + parts.join("") + end; │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: drawPolygon │ │ │ │ + * Render a polygon │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + drawPolygon: function(node, geometry) { │ │ │ │ + this.setNodeDimension(node, geometry); │ │ │ │ + │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + │ │ │ │ + var path = []; │ │ │ │ + var j, jj, points, area, first, second, i, ii, comp, pathComp, x, y; │ │ │ │ + for (j = 0, jj = geometry.components.length; j < jj; j++) { │ │ │ │ + path.push("m"); │ │ │ │ + points = geometry.components[j].components; │ │ │ │ + // we only close paths of interior rings with area │ │ │ │ + area = (j === 0); │ │ │ │ + first = null; │ │ │ │ + second = null; │ │ │ │ + for (i = 0, ii = points.length; i < ii; i++) { │ │ │ │ + comp = points[i]; │ │ │ │ + x = ((comp.x - this.featureDx) / resolution - this.offset.x) | 0; │ │ │ │ + y = (comp.y / resolution - this.offset.y) | 0; │ │ │ │ + pathComp = " " + x + "," + y; │ │ │ │ + path.push(pathComp); │ │ │ │ + if (i == 0) { │ │ │ │ + path.push(" l"); │ │ │ │ + } │ │ │ │ + if (!area) { │ │ │ │ + // IE improperly renders sub-paths that have no area. │ │ │ │ + // Instead of checking the area of every ring, we confirm │ │ │ │ + // the ring has at least three distinct points. This does │ │ │ │ + // not catch all non-zero area cases, but it greatly improves │ │ │ │ + // interior ring digitizing and is a minor performance hit │ │ │ │ + // when rendering rings with many points. │ │ │ │ + if (!first) { │ │ │ │ + first = pathComp; │ │ │ │ + } else if (first != pathComp) { │ │ │ │ + if (!second) { │ │ │ │ + second = pathComp; │ │ │ │ + } else if (second != pathComp) { │ │ │ │ + // stop looking │ │ │ │ + area = true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + path.push(area ? " x " : " "); │ │ │ │ + } │ │ │ │ + path.push("e"); │ │ │ │ + node.path = path.join(""); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: drawRectangle │ │ │ │ + * Render a rectangle │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + drawRectangle: function(node, geometry) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + │ │ │ │ + node.style.left = (((geometry.x - this.featureDx) / resolution - this.offset.x) | 0) + "px"; │ │ │ │ + node.style.top = ((geometry.y / resolution - this.offset.y) | 0) + "px"; │ │ │ │ + node.style.width = ((geometry.width / resolution) | 0) + "px"; │ │ │ │ + node.style.height = ((geometry.height / resolution) | 0) + "px"; │ │ │ │ + │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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 label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect"); │ │ │ │ + var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox"); │ │ │ │ + │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + label.style.left = (((location.x - this.featureDx) / resolution - this.offset.x) | 0) + "px"; │ │ │ │ + label.style.top = ((location.y / resolution - this.offset.y) | 0) + "px"; │ │ │ │ + label.style.flip = "y"; │ │ │ │ + │ │ │ │ + textbox.innerText = style.label; │ │ │ │ + │ │ │ │ + if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ + textbox.style.cursor = style.cursor; │ │ │ │ + } │ │ │ │ + if (style.fontColor) { │ │ │ │ + textbox.style.color = style.fontColor; │ │ │ │ + } │ │ │ │ + if (style.fontOpacity) { │ │ │ │ + textbox.style.filter = 'alpha(opacity=' + (style.fontOpacity * 100) + ')'; │ │ │ │ + } │ │ │ │ + if (style.fontFamily) { │ │ │ │ + textbox.style.fontFamily = style.fontFamily; │ │ │ │ + } │ │ │ │ + if (style.fontSize) { │ │ │ │ + textbox.style.fontSize = style.fontSize; │ │ │ │ + } │ │ │ │ + if (style.fontWeight) { │ │ │ │ + textbox.style.fontWeight = style.fontWeight; │ │ │ │ + } │ │ │ │ + if (style.fontStyle) { │ │ │ │ + textbox.style.fontStyle = style.fontStyle; │ │ │ │ + } │ │ │ │ + if (style.labelSelect === true) { │ │ │ │ + label._featureId = featureId; │ │ │ │ + textbox._featureId = featureId; │ │ │ │ + textbox._geometry = location; │ │ │ │ + textbox._geometryClass = location.CLASS_NAME; │ │ │ │ + } │ │ │ │ + textbox.style.whiteSpace = "nowrap"; │ │ │ │ + // fun with IE: IE7 in standards compliant mode does not display any │ │ │ │ + // text with a left inset of 0. So we set this to 1px and subtract one │ │ │ │ + // pixel later when we set label.style.left │ │ │ │ + textbox.inset = "1px,0px,0px,0px"; │ │ │ │ + │ │ │ │ + if (!label.parentNode) { │ │ │ │ + label.appendChild(textbox); │ │ │ │ + this.textRoot.appendChild(label); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var align = style.labelAlign || "cm"; │ │ │ │ + if (align.length == 1) { │ │ │ │ + align += "m"; │ │ │ │ + } │ │ │ │ + var xshift = textbox.clientWidth * │ │ │ │ + (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0, 1)]); │ │ │ │ + var yshift = textbox.clientHeight * │ │ │ │ + (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1, 1)]); │ │ │ │ + label.style.left = parseInt(label.style.left) - xshift - 1 + "px"; │ │ │ │ + label.style.top = parseInt(label.style.top) + yshift + "px"; │ │ │ │ + │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveRoot │ │ │ │ + * moves this renderer's root to a different renderer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * renderer - {<OpenLayers.Renderer>} target renderer for the moved root │ │ │ │ + * root - {DOMElement} optional root node. To be used when this renderer │ │ │ │ + * holds roots from multiple layers to tell this method which one to │ │ │ │ + * detach │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} true if successful, false otherwise │ │ │ │ + */ │ │ │ │ + moveRoot: function(renderer) { │ │ │ │ + var layer = this.map.getLayer(renderer.container.id); │ │ │ │ + if (layer instanceof OpenLayers.Layer.Vector.RootContainer) { │ │ │ │ + layer = this.map.getLayer(this.container.id); │ │ │ │ + } │ │ │ │ + layer && layer.renderer.clear(); │ │ │ │ + OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments); │ │ │ │ + layer && layer.redraw(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: importSymbol │ │ │ │ + * add a new symbol definition from the rendererer's symbol hash │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * graphicName - {String} name of the symbol to import │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} - hash of {DOMElement} "symbol" and {Number} "size" │ │ │ │ + */ │ │ │ │ + importSymbol: function(graphicName) { │ │ │ │ + var id = this.container.id + "-" + graphicName; │ │ │ │ + │ │ │ │ + // check if symbol already exists in the cache │ │ │ │ + var cache = this.symbolCache[id]; │ │ │ │ + if (cache) { │ │ │ │ + return cache; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var symbol = OpenLayers.Renderer.symbol[graphicName]; │ │ │ │ + if (!symbol) { │ │ │ │ + throw new Error(graphicName + ' is not a valid symbol name'); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var symbolExtent = new OpenLayers.Bounds( │ │ │ │ + Number.MAX_VALUE, Number.MAX_VALUE, 0, 0); │ │ │ │ + │ │ │ │ + var pathitems = ["m"]; │ │ │ │ + for (var i = 0; i < symbol.length; i = i + 2) { │ │ │ │ + var x = symbol[i]; │ │ │ │ + var 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); │ │ │ │ + │ │ │ │ + pathitems.push(x); │ │ │ │ + pathitems.push(y); │ │ │ │ + if (i == 0) { │ │ │ │ + pathitems.push("l"); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + pathitems.push("x e"); │ │ │ │ + var path = pathitems.join(" "); │ │ │ │ + │ │ │ │ + var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2; │ │ │ │ + if (diff > 0) { │ │ │ │ + symbolExtent.bottom = symbolExtent.bottom - diff; │ │ │ │ + symbolExtent.top = symbolExtent.top + diff; │ │ │ │ + } else { │ │ │ │ + symbolExtent.left = symbolExtent.left + diff; │ │ │ │ + symbolExtent.right = symbolExtent.right - diff; │ │ │ │ + } │ │ │ │ + │ │ │ │ + cache = { │ │ │ │ + path: path, │ │ │ │ + size: symbolExtent.getWidth(), // equals getHeight() now │ │ │ │ + left: symbolExtent.left, │ │ │ │ + bottom: symbolExtent.bottom │ │ │ │ + }; │ │ │ │ + this.symbolCache[id] = cache; │ │ │ │ + │ │ │ │ + return cache; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Renderer.VML" │ │ │ │ +}); │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Renderer.VML.LABEL_SHIFT │ │ │ │ + * {Object} │ │ │ │ + */ │ │ │ │ +OpenLayers.Renderer.VML.LABEL_SHIFT = { │ │ │ │ + "l": 0, │ │ │ │ + "c": .5, │ │ │ │ + "r": 1, │ │ │ │ + "t": 0, │ │ │ │ + "m": .5, │ │ │ │ + "b": 1 │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + 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/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/Strategy/BBOX.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 │ │ │ │ + * @requires OpenLayers/Filter/Spatial.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Strategy.BBOX │ │ │ │ + * A simple strategy that reads new features when the viewport invalidates │ │ │ │ + * some bounds. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Strategy> │ │ │ │ + */ │ │ │ │ +OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: bounds │ │ │ │ + * {<OpenLayers.Bounds>} The current data bounds (in the same projection │ │ │ │ + * as the layer - not always the same projection as the map). │ │ │ │ + */ │ │ │ │ + bounds: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: resolution │ │ │ │ + * {Float} The current data resolution. │ │ │ │ + */ │ │ │ │ + resolution: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: ratio │ │ │ │ + * {Float} The ratio of the data bounds to the viewport bounds (in each │ │ │ │ + * dimension). Default is 2. │ │ │ │ + */ │ │ │ │ + ratio: 2, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: resFactor │ │ │ │ + * {Float} Optional factor used to determine when previously requested │ │ │ │ + * features are invalid. If set, the resFactor will be compared to the │ │ │ │ + * resolution of the previous request to the current map resolution. │ │ │ │ + * If resFactor > (old / new) and 1/resFactor < (old / new). If you │ │ │ │ + * set a resFactor of 1, data will be requested every time the │ │ │ │ + * resolution changes. If you set a resFactor of 3, data will be │ │ │ │ + * requested if the old resolution is 3 times the new, or if the new is │ │ │ │ + * 3 times the old. If the old bounds do not contain the new bounds │ │ │ │ + * new data will always be requested (with or without considering │ │ │ │ + * resFactor). │ │ │ │ + */ │ │ │ │ + resFactor: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: response │ │ │ │ + * {<OpenLayers.Protocol.Response>} The protocol response object returned │ │ │ │ + * by the layer protocol. │ │ │ │ + */ │ │ │ │ + response: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Strategy.BBOX │ │ │ │ + * Create a new BBOX strategy. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: activate │ │ │ │ + * Set up strategy with regard to reading new batches of remote data. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The strategy was successfully activated. │ │ │ │ + */ │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + "moveend": this.update, │ │ │ │ + "refresh": this.update, │ │ │ │ + "visibilitychanged": this.update, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.update(); │ │ │ │ + } │ │ │ │ + return activated; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: deactivate │ │ │ │ + * Tear down strategy with regard to reading new batches of remote data. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ + */ │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.layer.events.un({ │ │ │ │ + "moveend": this.update, │ │ │ │ + "refresh": this.update, │ │ │ │ + "visibilitychanged": this.update, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + return deactivated; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: update │ │ │ │ + * Callback function called on "moveend" or "refresh" layer events. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} Optional object whose properties will determine │ │ │ │ + * the behaviour of this Strategy │ │ │ │ + * │ │ │ │ + * Valid options include: │ │ │ │ + * force - {Boolean} if true, new data must be unconditionally read. │ │ │ │ + * noAbort - {Boolean} if true, do not abort previous requests. │ │ │ │ + */ │ │ │ │ + update: function(options) { │ │ │ │ + var mapBounds = this.getMapBounds(); │ │ │ │ + if (mapBounds !== null && ((options && options.force) || │ │ │ │ + (this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds)))) { │ │ │ │ + this.calculateBounds(mapBounds); │ │ │ │ + this.resolution = this.layer.map.getResolution(); │ │ │ │ + this.triggerRead(options); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getMapBounds │ │ │ │ + * Get the map bounds expressed in the same projection as this layer. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} Map bounds in the projection of the layer. │ │ │ │ + */ │ │ │ │ + getMapBounds: function() { │ │ │ │ + if (this.layer.map === null) { │ │ │ │ + return null; │ │ │ │ + } │ │ │ │ + var bounds = this.layer.map.getExtent(); │ │ │ │ + if (bounds && !this.layer.projection.equals( │ │ │ │ + this.layer.map.getProjectionObject())) { │ │ │ │ + bounds = bounds.clone().transform( │ │ │ │ + this.layer.map.getProjectionObject(), this.layer.projection │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return bounds; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: invalidBounds │ │ │ │ + * Determine whether the previously requested set of features is invalid. │ │ │ │ + * This occurs when the new map bounds do not contain the previously │ │ │ │ + * requested bounds. In addition, if <resFactor> is set, it will be │ │ │ │ + * considered. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be │ │ │ │ + * retrieved from the map object if not provided │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} │ │ │ │ + */ │ │ │ │ + invalidBounds: function(mapBounds) { │ │ │ │ + if (!mapBounds) { │ │ │ │ + mapBounds = this.getMapBounds(); │ │ │ │ + } │ │ │ │ + var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds); │ │ │ │ + if (!invalid && this.resFactor) { │ │ │ │ + var ratio = this.resolution / this.layer.map.getResolution(); │ │ │ │ + invalid = (ratio >= this.resFactor || ratio <= (1 / this.resFactor)); │ │ │ │ + } │ │ │ │ + return invalid; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: calculateBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be │ │ │ │ + * retrieved from the map object if not provided │ │ │ │ + */ │ │ │ │ + calculateBounds: function(mapBounds) { │ │ │ │ + if (!mapBounds) { │ │ │ │ + mapBounds = this.getMapBounds(); │ │ │ │ + } │ │ │ │ + var center = mapBounds.getCenterLonLat(); │ │ │ │ + var dataWidth = mapBounds.getWidth() * this.ratio; │ │ │ │ + var dataHeight = mapBounds.getHeight() * this.ratio; │ │ │ │ + this.bounds = new OpenLayers.Bounds( │ │ │ │ + center.lon - (dataWidth / 2), │ │ │ │ + center.lat - (dataHeight / 2), │ │ │ │ + center.lon + (dataWidth / 2), │ │ │ │ + center.lat + (dataHeight / 2) │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: triggerRead │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} Additional options for the protocol's read method │ │ │ │ + * (optional) │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Protocol.Response>} The protocol response object │ │ │ │ + * returned by the layer protocol. │ │ │ │ + */ │ │ │ │ + triggerRead: function(options) { │ │ │ │ + if (this.response && !(options && options.noAbort === true)) { │ │ │ │ + this.layer.protocol.abort(this.response); │ │ │ │ + this.layer.events.triggerEvent("loadend"); │ │ │ │ + } │ │ │ │ + var evt = { │ │ │ │ + filter: this.createFilter() │ │ │ │ + }; │ │ │ │ + this.layer.events.triggerEvent("loadstart", evt); │ │ │ │ + this.response = this.layer.protocol.read( │ │ │ │ + OpenLayers.Util.applyDefaults({ │ │ │ │ + filter: evt.filter, │ │ │ │ + callback: this.merge, │ │ │ │ + scope: this │ │ │ │ + }, options)); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: createFilter │ │ │ │ + * Creates a spatial BBOX filter. If the layer that this strategy belongs │ │ │ │ + * to has a filter property, this filter will be combined with the BBOX │ │ │ │ + * filter. │ │ │ │ + * │ │ │ │ + * Returns │ │ │ │ + * {<OpenLayers.Filter>} The filter object. │ │ │ │ + */ │ │ │ │ + createFilter: function() { │ │ │ │ + var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ + value: this.bounds, │ │ │ │ + projection: this.layer.projection │ │ │ │ + }); │ │ │ │ + if (this.layer.filter) { │ │ │ │ + filter = new OpenLayers.Filter.Logical({ │ │ │ │ + type: OpenLayers.Filter.Logical.AND, │ │ │ │ + filters: [this.layer.filter, filter] │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + return filter; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: merge │ │ │ │ + * Given a list of features, determine which ones to add 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) { │ │ │ │ + this.layer.destroyFeatures(); │ │ │ │ + if (resp.success()) { │ │ │ │ + var features = resp.features; │ │ │ │ + if (features && features.length > 0) { │ │ │ │ + var remote = this.layer.projection; │ │ │ │ + var local = this.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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.layer.addFeatures(features); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.bounds = null; │ │ │ │ + } │ │ │ │ + this.response = null; │ │ │ │ + this.layer.events.triggerEvent("loadend", { │ │ │ │ + response: resp │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.BBOX" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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, │ │ │ │ │ │ │ │ /** │ │ │ │ @@ -15560,455 +20250,140 @@ │ │ │ │ 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/Renderer.js │ │ │ │ + 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/BaseTypes/Class.js │ │ │ │ + * @requires OpenLayers/Layer/XYZ.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. │ │ │ │ + * 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: │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * (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.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, │ │ │ │ +OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: featureDx │ │ │ │ - * {Number} Feature offset in x direction. Will be calculated for and │ │ │ │ - * applied to the current feature while rendering (see │ │ │ │ - * <calculateFeatureDx>). │ │ │ │ + * APIProperty: name │ │ │ │ + * {String} The layer name. Defaults to "OpenStreetMap" if the first │ │ │ │ + * argument to the constructor is null or undefined. │ │ │ │ */ │ │ │ │ - featureDx: 0, │ │ │ │ + name: "OpenStreetMap", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Renderer │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * containerID - {<String>} │ │ │ │ - * options - {Object} options for this renderer. See sublcasses for │ │ │ │ - * supported options. │ │ │ │ + * 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) │ │ │ │ */ │ │ │ │ - initialize: function(containerID, options) { │ │ │ │ - this.container = OpenLayers.Util.getElement(containerID); │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - }, │ │ │ │ + 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' │ │ │ │ + ], │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ + * Property: attribution │ │ │ │ + * {String} The layer attribution. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - this.container = null; │ │ │ │ - this.extent = null; │ │ │ │ - this.size = null; │ │ │ │ - this.resolution = null; │ │ │ │ - this.map = null; │ │ │ │ - }, │ │ │ │ + attribution: "© <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: supported │ │ │ │ - * This should be overridden by specific subclasses │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the browser supports the renderer class │ │ │ │ + * Property: sphericalMercator │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - supported: function() { │ │ │ │ - return false; │ │ │ │ - }, │ │ │ │ + sphericalMercator: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: wrapDateLine │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - }, │ │ │ │ + wrapDateLine: 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. │ │ │ │ + /** APIProperty: tileOptions │ │ │ │ + * {Object} optional configuration options for <OpenLayers.Tile> instances │ │ │ │ + * created by this Layer. Default is │ │ │ │ * │ │ │ │ - * 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(). │ │ │ │ + * (code) │ │ │ │ + * {crossOriginKeyword: 'anonymous'} │ │ │ │ + * (end) │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * When using OSM tilesets other than the default ones, it may be │ │ │ │ + * necessary to set this to │ │ │ │ * │ │ │ │ - * 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 │ │ │ │ + * (code) │ │ │ │ + * {crossOriginKeyword: null} │ │ │ │ + * (end) │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * if the server does not send Access-Control-Allow-Origin headers. │ │ │ │ */ │ │ │ │ - clear: function() {}, │ │ │ │ + tileOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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>} │ │ │ │ + * Constructor: OpenLayers.Layer.OSM │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * 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>). │ │ │ │ */ │ │ │ │ - getRenderLayerId: function() { │ │ │ │ - return this.container.id; │ │ │ │ + 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: applyDefaultSymbolizer │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * symbolizer - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} │ │ │ │ + * Method: clone │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.OSM( │ │ │ │ + this.name, this.url, this.getOptions()); │ │ │ │ } │ │ │ │ - OpenLayers.Util.extend(result, symbolizer); │ │ │ │ - return result; │ │ │ │ + obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer" │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.OSM" │ │ │ │ }); │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * 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/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 │ │ │ │ @@ -17297,141 +21672,14 @@ │ │ │ │ return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply( │ │ │ │ this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Layer.WMS" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - 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: "© <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/Layer/SphericalMercator.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. */ │ │ │ │ @@ -18768,762 +23016,2563 @@ │ │ │ │ */ │ │ │ │ getLongitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ return this.sphericalMercator ? │ │ │ │ this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon : │ │ │ │ moLonLat.lng(); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getLatitudeFromMapObjectLonLat │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moLonLat - {Object} MapObject LonLat format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Float} Latitude of the given MapObject LonLat │ │ │ │ - */ │ │ │ │ - getLatitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - var lat = this.sphericalMercator ? │ │ │ │ - this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat : │ │ │ │ - moLonLat.lat(); │ │ │ │ - return lat; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * APIMethod: getLatitudeFromMapObjectLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moLonLat - {Object} MapObject LonLat format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Float} Latitude of the given MapObject LonLat │ │ │ │ + */ │ │ │ │ + getLatitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + var lat = this.sphericalMercator ? │ │ │ │ + this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat : │ │ │ │ + moLonLat.lat(); │ │ │ │ + return lat; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + // Pixel │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getXFromMapObjectPixel │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moPixel - {Object} MapObject Pixel format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} X value of the MapObject Pixel │ │ │ │ + */ │ │ │ │ + getXFromMapObjectPixel: function(moPixel) { │ │ │ │ + return moPixel.x; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getYFromMapObjectPixel │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moPixel - {Object} MapObject Pixel format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} Y value of the MapObject Pixel │ │ │ │ + */ │ │ │ │ + getYFromMapObjectPixel: function(moPixel) { │ │ │ │ + return moPixel.y; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Google" │ │ │ │ + }); │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Property: OpenLayers.Layer.Google.cache │ │ │ │ + * {Object} Cache for elements that should only be created once per map. │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Google.cache = {}; │ │ │ │ + │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Layer.Google.v2 │ │ │ │ + * │ │ │ │ + * Mixin providing functionality specific to the Google Maps API v2. │ │ │ │ + * │ │ │ │ + * This API has been deprecated by Google. │ │ │ │ + * Developers are encouraged to migrate to v3 of the API; support for this │ │ │ │ + * is provided by <OpenLayers.Layer.Google.v3> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Google.v2 = { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: termsOfUse │ │ │ │ + * {DOMElement} Div for Google's copyright and terms of use link │ │ │ │ + */ │ │ │ │ + termsOfUse: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: poweredBy │ │ │ │ + * {DOMElement} Div for Google's powered by logo and link │ │ │ │ + */ │ │ │ │ + poweredBy: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: dragObject │ │ │ │ + * {GDraggableObject} Since 2.93, Google has exposed the ability to get │ │ │ │ + * the maps GDraggableObject. We can now use this for smooth panning │ │ │ │ + */ │ │ │ │ + dragObject: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: loadMapObject │ │ │ │ + * Load the GMap and register appropriate event listeners. If we can't │ │ │ │ + * load GMap2, then display a warning message. │ │ │ │ + */ │ │ │ │ + loadMapObject: function() { │ │ │ │ + if (!this.type) { │ │ │ │ + this.type = G_NORMAL_MAP; │ │ │ │ + } │ │ │ │ + var mapObject, termsOfUse, poweredBy; │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + // there are already Google layers added to this map │ │ │ │ + mapObject = cache.mapObject; │ │ │ │ + termsOfUse = cache.termsOfUse; │ │ │ │ + poweredBy = cache.poweredBy; │ │ │ │ + // increment the layer count │ │ │ │ + ++cache.count; │ │ │ │ + } else { │ │ │ │ + // this is the first Google layer for this map │ │ │ │ + │ │ │ │ + var container = this.map.viewPortDiv; │ │ │ │ + var div = document.createElement("div"); │ │ │ │ + div.id = this.map.id + "_GMap2Container"; │ │ │ │ + div.style.position = "absolute"; │ │ │ │ + div.style.width = "100%"; │ │ │ │ + div.style.height = "100%"; │ │ │ │ + container.appendChild(div); │ │ │ │ + │ │ │ │ + // create GMap and shuffle elements │ │ │ │ + try { │ │ │ │ + mapObject = new GMap2(div); │ │ │ │ + │ │ │ │ + // move the ToS and branding stuff up to the container div │ │ │ │ + termsOfUse = div.lastChild; │ │ │ │ + container.appendChild(termsOfUse); │ │ │ │ + termsOfUse.style.zIndex = "1100"; │ │ │ │ + termsOfUse.style.right = ""; │ │ │ │ + termsOfUse.style.bottom = ""; │ │ │ │ + termsOfUse.className = "olLayerGoogleCopyright"; │ │ │ │ + │ │ │ │ + poweredBy = div.lastChild; │ │ │ │ + container.appendChild(poweredBy); │ │ │ │ + poweredBy.style.zIndex = "1100"; │ │ │ │ + poweredBy.style.right = ""; │ │ │ │ + poweredBy.style.bottom = ""; │ │ │ │ + poweredBy.className = "olLayerGooglePoweredBy gmnoprint"; │ │ │ │ + │ │ │ │ + } catch (e) { │ │ │ │ + throw (e); │ │ │ │ + } │ │ │ │ + // cache elements for use by any other google layers added to │ │ │ │ + // this same map │ │ │ │ + OpenLayers.Layer.Google.cache[this.map.id] = { │ │ │ │ + mapObject: mapObject, │ │ │ │ + termsOfUse: termsOfUse, │ │ │ │ + poweredBy: poweredBy, │ │ │ │ + count: 1 │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.mapObject = mapObject; │ │ │ │ + this.termsOfUse = termsOfUse; │ │ │ │ + this.poweredBy = poweredBy; │ │ │ │ + │ │ │ │ + // ensure this layer type is one of the mapObject types │ │ │ │ + if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(), │ │ │ │ + this.type) === -1) { │ │ │ │ + this.mapObject.addMapType(this.type); │ │ │ │ + } │ │ │ │ + │ │ │ │ + //since v 2.93 getDragObject is now available. │ │ │ │ + if (typeof mapObject.getDragObject == "function") { │ │ │ │ + this.dragObject = mapObject.getDragObject(); │ │ │ │ + } else { │ │ │ │ + this.dragPanMapObject = null; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.isBaseLayer === false) { │ │ │ │ + this.setGMapVisibility(this.div.style.display !== "none"); │ │ │ │ + } │ │ │ │ + │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: onMapResize │ │ │ │ + */ │ │ │ │ + onMapResize: function() { │ │ │ │ + // workaround for resizing of invisible or not yet fully loaded layers │ │ │ │ + // where GMap2.checkResize() does not work. We need to load the GMap │ │ │ │ + // for the old div size, then checkResize(), and then call │ │ │ │ + // layer.moveTo() to trigger GMap.setCenter() (which will finish │ │ │ │ + // the GMap initialization). │ │ │ │ + if (this.visibility && this.mapObject.isLoaded()) { │ │ │ │ + this.mapObject.checkResize(); │ │ │ │ + } else { │ │ │ │ + if (!this._resized) { │ │ │ │ + var layer = this; │ │ │ │ + var handle = GEvent.addListener(this.mapObject, "load", function() { │ │ │ │ + GEvent.removeListener(handle); │ │ │ │ + delete layer._resized; │ │ │ │ + layer.mapObject.checkResize(); │ │ │ │ + layer.moveTo(layer.map.getCenter(), layer.map.getZoom()); │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + this._resized = true; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setGMapVisibility │ │ │ │ + * Display the GMap container and associated elements. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * visible - {Boolean} Display the GMap elements. │ │ │ │ + */ │ │ │ │ + setGMapVisibility: function(visible) { │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + var container = this.mapObject.getContainer(); │ │ │ │ + if (visible === true) { │ │ │ │ + this.mapObject.setMapType(this.type); │ │ │ │ + container.style.display = ""; │ │ │ │ + this.termsOfUse.style.left = ""; │ │ │ │ + this.termsOfUse.style.display = ""; │ │ │ │ + this.poweredBy.style.display = ""; │ │ │ │ + cache.displayed = this.id; │ │ │ │ + } else { │ │ │ │ + if (cache.displayed === this.id) { │ │ │ │ + delete cache.displayed; │ │ │ │ + } │ │ │ │ + if (!cache.displayed) { │ │ │ │ + container.style.display = "none"; │ │ │ │ + this.termsOfUse.style.display = "none"; │ │ │ │ + // move ToU far to the left in addition to setting display │ │ │ │ + // to "none", because at the end of the GMap2 load │ │ │ │ + // sequence, display: none will be unset and ToU would be │ │ │ │ + // visible after loading a map with a google layer that is │ │ │ │ + // initially hidden. │ │ │ │ + this.termsOfUse.style.left = "-9999px"; │ │ │ │ + this.poweredBy.style.display = "none"; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getMapContainer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} the GMap container's div │ │ │ │ + */ │ │ │ │ + getMapContainer: function() { │ │ │ │ + return this.mapObject.getContainer(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + // │ │ │ │ + // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ + // │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectBoundsFromOLBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * olBounds - {<OpenLayers.Bounds>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} A MapObject Bounds, translated from olBounds │ │ │ │ + * Returns null if null value is passed in │ │ │ │ + */ │ │ │ │ + getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ + var moBounds = null; │ │ │ │ + if (olBounds != null) { │ │ │ │ + var sw = this.sphericalMercator ? │ │ │ │ + this.inverseMercator(olBounds.bottom, olBounds.left) : │ │ │ │ + new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ + var ne = this.sphericalMercator ? │ │ │ │ + this.inverseMercator(olBounds.top, olBounds.right) : │ │ │ │ + new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ + moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon), │ │ │ │ + new GLatLng(ne.lat, ne.lon)); │ │ │ │ + } │ │ │ │ + return moBounds; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Interface Controls * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ + │ │ │ │ + │ │ │ │ + // Get&Set Center, Zoom │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setMapObjectCenter │ │ │ │ + * Set the mapObject to the specified center and zoom │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * center - {Object} MapObject LonLat format │ │ │ │ + * zoom - {int} MapObject zoom format │ │ │ │ + */ │ │ │ │ + setMapObjectCenter: function(center, zoom) { │ │ │ │ + this.mapObject.setCenter(center, zoom); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: dragPanMapObject │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * dX - {Integer} │ │ │ │ + * dY - {Integer} │ │ │ │ + */ │ │ │ │ + dragPanMapObject: function(dX, dY) { │ │ │ │ + this.dragObject.moveBy(new GSize(-dX, dY)); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + // LonLat - Pixel Translation │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectLonLatFromMapObjectPixel │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moPixel - {Object} MapObject Pixel format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject LonLat translated from MapObject Pixel │ │ │ │ + */ │ │ │ │ + getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ + return this.mapObject.fromContainerPixelToLatLng(moPixel); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectPixelFromMapObjectLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moLonLat - {Object} MapObject LonLat format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Pixel transtlated from MapObject LonLat │ │ │ │ + */ │ │ │ │ + getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + return this.mapObject.fromLatLngToContainerPixel(moLonLat); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + // Bounds │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectZoomFromMapObjectBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moBounds - {Object} MapObject Bounds format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Zoom for specified MapObject Bounds │ │ │ │ + */ │ │ │ │ + getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ + return this.mapObject.getBoundsZoomLevel(moBounds); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Primitives * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ + │ │ │ │ + │ │ │ │ + // LonLat │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectLonLatFromLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * lon - {Float} │ │ │ │ + * lat - {Float} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject LonLat built from lon and lat params │ │ │ │ + */ │ │ │ │ + getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ + var gLatLng; │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + var lonlat = this.inverseMercator(lon, lat); │ │ │ │ + gLatLng = new GLatLng(lonlat.lat, lonlat.lon); │ │ │ │ + } else { │ │ │ │ + gLatLng = new GLatLng(lat, lon); │ │ │ │ + } │ │ │ │ + return gLatLng; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + // Pixel │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectPixelFromXY │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * x - {Integer} │ │ │ │ + * y - {Integer} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Pixel from x and y parameters │ │ │ │ + */ │ │ │ │ + getMapObjectPixelFromXY: function(x, y) { │ │ │ │ + return new GPoint(x, y); │ │ │ │ + } │ │ │ │ + │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/Google/v3.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/Google.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Layer.Google.v3 │ │ │ │ + * │ │ │ │ + * Mixin providing functionality specific to the Google Maps API v3. │ │ │ │ + * │ │ │ │ + * To use this layer, you must include the GMaps v3 API in your html. │ │ │ │ + * │ │ │ │ + * Note that this layer configures the google.maps.map object with the │ │ │ │ + * "disableDefaultUI" option set to true. Using UI controls that the Google │ │ │ │ + * Maps API provides is not supported by the OpenLayers API. │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Google.v3 = { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: DEFAULTS │ │ │ │ + * {Object} It is not recommended to change the properties set here. Note │ │ │ │ + * that Google.v3 layers only work when sphericalMercator is set to true. │ │ │ │ + * │ │ │ │ + * (code) │ │ │ │ + * { │ │ │ │ + * sphericalMercator: true, │ │ │ │ + * projection: "EPSG:900913" │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ + */ │ │ │ │ + DEFAULTS: { │ │ │ │ + sphericalMercator: true, │ │ │ │ + projection: "EPSG:900913" │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: animationEnabled │ │ │ │ + * {Boolean} If set to true, the transition between zoom levels will be │ │ │ │ + * animated (if supported by the GMaps API for the device used). Set to │ │ │ │ + * false to match the zooming experience of other layer types. Default │ │ │ │ + * is true. Note that the GMaps API does not give us control over zoom │ │ │ │ + * animation, so if set to false, when zooming, this will make the │ │ │ │ + * layer temporarily invisible, wait until GMaps reports the map being │ │ │ │ + * idle, and make it visible again. The result will be a blank layer │ │ │ │ + * for a few moments while zooming. │ │ │ │ + */ │ │ │ │ + animationEnabled: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: loadMapObject │ │ │ │ + * Load the GMap and register appropriate event listeners. │ │ │ │ + */ │ │ │ │ + loadMapObject: function() { │ │ │ │ + if (!this.type) { │ │ │ │ + this.type = google.maps.MapTypeId.ROADMAP; │ │ │ │ + } │ │ │ │ + var mapObject; │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + // there are already Google layers added to this map │ │ │ │ + mapObject = cache.mapObject; │ │ │ │ + // increment the layer count │ │ │ │ + ++cache.count; │ │ │ │ + } else { │ │ │ │ + // this is the first Google layer for this map │ │ │ │ + // create GMap │ │ │ │ + var center = this.map.getCenter(); │ │ │ │ + var container = document.createElement('div'); │ │ │ │ + container.className = "olForeignContainer"; │ │ │ │ + container.style.width = '100%'; │ │ │ │ + container.style.height = '100%'; │ │ │ │ + mapObject = new google.maps.Map(container, { │ │ │ │ + center: center ? │ │ │ │ + new google.maps.LatLng(center.lat, center.lon) : new google.maps.LatLng(0, 0), │ │ │ │ + zoom: this.map.getZoom() || 0, │ │ │ │ + mapTypeId: this.type, │ │ │ │ + disableDefaultUI: true, │ │ │ │ + keyboardShortcuts: false, │ │ │ │ + draggable: false, │ │ │ │ + disableDoubleClickZoom: true, │ │ │ │ + scrollwheel: false, │ │ │ │ + streetViewControl: false │ │ │ │ + }); │ │ │ │ + var googleControl = document.createElement('div'); │ │ │ │ + googleControl.style.width = '100%'; │ │ │ │ + googleControl.style.height = '100%'; │ │ │ │ + mapObject.controls[google.maps.ControlPosition.TOP_LEFT].push(googleControl); │ │ │ │ + │ │ │ │ + // cache elements for use by any other google layers added to │ │ │ │ + // this same map │ │ │ │ + cache = { │ │ │ │ + googleControl: googleControl, │ │ │ │ + mapObject: mapObject, │ │ │ │ + count: 1 │ │ │ │ + }; │ │ │ │ + OpenLayers.Layer.Google.cache[this.map.id] = cache; │ │ │ │ + } │ │ │ │ + this.mapObject = mapObject; │ │ │ │ + this.setGMapVisibility(this.visibility); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: onMapResize │ │ │ │ + */ │ │ │ │ + onMapResize: function() { │ │ │ │ + if (this.visibility) { │ │ │ │ + google.maps.event.trigger(this.mapObject, "resize"); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setGMapVisibility │ │ │ │ + * Display the GMap container and associated elements. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * visible - {Boolean} Display the GMap elements. │ │ │ │ + */ │ │ │ │ + setGMapVisibility: function(visible) { │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + var map = this.map; │ │ │ │ + if (cache) { │ │ │ │ + var type = this.type; │ │ │ │ + var layers = map.layers; │ │ │ │ + var layer; │ │ │ │ + for (var i = layers.length - 1; i >= 0; --i) { │ │ │ │ + layer = layers[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.Google && │ │ │ │ + layer.visibility === true && layer.inRange === true) { │ │ │ │ + type = layer.type; │ │ │ │ + visible = true; │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var container = this.mapObject.getDiv(); │ │ │ │ + if (visible === true) { │ │ │ │ + if (container.parentNode !== map.div) { │ │ │ │ + if (!cache.rendered) { │ │ │ │ + var me = this; │ │ │ │ + google.maps.event.addListenerOnce(this.mapObject, 'tilesloaded', function() { │ │ │ │ + cache.rendered = true; │ │ │ │ + me.setGMapVisibility(me.getVisibility()); │ │ │ │ + me.moveTo(me.map.getCenter()); │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + map.div.appendChild(container); │ │ │ │ + cache.googleControl.appendChild(map.viewPortDiv); │ │ │ │ + google.maps.event.trigger(this.mapObject, 'resize'); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.mapObject.setMapTypeId(type); │ │ │ │ + } else if (cache.googleControl.hasChildNodes()) { │ │ │ │ + map.div.appendChild(map.viewPortDiv); │ │ │ │ + map.div.removeChild(container); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getMapContainer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} the GMap container's div │ │ │ │ + */ │ │ │ │ + getMapContainer: function() { │ │ │ │ + return this.mapObject.getDiv(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + // │ │ │ │ + // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ + // │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectBoundsFromOLBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * olBounds - {<OpenLayers.Bounds>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} A MapObject Bounds, translated from olBounds │ │ │ │ + * Returns null if null value is passed in │ │ │ │ + */ │ │ │ │ + getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ + var moBounds = null; │ │ │ │ + if (olBounds != null) { │ │ │ │ + var sw = this.sphericalMercator ? │ │ │ │ + this.inverseMercator(olBounds.bottom, olBounds.left) : │ │ │ │ + new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ + var ne = this.sphericalMercator ? │ │ │ │ + this.inverseMercator(olBounds.top, olBounds.right) : │ │ │ │ + new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ + moBounds = new google.maps.LatLngBounds( │ │ │ │ + new google.maps.LatLng(sw.lat, sw.lon), │ │ │ │ + new google.maps.LatLng(ne.lat, ne.lon) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return moBounds; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Interface Controls * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ + │ │ │ │ + │ │ │ │ + // LonLat - Pixel Translation │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectLonLatFromMapObjectPixel │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moPixel - {Object} MapObject Pixel format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject LonLat translated from MapObject Pixel │ │ │ │ + */ │ │ │ │ + getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ + var size = this.map.getSize(); │ │ │ │ + var lon = this.getLongitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ + var lat = this.getLatitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ + │ │ │ │ + var delta_x = moPixel.x - (size.w / 2); │ │ │ │ + var delta_y = moPixel.y - (size.h / 2); │ │ │ │ + │ │ │ │ + var lonlat = new OpenLayers.LonLat( │ │ │ │ + lon + delta_x * res, │ │ │ │ + lat - delta_y * res │ │ │ │ + ); │ │ │ │ + │ │ │ │ + if (this.wrapDateLine) { │ │ │ │ + lonlat = lonlat.wrapDateLine(this.maxExtent); │ │ │ │ + } │ │ │ │ + return this.getMapObjectLonLatFromLonLat(lonlat.lon, lonlat.lat); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectPixelFromMapObjectLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moLonLat - {Object} MapObject LonLat format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Pixel transtlated from MapObject LonLat │ │ │ │ + */ │ │ │ │ + getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); │ │ │ │ + var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ + var extent = this.map.getExtent(); │ │ │ │ + return this.getMapObjectPixelFromXY((1 / res * (lon - extent.left)), │ │ │ │ + (1 / res * (extent.top - lat))); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setMapObjectCenter │ │ │ │ + * Set the mapObject to the specified center and zoom │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * center - {Object} MapObject LonLat format │ │ │ │ + * zoom - {int} MapObject zoom format │ │ │ │ + */ │ │ │ │ + setMapObjectCenter: function(center, zoom) { │ │ │ │ + if (this.animationEnabled === false && zoom != this.mapObject.zoom) { │ │ │ │ + var mapContainer = this.getMapContainer(); │ │ │ │ + google.maps.event.addListenerOnce( │ │ │ │ + this.mapObject, │ │ │ │ + "idle", │ │ │ │ + function() { │ │ │ │ + mapContainer.style.visibility = ""; │ │ │ │ + } │ │ │ │ + ); │ │ │ │ + mapContainer.style.visibility = "hidden"; │ │ │ │ + } │ │ │ │ + this.mapObject.setOptions({ │ │ │ │ + center: center, │ │ │ │ + zoom: zoom │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + // Bounds │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectZoomFromMapObjectBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moBounds - {Object} MapObject Bounds format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Zoom for specified MapObject Bounds │ │ │ │ + */ │ │ │ │ + getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ + return this.mapObject.getBoundsZoomLevel(moBounds); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Primitives * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ + │ │ │ │ + │ │ │ │ + // LonLat │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectLonLatFromLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * lon - {Float} │ │ │ │ + * lat - {Float} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject LonLat built from lon and lat params │ │ │ │ + */ │ │ │ │ + getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ + var gLatLng; │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + var lonlat = this.inverseMercator(lon, lat); │ │ │ │ + gLatLng = new google.maps.LatLng(lonlat.lat, lonlat.lon); │ │ │ │ + } else { │ │ │ │ + gLatLng = new google.maps.LatLng(lat, lon); │ │ │ │ + } │ │ │ │ + return gLatLng; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + // Pixel │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectPixelFromXY │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * x - {Integer} │ │ │ │ + * y - {Integer} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Pixel from x and y parameters │ │ │ │ + */ │ │ │ │ + getMapObjectPixelFromXY: function(x, y) { │ │ │ │ + return new google.maps.Point(x, y); │ │ │ │ + } │ │ │ │ + │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + 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/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) {} │ │ │ │ + }; │ │ │ │ │ │ │ │ - // Pixel │ │ │ │ + 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); │ │ │ │ + }; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getXFromMapObjectPixel │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moPixel - {Object} MapObject Pixel format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} X value of the MapObject Pixel │ │ │ │ - */ │ │ │ │ - getXFromMapObjectPixel: function(moPixel) { │ │ │ │ - return moPixel.x; │ │ │ │ - }, │ │ │ │ + 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) { │ │ │ │ /** │ │ │ │ - * APIMethod: getYFromMapObjectPixel │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moPixel - {Object} MapObject Pixel format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} Y value of the MapObject Pixel │ │ │ │ + * This allows for OpenLayers/Request.js to be included │ │ │ │ + * before or after this script. │ │ │ │ */ │ │ │ │ - getYFromMapObjectPixel: function(moPixel) { │ │ │ │ - return moPixel.y; │ │ │ │ - }, │ │ │ │ + OpenLayers.Request = {}; │ │ │ │ + } │ │ │ │ + OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest; │ │ │ │ +})(); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Protocol/HTTP.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Google" │ │ │ │ - }); │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: OpenLayers.Layer.Google.cache │ │ │ │ - * {Object} Cache for elements that should only be created once per map. │ │ │ │ + * @requires OpenLayers/Protocol.js │ │ │ │ + * @requires OpenLayers/Request/XMLHttpRequest.js │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.Google.cache = {}; │ │ │ │ │ │ │ │ +/** │ │ │ │ + * if application uses the query string, for example, for BBOX parameters, │ │ │ │ + * OpenLayers/Format/QueryStringFilter.js should be included in the build config file │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Layer.Google.v2 │ │ │ │ - * │ │ │ │ - * Mixin providing functionality specific to the Google Maps API v2. │ │ │ │ - * │ │ │ │ - * This API has been deprecated by Google. │ │ │ │ - * Developers are encouraged to migrate to v3 of the API; support for this │ │ │ │ - * is provided by <OpenLayers.Layer.Google.v3> │ │ │ │ + * 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.Layer.Google.v2 = { │ │ │ │ +OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: termsOfUse │ │ │ │ - * {DOMElement} Div for Google's copyright and terms of use link │ │ │ │ + * Property: url │ │ │ │ + * {String} Service URL, read-only, set through the options │ │ │ │ + * passed to constructor. │ │ │ │ */ │ │ │ │ - termsOfUse: null, │ │ │ │ + url: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: poweredBy │ │ │ │ - * {DOMElement} Div for Google's powered by logo and link │ │ │ │ + * Property: headers │ │ │ │ + * {Object} HTTP request headers, read-only, set through the options │ │ │ │ + * passed to the constructor, │ │ │ │ + * Example: {'Content-Type': 'plain/text'} │ │ │ │ */ │ │ │ │ - poweredBy: null, │ │ │ │ + headers: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: dragObject │ │ │ │ - * {GDraggableObject} Since 2.93, Google has exposed the ability to get │ │ │ │ - * the maps GDraggableObject. We can now use this for smooth panning │ │ │ │ + * Property: params │ │ │ │ + * {Object} Parameters of GET requests, read-only, set through the options │ │ │ │ + * passed to the constructor, │ │ │ │ + * Example: {'bbox': '5,5,5,5'} │ │ │ │ */ │ │ │ │ - dragObject: null, │ │ │ │ + params: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: loadMapObject │ │ │ │ - * Load the GMap and register appropriate event listeners. If we can't │ │ │ │ - * load GMap2, then display a warning message. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - loadMapObject: function() { │ │ │ │ - if (!this.type) { │ │ │ │ - this.type = G_NORMAL_MAP; │ │ │ │ - } │ │ │ │ - var mapObject, termsOfUse, poweredBy; │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - // there are already Google layers added to this map │ │ │ │ - mapObject = cache.mapObject; │ │ │ │ - termsOfUse = cache.termsOfUse; │ │ │ │ - poweredBy = cache.poweredBy; │ │ │ │ - // increment the layer count │ │ │ │ - ++cache.count; │ │ │ │ - } else { │ │ │ │ - // this is the first Google layer for this map │ │ │ │ - │ │ │ │ - var container = this.map.viewPortDiv; │ │ │ │ - var div = document.createElement("div"); │ │ │ │ - div.id = this.map.id + "_GMap2Container"; │ │ │ │ - div.style.position = "absolute"; │ │ │ │ - div.style.width = "100%"; │ │ │ │ - div.style.height = "100%"; │ │ │ │ - container.appendChild(div); │ │ │ │ - │ │ │ │ - // create GMap and shuffle elements │ │ │ │ - try { │ │ │ │ - mapObject = new GMap2(div); │ │ │ │ - │ │ │ │ - // move the ToS and branding stuff up to the container div │ │ │ │ - termsOfUse = div.lastChild; │ │ │ │ - container.appendChild(termsOfUse); │ │ │ │ - termsOfUse.style.zIndex = "1100"; │ │ │ │ - termsOfUse.style.right = ""; │ │ │ │ - termsOfUse.style.bottom = ""; │ │ │ │ - termsOfUse.className = "olLayerGoogleCopyright"; │ │ │ │ - │ │ │ │ - poweredBy = div.lastChild; │ │ │ │ - container.appendChild(poweredBy); │ │ │ │ - poweredBy.style.zIndex = "1100"; │ │ │ │ - poweredBy.style.right = ""; │ │ │ │ - poweredBy.style.bottom = ""; │ │ │ │ - poweredBy.className = "olLayerGooglePoweredBy gmnoprint"; │ │ │ │ - │ │ │ │ - } catch (e) { │ │ │ │ - throw (e); │ │ │ │ - } │ │ │ │ - // cache elements for use by any other google layers added to │ │ │ │ - // this same map │ │ │ │ - OpenLayers.Layer.Google.cache[this.map.id] = { │ │ │ │ - mapObject: mapObject, │ │ │ │ - termsOfUse: termsOfUse, │ │ │ │ - poweredBy: poweredBy, │ │ │ │ - count: 1 │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - │ │ │ │ - this.mapObject = mapObject; │ │ │ │ - this.termsOfUse = termsOfUse; │ │ │ │ - this.poweredBy = poweredBy; │ │ │ │ - │ │ │ │ - // ensure this layer type is one of the mapObject types │ │ │ │ - if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(), │ │ │ │ - this.type) === -1) { │ │ │ │ - this.mapObject.addMapType(this.type); │ │ │ │ - } │ │ │ │ - │ │ │ │ - //since v 2.93 getDragObject is now available. │ │ │ │ - if (typeof mapObject.getDragObject == "function") { │ │ │ │ - this.dragObject = mapObject.getDragObject(); │ │ │ │ - } else { │ │ │ │ - this.dragPanMapObject = null; │ │ │ │ - } │ │ │ │ + callback: null, │ │ │ │ │ │ │ │ - if (this.isBaseLayer === false) { │ │ │ │ - this.setGMapVisibility(this.div.style.display !== "none"); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: onMapResize │ │ │ │ + * APIProperty: updateWithPOST │ │ │ │ + * {Boolean} true if update operations are done with POST requests │ │ │ │ + * defaults to false. │ │ │ │ */ │ │ │ │ - onMapResize: function() { │ │ │ │ - // workaround for resizing of invisible or not yet fully loaded layers │ │ │ │ - // where GMap2.checkResize() does not work. We need to load the GMap │ │ │ │ - // for the old div size, then checkResize(), and then call │ │ │ │ - // layer.moveTo() to trigger GMap.setCenter() (which will finish │ │ │ │ - // the GMap initialization). │ │ │ │ - if (this.visibility && this.mapObject.isLoaded()) { │ │ │ │ - this.mapObject.checkResize(); │ │ │ │ - } else { │ │ │ │ - if (!this._resized) { │ │ │ │ - var layer = this; │ │ │ │ - var handle = GEvent.addListener(this.mapObject, "load", function() { │ │ │ │ - GEvent.removeListener(handle); │ │ │ │ - delete layer._resized; │ │ │ │ - layer.mapObject.checkResize(); │ │ │ │ - layer.moveTo(layer.map.getCenter(), layer.map.getZoom()); │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - this._resized = true; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + updateWithPOST: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setGMapVisibility │ │ │ │ - * Display the GMap container and associated elements. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * visible - {Boolean} Display the GMap elements. │ │ │ │ + * 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(). │ │ │ │ */ │ │ │ │ - setGMapVisibility: function(visible) { │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - var container = this.mapObject.getContainer(); │ │ │ │ - if (visible === true) { │ │ │ │ - this.mapObject.setMapType(this.type); │ │ │ │ - container.style.display = ""; │ │ │ │ - this.termsOfUse.style.left = ""; │ │ │ │ - this.termsOfUse.style.display = ""; │ │ │ │ - this.poweredBy.style.display = ""; │ │ │ │ - cache.displayed = this.id; │ │ │ │ - } else { │ │ │ │ - if (cache.displayed === this.id) { │ │ │ │ - delete cache.displayed; │ │ │ │ - } │ │ │ │ - if (!cache.displayed) { │ │ │ │ - container.style.display = "none"; │ │ │ │ - this.termsOfUse.style.display = "none"; │ │ │ │ - // move ToU far to the left in addition to setting display │ │ │ │ - // to "none", because at the end of the GMap2 load │ │ │ │ - // sequence, display: none will be unset and ToU would be │ │ │ │ - // visible after loading a map with a google layer that is │ │ │ │ - // initially hidden. │ │ │ │ - this.termsOfUse.style.left = "-9999px"; │ │ │ │ - this.poweredBy.style.display = "none"; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + deleteWithPOST: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getMapContainer │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} the GMap container's div │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - getMapContainer: function() { │ │ │ │ - return this.mapObject.getContainer(); │ │ │ │ - }, │ │ │ │ + wildcarded: false, │ │ │ │ │ │ │ │ - // │ │ │ │ - // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ - // │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectBoundsFromOLBounds │ │ │ │ - * │ │ │ │ + * Constructor: OpenLayers.Protocol.HTTP │ │ │ │ + * A class for giving layers generic HTTP protocol. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * olBounds - {<OpenLayers.Bounds>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} A MapObject Bounds, translated from olBounds │ │ │ │ - * Returns null if null value is passed in │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ - var moBounds = null; │ │ │ │ - if (olBounds != null) { │ │ │ │ - var sw = this.sphericalMercator ? │ │ │ │ - this.inverseMercator(olBounds.bottom, olBounds.left) : │ │ │ │ - new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ - var ne = this.sphericalMercator ? │ │ │ │ - this.inverseMercator(olBounds.top, olBounds.right) : │ │ │ │ - new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ - moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon), │ │ │ │ - new GLatLng(ne.lat, ne.lon)); │ │ │ │ + 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); │ │ │ │ + }; │ │ │ │ } │ │ │ │ - return moBounds; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Interface Controls * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ - │ │ │ │ - │ │ │ │ - // Get&Set Center, Zoom │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: setMapObjectCenter │ │ │ │ - * Set the mapObject to the specified center and zoom │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * center - {Object} MapObject LonLat format │ │ │ │ - * zoom - {int} MapObject zoom format │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Clean up the protocol. │ │ │ │ */ │ │ │ │ - setMapObjectCenter: function(center, zoom) { │ │ │ │ - this.mapObject.setCenter(center, zoom); │ │ │ │ + destroy: function() { │ │ │ │ + this.params = null; │ │ │ │ + this.headers = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: dragPanMapObject │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * dX - {Integer} │ │ │ │ - * dY - {Integer} │ │ │ │ + * filter - {<OpenLayers.Filter>} filter to convert. │ │ │ │ + * params - {Object} The parameters object. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} The resulting parameters object. │ │ │ │ */ │ │ │ │ - dragPanMapObject: function(dX, dY) { │ │ │ │ - this.dragObject.moveBy(new GSize(-dX, dY)); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - // LonLat - Pixel Translation │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectLonLatFromMapObjectPixel │ │ │ │ - * │ │ │ │ + * APIMethod: read │ │ │ │ + * Construct a request for reading new features. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * moPixel - {Object} MapObject Pixel format │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * {Object} MapObject LonLat translated from MapObject Pixel │ │ │ │ + * {<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. │ │ │ │ */ │ │ │ │ - getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ - return this.mapObject.fromContainerPixelToLatLng(moPixel); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectPixelFromMapObjectLonLat │ │ │ │ - * │ │ │ │ + * Method: handleRead │ │ │ │ + * Individual callbacks are created for read, create and update, should │ │ │ │ + * a subclass need to override each one separately. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * moLonLat - {Object} MapObject LonLat format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject Pixel transtlated from MapObject LonLat │ │ │ │ + * resp - {<OpenLayers.Protocol.Response>} The response object to pass to │ │ │ │ + * the user callback. │ │ │ │ + * options - {Object} The user options passed to the read call. │ │ │ │ */ │ │ │ │ - getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - return this.mapObject.fromLatLngToContainerPixel(moLonLat); │ │ │ │ + handleRead: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options); │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ - // Bounds │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectZoomFromMapObjectBounds │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * APIMethod: create │ │ │ │ + * Construct a request for writing newly created features. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * moBounds - {Object} MapObject Bounds format │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * {Object} MapObject Zoom for specified MapObject Bounds │ │ │ │ + * {<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. │ │ │ │ */ │ │ │ │ - getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ - return this.mapObject.getBoundsZoomLevel(moBounds); │ │ │ │ - }, │ │ │ │ + create: function(features, options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Primitives * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ + 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) │ │ │ │ + }); │ │ │ │ │ │ │ │ - // LonLat │ │ │ │ + return resp; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectLonLatFromLonLat │ │ │ │ - * │ │ │ │ + * Method: handleCreate │ │ │ │ + * Called the the request issued by <create> is complete. May be overridden │ │ │ │ + * by subclasses. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * lon - {Float} │ │ │ │ - * lat - {Float} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject LonLat built from lon and lat params │ │ │ │ + * resp - {<OpenLayers.Protocol.Response>} The response object to pass to │ │ │ │ + * any user callback. │ │ │ │ + * options - {Object} The user options passed to the create call. │ │ │ │ */ │ │ │ │ - getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ - var gLatLng; │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - var lonlat = this.inverseMercator(lon, lat); │ │ │ │ - gLatLng = new GLatLng(lonlat.lat, lonlat.lon); │ │ │ │ - } else { │ │ │ │ - gLatLng = new GLatLng(lat, lon); │ │ │ │ - } │ │ │ │ - return gLatLng; │ │ │ │ + handleCreate: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options); │ │ │ │ }, │ │ │ │ │ │ │ │ - // Pixel │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectPixelFromXY │ │ │ │ - * │ │ │ │ + * APIMethod: update │ │ │ │ + * Construct a request updating modified feature. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * x - {Integer} │ │ │ │ - * y - {Integer} │ │ │ │ - * │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * options - {Object} Optional object for configuring the request. │ │ │ │ + * This object is modified and should not be reused. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} MapObject Pixel from x and y parameters │ │ │ │ + * {<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. │ │ │ │ */ │ │ │ │ - getMapObjectPixelFromXY: function(x, y) { │ │ │ │ - return new GPoint(x, y); │ │ │ │ - } │ │ │ │ - │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Layer/Google/v3.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. */ │ │ │ │ + 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" │ │ │ │ + }); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Layer/Google.js │ │ │ │ - */ │ │ │ │ + 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) │ │ │ │ + }); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Layer.Google.v3 │ │ │ │ - * │ │ │ │ - * Mixin providing functionality specific to the Google Maps API v3. │ │ │ │ - * │ │ │ │ - * To use this layer, you must include the GMaps v3 API in your html. │ │ │ │ - * │ │ │ │ - * Note that this layer configures the google.maps.map object with the │ │ │ │ - * "disableDefaultUI" option set to true. Using UI controls that the Google │ │ │ │ - * Maps API provides is not supported by the OpenLayers API. │ │ │ │ - */ │ │ │ │ -OpenLayers.Layer.Google.v3 = { │ │ │ │ + return resp; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: DEFAULTS │ │ │ │ - * {Object} It is not recommended to change the properties set here. Note │ │ │ │ - * that Google.v3 layers only work when sphericalMercator is set to true. │ │ │ │ - * │ │ │ │ - * (code) │ │ │ │ - * { │ │ │ │ - * sphericalMercator: true, │ │ │ │ - * projection: "EPSG:900913" │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - DEFAULTS: { │ │ │ │ - sphericalMercator: true, │ │ │ │ - projection: "EPSG:900913" │ │ │ │ + handleUpdate: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: animationEnabled │ │ │ │ - * {Boolean} If set to true, the transition between zoom levels will be │ │ │ │ - * animated (if supported by the GMaps API for the device used). Set to │ │ │ │ - * false to match the zooming experience of other layer types. Default │ │ │ │ - * is true. Note that the GMaps API does not give us control over zoom │ │ │ │ - * animation, so if set to false, when zooming, this will make the │ │ │ │ - * layer temporarily invisible, wait until GMaps reports the map being │ │ │ │ - * idle, and make it visible again. The result will be a blank layer │ │ │ │ - * for a few moments while zooming. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - animationEnabled: true, │ │ │ │ + "delete": function(feature, options) { │ │ │ │ + options = options || {}; │ │ │ │ + var url = options.url || │ │ │ │ + feature.url || │ │ │ │ + this.options.url + "/" + feature.fid; │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: loadMapObject │ │ │ │ - * Load the GMap and register appropriate event listeners. │ │ │ │ - */ │ │ │ │ - loadMapObject: function() { │ │ │ │ - if (!this.type) { │ │ │ │ - this.type = google.maps.MapTypeId.ROADMAP; │ │ │ │ - } │ │ │ │ - var mapObject; │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - // there are already Google layers added to this map │ │ │ │ - mapObject = cache.mapObject; │ │ │ │ - // increment the layer count │ │ │ │ - ++cache.count; │ │ │ │ - } else { │ │ │ │ - // this is the first Google layer for this map │ │ │ │ - // create GMap │ │ │ │ - var center = this.map.getCenter(); │ │ │ │ - var container = document.createElement('div'); │ │ │ │ - container.className = "olForeignContainer"; │ │ │ │ - container.style.width = '100%'; │ │ │ │ - container.style.height = '100%'; │ │ │ │ - mapObject = new google.maps.Map(container, { │ │ │ │ - center: center ? │ │ │ │ - new google.maps.LatLng(center.lat, center.lon) : new google.maps.LatLng(0, 0), │ │ │ │ - zoom: this.map.getZoom() || 0, │ │ │ │ - mapTypeId: this.type, │ │ │ │ - disableDefaultUI: true, │ │ │ │ - keyboardShortcuts: false, │ │ │ │ - draggable: false, │ │ │ │ - disableDoubleClickZoom: true, │ │ │ │ - scrollwheel: false, │ │ │ │ - streetViewControl: false │ │ │ │ - }); │ │ │ │ - var googleControl = document.createElement('div'); │ │ │ │ - googleControl.style.width = '100%'; │ │ │ │ - googleControl.style.height = '100%'; │ │ │ │ - mapObject.controls[google.maps.ControlPosition.TOP_LEFT].push(googleControl); │ │ │ │ + var resp = new OpenLayers.Protocol.Response({ │ │ │ │ + reqFeatures: feature, │ │ │ │ + requestType: "delete" │ │ │ │ + }); │ │ │ │ │ │ │ │ - // cache elements for use by any other google layers added to │ │ │ │ - // this same map │ │ │ │ - cache = { │ │ │ │ - googleControl: googleControl, │ │ │ │ - mapObject: mapObject, │ │ │ │ - count: 1 │ │ │ │ - }; │ │ │ │ - OpenLayers.Layer.Google.cache[this.map.id] = cache; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - this.mapObject = mapObject; │ │ │ │ - this.setGMapVisibility(this.visibility); │ │ │ │ + resp.priv = OpenLayers.Request[method](requestOptions); │ │ │ │ + │ │ │ │ + return resp; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: onMapResize │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - onMapResize: function() { │ │ │ │ - if (this.visibility) { │ │ │ │ - google.maps.event.trigger(this.mapObject, "resize"); │ │ │ │ - } │ │ │ │ + handleDelete: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setGMapVisibility │ │ │ │ - * Display the GMap container and associated elements. │ │ │ │ - * │ │ │ │ + * Method: handleResponse │ │ │ │ + * Called by CRUD specific handlers. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * visible - {Boolean} Display the GMap elements. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - setGMapVisibility: function(visible) { │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - var map = this.map; │ │ │ │ - if (cache) { │ │ │ │ - var type = this.type; │ │ │ │ - var layers = map.layers; │ │ │ │ - var layer; │ │ │ │ - for (var i = layers.length - 1; i >= 0; --i) { │ │ │ │ - layer = layers[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.Google && │ │ │ │ - layer.visibility === true && layer.inRange === true) { │ │ │ │ - type = layer.type; │ │ │ │ - visible = true; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var container = this.mapObject.getDiv(); │ │ │ │ - if (visible === true) { │ │ │ │ - if (container.parentNode !== map.div) { │ │ │ │ - if (!cache.rendered) { │ │ │ │ - var me = this; │ │ │ │ - google.maps.event.addListenerOnce(this.mapObject, 'tilesloaded', function() { │ │ │ │ - cache.rendered = true; │ │ │ │ - me.setGMapVisibility(me.getVisibility()); │ │ │ │ - me.moveTo(me.map.getCenter()); │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - map.div.appendChild(container); │ │ │ │ - cache.googleControl.appendChild(map.viewPortDiv); │ │ │ │ - google.maps.event.trigger(this.mapObject, 'resize'); │ │ │ │ - } │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - this.mapObject.setMapTypeId(type); │ │ │ │ - } else if (cache.googleControl.hasChildNodes()) { │ │ │ │ - map.div.appendChild(map.viewPortDiv); │ │ │ │ - map.div.removeChild(container); │ │ │ │ + resp.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ + } else { │ │ │ │ + // failure │ │ │ │ + resp.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ } │ │ │ │ + options.callback.call(options.scope, resp); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getMapContainer │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} the GMap container's div │ │ │ │ - */ │ │ │ │ - getMapContainer: function() { │ │ │ │ - return this.mapObject.getDiv(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - // │ │ │ │ - // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ - // │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectBoundsFromOLBounds │ │ │ │ - * │ │ │ │ + * Method: parseFeatures │ │ │ │ + * Read HTTP response body and return features. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * olBounds - {<OpenLayers.Bounds>} │ │ │ │ - * │ │ │ │ + * request - {XMLHttpRequest} The request object │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} A MapObject Bounds, translated from olBounds │ │ │ │ - * Returns null if null value is passed in │ │ │ │ + * {Array({<OpenLayers.Feature.Vector>})} or │ │ │ │ + * {<OpenLayers.Feature.Vector>} Array of features or a single feature. │ │ │ │ */ │ │ │ │ - getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ - var moBounds = null; │ │ │ │ - if (olBounds != null) { │ │ │ │ - var sw = this.sphericalMercator ? │ │ │ │ - this.inverseMercator(olBounds.bottom, olBounds.left) : │ │ │ │ - new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ - var ne = this.sphericalMercator ? │ │ │ │ - this.inverseMercator(olBounds.top, olBounds.right) : │ │ │ │ - new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ - moBounds = new google.maps.LatLngBounds( │ │ │ │ - new google.maps.LatLng(sw.lat, sw.lon), │ │ │ │ - new google.maps.LatLng(ne.lat, ne.lon) │ │ │ │ - ); │ │ │ │ + parseFeatures: function(request) { │ │ │ │ + var doc = request.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = request.responseText; │ │ │ │ } │ │ │ │ - return moBounds; │ │ │ │ + if (!doc || doc.length <= 0) { │ │ │ │ + return null; │ │ │ │ + } │ │ │ │ + return this.format.read(doc); │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Interface Controls * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ - │ │ │ │ - │ │ │ │ - // LonLat - Pixel Translation │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectLonLatFromMapObjectPixel │ │ │ │ - * │ │ │ │ + * APIMethod: commit │ │ │ │ + * Iterate over each feature and take action based on the feature state. │ │ │ │ + * Possible actions are create, update and delete. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * moPixel - {Object} MapObject Pixel format │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * {Object} MapObject LonLat translated from MapObject Pixel │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ - var size = this.map.getSize(); │ │ │ │ - var lon = this.getLongitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ - var lat = this.getLatitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - │ │ │ │ - var delta_x = moPixel.x - (size.w / 2); │ │ │ │ - var delta_y = moPixel.y - (size.h / 2); │ │ │ │ - │ │ │ │ - var lonlat = new OpenLayers.LonLat( │ │ │ │ - lon + delta_x * res, │ │ │ │ - lat - delta_y * res │ │ │ │ - ); │ │ │ │ + commit: function(features, options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ + var resp = [], │ │ │ │ + nResponses = 0; │ │ │ │ │ │ │ │ - if (this.wrapDateLine) { │ │ │ │ - lonlat = lonlat.wrapDateLine(this.maxExtent); │ │ │ │ + // 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); │ │ │ │ + } │ │ │ │ } │ │ │ │ - return this.getMapObjectLonLatFromLonLat(lonlat.lon, lonlat.lat); │ │ │ │ - }, │ │ │ │ + // 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; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectPixelFromMapObjectLonLat │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moLonLat - {Object} MapObject LonLat format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject Pixel transtlated from MapObject LonLat │ │ │ │ - */ │ │ │ │ - getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); │ │ │ │ - var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - var extent = this.map.getExtent(); │ │ │ │ - return this.getMapObjectPixelFromXY((1 / res * (lon - extent.left)), │ │ │ │ - (1 / res * (extent.top - lat))); │ │ │ │ - }, │ │ │ │ + // 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]); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: setMapObjectCenter │ │ │ │ - * Set the mapObject to the specified center and zoom │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * center - {Object} MapObject LonLat format │ │ │ │ - * zoom - {int} MapObject zoom format │ │ │ │ - */ │ │ │ │ - setMapObjectCenter: function(center, zoom) { │ │ │ │ - if (this.animationEnabled === false && zoom != this.mapObject.zoom) { │ │ │ │ - var mapContainer = this.getMapContainer(); │ │ │ │ - google.maps.event.addListenerOnce( │ │ │ │ - this.mapObject, │ │ │ │ - "idle", │ │ │ │ - function() { │ │ │ │ - mapContainer.style.visibility = ""; │ │ │ │ + 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]); │ │ │ │ } │ │ │ │ - ); │ │ │ │ - mapContainer.style.visibility = "hidden"; │ │ │ │ + } │ │ │ │ } │ │ │ │ - this.mapObject.setOptions({ │ │ │ │ - center: center, │ │ │ │ - zoom: zoom │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - │ │ │ │ │ │ │ │ - // Bounds │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectZoomFromMapObjectBounds │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moBounds - {Object} MapObject Bounds format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject Zoom for specified MapObject Bounds │ │ │ │ - */ │ │ │ │ - getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ - return this.mapObject.getBoundsZoomLevel(moBounds); │ │ │ │ + // 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; │ │ │ │ }, │ │ │ │ │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Primitives * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ - │ │ │ │ - │ │ │ │ - // LonLat │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectLonLatFromLonLat │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * lon - {Float} │ │ │ │ - * lat - {Float} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject LonLat built from lon and lat params │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} │ │ │ │ */ │ │ │ │ - getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ - var gLatLng; │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - var lonlat = this.inverseMercator(lon, lat); │ │ │ │ - gLatLng = new google.maps.LatLng(lonlat.lat, lonlat.lon); │ │ │ │ - } else { │ │ │ │ - gLatLng = new google.maps.LatLng(lat, lon); │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + response.priv.abort(); │ │ │ │ } │ │ │ │ - return gLatLng; │ │ │ │ }, │ │ │ │ │ │ │ │ - // Pixel │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectPixelFromXY │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * x - {Integer} │ │ │ │ - * y - {Integer} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject Pixel from x and y parameters │ │ │ │ + * resp - {<OpenLayers.Protocol.Response>} │ │ │ │ + * options - {Object} The map of options passed to the commit call. │ │ │ │ */ │ │ │ │ - getMapObjectPixelFromXY: function(x, y) { │ │ │ │ - return new google.maps.Point(x, y); │ │ │ │ - } │ │ │ │ + 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.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 │ │ │ │ @@ -20490,3412 +26539,534 @@ │ │ │ │ * 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/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/Control/LayerSwitcher.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/Lang.js │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ - * @requires OpenLayers/Events/buttonclick.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.LayerSwitcher │ │ │ │ - * The LayerSwitcher control displays a table of contents for the map. This │ │ │ │ - * allows the user interface to switch between BaseLasyers and to show or hide │ │ │ │ - * Overlays. By default the switcher is shown minimized on the right edge of │ │ │ │ - * the map, the user may expand it by clicking on the handle. │ │ │ │ - * │ │ │ │ - * To create the LayerSwitcher outside of the map, pass the Id of a html div │ │ │ │ - * as the first argument to the constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.LayerSwitcher = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: layerStates │ │ │ │ - * {Array(Object)} Basically a copy of the "state" of the map's layers │ │ │ │ - * the last time the control was drawn. We have this in order to avoid │ │ │ │ - * unnecessarily redrawing the control. │ │ │ │ - */ │ │ │ │ - layerStates: null, │ │ │ │ - │ │ │ │ - // DOM Elements │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: layersDiv │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - layersDiv: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: baseLayersDiv │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - baseLayersDiv: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: baseLayers │ │ │ │ - * {Array(Object)} │ │ │ │ - */ │ │ │ │ - baseLayers: null, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: dataLbl │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - dataLbl: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: dataLayersDiv │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - dataLayersDiv: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: dataLayers │ │ │ │ - * {Array(Object)} │ │ │ │ - */ │ │ │ │ - dataLayers: null, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: minimizeDiv │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - minimizeDiv: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: maximizeDiv │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - maximizeDiv: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: ascending │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - ascending: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.LayerSwitcher │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ - this.layerStates = []; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - │ │ │ │ - //clear out layers info and unregister their events │ │ │ │ - this.clearLayersArray("base"); │ │ │ │ - this.clearLayersArray("data"); │ │ │ │ - │ │ │ │ - this.map.events.un({ │ │ │ │ - buttonclick: this.onButtonClick, │ │ │ │ - addlayer: this.redraw, │ │ │ │ - changelayer: this.redraw, │ │ │ │ - removelayer: this.redraw, │ │ │ │ - changebaselayer: this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ - │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * │ │ │ │ - * Properties: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ - */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - │ │ │ │ - this.map.events.on({ │ │ │ │ - addlayer: this.redraw, │ │ │ │ - changelayer: this.redraw, │ │ │ │ - removelayer: this.redraw, │ │ │ │ - changebaselayer: this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - if (this.outsideViewport) { │ │ │ │ - this.events.attachToElement(this.div); │ │ │ │ - this.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ - } else { │ │ │ │ - this.map.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A reference to the DIV DOMElement containing the │ │ │ │ - * switcher tabs. │ │ │ │ - */ │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this); │ │ │ │ - │ │ │ │ - // create layout divs │ │ │ │ - this.loadContents(); │ │ │ │ - │ │ │ │ - // set mode to minimize │ │ │ │ - if (!this.outsideViewport) { │ │ │ │ - this.minimizeControl(); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // populate div with current info │ │ │ │ - this.redraw(); │ │ │ │ - │ │ │ │ - return this.div; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: onButtonClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - */ │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - var button = evt.buttonElement; │ │ │ │ - if (button === this.minimizeDiv) { │ │ │ │ - this.minimizeControl(); │ │ │ │ - } else if (button === this.maximizeDiv) { │ │ │ │ - this.maximizeControl(); │ │ │ │ - } else if (button._layerSwitcher === this.id) { │ │ │ │ - if (button["for"]) { │ │ │ │ - button = document.getElementById(button["for"]); │ │ │ │ - } │ │ │ │ - if (!button.disabled) { │ │ │ │ - if (button.type == "radio") { │ │ │ │ - button.checked = true; │ │ │ │ - this.map.setBaseLayer(this.map.getLayer(button._layer)); │ │ │ │ - } else { │ │ │ │ - button.checked = !button.checked; │ │ │ │ - this.updateMap(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: clearLayersArray │ │ │ │ - * User specifies either "base" or "data". we then clear all the │ │ │ │ - * corresponding listeners, the div, and reinitialize a new array. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layersType - {String} │ │ │ │ - */ │ │ │ │ - clearLayersArray: function(layersType) { │ │ │ │ - this[layersType + "LayersDiv"].innerHTML = ""; │ │ │ │ - this[layersType + "Layers"] = []; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: checkRedraw │ │ │ │ - * Checks if the layer state has changed since the last redraw() call. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The layer state changed since the last redraw() call. │ │ │ │ - */ │ │ │ │ - checkRedraw: function() { │ │ │ │ - if (!this.layerStates.length || │ │ │ │ - (this.map.layers.length != this.layerStates.length)) { │ │ │ │ - return true; │ │ │ │ - } │ │ │ │ - │ │ │ │ - for (var i = 0, len = this.layerStates.length; i < len; i++) { │ │ │ │ - var layerState = this.layerStates[i]; │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - if ((layerState.name != layer.name) || │ │ │ │ - (layerState.inRange != layer.inRange) || │ │ │ │ - (layerState.id != layer.id) || │ │ │ │ - (layerState.visibility != layer.visibility)) { │ │ │ │ - return true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return false; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: redraw │ │ │ │ - * Goes through and takes the current state of the Map and rebuilds the │ │ │ │ - * control to display that state. Groups base layers into a │ │ │ │ - * radio-button group and lists each data layer with a checkbox. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A reference to the DIV DOMElement containing the control │ │ │ │ - */ │ │ │ │ - redraw: function() { │ │ │ │ - //if the state hasn't changed since last redraw, no need │ │ │ │ - // to do anything. Just return the existing div. │ │ │ │ - if (!this.checkRedraw()) { │ │ │ │ - return this.div; │ │ │ │ - } │ │ │ │ - │ │ │ │ - //clear out previous layers │ │ │ │ - this.clearLayersArray("base"); │ │ │ │ - this.clearLayersArray("data"); │ │ │ │ - │ │ │ │ - var containsOverlays = false; │ │ │ │ - var containsBaseLayers = false; │ │ │ │ - │ │ │ │ - // Save state -- for checking layer if the map state changed. │ │ │ │ - // We save this before redrawing, because in the process of redrawing │ │ │ │ - // we will trigger more visibility changes, and we want to not redraw │ │ │ │ - // and enter an infinite loop. │ │ │ │ - var len = this.map.layers.length; │ │ │ │ - this.layerStates = new Array(len); │ │ │ │ - for (var i = 0; i < len; i++) { │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - this.layerStates[i] = { │ │ │ │ - 'name': layer.name, │ │ │ │ - 'visibility': layer.visibility, │ │ │ │ - 'inRange': layer.inRange, │ │ │ │ - 'id': layer.id │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var layers = this.map.layers.slice(); │ │ │ │ - if (!this.ascending) { │ │ │ │ - layers.reverse(); │ │ │ │ - } │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - var layer = layers[i]; │ │ │ │ - var baseLayer = layer.isBaseLayer; │ │ │ │ - │ │ │ │ - if (layer.displayInLayerSwitcher) { │ │ │ │ - │ │ │ │ - if (baseLayer) { │ │ │ │ - containsBaseLayers = true; │ │ │ │ - } else { │ │ │ │ - containsOverlays = true; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // only check a baselayer if it is *the* baselayer, check data │ │ │ │ - // layers if they are visible │ │ │ │ - var checked = (baseLayer) ? (layer == this.map.baseLayer) : │ │ │ │ - layer.getVisibility(); │ │ │ │ - │ │ │ │ - // create input element │ │ │ │ - var inputElem = document.createElement("input"), │ │ │ │ - // The input shall have an id attribute so we can use │ │ │ │ - // labels to interact with them. │ │ │ │ - inputId = OpenLayers.Util.createUniqueID( │ │ │ │ - this.id + "_input_" │ │ │ │ - ); │ │ │ │ - │ │ │ │ - inputElem.id = inputId; │ │ │ │ - inputElem.name = (baseLayer) ? this.id + "_baseLayers" : layer.name; │ │ │ │ - inputElem.type = (baseLayer) ? "radio" : "checkbox"; │ │ │ │ - inputElem.value = layer.name; │ │ │ │ - inputElem.checked = checked; │ │ │ │ - inputElem.defaultChecked = checked; │ │ │ │ - inputElem.className = "olButton"; │ │ │ │ - inputElem._layer = layer.id; │ │ │ │ - inputElem._layerSwitcher = this.id; │ │ │ │ - │ │ │ │ - if (!baseLayer && !layer.inRange) { │ │ │ │ - inputElem.disabled = true; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // create span │ │ │ │ - var labelSpan = document.createElement("label"); │ │ │ │ - // this isn't the DOM attribute 'for', but an arbitrary name we │ │ │ │ - // use to find the appropriate input element in <onButtonClick> │ │ │ │ - labelSpan["for"] = inputElem.id; │ │ │ │ - OpenLayers.Element.addClass(labelSpan, "labelSpan olButton"); │ │ │ │ - labelSpan._layer = layer.id; │ │ │ │ - labelSpan._layerSwitcher = this.id; │ │ │ │ - if (!baseLayer && !layer.inRange) { │ │ │ │ - labelSpan.style.color = "gray"; │ │ │ │ - } │ │ │ │ - labelSpan.innerHTML = layer.name; │ │ │ │ - labelSpan.style.verticalAlign = (baseLayer) ? "bottom" : │ │ │ │ - "baseline"; │ │ │ │ - // create line break │ │ │ │ - var br = document.createElement("br"); │ │ │ │ - │ │ │ │ - │ │ │ │ - var groupArray = (baseLayer) ? this.baseLayers : │ │ │ │ - this.dataLayers; │ │ │ │ - groupArray.push({ │ │ │ │ - 'layer': layer, │ │ │ │ - 'inputElem': inputElem, │ │ │ │ - 'labelSpan': labelSpan │ │ │ │ - }); │ │ │ │ - │ │ │ │ - │ │ │ │ - var groupDiv = (baseLayer) ? this.baseLayersDiv : │ │ │ │ - this.dataLayersDiv; │ │ │ │ - groupDiv.appendChild(inputElem); │ │ │ │ - groupDiv.appendChild(labelSpan); │ │ │ │ - groupDiv.appendChild(br); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // if no overlays, dont display the overlay label │ │ │ │ - this.dataLbl.style.display = (containsOverlays) ? "" : "none"; │ │ │ │ - │ │ │ │ - // if no baselayers, dont display the baselayer label │ │ │ │ - this.baseLbl.style.display = (containsBaseLayers) ? "" : "none"; │ │ │ │ - │ │ │ │ - return this.div; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: updateMap │ │ │ │ - * Cycles through the loaded data and base layer input arrays and makes │ │ │ │ - * the necessary calls to the Map object such that that the map's │ │ │ │ - * visual state corresponds to what the user has selected in │ │ │ │ - * the control. │ │ │ │ - */ │ │ │ │ - updateMap: function() { │ │ │ │ - │ │ │ │ - // set the newly selected base layer │ │ │ │ - for (var i = 0, len = this.baseLayers.length; i < len; i++) { │ │ │ │ - var layerEntry = this.baseLayers[i]; │ │ │ │ - if (layerEntry.inputElem.checked) { │ │ │ │ - this.map.setBaseLayer(layerEntry.layer, false); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // set the correct visibilities for the overlays │ │ │ │ - for (var i = 0, len = this.dataLayers.length; i < len; i++) { │ │ │ │ - var layerEntry = this.dataLayers[i]; │ │ │ │ - layerEntry.layer.setVisibility(layerEntry.inputElem.checked); │ │ │ │ - } │ │ │ │ - │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: maximizeControl │ │ │ │ - * Set up the labels and divs for the control │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {Event} │ │ │ │ - */ │ │ │ │ - maximizeControl: function(e) { │ │ │ │ - │ │ │ │ - // set the div's width and height to empty values, so │ │ │ │ - // the div dimensions can be controlled by CSS │ │ │ │ - this.div.style.width = ""; │ │ │ │ - this.div.style.height = ""; │ │ │ │ - │ │ │ │ - this.showControls(false); │ │ │ │ - │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: minimizeControl │ │ │ │ - * Hide all the contents of the control, shrink the size, │ │ │ │ - * add the maximize icon │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {Event} │ │ │ │ - */ │ │ │ │ - minimizeControl: function(e) { │ │ │ │ - │ │ │ │ - // to minimize the control we set its div's width │ │ │ │ - // and height to 0px, we cannot just set "display" │ │ │ │ - // to "none" because it would hide the maximize │ │ │ │ - // div │ │ │ │ - this.div.style.width = "0px"; │ │ │ │ - this.div.style.height = "0px"; │ │ │ │ - │ │ │ │ - this.showControls(true); │ │ │ │ - │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: showControls │ │ │ │ - * Hide/Show all LayerSwitcher controls depending on whether we are │ │ │ │ - * minimized or not │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * minimize - {Boolean} │ │ │ │ - */ │ │ │ │ - showControls: function(minimize) { │ │ │ │ - │ │ │ │ - this.maximizeDiv.style.display = minimize ? "" : "none"; │ │ │ │ - this.minimizeDiv.style.display = minimize ? "none" : ""; │ │ │ │ - │ │ │ │ - this.layersDiv.style.display = minimize ? "none" : ""; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: loadContents │ │ │ │ - * Set up the labels and divs for the control │ │ │ │ - */ │ │ │ │ - loadContents: function() { │ │ │ │ - │ │ │ │ - // layers list div │ │ │ │ - this.layersDiv = document.createElement("div"); │ │ │ │ - this.layersDiv.id = this.id + "_layersDiv"; │ │ │ │ - OpenLayers.Element.addClass(this.layersDiv, "layersDiv"); │ │ │ │ - │ │ │ │ - this.baseLbl = document.createElement("div"); │ │ │ │ - this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer"); │ │ │ │ - OpenLayers.Element.addClass(this.baseLbl, "baseLbl"); │ │ │ │ - │ │ │ │ - this.baseLayersDiv = document.createElement("div"); │ │ │ │ - OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv"); │ │ │ │ - │ │ │ │ - this.dataLbl = document.createElement("div"); │ │ │ │ - this.dataLbl.innerHTML = OpenLayers.i18n("Overlays"); │ │ │ │ - OpenLayers.Element.addClass(this.dataLbl, "dataLbl"); │ │ │ │ - │ │ │ │ - this.dataLayersDiv = document.createElement("div"); │ │ │ │ - OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv"); │ │ │ │ - │ │ │ │ - if (this.ascending) { │ │ │ │ - this.layersDiv.appendChild(this.baseLbl); │ │ │ │ - this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ - this.layersDiv.appendChild(this.dataLbl); │ │ │ │ - this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ - } else { │ │ │ │ - this.layersDiv.appendChild(this.dataLbl); │ │ │ │ - this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ - this.layersDiv.appendChild(this.baseLbl); │ │ │ │ - this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ - } │ │ │ │ - │ │ │ │ - this.div.appendChild(this.layersDiv); │ │ │ │ - │ │ │ │ - // maximize button div │ │ │ │ - var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png'); │ │ │ │ - this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ - "OpenLayers_Control_MaximizeDiv", │ │ │ │ - null, │ │ │ │ - null, │ │ │ │ - img, │ │ │ │ - "absolute"); │ │ │ │ - OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv olButton"); │ │ │ │ - this.maximizeDiv.style.display = "none"; │ │ │ │ - │ │ │ │ - this.div.appendChild(this.maximizeDiv); │ │ │ │ - │ │ │ │ - // minimize button div │ │ │ │ - var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png'); │ │ │ │ - this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ - "OpenLayers_Control_MinimizeDiv", │ │ │ │ - null, │ │ │ │ - null, │ │ │ │ - img, │ │ │ │ - "absolute"); │ │ │ │ - OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton"); │ │ │ │ - this.minimizeDiv.style.display = "none"; │ │ │ │ - │ │ │ │ - this.div.appendChild(this.minimizeDiv); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.LayerSwitcher" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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/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/Box.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/Handler/Drag.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Handler.Box │ │ │ │ - * Handler for dragging a rectangle across the map. Box is displayed │ │ │ │ - * on mouse down, moves on mouse move, and is finished on mouse up. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Handler> │ │ │ │ - */ │ │ │ │ -OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: dragHandler │ │ │ │ - * {<OpenLayers.Handler.Drag>} │ │ │ │ - */ │ │ │ │ - dragHandler: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: boxDivClassName │ │ │ │ - * {String} The CSS class to use for drawing the box. Default is │ │ │ │ - * olHandlerBoxZoomBox │ │ │ │ - */ │ │ │ │ - boxDivClassName: 'olHandlerBoxZoomBox', │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: boxOffsets │ │ │ │ - * {Object} Caches box offsets from css. This is used by the getBoxOffsets │ │ │ │ - * method. │ │ │ │ - */ │ │ │ │ - boxOffsets: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Handler.Box │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * control - {<OpenLayers.Control>} │ │ │ │ - * callbacks - {Object} An object with a properties whose values are │ │ │ │ - * functions. Various callbacks described below. │ │ │ │ - * options - {Object} │ │ │ │ - * │ │ │ │ - * Named callbacks: │ │ │ │ - * start - Called when the box drag operation starts. │ │ │ │ - * done - Called when the box drag operation is finished. │ │ │ │ - * The callback should expect to receive a single argument, the box │ │ │ │ - * bounds or a pixel. If the box dragging didn't span more than a 5 │ │ │ │ - * pixel distance, a pixel will be returned instead of a bounds object. │ │ │ │ - */ │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ - this.dragHandler = new OpenLayers.Handler.Drag( │ │ │ │ - this, { │ │ │ │ - down: this.startBox, │ │ │ │ - move: this.moveBox, │ │ │ │ - out: this.removeBox, │ │ │ │ - up: this.endBox │ │ │ │ - }, { │ │ │ │ - keyMask: this.keyMask │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ - if (this.dragHandler) { │ │ │ │ - this.dragHandler.destroy(); │ │ │ │ - this.dragHandler = null; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Handler.prototype.setMap.apply(this, arguments); │ │ │ │ - if (this.dragHandler) { │ │ │ │ - this.dragHandler.setMap(map); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: startBox │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * xy - {<OpenLayers.Pixel>} │ │ │ │ - */ │ │ │ │ - startBox: function(xy) { │ │ │ │ - this.callback("start", []); │ │ │ │ - this.zoomBox = OpenLayers.Util.createDiv('zoomBox', { │ │ │ │ - x: -9999, │ │ │ │ - y: -9999 │ │ │ │ - }); │ │ │ │ - this.zoomBox.className = this.boxDivClassName; │ │ │ │ - this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1; │ │ │ │ - │ │ │ │ - this.map.viewPortDiv.appendChild(this.zoomBox); │ │ │ │ - │ │ │ │ - OpenLayers.Element.addClass( │ │ │ │ - this.map.viewPortDiv, "olDrawBox" │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: moveBox │ │ │ │ - */ │ │ │ │ - moveBox: function(xy) { │ │ │ │ - var startX = this.dragHandler.start.x; │ │ │ │ - var startY = this.dragHandler.start.y; │ │ │ │ - var deltaX = Math.abs(startX - xy.x); │ │ │ │ - var deltaY = Math.abs(startY - xy.y); │ │ │ │ - │ │ │ │ - var offset = this.getBoxOffsets(); │ │ │ │ - this.zoomBox.style.width = (deltaX + offset.width + 1) + "px"; │ │ │ │ - this.zoomBox.style.height = (deltaY + offset.height + 1) + "px"; │ │ │ │ - this.zoomBox.style.left = (xy.x < startX ? │ │ │ │ - startX - deltaX - offset.left : startX - offset.left) + "px"; │ │ │ │ - this.zoomBox.style.top = (xy.y < startY ? │ │ │ │ - startY - deltaY - offset.top : startY - offset.top) + "px"; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: endBox │ │ │ │ - */ │ │ │ │ - endBox: function(end) { │ │ │ │ - var result; │ │ │ │ - if (Math.abs(this.dragHandler.start.x - end.x) > 5 || │ │ │ │ - Math.abs(this.dragHandler.start.y - end.y) > 5) { │ │ │ │ - var start = this.dragHandler.start; │ │ │ │ - var top = Math.min(start.y, end.y); │ │ │ │ - var bottom = Math.max(start.y, end.y); │ │ │ │ - var left = Math.min(start.x, end.x); │ │ │ │ - var right = Math.max(start.x, end.x); │ │ │ │ - result = new OpenLayers.Bounds(left, bottom, right, top); │ │ │ │ - } else { │ │ │ │ - result = this.dragHandler.start.clone(); // i.e. OL.Pixel │ │ │ │ - } │ │ │ │ - this.removeBox(); │ │ │ │ - │ │ │ │ - this.callback("done", [result]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: removeBox │ │ │ │ - * Remove the zoombox from the screen and nullify our reference to it. │ │ │ │ - */ │ │ │ │ - removeBox: function() { │ │ │ │ - this.map.viewPortDiv.removeChild(this.zoomBox); │ │ │ │ - this.zoomBox = null; │ │ │ │ - this.boxOffsets = null; │ │ │ │ - OpenLayers.Element.removeClass( │ │ │ │ - this.map.viewPortDiv, "olDrawBox" │ │ │ │ - ); │ │ │ │ - │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: activate │ │ │ │ - */ │ │ │ │ - activate: function() { │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.dragHandler.activate(); │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: deactivate │ │ │ │ - */ │ │ │ │ - deactivate: function() { │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - if (this.dragHandler.deactivate()) { │ │ │ │ - if (this.zoomBox) { │ │ │ │ - this.removeBox(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getBoxOffsets │ │ │ │ - * Determines border offsets for a box, according to the box model. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} an object with the following offsets: │ │ │ │ - * - left │ │ │ │ - * - right │ │ │ │ - * - top │ │ │ │ - * - bottom │ │ │ │ - * - width │ │ │ │ - * - height │ │ │ │ - */ │ │ │ │ - getBoxOffsets: function() { │ │ │ │ - if (!this.boxOffsets) { │ │ │ │ - // Determine the box model. If the testDiv's clientWidth is 3, then │ │ │ │ - // the borders are outside and we are dealing with the w3c box │ │ │ │ - // model. Otherwise, the browser uses the traditional box model and │ │ │ │ - // the borders are inside the box bounds, leaving us with a │ │ │ │ - // clientWidth of 1. │ │ │ │ - var testDiv = document.createElement("div"); │ │ │ │ - //testDiv.style.visibility = "hidden"; │ │ │ │ - testDiv.style.position = "absolute"; │ │ │ │ - testDiv.style.border = "1px solid black"; │ │ │ │ - testDiv.style.width = "3px"; │ │ │ │ - document.body.appendChild(testDiv); │ │ │ │ - var w3cBoxModel = testDiv.clientWidth == 3; │ │ │ │ - document.body.removeChild(testDiv); │ │ │ │ - │ │ │ │ - var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ - "border-left-width")); │ │ │ │ - var right = parseInt(OpenLayers.Element.getStyle( │ │ │ │ - this.zoomBox, "border-right-width")); │ │ │ │ - var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ - "border-top-width")); │ │ │ │ - var bottom = parseInt(OpenLayers.Element.getStyle( │ │ │ │ - this.zoomBox, "border-bottom-width")); │ │ │ │ - this.boxOffsets = { │ │ │ │ - left: left, │ │ │ │ - right: right, │ │ │ │ - top: top, │ │ │ │ - bottom: bottom, │ │ │ │ - width: w3cBoxModel === false ? left + right : 0, │ │ │ │ - height: w3cBoxModel === false ? top + bottom : 0 │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - return this.boxOffsets; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Box" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/ZoomBox.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/Box.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.ZoomBox │ │ │ │ - * The ZoomBox control enables zooming directly to a given extent, by drawing │ │ │ │ - * a box on the map. The box is drawn by holding down shift, whilst dragging │ │ │ │ - * the mouse. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - /** │ │ │ │ - * Property: type │ │ │ │ - * {OpenLayers.Control.TYPE} │ │ │ │ - */ │ │ │ │ - type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: out │ │ │ │ - * {Boolean} Should the control be used for zooming out? │ │ │ │ - */ │ │ │ │ - out: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: keyMask │ │ │ │ - * {Integer} Zoom only occurs if the keyMask matches the combination of │ │ │ │ - * keys down. Use bitwise operators and one or more of the │ │ │ │ - * <OpenLayers.Handler> constants to construct a keyMask. Leave null if │ │ │ │ - * not used mask. Default is null. │ │ │ │ - */ │ │ │ │ - keyMask: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: alwaysZoom │ │ │ │ - * {Boolean} Always zoom in/out when box drawn, even if the zoom level does │ │ │ │ - * not change. │ │ │ │ - */ │ │ │ │ - alwaysZoom: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: zoomOnClick │ │ │ │ - * {Boolean} Should we zoom when no box was dragged, i.e. the user only │ │ │ │ - * clicked? Default is true. │ │ │ │ - */ │ │ │ │ - zoomOnClick: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - */ │ │ │ │ - draw: function() { │ │ │ │ - this.handler = new OpenLayers.Handler.Box(this, { │ │ │ │ - done: this.zoomBox │ │ │ │ - }, { │ │ │ │ - keyMask: this.keyMask │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: zoomBox │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * position - {<OpenLayers.Bounds>} or {<OpenLayers.Pixel>} │ │ │ │ - */ │ │ │ │ - zoomBox: function(position) { │ │ │ │ - if (position instanceof OpenLayers.Bounds) { │ │ │ │ - var bounds, │ │ │ │ - targetCenterPx = position.getCenterPixel(); │ │ │ │ - if (!this.out) { │ │ │ │ - var minXY = this.map.getLonLatFromPixel({ │ │ │ │ - x: position.left, │ │ │ │ - y: position.bottom │ │ │ │ - }); │ │ │ │ - var maxXY = this.map.getLonLatFromPixel({ │ │ │ │ - x: position.right, │ │ │ │ - y: position.top │ │ │ │ - }); │ │ │ │ - bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat, │ │ │ │ - maxXY.lon, maxXY.lat); │ │ │ │ - } else { │ │ │ │ - var pixWidth = position.right - position.left; │ │ │ │ - var pixHeight = position.bottom - position.top; │ │ │ │ - var zoomFactor = Math.min((this.map.size.h / pixHeight), │ │ │ │ - (this.map.size.w / pixWidth)); │ │ │ │ - var extent = this.map.getExtent(); │ │ │ │ - var center = this.map.getLonLatFromPixel(targetCenterPx); │ │ │ │ - var xmin = center.lon - (extent.getWidth() / 2) * zoomFactor; │ │ │ │ - var xmax = center.lon + (extent.getWidth() / 2) * zoomFactor; │ │ │ │ - var ymin = center.lat - (extent.getHeight() / 2) * zoomFactor; │ │ │ │ - var ymax = center.lat + (extent.getHeight() / 2) * zoomFactor; │ │ │ │ - bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax); │ │ │ │ - } │ │ │ │ - // always zoom in/out │ │ │ │ - var lastZoom = this.map.getZoom(), │ │ │ │ - size = this.map.getSize(), │ │ │ │ - centerPx = { │ │ │ │ - x: size.w / 2, │ │ │ │ - y: size.h / 2 │ │ │ │ - }, │ │ │ │ - zoom = this.map.getZoomForExtent(bounds), │ │ │ │ - oldRes = this.map.getResolution(), │ │ │ │ - newRes = this.map.getResolutionForZoom(zoom); │ │ │ │ - if (oldRes == newRes) { │ │ │ │ - this.map.setCenter(this.map.getLonLatFromPixel(targetCenterPx)); │ │ │ │ - } else { │ │ │ │ - var zoomOriginPx = { │ │ │ │ - x: (oldRes * targetCenterPx.x - newRes * centerPx.x) / │ │ │ │ - (oldRes - newRes), │ │ │ │ - y: (oldRes * targetCenterPx.y - newRes * centerPx.y) / │ │ │ │ - (oldRes - newRes) │ │ │ │ - }; │ │ │ │ - this.map.zoomTo(zoom, zoomOriginPx); │ │ │ │ - } │ │ │ │ - if (lastZoom == this.map.getZoom() && this.alwaysZoom == true) { │ │ │ │ - this.map.zoomTo(lastZoom + (this.out ? -1 : 1)); │ │ │ │ - } │ │ │ │ - } else if (this.zoomOnClick) { // it's a pixel │ │ │ │ - if (!this.out) { │ │ │ │ - this.map.zoomTo(this.map.getZoom() + 1, position); │ │ │ │ - } else { │ │ │ │ - this.map.zoomTo(this.map.getZoom() - 1, position); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomBox" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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/Handler/MouseWheel.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.MouseWheel │ │ │ │ - * Handler for wheel up/down events. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Handler> │ │ │ │ - */ │ │ │ │ -OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - /** │ │ │ │ - * Property: wheelListener │ │ │ │ - * {function} │ │ │ │ - */ │ │ │ │ - wheelListener: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: interval │ │ │ │ - * {Integer} In order to increase server performance, an interval (in │ │ │ │ - * milliseconds) can be set to reduce the number of up/down events │ │ │ │ - * called. If set, a new up/down event will not be set until the │ │ │ │ - * interval has passed. │ │ │ │ - * Defaults to 0, meaning no interval. │ │ │ │ - */ │ │ │ │ - interval: 0, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: maxDelta │ │ │ │ - * {Integer} Maximum delta to collect before breaking from the current │ │ │ │ - * interval. In cumulative mode, this also limits the maximum delta │ │ │ │ - * returned from the handler. Default is Number.POSITIVE_INFINITY. │ │ │ │ - */ │ │ │ │ - maxDelta: Number.POSITIVE_INFINITY, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: delta │ │ │ │ - * {Integer} When interval is set, delta collects the mousewheel z-deltas │ │ │ │ - * of the events that occur within the interval. │ │ │ │ - * See also the cumulative option │ │ │ │ - */ │ │ │ │ - delta: 0, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: cumulative │ │ │ │ - * {Boolean} When interval is set: true to collect all the mousewheel │ │ │ │ - * z-deltas, false to only record the delta direction (positive or │ │ │ │ - * negative) │ │ │ │ - */ │ │ │ │ - cumulative: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Handler.MouseWheel │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * control - {<OpenLayers.Control>} │ │ │ │ - * 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 point geometry. │ │ │ │ - * options - {Object} │ │ │ │ - */ │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ - this.wheelListener = OpenLayers.Function.bindAsEventListener( │ │ │ │ - this.onWheelEvent, this │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ - this.wheelListener = null; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/ │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: onWheelEvent │ │ │ │ - * Catch the wheel event and handle it xbrowserly │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {Event} │ │ │ │ - */ │ │ │ │ - onWheelEvent: function(e) { │ │ │ │ - │ │ │ │ - // make sure we have a map and check keyboard modifiers │ │ │ │ - if (!this.map || !this.checkModifiers(e)) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // Ride up the element's DOM hierarchy to determine if it or any of │ │ │ │ - // its ancestors was: │ │ │ │ - // * specifically marked as scrollable (CSS overflow property) │ │ │ │ - // * one of our layer divs or a div marked as scrollable │ │ │ │ - // ('olScrollable' CSS class) │ │ │ │ - // * the map div │ │ │ │ - // │ │ │ │ - var overScrollableDiv = false; │ │ │ │ - var allowScroll = false; │ │ │ │ - var overMapDiv = false; │ │ │ │ - │ │ │ │ - var elem = OpenLayers.Event.element(e); │ │ │ │ - while ((elem != null) && !overMapDiv && !overScrollableDiv) { │ │ │ │ - │ │ │ │ - if (!overScrollableDiv) { │ │ │ │ - try { │ │ │ │ - var overflow; │ │ │ │ - if (elem.currentStyle) { │ │ │ │ - overflow = elem.currentStyle["overflow"]; │ │ │ │ - } else { │ │ │ │ - var style = │ │ │ │ - document.defaultView.getComputedStyle(elem, null); │ │ │ │ - overflow = style.getPropertyValue("overflow"); │ │ │ │ - } │ │ │ │ - overScrollableDiv = (overflow && │ │ │ │ - (overflow == "auto") || (overflow == "scroll")); │ │ │ │ - } catch (err) { │ │ │ │ - //sometimes when scrolling in a popup, this causes │ │ │ │ - // obscure browser error │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (!allowScroll) { │ │ │ │ - allowScroll = OpenLayers.Element.hasClass(elem, 'olScrollable'); │ │ │ │ - if (!allowScroll) { │ │ │ │ - for (var i = 0, len = this.map.layers.length; i < len; i++) { │ │ │ │ - // Are we in the layer div? Note that we have two cases │ │ │ │ - // here: one is to catch EventPane layers, which have a │ │ │ │ - // pane above the layer (layer.pane) │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - if (elem == layer.div || elem == layer.pane) { │ │ │ │ - allowScroll = true; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - overMapDiv = (elem == this.map.div); │ │ │ │ - │ │ │ │ - elem = elem.parentNode; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // Logic below is the following: │ │ │ │ - // │ │ │ │ - // If we are over a scrollable div or not over the map div: │ │ │ │ - // * do nothing (let the browser handle scrolling) │ │ │ │ - // │ │ │ │ - // otherwise │ │ │ │ - // │ │ │ │ - // If we are over the layer div or a 'olScrollable' div: │ │ │ │ - // * zoom/in out │ │ │ │ - // then │ │ │ │ - // * kill event (so as not to also scroll the page after zooming) │ │ │ │ - // │ │ │ │ - // otherwise │ │ │ │ - // │ │ │ │ - // Kill the event (dont scroll the page if we wheel over the │ │ │ │ - // layerswitcher or the pan/zoom control) │ │ │ │ - // │ │ │ │ - if (!overScrollableDiv && overMapDiv) { │ │ │ │ - if (allowScroll) { │ │ │ │ - var delta = 0; │ │ │ │ - │ │ │ │ - if (e.wheelDelta) { │ │ │ │ - delta = e.wheelDelta; │ │ │ │ - if (delta % 160 === 0) { │ │ │ │ - // opera have steps of 160 instead of 120 │ │ │ │ - delta = delta * 0.75; │ │ │ │ - } │ │ │ │ - delta = delta / 120; │ │ │ │ - } else if (e.detail) { │ │ │ │ - // detail in Firefox on OS X is 1/3 of Windows │ │ │ │ - // so force delta 1 / -1 │ │ │ │ - delta = -(e.detail / Math.abs(e.detail)); │ │ │ │ - } │ │ │ │ - this.delta += delta; │ │ │ │ - │ │ │ │ - window.clearTimeout(this._timeoutId); │ │ │ │ - if (this.interval && Math.abs(this.delta) < this.maxDelta) { │ │ │ │ - // store e because window.event might change during delay │ │ │ │ - var evt = OpenLayers.Util.extend({}, e); │ │ │ │ - this._timeoutId = window.setTimeout( │ │ │ │ - OpenLayers.Function.bind(function() { │ │ │ │ - this.wheelZoom(evt); │ │ │ │ - }, this), │ │ │ │ - this.interval │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - this.wheelZoom(e); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - OpenLayers.Event.stop(e); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: wheelZoom │ │ │ │ - * Given the wheel event, we carry out the appropriate zooming in or out, │ │ │ │ - * based on the 'wheelDelta' or 'detail' property of the event. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {Event} │ │ │ │ - */ │ │ │ │ - wheelZoom: function(e) { │ │ │ │ - var delta = this.delta; │ │ │ │ - this.delta = 0; │ │ │ │ - │ │ │ │ - if (delta) { │ │ │ │ - e.xy = this.map.events.getMousePosition(e); │ │ │ │ - if (delta < 0) { │ │ │ │ - this.callback("down", │ │ │ │ - [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]); │ │ │ │ - } else { │ │ │ │ - this.callback("up", │ │ │ │ - [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: activate │ │ │ │ - */ │ │ │ │ - activate: function(evt) { │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - //register mousewheel events specifically on the window and document │ │ │ │ - var wheelListener = this.wheelListener; │ │ │ │ - OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener); │ │ │ │ - OpenLayers.Event.observe(window, "mousewheel", wheelListener); │ │ │ │ - OpenLayers.Event.observe(document, "mousewheel", wheelListener); │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: deactivate │ │ │ │ - */ │ │ │ │ - deactivate: function(evt) { │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - // unregister mousewheel events specifically on the window and document │ │ │ │ - var wheelListener = this.wheelListener; │ │ │ │ - OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener); │ │ │ │ - OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener); │ │ │ │ - OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener); │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.MouseWheel" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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; │ │ │ │ + return item[property] == match || (test && match.test(item[property])); │ │ │ │ + }); │ │ │ │ + return found; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getTouchDistance │ │ │ │ + /** │ │ │ │ + * 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: │ │ │ │ - * {Boolean} The pixel displacement between two touches. │ │ │ │ + * {Array(<OpenLayers.Control>)} A list of controls matching the given name. │ │ │ │ + * An empty array is returned if no matches are found. │ │ │ │ */ │ │ │ │ - getTouchDistance: function(from, to) { │ │ │ │ - return Math.sqrt( │ │ │ │ - Math.pow(from.clientX - to.clientX, 2) + │ │ │ │ - Math.pow(from.clientY - to.clientY, 2) │ │ │ │ - ); │ │ │ │ + getControlsByName: function(match) { │ │ │ │ + return this.getControlsBy("name", match); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: passesDblclickTolerance │ │ │ │ - * Determine whether the event is within the optional double-cick pixel │ │ │ │ - * tolerance. │ │ │ │ + * 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: │ │ │ │ - * {Boolean} The click is within the double-click pixel tolerance. │ │ │ │ + * {Array(<OpenLayers.Control>)} A list of controls matching the given type. │ │ │ │ + * An empty array is returned if no matches are found. │ │ │ │ */ │ │ │ │ - passesDblclickTolerance: function(evt) { │ │ │ │ - var passes = true; │ │ │ │ - if (this.down && this.first) { │ │ │ │ - passes = this.down.xy.distanceTo(this.first.xy) <= this.dblclickTolerance; │ │ │ │ - } │ │ │ │ - return passes; │ │ │ │ + getControlsByClass: function(match) { │ │ │ │ + return this.getControlsBy("CLASS_NAME", match); │ │ │ │ }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Panel" │ │ │ │ +}); │ │ │ │ + │ │ │ │ +/* ====================================================================== │ │ │ │ + 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, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: clearTimer │ │ │ │ - * Clear the timer and set <timerId> to null. │ │ │ │ + * APIProperty: zoomInText │ │ │ │ + * {String} │ │ │ │ + * Text for zoom-in link. Default is "+". │ │ │ │ */ │ │ │ │ - clearTimer: function() { │ │ │ │ - if (this.timerId != null) { │ │ │ │ - window.clearTimeout(this.timerId); │ │ │ │ - this.timerId = null; │ │ │ │ - } │ │ │ │ - if (this.rightclickTimerId != null) { │ │ │ │ - window.clearTimeout(this.rightclickTimerId); │ │ │ │ - this.rightclickTimerId = null; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + zoomInText: "+", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: delayedCall │ │ │ │ - * Sets <timerId> to null. And optionally triggers the click callback if │ │ │ │ - * evt is set. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - delayedCall: function(evt) { │ │ │ │ - this.timerId = null; │ │ │ │ - if (evt) { │ │ │ │ - this.callback("click", [evt]); │ │ │ │ + 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: 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. │ │ │ │ + * Method: getOrCreateLinks │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * el - {DOMElement} │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An object with event related info. │ │ │ │ + * Return: │ │ │ │ + * {Object} Object with zoomIn and zoomOut properties referencing links. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }; │ │ │ │ - } │ │ │ │ + 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 { │ │ │ │ - xy: evt.xy, │ │ │ │ - touches: touches │ │ │ │ + zoomIn: zoomIn, │ │ │ │ + zoomOut: zoomOut │ │ │ │ }; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the handler. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The handler was successfully deactivated. │ │ │ │ + * Method: onZoomClick │ │ │ │ + * Called when zoomin/out link is clicked. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + onZoomClick: function(evt) { │ │ │ │ + var button = evt.buttonElement; │ │ │ │ + if (button === this.zoomInLink) { │ │ │ │ + this.map.zoomIn(); │ │ │ │ + } else if (button === this.zoomOutLink) { │ │ │ │ + this.map.zoomOut(); │ │ │ │ } │ │ │ │ - return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Click" │ │ │ │ + /** │ │ │ │ + * 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/Control/Navigation.js │ │ │ │ + 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/Control/ZoomBox.js │ │ │ │ - * @requires OpenLayers/Control/DragPan.js │ │ │ │ - * @requires OpenLayers/Handler/MouseWheel.js │ │ │ │ - * @requires OpenLayers/Handler/Click.js │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Navigation │ │ │ │ - * The navigation control handles map browsing with mouse events (dragging, │ │ │ │ - * double-clicking, and scrolling the wheel). Create a new navigation │ │ │ │ - * control with the <OpenLayers.Control.Navigation> control. │ │ │ │ - * │ │ │ │ - * Note that this control is added to the map by default (if no controls │ │ │ │ - * array is sent in the options object to the <OpenLayers.Map> │ │ │ │ - * constructor). │ │ │ │ - * │ │ │ │ - * Inherits: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * 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.Control.Navigation = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: dragPan │ │ │ │ - * {<OpenLayers.Control.DragPan>} │ │ │ │ - */ │ │ │ │ - dragPan: null, │ │ │ │ +OpenLayers.Handler = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: dragPanOptions │ │ │ │ - * {Object} Options passed to the DragPan control. │ │ │ │ + * Property: id │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - dragPanOptions: null, │ │ │ │ + id: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: pinchZoom │ │ │ │ - * {<OpenLayers.Control.PinchZoom>} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - pinchZoom: null, │ │ │ │ + control: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: pinchZoomOptions │ │ │ │ - * {Object} Options passed to the PinchZoom control. │ │ │ │ + * Property: map │ │ │ │ + * {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - pinchZoomOptions: null, │ │ │ │ + map: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: documentDrag │ │ │ │ - * {Boolean} Allow panning of the map by dragging outside map viewport. │ │ │ │ - * Default is false. │ │ │ │ - */ │ │ │ │ - documentDrag: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: zoomBox │ │ │ │ - * {<OpenLayers.Control.ZoomBox>} │ │ │ │ + * 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) │ │ │ │ */ │ │ │ │ - zoomBox: null, │ │ │ │ + keyMask: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: zoomBoxEnabled │ │ │ │ - * {Boolean} Whether the user can draw a box to zoom │ │ │ │ + * Property: active │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - zoomBoxEnabled: true, │ │ │ │ + active: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: zoomWheelEnabled │ │ │ │ - * {Boolean} Whether the mousewheel should zoom the map │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - zoomWheelEnabled: true, │ │ │ │ + evt: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: mouseWheelOptions │ │ │ │ - * {Object} Options passed to the MouseWheel control (only useful if │ │ │ │ - * <zoomWheelEnabled> is set to true). Default is no options for maps │ │ │ │ - * with fractionalZoom set to true, otherwise │ │ │ │ - * {cumulative: false, interval: 50, maxDelta: 6} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - mouseWheelOptions: null, │ │ │ │ + touch: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: handleRightClicks │ │ │ │ - * {Boolean} Whether or not to handle right clicks. Default is 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. │ │ │ │ */ │ │ │ │ - handleRightClicks: false, │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + this.control = control; │ │ │ │ + this.callbacks = callbacks; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: zoomBoxKeyMask │ │ │ │ - * {Integer} <OpenLayers.Handler> key code of the key, which has to be │ │ │ │ - * pressed, while drawing the zoom box with the mouse on the screen. │ │ │ │ - * You should probably set handleRightClicks to true if you use this │ │ │ │ - * with MOD_CTRL, to disable the context menu for machines which use │ │ │ │ - * CTRL-Click as a right click. │ │ │ │ - * Default: <OpenLayers.Handler.MOD_SHIFT> │ │ │ │ - */ │ │ │ │ - zoomBoxKeyMask: OpenLayers.Handler.MOD_SHIFT, │ │ │ │ + var map = this.map || control.map; │ │ │ │ + if (map) { │ │ │ │ + this.setMap(map); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ - */ │ │ │ │ - autoActivate: true, │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.Navigation │ │ │ │ - * Create a new navigation control │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * the control │ │ │ │ + * Method: setMap │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - this.handlers = {}; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ + setMap: function(map) { │ │ │ │ + this.map = map; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - │ │ │ │ - if (this.dragPan) { │ │ │ │ - this.dragPan.destroy(); │ │ │ │ - } │ │ │ │ - this.dragPan = null; │ │ │ │ - │ │ │ │ - if (this.zoomBox) { │ │ │ │ - this.zoomBox.destroy(); │ │ │ │ - } │ │ │ │ - this.zoomBox = null; │ │ │ │ - │ │ │ │ - if (this.pinchZoom) { │ │ │ │ - this.pinchZoom.destroy(); │ │ │ │ + checkModifiers: function(evt) { │ │ │ │ + if (this.keyMask == null) { │ │ │ │ + return true; │ │ │ │ } │ │ │ │ - this.pinchZoom = null; │ │ │ │ + /* 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); │ │ │ │ │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + /* if it differs from the handler object's key mask, │ │ │ │ + bail out of the event handler */ │ │ │ │ + return (keyModifiers == this.keyMask); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ + * APIMethod: activate │ │ │ │ + * Turn on the handler. Returns false if the handler was already active. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The handler was activated. │ │ │ │ */ │ │ │ │ activate: function() { │ │ │ │ - this.dragPan.activate(); │ │ │ │ - if (this.zoomWheelEnabled) { │ │ │ │ - this.handlers.wheel.activate(); │ │ │ │ - } │ │ │ │ - this.handlers.click.activate(); │ │ │ │ - if (this.zoomBoxEnabled) { │ │ │ │ - this.zoomBox.activate(); │ │ │ │ + if (this.active) { │ │ │ │ + return false; │ │ │ │ } │ │ │ │ - if (this.pinchZoom) { │ │ │ │ - this.pinchZoom.activate(); │ │ │ │ + // 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]]); │ │ │ │ + } │ │ │ │ } │ │ │ │ - return OpenLayers.Control.prototype.activate.apply(this, arguments); │ │ │ │ + this.active = true; │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Turn off the handler. Returns false if the handler was already inactive. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The handler was deactivated. │ │ │ │ */ │ │ │ │ deactivate: function() { │ │ │ │ - if (this.pinchZoom) { │ │ │ │ - this.pinchZoom.deactivate(); │ │ │ │ + if (!this.active) { │ │ │ │ + return false; │ │ │ │ } │ │ │ │ - this.zoomBox.deactivate(); │ │ │ │ - this.dragPan.deactivate(); │ │ │ │ - this.handlers.click.deactivate(); │ │ │ │ - this.handlers.wheel.deactivate(); │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply(this, arguments); │ │ │ │ + // 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: draw │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - draw: function() { │ │ │ │ - // disable right mouse context menu for support of right click events │ │ │ │ - if (this.handleRightClicks) { │ │ │ │ - this.map.viewPortDiv.oncontextmenu = OpenLayers.Function.False; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var clickCallbacks = { │ │ │ │ - 'click': this.defaultClick, │ │ │ │ - 'dblclick': this.defaultDblClick, │ │ │ │ - 'dblrightclick': this.defaultDblRightClick │ │ │ │ - }; │ │ │ │ - var clickOptions = { │ │ │ │ - 'double': true, │ │ │ │ - 'stopDouble': true │ │ │ │ - }; │ │ │ │ - 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.zoomBox = new OpenLayers.Control.ZoomBox({ │ │ │ │ - map: this.map, │ │ │ │ - keyMask: this.zoomBoxKeyMask │ │ │ │ - }); │ │ │ │ - this.dragPan.draw(); │ │ │ │ - this.zoomBox.draw(); │ │ │ │ - var wheelOptions = this.map.fractionalZoom ? {} : { │ │ │ │ - cumulative: false, │ │ │ │ - interval: 50, │ │ │ │ - maxDelta: 6 │ │ │ │ - }; │ │ │ │ - this.handlers.wheel = new OpenLayers.Handler.MouseWheel( │ │ │ │ - this, { │ │ │ │ - up: this.wheelUp, │ │ │ │ - down: this.wheelDown │ │ │ │ - }, │ │ │ │ - OpenLayers.Util.extend(wheelOptions, this.mouseWheelOptions) │ │ │ │ - ); │ │ │ │ - if (OpenLayers.Control.PinchZoom) { │ │ │ │ - this.pinchZoom = new OpenLayers.Control.PinchZoom( │ │ │ │ - OpenLayers.Util.extend({ │ │ │ │ - map: this.map │ │ │ │ - }, this.pinchZoomOptions)); │ │ │ │ + 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: defaultClick │ │ │ │ + * Method: callback │ │ │ │ + * Trigger the control's named callback with the given arguments │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - defaultClick: function(evt) { │ │ │ │ - if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ - this.map.zoomOut(); │ │ │ │ + callback: function(name, args) { │ │ │ │ + if (name && this.callbacks[name]) { │ │ │ │ + this.callbacks[name].apply(this.control, args); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: defaultDblClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * Method: register │ │ │ │ + * register an event on the map │ │ │ │ */ │ │ │ │ - defaultDblClick: function(evt) { │ │ │ │ - this.map.zoomTo(this.map.zoom + 1, evt.xy); │ │ │ │ + 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: defaultDblRightClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * Method: unregister │ │ │ │ + * unregister an event from the map │ │ │ │ */ │ │ │ │ - defaultDblRightClick: function(evt) { │ │ │ │ - this.map.zoomTo(this.map.zoom - 1, evt.xy); │ │ │ │ + unregister: function(name, method) { │ │ │ │ + this.map.events.unregister(name, this, method); │ │ │ │ + this.map.events.unregister(name, this, this.setEvent); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: wheelChange │ │ │ │ + * 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} │ │ │ │ - * deltaZ - {Integer} │ │ │ │ + * evt - {Event} The browser event. │ │ │ │ */ │ │ │ │ - wheelChange: function(evt, deltaZ) { │ │ │ │ - if (!this.map.fractionalZoom) { │ │ │ │ - deltaZ = Math.round(deltaZ); │ │ │ │ - } │ │ │ │ - var currentZoom = this.map.getZoom(), │ │ │ │ - newZoom = currentZoom + deltaZ; │ │ │ │ - newZoom = Math.max(newZoom, 0); │ │ │ │ - newZoom = Math.min(newZoom, this.map.getNumZoomLevels()); │ │ │ │ - if (newZoom === currentZoom) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - this.map.zoomTo(newZoom, evt.xy); │ │ │ │ + setEvent: function(evt) { │ │ │ │ + this.evt = evt; │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: wheelUp │ │ │ │ - * User spun scroll wheel up │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * delta - {Integer} │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + * Deconstruct the handler. │ │ │ │ */ │ │ │ │ - wheelUp: function(evt, delta) { │ │ │ │ - this.wheelChange(evt, delta || 1); │ │ │ │ + destroy: function() { │ │ │ │ + // unregister event listeners │ │ │ │ + this.deactivate(); │ │ │ │ + // eliminate circular references │ │ │ │ + this.control = this.map = null; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: wheelDown │ │ │ │ - * User spun scroll wheel down │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * delta - {Integer} │ │ │ │ - */ │ │ │ │ - wheelDown: function(evt, delta) { │ │ │ │ - this.wheelChange(evt, delta || -1); │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler" │ │ │ │ +}); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: disableZoomBox │ │ │ │ - */ │ │ │ │ - disableZoomBox: function() { │ │ │ │ - this.zoomBoxEnabled = false; │ │ │ │ - this.zoomBox.deactivate(); │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Handler.MOD_NONE │ │ │ │ + * If set as the <keyMask>, <checkModifiers> returns false if any key is down. │ │ │ │ + */ │ │ │ │ +OpenLayers.Handler.MOD_NONE = 0; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: enableZoomBox │ │ │ │ - */ │ │ │ │ - enableZoomBox: function() { │ │ │ │ - this.zoomBoxEnabled = true; │ │ │ │ - if (this.active) { │ │ │ │ - this.zoomBox.activate(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Handler.MOD_SHIFT │ │ │ │ + * If set as the <keyMask>, <checkModifiers> returns false if Shift is down. │ │ │ │ + */ │ │ │ │ +OpenLayers.Handler.MOD_SHIFT = 1; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: disableZoomWheel │ │ │ │ - */ │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Handler.MOD_CTRL │ │ │ │ + * If set as the <keyMask>, <checkModifiers> returns false if Ctrl is down. │ │ │ │ + */ │ │ │ │ +OpenLayers.Handler.MOD_CTRL = 2; │ │ │ │ │ │ │ │ - disableZoomWheel: function() { │ │ │ │ - this.zoomWheelEnabled = false; │ │ │ │ - this.handlers.wheel.deactivate(); │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Handler.MOD_ALT │ │ │ │ + * If set as the <keyMask>, <checkModifiers> returns false if Alt is down. │ │ │ │ + */ │ │ │ │ +OpenLayers.Handler.MOD_ALT = 4; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: enableZoomWheel │ │ │ │ - */ │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Handler.MOD_META │ │ │ │ + * If set as the <keyMask>, <checkModifiers> returns false if Cmd is down. │ │ │ │ + */ │ │ │ │ +OpenLayers.Handler.MOD_META = 8; │ │ │ │ │ │ │ │ - enableZoomWheel: function() { │ │ │ │ - this.zoomWheelEnabled = true; │ │ │ │ - if (this.active) { │ │ │ │ - this.handlers.wheel.activate(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Navigation" │ │ │ │ -}); │ │ │ │ /* ====================================================================== │ │ │ │ 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 │ │ │ │ @@ -25170,3865 +28341,2891 @@ │ │ │ │ this.activate(); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Control.SelectFeature" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Strategy.js │ │ │ │ + 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/BaseTypes/Class.js │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Strategy │ │ │ │ - * Abstract vector layer strategy class. Not to be instantiated directly. Use │ │ │ │ - * one of the strategy subclasses instead. │ │ │ │ + * 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.Strategy = OpenLayers.Class({ │ │ │ │ +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/Control/LayerSwitcher.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/Lang.js │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ + * @requires OpenLayers/Events/buttonclick.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.LayerSwitcher │ │ │ │ + * The LayerSwitcher control displays a table of contents for the map. This │ │ │ │ + * allows the user interface to switch between BaseLasyers and to show or hide │ │ │ │ + * Overlays. By default the switcher is shown minimized on the right edge of │ │ │ │ + * the map, the user may expand it by clicking on the handle. │ │ │ │ + * │ │ │ │ + * To create the LayerSwitcher outside of the map, pass the Id of a html div │ │ │ │ + * as the first argument to the constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.LayerSwitcher = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: layerStates │ │ │ │ + * {Array(Object)} Basically a copy of the "state" of the map's layers │ │ │ │ + * the last time the control was drawn. We have this in order to avoid │ │ │ │ + * unnecessarily redrawing the control. │ │ │ │ + */ │ │ │ │ + layerStates: null, │ │ │ │ + │ │ │ │ + // DOM Elements │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: layer │ │ │ │ - * {<OpenLayers.Layer.Vector>} The layer this strategy belongs to. │ │ │ │ + * Property: layersDiv │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - layer: null, │ │ │ │ + layersDiv: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: options │ │ │ │ - * {Object} Any options sent to the constructor. │ │ │ │ + * Property: baseLayersDiv │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - options: null, │ │ │ │ + baseLayersDiv: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: active │ │ │ │ - * {Boolean} The control is active. │ │ │ │ + /** │ │ │ │ + * Property: baseLayers │ │ │ │ + * {Array(Object)} │ │ │ │ */ │ │ │ │ - active: null, │ │ │ │ + baseLayers: 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. │ │ │ │ + * Property: dataLbl │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - autoActivate: true, │ │ │ │ + dataLbl: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: autoDestroy │ │ │ │ - * {Boolean} The creator of the strategy can set autoDestroy to false │ │ │ │ - * to fully control when the strategy is destroyed. Defaults to │ │ │ │ - * true. │ │ │ │ + * Property: dataLayersDiv │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - autoDestroy: true, │ │ │ │ + dataLayersDiv: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Strategy │ │ │ │ - * Abstract class for vector strategies. Create instances of a subclass. │ │ │ │ + * Property: dataLayers │ │ │ │ + * {Array(Object)} │ │ │ │ + */ │ │ │ │ + dataLayers: null, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: minimizeDiv │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + minimizeDiv: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: maximizeDiv │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + maximizeDiv: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: ascending │ │ │ │ + * {Boolean} │ │ │ │ + */ │ │ │ │ + ascending: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.LayerSwitcher │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ 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; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ + this.layerStates = []; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: destroy │ │ │ │ - * Clean up the strategy. │ │ │ │ */ │ │ │ │ destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - this.layer = null; │ │ │ │ - this.options = null; │ │ │ │ + │ │ │ │ + //clear out layers info and unregister their events │ │ │ │ + this.clearLayersArray("base"); │ │ │ │ + this.clearLayersArray("data"); │ │ │ │ + │ │ │ │ + this.map.events.un({ │ │ │ │ + buttonclick: this.onButtonClick, │ │ │ │ + addlayer: this.redraw, │ │ │ │ + changelayer: this.redraw, │ │ │ │ + removelayer: this.redraw, │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ + │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setLayer │ │ │ │ - * Called to set the <layer> property. │ │ │ │ + * Method: setMap │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} │ │ │ │ + * Properties: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - setLayer: function(layer) { │ │ │ │ - this.layer = layer; │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + │ │ │ │ + this.map.events.on({ │ │ │ │ + addlayer: this.redraw, │ │ │ │ + changelayer: this.redraw, │ │ │ │ + removelayer: this.redraw, │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + if (this.outsideViewport) { │ │ │ │ + this.events.attachToElement(this.div); │ │ │ │ + this.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ + } else { │ │ │ │ + this.map.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ + * Method: draw │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ - * the strategy was already active. │ │ │ │ + * {DOMElement} A reference to the DIV DOMElement containing the │ │ │ │ + * switcher tabs. │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - if (!this.active) { │ │ │ │ - this.active = true; │ │ │ │ - return true; │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this); │ │ │ │ + │ │ │ │ + // create layout divs │ │ │ │ + this.loadContents(); │ │ │ │ + │ │ │ │ + // set mode to minimize │ │ │ │ + if (!this.outsideViewport) { │ │ │ │ + this.minimizeControl(); │ │ │ │ } │ │ │ │ - return false; │ │ │ │ + │ │ │ │ + // populate div with current info │ │ │ │ + this.redraw(); │ │ │ │ + │ │ │ │ + return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ - * tear-down. │ │ │ │ + * Method: onButtonClick │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} True if the strategy was successfully deactivated or false if │ │ │ │ - * the strategy was already inactive. │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - if (this.active) { │ │ │ │ - this.active = false; │ │ │ │ - return true; │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + var button = evt.buttonElement; │ │ │ │ + if (button === this.minimizeDiv) { │ │ │ │ + this.minimizeControl(); │ │ │ │ + } else if (button === this.maximizeDiv) { │ │ │ │ + this.maximizeControl(); │ │ │ │ + } else if (button._layerSwitcher === this.id) { │ │ │ │ + if (button["for"]) { │ │ │ │ + button = document.getElementById(button["for"]); │ │ │ │ + } │ │ │ │ + if (!button.disabled) { │ │ │ │ + if (button.type == "radio") { │ │ │ │ + button.checked = true; │ │ │ │ + this.map.setBaseLayer(this.map.getLayer(button._layer)); │ │ │ │ + } else { │ │ │ │ + button.checked = !button.checked; │ │ │ │ + this.updateMap(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - return false; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Filter.js │ │ │ │ - ====================================================================== */ │ │ │ │ + /** │ │ │ │ + * Method: clearLayersArray │ │ │ │ + * User specifies either "base" or "data". we then clear all the │ │ │ │ + * corresponding listeners, the div, and reinitialize a new array. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layersType - {String} │ │ │ │ + */ │ │ │ │ + clearLayersArray: function(layersType) { │ │ │ │ + this[layersType + "LayersDiv"].innerHTML = ""; │ │ │ │ + this[layersType + "Layers"] = []; │ │ │ │ + }, │ │ │ │ │ │ │ │ -/* 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. */ │ │ │ │ │ │ │ │ + /** │ │ │ │ + * Method: checkRedraw │ │ │ │ + * Checks if the layer state has changed since the last redraw() call. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The layer state changed since the last redraw() call. │ │ │ │ + */ │ │ │ │ + checkRedraw: function() { │ │ │ │ + if (!this.layerStates.length || │ │ │ │ + (this.map.layers.length != this.layerStates.length)) { │ │ │ │ + return true; │ │ │ │ + } │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ - * @requires OpenLayers/Style.js │ │ │ │ - */ │ │ │ │ + for (var i = 0, len = this.layerStates.length; i < len; i++) { │ │ │ │ + var layerState = this.layerStates[i]; │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + if ((layerState.name != layer.name) || │ │ │ │ + (layerState.inRange != layer.inRange) || │ │ │ │ + (layerState.id != layer.id) || │ │ │ │ + (layerState.visibility != layer.visibility)) { │ │ │ │ + return true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Filter │ │ │ │ - * This class represents an OGC Filter. │ │ │ │ - */ │ │ │ │ -OpenLayers.Filter = OpenLayers.Class({ │ │ │ │ + return false; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Filter │ │ │ │ - * This class represents a generic filter. │ │ │ │ + /** │ │ │ │ + * Method: redraw │ │ │ │ + * Goes through and takes the current state of the Map and rebuilds the │ │ │ │ + * control to display that state. Groups base layers into a │ │ │ │ + * radio-button group and lists each data layer with a checkbox. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ - * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Filter>} │ │ │ │ + * {DOMElement} A reference to the DIV DOMElement containing the control │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ + redraw: function() { │ │ │ │ + //if the state hasn't changed since last redraw, no need │ │ │ │ + // to do anything. Just return the existing div. │ │ │ │ + if (!this.checkRedraw()) { │ │ │ │ + return this.div; │ │ │ │ + } │ │ │ │ + │ │ │ │ + //clear out previous layers │ │ │ │ + this.clearLayersArray("base"); │ │ │ │ + this.clearLayersArray("data"); │ │ │ │ + │ │ │ │ + var containsOverlays = false; │ │ │ │ + var containsBaseLayers = false; │ │ │ │ + │ │ │ │ + // Save state -- for checking layer if the map state changed. │ │ │ │ + // We save this before redrawing, because in the process of redrawing │ │ │ │ + // we will trigger more visibility changes, and we want to not redraw │ │ │ │ + // and enter an infinite loop. │ │ │ │ + var len = this.map.layers.length; │ │ │ │ + this.layerStates = new Array(len); │ │ │ │ + for (var i = 0; i < len; i++) { │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + this.layerStates[i] = { │ │ │ │ + 'name': layer.name, │ │ │ │ + 'visibility': layer.visibility, │ │ │ │ + 'inRange': layer.inRange, │ │ │ │ + 'id': layer.id │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var layers = this.map.layers.slice(); │ │ │ │ + if (!this.ascending) { │ │ │ │ + layers.reverse(); │ │ │ │ + } │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + var layer = layers[i]; │ │ │ │ + var baseLayer = layer.isBaseLayer; │ │ │ │ + │ │ │ │ + if (layer.displayInLayerSwitcher) { │ │ │ │ + │ │ │ │ + if (baseLayer) { │ │ │ │ + containsBaseLayers = true; │ │ │ │ + } else { │ │ │ │ + containsOverlays = true; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // only check a baselayer if it is *the* baselayer, check data │ │ │ │ + // layers if they are visible │ │ │ │ + var checked = (baseLayer) ? (layer == this.map.baseLayer) : │ │ │ │ + layer.getVisibility(); │ │ │ │ + │ │ │ │ + // create input element │ │ │ │ + var inputElem = document.createElement("input"), │ │ │ │ + // The input shall have an id attribute so we can use │ │ │ │ + // labels to interact with them. │ │ │ │ + inputId = OpenLayers.Util.createUniqueID( │ │ │ │ + this.id + "_input_" │ │ │ │ + ); │ │ │ │ + │ │ │ │ + inputElem.id = inputId; │ │ │ │ + inputElem.name = (baseLayer) ? this.id + "_baseLayers" : layer.name; │ │ │ │ + inputElem.type = (baseLayer) ? "radio" : "checkbox"; │ │ │ │ + inputElem.value = layer.name; │ │ │ │ + inputElem.checked = checked; │ │ │ │ + inputElem.defaultChecked = checked; │ │ │ │ + inputElem.className = "olButton"; │ │ │ │ + inputElem._layer = layer.id; │ │ │ │ + inputElem._layerSwitcher = this.id; │ │ │ │ + │ │ │ │ + if (!baseLayer && !layer.inRange) { │ │ │ │ + inputElem.disabled = true; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // create span │ │ │ │ + var labelSpan = document.createElement("label"); │ │ │ │ + // this isn't the DOM attribute 'for', but an arbitrary name we │ │ │ │ + // use to find the appropriate input element in <onButtonClick> │ │ │ │ + labelSpan["for"] = inputElem.id; │ │ │ │ + OpenLayers.Element.addClass(labelSpan, "labelSpan olButton"); │ │ │ │ + labelSpan._layer = layer.id; │ │ │ │ + labelSpan._layerSwitcher = this.id; │ │ │ │ + if (!baseLayer && !layer.inRange) { │ │ │ │ + labelSpan.style.color = "gray"; │ │ │ │ + } │ │ │ │ + labelSpan.innerHTML = layer.name; │ │ │ │ + labelSpan.style.verticalAlign = (baseLayer) ? "bottom" : │ │ │ │ + "baseline"; │ │ │ │ + // create line break │ │ │ │ + var br = document.createElement("br"); │ │ │ │ + │ │ │ │ + │ │ │ │ + var groupArray = (baseLayer) ? this.baseLayers : │ │ │ │ + this.dataLayers; │ │ │ │ + groupArray.push({ │ │ │ │ + 'layer': layer, │ │ │ │ + 'inputElem': inputElem, │ │ │ │ + 'labelSpan': labelSpan │ │ │ │ + }); │ │ │ │ + │ │ │ │ + │ │ │ │ + var groupDiv = (baseLayer) ? this.baseLayersDiv : │ │ │ │ + this.dataLayersDiv; │ │ │ │ + groupDiv.appendChild(inputElem); │ │ │ │ + groupDiv.appendChild(labelSpan); │ │ │ │ + groupDiv.appendChild(br); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // if no overlays, dont display the overlay label │ │ │ │ + this.dataLbl.style.display = (containsOverlays) ? "" : "none"; │ │ │ │ + │ │ │ │ + // if no baselayers, dont display the baselayer label │ │ │ │ + this.baseLbl.style.display = (containsBaseLayers) ? "" : "none"; │ │ │ │ + │ │ │ │ + return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Remove reference to anything added. │ │ │ │ + /** │ │ │ │ + * Method: updateMap │ │ │ │ + * Cycles through the loaded data and base layer input arrays and makes │ │ │ │ + * the necessary calls to the Map object such that that the map's │ │ │ │ + * visual state corresponds to what the user has selected in │ │ │ │ + * the control. │ │ │ │ */ │ │ │ │ - destroy: function() {}, │ │ │ │ + updateMap: function() { │ │ │ │ + │ │ │ │ + // set the newly selected base layer │ │ │ │ + for (var i = 0, len = this.baseLayers.length; i < len; i++) { │ │ │ │ + var layerEntry = this.baseLayers[i]; │ │ │ │ + if (layerEntry.inputElem.checked) { │ │ │ │ + this.map.setBaseLayer(layerEntry.layer, false); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // set the correct visibilities for the overlays │ │ │ │ + for (var i = 0, len = this.dataLayers.length; i < len; i++) { │ │ │ │ + var layerEntry = this.dataLayers[i]; │ │ │ │ + layerEntry.layer.setVisibility(layerEntry.inputElem.checked); │ │ │ │ + } │ │ │ │ + │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: evaluate │ │ │ │ - * Evaluates this filter in a specific context. Instances or subclasses │ │ │ │ - * are supposed to override this method. │ │ │ │ - * │ │ │ │ + * Method: maximizeControl │ │ │ │ + * Set up the labels and divs for the control │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * e - {Event} │ │ │ │ */ │ │ │ │ - evaluate: function(context) { │ │ │ │ - return true; │ │ │ │ + maximizeControl: function(e) { │ │ │ │ + │ │ │ │ + // set the div's width and height to empty values, so │ │ │ │ + // the div dimensions can be controlled by CSS │ │ │ │ + this.div.style.width = ""; │ │ │ │ + this.div.style.height = ""; │ │ │ │ + │ │ │ │ + this.showControls(false); │ │ │ │ + │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Clones this filter. Should be implemented by subclasses. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Filter>} Clone of this filter. │ │ │ │ + * Method: minimizeControl │ │ │ │ + * Hide all the contents of the control, shrink the size, │ │ │ │ + * add the maximize icon │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * e - {Event} │ │ │ │ */ │ │ │ │ - clone: function() { │ │ │ │ - return null; │ │ │ │ + minimizeControl: function(e) { │ │ │ │ + │ │ │ │ + // to minimize the control we set its div's width │ │ │ │ + // and height to 0px, we cannot just set "display" │ │ │ │ + // to "none" because it would hide the maximize │ │ │ │ + // div │ │ │ │ + this.div.style.width = "0px"; │ │ │ │ + this.div.style.height = "0px"; │ │ │ │ + │ │ │ │ + this.showControls(true); │ │ │ │ + │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: toString │ │ │ │ + * Method: showControls │ │ │ │ + * Hide/Show all LayerSwitcher controls depending on whether we are │ │ │ │ + * minimized or not │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {String} Include <OpenLayers.Format.CQL> in your build to get a CQL │ │ │ │ - * representation of the filter returned. Otherwise "[Object object]" │ │ │ │ - * will be returned. │ │ │ │ + * Parameters: │ │ │ │ + * minimize - {Boolean} │ │ │ │ */ │ │ │ │ - toString: function() { │ │ │ │ - var string; │ │ │ │ - if (OpenLayers.Format && OpenLayers.Format.CQL) { │ │ │ │ - string = OpenLayers.Format.CQL.prototype.write(this); │ │ │ │ + showControls: function(minimize) { │ │ │ │ + │ │ │ │ + this.maximizeDiv.style.display = minimize ? "" : "none"; │ │ │ │ + this.minimizeDiv.style.display = minimize ? "none" : ""; │ │ │ │ + │ │ │ │ + this.layersDiv.style.display = minimize ? "none" : ""; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: loadContents │ │ │ │ + * Set up the labels and divs for the control │ │ │ │ + */ │ │ │ │ + loadContents: function() { │ │ │ │ + │ │ │ │ + // layers list div │ │ │ │ + this.layersDiv = document.createElement("div"); │ │ │ │ + this.layersDiv.id = this.id + "_layersDiv"; │ │ │ │ + OpenLayers.Element.addClass(this.layersDiv, "layersDiv"); │ │ │ │ + │ │ │ │ + this.baseLbl = document.createElement("div"); │ │ │ │ + this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer"); │ │ │ │ + OpenLayers.Element.addClass(this.baseLbl, "baseLbl"); │ │ │ │ + │ │ │ │ + this.baseLayersDiv = document.createElement("div"); │ │ │ │ + OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv"); │ │ │ │ + │ │ │ │ + this.dataLbl = document.createElement("div"); │ │ │ │ + this.dataLbl.innerHTML = OpenLayers.i18n("Overlays"); │ │ │ │ + OpenLayers.Element.addClass(this.dataLbl, "dataLbl"); │ │ │ │ + │ │ │ │ + this.dataLayersDiv = document.createElement("div"); │ │ │ │ + OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv"); │ │ │ │ + │ │ │ │ + if (this.ascending) { │ │ │ │ + this.layersDiv.appendChild(this.baseLbl); │ │ │ │ + this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ + this.layersDiv.appendChild(this.dataLbl); │ │ │ │ + this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ } else { │ │ │ │ - string = Object.prototype.toString.call(this); │ │ │ │ + this.layersDiv.appendChild(this.dataLbl); │ │ │ │ + this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ + this.layersDiv.appendChild(this.baseLbl); │ │ │ │ + this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ } │ │ │ │ - return string; │ │ │ │ + │ │ │ │ + this.div.appendChild(this.layersDiv); │ │ │ │ + │ │ │ │ + // maximize button div │ │ │ │ + var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png'); │ │ │ │ + this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ + "OpenLayers_Control_MaximizeDiv", │ │ │ │ + null, │ │ │ │ + null, │ │ │ │ + img, │ │ │ │ + "absolute"); │ │ │ │ + OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv olButton"); │ │ │ │ + this.maximizeDiv.style.display = "none"; │ │ │ │ + │ │ │ │ + this.div.appendChild(this.maximizeDiv); │ │ │ │ + │ │ │ │ + // minimize button div │ │ │ │ + var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png'); │ │ │ │ + this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ + "OpenLayers_Control_MinimizeDiv", │ │ │ │ + null, │ │ │ │ + null, │ │ │ │ + img, │ │ │ │ + "absolute"); │ │ │ │ + OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton"); │ │ │ │ + this.minimizeDiv.style.display = "none"; │ │ │ │ + │ │ │ │ + this.div.appendChild(this.minimizeDiv); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Filter" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.LayerSwitcher" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Filter/Spatial.js │ │ │ │ + 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/Filter.js │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Filter.Spatial │ │ │ │ - * This class represents a spatial filter. │ │ │ │ - * Currently implemented: BBOX, DWithin and Intersects │ │ │ │ - * │ │ │ │ + * 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.Filter> │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -OpenLayers.Filter.Spatial = OpenLayers.Class(OpenLayers.Filter, { │ │ │ │ +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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Property: stopDown │ │ │ │ + * {Boolean} Stop propagation of mousedown events from getting to listeners │ │ │ │ + * on the same element. Default is true. │ │ │ │ */ │ │ │ │ - type: null, │ │ │ │ + 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: property │ │ │ │ - * {String} Name of the context property to compare. │ │ │ │ + * Property: lastMoveEvt │ │ │ │ + * {Object} The last mousemove event that occurred. Used to │ │ │ │ + * position the map correctly when our "delay drag" │ │ │ │ + * timeout expired. │ │ │ │ */ │ │ │ │ - property: null, │ │ │ │ + lastMoveEvt: 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. │ │ │ │ + * Property: oldOnselectstart │ │ │ │ + * {Function} │ │ │ │ */ │ │ │ │ - value: null, │ │ │ │ + oldOnselectstart: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: distance │ │ │ │ - * {Number} The distance to use in a DWithin spatial filter. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - distance: null, │ │ │ │ + interval: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: distanceUnits │ │ │ │ - * {String} The units to use for the distance, e.g. 'm'. │ │ │ │ + * Property: timeoutId │ │ │ │ + * {String} The id of the timeout used for the mousedown interval. │ │ │ │ + * This is "private", and should be left alone. │ │ │ │ */ │ │ │ │ - distanceUnits: null, │ │ │ │ + timeoutId: 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>} │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: evaluate │ │ │ │ - * Evaluates this filter for a specific feature. │ │ │ │ + * Property: documentEvents │ │ │ │ + * {Boolean} Are we currently observing document events? │ │ │ │ + */ │ │ │ │ + documentEvents: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Handler.Drag │ │ │ │ + * Returns OpenLayers.Handler.Drag │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} feature to apply the filter to. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The feature meets filter criteria. │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - throw new Error('evaluate is not implemented for this filter type.'); │ │ │ │ + }); │ │ │ │ + }; │ │ │ │ } │ │ │ │ - return intersect; │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Clones this filter. │ │ │ │ - * │ │ │ │ + * Method: dragstart │ │ │ │ + * This private method is factorized from mousedown and touchstart methods │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} The event │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Filter.Spatial>} Clone of this filter. │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ + 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]); │ │ │ │ │ │ │ │ -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/Strategy/BBOX.js │ │ │ │ - ====================================================================== */ │ │ │ │ + // prevent document dragging │ │ │ │ + OpenLayers.Event.preventDefault(evt); │ │ │ │ │ │ │ │ -/* 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. */ │ │ │ │ + if (!this.oldOnselectstart) { │ │ │ │ + this.oldOnselectstart = document.onselectstart ? │ │ │ │ + document.onselectstart : OpenLayers.Function.True; │ │ │ │ + } │ │ │ │ + document.onselectstart = OpenLayers.Function.False; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Strategy.js │ │ │ │ - * @requires OpenLayers/Filter/Spatial.js │ │ │ │ - */ │ │ │ │ + propagate = !this.stopDown; │ │ │ │ + } else { │ │ │ │ + this.started = false; │ │ │ │ + this.start = null; │ │ │ │ + this.last = null; │ │ │ │ + } │ │ │ │ + return propagate; │ │ │ │ + }, │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Strategy.BBOX │ │ │ │ - * A simple strategy that reads new features when the viewport invalidates │ │ │ │ - * some bounds. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Strategy> │ │ │ │ - */ │ │ │ │ -OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: bounds │ │ │ │ - * {<OpenLayers.Bounds>} The current data bounds (in the same projection │ │ │ │ - * as the layer - not always the same projection as the map). │ │ │ │ + * Method: dragend │ │ │ │ + * This private method is factorized from mouseup and touchend methods │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} The event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - bounds: null, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: resolution │ │ │ │ - * {Float} The current data resolution. │ │ │ │ + /** │ │ │ │ + * The four methods below (down, move, up, and out) are used by subclasses │ │ │ │ + * to do their own processing related to these mouse events. │ │ │ │ */ │ │ │ │ - resolution: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: ratio │ │ │ │ - * {Float} The ratio of the data bounds to the viewport bounds (in each │ │ │ │ - * dimension). Default is 2. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - ratio: 2, │ │ │ │ + down: function(evt) {}, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: resFactor │ │ │ │ - * {Float} Optional factor used to determine when previously requested │ │ │ │ - * features are invalid. If set, the resFactor will be compared to the │ │ │ │ - * resolution of the previous request to the current map resolution. │ │ │ │ - * If resFactor > (old / new) and 1/resFactor < (old / new). If you │ │ │ │ - * set a resFactor of 1, data will be requested every time the │ │ │ │ - * resolution changes. If you set a resFactor of 3, data will be │ │ │ │ - * requested if the old resolution is 3 times the new, or if the new is │ │ │ │ - * 3 times the old. If the old bounds do not contain the new bounds │ │ │ │ - * new data will always be requested (with or without considering │ │ │ │ - * resFactor). │ │ │ │ + /** │ │ │ │ + * 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 │ │ │ │ + * │ │ │ │ */ │ │ │ │ - resFactor: null, │ │ │ │ + move: function(evt) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: response │ │ │ │ - * {<OpenLayers.Protocol.Response>} The protocol response object returned │ │ │ │ - * by the layer protocol. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - response: null, │ │ │ │ + up: function(evt) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Strategy.BBOX │ │ │ │ - * Create a new BBOX strategy. │ │ │ │ + * Method: out │ │ │ │ + * This method is called during the handling of the mouse out event. │ │ │ │ + * Subclasses can do their own processing here. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * evt - {Event} The mouse out event │ │ │ │ */ │ │ │ │ + out: function(evt) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ - * Set up strategy with regard to reading new batches of remote data. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully activated. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - "moveend": this.update, │ │ │ │ - "refresh": this.update, │ │ │ │ - "visibilitychanged": this.update, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.update(); │ │ │ │ - } │ │ │ │ - return activated; │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Tear down strategy with regard to reading new batches of remote data. │ │ │ │ - * │ │ │ │ + * Method: mousedown │ │ │ │ + * Handle mousedown events │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} The strategy was successfully deactivated. │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.layer.events.un({ │ │ │ │ - "moveend": this.update, │ │ │ │ - "refresh": this.update, │ │ │ │ - "visibilitychanged": this.update, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - return deactivated; │ │ │ │ + mousedown: function(evt) { │ │ │ │ + return this.dragstart(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: update │ │ │ │ - * Callback function called on "moveend" or "refresh" layer events. │ │ │ │ + * Method: touchstart │ │ │ │ + * Handle touchstart events │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will determine │ │ │ │ - * the behaviour of this Strategy │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ - * Valid options include: │ │ │ │ - * force - {Boolean} if true, new data must be unconditionally read. │ │ │ │ - * noAbort - {Boolean} if true, do not abort previous requests. │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - update: function(options) { │ │ │ │ - var mapBounds = this.getMapBounds(); │ │ │ │ - if (mapBounds !== null && ((options && options.force) || │ │ │ │ - (this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds)))) { │ │ │ │ - this.calculateBounds(mapBounds); │ │ │ │ - this.resolution = this.layer.map.getResolution(); │ │ │ │ - this.triggerRead(options); │ │ │ │ - } │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + return this.dragstart(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getMapBounds │ │ │ │ - * Get the map bounds expressed in the same projection as this layer. │ │ │ │ + * Method: mousemove │ │ │ │ + * Handle mousemove events │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} Map bounds in the projection of the layer. │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - getMapBounds: function() { │ │ │ │ - if (this.layer.map === null) { │ │ │ │ - return null; │ │ │ │ - } │ │ │ │ - var bounds = this.layer.map.getExtent(); │ │ │ │ - if (bounds && !this.layer.projection.equals( │ │ │ │ - this.layer.map.getProjectionObject())) { │ │ │ │ - bounds = bounds.clone().transform( │ │ │ │ - this.layer.map.getProjectionObject(), this.layer.projection │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return bounds; │ │ │ │ + mousemove: function(evt) { │ │ │ │ + return this.dragmove(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: invalidBounds │ │ │ │ - * Determine whether the previously requested set of features is invalid. │ │ │ │ - * This occurs when the new map bounds do not contain the previously │ │ │ │ - * requested bounds. In addition, if <resFactor> is set, it will be │ │ │ │ - * considered. │ │ │ │ + * Method: touchmove │ │ │ │ + * Handle touchmove events │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be │ │ │ │ - * retrieved from the map object if not provided │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - invalidBounds: function(mapBounds) { │ │ │ │ - if (!mapBounds) { │ │ │ │ - mapBounds = this.getMapBounds(); │ │ │ │ - } │ │ │ │ - var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds); │ │ │ │ - if (!invalid && this.resFactor) { │ │ │ │ - var ratio = this.resolution / this.layer.map.getResolution(); │ │ │ │ - invalid = (ratio >= this.resFactor || ratio <= (1 / this.resFactor)); │ │ │ │ - } │ │ │ │ - return invalid; │ │ │ │ + touchmove: function(evt) { │ │ │ │ + return this.dragmove(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: calculateBounds │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be │ │ │ │ - * retrieved from the map object if not provided │ │ │ │ + * Method: removeTimeout │ │ │ │ + * Private. Called by mousemove() to remove the drag timeout. │ │ │ │ */ │ │ │ │ - calculateBounds: function(mapBounds) { │ │ │ │ - if (!mapBounds) { │ │ │ │ - mapBounds = this.getMapBounds(); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - var center = mapBounds.getCenterLonLat(); │ │ │ │ - var dataWidth = mapBounds.getWidth() * this.ratio; │ │ │ │ - var dataHeight = mapBounds.getHeight() * this.ratio; │ │ │ │ - this.bounds = new OpenLayers.Bounds( │ │ │ │ - center.lon - (dataWidth / 2), │ │ │ │ - center.lat - (dataHeight / 2), │ │ │ │ - center.lon + (dataWidth / 2), │ │ │ │ - center.lat + (dataHeight / 2) │ │ │ │ - ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: triggerRead │ │ │ │ + * Method: mouseup │ │ │ │ + * Handle mouseup events │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Additional options for the protocol's read method │ │ │ │ - * (optional) │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Protocol.Response>} The protocol response object │ │ │ │ - * returned by the layer protocol. │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - triggerRead: function(options) { │ │ │ │ - if (this.response && !(options && options.noAbort === true)) { │ │ │ │ - this.layer.protocol.abort(this.response); │ │ │ │ - this.layer.events.triggerEvent("loadend"); │ │ │ │ - } │ │ │ │ - var evt = { │ │ │ │ - filter: this.createFilter() │ │ │ │ - }; │ │ │ │ - this.layer.events.triggerEvent("loadstart", evt); │ │ │ │ - this.response = this.layer.protocol.read( │ │ │ │ - OpenLayers.Util.applyDefaults({ │ │ │ │ - filter: evt.filter, │ │ │ │ - callback: this.merge, │ │ │ │ - scope: this │ │ │ │ - }, options)); │ │ │ │ + mouseup: function(evt) { │ │ │ │ + return this.dragend(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createFilter │ │ │ │ - * Creates a spatial BBOX filter. If the layer that this strategy belongs │ │ │ │ - * to has a filter property, this filter will be combined with the BBOX │ │ │ │ - * filter. │ │ │ │ - * │ │ │ │ - * Returns │ │ │ │ - * {<OpenLayers.Filter>} The filter object. │ │ │ │ + * Method: touchend │ │ │ │ + * Handle touchend events │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - createFilter: function() { │ │ │ │ - var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ - value: this.bounds, │ │ │ │ - projection: this.layer.projection │ │ │ │ - }); │ │ │ │ - if (this.layer.filter) { │ │ │ │ - filter = new OpenLayers.Filter.Logical({ │ │ │ │ - type: OpenLayers.Filter.Logical.AND, │ │ │ │ - filters: [this.layer.filter, filter] │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - return filter; │ │ │ │ + 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: merge │ │ │ │ - * Given a list of features, determine which ones to add to the layer. │ │ │ │ - * If the layer projection differs from the map projection, features │ │ │ │ - * will be transformed from the layer projection to the map projection. │ │ │ │ + * Method: mouseout │ │ │ │ + * Handle mouseout events │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * resp - {<OpenLayers.Protocol.Response>} The response object passed │ │ │ │ - * by the protocol. │ │ │ │ + * evt - {Event} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - merge: function(resp) { │ │ │ │ - this.layer.destroyFeatures(); │ │ │ │ - if (resp.success()) { │ │ │ │ - var features = resp.features; │ │ │ │ - if (features && features.length > 0) { │ │ │ │ - var remote = this.layer.projection; │ │ │ │ - var local = this.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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - this.layer.addFeatures(features); │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - this.bounds = null; │ │ │ │ } │ │ │ │ - this.response = null; │ │ │ │ - this.layer.events.triggerEvent("loadend", { │ │ │ │ - response: resp │ │ │ │ - }); │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.BBOX" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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: 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 strategy: load data or add listener to load when visible │ │ │ │ - * │ │ │ │ + * Activate the handler. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ - * the strategy was already active. │ │ │ │ + * {Boolean} The handler was successfully activated. │ │ │ │ */ │ │ │ │ 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 │ │ │ │ - }); │ │ │ │ - } │ │ │ │ + var activated = false; │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.dragging = false; │ │ │ │ + activated = true; │ │ │ │ } │ │ │ │ return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Deactivate the strategy. Undo what is done in <activate>. │ │ │ │ + * Method: deactivate │ │ │ │ + * Deactivate the handler. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} The strategy was successfully deactivated. │ │ │ │ + * {Boolean} The handler 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 │ │ │ │ - }); │ │ │ │ + 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: load │ │ │ │ - * Tells protocol to load data and unhooks the visibilitychanged event │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * options - {Object} options to pass to protocol read. │ │ │ │ + * evt - {Object} │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + adjustXY: function(evt) { │ │ │ │ + var pos = OpenLayers.Util.pagePosition(this.map.viewPortDiv); │ │ │ │ + evt.xy.x -= pos[0]; │ │ │ │ + evt.xy.y -= pos[1]; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: addDocumentEvents │ │ │ │ + * Start observing document events when documentDrag is true and the mouse │ │ │ │ + * cursor leaves the map viewport while dragging. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + 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); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Fixed" │ │ │ │ + /** │ │ │ │ + * 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/Renderer/Elements.js │ │ │ │ + OpenLayers/Handler/Box.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 │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ + * @requires OpenLayers/Handler/Drag.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. │ │ │ │ + * Class: OpenLayers.Handler.Box │ │ │ │ + * Handler for dragging a rectangle across the map. Box is displayed │ │ │ │ + * on mouse down, moves on mouse move, and is finished on mouse up. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -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, │ │ │ │ +OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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). │ │ │ │ + /** │ │ │ │ + * Property: dragHandler │ │ │ │ + * {<OpenLayers.Handler.Drag>} │ │ │ │ */ │ │ │ │ - indices: null, │ │ │ │ + dragHandler: 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. │ │ │ │ + * APIProperty: boxDivClassName │ │ │ │ + * {String} The CSS class to use for drawing the box. Default is │ │ │ │ + * olHandlerBoxZoomBox │ │ │ │ */ │ │ │ │ - compare: null, │ │ │ │ + boxDivClassName: 'olHandlerBoxZoomBox', │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: initialize │ │ │ │ - * Create a new indexer with │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * yOrdering - {Boolean} Whether to use y-ordering. │ │ │ │ + * Property: boxOffsets │ │ │ │ + * {Object} Caches box offsets from css. This is used by the getBoxOffsets │ │ │ │ + * method. │ │ │ │ */ │ │ │ │ - initialize: function(yOrdering) { │ │ │ │ - │ │ │ │ - this.compare = yOrdering ? │ │ │ │ - OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER : │ │ │ │ - OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER; │ │ │ │ - │ │ │ │ - this.clear(); │ │ │ │ - }, │ │ │ │ + boxOffsets: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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)). │ │ │ │ - * │ │ │ │ + * Constructor: OpenLayers.Handler.Box │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * control - {<OpenLayers.Control>} │ │ │ │ + * callbacks - {Object} An object with a properties whose values are │ │ │ │ + * functions. Various callbacks described below. │ │ │ │ + * options - {Object} │ │ │ │ + * │ │ │ │ + * Named callbacks: │ │ │ │ + * start - Called when the box drag operation starts. │ │ │ │ + * done - Called when the box drag operation is finished. │ │ │ │ + * The callback should expect to receive a single argument, the box │ │ │ │ + * bounds or a pixel. If the box dragging didn't span more than a 5 │ │ │ │ + * pixel distance, a pixel will be returned instead of a bounds object. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ + this.dragHandler = new OpenLayers.Handler.Drag( │ │ │ │ + this, { │ │ │ │ + down: this.startBox, │ │ │ │ + move: this.moveBox, │ │ │ │ + out: this.removeBox, │ │ │ │ + up: this.endBox │ │ │ │ + }, { │ │ │ │ + keyMask: this.keyMask │ │ │ │ } │ │ │ │ - } │ │ │ │ - │ │ │ │ - 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. │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ + if (this.dragHandler) { │ │ │ │ + this.dragHandler.destroy(); │ │ │ │ + this.dragHandler = null; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clear │ │ │ │ + * Method: setMap │ │ │ │ */ │ │ │ │ - clear: function() { │ │ │ │ - this.order = []; │ │ │ │ - this.indices = {}; │ │ │ │ - this.maxZIndex = 0; │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Handler.prototype.setMap.apply(this, arguments); │ │ │ │ + if (this.dragHandler) { │ │ │ │ + this.dragHandler.setMap(map); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: exists │ │ │ │ + * Method: startBox │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} The node to test for existence. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the node exists in the indexer? │ │ │ │ + * xy - {<OpenLayers.Pixel>} │ │ │ │ */ │ │ │ │ - exists: function(node) { │ │ │ │ - return (this.indices[node.id] != null); │ │ │ │ - }, │ │ │ │ + startBox: function(xy) { │ │ │ │ + this.callback("start", []); │ │ │ │ + this.zoomBox = OpenLayers.Util.createDiv('zoomBox', { │ │ │ │ + x: -9999, │ │ │ │ + y: -9999 │ │ │ │ + }); │ │ │ │ + this.zoomBox.className = this.boxDivClassName; │ │ │ │ + this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ + this.map.viewPortDiv.appendChild(this.zoomBox); │ │ │ │ + │ │ │ │ + OpenLayers.Element.addClass( │ │ │ │ + this.map.viewPortDiv, "olDrawBox" │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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} │ │ │ │ + * Method: moveBox │ │ │ │ */ │ │ │ │ - determineZIndex: function(node) { │ │ │ │ - var zIndex = node._style.graphicZIndex; │ │ │ │ + moveBox: function(xy) { │ │ │ │ + var startX = this.dragHandler.start.x; │ │ │ │ + var startY = this.dragHandler.start.y; │ │ │ │ + var deltaX = Math.abs(startX - xy.x); │ │ │ │ + var deltaY = Math.abs(startY - xy.y); │ │ │ │ │ │ │ │ - // 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; │ │ │ │ - } │ │ │ │ + var offset = this.getBoxOffsets(); │ │ │ │ + this.zoomBox.style.width = (deltaX + offset.width + 1) + "px"; │ │ │ │ + this.zoomBox.style.height = (deltaY + offset.height + 1) + "px"; │ │ │ │ + this.zoomBox.style.left = (xy.x < startX ? │ │ │ │ + startX - deltaX - offset.left : startX - offset.left) + "px"; │ │ │ │ + this.zoomBox.style.top = (xy.y < startY ? │ │ │ │ + startY - deltaY - offset.top : startY - offset.top) + "px"; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: endBox │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + endBox: function(end) { │ │ │ │ + var result; │ │ │ │ + if (Math.abs(this.dragHandler.start.x - end.x) > 5 || │ │ │ │ + Math.abs(this.dragHandler.start.y - end.y) > 5) { │ │ │ │ + var start = this.dragHandler.start; │ │ │ │ + var top = Math.min(start.y, end.y); │ │ │ │ + var bottom = Math.max(start.y, end.y); │ │ │ │ + var left = Math.min(start.x, end.x); │ │ │ │ + var right = Math.max(start.x, end.x); │ │ │ │ + result = new OpenLayers.Bounds(left, bottom, right, top); │ │ │ │ } else { │ │ │ │ - return null; │ │ │ │ + result = this.dragHandler.start.clone(); // i.e. OL.Pixel │ │ │ │ } │ │ │ │ + this.removeBox(); │ │ │ │ + │ │ │ │ + this.callback("done", [result]); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.ElementsIndexer" │ │ │ │ -}); │ │ │ │ + /** │ │ │ │ + * Method: removeBox │ │ │ │ + * Remove the zoombox from the screen and nullify our reference to it. │ │ │ │ + */ │ │ │ │ + removeBox: function() { │ │ │ │ + this.map.viewPortDiv.removeChild(this.zoomBox); │ │ │ │ + this.zoomBox = null; │ │ │ │ + this.boxOffsets = null; │ │ │ │ + OpenLayers.Element.removeClass( │ │ │ │ + this.map.viewPortDiv, "olDrawBox" │ │ │ │ + ); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * 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} │ │ │ │ + * Method: activate │ │ │ │ */ │ │ │ │ - Z_ORDER: function(indexer, newNode, nextNode) { │ │ │ │ - var newZIndex = indexer.getZIndex(newNode); │ │ │ │ - │ │ │ │ - var returnVal = 0; │ │ │ │ - if (nextNode) { │ │ │ │ - var nextZIndex = indexer.getZIndex(nextNode); │ │ │ │ - returnVal = newZIndex - nextZIndex; │ │ │ │ + activate: function() { │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.dragHandler.activate(); │ │ │ │ + return true; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ } │ │ │ │ - │ │ │ │ - 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} │ │ │ │ + * Method: deactivate │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + deactivate: function() { │ │ │ │ + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + if (this.dragHandler.deactivate()) { │ │ │ │ + if (this.zoomBox) { │ │ │ │ + this.removeBox(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return true; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ } │ │ │ │ - │ │ │ │ - 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} │ │ │ │ + * Method: getBoxOffsets │ │ │ │ + * Determines border offsets for a box, according to the box model. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Integer} │ │ │ │ + * {Object} an object with the following offsets: │ │ │ │ + * - left │ │ │ │ + * - right │ │ │ │ + * - top │ │ │ │ + * - bottom │ │ │ │ + * - width │ │ │ │ + * - height │ │ │ │ */ │ │ │ │ - Z_ORDER_Y_ORDER: function(indexer, newNode, nextNode) { │ │ │ │ - var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER( │ │ │ │ - indexer, │ │ │ │ - newNode, │ │ │ │ - nextNode │ │ │ │ - ); │ │ │ │ + getBoxOffsets: function() { │ │ │ │ + if (!this.boxOffsets) { │ │ │ │ + // Determine the box model. If the testDiv's clientWidth is 3, then │ │ │ │ + // the borders are outside and we are dealing with the w3c box │ │ │ │ + // model. Otherwise, the browser uses the traditional box model and │ │ │ │ + // the borders are inside the box bounds, leaving us with a │ │ │ │ + // clientWidth of 1. │ │ │ │ + var testDiv = document.createElement("div"); │ │ │ │ + //testDiv.style.visibility = "hidden"; │ │ │ │ + testDiv.style.position = "absolute"; │ │ │ │ + testDiv.style.border = "1px solid black"; │ │ │ │ + testDiv.style.width = "3px"; │ │ │ │ + document.body.appendChild(testDiv); │ │ │ │ + var w3cBoxModel = testDiv.clientWidth == 3; │ │ │ │ + document.body.removeChild(testDiv); │ │ │ │ │ │ │ │ - if (nextNode && returnVal === 0) { │ │ │ │ - var result = nextNode._boundsBottom - newNode._boundsBottom; │ │ │ │ - returnVal = (result === 0) ? 1 : result; │ │ │ │ + var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ + "border-left-width")); │ │ │ │ + var right = parseInt(OpenLayers.Element.getStyle( │ │ │ │ + this.zoomBox, "border-right-width")); │ │ │ │ + var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ + "border-top-width")); │ │ │ │ + var bottom = parseInt(OpenLayers.Element.getStyle( │ │ │ │ + this.zoomBox, "border-bottom-width")); │ │ │ │ + this.boxOffsets = { │ │ │ │ + left: left, │ │ │ │ + right: right, │ │ │ │ + top: top, │ │ │ │ + bottom: bottom, │ │ │ │ + width: w3cBoxModel === false ? left + right : 0, │ │ │ │ + height: w3cBoxModel === false ? top + bottom : 0 │ │ │ │ + }; │ │ │ │ } │ │ │ │ + return this.boxOffsets; │ │ │ │ + }, │ │ │ │ │ │ │ │ - return returnVal; │ │ │ │ - } │ │ │ │ -}; │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Box" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/ZoomBox.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. */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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> │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Handler/Box.js │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.ZoomBox │ │ │ │ + * The ZoomBox control enables zooming directly to a given extent, by drawing │ │ │ │ + * a box on the map. The box is drawn by holding down shift, whilst dragging │ │ │ │ + * the mouse. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ /** │ │ │ │ - * Property: rendererRoot │ │ │ │ - * {DOMElement} │ │ │ │ + * Property: type │ │ │ │ + * {OpenLayers.Control.TYPE} │ │ │ │ */ │ │ │ │ - rendererRoot: null, │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: root │ │ │ │ - * {DOMElement} │ │ │ │ + * Property: out │ │ │ │ + * {Boolean} Should the control be used for zooming out? │ │ │ │ */ │ │ │ │ - root: null, │ │ │ │ + out: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: vectorRoot │ │ │ │ - * {DOMElement} │ │ │ │ + * APIProperty: keyMask │ │ │ │ + * {Integer} Zoom only occurs if the keyMask matches the combination of │ │ │ │ + * keys down. Use bitwise operators and one or more of the │ │ │ │ + * <OpenLayers.Handler> constants to construct a keyMask. Leave null if │ │ │ │ + * not used mask. Default is null. │ │ │ │ */ │ │ │ │ - vectorRoot: null, │ │ │ │ + keyMask: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: textRoot │ │ │ │ - * {DOMElement} │ │ │ │ + * APIProperty: alwaysZoom │ │ │ │ + * {Boolean} Always zoom in/out when box drawn, even if the zoom level does │ │ │ │ + * not change. │ │ │ │ */ │ │ │ │ - textRoot: null, │ │ │ │ + alwaysZoom: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: xmlns │ │ │ │ - * {String} │ │ │ │ + * APIProperty: zoomOnClick │ │ │ │ + * {Boolean} Should we zoom when no box was dragged, i.e. the user only │ │ │ │ + * clicked? Default is true. │ │ │ │ */ │ │ │ │ - xmlns: null, │ │ │ │ + zoomOnClick: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: draw │ │ │ │ */ │ │ │ │ - xOffset: 0, │ │ │ │ + draw: function() { │ │ │ │ + this.handler = new OpenLayers.Handler.Box(this, { │ │ │ │ + done: this.zoomBox │ │ │ │ + }, { │ │ │ │ + keyMask: this.keyMask │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: zoomBox │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * position - {<OpenLayers.Bounds>} or {<OpenLayers.Pixel>} │ │ │ │ */ │ │ │ │ + zoomBox: function(position) { │ │ │ │ + if (position instanceof OpenLayers.Bounds) { │ │ │ │ + var bounds, │ │ │ │ + targetCenterPx = position.getCenterPixel(); │ │ │ │ + if (!this.out) { │ │ │ │ + var minXY = this.map.getLonLatFromPixel({ │ │ │ │ + x: position.left, │ │ │ │ + y: position.bottom │ │ │ │ + }); │ │ │ │ + var maxXY = this.map.getLonLatFromPixel({ │ │ │ │ + x: position.right, │ │ │ │ + y: position.top │ │ │ │ + }); │ │ │ │ + bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat, │ │ │ │ + maxXY.lon, maxXY.lat); │ │ │ │ + } else { │ │ │ │ + var pixWidth = position.right - position.left; │ │ │ │ + var pixHeight = position.bottom - position.top; │ │ │ │ + var zoomFactor = Math.min((this.map.size.h / pixHeight), │ │ │ │ + (this.map.size.w / pixWidth)); │ │ │ │ + var extent = this.map.getExtent(); │ │ │ │ + var center = this.map.getLonLatFromPixel(targetCenterPx); │ │ │ │ + var xmin = center.lon - (extent.getWidth() / 2) * zoomFactor; │ │ │ │ + var xmax = center.lon + (extent.getWidth() / 2) * zoomFactor; │ │ │ │ + var ymin = center.lat - (extent.getHeight() / 2) * zoomFactor; │ │ │ │ + var ymax = center.lat + (extent.getHeight() / 2) * zoomFactor; │ │ │ │ + bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax); │ │ │ │ + } │ │ │ │ + // always zoom in/out │ │ │ │ + var lastZoom = this.map.getZoom(), │ │ │ │ + size = this.map.getSize(), │ │ │ │ + centerPx = { │ │ │ │ + x: size.w / 2, │ │ │ │ + y: size.h / 2 │ │ │ │ + }, │ │ │ │ + zoom = this.map.getZoomForExtent(bounds), │ │ │ │ + oldRes = this.map.getResolution(), │ │ │ │ + newRes = this.map.getResolutionForZoom(zoom); │ │ │ │ + if (oldRes == newRes) { │ │ │ │ + this.map.setCenter(this.map.getLonLatFromPixel(targetCenterPx)); │ │ │ │ + } else { │ │ │ │ + var zoomOriginPx = { │ │ │ │ + x: (oldRes * targetCenterPx.x - newRes * centerPx.x) / │ │ │ │ + (oldRes - newRes), │ │ │ │ + y: (oldRes * targetCenterPx.y - newRes * centerPx.y) / │ │ │ │ + (oldRes - newRes) │ │ │ │ + }; │ │ │ │ + this.map.zoomTo(zoom, zoomOriginPx); │ │ │ │ + } │ │ │ │ + if (lastZoom == this.map.getZoom() && this.alwaysZoom == true) { │ │ │ │ + this.map.zoomTo(lastZoom + (this.out ? -1 : 1)); │ │ │ │ + } │ │ │ │ + } else if (this.zoomOnClick) { // it's a pixel │ │ │ │ + if (!this.out) { │ │ │ │ + this.map.zoomTo(this.map.getZoom() + 1, position); │ │ │ │ + } else { │ │ │ │ + this.map.zoomTo(this.map.getZoom() - 1, position); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomBox" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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} │ │ │ │ */ │ │ │ │ - indexer: null, │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: BACKGROUND_ID_SUFFIX │ │ │ │ - * {String} │ │ │ │ + * Property: panned │ │ │ │ + * {Boolean} The map moved. │ │ │ │ */ │ │ │ │ - BACKGROUND_ID_SUFFIX: "_background", │ │ │ │ + panned: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: LABEL_ID_SUFFIX │ │ │ │ - * {String} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - LABEL_ID_SUFFIX: "_label", │ │ │ │ + interval: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: LABEL_OUTLINE_SUFFIX │ │ │ │ - * {String} │ │ │ │ + * APIProperty: documentDrag │ │ │ │ + * {Boolean} If set to true, mouse dragging will continue even if the │ │ │ │ + * mouse cursor leaves the map viewport. Default is false. │ │ │ │ */ │ │ │ │ - LABEL_OUTLINE_SUFFIX: "_outline", │ │ │ │ + documentDrag: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: kinetic │ │ │ │ + * {<OpenLayers.Kinetic>} The OpenLayers.Kinetic object. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + kinetic: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroy │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - │ │ │ │ - this.clear(); │ │ │ │ + enableKinetic: true, │ │ │ │ │ │ │ │ - this.rendererRoot = null; │ │ │ │ - this.root = null; │ │ │ │ - this.xmlns = null; │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - OpenLayers.Renderer.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clear │ │ │ │ - * Remove all the elements from the root │ │ │ │ + * Method: draw │ │ │ │ + * Creates a Drag handler, using <panMap> and │ │ │ │ + * <panMapDone> as callbacks. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - if (this.indexer) { │ │ │ │ - this.indexer.clear(); │ │ │ │ - } │ │ │ │ + this.handler = new OpenLayers.Handler.Drag(this, { │ │ │ │ + "move": this.panMap, │ │ │ │ + "done": this.panMapDone, │ │ │ │ + "down": this.panMapStart │ │ │ │ + }, { │ │ │ │ + interval: this.interval, │ │ │ │ + documentDrag: this.documentDrag │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: panMapStart │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + panMapStart: function() { │ │ │ │ + if (this.kinetic) { │ │ │ │ + this.kinetic.begin(); │ │ │ │ } │ │ │ │ - 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. │ │ │ │ + /** │ │ │ │ + * Method: panMap │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ - * featureId - {String} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} true if the geometry has been drawn completely; null if │ │ │ │ - * incomplete; false otherwise │ │ │ │ + * xy - {<OpenLayers.Pixel>} Pixel of the mouse position │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + panMap: function(xy) { │ │ │ │ + if (this.kinetic) { │ │ │ │ + this.kinetic.update(xy); │ │ │ │ } │ │ │ │ - if (removeBackground) { │ │ │ │ - var node = document.getElementById( │ │ │ │ - geometry.id + this.BACKGROUND_ID_SUFFIX); │ │ │ │ - if (node) { │ │ │ │ - node.parentNode.removeChild(node); │ │ │ │ + this.panned = true; │ │ │ │ + this.map.pan( │ │ │ │ + this.handler.last.x - xy.x, │ │ │ │ + this.handler.last.y - xy.y, { │ │ │ │ + dragging: true, │ │ │ │ + animate: false │ │ │ │ } │ │ │ │ - } │ │ │ │ - return rendered; │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: redrawNode │ │ │ │ - * │ │ │ │ + * Method: panMapDone │ │ │ │ + * Finish the panning operation. Only call setCenter (through <panMap>) │ │ │ │ + * if the map has actually been moved. │ │ │ │ + * │ │ │ │ * 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 │ │ │ │ + * xy - {<OpenLayers.Pixel>} Pixel of the mouse position │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + panMapDone: function(xy) { │ │ │ │ + if (this.panned) { │ │ │ │ + var res = null; │ │ │ │ + if (this.kinetic) { │ │ │ │ + res = this.kinetic.end(xy); │ │ │ │ } │ │ │ │ - } 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.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; │ │ │ │ } │ │ │ │ - │ │ │ │ - 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; │ │ │ │ + CLASS_NAME: "OpenLayers.Control.DragPan" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Handler/MouseWheel.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - // Erase background styles. │ │ │ │ - backgroundStyle.backgroundGraphic = null; │ │ │ │ - backgroundStyle.backgroundXOffset = null; │ │ │ │ - backgroundStyle.backgroundYOffset = null; │ │ │ │ - backgroundStyle.backgroundGraphicZIndex = null; │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - return this.redrawNode( │ │ │ │ - id + this.BACKGROUND_ID_SUFFIX, │ │ │ │ - geometry, │ │ │ │ - backgroundStyle, │ │ │ │ - null │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Handler.MouseWheel │ │ │ │ + * Handler for wheel up/down events. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ + */ │ │ │ │ +OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + /** │ │ │ │ + * Property: wheelListener │ │ │ │ + * {function} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + wheelListener: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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} │ │ │ │ + * Property: interval │ │ │ │ + * {Integer} In order to increase server performance, an interval (in │ │ │ │ + * milliseconds) can be set to reduce the number of up/down events │ │ │ │ + * called. If set, a new up/down event will not be set until the │ │ │ │ + * interval has passed. │ │ │ │ + * Defaults to 0, meaning no interval. │ │ │ │ */ │ │ │ │ - postDraw: function(node) {}, │ │ │ │ + interval: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Property: maxDelta │ │ │ │ + * {Integer} Maximum delta to collect before breaking from the current │ │ │ │ + * interval. In cumulative mode, this also limits the maximum delta │ │ │ │ + * returned from the handler. Default is Number.POSITIVE_INFINITY. │ │ │ │ */ │ │ │ │ - drawPoint: function(node, geometry) {}, │ │ │ │ + maxDelta: Number.POSITIVE_INFINITY, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Property: delta │ │ │ │ + * {Integer} When interval is set, delta collects the mousewheel z-deltas │ │ │ │ + * of the events that occur within the interval. │ │ │ │ + * See also the cumulative option │ │ │ │ */ │ │ │ │ - drawLineString: function(node, geometry) {}, │ │ │ │ + delta: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Property: cumulative │ │ │ │ + * {Boolean} When interval is set: true to collect all the mousewheel │ │ │ │ + * z-deltas, false to only record the delta direction (positive or │ │ │ │ + * negative) │ │ │ │ */ │ │ │ │ - drawLinearRing: function(node, geometry) {}, │ │ │ │ + cumulative: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Constructor: OpenLayers.Handler.MouseWheel │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * control - {<OpenLayers.Control>} │ │ │ │ + * 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 point geometry. │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ - drawPolygon: function(node, geometry) {}, │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ + this.wheelListener = OpenLayers.Function.bindAsEventListener( │ │ │ │ + this.onWheelEvent, this │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - drawRectangle: function(node, geometry) {}, │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ + this.wheelListener = null; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/ │ │ │ │ */ │ │ │ │ - drawCircle: function(node, geometry) {}, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: removeText │ │ │ │ - * Removes a label │ │ │ │ + /** │ │ │ │ + * Method: onWheelEvent │ │ │ │ + * Catch the wheel event and handle it xbrowserly │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * featureId - {String} │ │ │ │ + * e - {Event} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + onWheelEvent: function(e) { │ │ │ │ + │ │ │ │ + // make sure we have a map and check keyboard modifiers │ │ │ │ + if (!this.map || !this.checkModifiers(e)) { │ │ │ │ + return; │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - }, │ │ │ │ + // Ride up the element's DOM hierarchy to determine if it or any of │ │ │ │ + // its ancestors was: │ │ │ │ + // * specifically marked as scrollable (CSS overflow property) │ │ │ │ + // * one of our layer divs or a div marked as scrollable │ │ │ │ + // ('olScrollable' CSS class) │ │ │ │ + // * the map div │ │ │ │ + // │ │ │ │ + var overScrollableDiv = false; │ │ │ │ + var allowScroll = false; │ │ │ │ + var overMapDiv = false; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + var elem = OpenLayers.Event.element(e); │ │ │ │ + while ((elem != null) && !overMapDiv && !overScrollableDiv) { │ │ │ │ │ │ │ │ - if (this.indexer) { │ │ │ │ - this.indexer.remove(element); │ │ │ │ + if (!overScrollableDiv) { │ │ │ │ + try { │ │ │ │ + var overflow; │ │ │ │ + if (elem.currentStyle) { │ │ │ │ + overflow = elem.currentStyle["overflow"]; │ │ │ │ + } else { │ │ │ │ + var style = │ │ │ │ + document.defaultView.getComputedStyle(elem, null); │ │ │ │ + overflow = style.getPropertyValue("overflow"); │ │ │ │ + } │ │ │ │ + overScrollableDiv = (overflow && │ │ │ │ + (overflow == "auto") || (overflow == "scroll")); │ │ │ │ + } catch (err) { │ │ │ │ + //sometimes when scrolling in a popup, this causes │ │ │ │ + // obscure browser error │ │ │ │ } │ │ │ │ + } │ │ │ │ │ │ │ │ - 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); │ │ │ │ + if (!allowScroll) { │ │ │ │ + allowScroll = OpenLayers.Element.hasClass(elem, 'olScrollable'); │ │ │ │ + if (!allowScroll) { │ │ │ │ + for (var i = 0, len = this.map.layers.length; i < len; i++) { │ │ │ │ + // Are we in the layer div? Note that we have two cases │ │ │ │ + // here: one is to catch EventPane layers, which have a │ │ │ │ + // pane above the layer (layer.pane) │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + if (elem == layer.div || elem == layer.pane) { │ │ │ │ + allowScroll = true; │ │ │ │ + break; │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ + overMapDiv = (elem == this.map.div); │ │ │ │ + │ │ │ │ + elem = elem.parentNode; │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + // Logic below is the following: │ │ │ │ + // │ │ │ │ + // If we are over a scrollable div or not over the map div: │ │ │ │ + // * do nothing (let the browser handle scrolling) │ │ │ │ + // │ │ │ │ + // otherwise │ │ │ │ + // │ │ │ │ + // If we are over the layer div or a 'olScrollable' div: │ │ │ │ + // * zoom/in out │ │ │ │ + // then │ │ │ │ + // * kill event (so as not to also scroll the page after zooming) │ │ │ │ + // │ │ │ │ + // otherwise │ │ │ │ + // │ │ │ │ + // Kill the event (dont scroll the page if we wheel over the │ │ │ │ + // layerswitcher or the pan/zoom control) │ │ │ │ + // │ │ │ │ + if (!overScrollableDiv && overMapDiv) { │ │ │ │ + if (allowScroll) { │ │ │ │ + var delta = 0; │ │ │ │ + │ │ │ │ + if (e.wheelDelta) { │ │ │ │ + delta = e.wheelDelta; │ │ │ │ + if (delta % 160 === 0) { │ │ │ │ + // opera have steps of 160 instead of 120 │ │ │ │ + delta = delta * 0.75; │ │ │ │ + } │ │ │ │ + delta = delta / 120; │ │ │ │ + } else if (e.detail) { │ │ │ │ + // detail in Firefox on OS X is 1/3 of Windows │ │ │ │ + // so force delta 1 / -1 │ │ │ │ + delta = -(e.detail / Math.abs(e.detail)); │ │ │ │ + } │ │ │ │ + this.delta += delta; │ │ │ │ + │ │ │ │ + window.clearTimeout(this._timeoutId); │ │ │ │ + if (this.interval && Math.abs(this.delta) < this.maxDelta) { │ │ │ │ + // store e because window.event might change during delay │ │ │ │ + var evt = OpenLayers.Util.extend({}, e); │ │ │ │ + this._timeoutId = window.setTimeout( │ │ │ │ + OpenLayers.Function.bind(function() { │ │ │ │ + this.wheelZoom(evt); │ │ │ │ + }, this), │ │ │ │ + this.interval │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + this.wheelZoom(e); │ │ │ │ + } │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - node = this.createNode(type, id); │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ } │ │ │ │ - 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. │ │ │ │ + * Method: wheelZoom │ │ │ │ + * Given the wheel event, we carry out the appropriate zooming in or out, │ │ │ │ + * based on the 'wheelDelta' or 'detail' property of the event. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * renderer - {<OpenLayers.Renderer>} target renderer for the moved root │ │ │ │ + * e - {Event} │ │ │ │ */ │ │ │ │ - moveRoot: function(renderer) { │ │ │ │ - var root = this.root; │ │ │ │ - if (renderer.root.parentNode == this.rendererRoot) { │ │ │ │ - root = renderer.root; │ │ │ │ + wheelZoom: function(e) { │ │ │ │ + var delta = this.delta; │ │ │ │ + this.delta = 0; │ │ │ │ + │ │ │ │ + if (delta) { │ │ │ │ + e.xy = this.map.events.getMousePosition(e); │ │ │ │ + if (delta < 0) { │ │ │ │ + this.callback("down", │ │ │ │ + [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]); │ │ │ │ + } else { │ │ │ │ + this.callback("up", │ │ │ │ + [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]); │ │ │ │ + } │ │ │ │ } │ │ │ │ - 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. │ │ │ │ + * Method: activate │ │ │ │ */ │ │ │ │ - getRenderLayerId: function() { │ │ │ │ - return this.root.parentNode.parentNode.id; │ │ │ │ + activate: function(evt) { │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + //register mousewheel events specifically on the window and document │ │ │ │ + var wheelListener = this.wheelListener; │ │ │ │ + OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener); │ │ │ │ + OpenLayers.Event.observe(window, "mousewheel", wheelListener); │ │ │ │ + OpenLayers.Event.observe(document, "mousewheel", wheelListener); │ │ │ │ + return true; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Method: deactivate │ │ │ │ */ │ │ │ │ - isComplexSymbol: function(graphicName) { │ │ │ │ - return (graphicName != "circle") && !!graphicName; │ │ │ │ + deactivate: function(evt) { │ │ │ │ + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + // unregister mousewheel events specifically on the window and document │ │ │ │ + var wheelListener = this.wheelListener; │ │ │ │ + OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener); │ │ │ │ + OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener); │ │ │ │ + OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener); │ │ │ │ + return true; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.Elements" │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.MouseWheel" │ │ │ │ }); │ │ │ │ - │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Renderer/SVG.js │ │ │ │ + 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/Renderer/Elements.js │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Renderer.SVG │ │ │ │ + * 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: │ │ │ │ - * - <OpenLayers.Renderer.Elements> │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -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", │ │ │ │ - │ │ │ │ +OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: delay │ │ │ │ + * {Number} Number of milliseconds between clicks before the event is │ │ │ │ + * considered a double-click. │ │ │ │ */ │ │ │ │ - MAX_PIXEL: 15000, │ │ │ │ + delay: 300, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: translationParameters │ │ │ │ - * {Object} Hash with "x" and "y" properties │ │ │ │ + * APIProperty: single │ │ │ │ + * {Boolean} Handle single clicks. Default is true. If false, clicks │ │ │ │ + * will not be reported. If true, single-clicks will be reported. │ │ │ │ */ │ │ │ │ - translationParameters: null, │ │ │ │ + single: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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]. │ │ │ │ + * APIProperty: double │ │ │ │ + * {Boolean} Handle double-clicks. Default is false. │ │ │ │ */ │ │ │ │ - symbolMetrics: null, │ │ │ │ + 'double': false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Renderer.SVG │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * containerID - {String} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - initialize: function(containerID) { │ │ │ │ - if (!this.supported()) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - OpenLayers.Renderer.Elements.prototype.initialize.apply(this, │ │ │ │ - arguments); │ │ │ │ - this.translationParameters = { │ │ │ │ - x: 0, │ │ │ │ - y: 0 │ │ │ │ - }; │ │ │ │ - │ │ │ │ - this.symbolMetrics = {}; │ │ │ │ - }, │ │ │ │ + pixelTolerance: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: supported │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the browser supports the SVG renderer │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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"))); │ │ │ │ - }, │ │ │ │ + dblclickTolerance: 13, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - }, │ │ │ │ + stopSingle: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setExtent │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * extent - {<OpenLayers.Bounds>} │ │ │ │ - * resolutionChanged - {Boolean} │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + stopDouble: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: timerId │ │ │ │ + * {Number} The id of the timeout waiting to clear the <delayedCall>. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + timerId: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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, ","); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + down: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - createNode: function(type, id) { │ │ │ │ - var node = document.createElementNS(this.xmlns, type); │ │ │ │ - if (id) { │ │ │ │ - node.setAttributeNS(null, "id", id); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ + last: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Property: first │ │ │ │ + * {Object} When waiting for double clicks, this object will store │ │ │ │ + * information about the first click in a two click sequence. │ │ │ │ */ │ │ │ │ - nodeTypeCompare: function(node, type) { │ │ │ │ - return (type == node.nodeName); │ │ │ │ - }, │ │ │ │ + first: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createRenderRoot │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} The specific render engine's root element │ │ │ │ + * Property: rightclickTimerId │ │ │ │ + * {Number} The id of the right mouse timeout waiting to clear the │ │ │ │ + * <delayedEvent>. │ │ │ │ */ │ │ │ │ - createRenderRoot: function() { │ │ │ │ - var svg = this.nodeFactory(this.container.id + "_svgRoot", "svg"); │ │ │ │ - svg.style.display = "block"; │ │ │ │ - return svg; │ │ │ │ - }, │ │ │ │ + rightclickTimerId: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createRoot │ │ │ │ + * Constructor: OpenLayers.Handler.Click │ │ │ │ + * Create a new click handler. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * suffix - {String} suffix to append to the id │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - createRoot: function(suffix) { │ │ │ │ - return this.nodeFactory(this.container.id + suffix, "g"); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createDefs │ │ │ │ + * Method: touchstart │ │ │ │ + * Handle touchstart. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} The element to which we'll add the symbol definitions │ │ │ │ + * {Boolean} Continue propagating this event. │ │ │ │ */ │ │ │ │ - createDefs: function() { │ │ │ │ - var defs = this.nodeFactory(this.container.id + "_defs", "defs"); │ │ │ │ - this.rendererRoot.appendChild(defs); │ │ │ │ - return defs; │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + this.down = this.getEventInfo(evt); │ │ │ │ + this.last = this.getEventInfo(evt); │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ - /************************************** │ │ │ │ - * * │ │ │ │ - * GEOMETRY DRAWING FUNCTIONS * │ │ │ │ - * * │ │ │ │ - **************************************/ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: drawPoint │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ + * Method: touchmove │ │ │ │ + * Store position of last move, because touchend event can have │ │ │ │ + * an empty "touches" property. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} or false if the renderer could not draw the point │ │ │ │ + * {Boolean} Continue propagating this event. │ │ │ │ */ │ │ │ │ - drawPoint: function(node, geometry) { │ │ │ │ - return this.drawCircle(node, geometry, 1); │ │ │ │ + touchmove: function(evt) { │ │ │ │ + this.last = this.getEventInfo(evt); │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawCircle │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * radius - {Float} │ │ │ │ - * │ │ │ │ + * Method: touchend │ │ │ │ + * Correctly set event xy property, and add lastTouches to have │ │ │ │ + * touches property from last touchstart or touchmove │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} or false if the renderer could not draw the circle │ │ │ │ + * {Boolean} Continue propagating this event. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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: drawLineString │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ + * Method: mousedown │ │ │ │ + * Handle mousedown. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} or null if the renderer could not draw all components of │ │ │ │ - * the linestring, or false if nothing could be drawn │ │ │ │ + * {Boolean} Continue propagating this event. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + mousedown: function(evt) { │ │ │ │ + this.down = this.getEventInfo(evt); │ │ │ │ + this.last = this.getEventInfo(evt); │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawLinearRing │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * Method: mouseup │ │ │ │ + * Handle mouseup. Installed to support collection of right mouse events. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} or null if the renderer could not draw all components │ │ │ │ - * of the linear ring, or false if nothing could be drawn │ │ │ │ + * {Boolean} Continue propagating this event. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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: drawPolygon │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * {DOMElement} or null if the renderer could not draw all components │ │ │ │ - * of the polygon, or false if nothing could be drawn │ │ │ │ + * {Boolean} Continue propagating this event. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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 { │ │ │ │ - draw = false; │ │ │ │ + //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 │ │ │ │ + ); │ │ │ │ } │ │ │ │ } │ │ │ │ - d += " z"; │ │ │ │ - if (draw) { │ │ │ │ - node.setAttributeNS(null, "d", d); │ │ │ │ - node.setAttributeNS(null, "fill-rule", "evenodd"); │ │ │ │ - return complete ? node : null; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ + return !this.stopSingle; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Method: delayedRightCall │ │ │ │ + * Sets <rightclickTimerId> to null. And optionally triggers the │ │ │ │ + * rightclick callback if evt is set. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + delayedRightCall: function(evt) { │ │ │ │ + this.rightclickTimerId = null; │ │ │ │ + if (evt) { │ │ │ │ + this.callback('rightclick', [evt]); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawText │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * featureId - {String} │ │ │ │ - * style - │ │ │ │ - * location - {<OpenLayers.Geometry.Point>} │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Continue propagating this event. │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ + click: function(evt) { │ │ │ │ + if (!this.last) { │ │ │ │ + this.last = this.getEventInfo(evt); │ │ │ │ } │ │ │ │ - var align = style.labelAlign || OpenLayers.Renderer.defaultSymbolizer.labelAlign; │ │ │ │ - label.setAttributeNS(null, "text-anchor", │ │ │ │ - OpenLayers.Renderer.SVG.LABEL_ALIGN[align[0]] || "middle"); │ │ │ │ + this.handleSingle(evt); │ │ │ │ + return !this.stopSingle; │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (OpenLayers.IS_GECKO === true) { │ │ │ │ - label.setAttributeNS(null, "dominant-baseline", │ │ │ │ - OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]] || "central"); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - 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); │ │ │ │ + /** │ │ │ │ + * Method: handleDouble │ │ │ │ + * Handle double-click sequence. │ │ │ │ + */ │ │ │ │ + handleDouble: function(evt) { │ │ │ │ + if (this.passesDblclickTolerance(evt)) { │ │ │ │ + if (this["double"]) { │ │ │ │ + this.callback("dblclick", [evt]); │ │ │ │ } │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (!label.parentNode) { │ │ │ │ - this.textRoot.appendChild(label); │ │ │ │ + // to prevent a dblclick from firing the click callback in IE │ │ │ │ + this.clearTimer(); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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) │ │ │ │ + * Method: handleSingle │ │ │ │ + * Handle single click sequence. │ │ │ │ */ │ │ │ │ - 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])); │ │ │ │ + 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 (i < len - 1) { │ │ │ │ - if (this.getShortString(components[i + 1])) { │ │ │ │ - strings.push(this.clipLine(components[i], │ │ │ │ - components[i + 1])); │ │ │ │ - } │ │ │ │ + // 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(); │ │ │ │ } │ │ │ │ - complete = false; │ │ │ │ + } 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); │ │ │ │ } │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - return { │ │ │ │ - path: strings.join(separator || ","), │ │ │ │ - complete: complete │ │ │ │ - }; │ │ │ │ + /** │ │ │ │ + * 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: 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. │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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 x2 + "," + y2; │ │ │ │ + return passes; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getShortString │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * point - {<OpenLayers.Geometry.Point>} │ │ │ │ - * │ │ │ │ + * Method: getTouchDistance │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {String} or false if point is outside the valid range │ │ │ │ + * {Boolean} The pixel displacement between two touches. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + getTouchDistance: function(from, to) { │ │ │ │ + return Math.sqrt( │ │ │ │ + Math.pow(from.clientX - to.clientX, 2) + │ │ │ │ + Math.pow(from.clientY - to.clientY, 2) │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getPosition │ │ │ │ - * Finds the position of an svg node. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * │ │ │ │ + * Method: passesDblclickTolerance │ │ │ │ + * Determine whether the event is within the optional double-cick pixel │ │ │ │ + * tolerance. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} hash with x and y properties, representing the coordinates │ │ │ │ - * within the svg coordinate system │ │ │ │ + * {Boolean} The click is within the double-click pixel tolerance. │ │ │ │ */ │ │ │ │ - getPosition: function(node) { │ │ │ │ - return ({ │ │ │ │ - x: parseFloat(node.getAttributeNS(null, "cx")), │ │ │ │ - y: parseFloat(node.getAttributeNS(null, "cy")) │ │ │ │ - }); │ │ │ │ + passesDblclickTolerance: function(evt) { │ │ │ │ + var passes = true; │ │ │ │ + if (this.down && this.first) { │ │ │ │ + passes = this.down.xy.distanceTo(this.first.xy) <= this.dblclickTolerance; │ │ │ │ + } │ │ │ │ + return passes; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Method: clearTimer │ │ │ │ + * Clear the timer and set <timerId> to null. │ │ │ │ */ │ │ │ │ - importSymbol: function(graphicName) { │ │ │ │ - if (!this.defs) { │ │ │ │ - // create svg defs tag │ │ │ │ - this.defs = this.createDefs(); │ │ │ │ + clearTimer: function() { │ │ │ │ + if (this.timerId != null) { │ │ │ │ + window.clearTimeout(this.timerId); │ │ │ │ + this.timerId = null; │ │ │ │ } │ │ │ │ - var id = this.container.id + "-" + graphicName; │ │ │ │ - │ │ │ │ - // check if symbol already exists in the defs │ │ │ │ - var existing = document.getElementById(id); │ │ │ │ - if (existing != null) { │ │ │ │ - return existing; │ │ │ │ + if (this.rightclickTimerId != null) { │ │ │ │ + window.clearTimeout(this.rightclickTimerId); │ │ │ │ + this.rightclickTimerId = null; │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - var symbol = OpenLayers.Renderer.symbol[graphicName]; │ │ │ │ - if (!symbol) { │ │ │ │ - throw new Error(graphicName + ' is not a valid symbol name'); │ │ │ │ + /** │ │ │ │ + * 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]); │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - 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); │ │ │ │ + /** │ │ │ │ + * 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 │ │ │ │ + }; │ │ │ │ + } │ │ │ │ } │ │ │ │ - │ │ │ │ - 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; │ │ │ │ + return { │ │ │ │ + xy: evt.xy, │ │ │ │ + touches: touches │ │ │ │ + }; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getFeatureIdFromEvent │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} An <OpenLayers.Event> object │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the handler. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} A feature id or undefined. │ │ │ │ + * {Boolean} The handler was successfully deactivated. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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 featureId; │ │ │ │ + return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.SVG" │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Click" │ │ │ │ }); │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * 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/Renderer/VML.js │ │ │ │ + OpenLayers/Control/Navigation.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 │ │ │ │ + * @requires OpenLayers/Control/ZoomBox.js │ │ │ │ + * @requires OpenLayers/Control/DragPan.js │ │ │ │ + * @requires OpenLayers/Handler/MouseWheel.js │ │ │ │ + * @requires OpenLayers/Handler/Click.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Renderer.VML │ │ │ │ - * Render vector features in browsers with VML capability. Construct a new │ │ │ │ - * VML renderer with the <OpenLayers.Renderer.VML> constructor. │ │ │ │ + * Class: OpenLayers.Control.Navigation │ │ │ │ + * The navigation control handles map browsing with mouse events (dragging, │ │ │ │ + * double-clicking, and scrolling the wheel). Create a new navigation │ │ │ │ + * control with the <OpenLayers.Control.Navigation> control. │ │ │ │ * │ │ │ │ - * Note that for all calculations in this class, we use (num | 0) to truncate a │ │ │ │ - * float value to an integer. This is done because it seems that VML doesn't │ │ │ │ - * support float values. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Renderer.Elements> │ │ │ │ + * Note that this control is added to the map by default (if no controls │ │ │ │ + * array is sent in the options object to the <OpenLayers.Map> │ │ │ │ + * constructor). │ │ │ │ + * │ │ │ │ + * Inherits: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ +OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: xmlns │ │ │ │ - * {String} XML Namespace URN │ │ │ │ + /** │ │ │ │ + * Property: dragPan │ │ │ │ + * {<OpenLayers.Control.DragPan>} │ │ │ │ */ │ │ │ │ - xmlns: "urn:schemas-microsoft-com:vml", │ │ │ │ + dragPan: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: symbolCache │ │ │ │ - * {DOMElement} node holding symbols. This hash is keyed by symbol name, │ │ │ │ - * and each value is a hash with a "path" and an "extent" property. │ │ │ │ + * APIProperty: dragPanOptions │ │ │ │ + * {Object} Options passed to the DragPan control. │ │ │ │ */ │ │ │ │ - symbolCache: {}, │ │ │ │ + dragPanOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: offset │ │ │ │ - * {Object} Hash with "x" and "y" properties │ │ │ │ + * Property: pinchZoom │ │ │ │ + * {<OpenLayers.Control.PinchZoom>} │ │ │ │ */ │ │ │ │ - offset: null, │ │ │ │ + pinchZoom: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Renderer.VML │ │ │ │ - * Create a new VML renderer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * containerID - {String} The id for the element that contains the renderer │ │ │ │ + * APIProperty: pinchZoomOptions │ │ │ │ + * {Object} Options passed to the PinchZoom control. │ │ │ │ */ │ │ │ │ - initialize: function(containerID) { │ │ │ │ - if (!this.supported()) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - if (!document.namespaces.olv) { │ │ │ │ - document.namespaces.add("olv", this.xmlns); │ │ │ │ - var style = document.createStyleSheet(); │ │ │ │ - var shapes = ['shape', 'rect', 'oval', 'fill', 'stroke', 'imagedata', 'group', 'textbox']; │ │ │ │ - for (var i = 0, len = shapes.length; i < len; i++) { │ │ │ │ + pinchZoomOptions: null, │ │ │ │ │ │ │ │ - style.addRule('olv\\:' + shapes[i], "behavior: url(#default#VML); " + │ │ │ │ - "position: absolute; display: inline-block;"); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: documentDrag │ │ │ │ + * {Boolean} Allow panning of the map by dragging outside map viewport. │ │ │ │ + * Default is false. │ │ │ │ + */ │ │ │ │ + documentDrag: false, │ │ │ │ │ │ │ │ - OpenLayers.Renderer.Elements.prototype.initialize.apply(this, │ │ │ │ - arguments); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: zoomBox │ │ │ │ + * {<OpenLayers.Control.ZoomBox>} │ │ │ │ + */ │ │ │ │ + zoomBox: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: supported │ │ │ │ - * Determine whether a browser supports this renderer. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The browser supports the VML renderer │ │ │ │ + * APIProperty: zoomBoxEnabled │ │ │ │ + * {Boolean} Whether the user can draw a box to zoom │ │ │ │ */ │ │ │ │ - supported: function() { │ │ │ │ - return !!(document.namespaces); │ │ │ │ - }, │ │ │ │ + zoomBoxEnabled: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setExtent │ │ │ │ - * Set the renderer's extent │ │ │ │ - * │ │ │ │ - * 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. │ │ │ │ + * APIProperty: zoomWheelEnabled │ │ │ │ + * {Boolean} Whether the mousewheel should zoom the map │ │ │ │ */ │ │ │ │ - setExtent: function(extent, resolutionChanged) { │ │ │ │ - var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments); │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - │ │ │ │ - var left = (extent.left / resolution) | 0; │ │ │ │ - var top = (extent.top / resolution - this.size.h) | 0; │ │ │ │ - if (resolutionChanged || !this.offset) { │ │ │ │ - this.offset = { │ │ │ │ - x: left, │ │ │ │ - y: top │ │ │ │ - }; │ │ │ │ - left = 0; │ │ │ │ - top = 0; │ │ │ │ - } else { │ │ │ │ - left = left - this.offset.x; │ │ │ │ - top = top - this.offset.y; │ │ │ │ - } │ │ │ │ - │ │ │ │ - │ │ │ │ - var org = (left - this.xOffset) + " " + top; │ │ │ │ - this.root.coordorigin = org; │ │ │ │ - var roots = [this.root, this.vectorRoot, this.textRoot]; │ │ │ │ - var root; │ │ │ │ - for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ - root = roots[i]; │ │ │ │ - │ │ │ │ - var size = this.size.w + " " + this.size.h; │ │ │ │ - root.coordsize = size; │ │ │ │ - │ │ │ │ - } │ │ │ │ - // flip the VML display Y axis upside down so it │ │ │ │ - // matches the display Y axis of the map │ │ │ │ - this.root.style.flip = "y"; │ │ │ │ - │ │ │ │ - return coordSysUnchanged; │ │ │ │ - }, │ │ │ │ - │ │ │ │ + zoomWheelEnabled: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setSize │ │ │ │ - * Set the size of the drawing surface │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * size - {<OpenLayers.Size>} the size of the drawing surface │ │ │ │ + * Property: mouseWheelOptions │ │ │ │ + * {Object} Options passed to the MouseWheel control (only useful if │ │ │ │ + * <zoomWheelEnabled> is set to true). Default is no options for maps │ │ │ │ + * with fractionalZoom set to true, otherwise │ │ │ │ + * {cumulative: false, interval: 50, maxDelta: 6} │ │ │ │ */ │ │ │ │ - setSize: function(size) { │ │ │ │ - OpenLayers.Renderer.prototype.setSize.apply(this, arguments); │ │ │ │ - │ │ │ │ - // setting width and height on all roots to avoid flicker which we │ │ │ │ - // would get with 100% width and height on child roots │ │ │ │ - var roots = [ │ │ │ │ - this.rendererRoot, │ │ │ │ - this.root, │ │ │ │ - this.vectorRoot, │ │ │ │ - this.textRoot │ │ │ │ - ]; │ │ │ │ - var w = this.size.w + "px"; │ │ │ │ - var h = this.size.h + "px"; │ │ │ │ - var root; │ │ │ │ - for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ - root = roots[i]; │ │ │ │ - root.style.width = w; │ │ │ │ - root.style.height = h; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + mouseWheelOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getNodeType │ │ │ │ - * Get the node type for a geometry and style │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} The corresponding node type for the specified geometry │ │ │ │ + * APIProperty: handleRightClicks │ │ │ │ + * {Boolean} Whether or not to handle right clicks. Default is false. │ │ │ │ */ │ │ │ │ - getNodeType: function(geometry, style) { │ │ │ │ - var nodeType = null; │ │ │ │ - switch (geometry.CLASS_NAME) { │ │ │ │ - case "OpenLayers.Geometry.Point": │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - nodeType = "olv:rect"; │ │ │ │ - } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ - nodeType = "olv:shape"; │ │ │ │ - } else { │ │ │ │ - nodeType = "olv:oval"; │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "OpenLayers.Geometry.Rectangle": │ │ │ │ - nodeType = "olv:rect"; │ │ │ │ - break; │ │ │ │ - case "OpenLayers.Geometry.LineString": │ │ │ │ - case "OpenLayers.Geometry.LinearRing": │ │ │ │ - case "OpenLayers.Geometry.Polygon": │ │ │ │ - case "OpenLayers.Geometry.Curve": │ │ │ │ - nodeType = "olv:shape"; │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - return nodeType; │ │ │ │ - }, │ │ │ │ + handleRightClicks: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setStyle │ │ │ │ - * Use to set all the style attributes to a VML node. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} An VML element to decorate │ │ │ │ - * style - {Object} │ │ │ │ - * options - {Object} Currently supported options include │ │ │ │ - * 'isFilled' {Boolean} and │ │ │ │ - * 'isStroked' {Boolean} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * APIProperty: zoomBoxKeyMask │ │ │ │ + * {Integer} <OpenLayers.Handler> key code of the key, which has to be │ │ │ │ + * pressed, while drawing the zoom box with the mouse on the screen. │ │ │ │ + * You should probably set handleRightClicks to true if you use this │ │ │ │ + * with MOD_CTRL, to disable the context menu for machines which use │ │ │ │ + * CTRL-Click as a right click. │ │ │ │ + * Default: <OpenLayers.Handler.MOD_SHIFT> │ │ │ │ */ │ │ │ │ - setStyle: function(node, style, options, geometry) { │ │ │ │ - style = style || node._style; │ │ │ │ - options = options || node._options; │ │ │ │ - var fillColor = style.fillColor; │ │ │ │ - │ │ │ │ - var title = style.title || style.graphicTitle; │ │ │ │ - if (title) { │ │ │ │ - node.title = title; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - options.isFilled = true; │ │ │ │ - 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 resolution = this.getResolution(); │ │ │ │ - var xOffset = (style.graphicXOffset != undefined) ? │ │ │ │ - style.graphicXOffset : -(0.5 * width); │ │ │ │ - var yOffset = (style.graphicYOffset != undefined) ? │ │ │ │ - style.graphicYOffset : -(0.5 * height); │ │ │ │ - │ │ │ │ - node.style.left = ((((geometry.x - this.featureDx) / resolution - this.offset.x) + xOffset) | 0) + "px"; │ │ │ │ - node.style.top = (((geometry.y / resolution - this.offset.y) - (yOffset + height)) | 0) + "px"; │ │ │ │ - node.style.width = width + "px"; │ │ │ │ - node.style.height = height + "px"; │ │ │ │ - node.style.flip = "y"; │ │ │ │ - │ │ │ │ - // modify fillColor and options for stroke styling below │ │ │ │ - fillColor = "none"; │ │ │ │ - options.isStroked = false; │ │ │ │ - } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ - var cache = this.importSymbol(style.graphicName); │ │ │ │ - node.path = cache.path; │ │ │ │ - node.coordorigin = cache.left + "," + cache.bottom; │ │ │ │ - var size = cache.size; │ │ │ │ - node.coordsize = size + "," + size; │ │ │ │ - this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ - node.style.flip = "y"; │ │ │ │ - } else { │ │ │ │ - this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // fill │ │ │ │ - if (options.isFilled) { │ │ │ │ - node.fillcolor = fillColor; │ │ │ │ - } else { │ │ │ │ - node.filled = "false"; │ │ │ │ - } │ │ │ │ - var fills = node.getElementsByTagName("fill"); │ │ │ │ - var fill = (fills.length == 0) ? null : fills[0]; │ │ │ │ - if (!options.isFilled) { │ │ │ │ - if (fill) { │ │ │ │ - node.removeChild(fill); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (!fill) { │ │ │ │ - fill = this.createNode('olv:fill', node.id + "_fill"); │ │ │ │ - } │ │ │ │ - fill.opacity = style.fillOpacity; │ │ │ │ - │ │ │ │ - if (node._geometryClass === "OpenLayers.Geometry.Point" && │ │ │ │ - style.externalGraphic) { │ │ │ │ - │ │ │ │ - // override fillOpacity │ │ │ │ - if (style.graphicOpacity) { │ │ │ │ - fill.opacity = style.graphicOpacity; │ │ │ │ - } │ │ │ │ - │ │ │ │ - fill.src = style.externalGraphic; │ │ │ │ - fill.type = "frame"; │ │ │ │ - │ │ │ │ - if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ - fill.aspect = "atmost"; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (fill.parentNode != node) { │ │ │ │ - node.appendChild(fill); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // additional rendering for rotated graphics or symbols │ │ │ │ - var rotation = style.rotation; │ │ │ │ - if ((rotation !== undefined || node._rotation !== undefined)) { │ │ │ │ - node._rotation = rotation; │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ - // make the fill fully transparent, because we now have │ │ │ │ - // the graphic as imagedata element. We cannot just remove │ │ │ │ - // the fill, because this is part of the hack described │ │ │ │ - // in graphicRotate │ │ │ │ - fill.opacity = 0; │ │ │ │ - } else if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ - node.style.rotation = rotation || 0; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // stroke │ │ │ │ - var strokes = node.getElementsByTagName("stroke"); │ │ │ │ - var stroke = (strokes.length == 0) ? null : strokes[0]; │ │ │ │ - if (!options.isStroked) { │ │ │ │ - node.stroked = false; │ │ │ │ - if (stroke) { │ │ │ │ - stroke.on = false; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (!stroke) { │ │ │ │ - stroke = this.createNode('olv:stroke', node.id + "_stroke"); │ │ │ │ - node.appendChild(stroke); │ │ │ │ - } │ │ │ │ - stroke.on = true; │ │ │ │ - stroke.color = style.strokeColor; │ │ │ │ - stroke.weight = style.strokeWidth + "px"; │ │ │ │ - stroke.opacity = style.strokeOpacity; │ │ │ │ - stroke.endcap = style.strokeLinecap == 'butt' ? 'flat' : │ │ │ │ - (style.strokeLinecap || 'round'); │ │ │ │ - if (style.strokeDashstyle) { │ │ │ │ - stroke.dashstyle = this.dashStyle(style); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + zoomBoxKeyMask: OpenLayers.Handler.MOD_SHIFT, │ │ │ │ │ │ │ │ - if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ - node.style.cursor = style.cursor; │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * APIProperty: autoActivate │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * true. │ │ │ │ + */ │ │ │ │ + autoActivate: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: graphicRotate │ │ │ │ - * If a point is to be styled with externalGraphic and rotation, VML fills │ │ │ │ - * cannot be used to display the graphic, because rotation of graphic │ │ │ │ - * fills is not supported by the VML implementation of Internet Explorer. │ │ │ │ - * This method creates a olv:imagedata element inside the VML node, │ │ │ │ - * DXImageTransform.Matrix and BasicImage filters for rotation and │ │ │ │ - * opacity, and a 3-step hack to remove rendering artefacts from the │ │ │ │ - * graphic and preserve the ability of graphics to trigger events. │ │ │ │ - * Finally, OpenLayers methods are used to determine the correct │ │ │ │ - * insertion point of the rotated image, because DXImageTransform.Matrix │ │ │ │ - * does the rotation without the ability to specify a rotation center │ │ │ │ - * point. │ │ │ │ + * Constructor: OpenLayers.Control.Navigation │ │ │ │ + * Create a new navigation control │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * xOffset - {Number} rotation center relative to image, x coordinate │ │ │ │ - * yOffset - {Number} rotation center relative to image, y coordinate │ │ │ │ - * style - {Object} │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * the control │ │ │ │ */ │ │ │ │ - graphicRotate: function(node, xOffset, yOffset, style) { │ │ │ │ - var style = style || node._style; │ │ │ │ - var rotation = style.rotation || 0; │ │ │ │ + initialize: function(options) { │ │ │ │ + this.handlers = {}; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ - var aspectRatio, size; │ │ │ │ - if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ - // load the image to determine its size │ │ │ │ - var img = new Image(); │ │ │ │ - img.onreadystatechange = OpenLayers.Function.bind(function() { │ │ │ │ - if (img.readyState == "complete" || │ │ │ │ - img.readyState == "interactive") { │ │ │ │ - aspectRatio = img.width / img.height; │ │ │ │ - size = Math.max(style.pointRadius * 2, │ │ │ │ - style.graphicWidth || 0, │ │ │ │ - style.graphicHeight || 0); │ │ │ │ - xOffset = xOffset * aspectRatio; │ │ │ │ - style.graphicWidth = size * aspectRatio; │ │ │ │ - style.graphicHeight = size; │ │ │ │ - this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ - } │ │ │ │ - }, this); │ │ │ │ - img.src = style.externalGraphic; │ │ │ │ + /** │ │ │ │ + * 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(); │ │ │ │ │ │ │ │ - // will be called again by the onreadystate handler │ │ │ │ - return; │ │ │ │ - } else { │ │ │ │ - size = Math.max(style.graphicWidth, style.graphicHeight); │ │ │ │ - aspectRatio = style.graphicWidth / style.graphicHeight; │ │ │ │ + if (this.dragPan) { │ │ │ │ + this.dragPan.destroy(); │ │ │ │ } │ │ │ │ + this.dragPan = null; │ │ │ │ │ │ │ │ - var width = Math.round(style.graphicWidth || size * aspectRatio); │ │ │ │ - var height = Math.round(style.graphicHeight || size); │ │ │ │ - node.style.width = width + "px"; │ │ │ │ - node.style.height = height + "px"; │ │ │ │ - │ │ │ │ - // Three steps are required to remove artefacts for images with │ │ │ │ - // transparent backgrounds (resulting from using DXImageTransform │ │ │ │ - // filters on svg objects), while preserving awareness for browser │ │ │ │ - // events on images: │ │ │ │ - // - Use the fill as usual (like for unrotated images) to handle │ │ │ │ - // events │ │ │ │ - // - specify an imagedata element with the same src as the fill │ │ │ │ - // - style the imagedata element with an AlphaImageLoader filter │ │ │ │ - // with empty src │ │ │ │ - var image = document.getElementById(node.id + "_image"); │ │ │ │ - if (!image) { │ │ │ │ - image = this.createNode("olv:imagedata", node.id + "_image"); │ │ │ │ - node.appendChild(image); │ │ │ │ + if (this.zoomBox) { │ │ │ │ + this.zoomBox.destroy(); │ │ │ │ } │ │ │ │ - image.style.width = width + "px"; │ │ │ │ - image.style.height = height + "px"; │ │ │ │ - image.src = style.externalGraphic; │ │ │ │ - image.style.filter = │ │ │ │ - "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + │ │ │ │ - "src='', sizingMethod='scale')"; │ │ │ │ - │ │ │ │ - var rot = rotation * Math.PI / 180; │ │ │ │ - var sintheta = Math.sin(rot); │ │ │ │ - var costheta = Math.cos(rot); │ │ │ │ - │ │ │ │ - // do the rotation on the image │ │ │ │ - var filter = │ │ │ │ - "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta + │ │ │ │ - ",M12=" + (-sintheta) + ",M21=" + sintheta + ",M22=" + costheta + │ │ │ │ - ",SizingMethod='auto expand')\n"; │ │ │ │ + this.zoomBox = null; │ │ │ │ │ │ │ │ - // set the opacity (needed for the imagedata) │ │ │ │ - var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ - if (opacity && opacity != 1) { │ │ │ │ - filter += │ │ │ │ - "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + │ │ │ │ - opacity + ")\n"; │ │ │ │ + if (this.pinchZoom) { │ │ │ │ + this.pinchZoom.destroy(); │ │ │ │ } │ │ │ │ - node.style.filter = filter; │ │ │ │ - │ │ │ │ - // do the rotation again on a box, so we know the insertion point │ │ │ │ - var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset); │ │ │ │ - var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry(); │ │ │ │ - imgBox.rotate(style.rotation, centerPoint); │ │ │ │ - var imgBounds = imgBox.getBounds(); │ │ │ │ + this.pinchZoom = null; │ │ │ │ │ │ │ │ - node.style.left = Math.round( │ │ │ │ - parseInt(node.style.left) + imgBounds.left) + "px"; │ │ │ │ - node.style.top = Math.round( │ │ │ │ - parseInt(node.style.top) - imgBounds.bottom) + "px"; │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: postDraw │ │ │ │ - * Does some node postprocessing to work around browser issues: │ │ │ │ - * - Some versions of Internet Explorer seem to be unable to set fillcolor │ │ │ │ - * and strokecolor to "none" correctly before the fill node is appended │ │ │ │ - * to a visible vml node. This method takes care of that and sets │ │ │ │ - * fillcolor and strokecolor again if needed. │ │ │ │ - * - In some cases, a node won't become visible after being drawn. Setting │ │ │ │ - * style.visibility to "visible" works around that. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ + * Method: activate │ │ │ │ */ │ │ │ │ - postDraw: function(node) { │ │ │ │ - node.style.visibility = "visible"; │ │ │ │ - var fillColor = node._style.fillColor; │ │ │ │ - var strokeColor = node._style.strokeColor; │ │ │ │ - if (fillColor == "none" && │ │ │ │ - node.fillcolor != fillColor) { │ │ │ │ - node.fillcolor = fillColor; │ │ │ │ - } │ │ │ │ - if (strokeColor == "none" && │ │ │ │ - node.strokecolor != strokeColor) { │ │ │ │ - node.strokecolor = strokeColor; │ │ │ │ + activate: function() { │ │ │ │ + this.dragPan.activate(); │ │ │ │ + if (this.zoomWheelEnabled) { │ │ │ │ + this.handlers.wheel.activate(); │ │ │ │ } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setNodeDimension │ │ │ │ - * Get the geometry's bounds, convert it to our vml coordinate system, │ │ │ │ - * then set the node's position, size, and local coordinate system. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - */ │ │ │ │ - setNodeDimension: function(node, geometry) { │ │ │ │ - │ │ │ │ - var bbox = geometry.getBounds(); │ │ │ │ - if (bbox) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - │ │ │ │ - var scaledBox = │ │ │ │ - new OpenLayers.Bounds(((bbox.left - this.featureDx) / resolution - this.offset.x) | 0, │ │ │ │ - (bbox.bottom / resolution - this.offset.y) | 0, │ │ │ │ - ((bbox.right - this.featureDx) / resolution - this.offset.x) | 0, │ │ │ │ - (bbox.top / resolution - this.offset.y) | 0); │ │ │ │ - │ │ │ │ - // Set the internal coordinate system to draw the path │ │ │ │ - node.style.left = scaledBox.left + "px"; │ │ │ │ - node.style.top = scaledBox.top + "px"; │ │ │ │ - node.style.width = scaledBox.getWidth() + "px"; │ │ │ │ - node.style.height = scaledBox.getHeight() + "px"; │ │ │ │ - │ │ │ │ - node.coordorigin = scaledBox.left + " " + scaledBox.top; │ │ │ │ - node.coordsize = scaledBox.getWidth() + " " + scaledBox.getHeight(); │ │ │ │ + this.handlers.click.activate(); │ │ │ │ + if (this.zoomBoxEnabled) { │ │ │ │ + this.zoomBox.activate(); │ │ │ │ } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: dashStyle │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * style - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A VML compliant 'stroke-dasharray' value │ │ │ │ - */ │ │ │ │ - dashStyle: function(style) { │ │ │ │ - var dash = style.strokeDashstyle; │ │ │ │ - switch (dash) { │ │ │ │ - case 'solid': │ │ │ │ - case 'dot': │ │ │ │ - case 'dash': │ │ │ │ - case 'dashdot': │ │ │ │ - case 'longdash': │ │ │ │ - case 'longdashdot': │ │ │ │ - return dash; │ │ │ │ - default: │ │ │ │ - // very basic guessing of dash style patterns │ │ │ │ - var parts = dash.split(/[ ,]/); │ │ │ │ - if (parts.length == 2) { │ │ │ │ - if (1 * parts[0] >= 2 * parts[1]) { │ │ │ │ - return "longdash"; │ │ │ │ - } │ │ │ │ - return (parts[0] == 1 || parts[1] == 1) ? "dot" : "dash"; │ │ │ │ - } else if (parts.length == 4) { │ │ │ │ - return (1 * parts[0] >= 2 * parts[1]) ? "longdashdot" : │ │ │ │ - "dashdot"; │ │ │ │ - } │ │ │ │ - return "solid"; │ │ │ │ + if (this.pinchZoom) { │ │ │ │ + this.pinchZoom.activate(); │ │ │ │ } │ │ │ │ + return OpenLayers.Control.prototype.activate.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createNode │ │ │ │ - * Create a new node │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * type - {String} Kind of node to draw │ │ │ │ - * id - {String} Id for node │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A new node of the given type and id │ │ │ │ + * Method: deactivate │ │ │ │ */ │ │ │ │ - createNode: function(type, id) { │ │ │ │ - var node = document.createElement(type); │ │ │ │ - if (id) { │ │ │ │ - node.id = id; │ │ │ │ + deactivate: function() { │ │ │ │ + if (this.pinchZoom) { │ │ │ │ + this.pinchZoom.deactivate(); │ │ │ │ } │ │ │ │ - │ │ │ │ - // IE hack to make elements unselectable, to prevent 'blue flash' │ │ │ │ - // while dragging vectors; #1410 │ │ │ │ - node.unselectable = 'on'; │ │ │ │ - node.onselectstart = OpenLayers.Function.False; │ │ │ │ - │ │ │ │ - return node; │ │ │ │ + this.zoomBox.deactivate(); │ │ │ │ + this.dragPan.deactivate(); │ │ │ │ + this.handlers.click.deactivate(); │ │ │ │ + this.handlers.wheel.deactivate(); │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: nodeTypeCompare │ │ │ │ - * Determine whether a node is of a given type │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} An VML element │ │ │ │ - * type - {String} Kind of node │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the specified node is of the specified type │ │ │ │ + * Method: draw │ │ │ │ */ │ │ │ │ - nodeTypeCompare: function(node, type) { │ │ │ │ - │ │ │ │ - //split type │ │ │ │ - var subType = type; │ │ │ │ - var splitIndex = subType.indexOf(":"); │ │ │ │ - if (splitIndex != -1) { │ │ │ │ - subType = subType.substr(splitIndex + 1); │ │ │ │ + draw: function() { │ │ │ │ + // disable right mouse context menu for support of right click events │ │ │ │ + if (this.handleRightClicks) { │ │ │ │ + this.map.viewPortDiv.oncontextmenu = OpenLayers.Function.False; │ │ │ │ } │ │ │ │ │ │ │ │ - //split nodeName │ │ │ │ - var nodeName = node.nodeName; │ │ │ │ - splitIndex = nodeName.indexOf(":"); │ │ │ │ - if (splitIndex != -1) { │ │ │ │ - nodeName = nodeName.substr(splitIndex + 1); │ │ │ │ + var clickCallbacks = { │ │ │ │ + 'click': this.defaultClick, │ │ │ │ + 'dblclick': this.defaultDblClick, │ │ │ │ + 'dblrightclick': this.defaultDblRightClick │ │ │ │ + }; │ │ │ │ + var clickOptions = { │ │ │ │ + 'double': true, │ │ │ │ + 'stopDouble': true │ │ │ │ + }; │ │ │ │ + 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.zoomBox = new OpenLayers.Control.ZoomBox({ │ │ │ │ + map: this.map, │ │ │ │ + keyMask: this.zoomBoxKeyMask │ │ │ │ + }); │ │ │ │ + this.dragPan.draw(); │ │ │ │ + this.zoomBox.draw(); │ │ │ │ + var wheelOptions = this.map.fractionalZoom ? {} : { │ │ │ │ + cumulative: false, │ │ │ │ + interval: 50, │ │ │ │ + maxDelta: 6 │ │ │ │ + }; │ │ │ │ + this.handlers.wheel = new OpenLayers.Handler.MouseWheel( │ │ │ │ + this, { │ │ │ │ + up: this.wheelUp, │ │ │ │ + down: this.wheelDown │ │ │ │ + }, │ │ │ │ + OpenLayers.Util.extend(wheelOptions, this.mouseWheelOptions) │ │ │ │ + ); │ │ │ │ + if (OpenLayers.Control.PinchZoom) { │ │ │ │ + this.pinchZoom = new OpenLayers.Control.PinchZoom( │ │ │ │ + OpenLayers.Util.extend({ │ │ │ │ + map: this.map │ │ │ │ + }, this.pinchZoomOptions)); │ │ │ │ } │ │ │ │ - │ │ │ │ - return (subType == nodeName); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createRenderRoot │ │ │ │ - * Create the renderer root │ │ │ │ + * Method: defaultClick │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} The specific render engine's root element │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - createRenderRoot: function() { │ │ │ │ - return this.nodeFactory(this.container.id + "_vmlRoot", "div"); │ │ │ │ + defaultClick: function(evt) { │ │ │ │ + if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ + this.map.zoomOut(); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createRoot │ │ │ │ - * Create the main root element │ │ │ │ + * Method: defaultDblClick │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * suffix - {String} suffix to append to the id │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - createRoot: function(suffix) { │ │ │ │ - return this.nodeFactory(this.container.id + suffix, "olv:group"); │ │ │ │ + defaultDblClick: function(evt) { │ │ │ │ + this.map.zoomTo(this.map.zoom + 1, evt.xy); │ │ │ │ }, │ │ │ │ │ │ │ │ - /************************************** │ │ │ │ - * * │ │ │ │ - * GEOMETRY DRAWING FUNCTIONS * │ │ │ │ - * * │ │ │ │ - **************************************/ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: drawPoint │ │ │ │ - * Render a point │ │ │ │ + * Method: defaultDblRightClick │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} or false if the point could not be drawn │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - drawPoint: function(node, geometry) { │ │ │ │ - return this.drawCircle(node, geometry, 1); │ │ │ │ + defaultDblRightClick: function(evt) { │ │ │ │ + this.map.zoomTo(this.map.zoom - 1, evt.xy); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawCircle │ │ │ │ - * Render a circle. │ │ │ │ - * Size and Center a circle given geometry (x,y center) and radius │ │ │ │ - * │ │ │ │ + * Method: wheelChange │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * radius - {float} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} or false if the circle could not ne drawn │ │ │ │ + * evt - {Event} │ │ │ │ + * deltaZ - {Integer} │ │ │ │ */ │ │ │ │ - drawCircle: function(node, geometry, radius) { │ │ │ │ - if (!isNaN(geometry.x) && !isNaN(geometry.y)) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - │ │ │ │ - node.style.left = ((((geometry.x - this.featureDx) / resolution - this.offset.x) | 0) - radius) + "px"; │ │ │ │ - node.style.top = (((geometry.y / resolution - this.offset.y) | 0) - radius) + "px"; │ │ │ │ - │ │ │ │ - var diameter = radius * 2; │ │ │ │ - │ │ │ │ - node.style.width = diameter + "px"; │ │ │ │ - node.style.height = diameter + "px"; │ │ │ │ - return node; │ │ │ │ + wheelChange: function(evt, deltaZ) { │ │ │ │ + if (!this.map.fractionalZoom) { │ │ │ │ + deltaZ = Math.round(deltaZ); │ │ │ │ } │ │ │ │ - return false; │ │ │ │ + var currentZoom = this.map.getZoom(), │ │ │ │ + newZoom = currentZoom + deltaZ; │ │ │ │ + newZoom = Math.max(newZoom, 0); │ │ │ │ + newZoom = Math.min(newZoom, this.map.getNumZoomLevels()); │ │ │ │ + if (newZoom === currentZoom) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + this.map.zoomTo(newZoom, evt.xy); │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: drawLineString │ │ │ │ - * Render a linestring. │ │ │ │ + /** │ │ │ │ + * Method: wheelUp │ │ │ │ + * User spun scroll wheel up │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * evt - {Event} │ │ │ │ + * delta - {Integer} │ │ │ │ */ │ │ │ │ - drawLineString: function(node, geometry) { │ │ │ │ - return this.drawLine(node, geometry, false); │ │ │ │ + wheelUp: function(evt, delta) { │ │ │ │ + this.wheelChange(evt, delta || 1); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: drawLinearRing │ │ │ │ - * Render a linearring │ │ │ │ + /** │ │ │ │ + * Method: wheelDown │ │ │ │ + * User spun scroll wheel down │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * evt - {Event} │ │ │ │ + * delta - {Integer} │ │ │ │ */ │ │ │ │ - drawLinearRing: function(node, geometry) { │ │ │ │ - return this.drawLine(node, geometry, true); │ │ │ │ + wheelDown: function(evt, delta) { │ │ │ │ + this.wheelChange(evt, delta || -1); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: DrawLine │ │ │ │ - * Render a line. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * closeLine - {Boolean} Close the line? (make it a ring?) │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * Method: disableZoomBox │ │ │ │ */ │ │ │ │ - drawLine: function(node, geometry, closeLine) { │ │ │ │ - │ │ │ │ - this.setNodeDimension(node, geometry); │ │ │ │ - │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var numComponents = geometry.components.length; │ │ │ │ - var parts = new Array(numComponents); │ │ │ │ - │ │ │ │ - var comp, x, y; │ │ │ │ - for (var i = 0; i < numComponents; i++) { │ │ │ │ - comp = geometry.components[i]; │ │ │ │ - x = ((comp.x - this.featureDx) / resolution - this.offset.x) | 0; │ │ │ │ - y = (comp.y / resolution - this.offset.y) | 0; │ │ │ │ - parts[i] = " " + x + "," + y + " l "; │ │ │ │ - } │ │ │ │ - var end = (closeLine) ? " x e" : " e"; │ │ │ │ - node.path = "m" + parts.join("") + end; │ │ │ │ - return node; │ │ │ │ + disableZoomBox: function() { │ │ │ │ + this.zoomBoxEnabled = false; │ │ │ │ + this.zoomBox.deactivate(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawPolygon │ │ │ │ - * Render a polygon │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * Method: enableZoomBox │ │ │ │ */ │ │ │ │ - drawPolygon: function(node, geometry) { │ │ │ │ - this.setNodeDimension(node, geometry); │ │ │ │ - │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - │ │ │ │ - var path = []; │ │ │ │ - var j, jj, points, area, first, second, i, ii, comp, pathComp, x, y; │ │ │ │ - for (j = 0, jj = geometry.components.length; j < jj; j++) { │ │ │ │ - path.push("m"); │ │ │ │ - points = geometry.components[j].components; │ │ │ │ - // we only close paths of interior rings with area │ │ │ │ - area = (j === 0); │ │ │ │ - first = null; │ │ │ │ - second = null; │ │ │ │ - for (i = 0, ii = points.length; i < ii; i++) { │ │ │ │ - comp = points[i]; │ │ │ │ - x = ((comp.x - this.featureDx) / resolution - this.offset.x) | 0; │ │ │ │ - y = (comp.y / resolution - this.offset.y) | 0; │ │ │ │ - pathComp = " " + x + "," + y; │ │ │ │ - path.push(pathComp); │ │ │ │ - if (i == 0) { │ │ │ │ - path.push(" l"); │ │ │ │ - } │ │ │ │ - if (!area) { │ │ │ │ - // IE improperly renders sub-paths that have no area. │ │ │ │ - // Instead of checking the area of every ring, we confirm │ │ │ │ - // the ring has at least three distinct points. This does │ │ │ │ - // not catch all non-zero area cases, but it greatly improves │ │ │ │ - // interior ring digitizing and is a minor performance hit │ │ │ │ - // when rendering rings with many points. │ │ │ │ - if (!first) { │ │ │ │ - first = pathComp; │ │ │ │ - } else if (first != pathComp) { │ │ │ │ - if (!second) { │ │ │ │ - second = pathComp; │ │ │ │ - } else if (second != pathComp) { │ │ │ │ - // stop looking │ │ │ │ - area = true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - path.push(area ? " x " : " "); │ │ │ │ + enableZoomBox: function() { │ │ │ │ + this.zoomBoxEnabled = true; │ │ │ │ + if (this.active) { │ │ │ │ + this.zoomBox.activate(); │ │ │ │ } │ │ │ │ - path.push("e"); │ │ │ │ - node.path = path.join(""); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: drawRectangle │ │ │ │ - * Render a rectangle │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - drawRectangle: function(node, geometry) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - │ │ │ │ - node.style.left = (((geometry.x - this.featureDx) / resolution - this.offset.x) | 0) + "px"; │ │ │ │ - node.style.top = ((geometry.y / resolution - this.offset.y) | 0) + "px"; │ │ │ │ - node.style.width = ((geometry.width / resolution) | 0) + "px"; │ │ │ │ - node.style.height = ((geometry.height / resolution) | 0) + "px"; │ │ │ │ - │ │ │ │ - return node; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawText │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * featureId - {String} │ │ │ │ - * style - │ │ │ │ - * location - {<OpenLayers.Geometry.Point>} │ │ │ │ + * Method: disableZoomWheel │ │ │ │ */ │ │ │ │ - drawText: function(featureId, style, location) { │ │ │ │ - var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect"); │ │ │ │ - var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox"); │ │ │ │ - │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - label.style.left = (((location.x - this.featureDx) / resolution - this.offset.x) | 0) + "px"; │ │ │ │ - label.style.top = ((location.y / resolution - this.offset.y) | 0) + "px"; │ │ │ │ - label.style.flip = "y"; │ │ │ │ - │ │ │ │ - textbox.innerText = style.label; │ │ │ │ - │ │ │ │ - if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ - textbox.style.cursor = style.cursor; │ │ │ │ - } │ │ │ │ - if (style.fontColor) { │ │ │ │ - textbox.style.color = style.fontColor; │ │ │ │ - } │ │ │ │ - if (style.fontOpacity) { │ │ │ │ - textbox.style.filter = 'alpha(opacity=' + (style.fontOpacity * 100) + ')'; │ │ │ │ - } │ │ │ │ - if (style.fontFamily) { │ │ │ │ - textbox.style.fontFamily = style.fontFamily; │ │ │ │ - } │ │ │ │ - if (style.fontSize) { │ │ │ │ - textbox.style.fontSize = style.fontSize; │ │ │ │ - } │ │ │ │ - if (style.fontWeight) { │ │ │ │ - textbox.style.fontWeight = style.fontWeight; │ │ │ │ - } │ │ │ │ - if (style.fontStyle) { │ │ │ │ - textbox.style.fontStyle = style.fontStyle; │ │ │ │ - } │ │ │ │ - if (style.labelSelect === true) { │ │ │ │ - label._featureId = featureId; │ │ │ │ - textbox._featureId = featureId; │ │ │ │ - textbox._geometry = location; │ │ │ │ - textbox._geometryClass = location.CLASS_NAME; │ │ │ │ - } │ │ │ │ - textbox.style.whiteSpace = "nowrap"; │ │ │ │ - // fun with IE: IE7 in standards compliant mode does not display any │ │ │ │ - // text with a left inset of 0. So we set this to 1px and subtract one │ │ │ │ - // pixel later when we set label.style.left │ │ │ │ - textbox.inset = "1px,0px,0px,0px"; │ │ │ │ - │ │ │ │ - if (!label.parentNode) { │ │ │ │ - label.appendChild(textbox); │ │ │ │ - this.textRoot.appendChild(label); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var align = style.labelAlign || "cm"; │ │ │ │ - if (align.length == 1) { │ │ │ │ - align += "m"; │ │ │ │ - } │ │ │ │ - var xshift = textbox.clientWidth * │ │ │ │ - (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0, 1)]); │ │ │ │ - var yshift = textbox.clientHeight * │ │ │ │ - (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1, 1)]); │ │ │ │ - label.style.left = parseInt(label.style.left) - xshift - 1 + "px"; │ │ │ │ - label.style.top = parseInt(label.style.top) + yshift + "px"; │ │ │ │ - │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: moveRoot │ │ │ │ - * moves this renderer's root to a different renderer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * renderer - {<OpenLayers.Renderer>} target renderer for the moved root │ │ │ │ - * root - {DOMElement} optional root node. To be used when this renderer │ │ │ │ - * holds roots from multiple layers to tell this method which one to │ │ │ │ - * detach │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} true if successful, false otherwise │ │ │ │ - */ │ │ │ │ - moveRoot: function(renderer) { │ │ │ │ - var layer = this.map.getLayer(renderer.container.id); │ │ │ │ - if (layer instanceof OpenLayers.Layer.Vector.RootContainer) { │ │ │ │ - layer = this.map.getLayer(this.container.id); │ │ │ │ - } │ │ │ │ - layer && layer.renderer.clear(); │ │ │ │ - OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments); │ │ │ │ - layer && layer.redraw(); │ │ │ │ + disableZoomWheel: function() { │ │ │ │ + this.zoomWheelEnabled = false; │ │ │ │ + this.handlers.wheel.deactivate(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: importSymbol │ │ │ │ - * add a new symbol definition from the rendererer's symbol hash │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * graphicName - {String} name of the symbol to import │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} - hash of {DOMElement} "symbol" and {Number} "size" │ │ │ │ + * Method: enableZoomWheel │ │ │ │ */ │ │ │ │ - importSymbol: function(graphicName) { │ │ │ │ - var id = this.container.id + "-" + graphicName; │ │ │ │ - │ │ │ │ - // check if symbol already exists in the cache │ │ │ │ - var cache = this.symbolCache[id]; │ │ │ │ - if (cache) { │ │ │ │ - return cache; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var symbol = OpenLayers.Renderer.symbol[graphicName]; │ │ │ │ - if (!symbol) { │ │ │ │ - throw new Error(graphicName + ' is not a valid symbol name'); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var symbolExtent = new OpenLayers.Bounds( │ │ │ │ - Number.MAX_VALUE, Number.MAX_VALUE, 0, 0); │ │ │ │ - │ │ │ │ - var pathitems = ["m"]; │ │ │ │ - for (var i = 0; i < symbol.length; i = i + 2) { │ │ │ │ - var x = symbol[i]; │ │ │ │ - var 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); │ │ │ │ - │ │ │ │ - pathitems.push(x); │ │ │ │ - pathitems.push(y); │ │ │ │ - if (i == 0) { │ │ │ │ - pathitems.push("l"); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - pathitems.push("x e"); │ │ │ │ - var path = pathitems.join(" "); │ │ │ │ │ │ │ │ - var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2; │ │ │ │ - if (diff > 0) { │ │ │ │ - symbolExtent.bottom = symbolExtent.bottom - diff; │ │ │ │ - symbolExtent.top = symbolExtent.top + diff; │ │ │ │ - } else { │ │ │ │ - symbolExtent.left = symbolExtent.left + diff; │ │ │ │ - symbolExtent.right = symbolExtent.right - diff; │ │ │ │ + enableZoomWheel: function() { │ │ │ │ + this.zoomWheelEnabled = true; │ │ │ │ + if (this.active) { │ │ │ │ + this.handlers.wheel.activate(); │ │ │ │ } │ │ │ │ - │ │ │ │ - cache = { │ │ │ │ - path: path, │ │ │ │ - size: symbolExtent.getWidth(), // equals getHeight() now │ │ │ │ - left: symbolExtent.left, │ │ │ │ - bottom: symbolExtent.bottom │ │ │ │ - }; │ │ │ │ - this.symbolCache[id] = cache; │ │ │ │ - │ │ │ │ - return cache; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.VML" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Navigation" │ │ │ │ }); │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Renderer.VML.LABEL_SHIFT │ │ │ │ - * {Object} │ │ │ │ - */ │ │ │ │ -OpenLayers.Renderer.VML.LABEL_SHIFT = { │ │ │ │ - "l": 0, │ │ │ │ - "c": .5, │ │ │ │ - "r": 1, │ │ │ │ - "t": 0, │ │ │ │ - "m": .5, │ │ │ │ - "b": 1 │ │ │ │ -}; │ │ │ │ /* ====================================================================== │ │ │ │ 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 │ │ │ │ @@ -33488,2211 +35685,14 @@ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.GeoJSON" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - 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/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/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/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/Popup.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. */ │ │ ├── ./usr/share/javascript/openlayers/OpenLayers.light.min.js │ │ │ ├── js-beautify {} │ │ │ │ @@ -1605,547 +1605,14 @@ │ │ │ │ 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.Feature = OpenLayers.Class({ │ │ │ │ - layer: null, │ │ │ │ - id: null, │ │ │ │ - lonlat: null, │ │ │ │ - data: null, │ │ │ │ - marker: null, │ │ │ │ - popupClass: null, │ │ │ │ - popup: null, │ │ │ │ - initialize: function(layer, lonlat, data) { │ │ │ │ - this.layer = layer; │ │ │ │ - this.lonlat = lonlat; │ │ │ │ - this.data = data != null ? data : {}; │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.layer != null && this.layer.map != null) { │ │ │ │ - if (this.popup != null) { │ │ │ │ - this.layer.map.removePopup(this.popup) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - createMarker: function() { │ │ │ │ - if (this.lonlat != null) { │ │ │ │ - this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon) │ │ │ │ - } │ │ │ │ - return this.marker │ │ │ │ - }, │ │ │ │ - destroyMarker: function() { │ │ │ │ - this.marker.destroy() │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - destroyPopup: function() { │ │ │ │ - if (this.popup) { │ │ │ │ - this.popup.feature = null; │ │ │ │ - this.popup.destroy(); │ │ │ │ - this.popup = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Feature" │ │ │ │ -}); │ │ │ │ -OpenLayers.State = { │ │ │ │ - UNKNOWN: "Unknown", │ │ │ │ - INSERT: "Insert", │ │ │ │ - UPDATE: "Update", │ │ │ │ - DELETE: "Delete" │ │ │ │ -}; │ │ │ │ -OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, { │ │ │ │ - fid: null, │ │ │ │ - geometry: null, │ │ │ │ - attributes: null, │ │ │ │ - bounds: null, │ │ │ │ - state: null, │ │ │ │ - style: null, │ │ │ │ - url: null, │ │ │ │ - renderIntent: "default", │ │ │ │ - modified: null, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - clone: function() { │ │ │ │ - return new OpenLayers.Feature.Vector(this.geometry ? this.geometry.clone() : null, this.attributes, this.style) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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()) │ │ │ │ - }, │ │ │ │ - createMarker: function() { │ │ │ │ - return null │ │ │ │ - }, │ │ │ │ - destroyMarker: function() {}, │ │ │ │ - createPopup: function() { │ │ │ │ - return null │ │ │ │ - }, │ │ │ │ - atPoint: function(lonlat, toleranceLon, toleranceLat) { │ │ │ │ - var atPoint = false; │ │ │ │ - if (this.geometry) { │ │ │ │ - atPoint = this.geometry.atPoint(lonlat, toleranceLon, toleranceLat) │ │ │ │ - } │ │ │ │ - return atPoint │ │ │ │ - }, │ │ │ │ - destroyPopup: function() {}, │ │ │ │ - move: function(location) { │ │ │ │ - if (!this.layer || !this.geometry.move) { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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: │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -OpenLayers.Feature.Vector.style = { │ │ │ │ - default: { │ │ │ │ - fillColor: "#ee9900", │ │ │ │ - fillOpacity: .4, │ │ │ │ - hoverFillColor: "white", │ │ │ │ - hoverFillOpacity: .8, │ │ │ │ - strokeColor: "#ee9900", │ │ │ │ - strokeOpacity: 1, │ │ │ │ - strokeWidth: 1, │ │ │ │ - strokeLinecap: "round", │ │ │ │ - strokeDashstyle: "solid", │ │ │ │ - hoverStrokeColor: "red", │ │ │ │ - hoverStrokeOpacity: 1, │ │ │ │ - hoverStrokeWidth: .2, │ │ │ │ - pointRadius: 6, │ │ │ │ - hoverPointRadius: 1, │ │ │ │ - hoverPointUnit: "%", │ │ │ │ - pointerEvents: "visiblePainted", │ │ │ │ - cursor: "inherit", │ │ │ │ - fontColor: "#000000", │ │ │ │ - labelAlign: "cm", │ │ │ │ - labelOutlineColor: "white", │ │ │ │ - labelOutlineWidth: 3 │ │ │ │ - }, │ │ │ │ - select: { │ │ │ │ - fillColor: "blue", │ │ │ │ - fillOpacity: .4, │ │ │ │ - hoverFillColor: "white", │ │ │ │ - hoverFillOpacity: .8, │ │ │ │ - strokeColor: "blue", │ │ │ │ - strokeOpacity: 1, │ │ │ │ - strokeWidth: 2, │ │ │ │ - strokeLinecap: "round", │ │ │ │ - strokeDashstyle: "solid", │ │ │ │ - hoverStrokeColor: "red", │ │ │ │ - hoverStrokeOpacity: 1, │ │ │ │ - hoverStrokeWidth: .2, │ │ │ │ - pointRadius: 6, │ │ │ │ - hoverPointRadius: 1, │ │ │ │ - hoverPointUnit: "%", │ │ │ │ - pointerEvents: "visiblePainted", │ │ │ │ - cursor: "pointer", │ │ │ │ - fontColor: "#000000", │ │ │ │ - labelAlign: "cm", │ │ │ │ - labelOutlineColor: "white", │ │ │ │ - labelOutlineWidth: 3 │ │ │ │ - }, │ │ │ │ - temporary: { │ │ │ │ - fillColor: "#66cccc", │ │ │ │ - fillOpacity: .2, │ │ │ │ - hoverFillColor: "white", │ │ │ │ - hoverFillOpacity: .8, │ │ │ │ - strokeColor: "#66cccc", │ │ │ │ - strokeOpacity: 1, │ │ │ │ - strokeLinecap: "round", │ │ │ │ - strokeWidth: 2, │ │ │ │ - strokeDashstyle: "solid", │ │ │ │ - hoverStrokeColor: "red", │ │ │ │ - hoverStrokeOpacity: 1, │ │ │ │ - hoverStrokeWidth: .2, │ │ │ │ - pointRadius: 6, │ │ │ │ - hoverPointRadius: 1, │ │ │ │ - hoverPointUnit: "%", │ │ │ │ - pointerEvents: "visiblePainted", │ │ │ │ - cursor: "inherit", │ │ │ │ - fontColor: "#000000", │ │ │ │ - labelAlign: "cm", │ │ │ │ - labelOutlineColor: "white", │ │ │ │ - labelOutlineWidth: 3 │ │ │ │ - }, │ │ │ │ - delete: { │ │ │ │ - display: "none" │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -OpenLayers.Style = OpenLayers.Class({ │ │ │ │ - id: null, │ │ │ │ - name: null, │ │ │ │ - title: null, │ │ │ │ - description: null, │ │ │ │ - layerName: null, │ │ │ │ - isDefault: false, │ │ │ │ - rules: null, │ │ │ │ - context: null, │ │ │ │ - defaultStyle: null, │ │ │ │ - defaultsPerSymbolizer: false, │ │ │ │ - propertyStyles: null, │ │ │ │ - initialize: function(style, options) { │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - this.rules = []; │ │ │ │ - if (options && options.rules) { │ │ │ │ - this.addRules(options.rules) │ │ │ │ - } │ │ │ │ - this.setDefaultStyle(style || OpenLayers.Feature.Vector.style["default"]); │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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]; │ │ │ │ - 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 (appliedRules == false && elseRules.length > 0) { │ │ │ │ - appliedRules = true; │ │ │ │ - for (var i = 0, len = elseRules.length; i < len; i++) { │ │ │ │ - this.applySymbolizer(elseRules[i], style, feature) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (rules.length > 0 && appliedRules == false) { │ │ │ │ - style.display = "none" │ │ │ │ - } │ │ │ │ - if (style.label != null && typeof style.label !== "string") { │ │ │ │ - style.label = String(style.label) │ │ │ │ - } │ │ │ │ - return style │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return this.createLiterals(OpenLayers.Util.extend(style, symbolizer), feature) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - findPropertyStyles: function() { │ │ │ │ - var propertyStyles = {}; │ │ │ │ - var style = this.defaultStyle; │ │ │ │ - this.addPropertyStyles(propertyStyles, style); │ │ │ │ - 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") { │ │ │ │ - this.addPropertyStyles(propertyStyles, value) │ │ │ │ - } else { │ │ │ │ - this.addPropertyStyles(propertyStyles, symbolizer); │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return propertyStyles │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - addRules: function(rules) { │ │ │ │ - Array.prototype.push.apply(this.rules, rules); │ │ │ │ - this.propertyStyles = this.findPropertyStyles() │ │ │ │ - }, │ │ │ │ - setDefaultStyle: function(style) { │ │ │ │ - this.defaultStyle = style; │ │ │ │ - this.propertyStyles = this.findPropertyStyles() │ │ │ │ - }, │ │ │ │ - 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] │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clone: function() { │ │ │ │ - var options = OpenLayers.Util.extend({}, this); │ │ │ │ - if (this.rules) { │ │ │ │ - options.rules = []; │ │ │ │ - for (var i = 0, len = this.rules.length; i < len; ++i) { │ │ │ │ - options.rules.push(this.rules[i].clone()) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ - var defaultStyle = OpenLayers.Util.extend({}, this.defaultStyle); │ │ │ │ - return new OpenLayers.Style(defaultStyle, options) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Style" │ │ │ │ -}); │ │ │ │ -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 │ │ │ │ -}; │ │ │ │ -OpenLayers.Style.SYMBOLIZER_PREFIXES = ["Point", "Line", "Polygon", "Text", "Raster"]; │ │ │ │ -OpenLayers.Rule = OpenLayers.Class({ │ │ │ │ - id: null, │ │ │ │ - name: null, │ │ │ │ - title: null, │ │ │ │ - description: null, │ │ │ │ - context: null, │ │ │ │ - filter: null, │ │ │ │ - elseFilter: false, │ │ │ │ - symbolizer: null, │ │ │ │ - symbolizers: null, │ │ │ │ - minScaleDenominator: null, │ │ │ │ - maxScaleDenominator: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - this.symbolizer = {}; │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - if (this.symbolizers) { │ │ │ │ - delete this.symbolizer │ │ │ │ - } │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - for (var i in this.symbolizer) { │ │ │ │ - this.symbolizer[i] = null │ │ │ │ - } │ │ │ │ - this.symbolizer = null; │ │ │ │ - delete this.symbolizers │ │ │ │ - }, │ │ │ │ - evaluate: function(feature) { │ │ │ │ - var context = this.getContext(feature); │ │ │ │ - var applies = true; │ │ │ │ - if (this.minScaleDenominator || this.maxScaleDenominator) { │ │ │ │ - var scale = feature.layer.map.getScale() │ │ │ │ - } │ │ │ │ - if (this.minScaleDenominator) { │ │ │ │ - applies = scale >= OpenLayers.Style.createLiteral(this.minScaleDenominator, context) │ │ │ │ - } │ │ │ │ - if (applies && this.maxScaleDenominator) { │ │ │ │ - applies = scale < OpenLayers.Style.createLiteral(this.maxScaleDenominator, context) │ │ │ │ - } │ │ │ │ - if (applies && this.filter) { │ │ │ │ - if (this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") { │ │ │ │ - applies = this.filter.evaluate(feature) │ │ │ │ - } else { │ │ │ │ - applies = this.filter.evaluate(context) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return applies │ │ │ │ - }, │ │ │ │ - getContext: function(feature) { │ │ │ │ - var context = this.context; │ │ │ │ - if (!context) { │ │ │ │ - context = feature.attributes || feature.data │ │ │ │ - } │ │ │ │ - if (typeof this.context == "function") { │ │ │ │ - context = this.context(feature) │ │ │ │ - } │ │ │ │ - return context │ │ │ │ - }, │ │ │ │ - clone: function() { │ │ │ │ - var options = OpenLayers.Util.extend({}, this); │ │ │ │ - if (this.symbolizers) { │ │ │ │ - var len = this.symbolizers.length; │ │ │ │ - options.symbolizers = new Array(len); │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ - options.symbolizers[i] = this.symbolizers[i].clone() │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - options.symbolizer = {}; │ │ │ │ - var value, type; │ │ │ │ - for (var key in this.symbolizer) { │ │ │ │ - value = this.symbolizer[key]; │ │ │ │ - type = typeof value; │ │ │ │ - if (type === "object") { │ │ │ │ - options.symbolizer[key] = OpenLayers.Util.extend({}, value) │ │ │ │ - } else if (type === "string") { │ │ │ │ - options.symbolizer[key] = value │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - options.filter = this.filter && this.filter.clone(); │ │ │ │ - options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ - return new OpenLayers.Rule(options) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Rule" │ │ │ │ -}); │ │ │ │ OpenLayers.Util = OpenLayers.Util || {}; │ │ │ │ OpenLayers.Util.vendorPrefix = function() { │ │ │ │ "use strict"; │ │ │ │ var VENDOR_PREFIXES = ["", "O", "ms", "Moz", "Webkit"], │ │ │ │ divStyle = document.createElement("div").style, │ │ │ │ cssCache = {}, │ │ │ │ jsCache = {}; │ │ │ │ @@ -4130,14 +3597,631 @@ │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Map" │ │ │ │ }); │ │ │ │ OpenLayers.Map.TILE_WIDTH = 256; │ │ │ │ OpenLayers.Map.TILE_HEIGHT = 256; │ │ │ │ +OpenLayers.Kinetic = OpenLayers.Class({ │ │ │ │ + threshold: 0, │ │ │ │ + deceleration: .0035, │ │ │ │ + nbPoints: 100, │ │ │ │ + delay: 200, │ │ │ │ + points: undefined, │ │ │ │ + timerId: undefined, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Util.extend(this, options) │ │ │ │ + }, │ │ │ │ + begin: function() { │ │ │ │ + OpenLayers.Animation.stop(this.timerId); │ │ │ │ + this.timerId = undefined; │ │ │ │ + this.points = [] │ │ │ │ + }, │ │ │ │ + update: function(xy) { │ │ │ │ + this.points.unshift({ │ │ │ │ + xy: xy, │ │ │ │ + tick: (new Date).getTime() │ │ │ │ + }); │ │ │ │ + if (this.points.length > this.nbPoints) { │ │ │ │ + this.points.pop() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 + 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.Feature = OpenLayers.Class({ │ │ │ │ + layer: null, │ │ │ │ + id: null, │ │ │ │ + lonlat: null, │ │ │ │ + data: null, │ │ │ │ + marker: null, │ │ │ │ + popupClass: null, │ │ │ │ + popup: null, │ │ │ │ + initialize: function(layer, lonlat, data) { │ │ │ │ + this.layer = layer; │ │ │ │ + this.lonlat = lonlat; │ │ │ │ + this.data = data != null ? data : {}; │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.layer != null && this.layer.map != null) { │ │ │ │ + if (this.popup != null) { │ │ │ │ + this.layer.map.removePopup(this.popup) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + createMarker: function() { │ │ │ │ + if (this.lonlat != null) { │ │ │ │ + this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon) │ │ │ │ + } │ │ │ │ + return this.marker │ │ │ │ + }, │ │ │ │ + destroyMarker: function() { │ │ │ │ + this.marker.destroy() │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + destroyPopup: function() { │ │ │ │ + if (this.popup) { │ │ │ │ + this.popup.feature = null; │ │ │ │ + this.popup.destroy(); │ │ │ │ + this.popup = null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Feature" │ │ │ │ +}); │ │ │ │ +OpenLayers.State = { │ │ │ │ + UNKNOWN: "Unknown", │ │ │ │ + INSERT: "Insert", │ │ │ │ + UPDATE: "Update", │ │ │ │ + DELETE: "Delete" │ │ │ │ +}; │ │ │ │ +OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, { │ │ │ │ + fid: null, │ │ │ │ + geometry: null, │ │ │ │ + attributes: null, │ │ │ │ + bounds: null, │ │ │ │ + state: null, │ │ │ │ + style: null, │ │ │ │ + url: null, │ │ │ │ + renderIntent: "default", │ │ │ │ + modified: null, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + clone: function() { │ │ │ │ + return new OpenLayers.Feature.Vector(this.geometry ? this.geometry.clone() : null, this.attributes, this.style) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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()) │ │ │ │ + }, │ │ │ │ + createMarker: function() { │ │ │ │ + return null │ │ │ │ + }, │ │ │ │ + destroyMarker: function() {}, │ │ │ │ + createPopup: function() { │ │ │ │ + return null │ │ │ │ + }, │ │ │ │ + atPoint: function(lonlat, toleranceLon, toleranceLat) { │ │ │ │ + var atPoint = false; │ │ │ │ + if (this.geometry) { │ │ │ │ + atPoint = this.geometry.atPoint(lonlat, toleranceLon, toleranceLat) │ │ │ │ + } │ │ │ │ + return atPoint │ │ │ │ + }, │ │ │ │ + destroyPopup: function() {}, │ │ │ │ + move: function(location) { │ │ │ │ + if (!this.layer || !this.geometry.move) { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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: │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +OpenLayers.Feature.Vector.style = { │ │ │ │ + default: { │ │ │ │ + fillColor: "#ee9900", │ │ │ │ + fillOpacity: .4, │ │ │ │ + hoverFillColor: "white", │ │ │ │ + hoverFillOpacity: .8, │ │ │ │ + strokeColor: "#ee9900", │ │ │ │ + strokeOpacity: 1, │ │ │ │ + strokeWidth: 1, │ │ │ │ + strokeLinecap: "round", │ │ │ │ + strokeDashstyle: "solid", │ │ │ │ + hoverStrokeColor: "red", │ │ │ │ + hoverStrokeOpacity: 1, │ │ │ │ + hoverStrokeWidth: .2, │ │ │ │ + pointRadius: 6, │ │ │ │ + hoverPointRadius: 1, │ │ │ │ + hoverPointUnit: "%", │ │ │ │ + pointerEvents: "visiblePainted", │ │ │ │ + cursor: "inherit", │ │ │ │ + fontColor: "#000000", │ │ │ │ + labelAlign: "cm", │ │ │ │ + labelOutlineColor: "white", │ │ │ │ + labelOutlineWidth: 3 │ │ │ │ + }, │ │ │ │ + select: { │ │ │ │ + fillColor: "blue", │ │ │ │ + fillOpacity: .4, │ │ │ │ + hoverFillColor: "white", │ │ │ │ + hoverFillOpacity: .8, │ │ │ │ + strokeColor: "blue", │ │ │ │ + strokeOpacity: 1, │ │ │ │ + strokeWidth: 2, │ │ │ │ + strokeLinecap: "round", │ │ │ │ + strokeDashstyle: "solid", │ │ │ │ + hoverStrokeColor: "red", │ │ │ │ + hoverStrokeOpacity: 1, │ │ │ │ + hoverStrokeWidth: .2, │ │ │ │ + pointRadius: 6, │ │ │ │ + hoverPointRadius: 1, │ │ │ │ + hoverPointUnit: "%", │ │ │ │ + pointerEvents: "visiblePainted", │ │ │ │ + cursor: "pointer", │ │ │ │ + fontColor: "#000000", │ │ │ │ + labelAlign: "cm", │ │ │ │ + labelOutlineColor: "white", │ │ │ │ + labelOutlineWidth: 3 │ │ │ │ + }, │ │ │ │ + temporary: { │ │ │ │ + fillColor: "#66cccc", │ │ │ │ + fillOpacity: .2, │ │ │ │ + hoverFillColor: "white", │ │ │ │ + hoverFillOpacity: .8, │ │ │ │ + strokeColor: "#66cccc", │ │ │ │ + strokeOpacity: 1, │ │ │ │ + strokeLinecap: "round", │ │ │ │ + strokeWidth: 2, │ │ │ │ + strokeDashstyle: "solid", │ │ │ │ + hoverStrokeColor: "red", │ │ │ │ + hoverStrokeOpacity: 1, │ │ │ │ + hoverStrokeWidth: .2, │ │ │ │ + pointRadius: 6, │ │ │ │ + hoverPointRadius: 1, │ │ │ │ + hoverPointUnit: "%", │ │ │ │ + pointerEvents: "visiblePainted", │ │ │ │ + cursor: "inherit", │ │ │ │ + fontColor: "#000000", │ │ │ │ + labelAlign: "cm", │ │ │ │ + labelOutlineColor: "white", │ │ │ │ + labelOutlineWidth: 3 │ │ │ │ + }, │ │ │ │ + delete: { │ │ │ │ + display: "none" │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.Style = OpenLayers.Class({ │ │ │ │ + id: null, │ │ │ │ + name: null, │ │ │ │ + title: null, │ │ │ │ + description: null, │ │ │ │ + layerName: null, │ │ │ │ + isDefault: false, │ │ │ │ + rules: null, │ │ │ │ + context: null, │ │ │ │ + defaultStyle: null, │ │ │ │ + defaultsPerSymbolizer: false, │ │ │ │ + propertyStyles: null, │ │ │ │ + initialize: function(style, options) { │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + this.rules = []; │ │ │ │ + if (options && options.rules) { │ │ │ │ + this.addRules(options.rules) │ │ │ │ + } │ │ │ │ + this.setDefaultStyle(style || OpenLayers.Feature.Vector.style["default"]); │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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]; │ │ │ │ + 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 (appliedRules == false && elseRules.length > 0) { │ │ │ │ + appliedRules = true; │ │ │ │ + for (var i = 0, len = elseRules.length; i < len; i++) { │ │ │ │ + this.applySymbolizer(elseRules[i], style, feature) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (rules.length > 0 && appliedRules == false) { │ │ │ │ + style.display = "none" │ │ │ │ + } │ │ │ │ + if (style.label != null && typeof style.label !== "string") { │ │ │ │ + style.label = String(style.label) │ │ │ │ + } │ │ │ │ + return style │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return this.createLiterals(OpenLayers.Util.extend(style, symbolizer), feature) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + findPropertyStyles: function() { │ │ │ │ + var propertyStyles = {}; │ │ │ │ + var style = this.defaultStyle; │ │ │ │ + this.addPropertyStyles(propertyStyles, style); │ │ │ │ + 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") { │ │ │ │ + this.addPropertyStyles(propertyStyles, value) │ │ │ │ + } else { │ │ │ │ + this.addPropertyStyles(propertyStyles, symbolizer); │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return propertyStyles │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + addRules: function(rules) { │ │ │ │ + Array.prototype.push.apply(this.rules, rules); │ │ │ │ + this.propertyStyles = this.findPropertyStyles() │ │ │ │ + }, │ │ │ │ + setDefaultStyle: function(style) { │ │ │ │ + this.defaultStyle = style; │ │ │ │ + this.propertyStyles = this.findPropertyStyles() │ │ │ │ + }, │ │ │ │ + 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] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + clone: function() { │ │ │ │ + var options = OpenLayers.Util.extend({}, this); │ │ │ │ + if (this.rules) { │ │ │ │ + options.rules = []; │ │ │ │ + for (var i = 0, len = this.rules.length; i < len; ++i) { │ │ │ │ + options.rules.push(this.rules[i].clone()) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ + var defaultStyle = OpenLayers.Util.extend({}, this.defaultStyle); │ │ │ │ + return new OpenLayers.Style(defaultStyle, options) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Style" │ │ │ │ +}); │ │ │ │ +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 │ │ │ │ +}; │ │ │ │ +OpenLayers.Style.SYMBOLIZER_PREFIXES = ["Point", "Line", "Polygon", "Text", "Raster"]; │ │ │ │ +OpenLayers.Rule = OpenLayers.Class({ │ │ │ │ + id: null, │ │ │ │ + name: null, │ │ │ │ + title: null, │ │ │ │ + description: null, │ │ │ │ + context: null, │ │ │ │ + filter: null, │ │ │ │ + elseFilter: false, │ │ │ │ + symbolizer: null, │ │ │ │ + symbolizers: null, │ │ │ │ + minScaleDenominator: null, │ │ │ │ + maxScaleDenominator: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + this.symbolizer = {}; │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + if (this.symbolizers) { │ │ │ │ + delete this.symbolizer │ │ │ │ + } │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + for (var i in this.symbolizer) { │ │ │ │ + this.symbolizer[i] = null │ │ │ │ + } │ │ │ │ + this.symbolizer = null; │ │ │ │ + delete this.symbolizers │ │ │ │ + }, │ │ │ │ + evaluate: function(feature) { │ │ │ │ + var context = this.getContext(feature); │ │ │ │ + var applies = true; │ │ │ │ + if (this.minScaleDenominator || this.maxScaleDenominator) { │ │ │ │ + var scale = feature.layer.map.getScale() │ │ │ │ + } │ │ │ │ + if (this.minScaleDenominator) { │ │ │ │ + applies = scale >= OpenLayers.Style.createLiteral(this.minScaleDenominator, context) │ │ │ │ + } │ │ │ │ + if (applies && this.maxScaleDenominator) { │ │ │ │ + applies = scale < OpenLayers.Style.createLiteral(this.maxScaleDenominator, context) │ │ │ │ + } │ │ │ │ + if (applies && this.filter) { │ │ │ │ + if (this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") { │ │ │ │ + applies = this.filter.evaluate(feature) │ │ │ │ + } else { │ │ │ │ + applies = this.filter.evaluate(context) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return applies │ │ │ │ + }, │ │ │ │ + getContext: function(feature) { │ │ │ │ + var context = this.context; │ │ │ │ + if (!context) { │ │ │ │ + context = feature.attributes || feature.data │ │ │ │ + } │ │ │ │ + if (typeof this.context == "function") { │ │ │ │ + context = this.context(feature) │ │ │ │ + } │ │ │ │ + return context │ │ │ │ + }, │ │ │ │ + clone: function() { │ │ │ │ + var options = OpenLayers.Util.extend({}, this); │ │ │ │ + if (this.symbolizers) { │ │ │ │ + var len = this.symbolizers.length; │ │ │ │ + options.symbolizers = new Array(len); │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ + options.symbolizers[i] = this.symbolizers[i].clone() │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + options.symbolizer = {}; │ │ │ │ + var value, type; │ │ │ │ + for (var key in this.symbolizer) { │ │ │ │ + value = this.symbolizer[key]; │ │ │ │ + type = typeof value; │ │ │ │ + if (type === "object") { │ │ │ │ + options.symbolizer[key] = OpenLayers.Util.extend({}, value) │ │ │ │ + } else if (type === "string") { │ │ │ │ + options.symbolizer[key] = value │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + options.filter = this.filter && this.filter.clone(); │ │ │ │ + options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ + return new OpenLayers.Rule(options) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Rule" │ │ │ │ +}); │ │ │ │ OpenLayers.StyleMap = OpenLayers.Class({ │ │ │ │ styles: null, │ │ │ │ extendDefault: true, │ │ │ │ initialize: function(style, options) { │ │ │ │ this.styles = { │ │ │ │ default: new OpenLayers.Style(OpenLayers.Feature.Vector.style["default"]), │ │ │ │ select: new OpenLayers.Style(OpenLayers.Feature.Vector.style["select"]), │ │ │ │ @@ -4199,97 +4283,2021 @@ │ │ │ │ }) │ │ │ │ })) │ │ │ │ } │ │ │ │ this.styles[renderIntent].addRules(rules) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.StyleMap" │ │ │ │ }); │ │ │ │ -OpenLayers.Kinetic = OpenLayers.Class({ │ │ │ │ - threshold: 0, │ │ │ │ - deceleration: .0035, │ │ │ │ - nbPoints: 100, │ │ │ │ - delay: 200, │ │ │ │ - points: undefined, │ │ │ │ - timerId: undefined, │ │ │ │ +OpenLayers.Filter = OpenLayers.Class({ │ │ │ │ initialize: function(options) { │ │ │ │ OpenLayers.Util.extend(this, options) │ │ │ │ }, │ │ │ │ - begin: function() { │ │ │ │ - OpenLayers.Animation.stop(this.timerId); │ │ │ │ - this.timerId = undefined; │ │ │ │ - this.points = [] │ │ │ │ + destroy: function() {}, │ │ │ │ + evaluate: function(context) { │ │ │ │ + return true │ │ │ │ }, │ │ │ │ - update: function(xy) { │ │ │ │ - this.points.unshift({ │ │ │ │ - xy: xy, │ │ │ │ - tick: (new Date).getTime() │ │ │ │ + clone: function() { │ │ │ │ + return null │ │ │ │ + }, │ │ │ │ + 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.Comparison = OpenLayers.Class(OpenLayers.Filter, { │ │ │ │ + type: null, │ │ │ │ + property: null, │ │ │ │ + value: null, │ │ │ │ + matchCase: true, │ │ │ │ + lowerBoundary: null, │ │ │ │ + upperBoundary: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Filter.prototype.initialize.apply(this, [options]); │ │ │ │ + if (this.type === OpenLayers.Filter.Comparison.LIKE && options.matchCase === undefined) { │ │ │ │ + this.matchCase = null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + value2regex: function(wildCard, singleChar, escapeChar) { │ │ │ │ + if (wildCard == ".") { │ │ │ │ + throw new Error("'.' is an unsupported wildCard character for " + "OpenLayers.Filter.Comparison") │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + regex2value: function() { │ │ │ │ + var value = this.value; │ │ │ │ + value = value.replace(/!/g, "!!"); │ │ │ │ + value = value.replace(/(\\)?\\\./g, function($0, $1) { │ │ │ │ + return $1 ? $0 : "!." │ │ │ │ }); │ │ │ │ - if (this.points.length > this.nbPoints) { │ │ │ │ - this.points.pop() │ │ │ │ + value = value.replace(/(\\)?\\\*/g, function($0, $1) { │ │ │ │ + return $1 ? $0 : "!*" │ │ │ │ + }); │ │ │ │ + value = value.replace(/\\\\/g, "\\"); │ │ │ │ + value = value.replace(/\.\*/g, "*"); │ │ │ │ + return value │ │ │ │ + }, │ │ │ │ + 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.Filter.Logical = OpenLayers.Class(OpenLayers.Filter, { │ │ │ │ + filters: null, │ │ │ │ + type: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + this.filters = []; │ │ │ │ + OpenLayers.Filter.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.filters = null; │ │ │ │ + OpenLayers.Filter.prototype.destroy.apply(this) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ }, │ │ │ │ - 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) { │ │ │ │ + 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.Renderer = OpenLayers.Class({ │ │ │ │ + container: null, │ │ │ │ + root: null, │ │ │ │ + extent: null, │ │ │ │ + locked: false, │ │ │ │ + size: null, │ │ │ │ + resolution: null, │ │ │ │ + map: null, │ │ │ │ + featureDx: 0, │ │ │ │ + initialize: function(containerID, options) { │ │ │ │ + this.container = OpenLayers.Util.getElement(containerID); │ │ │ │ + OpenLayers.Util.extend(this, options) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.container = null; │ │ │ │ + this.extent = null; │ │ │ │ + this.size = null; │ │ │ │ + this.resolution = null; │ │ │ │ + this.map = null │ │ │ │ + }, │ │ │ │ + supported: function() { │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + setSize: function(size) { │ │ │ │ + this.size = size.clone(); │ │ │ │ + this.resolution = null │ │ │ │ + }, │ │ │ │ + getResolution: function() { │ │ │ │ + this.resolution = this.resolution || this.map.getResolution(); │ │ │ │ + return this.resolution │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawGeometry: function(geometry, style, featureId) {}, │ │ │ │ + drawText: function(featureId, style, location) {}, │ │ │ │ + removeText: function(featureId) {}, │ │ │ │ + clear: function() {}, │ │ │ │ + getFeatureIdFromEvent: function(evt) {}, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + eraseGeometry: function(geometry, featureId) {}, │ │ │ │ + moveRoot: function(renderer) {}, │ │ │ │ + getRenderLayerId: function() { │ │ │ │ + return this.container.id │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +OpenLayers.Renderer.defaultSymbolizer = { │ │ │ │ + fillColor: "#000000", │ │ │ │ + strokeColor: "#000000", │ │ │ │ + strokeWidth: 2, │ │ │ │ + fillOpacity: 1, │ │ │ │ + strokeOpacity: 1, │ │ │ │ + pointRadius: 0, │ │ │ │ + labelAlign: "cm" │ │ │ │ +}; │ │ │ │ +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.ElementsIndexer = OpenLayers.Class({ │ │ │ │ + maxZIndex: null, │ │ │ │ + order: null, │ │ │ │ + indices: null, │ │ │ │ + compare: null, │ │ │ │ + initialize: function(yOrdering) { │ │ │ │ + this.compare = yOrdering ? OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER : OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER; │ │ │ │ + this.clear() │ │ │ │ + }, │ │ │ │ + insert: function(newNode) { │ │ │ │ + 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); │ │ │ │ + return this.getNextElement(rightIndex) │ │ │ │ + }, │ │ │ │ + remove: function(node) { │ │ │ │ + var nodeId = node.id; │ │ │ │ + var arrayIndex = OpenLayers.Util.indexOf(this.order, nodeId); │ │ │ │ + if (arrayIndex >= 0) { │ │ │ │ + this.order.splice(arrayIndex, 1); │ │ │ │ + delete this.indices[nodeId]; │ │ │ │ + if (this.order.length > 0) { │ │ │ │ + var lastId = this.order[this.order.length - 1]; │ │ │ │ + this.maxZIndex = this.indices[lastId] │ │ │ │ + } else { │ │ │ │ + this.maxZIndex = 0 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + clear: function() { │ │ │ │ + this.order = []; │ │ │ │ + this.indices = {}; │ │ │ │ + this.maxZIndex = 0 │ │ │ │ + }, │ │ │ │ + exists: function(node) { │ │ │ │ + return this.indices[node.id] != null │ │ │ │ + }, │ │ │ │ + getZIndex: function(node) { │ │ │ │ + return node._style.graphicZIndex │ │ │ │ + }, │ │ │ │ + determineZIndex: function(node) { │ │ │ │ + var zIndex = node._style.graphicZIndex; │ │ │ │ + if (zIndex == null) { │ │ │ │ + zIndex = this.maxZIndex; │ │ │ │ + node._style.graphicZIndex = zIndex │ │ │ │ + } else if (zIndex > this.maxZIndex) { │ │ │ │ + this.maxZIndex = zIndex │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +OpenLayers.ElementsIndexer.IndexingMethods = { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + Z_ORDER_DRAWING_ORDER: function(indexer, newNode, nextNode) { │ │ │ │ + var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(indexer, newNode, nextNode); │ │ │ │ + if (nextNode && returnVal == 0) { │ │ │ │ + returnVal = 1 │ │ │ │ + } │ │ │ │ + return returnVal │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ + rendererRoot: null, │ │ │ │ + root: null, │ │ │ │ + vectorRoot: null, │ │ │ │ + textRoot: null, │ │ │ │ + xmlns: null, │ │ │ │ + xOffset: 0, │ │ │ │ + indexer: null, │ │ │ │ + BACKGROUND_ID_SUFFIX: "_background", │ │ │ │ + LABEL_ID_SUFFIX: "_label", │ │ │ │ + LABEL_OUTLINE_SUFFIX: "_outline", │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.clear(); │ │ │ │ + this.rendererRoot = null; │ │ │ │ + this.root = null; │ │ │ │ + this.xmlns = null; │ │ │ │ + OpenLayers.Renderer.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + getNodeType: function(geometry, style) {}, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + redrawNode: function(id, geometry, style, featureId) { │ │ │ │ + style = this.applyDefaultSymbolizer(style); │ │ │ │ + var node = this.nodeFactory(id, this.getNodeType(geometry, style)); │ │ │ │ + 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; │ │ │ │ + if (this.indexer) { │ │ │ │ + var insert = this.indexer.insert(node); │ │ │ │ + if (insert) { │ │ │ │ + this.vectorRoot.insertBefore(node, insert) │ │ │ │ + } else { │ │ │ │ + this.vectorRoot.appendChild(node) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (node.parentNode !== this.vectorRoot) { │ │ │ │ + this.vectorRoot.appendChild(node) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.postDraw(node); │ │ │ │ + return drawResult.complete │ │ │ │ + }, │ │ │ │ + redrawBackgroundNode: function(id, geometry, style, featureId) { │ │ │ │ + var backgroundStyle = OpenLayers.Util.extend({}, style); │ │ │ │ + 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; │ │ │ │ + backgroundStyle.backgroundGraphic = null; │ │ │ │ + backgroundStyle.backgroundXOffset = null; │ │ │ │ + backgroundStyle.backgroundYOffset = null; │ │ │ │ + backgroundStyle.backgroundGraphicZIndex = null; │ │ │ │ + return this.redrawNode(id + this.BACKGROUND_ID_SUFFIX, geometry, backgroundStyle, null) │ │ │ │ + }, │ │ │ │ + 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; │ │ │ │ + if (drawn != false) { │ │ │ │ + return { │ │ │ │ + node: this.setStyle(node, style, options, geometry), │ │ │ │ + complete: drawn │ │ │ │ } │ │ │ │ - last = point │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ } │ │ │ │ - if (!last) { │ │ │ │ - return │ │ │ │ + }, │ │ │ │ + postDraw: function(node) {}, │ │ │ │ + drawPoint: function(node, geometry) {}, │ │ │ │ + drawLineString: function(node, geometry) {}, │ │ │ │ + drawLinearRing: function(node, geometry) {}, │ │ │ │ + drawPolygon: function(node, geometry) {}, │ │ │ │ + drawRectangle: function(node, geometry) {}, │ │ │ │ + drawCircle: function(node, geometry) {}, │ │ │ │ + removeText: function(featureId) { │ │ │ │ + var label = document.getElementById(featureId + this.LABEL_ID_SUFFIX); │ │ │ │ + if (label) { │ │ │ │ + this.textRoot.removeChild(label) │ │ │ │ } │ │ │ │ - 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) { │ │ │ │ + var outline = document.getElementById(featureId + this.LABEL_OUTLINE_SUFFIX); │ │ │ │ + if (outline) { │ │ │ │ + this.textRoot.removeChild(outline) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getFeatureIdFromEvent: function(evt) { │ │ │ │ + var target = evt.target; │ │ │ │ + var useElement = target && target.correspondingUseElement; │ │ │ │ + var node = useElement ? useElement : target || evt.srcElement; │ │ │ │ + return node._featureId │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + bElem.parentNode.removeChild(bElem) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + nodeTypeCompare: function(node, type) {}, │ │ │ │ + createNode: function(type, id) {}, │ │ │ │ + moveRoot: function(renderer) { │ │ │ │ + var root = this.root; │ │ │ │ + if (renderer.root.parentNode == this.rendererRoot) { │ │ │ │ + root = renderer.root │ │ │ │ + } │ │ │ │ + root.parentNode.removeChild(root); │ │ │ │ + renderer.rendererRoot.appendChild(root) │ │ │ │ + }, │ │ │ │ + getRenderLayerId: function() { │ │ │ │ + return this.root.parentNode.parentNode.id │ │ │ │ + }, │ │ │ │ + isComplexSymbol: function(graphicName) { │ │ │ │ + return graphicName != "circle" && !!graphicName │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Renderer.Elements" │ │ │ │ +}); │ │ │ │ +OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ + xmlns: "http://www.w3.org/2000/svg", │ │ │ │ + xlinkns: "http://www.w3.org/1999/xlink", │ │ │ │ + MAX_PIXEL: 15e3, │ │ │ │ + translationParameters: null, │ │ │ │ + symbolMetrics: null, │ │ │ │ + initialize: function(containerID) { │ │ │ │ + if (!this.supported()) { │ │ │ │ return │ │ │ │ } │ │ │ │ - var theta = Math.asin((xy.y - last.xy.y) / dist); │ │ │ │ - if (last.xy.x <= xy.x) { │ │ │ │ - theta = Math.PI - theta │ │ │ │ + OpenLayers.Renderer.Elements.prototype.initialize.apply(this, arguments); │ │ │ │ + this.translationParameters = { │ │ │ │ + x: 0, │ │ │ │ + y: 0 │ │ │ │ + }; │ │ │ │ + this.symbolMetrics = {} │ │ │ │ + }, │ │ │ │ + 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")) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 (resolutionChanged) { │ │ │ │ + this.left = left; │ │ │ │ + this.top = top; │ │ │ │ + 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) { │ │ │ │ + this.setExtent(extent, true) │ │ │ │ + } │ │ │ │ + return coordSysUnchanged && inRange │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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); │ │ │ │ + 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 : -(.5 * width); │ │ │ │ + var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.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)) { │ │ │ │ + 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; │ │ │ │ + var parent = node.parentNode; │ │ │ │ + var nextSibling = node.nextSibling; │ │ │ │ + if (parent) { │ │ │ │ + parent.removeChild(node) │ │ │ │ + } │ │ │ │ + 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); │ │ │ │ + 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"); │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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, ",") │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + createNode: function(type, id) { │ │ │ │ + var node = document.createElementNS(this.xmlns, type); │ │ │ │ + if (id) { │ │ │ │ + node.setAttributeNS(null, "id", id) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + nodeTypeCompare: function(node, type) { │ │ │ │ + return type == node.nodeName │ │ │ │ + }, │ │ │ │ + createRenderRoot: function() { │ │ │ │ + var svg = this.nodeFactory(this.container.id + "_svgRoot", "svg"); │ │ │ │ + svg.style.display = "block"; │ │ │ │ + return svg │ │ │ │ + }, │ │ │ │ + createRoot: function(suffix) { │ │ │ │ + return this.nodeFactory(this.container.id + suffix, "g") │ │ │ │ + }, │ │ │ │ + createDefs: function() { │ │ │ │ + var defs = this.nodeFactory(this.container.id + "_defs", "defs"); │ │ │ │ + this.rendererRoot.appendChild(defs); │ │ │ │ + return defs │ │ │ │ + }, │ │ │ │ + drawPoint: function(node, geometry) { │ │ │ │ + return this.drawCircle(node, geometry, 1) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawText: function(featureId, style, location) { │ │ │ │ + var drawOutline = !!style.labelOutlineWidth; │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 { │ │ │ │ + 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 { │ │ │ │ - speed: speed, │ │ │ │ - theta: theta │ │ │ │ + path: strings.join(separator || ","), │ │ │ │ + complete: complete │ │ │ │ } │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getPosition: function(node) { │ │ │ │ + return { │ │ │ │ + x: parseFloat(node.getAttributeNS(null, "cx")), │ │ │ │ + y: parseFloat(node.getAttributeNS(null, "cy")) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + importSymbol: function(graphicName) { │ │ │ │ + if (!this.defs) { │ │ │ │ + this.defs = this.createDefs() │ │ │ │ + } │ │ │ │ + var id = this.container.id + "-" + graphicName; │ │ │ │ + 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(); │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +OpenLayers.Renderer.SVG.LABEL_ALIGN = { │ │ │ │ + l: "start", │ │ │ │ + r: "end", │ │ │ │ + b: "bottom", │ │ │ │ + t: "hanging" │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.SVG.LABEL_VSHIFT = { │ │ │ │ + t: "-70%", │ │ │ │ + b: "0" │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.SVG.LABEL_VFACTOR = { │ │ │ │ + t: 0, │ │ │ │ + b: -1 │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.SVG.preventDefault = function(e) { │ │ │ │ + OpenLayers.Event.preventDefault(e) │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ + xmlns: "urn:schemas-microsoft-com:vml", │ │ │ │ + symbolCache: {}, │ │ │ │ + offset: null, │ │ │ │ + initialize: function(containerID) { │ │ │ │ + if (!this.supported()) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + if (!document.namespaces.olv) { │ │ │ │ + document.namespaces.add("olv", this.xmlns); │ │ │ │ + var style = document.createStyleSheet(); │ │ │ │ + var shapes = ["shape", "rect", "oval", "fill", "stroke", "imagedata", "group", "textbox"]; │ │ │ │ + for (var i = 0, len = shapes.length; i < len; i++) { │ │ │ │ + style.addRule("olv\\:" + shapes[i], "behavior: url(#default#VML); " + "position: absolute; display: inline-block;") │ │ │ │ } │ │ │ │ - var t = (new Date).getTime() - initialTime; │ │ │ │ - var p = -this.deceleration * Math.pow(t, 2) / 2 + 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 │ │ │ │ + } │ │ │ │ + OpenLayers.Renderer.Elements.prototype.initialize.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + supported: function() { │ │ │ │ + return !!document.namespaces │ │ │ │ + }, │ │ │ │ + setExtent: function(extent, resolutionChanged) { │ │ │ │ + var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var left = extent.left / resolution | 0; │ │ │ │ + var top = extent.top / resolution - this.size.h | 0; │ │ │ │ + if (resolutionChanged || !this.offset) { │ │ │ │ + this.offset = { │ │ │ │ + x: left, │ │ │ │ + y: top │ │ │ │ + }; │ │ │ │ + left = 0; │ │ │ │ + top = 0 │ │ │ │ + } else { │ │ │ │ + left = left - this.offset.x; │ │ │ │ + top = top - this.offset.y │ │ │ │ + } │ │ │ │ + var org = left - this.xOffset + " " + top; │ │ │ │ + this.root.coordorigin = org; │ │ │ │ + var roots = [this.root, this.vectorRoot, this.textRoot]; │ │ │ │ + var root; │ │ │ │ + for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ + root = roots[i]; │ │ │ │ + var size = this.size.w + " " + this.size.h; │ │ │ │ + root.coordsize = size │ │ │ │ + } │ │ │ │ + this.root.style.flip = "y"; │ │ │ │ + return coordSysUnchanged │ │ │ │ + }, │ │ │ │ + setSize: function(size) { │ │ │ │ + OpenLayers.Renderer.prototype.setSize.apply(this, arguments); │ │ │ │ + var roots = [this.rendererRoot, this.root, this.vectorRoot, this.textRoot]; │ │ │ │ + var w = this.size.w + "px"; │ │ │ │ + var h = this.size.h + "px"; │ │ │ │ + var root; │ │ │ │ + for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ + root = roots[i]; │ │ │ │ + root.style.width = w; │ │ │ │ + root.style.height = h │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getNodeType: function(geometry, style) { │ │ │ │ + var nodeType = null; │ │ │ │ + switch (geometry.CLASS_NAME) { │ │ │ │ + case "OpenLayers.Geometry.Point": │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + nodeType = "olv:rect" │ │ │ │ + } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ + nodeType = "olv:shape" │ │ │ │ + } else { │ │ │ │ + nodeType = "olv:oval" │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case "OpenLayers.Geometry.Rectangle": │ │ │ │ + nodeType = "olv:rect"; │ │ │ │ + break; │ │ │ │ + case "OpenLayers.Geometry.LineString": │ │ │ │ + case "OpenLayers.Geometry.LinearRing": │ │ │ │ + case "OpenLayers.Geometry.Polygon": │ │ │ │ + case "OpenLayers.Geometry.Curve": │ │ │ │ + nodeType = "olv:shape"; │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + break │ │ │ │ + } │ │ │ │ + return nodeType │ │ │ │ + }, │ │ │ │ + setStyle: function(node, style, options, geometry) { │ │ │ │ + style = style || node._style; │ │ │ │ + options = options || node._options; │ │ │ │ + var fillColor = style.fillColor; │ │ │ │ + var title = style.title || style.graphicTitle; │ │ │ │ + if (title) { │ │ │ │ + node.title = title │ │ │ │ + } │ │ │ │ + if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + options.isFilled = true; │ │ │ │ + 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 resolution = this.getResolution(); │ │ │ │ + var xOffset = style.graphicXOffset != undefined ? style.graphicXOffset : -(.5 * width); │ │ │ │ + var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.5 * height); │ │ │ │ + node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x + xOffset | 0) + "px"; │ │ │ │ + node.style.top = (geometry.y / resolution - this.offset.y - (yOffset + height) | 0) + "px"; │ │ │ │ + node.style.width = width + "px"; │ │ │ │ + node.style.height = height + "px"; │ │ │ │ + node.style.flip = "y"; │ │ │ │ + fillColor = "none"; │ │ │ │ + options.isStroked = false │ │ │ │ + } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ + var cache = this.importSymbol(style.graphicName); │ │ │ │ + node.path = cache.path; │ │ │ │ + node.coordorigin = cache.left + "," + cache.bottom; │ │ │ │ + var size = cache.size; │ │ │ │ + node.coordsize = size + "," + size; │ │ │ │ + this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ + node.style.flip = "y" │ │ │ │ + } else { │ │ │ │ + this.drawCircle(node, geometry, style.pointRadius) │ │ │ │ } │ │ │ │ - args.x = x - lastX; │ │ │ │ - args.y = y - lastY; │ │ │ │ - lastX = x; │ │ │ │ - lastY = y; │ │ │ │ - callback(args.x, args.y, args.end) │ │ │ │ + } │ │ │ │ + if (options.isFilled) { │ │ │ │ + node.fillcolor = fillColor │ │ │ │ + } else { │ │ │ │ + node.filled = "false" │ │ │ │ + } │ │ │ │ + var fills = node.getElementsByTagName("fill"); │ │ │ │ + var fill = fills.length == 0 ? null : fills[0]; │ │ │ │ + if (!options.isFilled) { │ │ │ │ + if (fill) { │ │ │ │ + node.removeChild(fill) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (!fill) { │ │ │ │ + fill = this.createNode("olv:fill", node.id + "_fill") │ │ │ │ + } │ │ │ │ + fill.opacity = style.fillOpacity; │ │ │ │ + if (node._geometryClass === "OpenLayers.Geometry.Point" && style.externalGraphic) { │ │ │ │ + if (style.graphicOpacity) { │ │ │ │ + fill.opacity = style.graphicOpacity │ │ │ │ + } │ │ │ │ + fill.src = style.externalGraphic; │ │ │ │ + fill.type = "frame"; │ │ │ │ + if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ + fill.aspect = "atmost" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (fill.parentNode != node) { │ │ │ │ + node.appendChild(fill) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var rotation = style.rotation; │ │ │ │ + if (rotation !== undefined || node._rotation !== undefined) { │ │ │ │ + node._rotation = rotation; │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ + fill.opacity = 0 │ │ │ │ + } else if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ + node.style.rotation = rotation || 0 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var strokes = node.getElementsByTagName("stroke"); │ │ │ │ + var stroke = strokes.length == 0 ? null : strokes[0]; │ │ │ │ + if (!options.isStroked) { │ │ │ │ + node.stroked = false; │ │ │ │ + if (stroke) { │ │ │ │ + stroke.on = false │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (!stroke) { │ │ │ │ + stroke = this.createNode("olv:stroke", node.id + "_stroke"); │ │ │ │ + node.appendChild(stroke) │ │ │ │ + } │ │ │ │ + stroke.on = true; │ │ │ │ + stroke.color = style.strokeColor; │ │ │ │ + stroke.weight = style.strokeWidth + "px"; │ │ │ │ + stroke.opacity = style.strokeOpacity; │ │ │ │ + stroke.endcap = style.strokeLinecap == "butt" ? "flat" : style.strokeLinecap || "round"; │ │ │ │ + if (style.strokeDashstyle) { │ │ │ │ + stroke.dashstyle = this.dashStyle(style) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ + node.style.cursor = style.cursor │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + graphicRotate: function(node, xOffset, yOffset, style) { │ │ │ │ + var style = style || node._style; │ │ │ │ + var rotation = style.rotation || 0; │ │ │ │ + var aspectRatio, size; │ │ │ │ + if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ + var img = new Image; │ │ │ │ + img.onreadystatechange = OpenLayers.Function.bind(function() { │ │ │ │ + if (img.readyState == "complete" || img.readyState == "interactive") { │ │ │ │ + aspectRatio = img.width / img.height; │ │ │ │ + size = Math.max(style.pointRadius * 2, style.graphicWidth || 0, style.graphicHeight || 0); │ │ │ │ + xOffset = xOffset * aspectRatio; │ │ │ │ + style.graphicWidth = size * aspectRatio; │ │ │ │ + style.graphicHeight = size; │ │ │ │ + this.graphicRotate(node, xOffset, yOffset, style) │ │ │ │ + } │ │ │ │ + }, this); │ │ │ │ + img.src = style.externalGraphic; │ │ │ │ + return │ │ │ │ + } else { │ │ │ │ + size = Math.max(style.graphicWidth, style.graphicHeight); │ │ │ │ + aspectRatio = style.graphicWidth / style.graphicHeight │ │ │ │ + } │ │ │ │ + var width = Math.round(style.graphicWidth || size * aspectRatio); │ │ │ │ + var height = Math.round(style.graphicHeight || size); │ │ │ │ + node.style.width = width + "px"; │ │ │ │ + node.style.height = height + "px"; │ │ │ │ + var image = document.getElementById(node.id + "_image"); │ │ │ │ + if (!image) { │ │ │ │ + image = this.createNode("olv:imagedata", node.id + "_image"); │ │ │ │ + node.appendChild(image) │ │ │ │ + } │ │ │ │ + image.style.width = width + "px"; │ │ │ │ + image.style.height = height + "px"; │ │ │ │ + image.src = style.externalGraphic; │ │ │ │ + image.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + "src='', sizingMethod='scale')"; │ │ │ │ + var rot = rotation * Math.PI / 180; │ │ │ │ + var sintheta = Math.sin(rot); │ │ │ │ + var costheta = Math.cos(rot); │ │ │ │ + var filter = "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta + ",M12=" + -sintheta + ",M21=" + sintheta + ",M22=" + costheta + ",SizingMethod='auto expand')\n"; │ │ │ │ + var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ + if (opacity && opacity != 1) { │ │ │ │ + filter += "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + opacity + ")\n" │ │ │ │ + } │ │ │ │ + node.style.filter = filter; │ │ │ │ + var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset); │ │ │ │ + var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry(); │ │ │ │ + imgBox.rotate(style.rotation, centerPoint); │ │ │ │ + var imgBounds = imgBox.getBounds(); │ │ │ │ + node.style.left = Math.round(parseInt(node.style.left) + imgBounds.left) + "px"; │ │ │ │ + node.style.top = Math.round(parseInt(node.style.top) - imgBounds.bottom) + "px" │ │ │ │ + }, │ │ │ │ + postDraw: function(node) { │ │ │ │ + node.style.visibility = "visible"; │ │ │ │ + var fillColor = node._style.fillColor; │ │ │ │ + var strokeColor = node._style.strokeColor; │ │ │ │ + if (fillColor == "none" && node.fillcolor != fillColor) { │ │ │ │ + node.fillcolor = fillColor │ │ │ │ + } │ │ │ │ + if (strokeColor == "none" && node.strokecolor != strokeColor) { │ │ │ │ + node.strokecolor = strokeColor │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setNodeDimension: function(node, geometry) { │ │ │ │ + var bbox = geometry.getBounds(); │ │ │ │ + if (bbox) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var scaledBox = new OpenLayers.Bounds((bbox.left - this.featureDx) / resolution - this.offset.x | 0, bbox.bottom / resolution - this.offset.y | 0, (bbox.right - this.featureDx) / resolution - this.offset.x | 0, bbox.top / resolution - this.offset.y | 0); │ │ │ │ + node.style.left = scaledBox.left + "px"; │ │ │ │ + node.style.top = scaledBox.top + "px"; │ │ │ │ + node.style.width = scaledBox.getWidth() + "px"; │ │ │ │ + node.style.height = scaledBox.getHeight() + "px"; │ │ │ │ + node.coordorigin = scaledBox.left + " " + scaledBox.top; │ │ │ │ + node.coordsize = scaledBox.getWidth() + " " + scaledBox.getHeight() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + dashStyle: function(style) { │ │ │ │ + var dash = style.strokeDashstyle; │ │ │ │ + switch (dash) { │ │ │ │ + case "solid": │ │ │ │ + case "dot": │ │ │ │ + case "dash": │ │ │ │ + case "dashdot": │ │ │ │ + case "longdash": │ │ │ │ + case "longdashdot": │ │ │ │ + return dash; │ │ │ │ + default: │ │ │ │ + var parts = dash.split(/[ ,]/); │ │ │ │ + if (parts.length == 2) { │ │ │ │ + if (1 * parts[0] >= 2 * parts[1]) { │ │ │ │ + return "longdash" │ │ │ │ + } │ │ │ │ + return parts[0] == 1 || parts[1] == 1 ? "dot" : "dash" │ │ │ │ + } else if (parts.length == 4) { │ │ │ │ + return 1 * parts[0] >= 2 * parts[1] ? "longdashdot" : "dashdot" │ │ │ │ + } │ │ │ │ + return "solid" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + createNode: function(type, id) { │ │ │ │ + var node = document.createElement(type); │ │ │ │ + if (id) { │ │ │ │ + node.id = id │ │ │ │ + } │ │ │ │ + node.unselectable = "on"; │ │ │ │ + node.onselectstart = OpenLayers.Function.False; │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + nodeTypeCompare: function(node, type) { │ │ │ │ + var subType = type; │ │ │ │ + var splitIndex = subType.indexOf(":"); │ │ │ │ + if (splitIndex != -1) { │ │ │ │ + subType = subType.substr(splitIndex + 1) │ │ │ │ + } │ │ │ │ + var nodeName = node.nodeName; │ │ │ │ + splitIndex = nodeName.indexOf(":"); │ │ │ │ + if (splitIndex != -1) { │ │ │ │ + nodeName = nodeName.substr(splitIndex + 1) │ │ │ │ + } │ │ │ │ + return subType == nodeName │ │ │ │ + }, │ │ │ │ + createRenderRoot: function() { │ │ │ │ + return this.nodeFactory(this.container.id + "_vmlRoot", "div") │ │ │ │ + }, │ │ │ │ + createRoot: function(suffix) { │ │ │ │ + return this.nodeFactory(this.container.id + suffix, "olv:group") │ │ │ │ + }, │ │ │ │ + drawPoint: function(node, geometry) { │ │ │ │ + return this.drawCircle(node, geometry, 1) │ │ │ │ + }, │ │ │ │ + drawCircle: function(node, geometry, radius) { │ │ │ │ + if (!isNaN(geometry.x) && !isNaN(geometry.y)) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x | 0) - radius + "px"; │ │ │ │ + node.style.top = (geometry.y / resolution - this.offset.y | 0) - radius + "px"; │ │ │ │ + var diameter = radius * 2; │ │ │ │ + node.style.width = diameter + "px"; │ │ │ │ + node.style.height = diameter + "px"; │ │ │ │ + return node │ │ │ │ + } │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + drawLineString: function(node, geometry) { │ │ │ │ + return this.drawLine(node, geometry, false) │ │ │ │ + }, │ │ │ │ + drawLinearRing: function(node, geometry) { │ │ │ │ + return this.drawLine(node, geometry, true) │ │ │ │ + }, │ │ │ │ + drawLine: function(node, geometry, closeLine) { │ │ │ │ + this.setNodeDimension(node, geometry); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var numComponents = geometry.components.length; │ │ │ │ + var parts = new Array(numComponents); │ │ │ │ + var comp, x, y; │ │ │ │ + for (var i = 0; i < numComponents; i++) { │ │ │ │ + comp = geometry.components[i]; │ │ │ │ + x = (comp.x - this.featureDx) / resolution - this.offset.x | 0; │ │ │ │ + y = comp.y / resolution - this.offset.y | 0; │ │ │ │ + parts[i] = " " + x + "," + y + " l " │ │ │ │ + } │ │ │ │ + var end = closeLine ? " x e" : " e"; │ │ │ │ + node.path = "m" + parts.join("") + end; │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + drawPolygon: function(node, geometry) { │ │ │ │ + this.setNodeDimension(node, geometry); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var path = []; │ │ │ │ + var j, jj, points, area, first, second, i, ii, comp, pathComp, x, y; │ │ │ │ + for (j = 0, jj = geometry.components.length; j < jj; j++) { │ │ │ │ + path.push("m"); │ │ │ │ + points = geometry.components[j].components; │ │ │ │ + area = j === 0; │ │ │ │ + first = null; │ │ │ │ + second = null; │ │ │ │ + for (i = 0, ii = points.length; i < ii; i++) { │ │ │ │ + comp = points[i]; │ │ │ │ + x = (comp.x - this.featureDx) / resolution - this.offset.x | 0; │ │ │ │ + y = comp.y / resolution - this.offset.y | 0; │ │ │ │ + pathComp = " " + x + "," + y; │ │ │ │ + path.push(pathComp); │ │ │ │ + if (i == 0) { │ │ │ │ + path.push(" l") │ │ │ │ + } │ │ │ │ + if (!area) { │ │ │ │ + if (!first) { │ │ │ │ + first = pathComp │ │ │ │ + } else if (first != pathComp) { │ │ │ │ + if (!second) { │ │ │ │ + second = pathComp │ │ │ │ + } else if (second != pathComp) { │ │ │ │ + area = true │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + path.push(area ? " x " : " ") │ │ │ │ + } │ │ │ │ + path.push("e"); │ │ │ │ + node.path = path.join(""); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + drawRectangle: function(node, geometry) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x | 0) + "px"; │ │ │ │ + node.style.top = (geometry.y / resolution - this.offset.y | 0) + "px"; │ │ │ │ + node.style.width = (geometry.width / resolution | 0) + "px"; │ │ │ │ + node.style.height = (geometry.height / resolution | 0) + "px"; │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + drawText: function(featureId, style, location) { │ │ │ │ + var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect"); │ │ │ │ + var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox"); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + label.style.left = ((location.x - this.featureDx) / resolution - this.offset.x | 0) + "px"; │ │ │ │ + label.style.top = (location.y / resolution - this.offset.y | 0) + "px"; │ │ │ │ + label.style.flip = "y"; │ │ │ │ + textbox.innerText = style.label; │ │ │ │ + if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ + textbox.style.cursor = style.cursor │ │ │ │ + } │ │ │ │ + if (style.fontColor) { │ │ │ │ + textbox.style.color = style.fontColor │ │ │ │ + } │ │ │ │ + if (style.fontOpacity) { │ │ │ │ + textbox.style.filter = "alpha(opacity=" + style.fontOpacity * 100 + ")" │ │ │ │ + } │ │ │ │ + if (style.fontFamily) { │ │ │ │ + textbox.style.fontFamily = style.fontFamily │ │ │ │ + } │ │ │ │ + if (style.fontSize) { │ │ │ │ + textbox.style.fontSize = style.fontSize │ │ │ │ + } │ │ │ │ + if (style.fontWeight) { │ │ │ │ + textbox.style.fontWeight = style.fontWeight │ │ │ │ + } │ │ │ │ + if (style.fontStyle) { │ │ │ │ + textbox.style.fontStyle = style.fontStyle │ │ │ │ + } │ │ │ │ + if (style.labelSelect === true) { │ │ │ │ + label._featureId = featureId; │ │ │ │ + textbox._featureId = featureId; │ │ │ │ + textbox._geometry = location; │ │ │ │ + textbox._geometryClass = location.CLASS_NAME │ │ │ │ + } │ │ │ │ + textbox.style.whiteSpace = "nowrap"; │ │ │ │ + textbox.inset = "1px,0px,0px,0px"; │ │ │ │ + if (!label.parentNode) { │ │ │ │ + label.appendChild(textbox); │ │ │ │ + this.textRoot.appendChild(label) │ │ │ │ + } │ │ │ │ + var align = style.labelAlign || "cm"; │ │ │ │ + if (align.length == 1) { │ │ │ │ + align += "m" │ │ │ │ + } │ │ │ │ + var xshift = textbox.clientWidth * OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0, 1)]; │ │ │ │ + var yshift = textbox.clientHeight * OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1, 1)]; │ │ │ │ + label.style.left = parseInt(label.style.left) - xshift - 1 + "px"; │ │ │ │ + label.style.top = parseInt(label.style.top) + yshift + "px" │ │ │ │ + }, │ │ │ │ + moveRoot: function(renderer) { │ │ │ │ + var layer = this.map.getLayer(renderer.container.id); │ │ │ │ + if (layer instanceof OpenLayers.Layer.Vector.RootContainer) { │ │ │ │ + layer = this.map.getLayer(this.container.id) │ │ │ │ + } │ │ │ │ + layer && layer.renderer.clear(); │ │ │ │ + OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments); │ │ │ │ + layer && layer.redraw() │ │ │ │ + }, │ │ │ │ + importSymbol: function(graphicName) { │ │ │ │ + var id = this.container.id + "-" + graphicName; │ │ │ │ + var cache = this.symbolCache[id]; │ │ │ │ + if (cache) { │ │ │ │ + return cache │ │ │ │ + } │ │ │ │ + var symbol = OpenLayers.Renderer.symbol[graphicName]; │ │ │ │ + if (!symbol) { │ │ │ │ + throw new Error(graphicName + " is not a valid symbol name") │ │ │ │ + } │ │ │ │ + var symbolExtent = new OpenLayers.Bounds(Number.MAX_VALUE, Number.MAX_VALUE, 0, 0); │ │ │ │ + var pathitems = ["m"]; │ │ │ │ + for (var i = 0; i < symbol.length; i = i + 2) { │ │ │ │ + var x = symbol[i]; │ │ │ │ + var 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); │ │ │ │ + pathitems.push(x); │ │ │ │ + pathitems.push(y); │ │ │ │ + if (i == 0) { │ │ │ │ + pathitems.push("l") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + pathitems.push("x e"); │ │ │ │ + var path = pathitems.join(" "); │ │ │ │ + var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2; │ │ │ │ + if (diff > 0) { │ │ │ │ + symbolExtent.bottom = symbolExtent.bottom - diff; │ │ │ │ + symbolExtent.top = symbolExtent.top + diff │ │ │ │ + } else { │ │ │ │ + symbolExtent.left = symbolExtent.left + diff; │ │ │ │ + symbolExtent.right = symbolExtent.right - diff │ │ │ │ + } │ │ │ │ + cache = { │ │ │ │ + path: path, │ │ │ │ + size: symbolExtent.getWidth(), │ │ │ │ + left: symbolExtent.left, │ │ │ │ + bottom: symbolExtent.bottom │ │ │ │ }; │ │ │ │ - this.timerId = OpenLayers.Animation.start(OpenLayers.Function.bind(timerCallback, this)) │ │ │ │ + this.symbolCache[id] = cache; │ │ │ │ + return cache │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Kinetic" │ │ │ │ + CLASS_NAME: "OpenLayers.Renderer.VML" │ │ │ │ +}); │ │ │ │ +OpenLayers.Renderer.VML.LABEL_SHIFT = { │ │ │ │ + l: 0, │ │ │ │ + c: .5, │ │ │ │ + r: 1, │ │ │ │ + t: 0, │ │ │ │ + m: .5, │ │ │ │ + b: 1 │ │ │ │ +}; │ │ │ │ +OpenLayers.Strategy = OpenLayers.Class({ │ │ │ │ + layer: null, │ │ │ │ + options: null, │ │ │ │ + active: null, │ │ │ │ + autoActivate: true, │ │ │ │ + autoDestroy: true, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + this.options = options; │ │ │ │ + this.active = false │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + this.layer = null; │ │ │ │ + this.options = null │ │ │ │ + }, │ │ │ │ + setLayer: function(layer) { │ │ │ │ + this.layer = layer │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (!this.active) { │ │ │ │ + this.active = true; │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (this.active) { │ │ │ │ + this.active = false; │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ +}); │ │ │ │ +OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + preload: false, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + 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.Filter.Spatial = OpenLayers.Class(OpenLayers.Filter, { │ │ │ │ + type: null, │ │ │ │ + property: null, │ │ │ │ + value: null, │ │ │ │ + distance: null, │ │ │ │ + distanceUnits: null, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + bounds: null, │ │ │ │ + resolution: null, │ │ │ │ + ratio: 2, │ │ │ │ + resFactor: null, │ │ │ │ + response: null, │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + moveend: this.update, │ │ │ │ + refresh: this.update, │ │ │ │ + visibilitychanged: this.update, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.update() │ │ │ │ + } │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.layer.events.un({ │ │ │ │ + moveend: this.update, │ │ │ │ + refresh: this.update, │ │ │ │ + visibilitychanged: this.update, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + return deactivated │ │ │ │ + }, │ │ │ │ + update: function(options) { │ │ │ │ + var mapBounds = this.getMapBounds(); │ │ │ │ + if (mapBounds !== null && (options && options.force || this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds))) { │ │ │ │ + this.calculateBounds(mapBounds); │ │ │ │ + this.resolution = this.layer.map.getResolution(); │ │ │ │ + this.triggerRead(options) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getMapBounds: function() { │ │ │ │ + if (this.layer.map === null) { │ │ │ │ + return null │ │ │ │ + } │ │ │ │ + var bounds = this.layer.map.getExtent(); │ │ │ │ + if (bounds && !this.layer.projection.equals(this.layer.map.getProjectionObject())) { │ │ │ │ + bounds = bounds.clone().transform(this.layer.map.getProjectionObject(), this.layer.projection) │ │ │ │ + } │ │ │ │ + return bounds │ │ │ │ + }, │ │ │ │ + invalidBounds: function(mapBounds) { │ │ │ │ + if (!mapBounds) { │ │ │ │ + mapBounds = this.getMapBounds() │ │ │ │ + } │ │ │ │ + var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds); │ │ │ │ + if (!invalid && this.resFactor) { │ │ │ │ + var ratio = this.resolution / this.layer.map.getResolution(); │ │ │ │ + invalid = ratio >= this.resFactor || ratio <= 1 / this.resFactor │ │ │ │ + } │ │ │ │ + return invalid │ │ │ │ + }, │ │ │ │ + calculateBounds: function(mapBounds) { │ │ │ │ + if (!mapBounds) { │ │ │ │ + mapBounds = this.getMapBounds() │ │ │ │ + } │ │ │ │ + var center = mapBounds.getCenterLonLat(); │ │ │ │ + var dataWidth = mapBounds.getWidth() * this.ratio; │ │ │ │ + var dataHeight = mapBounds.getHeight() * this.ratio; │ │ │ │ + this.bounds = new OpenLayers.Bounds(center.lon - dataWidth / 2, center.lat - dataHeight / 2, center.lon + dataWidth / 2, center.lat + dataHeight / 2) │ │ │ │ + }, │ │ │ │ + triggerRead: function(options) { │ │ │ │ + if (this.response && !(options && options.noAbort === true)) { │ │ │ │ + this.layer.protocol.abort(this.response); │ │ │ │ + this.layer.events.triggerEvent("loadend") │ │ │ │ + } │ │ │ │ + var evt = { │ │ │ │ + filter: this.createFilter() │ │ │ │ + }; │ │ │ │ + this.layer.events.triggerEvent("loadstart", evt); │ │ │ │ + this.response = this.layer.protocol.read(OpenLayers.Util.applyDefaults({ │ │ │ │ + filter: evt.filter, │ │ │ │ + callback: this.merge, │ │ │ │ + scope: this │ │ │ │ + }, options)) │ │ │ │ + }, │ │ │ │ + createFilter: function() { │ │ │ │ + var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ + value: this.bounds, │ │ │ │ + projection: this.layer.projection │ │ │ │ + }); │ │ │ │ + if (this.layer.filter) { │ │ │ │ + filter = new OpenLayers.Filter.Logical({ │ │ │ │ + type: OpenLayers.Filter.Logical.AND, │ │ │ │ + filters: [this.layer.filter, filter] │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + return filter │ │ │ │ + }, │ │ │ │ + merge: function(resp) { │ │ │ │ + this.layer.destroyFeatures(); │ │ │ │ + if (resp.success()) { │ │ │ │ + var features = resp.features; │ │ │ │ + if (features && features.length > 0) { │ │ │ │ + var remote = this.layer.projection; │ │ │ │ + var local = this.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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.layer.addFeatures(features) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.bounds = null │ │ │ │ + } │ │ │ │ + this.response = null; │ │ │ │ + this.layer.events.triggerEvent("loadend", { │ │ │ │ + response: resp │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.BBOX" │ │ │ │ }); │ │ │ │ OpenLayers.Layer = OpenLayers.Class({ │ │ │ │ id: null, │ │ │ │ name: null, │ │ │ │ div: null, │ │ │ │ opacity: 1, │ │ │ │ alwaysInRange: null, │ │ │ │ @@ -6003,154 +8011,36 @@ │ │ │ │ this.metadata = metadata; │ │ │ │ this.initLayer(); │ │ │ │ var script = document.getElementById(this._callbackId); │ │ │ │ script.parentNode.removeChild(script); │ │ │ │ window[this._callbackId] = undefined; │ │ │ │ delete this._callbackId │ │ │ │ }; │ │ │ │ -OpenLayers.Renderer = OpenLayers.Class({ │ │ │ │ - container: null, │ │ │ │ - root: null, │ │ │ │ - extent: null, │ │ │ │ - locked: false, │ │ │ │ - size: null, │ │ │ │ - resolution: null, │ │ │ │ - map: null, │ │ │ │ - featureDx: 0, │ │ │ │ - initialize: function(containerID, options) { │ │ │ │ - this.container = OpenLayers.Util.getElement(containerID); │ │ │ │ - OpenLayers.Util.extend(this, options) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.container = null; │ │ │ │ - this.extent = null; │ │ │ │ - this.size = null; │ │ │ │ - this.resolution = null; │ │ │ │ - this.map = null │ │ │ │ - }, │ │ │ │ - supported: function() { │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - setSize: function(size) { │ │ │ │ - this.size = size.clone(); │ │ │ │ - this.resolution = null │ │ │ │ - }, │ │ │ │ - getResolution: function() { │ │ │ │ - this.resolution = this.resolution || this.map.getResolution(); │ │ │ │ - return this.resolution │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawGeometry: function(geometry, style, featureId) {}, │ │ │ │ - drawText: function(featureId, style, location) {}, │ │ │ │ - removeText: function(featureId) {}, │ │ │ │ - clear: function() {}, │ │ │ │ - getFeatureIdFromEvent: function(evt) {}, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - eraseGeometry: function(geometry, featureId) {}, │ │ │ │ - moveRoot: function(renderer) {}, │ │ │ │ - getRenderLayerId: function() { │ │ │ │ - return this.container.id │ │ │ │ +OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ + name: "OpenStreetMap", │ │ │ │ + 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"], │ │ │ │ + attribution: "© <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors", │ │ │ │ + sphericalMercator: true, │ │ │ │ + wrapDateLine: true, │ │ │ │ + tileOptions: null, │ │ │ │ + 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) │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.OSM(this.name, this.url, this.getOptions()) │ │ │ │ } │ │ │ │ - OpenLayers.Util.extend(result, symbolizer); │ │ │ │ - return result │ │ │ │ + obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer" │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.OSM" │ │ │ │ }); │ │ │ │ -OpenLayers.Renderer.defaultSymbolizer = { │ │ │ │ - fillColor: "#000000", │ │ │ │ - strokeColor: "#000000", │ │ │ │ - strokeWidth: 2, │ │ │ │ - fillOpacity: 1, │ │ │ │ - strokeOpacity: 1, │ │ │ │ - pointRadius: 0, │ │ │ │ - labelAlign: "cm" │ │ │ │ -}; │ │ │ │ -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.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ isBaseLayer: false, │ │ │ │ isFixed: false, │ │ │ │ features: null, │ │ │ │ filter: null, │ │ │ │ selectedFeatures: null, │ │ │ │ unrenderedFeatures: null, │ │ │ │ @@ -6648,36 +8538,14 @@ │ │ │ │ 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.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ - name: "OpenStreetMap", │ │ │ │ - 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"], │ │ │ │ - attribution: "© <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors", │ │ │ │ - sphericalMercator: true, │ │ │ │ - wrapDateLine: true, │ │ │ │ - tileOptions: null, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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.Layer.SphericalMercator = { │ │ │ │ getExtent: function() { │ │ │ │ var extent = null; │ │ │ │ if (this.sphericalMercator) { │ │ │ │ extent = this.map.calculateBounds() │ │ │ │ } else { │ │ │ │ extent = OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this) │ │ │ │ @@ -7410,14 +9278,681 @@ │ │ │ │ } │ │ │ │ return gLatLng │ │ │ │ }, │ │ │ │ getMapObjectPixelFromXY: function(x, y) { │ │ │ │ return new google.maps.Point(x, y) │ │ │ │ } │ │ │ │ }; │ │ │ │ +OpenLayers.Protocol = OpenLayers.Class({ │ │ │ │ + format: null, │ │ │ │ + options: null, │ │ │ │ + autoDestroy: true, │ │ │ │ + defaultFilter: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + this.options = options │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.options = null; │ │ │ │ + this.format = null │ │ │ │ + }, │ │ │ │ + read: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + options.filter = this.mergeWithDefaultFilter(options.filter) │ │ │ │ + }, │ │ │ │ + create: function() {}, │ │ │ │ + update: function() {}, │ │ │ │ + delete: function() {}, │ │ │ │ + commit: function() {}, │ │ │ │ + abort: function(response) {}, │ │ │ │ + createCallback: function(method, response, options) { │ │ │ │ + return OpenLayers.Function.bind(function() { │ │ │ │ + method.apply(this, [response, options]) │ │ │ │ + }, this) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol" │ │ │ │ +}); │ │ │ │ +OpenLayers.Protocol.Response = OpenLayers.Class({ │ │ │ │ + code: null, │ │ │ │ + requestType: null, │ │ │ │ + last: true, │ │ │ │ + features: null, │ │ │ │ + data: null, │ │ │ │ + reqFeatures: null, │ │ │ │ + priv: null, │ │ │ │ + error: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Util.extend(this, options) │ │ │ │ + }, │ │ │ │ + success: function() { │ │ │ │ + return this.code > 0 │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.Response" │ │ │ │ +}); │ │ │ │ +OpenLayers.Protocol.Response.SUCCESS = 1; │ │ │ │ +OpenLayers.Protocol.Response.FAILURE = 0; │ │ │ │ +OpenLayers.ProxyHost = ""; │ │ │ │ +if (!OpenLayers.Request) { │ │ │ │ + OpenLayers.Request = {} │ │ │ │ +} │ │ │ │ +OpenLayers.Util.extend(OpenLayers.Request, { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + URL_SPLIT_REGEX: /([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/, │ │ │ │ + events: new OpenLayers.Events(this), │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + issue: function(config) { │ │ │ │ + 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); │ │ │ │ + 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) { │ │ │ │ + config.headers["X-Requested-With"] = "XMLHttpRequest" │ │ │ │ + } │ │ │ │ + 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; │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }; │ │ │ │ + if (config.async === false) { │ │ │ │ + request.send(config.data) │ │ │ │ + } else { │ │ │ │ + window.setTimeout(function() { │ │ │ │ + if (request.readyState !== 0) { │ │ │ │ + request.send(config.data) │ │ │ │ + } │ │ │ │ + }, 0) │ │ │ │ + } │ │ │ │ + return request │ │ │ │ + }, │ │ │ │ + runCallbacks: function(options) { │ │ │ │ + var request = options.request; │ │ │ │ + var config = options.config; │ │ │ │ + var complete = config.scope ? OpenLayers.Function.bind(config.callback, config.scope) : config.callback; │ │ │ │ + var success; │ │ │ │ + if (config.success) { │ │ │ │ + success = config.scope ? OpenLayers.Function.bind(config.success, config.scope) : config.success │ │ │ │ + } │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + GET: function(config) { │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ + method: "GET" │ │ │ │ + }); │ │ │ │ + return OpenLayers.Request.issue(config) │ │ │ │ + }, │ │ │ │ + POST: function(config) { │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ + method: "POST" │ │ │ │ + }); │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + PUT: function(config) { │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ + method: "PUT" │ │ │ │ + }); │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + DELETE: function(config) { │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ + method: "DELETE" │ │ │ │ + }); │ │ │ │ + return OpenLayers.Request.issue(config) │ │ │ │ + }, │ │ │ │ + HEAD: function(config) { │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ + method: "HEAD" │ │ │ │ + }); │ │ │ │ + return OpenLayers.Request.issue(config) │ │ │ │ + }, │ │ │ │ + OPTIONS: function(config) { │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ + method: "OPTIONS" │ │ │ │ + }); │ │ │ │ + return OpenLayers.Request.issue(config) │ │ │ │ + } │ │ │ │ +}); │ │ │ │ +(function() { │ │ │ │ + var oXMLHttpRequest = window.XMLHttpRequest; │ │ │ │ + var bGecko = !!window.controllers, │ │ │ │ + bIE = window.document.all && !window.opera, │ │ │ │ + bIE7 = bIE && window.navigator.userAgent.match(/MSIE 7.0/); │ │ │ │ + │ │ │ │ + function fXMLHttpRequest() { │ │ │ │ + this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP"); │ │ │ │ + this._listeners = [] │ │ │ │ + } │ │ │ │ + │ │ │ │ + function cXMLHttpRequest() { │ │ │ │ + return new fXMLHttpRequest │ │ │ │ + } │ │ │ │ + cXMLHttpRequest.prototype = fXMLHttpRequest.prototype; │ │ │ │ + if (bGecko && oXMLHttpRequest.wrapped) cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped; │ │ │ │ + cXMLHttpRequest.UNSENT = 0; │ │ │ │ + cXMLHttpRequest.OPENED = 1; │ │ │ │ + cXMLHttpRequest.HEADERS_RECEIVED = 2; │ │ │ │ + cXMLHttpRequest.LOADING = 3; │ │ │ │ + cXMLHttpRequest.DONE = 4; │ │ │ │ + cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ + cXMLHttpRequest.prototype.responseText = ""; │ │ │ │ + cXMLHttpRequest.prototype.responseXML = null; │ │ │ │ + cXMLHttpRequest.prototype.status = 0; │ │ │ │ + cXMLHttpRequest.prototype.statusText = ""; │ │ │ │ + cXMLHttpRequest.prototype.priority = "NORMAL"; │ │ │ │ + cXMLHttpRequest.prototype.onreadystatechange = null; │ │ │ │ + cXMLHttpRequest.onreadystatechange = null; │ │ │ │ + cXMLHttpRequest.onopen = null; │ │ │ │ + cXMLHttpRequest.onsend = null; │ │ │ │ + cXMLHttpRequest.onabort = null; │ │ │ │ + cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) { │ │ │ │ + delete this._headers; │ │ │ │ + if (arguments.length < 3) bAsync = true; │ │ │ │ + this._async = bAsync; │ │ │ │ + var oRequest = this, │ │ │ │ + nState = this.readyState, │ │ │ │ + fOnUnload; │ │ │ │ + if (bIE && bAsync) { │ │ │ │ + fOnUnload = function() { │ │ │ │ + if (nState != cXMLHttpRequest.DONE) { │ │ │ │ + fCleanTransport(oRequest); │ │ │ │ + oRequest.abort() │ │ │ │ + } │ │ │ │ + }; │ │ │ │ + window.attachEvent("onunload", fOnUnload) │ │ │ │ + } │ │ │ │ + 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; │ │ │ │ + oRequest.readyState = oRequest._object.readyState; │ │ │ │ + fSynchronizeValues(oRequest); │ │ │ │ + if (oRequest._aborted) { │ │ │ │ + oRequest.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ + return │ │ │ │ + } │ │ │ │ + if (oRequest.readyState == cXMLHttpRequest.DONE) { │ │ │ │ + delete oRequest._data; │ │ │ │ + fCleanTransport(oRequest); │ │ │ │ + if (bIE && bAsync) window.detachEvent("onunload", fOnUnload) │ │ │ │ + } │ │ │ │ + if (nState != oRequest.readyState) fReadyStateChange(oRequest); │ │ │ │ + nState = oRequest.readyState │ │ │ │ + } │ │ │ │ + }; │ │ │ │ + │ │ │ │ + function fXMLHttpRequest_send(oRequest) { │ │ │ │ + oRequest._object.send(oRequest._data); │ │ │ │ + if (bGecko && !oRequest._async) { │ │ │ │ + oRequest.readyState = cXMLHttpRequest.OPENED; │ │ │ │ + fSynchronizeValues(oRequest); │ │ │ │ + while (oRequest.readyState < cXMLHttpRequest.DONE) { │ │ │ │ + oRequest.readyState++; │ │ │ │ + fReadyStateChange(oRequest); │ │ │ │ + if (oRequest._aborted) return │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + cXMLHttpRequest.prototype.send = function(vData) { │ │ │ │ + if (cXMLHttpRequest.onsend) cXMLHttpRequest.onsend.apply(this, arguments); │ │ │ │ + if (!arguments.length) vData = null; │ │ │ │ + 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; │ │ │ │ + fXMLHttpRequest_send(this) │ │ │ │ + }; │ │ │ │ + cXMLHttpRequest.prototype.abort = function() { │ │ │ │ + if (cXMLHttpRequest.onabort) cXMLHttpRequest.onabort.apply(this, arguments); │ │ │ │ + if (this.readyState > cXMLHttpRequest.UNSENT) this._aborted = true; │ │ │ │ + this._object.abort(); │ │ │ │ + fCleanTransport(this); │ │ │ │ + this.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ + delete this._data │ │ │ │ + }; │ │ │ │ + cXMLHttpRequest.prototype.getAllResponseHeaders = function() { │ │ │ │ + return this._object.getAllResponseHeaders() │ │ │ │ + }; │ │ │ │ + cXMLHttpRequest.prototype.getResponseHeader = function(sName) { │ │ │ │ + return this._object.getResponseHeader(sName) │ │ │ │ + }; │ │ │ │ + cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) { │ │ │ │ + if (!this._headers) this._headers = {}; │ │ │ │ + this._headers[sName] = sValue; │ │ │ │ + return this._object.setRequestHeader(sName, sValue) │ │ │ │ + }; │ │ │ │ + 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; │ │ │ │ + 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; │ │ │ │ + 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() {}, │ │ │ │ + preventDefault: function() {}, │ │ │ │ + initEvent: function() {} │ │ │ │ + }; │ │ │ │ + if (oEventPseudo.type == "readystatechange" && this.onreadystatechange)(this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]); │ │ │ │ + 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" + "]" │ │ │ │ + }; │ │ │ │ + │ │ │ │ + function fReadyStateChange(oRequest) { │ │ │ │ + if (cXMLHttpRequest.onreadystatechange) cXMLHttpRequest.onreadystatechange.apply(oRequest); │ │ │ │ + oRequest.dispatchEvent({ │ │ │ │ + type: "readystatechange", │ │ │ │ + bubbles: false, │ │ │ │ + cancelable: false, │ │ │ │ + timeStamp: new Date + 0 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + │ │ │ │ + function fGetDocument(oRequest) { │ │ │ │ + var oDocument = oRequest.responseXML, │ │ │ │ + sResponse = oRequest.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) │ │ │ │ + } │ │ │ │ + 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) { │ │ │ │ + oRequest._object.onreadystatechange = new window.Function │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (!OpenLayers.Request) { │ │ │ │ + OpenLayers.Request = {} │ │ │ │ + } │ │ │ │ + OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest │ │ │ │ +})(); │ │ │ │ +OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ + url: null, │ │ │ │ + headers: null, │ │ │ │ + params: null, │ │ │ │ + callback: null, │ │ │ │ + scope: null, │ │ │ │ + readWithPOST: false, │ │ │ │ + updateWithPOST: false, │ │ │ │ + deleteWithPOST: false, │ │ │ │ + wildcarded: false, │ │ │ │ + srsInBBOX: false, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.params = null; │ │ │ │ + this.headers = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleRead: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleCreate: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleUpdate: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleDelete: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options) │ │ │ │ + }, │ │ │ │ + handleResponse: function(resp, options) { │ │ │ │ + var request = resp.priv; │ │ │ │ + if (options.callback) { │ │ │ │ + if (request.status >= 200 && request.status < 300) { │ │ │ │ + if (resp.requestType != "delete") { │ │ │ │ + resp.features = this.parseFeatures(request) │ │ │ │ + } │ │ │ │ + resp.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ + } else { │ │ │ │ + resp.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ + } │ │ │ │ + options.callback.call(options.scope, resp) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + commit: function(features, options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ + var resp = [], │ │ │ │ + nResponses = 0; │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var nRequests = (types[OpenLayers.State.INSERT].length > 0 ? 1 : 0) + types[OpenLayers.State.UPDATE].length + types[OpenLayers.State.DELETE].length; │ │ │ │ + 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]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + response.priv.abort() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 = OpenLayers.Class({ │ │ │ │ id: null, │ │ │ │ map: null, │ │ │ │ div: null, │ │ │ │ type: null, │ │ │ │ allowSelection: false, │ │ │ │ displayClass: "", │ │ │ │ @@ -7871,14 +10406,675 @@ │ │ │ │ } │ │ │ │ delete this.zoomInLink; │ │ │ │ delete this.zoomOutLink; │ │ │ │ OpenLayers.Control.prototype.destroy.apply(this) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.Zoom" │ │ │ │ }); │ │ │ │ +OpenLayers.Handler = OpenLayers.Class({ │ │ │ │ + id: null, │ │ │ │ + control: null, │ │ │ │ + map: null, │ │ │ │ + keyMask: null, │ │ │ │ + active: false, │ │ │ │ + evt: null, │ │ │ │ + touch: false, │ │ │ │ + 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 + "_") │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + this.map = map │ │ │ │ + }, │ │ │ │ + checkModifiers: function(evt) { │ │ │ │ + if (this.keyMask == null) { │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + 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); │ │ │ │ + return keyModifiers == this.keyMask │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (this.active) { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (!this.active) { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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]]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + callback: function(name, args) { │ │ │ │ + if (name && this.callbacks[name]) { │ │ │ │ + this.callbacks[name].apply(this.control, args) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + register: function(name, method) { │ │ │ │ + this.map.events.registerPriority(name, this, method); │ │ │ │ + this.map.events.registerPriority(name, this, this.setEvent) │ │ │ │ + }, │ │ │ │ + unregister: function(name, method) { │ │ │ │ + this.map.events.unregister(name, this, method); │ │ │ │ + this.map.events.unregister(name, this, this.setEvent) │ │ │ │ + }, │ │ │ │ + setEvent: function(evt) { │ │ │ │ + this.evt = evt; │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + this.control = this.map = null │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.MOD_NONE = 0; │ │ │ │ +OpenLayers.Handler.MOD_SHIFT = 1; │ │ │ │ +OpenLayers.Handler.MOD_CTRL = 2; │ │ │ │ +OpenLayers.Handler.MOD_ALT = 4; │ │ │ │ +OpenLayers.Handler.MOD_META = 8; │ │ │ │ +OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + 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" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + feature: null, │ │ │ │ + lastFeature: null, │ │ │ │ + down: null, │ │ │ │ + up: null, │ │ │ │ + clickTolerance: 4, │ │ │ │ + geometryTypes: null, │ │ │ │ + stopClick: true, │ │ │ │ + stopDown: true, │ │ │ │ + stopUp: false, │ │ │ │ + initialize: function(control, layer, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ + this.layer = layer │ │ │ │ + }, │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + return OpenLayers.Event.isMultiTouch(evt) ? true : this.mousedown(evt) │ │ │ │ + }, │ │ │ │ + touchmove: function(evt) { │ │ │ │ + OpenLayers.Event.preventDefault(evt) │ │ │ │ + }, │ │ │ │ + mousedown: function(evt) { │ │ │ │ + if (OpenLayers.Event.isLeftClick(evt) || OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ + this.down = evt.xy │ │ │ │ + } │ │ │ │ + return this.handle(evt) ? !this.stopDown : true │ │ │ │ + }, │ │ │ │ + mouseup: function(evt) { │ │ │ │ + this.up = evt.xy; │ │ │ │ + return this.handle(evt) ? !this.stopUp : true │ │ │ │ + }, │ │ │ │ + click: function(evt) { │ │ │ │ + return this.handle(evt) ? !this.stopClick : true │ │ │ │ + }, │ │ │ │ + mousemove: function(evt) { │ │ │ │ + if (!this.callbacks["over"] && !this.callbacks["out"]) { │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + this.handle(evt); │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + dblclick: function(evt) { │ │ │ │ + return !this.handle(evt) │ │ │ │ + }, │ │ │ │ + geometryTypeMatches: function(feature) { │ │ │ │ + return this.geometryTypes == null || OpenLayers.Util.indexOf(this.geometryTypes, feature.geometry.CLASS_NAME) > -1 │ │ │ │ + }, │ │ │ │ + handle: function(evt) { │ │ │ │ + if (this.feature && !this.feature.layer) { │ │ │ │ + this.feature = null │ │ │ │ + } │ │ │ │ + var type = evt.type; │ │ │ │ + var handled = false; │ │ │ │ + var previouslyIn = !!this.feature; │ │ │ │ + var click = type == "click" || type == "dblclick" || type == "touchstart"; │ │ │ │ + this.feature = this.layer.getFeatureFromEvent(evt); │ │ │ │ + if (this.feature && !this.feature.layer) { │ │ │ │ + this.feature = null │ │ │ │ + } │ │ │ │ + if (this.lastFeature && !this.lastFeature.layer) { │ │ │ │ + this.lastFeature = null │ │ │ │ + } │ │ │ │ + if (this.feature) { │ │ │ │ + if (type === "touchstart") { │ │ │ │ + OpenLayers.Event.preventDefault(evt) │ │ │ │ + } │ │ │ │ + var inNew = this.feature != this.lastFeature; │ │ │ │ + if (this.geometryTypeMatches(this.feature)) { │ │ │ │ + if (previouslyIn && inNew) { │ │ │ │ + if (this.lastFeature) { │ │ │ │ + this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ + } │ │ │ │ + this.triggerCallback(type, "in", [this.feature]) │ │ │ │ + } else if (!previouslyIn || click) { │ │ │ │ + this.triggerCallback(type, "in", [this.feature]) │ │ │ │ + } │ │ │ │ + this.lastFeature = this.feature; │ │ │ │ + handled = true │ │ │ │ + } else { │ │ │ │ + if (this.lastFeature && (previouslyIn && inNew || click)) { │ │ │ │ + this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ + } │ │ │ │ + this.feature = null │ │ │ │ + } │ │ │ │ + } else if (this.lastFeature && (previouslyIn || click)) { │ │ │ │ + this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ + } │ │ │ │ + return handled │ │ │ │ + }, │ │ │ │ + triggerCallback: function(type, mode, args) { │ │ │ │ + var key = this.EVENTMAP[type][mode]; │ │ │ │ + if (key) { │ │ │ │ + if (type == "click" && this.up && this.down) { │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + this.up = this.down = null │ │ │ │ + } else { │ │ │ │ + this.callback(key, args) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleMapEvents: function(evt) { │ │ │ │ + if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ + this.moveLayerToTop() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + moveLayerToTop: function() { │ │ │ │ + var index = Math.max(this.map.Z_INDEX_BASE["Feature"] - 1, this.layer.getZIndex()) + 1; │ │ │ │ + this.layer.setZIndex(index) │ │ │ │ + }, │ │ │ │ + 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.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ + displayInLayerSwitcher: false, │ │ │ │ + layers: null, │ │ │ │ + display: function() {}, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ + this.collectRoots(); │ │ │ │ + map.events.register("changelayer", this, this.handleChangeLayer) │ │ │ │ + }, │ │ │ │ + removeMap: function(map) { │ │ │ │ + map.events.unregister("changelayer", this, this.handleChangeLayer); │ │ │ │ + this.resetRoots(); │ │ │ │ + OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + collectRoots: function() { │ │ │ │ + var layer; │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + multipleKey: null, │ │ │ │ + toggleKey: null, │ │ │ │ + multiple: false, │ │ │ │ + clickout: true, │ │ │ │ + toggle: false, │ │ │ │ + hover: false, │ │ │ │ + highlightOnly: false, │ │ │ │ + box: false, │ │ │ │ + onBeforeSelect: function() {}, │ │ │ │ + onSelect: function() {}, │ │ │ │ + onUnselect: function() {}, │ │ │ │ + scope: null, │ │ │ │ + geometryTypes: null, │ │ │ │ + layer: null, │ │ │ │ + layers: null, │ │ │ │ + callbacks: null, │ │ │ │ + selectStyle: null, │ │ │ │ + renderIntent: "select", │ │ │ │ + handlers: null, │ │ │ │ + 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" │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + unselectAll: function(options) { │ │ │ │ + var layers = this.layers || [this.layer], │ │ │ │ + layer, feature, l, numExcept; │ │ │ │ + for (l = 0; l < layers.length; ++l) { │ │ │ │ + layer = layers[l]; │ │ │ │ + numExcept = 0; │ │ │ │ + if (layer.selectedFeatures != null) { │ │ │ │ + while (layer.selectedFeatures.length > numExcept) { │ │ │ │ + feature = layer.selectedFeatures[numExcept]; │ │ │ │ + if (!options || options.except != feature) { │ │ │ │ + this.unselect(feature) │ │ │ │ + } else { │ │ │ │ + ++numExcept │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + multipleSelect: function() { │ │ │ │ + return this.multiple || this.handlers.feature.evt && this.handlers.feature.evt[this.multipleKey] │ │ │ │ + }, │ │ │ │ + toggleSelect: function() { │ │ │ │ + return this.toggle || this.handlers.feature.evt && this.handlers.feature.evt[this.toggleKey] │ │ │ │ + }, │ │ │ │ + clickoutFeature: function(feature) { │ │ │ │ + if (!this.hover && this.clickout) { │ │ │ │ + this.unselectAll() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + outFeature: function(feature) { │ │ │ │ + if (this.hover) { │ │ │ │ + if (this.highlightOnly) { │ │ │ │ + if (feature._lastHighlighter == this.id) { │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + unhighlight: function(feature) { │ │ │ │ + var layer = feature.layer; │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + 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 (!this.handlers.feature.lastFeature) { │ │ │ │ + this.handlers.feature.lastFeature = layer.selectedFeatures[0] │ │ │ │ + } │ │ │ │ + layer.events.triggerEvent("featureselected", { │ │ │ │ + feature: feature │ │ │ │ + }); │ │ │ │ + this.onSelect.call(this.scope, feature) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + unselect: function(feature) { │ │ │ │ + var layer = feature.layer; │ │ │ │ + this.unhighlight(feature); │ │ │ │ + OpenLayers.Util.removeItem(layer.selectedFeatures, feature); │ │ │ │ + layer.events.triggerEvent("featureunselected", { │ │ │ │ + feature: feature │ │ │ │ + }); │ │ │ │ + this.onUnselect.call(this.scope, feature) │ │ │ │ + }, │ │ │ │ + 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 (!this.multipleSelect()) { │ │ │ │ + this.unselectAll() │ │ │ │ + } │ │ │ │ + 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]; │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + this.handlers.feature.setMap(map); │ │ │ │ + if (this.box) { │ │ │ │ + this.handlers.box.setMap(map) │ │ │ │ + } │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + 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.Control.Attribution = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + separator: ", ", │ │ │ │ + template: "${layers}", │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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()) { │ │ │ │ + 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.Control.LayerSwitcher = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ layerStates: null, │ │ │ │ layersDiv: null, │ │ │ │ baseLayersDiv: null, │ │ │ │ baseLayers: null, │ │ │ │ dataLbl: null, │ │ │ │ dataLayersDiv: null, │ │ │ │ @@ -8109,151 +11305,14 @@ │ │ │ │ this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MinimizeDiv", null, null, img, "absolute"); │ │ │ │ OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton"); │ │ │ │ this.minimizeDiv.style.display = "none"; │ │ │ │ this.div.appendChild(this.minimizeDiv) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.LayerSwitcher" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.Attribution = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - separator: ", ", │ │ │ │ - template: "${layers}", │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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()) { │ │ │ │ - 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.Handler = OpenLayers.Class({ │ │ │ │ - id: null, │ │ │ │ - control: null, │ │ │ │ - map: null, │ │ │ │ - keyMask: null, │ │ │ │ - active: false, │ │ │ │ - evt: null, │ │ │ │ - touch: false, │ │ │ │ - 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 + "_") │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - this.map = map │ │ │ │ - }, │ │ │ │ - checkModifiers: function(evt) { │ │ │ │ - if (this.keyMask == null) { │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - 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); │ │ │ │ - return keyModifiers == this.keyMask │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (this.active) { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (!this.active) { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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]]) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - callback: function(name, args) { │ │ │ │ - if (name && this.callbacks[name]) { │ │ │ │ - this.callbacks[name].apply(this.control, args) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - register: function(name, method) { │ │ │ │ - this.map.events.registerPriority(name, this, method); │ │ │ │ - this.map.events.registerPriority(name, this, this.setEvent) │ │ │ │ - }, │ │ │ │ - unregister: function(name, method) { │ │ │ │ - this.map.events.unregister(name, this, method); │ │ │ │ - this.map.events.unregister(name, this, this.setEvent) │ │ │ │ - }, │ │ │ │ - setEvent: function(evt) { │ │ │ │ - this.evt = evt; │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - this.control = this.map = null │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.MOD_NONE = 0; │ │ │ │ -OpenLayers.Handler.MOD_SHIFT = 1; │ │ │ │ -OpenLayers.Handler.MOD_CTRL = 2; │ │ │ │ -OpenLayers.Handler.MOD_ALT = 4; │ │ │ │ -OpenLayers.Handler.MOD_META = 8; │ │ │ │ OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ started: false, │ │ │ │ stopDown: true, │ │ │ │ dragging: false, │ │ │ │ last: null, │ │ │ │ start: null, │ │ │ │ lastMoveEvt: null, │ │ │ │ @@ -9131,2255 +12190,14 @@ │ │ │ │ this.zoomWheelEnabled = true; │ │ │ │ if (this.active) { │ │ │ │ this.handlers.wheel.activate() │ │ │ │ } │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.Navigation" │ │ │ │ }); │ │ │ │ -OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - 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" │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - feature: null, │ │ │ │ - lastFeature: null, │ │ │ │ - down: null, │ │ │ │ - up: null, │ │ │ │ - clickTolerance: 4, │ │ │ │ - geometryTypes: null, │ │ │ │ - stopClick: true, │ │ │ │ - stopDown: true, │ │ │ │ - stopUp: false, │ │ │ │ - initialize: function(control, layer, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ - this.layer = layer │ │ │ │ - }, │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - return OpenLayers.Event.isMultiTouch(evt) ? true : this.mousedown(evt) │ │ │ │ - }, │ │ │ │ - touchmove: function(evt) { │ │ │ │ - OpenLayers.Event.preventDefault(evt) │ │ │ │ - }, │ │ │ │ - mousedown: function(evt) { │ │ │ │ - if (OpenLayers.Event.isLeftClick(evt) || OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ - this.down = evt.xy │ │ │ │ - } │ │ │ │ - return this.handle(evt) ? !this.stopDown : true │ │ │ │ - }, │ │ │ │ - mouseup: function(evt) { │ │ │ │ - this.up = evt.xy; │ │ │ │ - return this.handle(evt) ? !this.stopUp : true │ │ │ │ - }, │ │ │ │ - click: function(evt) { │ │ │ │ - return this.handle(evt) ? !this.stopClick : true │ │ │ │ - }, │ │ │ │ - mousemove: function(evt) { │ │ │ │ - if (!this.callbacks["over"] && !this.callbacks["out"]) { │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - this.handle(evt); │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - dblclick: function(evt) { │ │ │ │ - return !this.handle(evt) │ │ │ │ - }, │ │ │ │ - geometryTypeMatches: function(feature) { │ │ │ │ - return this.geometryTypes == null || OpenLayers.Util.indexOf(this.geometryTypes, feature.geometry.CLASS_NAME) > -1 │ │ │ │ - }, │ │ │ │ - handle: function(evt) { │ │ │ │ - if (this.feature && !this.feature.layer) { │ │ │ │ - this.feature = null │ │ │ │ - } │ │ │ │ - var type = evt.type; │ │ │ │ - var handled = false; │ │ │ │ - var previouslyIn = !!this.feature; │ │ │ │ - var click = type == "click" || type == "dblclick" || type == "touchstart"; │ │ │ │ - this.feature = this.layer.getFeatureFromEvent(evt); │ │ │ │ - if (this.feature && !this.feature.layer) { │ │ │ │ - this.feature = null │ │ │ │ - } │ │ │ │ - if (this.lastFeature && !this.lastFeature.layer) { │ │ │ │ - this.lastFeature = null │ │ │ │ - } │ │ │ │ - if (this.feature) { │ │ │ │ - if (type === "touchstart") { │ │ │ │ - OpenLayers.Event.preventDefault(evt) │ │ │ │ - } │ │ │ │ - var inNew = this.feature != this.lastFeature; │ │ │ │ - if (this.geometryTypeMatches(this.feature)) { │ │ │ │ - if (previouslyIn && inNew) { │ │ │ │ - if (this.lastFeature) { │ │ │ │ - this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ - } │ │ │ │ - this.triggerCallback(type, "in", [this.feature]) │ │ │ │ - } else if (!previouslyIn || click) { │ │ │ │ - this.triggerCallback(type, "in", [this.feature]) │ │ │ │ - } │ │ │ │ - this.lastFeature = this.feature; │ │ │ │ - handled = true │ │ │ │ - } else { │ │ │ │ - if (this.lastFeature && (previouslyIn && inNew || click)) { │ │ │ │ - this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ - } │ │ │ │ - this.feature = null │ │ │ │ - } │ │ │ │ - } else if (this.lastFeature && (previouslyIn || click)) { │ │ │ │ - this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ - } │ │ │ │ - return handled │ │ │ │ - }, │ │ │ │ - triggerCallback: function(type, mode, args) { │ │ │ │ - var key = this.EVENTMAP[type][mode]; │ │ │ │ - if (key) { │ │ │ │ - if (type == "click" && this.up && this.down) { │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - this.up = this.down = null │ │ │ │ - } else { │ │ │ │ - this.callback(key, args) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - handleMapEvents: function(evt) { │ │ │ │ - if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ - this.moveLayerToTop() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - moveLayerToTop: function() { │ │ │ │ - var index = Math.max(this.map.Z_INDEX_BASE["Feature"] - 1, this.layer.getZIndex()) + 1; │ │ │ │ - this.layer.setZIndex(index) │ │ │ │ - }, │ │ │ │ - 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.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ - displayInLayerSwitcher: false, │ │ │ │ - layers: null, │ │ │ │ - display: function() {}, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ - this.collectRoots(); │ │ │ │ - map.events.register("changelayer", this, this.handleChangeLayer) │ │ │ │ - }, │ │ │ │ - removeMap: function(map) { │ │ │ │ - map.events.unregister("changelayer", this, this.handleChangeLayer); │ │ │ │ - this.resetRoots(); │ │ │ │ - OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - collectRoots: function() { │ │ │ │ - var layer; │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - multipleKey: null, │ │ │ │ - toggleKey: null, │ │ │ │ - multiple: false, │ │ │ │ - clickout: true, │ │ │ │ - toggle: false, │ │ │ │ - hover: false, │ │ │ │ - highlightOnly: false, │ │ │ │ - box: false, │ │ │ │ - onBeforeSelect: function() {}, │ │ │ │ - onSelect: function() {}, │ │ │ │ - onUnselect: function() {}, │ │ │ │ - scope: null, │ │ │ │ - geometryTypes: null, │ │ │ │ - layer: null, │ │ │ │ - layers: null, │ │ │ │ - callbacks: null, │ │ │ │ - selectStyle: null, │ │ │ │ - renderIntent: "select", │ │ │ │ - handlers: null, │ │ │ │ - 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" │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - unselectAll: function(options) { │ │ │ │ - var layers = this.layers || [this.layer], │ │ │ │ - layer, feature, l, numExcept; │ │ │ │ - for (l = 0; l < layers.length; ++l) { │ │ │ │ - layer = layers[l]; │ │ │ │ - numExcept = 0; │ │ │ │ - if (layer.selectedFeatures != null) { │ │ │ │ - while (layer.selectedFeatures.length > numExcept) { │ │ │ │ - feature = layer.selectedFeatures[numExcept]; │ │ │ │ - if (!options || options.except != feature) { │ │ │ │ - this.unselect(feature) │ │ │ │ - } else { │ │ │ │ - ++numExcept │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - multipleSelect: function() { │ │ │ │ - return this.multiple || this.handlers.feature.evt && this.handlers.feature.evt[this.multipleKey] │ │ │ │ - }, │ │ │ │ - toggleSelect: function() { │ │ │ │ - return this.toggle || this.handlers.feature.evt && this.handlers.feature.evt[this.toggleKey] │ │ │ │ - }, │ │ │ │ - clickoutFeature: function(feature) { │ │ │ │ - if (!this.hover && this.clickout) { │ │ │ │ - this.unselectAll() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - outFeature: function(feature) { │ │ │ │ - if (this.hover) { │ │ │ │ - if (this.highlightOnly) { │ │ │ │ - if (feature._lastHighlighter == this.id) { │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - unhighlight: function(feature) { │ │ │ │ - var layer = feature.layer; │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - 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 (!this.handlers.feature.lastFeature) { │ │ │ │ - this.handlers.feature.lastFeature = layer.selectedFeatures[0] │ │ │ │ - } │ │ │ │ - layer.events.triggerEvent("featureselected", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - this.onSelect.call(this.scope, feature) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - unselect: function(feature) { │ │ │ │ - var layer = feature.layer; │ │ │ │ - this.unhighlight(feature); │ │ │ │ - OpenLayers.Util.removeItem(layer.selectedFeatures, feature); │ │ │ │ - layer.events.triggerEvent("featureunselected", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - this.onUnselect.call(this.scope, feature) │ │ │ │ - }, │ │ │ │ - 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 (!this.multipleSelect()) { │ │ │ │ - this.unselectAll() │ │ │ │ - } │ │ │ │ - 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]; │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - this.handlers.feature.setMap(map); │ │ │ │ - if (this.box) { │ │ │ │ - this.handlers.box.setMap(map) │ │ │ │ - } │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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.Strategy = OpenLayers.Class({ │ │ │ │ - layer: null, │ │ │ │ - options: null, │ │ │ │ - active: null, │ │ │ │ - autoActivate: true, │ │ │ │ - autoDestroy: true, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - this.options = options; │ │ │ │ - this.active = false │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - this.layer = null; │ │ │ │ - this.options = null │ │ │ │ - }, │ │ │ │ - setLayer: function(layer) { │ │ │ │ - this.layer = layer │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (!this.active) { │ │ │ │ - this.active = true; │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (this.active) { │ │ │ │ - this.active = false; │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ -}); │ │ │ │ -OpenLayers.Filter = OpenLayers.Class({ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options) │ │ │ │ - }, │ │ │ │ - destroy: function() {}, │ │ │ │ - evaluate: function(context) { │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - clone: function() { │ │ │ │ - return null │ │ │ │ - }, │ │ │ │ - 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.Spatial = OpenLayers.Class(OpenLayers.Filter, { │ │ │ │ - type: null, │ │ │ │ - property: null, │ │ │ │ - value: null, │ │ │ │ - distance: null, │ │ │ │ - distanceUnits: null, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - bounds: null, │ │ │ │ - resolution: null, │ │ │ │ - ratio: 2, │ │ │ │ - resFactor: null, │ │ │ │ - response: null, │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - moveend: this.update, │ │ │ │ - refresh: this.update, │ │ │ │ - visibilitychanged: this.update, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.update() │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.layer.events.un({ │ │ │ │ - moveend: this.update, │ │ │ │ - refresh: this.update, │ │ │ │ - visibilitychanged: this.update, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - update: function(options) { │ │ │ │ - var mapBounds = this.getMapBounds(); │ │ │ │ - if (mapBounds !== null && (options && options.force || this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds))) { │ │ │ │ - this.calculateBounds(mapBounds); │ │ │ │ - this.resolution = this.layer.map.getResolution(); │ │ │ │ - this.triggerRead(options) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getMapBounds: function() { │ │ │ │ - if (this.layer.map === null) { │ │ │ │ - return null │ │ │ │ - } │ │ │ │ - var bounds = this.layer.map.getExtent(); │ │ │ │ - if (bounds && !this.layer.projection.equals(this.layer.map.getProjectionObject())) { │ │ │ │ - bounds = bounds.clone().transform(this.layer.map.getProjectionObject(), this.layer.projection) │ │ │ │ - } │ │ │ │ - return bounds │ │ │ │ - }, │ │ │ │ - invalidBounds: function(mapBounds) { │ │ │ │ - if (!mapBounds) { │ │ │ │ - mapBounds = this.getMapBounds() │ │ │ │ - } │ │ │ │ - var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds); │ │ │ │ - if (!invalid && this.resFactor) { │ │ │ │ - var ratio = this.resolution / this.layer.map.getResolution(); │ │ │ │ - invalid = ratio >= this.resFactor || ratio <= 1 / this.resFactor │ │ │ │ - } │ │ │ │ - return invalid │ │ │ │ - }, │ │ │ │ - calculateBounds: function(mapBounds) { │ │ │ │ - if (!mapBounds) { │ │ │ │ - mapBounds = this.getMapBounds() │ │ │ │ - } │ │ │ │ - var center = mapBounds.getCenterLonLat(); │ │ │ │ - var dataWidth = mapBounds.getWidth() * this.ratio; │ │ │ │ - var dataHeight = mapBounds.getHeight() * this.ratio; │ │ │ │ - this.bounds = new OpenLayers.Bounds(center.lon - dataWidth / 2, center.lat - dataHeight / 2, center.lon + dataWidth / 2, center.lat + dataHeight / 2) │ │ │ │ - }, │ │ │ │ - triggerRead: function(options) { │ │ │ │ - if (this.response && !(options && options.noAbort === true)) { │ │ │ │ - this.layer.protocol.abort(this.response); │ │ │ │ - this.layer.events.triggerEvent("loadend") │ │ │ │ - } │ │ │ │ - var evt = { │ │ │ │ - filter: this.createFilter() │ │ │ │ - }; │ │ │ │ - this.layer.events.triggerEvent("loadstart", evt); │ │ │ │ - this.response = this.layer.protocol.read(OpenLayers.Util.applyDefaults({ │ │ │ │ - filter: evt.filter, │ │ │ │ - callback: this.merge, │ │ │ │ - scope: this │ │ │ │ - }, options)) │ │ │ │ - }, │ │ │ │ - createFilter: function() { │ │ │ │ - var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ - value: this.bounds, │ │ │ │ - projection: this.layer.projection │ │ │ │ - }); │ │ │ │ - if (this.layer.filter) { │ │ │ │ - filter = new OpenLayers.Filter.Logical({ │ │ │ │ - type: OpenLayers.Filter.Logical.AND, │ │ │ │ - filters: [this.layer.filter, filter] │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return filter │ │ │ │ - }, │ │ │ │ - merge: function(resp) { │ │ │ │ - this.layer.destroyFeatures(); │ │ │ │ - if (resp.success()) { │ │ │ │ - var features = resp.features; │ │ │ │ - if (features && features.length > 0) { │ │ │ │ - var remote = this.layer.projection; │ │ │ │ - var local = this.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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.layer.addFeatures(features) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.bounds = null │ │ │ │ - } │ │ │ │ - this.response = null; │ │ │ │ - this.layer.events.triggerEvent("loadend", { │ │ │ │ - response: resp │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.BBOX" │ │ │ │ -}); │ │ │ │ -OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - preload: false, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - 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.ElementsIndexer = OpenLayers.Class({ │ │ │ │ - maxZIndex: null, │ │ │ │ - order: null, │ │ │ │ - indices: null, │ │ │ │ - compare: null, │ │ │ │ - initialize: function(yOrdering) { │ │ │ │ - this.compare = yOrdering ? OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER : OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER; │ │ │ │ - this.clear() │ │ │ │ - }, │ │ │ │ - insert: function(newNode) { │ │ │ │ - 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); │ │ │ │ - return this.getNextElement(rightIndex) │ │ │ │ - }, │ │ │ │ - remove: function(node) { │ │ │ │ - var nodeId = node.id; │ │ │ │ - var arrayIndex = OpenLayers.Util.indexOf(this.order, nodeId); │ │ │ │ - if (arrayIndex >= 0) { │ │ │ │ - this.order.splice(arrayIndex, 1); │ │ │ │ - delete this.indices[nodeId]; │ │ │ │ - if (this.order.length > 0) { │ │ │ │ - var lastId = this.order[this.order.length - 1]; │ │ │ │ - this.maxZIndex = this.indices[lastId] │ │ │ │ - } else { │ │ │ │ - this.maxZIndex = 0 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clear: function() { │ │ │ │ - this.order = []; │ │ │ │ - this.indices = {}; │ │ │ │ - this.maxZIndex = 0 │ │ │ │ - }, │ │ │ │ - exists: function(node) { │ │ │ │ - return this.indices[node.id] != null │ │ │ │ - }, │ │ │ │ - getZIndex: function(node) { │ │ │ │ - return node._style.graphicZIndex │ │ │ │ - }, │ │ │ │ - determineZIndex: function(node) { │ │ │ │ - var zIndex = node._style.graphicZIndex; │ │ │ │ - if (zIndex == null) { │ │ │ │ - zIndex = this.maxZIndex; │ │ │ │ - node._style.graphicZIndex = zIndex │ │ │ │ - } else if (zIndex > this.maxZIndex) { │ │ │ │ - this.maxZIndex = zIndex │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -OpenLayers.ElementsIndexer.IndexingMethods = { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - Z_ORDER_DRAWING_ORDER: function(indexer, newNode, nextNode) { │ │ │ │ - var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(indexer, newNode, nextNode); │ │ │ │ - if (nextNode && returnVal == 0) { │ │ │ │ - returnVal = 1 │ │ │ │ - } │ │ │ │ - return returnVal │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ - rendererRoot: null, │ │ │ │ - root: null, │ │ │ │ - vectorRoot: null, │ │ │ │ - textRoot: null, │ │ │ │ - xmlns: null, │ │ │ │ - xOffset: 0, │ │ │ │ - indexer: null, │ │ │ │ - BACKGROUND_ID_SUFFIX: "_background", │ │ │ │ - LABEL_ID_SUFFIX: "_label", │ │ │ │ - LABEL_OUTLINE_SUFFIX: "_outline", │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.clear(); │ │ │ │ - this.rendererRoot = null; │ │ │ │ - this.root = null; │ │ │ │ - this.xmlns = null; │ │ │ │ - OpenLayers.Renderer.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - getNodeType: function(geometry, style) {}, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - redrawNode: function(id, geometry, style, featureId) { │ │ │ │ - style = this.applyDefaultSymbolizer(style); │ │ │ │ - var node = this.nodeFactory(id, this.getNodeType(geometry, style)); │ │ │ │ - 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; │ │ │ │ - if (this.indexer) { │ │ │ │ - var insert = this.indexer.insert(node); │ │ │ │ - if (insert) { │ │ │ │ - this.vectorRoot.insertBefore(node, insert) │ │ │ │ - } else { │ │ │ │ - this.vectorRoot.appendChild(node) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (node.parentNode !== this.vectorRoot) { │ │ │ │ - this.vectorRoot.appendChild(node) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.postDraw(node); │ │ │ │ - return drawResult.complete │ │ │ │ - }, │ │ │ │ - redrawBackgroundNode: function(id, geometry, style, featureId) { │ │ │ │ - var backgroundStyle = OpenLayers.Util.extend({}, style); │ │ │ │ - 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; │ │ │ │ - backgroundStyle.backgroundGraphic = null; │ │ │ │ - backgroundStyle.backgroundXOffset = null; │ │ │ │ - backgroundStyle.backgroundYOffset = null; │ │ │ │ - backgroundStyle.backgroundGraphicZIndex = null; │ │ │ │ - return this.redrawNode(id + this.BACKGROUND_ID_SUFFIX, geometry, backgroundStyle, null) │ │ │ │ - }, │ │ │ │ - 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; │ │ │ │ - if (drawn != false) { │ │ │ │ - return { │ │ │ │ - node: this.setStyle(node, style, options, geometry), │ │ │ │ - complete: drawn │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - postDraw: function(node) {}, │ │ │ │ - drawPoint: function(node, geometry) {}, │ │ │ │ - drawLineString: function(node, geometry) {}, │ │ │ │ - drawLinearRing: function(node, geometry) {}, │ │ │ │ - drawPolygon: function(node, geometry) {}, │ │ │ │ - drawRectangle: function(node, geometry) {}, │ │ │ │ - drawCircle: function(node, geometry) {}, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getFeatureIdFromEvent: function(evt) { │ │ │ │ - var target = evt.target; │ │ │ │ - var useElement = target && target.correspondingUseElement; │ │ │ │ - var node = useElement ? useElement : target || evt.srcElement; │ │ │ │ - return node._featureId │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - bElem.parentNode.removeChild(bElem) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - nodeTypeCompare: function(node, type) {}, │ │ │ │ - createNode: function(type, id) {}, │ │ │ │ - moveRoot: function(renderer) { │ │ │ │ - var root = this.root; │ │ │ │ - if (renderer.root.parentNode == this.rendererRoot) { │ │ │ │ - root = renderer.root │ │ │ │ - } │ │ │ │ - root.parentNode.removeChild(root); │ │ │ │ - renderer.rendererRoot.appendChild(root) │ │ │ │ - }, │ │ │ │ - getRenderLayerId: function() { │ │ │ │ - return this.root.parentNode.parentNode.id │ │ │ │ - }, │ │ │ │ - isComplexSymbol: function(graphicName) { │ │ │ │ - return graphicName != "circle" && !!graphicName │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.Elements" │ │ │ │ -}); │ │ │ │ -OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ - xmlns: "http://www.w3.org/2000/svg", │ │ │ │ - xlinkns: "http://www.w3.org/1999/xlink", │ │ │ │ - MAX_PIXEL: 15e3, │ │ │ │ - translationParameters: null, │ │ │ │ - symbolMetrics: null, │ │ │ │ - initialize: function(containerID) { │ │ │ │ - if (!this.supported()) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - OpenLayers.Renderer.Elements.prototype.initialize.apply(this, arguments); │ │ │ │ - this.translationParameters = { │ │ │ │ - x: 0, │ │ │ │ - y: 0 │ │ │ │ - }; │ │ │ │ - this.symbolMetrics = {} │ │ │ │ - }, │ │ │ │ - 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")) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 (resolutionChanged) { │ │ │ │ - this.left = left; │ │ │ │ - this.top = top; │ │ │ │ - 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) { │ │ │ │ - this.setExtent(extent, true) │ │ │ │ - } │ │ │ │ - return coordSysUnchanged && inRange │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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); │ │ │ │ - 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 : -(.5 * width); │ │ │ │ - var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.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)) { │ │ │ │ - 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; │ │ │ │ - var parent = node.parentNode; │ │ │ │ - var nextSibling = node.nextSibling; │ │ │ │ - if (parent) { │ │ │ │ - parent.removeChild(node) │ │ │ │ - } │ │ │ │ - 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); │ │ │ │ - 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"); │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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, ",") │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - createNode: function(type, id) { │ │ │ │ - var node = document.createElementNS(this.xmlns, type); │ │ │ │ - if (id) { │ │ │ │ - node.setAttributeNS(null, "id", id) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - nodeTypeCompare: function(node, type) { │ │ │ │ - return type == node.nodeName │ │ │ │ - }, │ │ │ │ - createRenderRoot: function() { │ │ │ │ - var svg = this.nodeFactory(this.container.id + "_svgRoot", "svg"); │ │ │ │ - svg.style.display = "block"; │ │ │ │ - return svg │ │ │ │ - }, │ │ │ │ - createRoot: function(suffix) { │ │ │ │ - return this.nodeFactory(this.container.id + suffix, "g") │ │ │ │ - }, │ │ │ │ - createDefs: function() { │ │ │ │ - var defs = this.nodeFactory(this.container.id + "_defs", "defs"); │ │ │ │ - this.rendererRoot.appendChild(defs); │ │ │ │ - return defs │ │ │ │ - }, │ │ │ │ - drawPoint: function(node, geometry) { │ │ │ │ - return this.drawCircle(node, geometry, 1) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawText: function(featureId, style, location) { │ │ │ │ - var drawOutline = !!style.labelOutlineWidth; │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 { │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getPosition: function(node) { │ │ │ │ - return { │ │ │ │ - x: parseFloat(node.getAttributeNS(null, "cx")), │ │ │ │ - y: parseFloat(node.getAttributeNS(null, "cy")) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - importSymbol: function(graphicName) { │ │ │ │ - if (!this.defs) { │ │ │ │ - this.defs = this.createDefs() │ │ │ │ - } │ │ │ │ - var id = this.container.id + "-" + graphicName; │ │ │ │ - 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(); │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -OpenLayers.Renderer.SVG.LABEL_ALIGN = { │ │ │ │ - l: "start", │ │ │ │ - r: "end", │ │ │ │ - b: "bottom", │ │ │ │ - t: "hanging" │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.SVG.LABEL_VSHIFT = { │ │ │ │ - t: "-70%", │ │ │ │ - b: "0" │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.SVG.LABEL_VFACTOR = { │ │ │ │ - t: 0, │ │ │ │ - b: -1 │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.SVG.preventDefault = function(e) { │ │ │ │ - OpenLayers.Event.preventDefault(e) │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ - xmlns: "urn:schemas-microsoft-com:vml", │ │ │ │ - symbolCache: {}, │ │ │ │ - offset: null, │ │ │ │ - initialize: function(containerID) { │ │ │ │ - if (!this.supported()) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - if (!document.namespaces.olv) { │ │ │ │ - document.namespaces.add("olv", this.xmlns); │ │ │ │ - var style = document.createStyleSheet(); │ │ │ │ - var shapes = ["shape", "rect", "oval", "fill", "stroke", "imagedata", "group", "textbox"]; │ │ │ │ - for (var i = 0, len = shapes.length; i < len; i++) { │ │ │ │ - style.addRule("olv\\:" + shapes[i], "behavior: url(#default#VML); " + "position: absolute; display: inline-block;") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - OpenLayers.Renderer.Elements.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - supported: function() { │ │ │ │ - return !!document.namespaces │ │ │ │ - }, │ │ │ │ - setExtent: function(extent, resolutionChanged) { │ │ │ │ - var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments); │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var left = extent.left / resolution | 0; │ │ │ │ - var top = extent.top / resolution - this.size.h | 0; │ │ │ │ - if (resolutionChanged || !this.offset) { │ │ │ │ - this.offset = { │ │ │ │ - x: left, │ │ │ │ - y: top │ │ │ │ - }; │ │ │ │ - left = 0; │ │ │ │ - top = 0 │ │ │ │ - } else { │ │ │ │ - left = left - this.offset.x; │ │ │ │ - top = top - this.offset.y │ │ │ │ - } │ │ │ │ - var org = left - this.xOffset + " " + top; │ │ │ │ - this.root.coordorigin = org; │ │ │ │ - var roots = [this.root, this.vectorRoot, this.textRoot]; │ │ │ │ - var root; │ │ │ │ - for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ - root = roots[i]; │ │ │ │ - var size = this.size.w + " " + this.size.h; │ │ │ │ - root.coordsize = size │ │ │ │ - } │ │ │ │ - this.root.style.flip = "y"; │ │ │ │ - return coordSysUnchanged │ │ │ │ - }, │ │ │ │ - setSize: function(size) { │ │ │ │ - OpenLayers.Renderer.prototype.setSize.apply(this, arguments); │ │ │ │ - var roots = [this.rendererRoot, this.root, this.vectorRoot, this.textRoot]; │ │ │ │ - var w = this.size.w + "px"; │ │ │ │ - var h = this.size.h + "px"; │ │ │ │ - var root; │ │ │ │ - for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ - root = roots[i]; │ │ │ │ - root.style.width = w; │ │ │ │ - root.style.height = h │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getNodeType: function(geometry, style) { │ │ │ │ - var nodeType = null; │ │ │ │ - switch (geometry.CLASS_NAME) { │ │ │ │ - case "OpenLayers.Geometry.Point": │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - nodeType = "olv:rect" │ │ │ │ - } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ - nodeType = "olv:shape" │ │ │ │ - } else { │ │ │ │ - nodeType = "olv:oval" │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "OpenLayers.Geometry.Rectangle": │ │ │ │ - nodeType = "olv:rect"; │ │ │ │ - break; │ │ │ │ - case "OpenLayers.Geometry.LineString": │ │ │ │ - case "OpenLayers.Geometry.LinearRing": │ │ │ │ - case "OpenLayers.Geometry.Polygon": │ │ │ │ - case "OpenLayers.Geometry.Curve": │ │ │ │ - nodeType = "olv:shape"; │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - break │ │ │ │ - } │ │ │ │ - return nodeType │ │ │ │ - }, │ │ │ │ - setStyle: function(node, style, options, geometry) { │ │ │ │ - style = style || node._style; │ │ │ │ - options = options || node._options; │ │ │ │ - var fillColor = style.fillColor; │ │ │ │ - var title = style.title || style.graphicTitle; │ │ │ │ - if (title) { │ │ │ │ - node.title = title │ │ │ │ - } │ │ │ │ - if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - options.isFilled = true; │ │ │ │ - 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 resolution = this.getResolution(); │ │ │ │ - var xOffset = style.graphicXOffset != undefined ? style.graphicXOffset : -(.5 * width); │ │ │ │ - var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.5 * height); │ │ │ │ - node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x + xOffset | 0) + "px"; │ │ │ │ - node.style.top = (geometry.y / resolution - this.offset.y - (yOffset + height) | 0) + "px"; │ │ │ │ - node.style.width = width + "px"; │ │ │ │ - node.style.height = height + "px"; │ │ │ │ - node.style.flip = "y"; │ │ │ │ - fillColor = "none"; │ │ │ │ - options.isStroked = false │ │ │ │ - } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ - var cache = this.importSymbol(style.graphicName); │ │ │ │ - node.path = cache.path; │ │ │ │ - node.coordorigin = cache.left + "," + cache.bottom; │ │ │ │ - var size = cache.size; │ │ │ │ - node.coordsize = size + "," + size; │ │ │ │ - this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ - node.style.flip = "y" │ │ │ │ - } else { │ │ │ │ - this.drawCircle(node, geometry, style.pointRadius) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (options.isFilled) { │ │ │ │ - node.fillcolor = fillColor │ │ │ │ - } else { │ │ │ │ - node.filled = "false" │ │ │ │ - } │ │ │ │ - var fills = node.getElementsByTagName("fill"); │ │ │ │ - var fill = fills.length == 0 ? null : fills[0]; │ │ │ │ - if (!options.isFilled) { │ │ │ │ - if (fill) { │ │ │ │ - node.removeChild(fill) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (!fill) { │ │ │ │ - fill = this.createNode("olv:fill", node.id + "_fill") │ │ │ │ - } │ │ │ │ - fill.opacity = style.fillOpacity; │ │ │ │ - if (node._geometryClass === "OpenLayers.Geometry.Point" && style.externalGraphic) { │ │ │ │ - if (style.graphicOpacity) { │ │ │ │ - fill.opacity = style.graphicOpacity │ │ │ │ - } │ │ │ │ - fill.src = style.externalGraphic; │ │ │ │ - fill.type = "frame"; │ │ │ │ - if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ - fill.aspect = "atmost" │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (fill.parentNode != node) { │ │ │ │ - node.appendChild(fill) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var rotation = style.rotation; │ │ │ │ - if (rotation !== undefined || node._rotation !== undefined) { │ │ │ │ - node._rotation = rotation; │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ - fill.opacity = 0 │ │ │ │ - } else if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ - node.style.rotation = rotation || 0 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var strokes = node.getElementsByTagName("stroke"); │ │ │ │ - var stroke = strokes.length == 0 ? null : strokes[0]; │ │ │ │ - if (!options.isStroked) { │ │ │ │ - node.stroked = false; │ │ │ │ - if (stroke) { │ │ │ │ - stroke.on = false │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (!stroke) { │ │ │ │ - stroke = this.createNode("olv:stroke", node.id + "_stroke"); │ │ │ │ - node.appendChild(stroke) │ │ │ │ - } │ │ │ │ - stroke.on = true; │ │ │ │ - stroke.color = style.strokeColor; │ │ │ │ - stroke.weight = style.strokeWidth + "px"; │ │ │ │ - stroke.opacity = style.strokeOpacity; │ │ │ │ - stroke.endcap = style.strokeLinecap == "butt" ? "flat" : style.strokeLinecap || "round"; │ │ │ │ - if (style.strokeDashstyle) { │ │ │ │ - stroke.dashstyle = this.dashStyle(style) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ - node.style.cursor = style.cursor │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - graphicRotate: function(node, xOffset, yOffset, style) { │ │ │ │ - var style = style || node._style; │ │ │ │ - var rotation = style.rotation || 0; │ │ │ │ - var aspectRatio, size; │ │ │ │ - if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ - var img = new Image; │ │ │ │ - img.onreadystatechange = OpenLayers.Function.bind(function() { │ │ │ │ - if (img.readyState == "complete" || img.readyState == "interactive") { │ │ │ │ - aspectRatio = img.width / img.height; │ │ │ │ - size = Math.max(style.pointRadius * 2, style.graphicWidth || 0, style.graphicHeight || 0); │ │ │ │ - xOffset = xOffset * aspectRatio; │ │ │ │ - style.graphicWidth = size * aspectRatio; │ │ │ │ - style.graphicHeight = size; │ │ │ │ - this.graphicRotate(node, xOffset, yOffset, style) │ │ │ │ - } │ │ │ │ - }, this); │ │ │ │ - img.src = style.externalGraphic; │ │ │ │ - return │ │ │ │ - } else { │ │ │ │ - size = Math.max(style.graphicWidth, style.graphicHeight); │ │ │ │ - aspectRatio = style.graphicWidth / style.graphicHeight │ │ │ │ - } │ │ │ │ - var width = Math.round(style.graphicWidth || size * aspectRatio); │ │ │ │ - var height = Math.round(style.graphicHeight || size); │ │ │ │ - node.style.width = width + "px"; │ │ │ │ - node.style.height = height + "px"; │ │ │ │ - var image = document.getElementById(node.id + "_image"); │ │ │ │ - if (!image) { │ │ │ │ - image = this.createNode("olv:imagedata", node.id + "_image"); │ │ │ │ - node.appendChild(image) │ │ │ │ - } │ │ │ │ - image.style.width = width + "px"; │ │ │ │ - image.style.height = height + "px"; │ │ │ │ - image.src = style.externalGraphic; │ │ │ │ - image.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + "src='', sizingMethod='scale')"; │ │ │ │ - var rot = rotation * Math.PI / 180; │ │ │ │ - var sintheta = Math.sin(rot); │ │ │ │ - var costheta = Math.cos(rot); │ │ │ │ - var filter = "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta + ",M12=" + -sintheta + ",M21=" + sintheta + ",M22=" + costheta + ",SizingMethod='auto expand')\n"; │ │ │ │ - var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ - if (opacity && opacity != 1) { │ │ │ │ - filter += "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + opacity + ")\n" │ │ │ │ - } │ │ │ │ - node.style.filter = filter; │ │ │ │ - var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset); │ │ │ │ - var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry(); │ │ │ │ - imgBox.rotate(style.rotation, centerPoint); │ │ │ │ - var imgBounds = imgBox.getBounds(); │ │ │ │ - node.style.left = Math.round(parseInt(node.style.left) + imgBounds.left) + "px"; │ │ │ │ - node.style.top = Math.round(parseInt(node.style.top) - imgBounds.bottom) + "px" │ │ │ │ - }, │ │ │ │ - postDraw: function(node) { │ │ │ │ - node.style.visibility = "visible"; │ │ │ │ - var fillColor = node._style.fillColor; │ │ │ │ - var strokeColor = node._style.strokeColor; │ │ │ │ - if (fillColor == "none" && node.fillcolor != fillColor) { │ │ │ │ - node.fillcolor = fillColor │ │ │ │ - } │ │ │ │ - if (strokeColor == "none" && node.strokecolor != strokeColor) { │ │ │ │ - node.strokecolor = strokeColor │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setNodeDimension: function(node, geometry) { │ │ │ │ - var bbox = geometry.getBounds(); │ │ │ │ - if (bbox) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var scaledBox = new OpenLayers.Bounds((bbox.left - this.featureDx) / resolution - this.offset.x | 0, bbox.bottom / resolution - this.offset.y | 0, (bbox.right - this.featureDx) / resolution - this.offset.x | 0, bbox.top / resolution - this.offset.y | 0); │ │ │ │ - node.style.left = scaledBox.left + "px"; │ │ │ │ - node.style.top = scaledBox.top + "px"; │ │ │ │ - node.style.width = scaledBox.getWidth() + "px"; │ │ │ │ - node.style.height = scaledBox.getHeight() + "px"; │ │ │ │ - node.coordorigin = scaledBox.left + " " + scaledBox.top; │ │ │ │ - node.coordsize = scaledBox.getWidth() + " " + scaledBox.getHeight() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - dashStyle: function(style) { │ │ │ │ - var dash = style.strokeDashstyle; │ │ │ │ - switch (dash) { │ │ │ │ - case "solid": │ │ │ │ - case "dot": │ │ │ │ - case "dash": │ │ │ │ - case "dashdot": │ │ │ │ - case "longdash": │ │ │ │ - case "longdashdot": │ │ │ │ - return dash; │ │ │ │ - default: │ │ │ │ - var parts = dash.split(/[ ,]/); │ │ │ │ - if (parts.length == 2) { │ │ │ │ - if (1 * parts[0] >= 2 * parts[1]) { │ │ │ │ - return "longdash" │ │ │ │ - } │ │ │ │ - return parts[0] == 1 || parts[1] == 1 ? "dot" : "dash" │ │ │ │ - } else if (parts.length == 4) { │ │ │ │ - return 1 * parts[0] >= 2 * parts[1] ? "longdashdot" : "dashdot" │ │ │ │ - } │ │ │ │ - return "solid" │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - createNode: function(type, id) { │ │ │ │ - var node = document.createElement(type); │ │ │ │ - if (id) { │ │ │ │ - node.id = id │ │ │ │ - } │ │ │ │ - node.unselectable = "on"; │ │ │ │ - node.onselectstart = OpenLayers.Function.False; │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - nodeTypeCompare: function(node, type) { │ │ │ │ - var subType = type; │ │ │ │ - var splitIndex = subType.indexOf(":"); │ │ │ │ - if (splitIndex != -1) { │ │ │ │ - subType = subType.substr(splitIndex + 1) │ │ │ │ - } │ │ │ │ - var nodeName = node.nodeName; │ │ │ │ - splitIndex = nodeName.indexOf(":"); │ │ │ │ - if (splitIndex != -1) { │ │ │ │ - nodeName = nodeName.substr(splitIndex + 1) │ │ │ │ - } │ │ │ │ - return subType == nodeName │ │ │ │ - }, │ │ │ │ - createRenderRoot: function() { │ │ │ │ - return this.nodeFactory(this.container.id + "_vmlRoot", "div") │ │ │ │ - }, │ │ │ │ - createRoot: function(suffix) { │ │ │ │ - return this.nodeFactory(this.container.id + suffix, "olv:group") │ │ │ │ - }, │ │ │ │ - drawPoint: function(node, geometry) { │ │ │ │ - return this.drawCircle(node, geometry, 1) │ │ │ │ - }, │ │ │ │ - drawCircle: function(node, geometry, radius) { │ │ │ │ - if (!isNaN(geometry.x) && !isNaN(geometry.y)) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x | 0) - radius + "px"; │ │ │ │ - node.style.top = (geometry.y / resolution - this.offset.y | 0) - radius + "px"; │ │ │ │ - var diameter = radius * 2; │ │ │ │ - node.style.width = diameter + "px"; │ │ │ │ - node.style.height = diameter + "px"; │ │ │ │ - return node │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - drawLineString: function(node, geometry) { │ │ │ │ - return this.drawLine(node, geometry, false) │ │ │ │ - }, │ │ │ │ - drawLinearRing: function(node, geometry) { │ │ │ │ - return this.drawLine(node, geometry, true) │ │ │ │ - }, │ │ │ │ - drawLine: function(node, geometry, closeLine) { │ │ │ │ - this.setNodeDimension(node, geometry); │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var numComponents = geometry.components.length; │ │ │ │ - var parts = new Array(numComponents); │ │ │ │ - var comp, x, y; │ │ │ │ - for (var i = 0; i < numComponents; i++) { │ │ │ │ - comp = geometry.components[i]; │ │ │ │ - x = (comp.x - this.featureDx) / resolution - this.offset.x | 0; │ │ │ │ - y = comp.y / resolution - this.offset.y | 0; │ │ │ │ - parts[i] = " " + x + "," + y + " l " │ │ │ │ - } │ │ │ │ - var end = closeLine ? " x e" : " e"; │ │ │ │ - node.path = "m" + parts.join("") + end; │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - drawPolygon: function(node, geometry) { │ │ │ │ - this.setNodeDimension(node, geometry); │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var path = []; │ │ │ │ - var j, jj, points, area, first, second, i, ii, comp, pathComp, x, y; │ │ │ │ - for (j = 0, jj = geometry.components.length; j < jj; j++) { │ │ │ │ - path.push("m"); │ │ │ │ - points = geometry.components[j].components; │ │ │ │ - area = j === 0; │ │ │ │ - first = null; │ │ │ │ - second = null; │ │ │ │ - for (i = 0, ii = points.length; i < ii; i++) { │ │ │ │ - comp = points[i]; │ │ │ │ - x = (comp.x - this.featureDx) / resolution - this.offset.x | 0; │ │ │ │ - y = comp.y / resolution - this.offset.y | 0; │ │ │ │ - pathComp = " " + x + "," + y; │ │ │ │ - path.push(pathComp); │ │ │ │ - if (i == 0) { │ │ │ │ - path.push(" l") │ │ │ │ - } │ │ │ │ - if (!area) { │ │ │ │ - if (!first) { │ │ │ │ - first = pathComp │ │ │ │ - } else if (first != pathComp) { │ │ │ │ - if (!second) { │ │ │ │ - second = pathComp │ │ │ │ - } else if (second != pathComp) { │ │ │ │ - area = true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - path.push(area ? " x " : " ") │ │ │ │ - } │ │ │ │ - path.push("e"); │ │ │ │ - node.path = path.join(""); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - drawRectangle: function(node, geometry) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x | 0) + "px"; │ │ │ │ - node.style.top = (geometry.y / resolution - this.offset.y | 0) + "px"; │ │ │ │ - node.style.width = (geometry.width / resolution | 0) + "px"; │ │ │ │ - node.style.height = (geometry.height / resolution | 0) + "px"; │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - drawText: function(featureId, style, location) { │ │ │ │ - var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect"); │ │ │ │ - var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox"); │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - label.style.left = ((location.x - this.featureDx) / resolution - this.offset.x | 0) + "px"; │ │ │ │ - label.style.top = (location.y / resolution - this.offset.y | 0) + "px"; │ │ │ │ - label.style.flip = "y"; │ │ │ │ - textbox.innerText = style.label; │ │ │ │ - if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ - textbox.style.cursor = style.cursor │ │ │ │ - } │ │ │ │ - if (style.fontColor) { │ │ │ │ - textbox.style.color = style.fontColor │ │ │ │ - } │ │ │ │ - if (style.fontOpacity) { │ │ │ │ - textbox.style.filter = "alpha(opacity=" + style.fontOpacity * 100 + ")" │ │ │ │ - } │ │ │ │ - if (style.fontFamily) { │ │ │ │ - textbox.style.fontFamily = style.fontFamily │ │ │ │ - } │ │ │ │ - if (style.fontSize) { │ │ │ │ - textbox.style.fontSize = style.fontSize │ │ │ │ - } │ │ │ │ - if (style.fontWeight) { │ │ │ │ - textbox.style.fontWeight = style.fontWeight │ │ │ │ - } │ │ │ │ - if (style.fontStyle) { │ │ │ │ - textbox.style.fontStyle = style.fontStyle │ │ │ │ - } │ │ │ │ - if (style.labelSelect === true) { │ │ │ │ - label._featureId = featureId; │ │ │ │ - textbox._featureId = featureId; │ │ │ │ - textbox._geometry = location; │ │ │ │ - textbox._geometryClass = location.CLASS_NAME │ │ │ │ - } │ │ │ │ - textbox.style.whiteSpace = "nowrap"; │ │ │ │ - textbox.inset = "1px,0px,0px,0px"; │ │ │ │ - if (!label.parentNode) { │ │ │ │ - label.appendChild(textbox); │ │ │ │ - this.textRoot.appendChild(label) │ │ │ │ - } │ │ │ │ - var align = style.labelAlign || "cm"; │ │ │ │ - if (align.length == 1) { │ │ │ │ - align += "m" │ │ │ │ - } │ │ │ │ - var xshift = textbox.clientWidth * OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0, 1)]; │ │ │ │ - var yshift = textbox.clientHeight * OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1, 1)]; │ │ │ │ - label.style.left = parseInt(label.style.left) - xshift - 1 + "px"; │ │ │ │ - label.style.top = parseInt(label.style.top) + yshift + "px" │ │ │ │ - }, │ │ │ │ - moveRoot: function(renderer) { │ │ │ │ - var layer = this.map.getLayer(renderer.container.id); │ │ │ │ - if (layer instanceof OpenLayers.Layer.Vector.RootContainer) { │ │ │ │ - layer = this.map.getLayer(this.container.id) │ │ │ │ - } │ │ │ │ - layer && layer.renderer.clear(); │ │ │ │ - OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments); │ │ │ │ - layer && layer.redraw() │ │ │ │ - }, │ │ │ │ - importSymbol: function(graphicName) { │ │ │ │ - var id = this.container.id + "-" + graphicName; │ │ │ │ - var cache = this.symbolCache[id]; │ │ │ │ - if (cache) { │ │ │ │ - return cache │ │ │ │ - } │ │ │ │ - var symbol = OpenLayers.Renderer.symbol[graphicName]; │ │ │ │ - if (!symbol) { │ │ │ │ - throw new Error(graphicName + " is not a valid symbol name") │ │ │ │ - } │ │ │ │ - var symbolExtent = new OpenLayers.Bounds(Number.MAX_VALUE, Number.MAX_VALUE, 0, 0); │ │ │ │ - var pathitems = ["m"]; │ │ │ │ - for (var i = 0; i < symbol.length; i = i + 2) { │ │ │ │ - var x = symbol[i]; │ │ │ │ - var 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); │ │ │ │ - pathitems.push(x); │ │ │ │ - pathitems.push(y); │ │ │ │ - if (i == 0) { │ │ │ │ - pathitems.push("l") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - pathitems.push("x e"); │ │ │ │ - var path = pathitems.join(" "); │ │ │ │ - var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2; │ │ │ │ - if (diff > 0) { │ │ │ │ - symbolExtent.bottom = symbolExtent.bottom - diff; │ │ │ │ - symbolExtent.top = symbolExtent.top + diff │ │ │ │ - } else { │ │ │ │ - symbolExtent.left = symbolExtent.left + diff; │ │ │ │ - symbolExtent.right = symbolExtent.right - diff │ │ │ │ - } │ │ │ │ - cache = { │ │ │ │ - path: path, │ │ │ │ - size: symbolExtent.getWidth(), │ │ │ │ - left: symbolExtent.left, │ │ │ │ - bottom: symbolExtent.bottom │ │ │ │ - }; │ │ │ │ - this.symbolCache[id] = cache; │ │ │ │ - return cache │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.VML" │ │ │ │ -}); │ │ │ │ -OpenLayers.Renderer.VML.LABEL_SHIFT = { │ │ │ │ - l: 0, │ │ │ │ - c: .5, │ │ │ │ - r: 1, │ │ │ │ - t: 0, │ │ │ │ - m: .5, │ │ │ │ - b: 1 │ │ │ │ -}; │ │ │ │ OpenLayers.Format = OpenLayers.Class({ │ │ │ │ options: null, │ │ │ │ externalProjection: null, │ │ │ │ internalProjection: null, │ │ │ │ data: null, │ │ │ │ keepData: false, │ │ │ │ initialize: function(options) { │ │ │ │ @@ -13335,832 +14153,14 @@ │ │ │ │ array[i] = this.extract.geometry.apply(this, [collection.components[i]]) │ │ │ │ } │ │ │ │ return array │ │ │ │ } │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.GeoJSON" │ │ │ │ }); │ │ │ │ -OpenLayers.Protocol = OpenLayers.Class({ │ │ │ │ - format: null, │ │ │ │ - options: null, │ │ │ │ - autoDestroy: true, │ │ │ │ - defaultFilter: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - this.options = options │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.options = null; │ │ │ │ - this.format = null │ │ │ │ - }, │ │ │ │ - read: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.filter = this.mergeWithDefaultFilter(options.filter) │ │ │ │ - }, │ │ │ │ - create: function() {}, │ │ │ │ - update: function() {}, │ │ │ │ - delete: function() {}, │ │ │ │ - commit: function() {}, │ │ │ │ - abort: function(response) {}, │ │ │ │ - createCallback: function(method, response, options) { │ │ │ │ - return OpenLayers.Function.bind(function() { │ │ │ │ - method.apply(this, [response, options]) │ │ │ │ - }, this) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol" │ │ │ │ -}); │ │ │ │ -OpenLayers.Protocol.Response = OpenLayers.Class({ │ │ │ │ - code: null, │ │ │ │ - requestType: null, │ │ │ │ - last: true, │ │ │ │ - features: null, │ │ │ │ - data: null, │ │ │ │ - reqFeatures: null, │ │ │ │ - priv: null, │ │ │ │ - error: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options) │ │ │ │ - }, │ │ │ │ - success: function() { │ │ │ │ - return this.code > 0 │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.Response" │ │ │ │ -}); │ │ │ │ -OpenLayers.Protocol.Response.SUCCESS = 1; │ │ │ │ -OpenLayers.Protocol.Response.FAILURE = 0; │ │ │ │ -OpenLayers.ProxyHost = ""; │ │ │ │ -if (!OpenLayers.Request) { │ │ │ │ - OpenLayers.Request = {} │ │ │ │ -} │ │ │ │ -OpenLayers.Util.extend(OpenLayers.Request, { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - URL_SPLIT_REGEX: /([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/, │ │ │ │ - events: new OpenLayers.Events(this), │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - issue: function(config) { │ │ │ │ - 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); │ │ │ │ - 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) { │ │ │ │ - config.headers["X-Requested-With"] = "XMLHttpRequest" │ │ │ │ - } │ │ │ │ - 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; │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }; │ │ │ │ - if (config.async === false) { │ │ │ │ - request.send(config.data) │ │ │ │ - } else { │ │ │ │ - window.setTimeout(function() { │ │ │ │ - if (request.readyState !== 0) { │ │ │ │ - request.send(config.data) │ │ │ │ - } │ │ │ │ - }, 0) │ │ │ │ - } │ │ │ │ - return request │ │ │ │ - }, │ │ │ │ - runCallbacks: function(options) { │ │ │ │ - var request = options.request; │ │ │ │ - var config = options.config; │ │ │ │ - var complete = config.scope ? OpenLayers.Function.bind(config.callback, config.scope) : config.callback; │ │ │ │ - var success; │ │ │ │ - if (config.success) { │ │ │ │ - success = config.scope ? OpenLayers.Function.bind(config.success, config.scope) : config.success │ │ │ │ - } │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - GET: function(config) { │ │ │ │ - config = OpenLayers.Util.extend(config, { │ │ │ │ - method: "GET" │ │ │ │ - }); │ │ │ │ - return OpenLayers.Request.issue(config) │ │ │ │ - }, │ │ │ │ - POST: function(config) { │ │ │ │ - config = OpenLayers.Util.extend(config, { │ │ │ │ - method: "POST" │ │ │ │ - }); │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - PUT: function(config) { │ │ │ │ - config = OpenLayers.Util.extend(config, { │ │ │ │ - method: "PUT" │ │ │ │ - }); │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - DELETE: function(config) { │ │ │ │ - config = OpenLayers.Util.extend(config, { │ │ │ │ - method: "DELETE" │ │ │ │ - }); │ │ │ │ - return OpenLayers.Request.issue(config) │ │ │ │ - }, │ │ │ │ - HEAD: function(config) { │ │ │ │ - config = OpenLayers.Util.extend(config, { │ │ │ │ - method: "HEAD" │ │ │ │ - }); │ │ │ │ - return OpenLayers.Request.issue(config) │ │ │ │ - }, │ │ │ │ - OPTIONS: function(config) { │ │ │ │ - config = OpenLayers.Util.extend(config, { │ │ │ │ - method: "OPTIONS" │ │ │ │ - }); │ │ │ │ - return OpenLayers.Request.issue(config) │ │ │ │ - } │ │ │ │ -}); │ │ │ │ -(function() { │ │ │ │ - var oXMLHttpRequest = window.XMLHttpRequest; │ │ │ │ - var bGecko = !!window.controllers, │ │ │ │ - bIE = window.document.all && !window.opera, │ │ │ │ - bIE7 = bIE && window.navigator.userAgent.match(/MSIE 7.0/); │ │ │ │ - │ │ │ │ - function fXMLHttpRequest() { │ │ │ │ - this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP"); │ │ │ │ - this._listeners = [] │ │ │ │ - } │ │ │ │ - │ │ │ │ - function cXMLHttpRequest() { │ │ │ │ - return new fXMLHttpRequest │ │ │ │ - } │ │ │ │ - cXMLHttpRequest.prototype = fXMLHttpRequest.prototype; │ │ │ │ - if (bGecko && oXMLHttpRequest.wrapped) cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped; │ │ │ │ - cXMLHttpRequest.UNSENT = 0; │ │ │ │ - cXMLHttpRequest.OPENED = 1; │ │ │ │ - cXMLHttpRequest.HEADERS_RECEIVED = 2; │ │ │ │ - cXMLHttpRequest.LOADING = 3; │ │ │ │ - cXMLHttpRequest.DONE = 4; │ │ │ │ - cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ - cXMLHttpRequest.prototype.responseText = ""; │ │ │ │ - cXMLHttpRequest.prototype.responseXML = null; │ │ │ │ - cXMLHttpRequest.prototype.status = 0; │ │ │ │ - cXMLHttpRequest.prototype.statusText = ""; │ │ │ │ - cXMLHttpRequest.prototype.priority = "NORMAL"; │ │ │ │ - cXMLHttpRequest.prototype.onreadystatechange = null; │ │ │ │ - cXMLHttpRequest.onreadystatechange = null; │ │ │ │ - cXMLHttpRequest.onopen = null; │ │ │ │ - cXMLHttpRequest.onsend = null; │ │ │ │ - cXMLHttpRequest.onabort = null; │ │ │ │ - cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) { │ │ │ │ - delete this._headers; │ │ │ │ - if (arguments.length < 3) bAsync = true; │ │ │ │ - this._async = bAsync; │ │ │ │ - var oRequest = this, │ │ │ │ - nState = this.readyState, │ │ │ │ - fOnUnload; │ │ │ │ - if (bIE && bAsync) { │ │ │ │ - fOnUnload = function() { │ │ │ │ - if (nState != cXMLHttpRequest.DONE) { │ │ │ │ - fCleanTransport(oRequest); │ │ │ │ - oRequest.abort() │ │ │ │ - } │ │ │ │ - }; │ │ │ │ - window.attachEvent("onunload", fOnUnload) │ │ │ │ - } │ │ │ │ - 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; │ │ │ │ - oRequest.readyState = oRequest._object.readyState; │ │ │ │ - fSynchronizeValues(oRequest); │ │ │ │ - if (oRequest._aborted) { │ │ │ │ - oRequest.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ - return │ │ │ │ - } │ │ │ │ - if (oRequest.readyState == cXMLHttpRequest.DONE) { │ │ │ │ - delete oRequest._data; │ │ │ │ - fCleanTransport(oRequest); │ │ │ │ - if (bIE && bAsync) window.detachEvent("onunload", fOnUnload) │ │ │ │ - } │ │ │ │ - if (nState != oRequest.readyState) fReadyStateChange(oRequest); │ │ │ │ - nState = oRequest.readyState │ │ │ │ - } │ │ │ │ - }; │ │ │ │ - │ │ │ │ - function fXMLHttpRequest_send(oRequest) { │ │ │ │ - oRequest._object.send(oRequest._data); │ │ │ │ - if (bGecko && !oRequest._async) { │ │ │ │ - oRequest.readyState = cXMLHttpRequest.OPENED; │ │ │ │ - fSynchronizeValues(oRequest); │ │ │ │ - while (oRequest.readyState < cXMLHttpRequest.DONE) { │ │ │ │ - oRequest.readyState++; │ │ │ │ - fReadyStateChange(oRequest); │ │ │ │ - if (oRequest._aborted) return │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - cXMLHttpRequest.prototype.send = function(vData) { │ │ │ │ - if (cXMLHttpRequest.onsend) cXMLHttpRequest.onsend.apply(this, arguments); │ │ │ │ - if (!arguments.length) vData = null; │ │ │ │ - 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; │ │ │ │ - fXMLHttpRequest_send(this) │ │ │ │ - }; │ │ │ │ - cXMLHttpRequest.prototype.abort = function() { │ │ │ │ - if (cXMLHttpRequest.onabort) cXMLHttpRequest.onabort.apply(this, arguments); │ │ │ │ - if (this.readyState > cXMLHttpRequest.UNSENT) this._aborted = true; │ │ │ │ - this._object.abort(); │ │ │ │ - fCleanTransport(this); │ │ │ │ - this.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ - delete this._data │ │ │ │ - }; │ │ │ │ - cXMLHttpRequest.prototype.getAllResponseHeaders = function() { │ │ │ │ - return this._object.getAllResponseHeaders() │ │ │ │ - }; │ │ │ │ - cXMLHttpRequest.prototype.getResponseHeader = function(sName) { │ │ │ │ - return this._object.getResponseHeader(sName) │ │ │ │ - }; │ │ │ │ - cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) { │ │ │ │ - if (!this._headers) this._headers = {}; │ │ │ │ - this._headers[sName] = sValue; │ │ │ │ - return this._object.setRequestHeader(sName, sValue) │ │ │ │ - }; │ │ │ │ - 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; │ │ │ │ - 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; │ │ │ │ - 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() {}, │ │ │ │ - preventDefault: function() {}, │ │ │ │ - initEvent: function() {} │ │ │ │ - }; │ │ │ │ - if (oEventPseudo.type == "readystatechange" && this.onreadystatechange)(this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]); │ │ │ │ - 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" + "]" │ │ │ │ - }; │ │ │ │ - │ │ │ │ - function fReadyStateChange(oRequest) { │ │ │ │ - if (cXMLHttpRequest.onreadystatechange) cXMLHttpRequest.onreadystatechange.apply(oRequest); │ │ │ │ - oRequest.dispatchEvent({ │ │ │ │ - type: "readystatechange", │ │ │ │ - bubbles: false, │ │ │ │ - cancelable: false, │ │ │ │ - timeStamp: new Date + 0 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - │ │ │ │ - function fGetDocument(oRequest) { │ │ │ │ - var oDocument = oRequest.responseXML, │ │ │ │ - sResponse = oRequest.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) │ │ │ │ - } │ │ │ │ - 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) { │ │ │ │ - oRequest._object.onreadystatechange = new window.Function │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (!OpenLayers.Request) { │ │ │ │ - OpenLayers.Request = {} │ │ │ │ - } │ │ │ │ - OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest │ │ │ │ -})(); │ │ │ │ -OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - url: null, │ │ │ │ - headers: null, │ │ │ │ - params: null, │ │ │ │ - callback: null, │ │ │ │ - scope: null, │ │ │ │ - readWithPOST: false, │ │ │ │ - updateWithPOST: false, │ │ │ │ - deleteWithPOST: false, │ │ │ │ - wildcarded: false, │ │ │ │ - srsInBBOX: false, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.params = null; │ │ │ │ - this.headers = null; │ │ │ │ - OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - handleRead: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - handleCreate: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - handleUpdate: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - handleDelete: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options) │ │ │ │ - }, │ │ │ │ - handleResponse: function(resp, options) { │ │ │ │ - var request = resp.priv; │ │ │ │ - if (options.callback) { │ │ │ │ - if (request.status >= 200 && request.status < 300) { │ │ │ │ - if (resp.requestType != "delete") { │ │ │ │ - resp.features = this.parseFeatures(request) │ │ │ │ - } │ │ │ │ - resp.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ - } else { │ │ │ │ - resp.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ - } │ │ │ │ - options.callback.call(options.scope, resp) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - commit: function(features, options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ - var resp = [], │ │ │ │ - nResponses = 0; │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var nRequests = (types[OpenLayers.State.INSERT].length > 0 ? 1 : 0) + types[OpenLayers.State.UPDATE].length + types[OpenLayers.State.DELETE].length; │ │ │ │ - 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]) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - abort: function(response) { │ │ │ │ - if (response) { │ │ │ │ - response.priv.abort() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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.Filter.Logical = OpenLayers.Class(OpenLayers.Filter, { │ │ │ │ - filters: null, │ │ │ │ - type: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - this.filters = []; │ │ │ │ - OpenLayers.Filter.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.filters = null; │ │ │ │ - OpenLayers.Filter.prototype.destroy.apply(this) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 = OpenLayers.Class(OpenLayers.Filter, { │ │ │ │ - type: null, │ │ │ │ - property: null, │ │ │ │ - value: null, │ │ │ │ - matchCase: true, │ │ │ │ - lowerBoundary: null, │ │ │ │ - upperBoundary: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Filter.prototype.initialize.apply(this, [options]); │ │ │ │ - if (this.type === OpenLayers.Filter.Comparison.LIKE && options.matchCase === undefined) { │ │ │ │ - this.matchCase = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - value2regex: function(wildCard, singleChar, escapeChar) { │ │ │ │ - if (wildCard == ".") { │ │ │ │ - throw new Error("'.' is an unsupported wildCard character for " + "OpenLayers.Filter.Comparison") │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - regex2value: function() { │ │ │ │ - var value = this.value; │ │ │ │ - value = value.replace(/!/g, "!!"); │ │ │ │ - value = value.replace(/(\\)?\\\./g, function($0, $1) { │ │ │ │ - return $1 ? $0 : "!." │ │ │ │ - }); │ │ │ │ - value = value.replace(/(\\)?\\\*/g, function($0, $1) { │ │ │ │ - return $1 ? $0 : "!*" │ │ │ │ - }); │ │ │ │ - value = value.replace(/\\\\/g, "\\"); │ │ │ │ - value = value.replace(/\.\*/g, "*"); │ │ │ │ - return value │ │ │ │ - }, │ │ │ │ - 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.Popup = OpenLayers.Class({ │ │ │ │ events: null, │ │ │ │ id: "", │ │ │ │ lonlat: null, │ │ │ │ div: null, │ │ │ │ contentSize: null, │ │ │ │ size: null, │ │ ├── ./usr/share/javascript/openlayers/OpenLayers.min.js │ │ │ ├── js-beautify {} │ │ │ │ @@ -17,92 +17,14 @@ │ │ │ │ } │ │ │ │ return function() { │ │ │ │ return l │ │ │ │ } │ │ │ │ }(), │ │ │ │ ImgPath: "" │ │ │ │ }; │ │ │ │ -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 │ │ │ │ -}; │ │ │ │ -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) │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var sourceIsEvt = typeof window.Event == "function" && source instanceof window.Event; │ │ │ │ - if (!sourceIsEvt && source.hasOwnProperty && source.hasOwnProperty("toString")) { │ │ │ │ - destination.toString = source.toString │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return destination │ │ │ │ -}; │ │ │ │ -OpenLayers.Console = { │ │ │ │ - log: function() {}, │ │ │ │ - debug: function() {}, │ │ │ │ - info: function() {}, │ │ │ │ - warn: function() {}, │ │ │ │ - error: function() {}, │ │ │ │ - userError: function(error) { │ │ │ │ - alert(error) │ │ │ │ - }, │ │ │ │ - assert: function() {}, │ │ │ │ - dir: function() {}, │ │ │ │ - dirxml: function() {}, │ │ │ │ - trace: function() {}, │ │ │ │ - group: function() {}, │ │ │ │ - groupEnd: function() {}, │ │ │ │ - time: function() {}, │ │ │ │ - timeEnd: function() {}, │ │ │ │ - profile: function() {}, │ │ │ │ - profileEnd: function() {}, │ │ │ │ - count: function() {}, │ │ │ │ - CLASS_NAME: "OpenLayers.Console" │ │ │ │ -}; │ │ │ │ -(function() { │ │ │ │ - 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.String = { │ │ │ │ startsWith: function(str, sub) { │ │ │ │ return str.indexOf(sub) == 0 │ │ │ │ }, │ │ │ │ contains: function(str, sub) { │ │ │ │ return str.indexOf(sub) != -1 │ │ │ │ }, │ │ │ │ @@ -245,14 +167,276 @@ │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ return selected │ │ │ │ } │ │ │ │ }; │ │ │ │ +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 │ │ │ │ +}; │ │ │ │ +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) │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var sourceIsEvt = typeof window.Event == "function" && source instanceof window.Event; │ │ │ │ + if (!sourceIsEvt && source.hasOwnProperty && source.hasOwnProperty("toString")) { │ │ │ │ + destination.toString = source.toString │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return destination │ │ │ │ +}; │ │ │ │ +OpenLayers.Console = { │ │ │ │ + log: function() {}, │ │ │ │ + debug: function() {}, │ │ │ │ + info: function() {}, │ │ │ │ + warn: function() {}, │ │ │ │ + error: function() {}, │ │ │ │ + userError: function(error) { │ │ │ │ + alert(error) │ │ │ │ + }, │ │ │ │ + assert: function() {}, │ │ │ │ + dir: function() {}, │ │ │ │ + dirxml: function() {}, │ │ │ │ + trace: function() {}, │ │ │ │ + group: function() {}, │ │ │ │ + groupEnd: function() {}, │ │ │ │ + time: function() {}, │ │ │ │ + timeEnd: function() {}, │ │ │ │ + profile: function() {}, │ │ │ │ + profileEnd: function() {}, │ │ │ │ + count: function() {}, │ │ │ │ + CLASS_NAME: "OpenLayers.Console" │ │ │ │ +}; │ │ │ │ +(function() { │ │ │ │ + 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 = { │ │ │ │ + code: null, │ │ │ │ + defaultCode: "en", │ │ │ │ + getCode: function() { │ │ │ │ + if (!OpenLayers.Lang.code) { │ │ │ │ + OpenLayers.Lang.setCode() │ │ │ │ + } │ │ │ │ + return OpenLayers.Lang.code │ │ │ │ + }, │ │ │ │ + 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] │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + translate: function(key, context) { │ │ │ │ + var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()]; │ │ │ │ + var message = dictionary && dictionary[key]; │ │ │ │ + if (!message) { │ │ │ │ + message = key │ │ │ │ + } │ │ │ │ + if (context) { │ │ │ │ + message = OpenLayers.String.format(message, context) │ │ │ │ + } │ │ │ │ + return message │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.i18n = OpenLayers.Lang.translate; │ │ │ │ +OpenLayers.Renderer = OpenLayers.Class({ │ │ │ │ + container: null, │ │ │ │ + root: null, │ │ │ │ + extent: null, │ │ │ │ + locked: false, │ │ │ │ + size: null, │ │ │ │ + resolution: null, │ │ │ │ + map: null, │ │ │ │ + featureDx: 0, │ │ │ │ + initialize: function(containerID, options) { │ │ │ │ + this.container = OpenLayers.Util.getElement(containerID); │ │ │ │ + OpenLayers.Util.extend(this, options) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.container = null; │ │ │ │ + this.extent = null; │ │ │ │ + this.size = null; │ │ │ │ + this.resolution = null; │ │ │ │ + this.map = null │ │ │ │ + }, │ │ │ │ + supported: function() { │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + setSize: function(size) { │ │ │ │ + this.size = size.clone(); │ │ │ │ + this.resolution = null │ │ │ │ + }, │ │ │ │ + getResolution: function() { │ │ │ │ + this.resolution = this.resolution || this.map.getResolution(); │ │ │ │ + return this.resolution │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawGeometry: function(geometry, style, featureId) {}, │ │ │ │ + drawText: function(featureId, style, location) {}, │ │ │ │ + removeText: function(featureId) {}, │ │ │ │ + clear: function() {}, │ │ │ │ + getFeatureIdFromEvent: function(evt) {}, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + eraseGeometry: function(geometry, featureId) {}, │ │ │ │ + moveRoot: function(renderer) {}, │ │ │ │ + getRenderLayerId: function() { │ │ │ │ + return this.container.id │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +OpenLayers.Renderer.defaultSymbolizer = { │ │ │ │ + fillColor: "#000000", │ │ │ │ + strokeColor: "#000000", │ │ │ │ + strokeWidth: 2, │ │ │ │ + fillOpacity: 1, │ │ │ │ + strokeOpacity: 1, │ │ │ │ + pointRadius: 0, │ │ │ │ + labelAlign: "cm" │ │ │ │ +}; │ │ │ │ +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.Bounds = OpenLayers.Class({ │ │ │ │ left: null, │ │ │ │ bottom: null, │ │ │ │ right: null, │ │ │ │ top: null, │ │ │ │ centerLonLat: null, │ │ │ │ initialize: function(left, bottom, right, top) { │ │ │ │ @@ -561,14 +745,79 @@ │ │ │ │ }; │ │ │ │ OpenLayers.Bounds.oppositeQuadrant = function(quadrant) { │ │ │ │ var opp = ""; │ │ │ │ opp += quadrant.charAt(0) == "t" ? "b" : "t"; │ │ │ │ opp += quadrant.charAt(1) == "l" ? "r" : "l"; │ │ │ │ return opp │ │ │ │ }; │ │ │ │ +OpenLayers.Element = { │ │ │ │ + visible: function(element) { │ │ │ │ + return OpenLayers.Util.getElement(element).style.display != "none" │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + remove: function(element) { │ │ │ │ + element = OpenLayers.Util.getElement(element); │ │ │ │ + element.parentNode.removeChild(element) │ │ │ │ + }, │ │ │ │ + getHeight: function(element) { │ │ │ │ + element = OpenLayers.Util.getElement(element); │ │ │ │ + return element.offsetHeight │ │ │ │ + }, │ │ │ │ + hasClass: function(element, name) { │ │ │ │ + var names = element.className; │ │ │ │ + return !!names && new RegExp("(^|\\s)" + name + "(\\s|$)").test(names) │ │ │ │ + }, │ │ │ │ + addClass: function(element, name) { │ │ │ │ + if (!OpenLayers.Element.hasClass(element, name)) { │ │ │ │ + element.className += (element.className ? " " : "") + name │ │ │ │ + } │ │ │ │ + return 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 │ │ │ │ + }, │ │ │ │ + toggleClass: function(element, name) { │ │ │ │ + if (OpenLayers.Element.hasClass(element, name)) { │ │ │ │ + OpenLayers.Element.removeClass(element, name) │ │ │ │ + } else { │ │ │ │ + OpenLayers.Element.addClass(element, name) │ │ │ │ + } │ │ │ │ + return element │ │ │ │ + }, │ │ │ │ + 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.LonLat = OpenLayers.Class({ │ │ │ │ lon: 0, │ │ │ │ lat: 0, │ │ │ │ initialize: function(lon, lat) { │ │ │ │ if (OpenLayers.Util.isArray(lon)) { │ │ │ │ lat = lon[1]; │ │ │ │ lon = lon[0] │ │ │ │ @@ -687,58 +936,14 @@ │ │ │ │ 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.Lang = { │ │ │ │ - code: null, │ │ │ │ - defaultCode: "en", │ │ │ │ - getCode: function() { │ │ │ │ - if (!OpenLayers.Lang.code) { │ │ │ │ - OpenLayers.Lang.setCode() │ │ │ │ - } │ │ │ │ - return OpenLayers.Lang.code │ │ │ │ - }, │ │ │ │ - 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] │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - translate: function(key, context) { │ │ │ │ - var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()]; │ │ │ │ - var message = dictionary && dictionary[key]; │ │ │ │ - if (!message) { │ │ │ │ - message = key │ │ │ │ - } │ │ │ │ - if (context) { │ │ │ │ - message = OpenLayers.String.format(message, context) │ │ │ │ - } │ │ │ │ - return message │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -OpenLayers.i18n = OpenLayers.Lang.translate; │ │ │ │ OpenLayers.Util = OpenLayers.Util || {}; │ │ │ │ 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) │ │ │ │ @@ -1540,537 +1745,14 @@ │ │ │ │ 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.Element = { │ │ │ │ - visible: function(element) { │ │ │ │ - return OpenLayers.Util.getElement(element).style.display != "none" │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - remove: function(element) { │ │ │ │ - element = OpenLayers.Util.getElement(element); │ │ │ │ - element.parentNode.removeChild(element) │ │ │ │ - }, │ │ │ │ - getHeight: function(element) { │ │ │ │ - element = OpenLayers.Util.getElement(element); │ │ │ │ - return element.offsetHeight │ │ │ │ - }, │ │ │ │ - hasClass: function(element, name) { │ │ │ │ - var names = element.className; │ │ │ │ - return !!names && new RegExp("(^|\\s)" + name + "(\\s|$)").test(names) │ │ │ │ - }, │ │ │ │ - addClass: function(element, name) { │ │ │ │ - if (!OpenLayers.Element.hasClass(element, name)) { │ │ │ │ - element.className += (element.className ? " " : "") + name │ │ │ │ - } │ │ │ │ - return 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 │ │ │ │ - }, │ │ │ │ - toggleClass: function(element, name) { │ │ │ │ - if (OpenLayers.Element.hasClass(element, name)) { │ │ │ │ - OpenLayers.Element.removeClass(element, name) │ │ │ │ - } else { │ │ │ │ - OpenLayers.Element.addClass(element, name) │ │ │ │ - } │ │ │ │ - return element │ │ │ │ - }, │ │ │ │ - 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.Console.warn("OpenLayers.Rico is deprecated"); │ │ │ │ -OpenLayers.Rico = OpenLayers.Rico || {}; │ │ │ │ -OpenLayers.Rico.Color = OpenLayers.Class({ │ │ │ │ - initialize: function(red, green, blue) { │ │ │ │ - this.rgb = { │ │ │ │ - r: red, │ │ │ │ - g: green, │ │ │ │ - b: blue │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setRed: function(r) { │ │ │ │ - this.rgb.r = r │ │ │ │ - }, │ │ │ │ - setGreen: function(g) { │ │ │ │ - this.rgb.g = g │ │ │ │ - }, │ │ │ │ - setBlue: function(b) { │ │ │ │ - this.rgb.b = b │ │ │ │ - }, │ │ │ │ - setHue: function(h) { │ │ │ │ - var hsb = this.asHSB(); │ │ │ │ - hsb.h = h; │ │ │ │ - this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b) │ │ │ │ - }, │ │ │ │ - setSaturation: function(s) { │ │ │ │ - var hsb = this.asHSB(); │ │ │ │ - hsb.s = s; │ │ │ │ - this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b) │ │ │ │ - }, │ │ │ │ - setBrightness: function(b) { │ │ │ │ - var hsb = this.asHSB(); │ │ │ │ - hsb.b = b; │ │ │ │ - this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b) │ │ │ │ - }, │ │ │ │ - darken: function(percent) { │ │ │ │ - var hsb = this.asHSB(); │ │ │ │ - this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent, 0)) │ │ │ │ - }, │ │ │ │ - brighten: function(percent) { │ │ │ │ - var hsb = this.asHSB(); │ │ │ │ - this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent, 1)) │ │ │ │ - }, │ │ │ │ - blend: function(other) { │ │ │ │ - this.rgb.r = Math.floor((this.rgb.r + other.rgb.r) / 2); │ │ │ │ - this.rgb.g = Math.floor((this.rgb.g + other.rgb.g) / 2); │ │ │ │ - this.rgb.b = Math.floor((this.rgb.b + other.rgb.b) / 2) │ │ │ │ - }, │ │ │ │ - isBright: function() { │ │ │ │ - var hsb = this.asHSB(); │ │ │ │ - return this.asHSB().b > .5 │ │ │ │ - }, │ │ │ │ - isDark: function() { │ │ │ │ - return !this.isBright() │ │ │ │ - }, │ │ │ │ - asRGB: function() { │ │ │ │ - return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")" │ │ │ │ - }, │ │ │ │ - asHex: function() { │ │ │ │ - return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart() │ │ │ │ - }, │ │ │ │ - asHSB: function() { │ │ │ │ - return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b) │ │ │ │ - }, │ │ │ │ - toString: function() { │ │ │ │ - return this.asHex() │ │ │ │ - } │ │ │ │ -}); │ │ │ │ -OpenLayers.Rico.Color.createFromHex = function(hexCode) { │ │ │ │ - if (hexCode.length == 4) { │ │ │ │ - var shortHexCode = hexCode; │ │ │ │ - var hexCode = "#"; │ │ │ │ - for (var i = 1; i < 4; i++) { │ │ │ │ - hexCode += shortHexCode.charAt(i) + shortHexCode.charAt(i) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (hexCode.indexOf("#") == 0) { │ │ │ │ - hexCode = hexCode.substring(1) │ │ │ │ - } │ │ │ │ - var red = hexCode.substring(0, 2); │ │ │ │ - var green = hexCode.substring(2, 4); │ │ │ │ - var blue = hexCode.substring(4, 6); │ │ │ │ - return new OpenLayers.Rico.Color(parseInt(red, 16), parseInt(green, 16), parseInt(blue, 16)) │ │ │ │ -}; │ │ │ │ -OpenLayers.Rico.Color.createColorFromBackground = function(elem) { │ │ │ │ - var actualColor = OpenLayers.Element.getStyle(OpenLayers.Util.getElement(elem), "backgroundColor"); │ │ │ │ - if (actualColor == "transparent" && elem.parentNode) { │ │ │ │ - return OpenLayers.Rico.Color.createColorFromBackground(elem.parentNode) │ │ │ │ - } │ │ │ │ - if (actualColor == null) { │ │ │ │ - return new OpenLayers.Rico.Color(255, 255, 255) │ │ │ │ - } │ │ │ │ - if (actualColor.indexOf("rgb(") == 0) { │ │ │ │ - var colors = actualColor.substring(4, actualColor.length - 1); │ │ │ │ - var colorArray = colors.split(","); │ │ │ │ - return new OpenLayers.Rico.Color(parseInt(colorArray[0]), parseInt(colorArray[1]), parseInt(colorArray[2])) │ │ │ │ - } else if (actualColor.indexOf("#") == 0) { │ │ │ │ - return OpenLayers.Rico.Color.createFromHex(actualColor) │ │ │ │ - } else { │ │ │ │ - return new OpenLayers.Rico.Color(255, 255, 255) │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -OpenLayers.Rico.Color.HSBtoRGB = function(hue, saturation, brightness) { │ │ │ │ - var red = 0; │ │ │ │ - var green = 0; │ │ │ │ - var blue = 0; │ │ │ │ - if (saturation == 0) { │ │ │ │ - red = parseInt(brightness * 255 + .5); │ │ │ │ - green = red; │ │ │ │ - blue = red │ │ │ │ - } else { │ │ │ │ - var h = (hue - Math.floor(hue)) * 6; │ │ │ │ - var f = h - Math.floor(h); │ │ │ │ - var p = brightness * (1 - saturation); │ │ │ │ - var q = brightness * (1 - saturation * f); │ │ │ │ - var t = brightness * (1 - saturation * (1 - f)); │ │ │ │ - switch (parseInt(h)) { │ │ │ │ - case 0: │ │ │ │ - red = brightness * 255 + .5; │ │ │ │ - green = t * 255 + .5; │ │ │ │ - blue = p * 255 + .5; │ │ │ │ - break; │ │ │ │ - case 1: │ │ │ │ - red = q * 255 + .5; │ │ │ │ - green = brightness * 255 + .5; │ │ │ │ - blue = p * 255 + .5; │ │ │ │ - break; │ │ │ │ - case 2: │ │ │ │ - red = p * 255 + .5; │ │ │ │ - green = brightness * 255 + .5; │ │ │ │ - blue = t * 255 + .5; │ │ │ │ - break; │ │ │ │ - case 3: │ │ │ │ - red = p * 255 + .5; │ │ │ │ - green = q * 255 + .5; │ │ │ │ - blue = brightness * 255 + .5; │ │ │ │ - break; │ │ │ │ - case 4: │ │ │ │ - red = t * 255 + .5; │ │ │ │ - green = p * 255 + .5; │ │ │ │ - blue = brightness * 255 + .5; │ │ │ │ - break; │ │ │ │ - case 5: │ │ │ │ - red = brightness * 255 + .5; │ │ │ │ - green = p * 255 + .5; │ │ │ │ - blue = q * 255 + .5; │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return { │ │ │ │ - r: parseInt(red), │ │ │ │ - g: parseInt(green), │ │ │ │ - b: parseInt(blue) │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -OpenLayers.Rico.Color.RGBtoHSB = function(r, g, b) { │ │ │ │ - var hue; │ │ │ │ - var saturation; │ │ │ │ - var brightness; │ │ │ │ - var cmax = r > g ? r : g; │ │ │ │ - if (b > cmax) { │ │ │ │ - cmax = b │ │ │ │ - } │ │ │ │ - var cmin = r < g ? r : g; │ │ │ │ - if (b < cmin) { │ │ │ │ - cmin = b │ │ │ │ - } │ │ │ │ - brightness = cmax / 255; │ │ │ │ - if (cmax != 0) { │ │ │ │ - saturation = (cmax - cmin) / cmax │ │ │ │ - } else { │ │ │ │ - saturation = 0 │ │ │ │ - } │ │ │ │ - if (saturation == 0) { │ │ │ │ - hue = 0 │ │ │ │ - } else { │ │ │ │ - var redc = (cmax - r) / (cmax - cmin); │ │ │ │ - var greenc = (cmax - g) / (cmax - cmin); │ │ │ │ - var bluec = (cmax - b) / (cmax - cmin); │ │ │ │ - if (r == cmax) { │ │ │ │ - hue = bluec - greenc │ │ │ │ - } else if (g == cmax) { │ │ │ │ - hue = 2 + redc - bluec │ │ │ │ - } else { │ │ │ │ - hue = 4 + greenc - redc │ │ │ │ - } │ │ │ │ - hue = hue / 6; │ │ │ │ - if (hue < 0) { │ │ │ │ - hue = hue + 1 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return { │ │ │ │ - h: hue, │ │ │ │ - s: saturation, │ │ │ │ - b: brightness │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -OpenLayers.Console.warn("OpenLayers.Rico is deprecated"); │ │ │ │ -OpenLayers.Rico = OpenLayers.Rico || {}; │ │ │ │ -OpenLayers.Rico.Corner = { │ │ │ │ - round: function(e, options) { │ │ │ │ - e = OpenLayers.Util.getElement(e); │ │ │ │ - this._setOptions(options); │ │ │ │ - var color = this.options.color; │ │ │ │ - if (this.options.color == "fromElement") { │ │ │ │ - color = this._background(e) │ │ │ │ - } │ │ │ │ - var bgColor = this.options.bgColor; │ │ │ │ - if (this.options.bgColor == "fromParent") { │ │ │ │ - bgColor = this._background(e.offsetParent) │ │ │ │ - } │ │ │ │ - this._roundCornersImpl(e, color, bgColor) │ │ │ │ - }, │ │ │ │ - changeColor: function(theDiv, newColor) { │ │ │ │ - theDiv.style.backgroundColor = newColor; │ │ │ │ - var spanElements = theDiv.parentNode.getElementsByTagName("span"); │ │ │ │ - for (var currIdx = 0; currIdx < spanElements.length; currIdx++) { │ │ │ │ - spanElements[currIdx].style.backgroundColor = newColor │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - changeOpacity: function(theDiv, newOpacity) { │ │ │ │ - var mozillaOpacity = newOpacity; │ │ │ │ - var ieOpacity = "alpha(opacity=" + newOpacity * 100 + ")"; │ │ │ │ - theDiv.style.opacity = mozillaOpacity; │ │ │ │ - theDiv.style.filter = ieOpacity; │ │ │ │ - var spanElements = theDiv.parentNode.getElementsByTagName("span"); │ │ │ │ - for (var currIdx = 0; currIdx < spanElements.length; currIdx++) { │ │ │ │ - spanElements[currIdx].style.opacity = mozillaOpacity; │ │ │ │ - spanElements[currIdx].style.filter = ieOpacity │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - reRound: function(theDiv, options) { │ │ │ │ - var topRico = theDiv.parentNode.childNodes[0]; │ │ │ │ - var bottomRico = theDiv.parentNode.childNodes[2]; │ │ │ │ - theDiv.parentNode.removeChild(topRico); │ │ │ │ - theDiv.parentNode.removeChild(bottomRico); │ │ │ │ - this.round(theDiv.parentNode, options) │ │ │ │ - }, │ │ │ │ - _roundCornersImpl: function(e, color, bgColor) { │ │ │ │ - if (this.options.border) { │ │ │ │ - this._renderBorder(e, bgColor) │ │ │ │ - } │ │ │ │ - if (this._isTopRounded()) { │ │ │ │ - this._roundTopCorners(e, color, bgColor) │ │ │ │ - } │ │ │ │ - if (this._isBottomRounded()) { │ │ │ │ - this._roundBottomCorners(e, color, bgColor) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - _renderBorder: function(el, bgColor) { │ │ │ │ - var borderValue = "1px solid " + this._borderColor(bgColor); │ │ │ │ - var borderL = "border-left: " + borderValue; │ │ │ │ - var borderR = "border-right: " + borderValue; │ │ │ │ - var style = "style='" + borderL + ";" + borderR + "'"; │ │ │ │ - el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>" │ │ │ │ - }, │ │ │ │ - _roundTopCorners: function(el, color, bgColor) { │ │ │ │ - var corner = this._createCorner(bgColor); │ │ │ │ - for (var i = 0; i < this.options.numSlices; i++) { │ │ │ │ - corner.appendChild(this._createCornerSlice(color, bgColor, i, "top")) │ │ │ │ - } │ │ │ │ - el.style.paddingTop = 0; │ │ │ │ - el.insertBefore(corner, el.firstChild) │ │ │ │ - }, │ │ │ │ - _roundBottomCorners: function(el, color, bgColor) { │ │ │ │ - var corner = this._createCorner(bgColor); │ │ │ │ - for (var i = this.options.numSlices - 1; i >= 0; i--) { │ │ │ │ - corner.appendChild(this._createCornerSlice(color, bgColor, i, "bottom")) │ │ │ │ - } │ │ │ │ - el.style.paddingBottom = 0; │ │ │ │ - el.appendChild(corner) │ │ │ │ - }, │ │ │ │ - _createCorner: function(bgColor) { │ │ │ │ - var corner = document.createElement("div"); │ │ │ │ - corner.style.backgroundColor = this._isTransparent() ? "transparent" : bgColor; │ │ │ │ - return corner │ │ │ │ - }, │ │ │ │ - _createCornerSlice: function(color, bgColor, n, position) { │ │ │ │ - var slice = document.createElement("span"); │ │ │ │ - var inStyle = slice.style; │ │ │ │ - inStyle.backgroundColor = color; │ │ │ │ - inStyle.display = "block"; │ │ │ │ - inStyle.height = "1px"; │ │ │ │ - inStyle.overflow = "hidden"; │ │ │ │ - inStyle.fontSize = "1px"; │ │ │ │ - var borderColor = this._borderColor(color, bgColor); │ │ │ │ - if (this.options.border && n == 0) { │ │ │ │ - inStyle.borderTopStyle = "solid"; │ │ │ │ - inStyle.borderTopWidth = "1px"; │ │ │ │ - inStyle.borderLeftWidth = "0px"; │ │ │ │ - inStyle.borderRightWidth = "0px"; │ │ │ │ - inStyle.borderBottomWidth = "0px"; │ │ │ │ - inStyle.height = "0px"; │ │ │ │ - inStyle.borderColor = borderColor │ │ │ │ - } else if (borderColor) { │ │ │ │ - inStyle.borderColor = borderColor; │ │ │ │ - inStyle.borderStyle = "solid"; │ │ │ │ - inStyle.borderWidth = "0px 1px" │ │ │ │ - } │ │ │ │ - if (!this.options.compact && n == this.options.numSlices - 1) { │ │ │ │ - inStyle.height = "2px" │ │ │ │ - } │ │ │ │ - this._setMargin(slice, n, position); │ │ │ │ - this._setBorder(slice, n, position); │ │ │ │ - return slice │ │ │ │ - }, │ │ │ │ - _setOptions: function(options) { │ │ │ │ - this.options = { │ │ │ │ - corners: "all", │ │ │ │ - color: "fromElement", │ │ │ │ - bgColor: "fromParent", │ │ │ │ - blend: true, │ │ │ │ - border: false, │ │ │ │ - compact: false │ │ │ │ - }; │ │ │ │ - OpenLayers.Util.extend(this.options, options || {}); │ │ │ │ - this.options.numSlices = this.options.compact ? 2 : 4; │ │ │ │ - if (this._isTransparent()) { │ │ │ │ - this.options.blend = false │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - _whichSideTop: function() { │ │ │ │ - if (this._hasString(this.options.corners, "all", "top")) { │ │ │ │ - return "" │ │ │ │ - } │ │ │ │ - if (this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0) { │ │ │ │ - return "" │ │ │ │ - } │ │ │ │ - if (this.options.corners.indexOf("tl") >= 0) { │ │ │ │ - return "left" │ │ │ │ - } else if (this.options.corners.indexOf("tr") >= 0) { │ │ │ │ - return "right" │ │ │ │ - } │ │ │ │ - return "" │ │ │ │ - }, │ │ │ │ - _whichSideBottom: function() { │ │ │ │ - if (this._hasString(this.options.corners, "all", "bottom")) { │ │ │ │ - return "" │ │ │ │ - } │ │ │ │ - if (this.options.corners.indexOf("bl") >= 0 && this.options.corners.indexOf("br") >= 0) { │ │ │ │ - return "" │ │ │ │ - } │ │ │ │ - if (this.options.corners.indexOf("bl") >= 0) { │ │ │ │ - return "left" │ │ │ │ - } else if (this.options.corners.indexOf("br") >= 0) { │ │ │ │ - return "right" │ │ │ │ - } │ │ │ │ - return "" │ │ │ │ - }, │ │ │ │ - _borderColor: function(color, bgColor) { │ │ │ │ - if (color == "transparent") { │ │ │ │ - return bgColor │ │ │ │ - } else if (this.options.border) { │ │ │ │ - return this.options.border │ │ │ │ - } else if (this.options.blend) { │ │ │ │ - return this._blend(bgColor, color) │ │ │ │ - } else { │ │ │ │ - return "" │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - _setMargin: function(el, n, corners) { │ │ │ │ - var marginSize = this._marginSize(n); │ │ │ │ - var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); │ │ │ │ - if (whichSide == "left") { │ │ │ │ - el.style.marginLeft = marginSize + "px"; │ │ │ │ - el.style.marginRight = "0px" │ │ │ │ - } else if (whichSide == "right") { │ │ │ │ - el.style.marginRight = marginSize + "px"; │ │ │ │ - el.style.marginLeft = "0px" │ │ │ │ - } else { │ │ │ │ - el.style.marginLeft = marginSize + "px"; │ │ │ │ - el.style.marginRight = marginSize + "px" │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - _setBorder: function(el, n, corners) { │ │ │ │ - var borderSize = this._borderSize(n); │ │ │ │ - var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); │ │ │ │ - if (whichSide == "left") { │ │ │ │ - el.style.borderLeftWidth = borderSize + "px"; │ │ │ │ - el.style.borderRightWidth = "0px" │ │ │ │ - } else if (whichSide == "right") { │ │ │ │ - el.style.borderRightWidth = borderSize + "px"; │ │ │ │ - el.style.borderLeftWidth = "0px" │ │ │ │ - } else { │ │ │ │ - el.style.borderLeftWidth = borderSize + "px"; │ │ │ │ - el.style.borderRightWidth = borderSize + "px" │ │ │ │ - } │ │ │ │ - if (this.options.border != false) { │ │ │ │ - el.style.borderLeftWidth = borderSize + "px"; │ │ │ │ - el.style.borderRightWidth = borderSize + "px" │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - _marginSize: function(n) { │ │ │ │ - if (this._isTransparent()) { │ │ │ │ - return 0 │ │ │ │ - } │ │ │ │ - var marginSizes = [5, 3, 2, 1]; │ │ │ │ - var blendedMarginSizes = [3, 2, 1, 0]; │ │ │ │ - var compactMarginSizes = [2, 1]; │ │ │ │ - var smBlendedMarginSizes = [1, 0]; │ │ │ │ - if (this.options.compact && this.options.blend) { │ │ │ │ - return smBlendedMarginSizes[n] │ │ │ │ - } else if (this.options.compact) { │ │ │ │ - return compactMarginSizes[n] │ │ │ │ - } else if (this.options.blend) { │ │ │ │ - return blendedMarginSizes[n] │ │ │ │ - } else { │ │ │ │ - return marginSizes[n] │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - _borderSize: function(n) { │ │ │ │ - var transparentBorderSizes = [5, 3, 2, 1]; │ │ │ │ - var blendedBorderSizes = [2, 1, 1, 1]; │ │ │ │ - var compactBorderSizes = [1, 0]; │ │ │ │ - var actualBorderSizes = [0, 2, 0, 0]; │ │ │ │ - if (this.options.compact && (this.options.blend || this._isTransparent())) { │ │ │ │ - return 1 │ │ │ │ - } else if (this.options.compact) { │ │ │ │ - return compactBorderSizes[n] │ │ │ │ - } else if (this.options.blend) { │ │ │ │ - return blendedBorderSizes[n] │ │ │ │ - } else if (this.options.border) { │ │ │ │ - return actualBorderSizes[n] │ │ │ │ - } else if (this._isTransparent()) { │ │ │ │ - return transparentBorderSizes[n] │ │ │ │ - } │ │ │ │ - return 0 │ │ │ │ - }, │ │ │ │ - _hasString: function(str) { │ │ │ │ - for (var i = 1; i < arguments.length; i++) │ │ │ │ - if (str.indexOf(arguments[i]) >= 0) { │ │ │ │ - return true │ │ │ │ - } return false │ │ │ │ - }, │ │ │ │ - _blend: function(c1, c2) { │ │ │ │ - var cc1 = OpenLayers.Rico.Color.createFromHex(c1); │ │ │ │ - cc1.blend(OpenLayers.Rico.Color.createFromHex(c2)); │ │ │ │ - return cc1 │ │ │ │ - }, │ │ │ │ - _background: function(el) { │ │ │ │ - try { │ │ │ │ - return OpenLayers.Rico.Color.createColorFromBackground(el).asHex() │ │ │ │ - } catch (err) { │ │ │ │ - return "#ffffff" │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - _isTransparent: function() { │ │ │ │ - return this.options.color == "transparent" │ │ │ │ - }, │ │ │ │ - _isTopRounded: function() { │ │ │ │ - return this._hasString(this.options.corners, "all", "top", "tl", "tr") │ │ │ │ - }, │ │ │ │ - _isBottomRounded: function() { │ │ │ │ - return this._hasString(this.options.corners, "all", "bottom", "bl", "br") │ │ │ │ - }, │ │ │ │ - _hasSingleTextChild: function(el) { │ │ │ │ - return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3 │ │ │ │ - } │ │ │ │ -}; │ │ │ │ OpenLayers.Feature = OpenLayers.Class({ │ │ │ │ layer: null, │ │ │ │ id: null, │ │ │ │ lonlat: null, │ │ │ │ data: null, │ │ │ │ marker: null, │ │ │ │ popupClass: null, │ │ │ │ @@ -2511,98 +2193,35 @@ │ │ │ │ if (typeof value == "string" && value.indexOf("${") != -1) { │ │ │ │ value = OpenLayers.String.format(value, context, [feature, property]); │ │ │ │ value = isNaN(value) || !value ? value : parseFloat(value) │ │ │ │ } │ │ │ │ return value │ │ │ │ }; │ │ │ │ OpenLayers.Style.SYMBOLIZER_PREFIXES = ["Point", "Line", "Polygon", "Text", "Raster"]; │ │ │ │ -OpenLayers.Rule = OpenLayers.Class({ │ │ │ │ - id: null, │ │ │ │ - name: null, │ │ │ │ - title: null, │ │ │ │ - description: null, │ │ │ │ - context: null, │ │ │ │ - filter: null, │ │ │ │ - elseFilter: false, │ │ │ │ - symbolizer: null, │ │ │ │ - symbolizers: null, │ │ │ │ - minScaleDenominator: null, │ │ │ │ - maxScaleDenominator: null, │ │ │ │ +OpenLayers.Filter = OpenLayers.Class({ │ │ │ │ initialize: function(options) { │ │ │ │ - this.symbolizer = {}; │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - if (this.symbolizers) { │ │ │ │ - delete this.symbolizer │ │ │ │ - } │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - for (var i in this.symbolizer) { │ │ │ │ - this.symbolizer[i] = null │ │ │ │ - } │ │ │ │ - this.symbolizer = null; │ │ │ │ - delete this.symbolizers │ │ │ │ - }, │ │ │ │ - evaluate: function(feature) { │ │ │ │ - var context = this.getContext(feature); │ │ │ │ - var applies = true; │ │ │ │ - if (this.minScaleDenominator || this.maxScaleDenominator) { │ │ │ │ - var scale = feature.layer.map.getScale() │ │ │ │ - } │ │ │ │ - if (this.minScaleDenominator) { │ │ │ │ - applies = scale >= OpenLayers.Style.createLiteral(this.minScaleDenominator, context) │ │ │ │ - } │ │ │ │ - if (applies && this.maxScaleDenominator) { │ │ │ │ - applies = scale < OpenLayers.Style.createLiteral(this.maxScaleDenominator, context) │ │ │ │ - } │ │ │ │ - if (applies && this.filter) { │ │ │ │ - if (this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") { │ │ │ │ - applies = this.filter.evaluate(feature) │ │ │ │ - } else { │ │ │ │ - applies = this.filter.evaluate(context) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return applies │ │ │ │ + OpenLayers.Util.extend(this, options) │ │ │ │ }, │ │ │ │ - getContext: function(feature) { │ │ │ │ - var context = this.context; │ │ │ │ - if (!context) { │ │ │ │ - context = feature.attributes || feature.data │ │ │ │ - } │ │ │ │ - if (typeof this.context == "function") { │ │ │ │ - context = this.context(feature) │ │ │ │ - } │ │ │ │ - return context │ │ │ │ + destroy: function() {}, │ │ │ │ + evaluate: function(context) { │ │ │ │ + return true │ │ │ │ }, │ │ │ │ clone: function() { │ │ │ │ - var options = OpenLayers.Util.extend({}, this); │ │ │ │ - if (this.symbolizers) { │ │ │ │ - var len = this.symbolizers.length; │ │ │ │ - options.symbolizers = new Array(len); │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ - options.symbolizers[i] = this.symbolizers[i].clone() │ │ │ │ - } │ │ │ │ + return null │ │ │ │ + }, │ │ │ │ + toString: function() { │ │ │ │ + var string; │ │ │ │ + if (OpenLayers.Format && OpenLayers.Format.CQL) { │ │ │ │ + string = OpenLayers.Format.CQL.prototype.write(this) │ │ │ │ } else { │ │ │ │ - options.symbolizer = {}; │ │ │ │ - var value, type; │ │ │ │ - for (var key in this.symbolizer) { │ │ │ │ - value = this.symbolizer[key]; │ │ │ │ - type = typeof value; │ │ │ │ - if (type === "object") { │ │ │ │ - options.symbolizer[key] = OpenLayers.Util.extend({}, value) │ │ │ │ - } else if (type === "string") { │ │ │ │ - options.symbolizer[key] = value │ │ │ │ - } │ │ │ │ - } │ │ │ │ + string = Object.prototype.toString.call(this) │ │ │ │ } │ │ │ │ - options.filter = this.filter && this.filter.clone(); │ │ │ │ - options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ - return new OpenLayers.Rule(options) │ │ │ │ + return string │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Rule" │ │ │ │ + CLASS_NAME: "OpenLayers.Filter" │ │ │ │ }); │ │ │ │ OpenLayers.Util = OpenLayers.Util || {}; │ │ │ │ OpenLayers.Util.vendorPrefix = function() { │ │ │ │ "use strict"; │ │ │ │ var VENDOR_PREFIXES = ["", "O", "ms", "Moz", "Webkit"], │ │ │ │ divStyle = document.createElement("div").style, │ │ │ │ cssCache = {}, │ │ │ │ @@ -2660,163 +2279,14 @@ │ │ │ │ css: css, │ │ │ │ js: js, │ │ │ │ style: style, │ │ │ │ cssCache: cssCache, │ │ │ │ jsCache: jsCache │ │ │ │ } │ │ │ │ }(); │ │ │ │ -OpenLayers.Animation = function(window) { │ │ │ │ - var requestAnimationFrame = OpenLayers.Util.vendorPrefix.js(window, "requestAnimationFrame"); │ │ │ │ - var isNative = !!requestAnimationFrame; │ │ │ │ - var requestFrame = function() { │ │ │ │ - var request = window[requestAnimationFrame] || function(callback, element) { │ │ │ │ - window.setTimeout(callback, 16) │ │ │ │ - }; │ │ │ │ - return function(callback, element) { │ │ │ │ - request.apply(window, [callback, element]) │ │ │ │ - } │ │ │ │ - }(); │ │ │ │ - var counter = 0; │ │ │ │ - var loops = {}; │ │ │ │ - │ │ │ │ - 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(id) { │ │ │ │ - delete loops[id] │ │ │ │ - } │ │ │ │ - return { │ │ │ │ - isNative: isNative, │ │ │ │ - requestFrame: requestFrame, │ │ │ │ - start: start, │ │ │ │ - stop: stop │ │ │ │ - } │ │ │ │ -}(window); │ │ │ │ -OpenLayers.Tween = OpenLayers.Class({ │ │ │ │ - easing: null, │ │ │ │ - begin: null, │ │ │ │ - finish: null, │ │ │ │ - duration: null, │ │ │ │ - callbacks: null, │ │ │ │ - time: null, │ │ │ │ - minFrameRate: null, │ │ │ │ - startTime: null, │ │ │ │ - animationId: null, │ │ │ │ - playing: false, │ │ │ │ - initialize: function(easing) { │ │ │ │ - this.easing = easing ? easing : OpenLayers.Easing.Expo.easeOut │ │ │ │ - }, │ │ │ │ - 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)) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - if (((new Date).getTime() - this.startTime) / this.time <= 1e3 / this.minFrameRate) { │ │ │ │ - this.callbacks.eachStep.call(this, value) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.time > this.duration) { │ │ │ │ - this.stop() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Tween" │ │ │ │ -}); │ │ │ │ -OpenLayers.Easing = { │ │ │ │ - CLASS_NAME: "OpenLayers.Easing" │ │ │ │ -}; │ │ │ │ -OpenLayers.Easing.Linear = { │ │ │ │ - easeIn: function(t, b, c, d) { │ │ │ │ - return c * t / d + b │ │ │ │ - }, │ │ │ │ - easeOut: function(t, b, c, d) { │ │ │ │ - return c * t / d + b │ │ │ │ - }, │ │ │ │ - easeInOut: function(t, b, c, d) { │ │ │ │ - return c * t / d + b │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Easing.Linear" │ │ │ │ -}; │ │ │ │ -OpenLayers.Easing.Expo = { │ │ │ │ - easeIn: function(t, b, c, d) { │ │ │ │ - return t == 0 ? b : c * Math.pow(2, 10 * (t / d - 1)) + b │ │ │ │ - }, │ │ │ │ - easeOut: function(t, b, c, d) { │ │ │ │ - return t == d ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}; │ │ │ │ -OpenLayers.Easing.Quad = { │ │ │ │ - easeIn: function(t, b, c, d) { │ │ │ │ - return c * (t /= d) * t + b │ │ │ │ - }, │ │ │ │ - easeOut: function(t, b, c, d) { │ │ │ │ - return -c * (t /= d) * (t - 2) + b │ │ │ │ - }, │ │ │ │ - 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.Event = { │ │ │ │ observers: false, │ │ │ │ KEY_SPACE: 32, │ │ │ │ KEY_BACKSPACE: 8, │ │ │ │ KEY_TAB: 9, │ │ │ │ KEY_RETURN: 13, │ │ │ │ KEY_ESC: 27, │ │ │ │ @@ -3267,14 +2737,163 @@ │ │ │ │ e.touches = touches.slice(); │ │ │ │ handler(e) │ │ │ │ }; │ │ │ │ OpenLayers.Event.observe(element, "MSPointerUp", cb) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Events" │ │ │ │ }); │ │ │ │ +OpenLayers.Animation = function(window) { │ │ │ │ + var requestAnimationFrame = OpenLayers.Util.vendorPrefix.js(window, "requestAnimationFrame"); │ │ │ │ + var isNative = !!requestAnimationFrame; │ │ │ │ + var requestFrame = function() { │ │ │ │ + var request = window[requestAnimationFrame] || function(callback, element) { │ │ │ │ + window.setTimeout(callback, 16) │ │ │ │ + }; │ │ │ │ + return function(callback, element) { │ │ │ │ + request.apply(window, [callback, element]) │ │ │ │ + } │ │ │ │ + }(); │ │ │ │ + var counter = 0; │ │ │ │ + var loops = {}; │ │ │ │ + │ │ │ │ + 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(id) { │ │ │ │ + delete loops[id] │ │ │ │ + } │ │ │ │ + return { │ │ │ │ + isNative: isNative, │ │ │ │ + requestFrame: requestFrame, │ │ │ │ + start: start, │ │ │ │ + stop: stop │ │ │ │ + } │ │ │ │ +}(window); │ │ │ │ +OpenLayers.Tween = OpenLayers.Class({ │ │ │ │ + easing: null, │ │ │ │ + begin: null, │ │ │ │ + finish: null, │ │ │ │ + duration: null, │ │ │ │ + callbacks: null, │ │ │ │ + time: null, │ │ │ │ + minFrameRate: null, │ │ │ │ + startTime: null, │ │ │ │ + animationId: null, │ │ │ │ + playing: false, │ │ │ │ + initialize: function(easing) { │ │ │ │ + this.easing = easing ? easing : OpenLayers.Easing.Expo.easeOut │ │ │ │ + }, │ │ │ │ + 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)) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + if (((new Date).getTime() - this.startTime) / this.time <= 1e3 / this.minFrameRate) { │ │ │ │ + this.callbacks.eachStep.call(this, value) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.time > this.duration) { │ │ │ │ + this.stop() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Tween" │ │ │ │ +}); │ │ │ │ +OpenLayers.Easing = { │ │ │ │ + CLASS_NAME: "OpenLayers.Easing" │ │ │ │ +}; │ │ │ │ +OpenLayers.Easing.Linear = { │ │ │ │ + easeIn: function(t, b, c, d) { │ │ │ │ + return c * t / d + b │ │ │ │ + }, │ │ │ │ + easeOut: function(t, b, c, d) { │ │ │ │ + return c * t / d + b │ │ │ │ + }, │ │ │ │ + easeInOut: function(t, b, c, d) { │ │ │ │ + return c * t / d + b │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Easing.Linear" │ │ │ │ +}; │ │ │ │ +OpenLayers.Easing.Expo = { │ │ │ │ + easeIn: function(t, b, c, d) { │ │ │ │ + return t == 0 ? b : c * Math.pow(2, 10 * (t / d - 1)) + b │ │ │ │ + }, │ │ │ │ + easeOut: function(t, b, c, d) { │ │ │ │ + return t == d ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}; │ │ │ │ +OpenLayers.Easing.Quad = { │ │ │ │ + easeIn: function(t, b, c, d) { │ │ │ │ + return c * (t /= d) * t + b │ │ │ │ + }, │ │ │ │ + easeOut: function(t, b, c, d) { │ │ │ │ + return -c * (t /= d) * (t - 2) + b │ │ │ │ + }, │ │ │ │ + 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 = OpenLayers.Class({ │ │ │ │ proj: null, │ │ │ │ projCode: null, │ │ │ │ titleRegEx: /\+title=[^\+]*/, │ │ │ │ initialize: function(projCode, options) { │ │ │ │ OpenLayers.Util.extend(this, options); │ │ │ │ this.projCode = projCode; │ │ │ │ @@ -6359,143 +5978,178 @@ │ │ │ │ this.tileQueue = null; │ │ │ │ this.tileQueueId = null; │ │ │ │ this.tileCache = null; │ │ │ │ this.tileCacheIndex = null; │ │ │ │ this._destroyed = true │ │ │ │ } │ │ │ │ }); │ │ │ │ -OpenLayers.Strategy = OpenLayers.Class({ │ │ │ │ - layer: null, │ │ │ │ - options: null, │ │ │ │ - active: null, │ │ │ │ - autoActivate: true, │ │ │ │ - autoDestroy: true, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - this.options = options; │ │ │ │ - this.active = false │ │ │ │ +OpenLayers.Icon = OpenLayers.Class({ │ │ │ │ + url: null, │ │ │ │ + size: null, │ │ │ │ + offset: null, │ │ │ │ + calculateOffset: null, │ │ │ │ + imageDiv: null, │ │ │ │ + px: null, │ │ │ │ + initialize: function(url, size, offset, calculateOffset) { │ │ │ │ + this.url = url; │ │ │ │ + this.size = size || { │ │ │ │ + w: 20, │ │ │ │ + h: 20 │ │ │ │ + }; │ │ │ │ + this.offset = offset || { │ │ │ │ + x: -(this.size.w / 2), │ │ │ │ + y: -(this.size.h / 2) │ │ │ │ + }; │ │ │ │ + this.calculateOffset = calculateOffset; │ │ │ │ + var id = OpenLayers.Util.createUniqueID("OL_Icon_"); │ │ │ │ + this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id) │ │ │ │ }, │ │ │ │ destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - this.layer = null; │ │ │ │ - this.options = null │ │ │ │ - }, │ │ │ │ - setLayer: function(layer) { │ │ │ │ - this.layer = layer │ │ │ │ + this.erase(); │ │ │ │ + OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild); │ │ │ │ + this.imageDiv.innerHTML = ""; │ │ │ │ + this.imageDiv = null │ │ │ │ }, │ │ │ │ - activate: function() { │ │ │ │ - if (!this.active) { │ │ │ │ - this.active = true; │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - return false │ │ │ │ + clone: function() { │ │ │ │ + return new OpenLayers.Icon(this.url, this.size, this.offset, this.calculateOffset) │ │ │ │ }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (this.active) { │ │ │ │ - this.active = false; │ │ │ │ - return true │ │ │ │ + setSize: function(size) { │ │ │ │ + if (size != null) { │ │ │ │ + this.size = size │ │ │ │ } │ │ │ │ - return false │ │ │ │ + this.draw() │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler = OpenLayers.Class({ │ │ │ │ - id: null, │ │ │ │ - control: null, │ │ │ │ - map: null, │ │ │ │ - keyMask: null, │ │ │ │ - active: false, │ │ │ │ - evt: null, │ │ │ │ - touch: false, │ │ │ │ - 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) │ │ │ │ + setUrl: function(url) { │ │ │ │ + if (url != null) { │ │ │ │ + this.url = url │ │ │ │ } │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ + this.draw() │ │ │ │ }, │ │ │ │ - setMap: function(map) { │ │ │ │ - this.map = map │ │ │ │ + draw: function(px) { │ │ │ │ + OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, this.size, this.url, "absolute"); │ │ │ │ + this.moveTo(px); │ │ │ │ + return this.imageDiv │ │ │ │ }, │ │ │ │ - checkModifiers: function(evt) { │ │ │ │ - if (this.keyMask == null) { │ │ │ │ - return true │ │ │ │ + erase: function() { │ │ │ │ + if (this.imageDiv != null && this.imageDiv.parentNode != null) { │ │ │ │ + OpenLayers.Element.remove(this.imageDiv) │ │ │ │ } │ │ │ │ - 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); │ │ │ │ - return keyModifiers == this.keyMask │ │ │ │ }, │ │ │ │ - activate: function() { │ │ │ │ - if (this.active) { │ │ │ │ - return false │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ + OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, null, null, null, null, opacity) │ │ │ │ + }, │ │ │ │ + moveTo: function(px) { │ │ │ │ + if (px != null) { │ │ │ │ + this.px = px │ │ │ │ } │ │ │ │ - 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]]) │ │ │ │ + if (this.imageDiv != null) { │ │ │ │ + if (this.px == null) { │ │ │ │ + this.display(false) │ │ │ │ + } else { │ │ │ │ + if (this.calculateOffset) { │ │ │ │ + this.offset = this.calculateOffset(this.size) │ │ │ │ + } │ │ │ │ + OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, { │ │ │ │ + x: this.px.x + this.offset.x, │ │ │ │ + y: this.px.y + this.offset.y │ │ │ │ + }) │ │ │ │ } │ │ │ │ } │ │ │ │ - this.active = true; │ │ │ │ - return true │ │ │ │ }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (!this.active) { │ │ │ │ - return false │ │ │ │ + display: function(display) { │ │ │ │ + this.imageDiv.style.display = display ? "" : "none" │ │ │ │ + }, │ │ │ │ + isDrawn: function() { │ │ │ │ + var isDrawn = this.imageDiv && this.imageDiv.parentNode && this.imageDiv.parentNode.nodeType != 11; │ │ │ │ + return isDrawn │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Icon" │ │ │ │ +}); │ │ │ │ +OpenLayers.Marker = OpenLayers.Class({ │ │ │ │ + icon: null, │ │ │ │ + lonlat: null, │ │ │ │ + events: null, │ │ │ │ + map: null, │ │ │ │ + initialize: function(lonlat, icon) { │ │ │ │ + this.lonlat = lonlat; │ │ │ │ + var newIcon = icon ? icon : OpenLayers.Marker.defaultIcon(); │ │ │ │ + if (this.icon == null) { │ │ │ │ + this.icon = newIcon │ │ │ │ + } else { │ │ │ │ + this.icon.url = newIcon.url; │ │ │ │ + this.icon.size = newIcon.size; │ │ │ │ + this.icon.offset = newIcon.offset; │ │ │ │ + this.icon.calculateOffset = newIcon.calculateOffset │ │ │ │ } │ │ │ │ - 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.events = new OpenLayers.Events(this, this.icon.imageDiv) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.erase(); │ │ │ │ + this.map = null; │ │ │ │ + this.events.destroy(); │ │ │ │ + this.events = null; │ │ │ │ + if (this.icon != null) { │ │ │ │ + this.icon.destroy(); │ │ │ │ + this.icon = null │ │ │ │ } │ │ │ │ - this.touch = false; │ │ │ │ - this.active = false; │ │ │ │ - return true │ │ │ │ }, │ │ │ │ - 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]]) │ │ │ │ - } │ │ │ │ - } │ │ │ │ + draw: function(px) { │ │ │ │ + return this.icon.draw(px) │ │ │ │ + }, │ │ │ │ + erase: function() { │ │ │ │ + if (this.icon != null) { │ │ │ │ + this.icon.erase() │ │ │ │ } │ │ │ │ }, │ │ │ │ - callback: function(name, args) { │ │ │ │ - if (name && this.callbacks[name]) { │ │ │ │ - this.callbacks[name].apply(this.control, args) │ │ │ │ + moveTo: function(px) { │ │ │ │ + if (px != null && this.icon != null) { │ │ │ │ + this.icon.moveTo(px) │ │ │ │ } │ │ │ │ + this.lonlat = this.map.getLonLatFromLayerPx(px) │ │ │ │ }, │ │ │ │ - register: function(name, method) { │ │ │ │ - this.map.events.registerPriority(name, this, method); │ │ │ │ - this.map.events.registerPriority(name, this, this.setEvent) │ │ │ │ + isDrawn: function() { │ │ │ │ + var isDrawn = this.icon && this.icon.isDrawn(); │ │ │ │ + return isDrawn │ │ │ │ }, │ │ │ │ - unregister: function(name, method) { │ │ │ │ - this.map.events.unregister(name, this, method); │ │ │ │ - this.map.events.unregister(name, this, this.setEvent) │ │ │ │ + onScreen: function() { │ │ │ │ + var onScreen = false; │ │ │ │ + if (this.map) { │ │ │ │ + var screenBounds = this.map.getExtent(); │ │ │ │ + onScreen = screenBounds.containsLonLat(this.lonlat) │ │ │ │ + } │ │ │ │ + return onScreen │ │ │ │ }, │ │ │ │ - setEvent: function(evt) { │ │ │ │ - this.evt = evt; │ │ │ │ - return true │ │ │ │ + inflate: function(inflate) { │ │ │ │ + if (this.icon) { │ │ │ │ + this.icon.setSize({ │ │ │ │ + w: this.icon.size.w * inflate, │ │ │ │ + h: this.icon.size.h * inflate │ │ │ │ + }) │ │ │ │ + } │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - this.control = this.map = null │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ + this.icon.setOpacity(opacity) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler" │ │ │ │ + setUrl: function(url) { │ │ │ │ + this.icon.setUrl(url) │ │ │ │ + }, │ │ │ │ + display: function(display) { │ │ │ │ + this.icon.display(display) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Marker" │ │ │ │ }); │ │ │ │ -OpenLayers.Handler.MOD_NONE = 0; │ │ │ │ -OpenLayers.Handler.MOD_SHIFT = 1; │ │ │ │ -OpenLayers.Handler.MOD_CTRL = 2; │ │ │ │ -OpenLayers.Handler.MOD_ALT = 4; │ │ │ │ -OpenLayers.Handler.MOD_META = 8; │ │ │ │ +OpenLayers.Marker.defaultIcon = function() { │ │ │ │ + return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"), { │ │ │ │ + w: 21, │ │ │ │ + h: 25 │ │ │ │ + }, { │ │ │ │ + x: -10.5, │ │ │ │ + y: -25 │ │ │ │ + }) │ │ │ │ +}; │ │ │ │ OpenLayers.Geometry = OpenLayers.Class({ │ │ │ │ id: null, │ │ │ │ parent: null, │ │ │ │ bounds: null, │ │ │ │ initialize: function() { │ │ │ │ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ }, │ │ │ │ @@ -6692,212 +6346,14 @@ │ │ │ │ return { │ │ │ │ distance: Math.pow(x - x0, 2) + Math.pow(y - y0, 2), │ │ │ │ x: x, │ │ │ │ y: y, │ │ │ │ along: along │ │ │ │ } │ │ │ │ }; │ │ │ │ -OpenLayers.Icon = OpenLayers.Class({ │ │ │ │ - url: null, │ │ │ │ - size: null, │ │ │ │ - offset: null, │ │ │ │ - calculateOffset: null, │ │ │ │ - imageDiv: null, │ │ │ │ - px: null, │ │ │ │ - initialize: function(url, size, offset, calculateOffset) { │ │ │ │ - this.url = url; │ │ │ │ - this.size = size || { │ │ │ │ - w: 20, │ │ │ │ - h: 20 │ │ │ │ - }; │ │ │ │ - this.offset = offset || { │ │ │ │ - x: -(this.size.w / 2), │ │ │ │ - y: -(this.size.h / 2) │ │ │ │ - }; │ │ │ │ - this.calculateOffset = calculateOffset; │ │ │ │ - var id = OpenLayers.Util.createUniqueID("OL_Icon_"); │ │ │ │ - this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.erase(); │ │ │ │ - OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild); │ │ │ │ - this.imageDiv.innerHTML = ""; │ │ │ │ - this.imageDiv = null │ │ │ │ - }, │ │ │ │ - clone: function() { │ │ │ │ - return new OpenLayers.Icon(this.url, this.size, this.offset, this.calculateOffset) │ │ │ │ - }, │ │ │ │ - setSize: function(size) { │ │ │ │ - if (size != null) { │ │ │ │ - this.size = size │ │ │ │ - } │ │ │ │ - this.draw() │ │ │ │ - }, │ │ │ │ - setUrl: function(url) { │ │ │ │ - if (url != null) { │ │ │ │ - this.url = url │ │ │ │ - } │ │ │ │ - this.draw() │ │ │ │ - }, │ │ │ │ - draw: function(px) { │ │ │ │ - OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, this.size, this.url, "absolute"); │ │ │ │ - this.moveTo(px); │ │ │ │ - return this.imageDiv │ │ │ │ - }, │ │ │ │ - erase: function() { │ │ │ │ - if (this.imageDiv != null && this.imageDiv.parentNode != null) { │ │ │ │ - OpenLayers.Element.remove(this.imageDiv) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ - OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, null, null, null, null, opacity) │ │ │ │ - }, │ │ │ │ - moveTo: function(px) { │ │ │ │ - if (px != null) { │ │ │ │ - this.px = px │ │ │ │ - } │ │ │ │ - if (this.imageDiv != null) { │ │ │ │ - if (this.px == null) { │ │ │ │ - this.display(false) │ │ │ │ - } else { │ │ │ │ - if (this.calculateOffset) { │ │ │ │ - this.offset = this.calculateOffset(this.size) │ │ │ │ - } │ │ │ │ - OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, { │ │ │ │ - x: this.px.x + this.offset.x, │ │ │ │ - y: this.px.y + this.offset.y │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - display: function(display) { │ │ │ │ - this.imageDiv.style.display = display ? "" : "none" │ │ │ │ - }, │ │ │ │ - isDrawn: function() { │ │ │ │ - var isDrawn = this.imageDiv && this.imageDiv.parentNode && this.imageDiv.parentNode.nodeType != 11; │ │ │ │ - return isDrawn │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Icon" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control = OpenLayers.Class({ │ │ │ │ - id: null, │ │ │ │ - map: null, │ │ │ │ - div: null, │ │ │ │ - type: null, │ │ │ │ - allowSelection: false, │ │ │ │ - displayClass: "", │ │ │ │ - title: "", │ │ │ │ - autoActivate: false, │ │ │ │ - active: null, │ │ │ │ - handlerOptions: null, │ │ │ │ - handler: null, │ │ │ │ - eventListeners: null, │ │ │ │ - events: null, │ │ │ │ - initialize: function(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 + "_") │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.events) { │ │ │ │ - if (this.eventListeners) { │ │ │ │ - this.events.un(this.eventListeners) │ │ │ │ - } │ │ │ │ - this.events.destroy(); │ │ │ │ - this.events = null │ │ │ │ - } │ │ │ │ - this.eventListeners = null; │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - this.map = map; │ │ │ │ - if (this.handler) { │ │ │ │ - this.handler.setMap(map) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - moveTo: function(px) { │ │ │ │ - if (px != null && this.div != null) { │ │ │ │ - this.div.style.left = px.x + "px"; │ │ │ │ - this.div.style.top = px.y + "px" │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.TYPE_BUTTON = 1; │ │ │ │ -OpenLayers.Control.TYPE_TOGGLE = 2; │ │ │ │ -OpenLayers.Control.TYPE_TOOL = 3; │ │ │ │ OpenLayers.Format = OpenLayers.Class({ │ │ │ │ options: null, │ │ │ │ externalProjection: null, │ │ │ │ internalProjection: null, │ │ │ │ data: null, │ │ │ │ keepData: false, │ │ │ │ initialize: function(options) { │ │ │ │ @@ -9874,36 +9330,14 @@ │ │ │ │ throw "Unsupported WFST version: " + options.version │ │ │ │ } │ │ │ │ return new cls(options) │ │ │ │ }; │ │ │ │ OpenLayers.Format.WFST.DEFAULTS = { │ │ │ │ version: "1.0.0" │ │ │ │ }; │ │ │ │ -OpenLayers.Filter = OpenLayers.Class({ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options) │ │ │ │ - }, │ │ │ │ - destroy: function() {}, │ │ │ │ - evaluate: function(context) { │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - clone: function() { │ │ │ │ - return null │ │ │ │ - }, │ │ │ │ - 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.Spatial = OpenLayers.Class(OpenLayers.Filter, { │ │ │ │ type: null, │ │ │ │ property: null, │ │ │ │ value: null, │ │ │ │ distance: null, │ │ │ │ distanceUnits: null, │ │ │ │ evaluate: function(feature) { │ │ │ │ @@ -13127,642 +12561,48 @@ │ │ │ │ process: null, │ │ │ │ output: null, │ │ │ │ initialize: function(options) { │ │ │ │ OpenLayers.Util.extend(this, options) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.WPSProcess.ChainLink" │ │ │ │ }); │ │ │ │ -OpenLayers.Spherical = OpenLayers.Spherical || {}; │ │ │ │ -OpenLayers.Spherical.DEFAULT_RADIUS = 6378137; │ │ │ │ -OpenLayers.Spherical.computeDistanceBetween = function(from, to, radius) { │ │ │ │ - var R = radius || OpenLayers.Spherical.DEFAULT_RADIUS; │ │ │ │ - var sinHalfDeltaLon = Math.sin(Math.PI * (to.lon - from.lon) / 360); │ │ │ │ - var sinHalfDeltaLat = Math.sin(Math.PI * (to.lat - from.lat) / 360); │ │ │ │ - var a = sinHalfDeltaLat * sinHalfDeltaLat + sinHalfDeltaLon * sinHalfDeltaLon * Math.cos(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ - return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) │ │ │ │ -}; │ │ │ │ -OpenLayers.Spherical.computeHeading = function(from, to) { │ │ │ │ - var y = Math.sin(Math.PI * (from.lon - to.lon) / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ - var x = Math.cos(Math.PI * from.lat / 180) * Math.sin(Math.PI * to.lat / 180) - Math.sin(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180) * Math.cos(Math.PI * (from.lon - to.lon) / 180); │ │ │ │ - return 180 * Math.atan2(y, x) / Math.PI │ │ │ │ -}; │ │ │ │ -OpenLayers.Protocol = OpenLayers.Class({ │ │ │ │ - format: null, │ │ │ │ +OpenLayers.Strategy = OpenLayers.Class({ │ │ │ │ + layer: null, │ │ │ │ options: null, │ │ │ │ + active: null, │ │ │ │ + autoActivate: true, │ │ │ │ autoDestroy: true, │ │ │ │ - defaultFilter: null, │ │ │ │ initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ OpenLayers.Util.extend(this, options); │ │ │ │ - this.options = options │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.options = null; │ │ │ │ - this.format = null │ │ │ │ - }, │ │ │ │ - read: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.filter = this.mergeWithDefaultFilter(options.filter) │ │ │ │ - }, │ │ │ │ - create: function() {}, │ │ │ │ - update: function() {}, │ │ │ │ - delete: function() {}, │ │ │ │ - commit: function() {}, │ │ │ │ - abort: function(response) {}, │ │ │ │ - createCallback: function(method, response, options) { │ │ │ │ - return OpenLayers.Function.bind(function() { │ │ │ │ - method.apply(this, [response, options]) │ │ │ │ - }, this) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol" │ │ │ │ -}); │ │ │ │ -OpenLayers.Protocol.Response = OpenLayers.Class({ │ │ │ │ - code: null, │ │ │ │ - requestType: null, │ │ │ │ - last: true, │ │ │ │ - features: null, │ │ │ │ - data: null, │ │ │ │ - reqFeatures: null, │ │ │ │ - priv: null, │ │ │ │ - error: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options) │ │ │ │ - }, │ │ │ │ - success: function() { │ │ │ │ - return this.code > 0 │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.Response" │ │ │ │ -}); │ │ │ │ -OpenLayers.Protocol.Response.SUCCESS = 1; │ │ │ │ -OpenLayers.Protocol.Response.FAILURE = 0; │ │ │ │ -OpenLayers.Renderer = OpenLayers.Class({ │ │ │ │ - container: null, │ │ │ │ - root: null, │ │ │ │ - extent: null, │ │ │ │ - locked: false, │ │ │ │ - size: null, │ │ │ │ - resolution: null, │ │ │ │ - map: null, │ │ │ │ - featureDx: 0, │ │ │ │ - initialize: function(containerID, options) { │ │ │ │ - this.container = OpenLayers.Util.getElement(containerID); │ │ │ │ - OpenLayers.Util.extend(this, options) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.container = null; │ │ │ │ - this.extent = null; │ │ │ │ - this.size = null; │ │ │ │ - this.resolution = null; │ │ │ │ - this.map = null │ │ │ │ - }, │ │ │ │ - supported: function() { │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - setSize: function(size) { │ │ │ │ - this.size = size.clone(); │ │ │ │ - this.resolution = null │ │ │ │ - }, │ │ │ │ - getResolution: function() { │ │ │ │ - this.resolution = this.resolution || this.map.getResolution(); │ │ │ │ - return this.resolution │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawGeometry: function(geometry, style, featureId) {}, │ │ │ │ - drawText: function(featureId, style, location) {}, │ │ │ │ - removeText: function(featureId) {}, │ │ │ │ - clear: function() {}, │ │ │ │ - getFeatureIdFromEvent: function(evt) {}, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - eraseGeometry: function(geometry, featureId) {}, │ │ │ │ - moveRoot: function(renderer) {}, │ │ │ │ - getRenderLayerId: function() { │ │ │ │ - return this.container.id │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -OpenLayers.Renderer.defaultSymbolizer = { │ │ │ │ - fillColor: "#000000", │ │ │ │ - strokeColor: "#000000", │ │ │ │ - strokeWidth: 2, │ │ │ │ - fillOpacity: 1, │ │ │ │ - strokeOpacity: 1, │ │ │ │ - pointRadius: 0, │ │ │ │ - labelAlign: "cm" │ │ │ │ -}; │ │ │ │ -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.Symbolizer = OpenLayers.Class({ │ │ │ │ - zIndex: 0, │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Util.extend(this, config) │ │ │ │ - }, │ │ │ │ - clone: function() { │ │ │ │ - var Type = eval(this.CLASS_NAME); │ │ │ │ - return new Type(OpenLayers.Util.extend({}, this)) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer" │ │ │ │ -}); │ │ │ │ -OpenLayers.StyleMap = OpenLayers.Class({ │ │ │ │ - styles: null, │ │ │ │ - extendDefault: true, │ │ │ │ - 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"]) │ │ │ │ - }; │ │ │ │ - if (style instanceof OpenLayers.Style) { │ │ │ │ - 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) { │ │ │ │ - this.styles[key] = style[key] │ │ │ │ - } else if (typeof style[key] == "object") { │ │ │ │ - this.styles[key] = new OpenLayers.Style(style[key]) │ │ │ │ - } else { │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - for (var key in this.styles) { │ │ │ │ - this.styles[key].destroy() │ │ │ │ - } │ │ │ │ - this.styles = null │ │ │ │ - }, │ │ │ │ - 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)) │ │ │ │ - }, │ │ │ │ - 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.Marker = OpenLayers.Class({ │ │ │ │ - icon: null, │ │ │ │ - lonlat: null, │ │ │ │ - events: null, │ │ │ │ - map: null, │ │ │ │ - initialize: function(lonlat, icon) { │ │ │ │ - this.lonlat = lonlat; │ │ │ │ - var newIcon = icon ? icon : OpenLayers.Marker.defaultIcon(); │ │ │ │ - if (this.icon == null) { │ │ │ │ - this.icon = newIcon │ │ │ │ - } else { │ │ │ │ - this.icon.url = newIcon.url; │ │ │ │ - this.icon.size = newIcon.size; │ │ │ │ - this.icon.offset = newIcon.offset; │ │ │ │ - this.icon.calculateOffset = newIcon.calculateOffset │ │ │ │ - } │ │ │ │ - this.events = new OpenLayers.Events(this, this.icon.imageDiv) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.erase(); │ │ │ │ - this.map = null; │ │ │ │ - this.events.destroy(); │ │ │ │ - this.events = null; │ │ │ │ - if (this.icon != null) { │ │ │ │ - this.icon.destroy(); │ │ │ │ - this.icon = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - draw: function(px) { │ │ │ │ - return this.icon.draw(px) │ │ │ │ - }, │ │ │ │ - erase: function() { │ │ │ │ - if (this.icon != null) { │ │ │ │ - this.icon.erase() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - moveTo: function(px) { │ │ │ │ - if (px != null && this.icon != null) { │ │ │ │ - this.icon.moveTo(px) │ │ │ │ - } │ │ │ │ - this.lonlat = this.map.getLonLatFromLayerPx(px) │ │ │ │ - }, │ │ │ │ - isDrawn: function() { │ │ │ │ - var isDrawn = this.icon && this.icon.isDrawn(); │ │ │ │ - return isDrawn │ │ │ │ - }, │ │ │ │ - onScreen: function() { │ │ │ │ - var onScreen = false; │ │ │ │ - if (this.map) { │ │ │ │ - var screenBounds = this.map.getExtent(); │ │ │ │ - onScreen = screenBounds.containsLonLat(this.lonlat) │ │ │ │ - } │ │ │ │ - return onScreen │ │ │ │ - }, │ │ │ │ - inflate: function(inflate) { │ │ │ │ - if (this.icon) { │ │ │ │ - this.icon.setSize({ │ │ │ │ - w: this.icon.size.w * inflate, │ │ │ │ - h: this.icon.size.h * inflate │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ - this.icon.setOpacity(opacity) │ │ │ │ - }, │ │ │ │ - setUrl: function(url) { │ │ │ │ - this.icon.setUrl(url) │ │ │ │ - }, │ │ │ │ - display: function(display) { │ │ │ │ - this.icon.display(display) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Marker" │ │ │ │ -}); │ │ │ │ -OpenLayers.Marker.defaultIcon = function() { │ │ │ │ - return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"), { │ │ │ │ - w: 21, │ │ │ │ - h: 25 │ │ │ │ - }, { │ │ │ │ - x: -10.5, │ │ │ │ - y: -25 │ │ │ │ - }) │ │ │ │ -}; │ │ │ │ -OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Point" │ │ │ │ -}); │ │ │ │ -OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Line" │ │ │ │ -}); │ │ │ │ -OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Polygon" │ │ │ │ -}); │ │ │ │ -OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Text" │ │ │ │ -}); │ │ │ │ -OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Raster" │ │ │ │ -}); │ │ │ │ -OpenLayers.Style2 = OpenLayers.Class({ │ │ │ │ - id: null, │ │ │ │ - name: null, │ │ │ │ - title: null, │ │ │ │ - description: null, │ │ │ │ - layerName: null, │ │ │ │ - isDefault: false, │ │ │ │ - rules: null, │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Util.extend(this, config); │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ + this.options = options; │ │ │ │ + this.active = false │ │ │ │ }, │ │ │ │ destroy: function() { │ │ │ │ - for (var i = 0, len = this.rules.length; i < len; i++) { │ │ │ │ - this.rules[i].destroy() │ │ │ │ - } │ │ │ │ - delete this.rules │ │ │ │ - }, │ │ │ │ - clone: function() { │ │ │ │ - var config = OpenLayers.Util.extend({}, this); │ │ │ │ - if (this.rules) { │ │ │ │ - config.rules = []; │ │ │ │ - for (var i = 0, len = this.rules.length; i < len; ++i) { │ │ │ │ - config.rules.push(this.rules[i].clone()) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return new OpenLayers.Style2(config) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Style2" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WPSDescribeProcess = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - VERSION: "1.0.0", │ │ │ │ - namespaces: { │ │ │ │ - wps: "http://www.opengis.net/wps/1.0.0", │ │ │ │ - ows: "http://www.opengis.net/ows/1.1", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ - schemaLocation: "http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd", │ │ │ │ - defaultPrefix: "wps", │ │ │ │ - regExes: { │ │ │ │ - trimSpace: /^\s*|\s*$/g, │ │ │ │ - removeSpace: /\s*/g, │ │ │ │ - splitSpace: /\s+/, │ │ │ │ - trimComma: /\s*,\s*/g │ │ │ │ - }, │ │ │ │ - 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 info = {}; │ │ │ │ - this.readNode(data, info); │ │ │ │ - return info │ │ │ │ - }, │ │ │ │ - readers: { │ │ │ │ - wps: { │ │ │ │ - ProcessDescriptions: function(node, obj) { │ │ │ │ - obj.processDescriptions = {}; │ │ │ │ - this.readChildNodes(node, obj.processDescriptions) │ │ │ │ - }, │ │ │ │ - ProcessDescription: function(node, processDescriptions) { │ │ │ │ - var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); │ │ │ │ - var processDescription = { │ │ │ │ - processVersion: processVersion, │ │ │ │ - statusSupported: node.getAttribute("statusSupported") === "true", │ │ │ │ - storeSupported: node.getAttribute("storeSupported") === "true" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, processDescription); │ │ │ │ - processDescriptions[processDescription.identifier] = processDescription │ │ │ │ - }, │ │ │ │ - DataInputs: function(node, processDescription) { │ │ │ │ - processDescription.dataInputs = []; │ │ │ │ - this.readChildNodes(node, processDescription.dataInputs) │ │ │ │ - }, │ │ │ │ - ProcessOutputs: function(node, processDescription) { │ │ │ │ - processDescription.processOutputs = []; │ │ │ │ - this.readChildNodes(node, processDescription.processOutputs) │ │ │ │ - }, │ │ │ │ - Output: function(node, processOutputs) { │ │ │ │ - var output = {}; │ │ │ │ - this.readChildNodes(node, output); │ │ │ │ - processOutputs.push(output) │ │ │ │ - }, │ │ │ │ - ComplexOutput: function(node, output) { │ │ │ │ - output.complexOutput = {}; │ │ │ │ - this.readChildNodes(node, output.complexOutput) │ │ │ │ - }, │ │ │ │ - LiteralOutput: function(node, output) { │ │ │ │ - output.literalOutput = {}; │ │ │ │ - this.readChildNodes(node, output.literalOutput) │ │ │ │ - }, │ │ │ │ - Input: function(node, dataInputs) { │ │ │ │ - var input = { │ │ │ │ - maxOccurs: parseInt(node.getAttribute("maxOccurs")), │ │ │ │ - minOccurs: parseInt(node.getAttribute("minOccurs")) │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, input); │ │ │ │ - dataInputs.push(input) │ │ │ │ - }, │ │ │ │ - BoundingBoxData: function(node, input) { │ │ │ │ - input.boundingBoxData = {}; │ │ │ │ - this.readChildNodes(node, input.boundingBoxData) │ │ │ │ - }, │ │ │ │ - CRS: function(node, obj) { │ │ │ │ - if (!obj.CRSs) { │ │ │ │ - obj.CRSs = {} │ │ │ │ - } │ │ │ │ - obj.CRSs[this.getChildValue(node)] = true │ │ │ │ - }, │ │ │ │ - LiteralData: function(node, input) { │ │ │ │ - input.literalData = {}; │ │ │ │ - this.readChildNodes(node, input.literalData) │ │ │ │ - }, │ │ │ │ - ComplexData: function(node, input) { │ │ │ │ - input.complexData = {}; │ │ │ │ - this.readChildNodes(node, input.complexData) │ │ │ │ - }, │ │ │ │ - Default: function(node, complexData) { │ │ │ │ - complexData["default"] = {}; │ │ │ │ - this.readChildNodes(node, complexData["default"]) │ │ │ │ - }, │ │ │ │ - Supported: function(node, complexData) { │ │ │ │ - complexData["supported"] = {}; │ │ │ │ - this.readChildNodes(node, complexData["supported"]) │ │ │ │ - }, │ │ │ │ - Format: function(node, obj) { │ │ │ │ - var format = {}; │ │ │ │ - this.readChildNodes(node, format); │ │ │ │ - if (!obj.formats) { │ │ │ │ - obj.formats = {} │ │ │ │ - } │ │ │ │ - obj.formats[format.mimeType] = true │ │ │ │ - }, │ │ │ │ - MimeType: function(node, format) { │ │ │ │ - format.mimeType = this.getChildValue(node) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - ows: OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WPSDescribeProcess" │ │ │ │ -}); │ │ │ │ -OpenLayers.WPSClient = OpenLayers.Class({ │ │ │ │ - servers: null, │ │ │ │ - version: "1.0.0", │ │ │ │ - lazy: false, │ │ │ │ - events: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - this.events = new OpenLayers.Events(this); │ │ │ │ - this.servers = {}; │ │ │ │ - for (var s in options.servers) { │ │ │ │ - this.servers[s] = typeof options.servers[s] == "string" ? { │ │ │ │ - url: options.servers[s], │ │ │ │ - version: this.version, │ │ │ │ - processDescription: {} │ │ │ │ - } : options.servers[s] │ │ │ │ - } │ │ │ │ + this.deactivate(); │ │ │ │ + this.layer = null; │ │ │ │ + this.options = null │ │ │ │ }, │ │ │ │ - execute: function(options) { │ │ │ │ - var process = this.getProcess(options.server, options.process); │ │ │ │ - process.execute({ │ │ │ │ - inputs: options.inputs, │ │ │ │ - success: options.success, │ │ │ │ - scope: options.scope │ │ │ │ - }) │ │ │ │ + setLayer: function(layer) { │ │ │ │ + this.layer = layer │ │ │ │ }, │ │ │ │ - getProcess: function(serverID, processID) { │ │ │ │ - var process = new OpenLayers.WPSProcess({ │ │ │ │ - client: this, │ │ │ │ - server: serverID, │ │ │ │ - identifier: processID │ │ │ │ - }); │ │ │ │ - if (!this.lazy) { │ │ │ │ - process.describe() │ │ │ │ + activate: function() { │ │ │ │ + if (!this.active) { │ │ │ │ + this.active = true; │ │ │ │ + return true │ │ │ │ } │ │ │ │ - return process │ │ │ │ + return false │ │ │ │ }, │ │ │ │ - describeProcess: function(serverID, processID, callback, scope) { │ │ │ │ - var server = this.servers[serverID]; │ │ │ │ - if (!server.processDescription[processID]) { │ │ │ │ - if (!(processID in server.processDescription)) { │ │ │ │ - server.processDescription[processID] = null; │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ - url: server.url, │ │ │ │ - params: { │ │ │ │ - SERVICE: "WPS", │ │ │ │ - VERSION: server.version, │ │ │ │ - REQUEST: "DescribeProcess", │ │ │ │ - IDENTIFIER: processID │ │ │ │ - }, │ │ │ │ - success: function(response) { │ │ │ │ - server.processDescription[processID] = response.responseText; │ │ │ │ - this.events.triggerEvent("describeprocess", { │ │ │ │ - identifier: processID, │ │ │ │ - raw: response.responseText │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } else { │ │ │ │ - this.events.register("describeprocess", this, function describe(evt) { │ │ │ │ - if (evt.identifier === processID) { │ │ │ │ - this.events.unregister("describeprocess", this, describe); │ │ │ │ - callback.call(scope, evt.raw) │ │ │ │ - } │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - window.setTimeout(function() { │ │ │ │ - callback.call(scope, server.processDescription[processID]) │ │ │ │ - }, 0) │ │ │ │ + deactivate: function() { │ │ │ │ + if (this.active) { │ │ │ │ + this.active = false; │ │ │ │ + return true │ │ │ │ } │ │ │ │ + return false │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - this.events.destroy(); │ │ │ │ - this.events = null; │ │ │ │ - this.servers = null │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.WPSClient" │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ }); │ │ │ │ OpenLayers.Popup = OpenLayers.Class({ │ │ │ │ events: null, │ │ │ │ id: "", │ │ │ │ lonlat: null, │ │ │ │ div: null, │ │ │ │ contentSize: null, │ │ │ │ @@ -14195,14 +13035,130 @@ │ │ │ │ CLASS_NAME: "OpenLayers.Popup" │ │ │ │ }); │ │ │ │ OpenLayers.Popup.WIDTH = 200; │ │ │ │ OpenLayers.Popup.HEIGHT = 200; │ │ │ │ OpenLayers.Popup.COLOR = "white"; │ │ │ │ OpenLayers.Popup.OPACITY = 1; │ │ │ │ OpenLayers.Popup.BORDER = "0px"; │ │ │ │ +OpenLayers.Control = OpenLayers.Class({ │ │ │ │ + id: null, │ │ │ │ + map: null, │ │ │ │ + div: null, │ │ │ │ + type: null, │ │ │ │ + allowSelection: false, │ │ │ │ + displayClass: "", │ │ │ │ + title: "", │ │ │ │ + autoActivate: false, │ │ │ │ + active: null, │ │ │ │ + handlerOptions: null, │ │ │ │ + handler: null, │ │ │ │ + eventListeners: null, │ │ │ │ + events: null, │ │ │ │ + initialize: function(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 + "_") │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.events) { │ │ │ │ + if (this.eventListeners) { │ │ │ │ + this.events.un(this.eventListeners) │ │ │ │ + } │ │ │ │ + this.events.destroy(); │ │ │ │ + this.events = null │ │ │ │ + } │ │ │ │ + this.eventListeners = null; │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + this.map = map; │ │ │ │ + if (this.handler) { │ │ │ │ + this.handler.setMap(map) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + moveTo: function(px) { │ │ │ │ + if (px != null && this.div != null) { │ │ │ │ + this.div.style.left = px.x + "px"; │ │ │ │ + this.div.style.top = px.y + "px" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.TYPE_BUTTON = 1; │ │ │ │ +OpenLayers.Control.TYPE_TOGGLE = 2; │ │ │ │ +OpenLayers.Control.TYPE_TOOL = 3; │ │ │ │ OpenLayers.Kinetic = OpenLayers.Class({ │ │ │ │ threshold: 0, │ │ │ │ deceleration: .0035, │ │ │ │ nbPoints: 100, │ │ │ │ delay: 200, │ │ │ │ points: undefined, │ │ │ │ timerId: undefined, │ │ │ │ @@ -14279,1455 +13235,5645 @@ │ │ │ │ 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.Markers = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ - isBaseLayer: false, │ │ │ │ - markers: null, │ │ │ │ - drawn: false, │ │ │ │ - initialize: function(name, options) { │ │ │ │ - OpenLayers.Layer.prototype.initialize.apply(this, arguments); │ │ │ │ - this.markers = [] │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.clearMarkers(); │ │ │ │ - this.markers = null; │ │ │ │ - OpenLayers.Layer.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ - if (opacity != this.opacity) { │ │ │ │ - this.opacity = opacity; │ │ │ │ - for (var i = 0, len = this.markers.length; i < len; i++) { │ │ │ │ - this.markers[i].setOpacity(this.opacity) │ │ │ │ - } │ │ │ │ +OpenLayers.Rule = OpenLayers.Class({ │ │ │ │ + id: null, │ │ │ │ + name: null, │ │ │ │ + title: null, │ │ │ │ + description: null, │ │ │ │ + context: null, │ │ │ │ + filter: null, │ │ │ │ + elseFilter: false, │ │ │ │ + symbolizer: null, │ │ │ │ + symbolizers: null, │ │ │ │ + minScaleDenominator: null, │ │ │ │ + maxScaleDenominator: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + this.symbolizer = {}; │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + if (this.symbolizers) { │ │ │ │ + delete this.symbolizer │ │ │ │ } │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ }, │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ - if (zoomChanged || !this.drawn) { │ │ │ │ - for (var i = 0, len = this.markers.length; i < len; i++) { │ │ │ │ - this.drawMarker(this.markers[i]) │ │ │ │ - } │ │ │ │ - this.drawn = true │ │ │ │ + destroy: function() { │ │ │ │ + for (var i in this.symbolizer) { │ │ │ │ + this.symbolizer[i] = null │ │ │ │ } │ │ │ │ + this.symbolizer = null; │ │ │ │ + delete this.symbolizers │ │ │ │ }, │ │ │ │ - addMarker: function(marker) { │ │ │ │ - this.markers.push(marker); │ │ │ │ - if (this.opacity < 1) { │ │ │ │ - marker.setOpacity(this.opacity) │ │ │ │ + evaluate: function(feature) { │ │ │ │ + var context = this.getContext(feature); │ │ │ │ + var applies = true; │ │ │ │ + if (this.minScaleDenominator || this.maxScaleDenominator) { │ │ │ │ + var scale = feature.layer.map.getScale() │ │ │ │ } │ │ │ │ - if (this.map && this.map.getExtent()) { │ │ │ │ - marker.map = this.map; │ │ │ │ - this.drawMarker(marker) │ │ │ │ + if (this.minScaleDenominator) { │ │ │ │ + applies = scale >= OpenLayers.Style.createLiteral(this.minScaleDenominator, context) │ │ │ │ } │ │ │ │ - }, │ │ │ │ - removeMarker: function(marker) { │ │ │ │ - if (this.markers && this.markers.length) { │ │ │ │ - OpenLayers.Util.removeItem(this.markers, marker); │ │ │ │ - marker.erase() │ │ │ │ + if (applies && this.maxScaleDenominator) { │ │ │ │ + applies = scale < OpenLayers.Style.createLiteral(this.maxScaleDenominator, context) │ │ │ │ } │ │ │ │ - }, │ │ │ │ - clearMarkers: function() { │ │ │ │ - if (this.markers != null) { │ │ │ │ - while (this.markers.length > 0) { │ │ │ │ - this.removeMarker(this.markers[0]) │ │ │ │ + if (applies && this.filter) { │ │ │ │ + if (this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") { │ │ │ │ + applies = this.filter.evaluate(feature) │ │ │ │ + } else { │ │ │ │ + applies = this.filter.evaluate(context) │ │ │ │ } │ │ │ │ } │ │ │ │ + return applies │ │ │ │ }, │ │ │ │ - drawMarker: function(marker) { │ │ │ │ - var px = this.map.getLayerPxFromLonLat(marker.lonlat); │ │ │ │ - if (px == null) { │ │ │ │ - marker.display(false) │ │ │ │ - } else { │ │ │ │ - if (!marker.isDrawn()) { │ │ │ │ - var markerImg = marker.draw(px); │ │ │ │ - this.div.appendChild(markerImg) │ │ │ │ - } else if (marker.icon) { │ │ │ │ - marker.icon.moveTo(px) │ │ │ │ - } │ │ │ │ + getContext: function(feature) { │ │ │ │ + var context = this.context; │ │ │ │ + if (!context) { │ │ │ │ + context = feature.attributes || feature.data │ │ │ │ + } │ │ │ │ + if (typeof this.context == "function") { │ │ │ │ + context = this.context(feature) │ │ │ │ } │ │ │ │ + return context │ │ │ │ }, │ │ │ │ - getDataExtent: function() { │ │ │ │ - var maxExtent = null; │ │ │ │ - if (this.markers && this.markers.length > 0) { │ │ │ │ - var maxExtent = new OpenLayers.Bounds; │ │ │ │ - for (var i = 0, len = this.markers.length; i < len; i++) { │ │ │ │ - var marker = this.markers[i]; │ │ │ │ - maxExtent.extend(marker.lonlat) │ │ │ │ + clone: function() { │ │ │ │ + var options = OpenLayers.Util.extend({}, this); │ │ │ │ + if (this.symbolizers) { │ │ │ │ + var len = this.symbolizers.length; │ │ │ │ + options.symbolizers = new Array(len); │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ + options.symbolizers[i] = this.symbolizers[i].clone() │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + options.symbolizer = {}; │ │ │ │ + var value, type; │ │ │ │ + for (var key in this.symbolizer) { │ │ │ │ + value = this.symbolizer[key]; │ │ │ │ + type = typeof value; │ │ │ │ + if (type === "object") { │ │ │ │ + options.symbolizer[key] = OpenLayers.Util.extend({}, value) │ │ │ │ + } else if (type === "string") { │ │ │ │ + options.symbolizer[key] = value │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ - return maxExtent │ │ │ │ + options.filter = this.filter && this.filter.clone(); │ │ │ │ + options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ + return new OpenLayers.Rule(options) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Markers" │ │ │ │ + CLASS_NAME: "OpenLayers.Rule" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.GeoRSS = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ - location: null, │ │ │ │ - features: null, │ │ │ │ - formatOptions: null, │ │ │ │ - selectedFeature: null, │ │ │ │ - icon: null, │ │ │ │ - popupSize: null, │ │ │ │ - useFeedTitle: true, │ │ │ │ - initialize: function(name, location, options) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.initialize.apply(this, [name, options]); │ │ │ │ - this.location = location; │ │ │ │ - this.features = [] │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ - this.clearFeatures(); │ │ │ │ - this.features = null │ │ │ │ - }, │ │ │ │ - loadRSS: function() { │ │ │ │ - if (!this.loaded) { │ │ │ │ - this.events.triggerEvent("loadstart"); │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ - url: this.location, │ │ │ │ - success: this.parseData, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.loaded = true │ │ │ │ +OpenLayers.Spherical = OpenLayers.Spherical || {}; │ │ │ │ +OpenLayers.Spherical.DEFAULT_RADIUS = 6378137; │ │ │ │ +OpenLayers.Spherical.computeDistanceBetween = function(from, to, radius) { │ │ │ │ + var R = radius || OpenLayers.Spherical.DEFAULT_RADIUS; │ │ │ │ + var sinHalfDeltaLon = Math.sin(Math.PI * (to.lon - from.lon) / 360); │ │ │ │ + var sinHalfDeltaLat = Math.sin(Math.PI * (to.lat - from.lat) / 360); │ │ │ │ + var a = sinHalfDeltaLat * sinHalfDeltaLat + sinHalfDeltaLon * sinHalfDeltaLon * Math.cos(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ + return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) │ │ │ │ +}; │ │ │ │ +OpenLayers.Spherical.computeHeading = function(from, to) { │ │ │ │ + var y = Math.sin(Math.PI * (from.lon - to.lon) / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ + var x = Math.cos(Math.PI * from.lat / 180) * Math.sin(Math.PI * to.lat / 180) - Math.sin(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180) * Math.cos(Math.PI * (from.lon - to.lon) / 180); │ │ │ │ + return 180 * Math.atan2(y, x) / Math.PI │ │ │ │ +}; │ │ │ │ +OpenLayers.Handler = OpenLayers.Class({ │ │ │ │ + id: null, │ │ │ │ + control: null, │ │ │ │ + map: null, │ │ │ │ + keyMask: null, │ │ │ │ + active: false, │ │ │ │ + evt: null, │ │ │ │ + touch: false, │ │ │ │ + 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 + "_") │ │ │ │ }, │ │ │ │ - moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ - if (this.visibility && !this.loaded) { │ │ │ │ - this.loadRSS() │ │ │ │ + setMap: function(map) { │ │ │ │ + this.map = map │ │ │ │ + }, │ │ │ │ + checkModifiers: function(evt) { │ │ │ │ + if (this.keyMask == null) { │ │ │ │ + return true │ │ │ │ } │ │ │ │ + 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); │ │ │ │ + return keyModifiers == this.keyMask │ │ │ │ }, │ │ │ │ - parseData: function(ajaxRequest) { │ │ │ │ - var doc = ajaxRequest.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = OpenLayers.Format.XML.prototype.read(ajaxRequest.responseText) │ │ │ │ + activate: function() { │ │ │ │ + if (this.active) { │ │ │ │ + return false │ │ │ │ } │ │ │ │ - if (this.useFeedTitle) { │ │ │ │ - var name = null; │ │ │ │ - try { │ │ │ │ - name = doc.getElementsByTagNameNS("*", "title")[0].firstChild.nodeValue │ │ │ │ - } catch (e) { │ │ │ │ - try { │ │ │ │ - name = doc.getElementsByTagName("title")[0].firstChild.nodeValue │ │ │ │ - } catch (e) {} │ │ │ │ - } │ │ │ │ - if (name) { │ │ │ │ - this.setName(name) │ │ │ │ + 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]]) │ │ │ │ } │ │ │ │ } │ │ │ │ - var options = {}; │ │ │ │ - OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ - if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ - options.externalProjection = this.projection; │ │ │ │ - options.internalProjection = this.map.getProjectionObject() │ │ │ │ + this.active = true; │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (!this.active) { │ │ │ │ + return false │ │ │ │ } │ │ │ │ - var format = new OpenLayers.Format.GeoRSS(options); │ │ │ │ - var features = format.read(doc); │ │ │ │ - for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ - var data = {}; │ │ │ │ - var feature = features[i]; │ │ │ │ - if (!feature.geometry) { │ │ │ │ - continue │ │ │ │ - } │ │ │ │ - var title = feature.attributes.title ? feature.attributes.title : "Untitled"; │ │ │ │ - var description = feature.attributes.description ? feature.attributes.description : "No description."; │ │ │ │ - var link = feature.attributes.link ? feature.attributes.link : ""; │ │ │ │ - var location = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ - data.icon = this.icon == null ? OpenLayers.Marker.defaultIcon() : this.icon.clone(); │ │ │ │ - data.popupSize = this.popupSize ? this.popupSize.clone() : new OpenLayers.Size(250, 120); │ │ │ │ - if (title || description) { │ │ │ │ - data.title = title; │ │ │ │ - data.description = description; │ │ │ │ - var contentHTML = '<div class="olLayerGeoRSSClose">[x]</div>'; │ │ │ │ - contentHTML += '<div class="olLayerGeoRSSTitle">'; │ │ │ │ - if (link) { │ │ │ │ - contentHTML += '<a class="link" href="' + link + '" target="_blank">' │ │ │ │ - } │ │ │ │ - contentHTML += title; │ │ │ │ - if (link) { │ │ │ │ - contentHTML += "</a>" │ │ │ │ - } │ │ │ │ - contentHTML += "</div>"; │ │ │ │ - contentHTML += '<div style="" class="olLayerGeoRSSDescription">'; │ │ │ │ - contentHTML += description; │ │ │ │ - contentHTML += "</div>"; │ │ │ │ - data["popupContentHTML"] = contentHTML │ │ │ │ + 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]]) │ │ │ │ } │ │ │ │ - var feature = new OpenLayers.Feature(this, location, data); │ │ │ │ - this.features.push(feature); │ │ │ │ - var marker = feature.createMarker(); │ │ │ │ - marker.events.register("click", feature, this.markerClick); │ │ │ │ - this.addMarker(marker) │ │ │ │ } │ │ │ │ - this.events.triggerEvent("loadend") │ │ │ │ + this.touch = false; │ │ │ │ + this.active = false; │ │ │ │ + return true │ │ │ │ }, │ │ │ │ - markerClick: function(evt) { │ │ │ │ - var sameMarkerClicked = this == this.layer.selectedFeature; │ │ │ │ - this.layer.selectedFeature = !sameMarkerClicked ? this : null; │ │ │ │ - for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ - this.layer.map.removePopup(this.layer.map.popups[i]) │ │ │ │ - } │ │ │ │ - if (!sameMarkerClicked) { │ │ │ │ - var popup = this.createPopup(); │ │ │ │ - OpenLayers.Event.observe(popup.div, "click", OpenLayers.Function.bind(function() { │ │ │ │ - for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ - this.layer.map.removePopup(this.layer.map.popups[i]) │ │ │ │ + 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]]) │ │ │ │ } │ │ │ │ - }, this)); │ │ │ │ - this.layer.map.addPopup(popup) │ │ │ │ - } │ │ │ │ - OpenLayers.Event.stop(evt) │ │ │ │ - }, │ │ │ │ - clearFeatures: function() { │ │ │ │ - if (this.features != null) { │ │ │ │ - while (this.features.length > 0) { │ │ │ │ - var feature = this.features[0]; │ │ │ │ - OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ - feature.destroy() │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.GeoRSS" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - isBaseLayer: true, │ │ │ │ - sphericalMercator: false, │ │ │ │ - zoomOffset: 0, │ │ │ │ - serverResolutions: null, │ │ │ │ - initialize: function(name, url, options) { │ │ │ │ - if (options && options.sphericalMercator || this.sphericalMercator) { │ │ │ │ - options = OpenLayers.Util.extend({ │ │ │ │ - projection: "EPSG:900913", │ │ │ │ - numZoomLevels: 19 │ │ │ │ - }, options) │ │ │ │ + callback: function(name, args) { │ │ │ │ + if (name && this.callbacks[name]) { │ │ │ │ + this.callbacks[name].apply(this.control, args) │ │ │ │ } │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, [name || this.name, url || this.url, {}, options]) │ │ │ │ }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.XYZ(this.name, this.url, this.getOptions()) │ │ │ │ - } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ + register: function(name, method) { │ │ │ │ + this.map.events.registerPriority(name, this, method); │ │ │ │ + this.map.events.registerPriority(name, this, this.setEvent) │ │ │ │ }, │ │ │ │ - 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) │ │ │ │ + unregister: function(name, method) { │ │ │ │ + this.map.events.unregister(name, this, method); │ │ │ │ + this.map.events.unregister(name, this, this.setEvent) │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ + setEvent: function(evt) { │ │ │ │ + this.evt = evt; │ │ │ │ + return true │ │ │ │ }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + this.control = this.map = null │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.XYZ" │ │ │ │ + CLASS_NAME: "OpenLayers.Handler" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.ArcGISCache = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ - url: null, │ │ │ │ - tileOrigin: null, │ │ │ │ - tileSize: new OpenLayers.Size(256, 256), │ │ │ │ - useArcGISServer: true, │ │ │ │ - type: "png", │ │ │ │ - useScales: false, │ │ │ │ - overrideDPI: false, │ │ │ │ - initialize: function(name, url, options) { │ │ │ │ - OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments); │ │ │ │ - if (this.resolutions) { │ │ │ │ - this.serverResolutions = this.resolutions; │ │ │ │ - this.maxExtent = this.getMaxExtentForResolution(this.resolutions[0]) │ │ │ │ +OpenLayers.Handler.MOD_NONE = 0; │ │ │ │ +OpenLayers.Handler.MOD_SHIFT = 1; │ │ │ │ +OpenLayers.Handler.MOD_CTRL = 2; │ │ │ │ +OpenLayers.Handler.MOD_ALT = 4; │ │ │ │ +OpenLayers.Handler.MOD_META = 8; │ │ │ │ +OpenLayers.Format.WPSDescribeProcess = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + VERSION: "1.0.0", │ │ │ │ + namespaces: { │ │ │ │ + wps: "http://www.opengis.net/wps/1.0.0", │ │ │ │ + ows: "http://www.opengis.net/ows/1.1", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + }, │ │ │ │ + schemaLocation: "http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd", │ │ │ │ + defaultPrefix: "wps", │ │ │ │ + regExes: { │ │ │ │ + trimSpace: /^\s*|\s*$/g, │ │ │ │ + removeSpace: /\s*/g, │ │ │ │ + splitSpace: /\s+/, │ │ │ │ + trimComma: /\s*,\s*/g │ │ │ │ + }, │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ } │ │ │ │ - if (this.layerInfo) { │ │ │ │ - var info = this.layerInfo; │ │ │ │ - var startingTileExtent = new OpenLayers.Bounds(info.fullExtent.xmin, info.fullExtent.ymin, info.fullExtent.xmax, info.fullExtent.ymax); │ │ │ │ - this.projection = "EPSG:" + info.spatialReference.wkid; │ │ │ │ - this.sphericalMercator = info.spatialReference.wkid == 102100; │ │ │ │ - this.units = info.units == "esriFeet" ? "ft" : "m"; │ │ │ │ - if (!!info.tileInfo) { │ │ │ │ - this.tileSize = new OpenLayers.Size(info.tileInfo.width || info.tileInfo.cols, info.tileInfo.height || info.tileInfo.rows); │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat(info.tileInfo.origin.x, info.tileInfo.origin.y); │ │ │ │ - var upperLeft = new OpenLayers.Geometry.Point(startingTileExtent.left, startingTileExtent.top); │ │ │ │ - var bottomRight = new OpenLayers.Geometry.Point(startingTileExtent.right, startingTileExtent.bottom); │ │ │ │ - if (this.useScales) { │ │ │ │ - this.scales = [] │ │ │ │ - } else { │ │ │ │ - this.resolutions = [] │ │ │ │ - } │ │ │ │ - this.lods = []; │ │ │ │ - for (var key in info.tileInfo.lods) { │ │ │ │ - if (info.tileInfo.lods.hasOwnProperty(key)) { │ │ │ │ - var lod = info.tileInfo.lods[key]; │ │ │ │ - if (this.useScales) { │ │ │ │ - this.scales.push(lod.scale) │ │ │ │ - } else { │ │ │ │ - this.resolutions.push(lod.resolution) │ │ │ │ - } │ │ │ │ - var start = this.getContainingTileCoords(upperLeft, lod.resolution); │ │ │ │ - lod.startTileCol = start.x; │ │ │ │ - lod.startTileRow = start.y; │ │ │ │ - var end = this.getContainingTileCoords(bottomRight, lod.resolution); │ │ │ │ - lod.endTileCol = end.x; │ │ │ │ - lod.endTileRow = end.y; │ │ │ │ - this.lods.push(lod) │ │ │ │ - } │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement │ │ │ │ + } │ │ │ │ + var info = {}; │ │ │ │ + this.readNode(data, info); │ │ │ │ + return info │ │ │ │ + }, │ │ │ │ + readers: { │ │ │ │ + wps: { │ │ │ │ + ProcessDescriptions: function(node, obj) { │ │ │ │ + obj.processDescriptions = {}; │ │ │ │ + this.readChildNodes(node, obj.processDescriptions) │ │ │ │ + }, │ │ │ │ + ProcessDescription: function(node, processDescriptions) { │ │ │ │ + var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); │ │ │ │ + var processDescription = { │ │ │ │ + processVersion: processVersion, │ │ │ │ + statusSupported: node.getAttribute("statusSupported") === "true", │ │ │ │ + storeSupported: node.getAttribute("storeSupported") === "true" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, processDescription); │ │ │ │ + processDescriptions[processDescription.identifier] = processDescription │ │ │ │ + }, │ │ │ │ + DataInputs: function(node, processDescription) { │ │ │ │ + processDescription.dataInputs = []; │ │ │ │ + this.readChildNodes(node, processDescription.dataInputs) │ │ │ │ + }, │ │ │ │ + ProcessOutputs: function(node, processDescription) { │ │ │ │ + processDescription.processOutputs = []; │ │ │ │ + this.readChildNodes(node, processDescription.processOutputs) │ │ │ │ + }, │ │ │ │ + Output: function(node, processOutputs) { │ │ │ │ + var output = {}; │ │ │ │ + this.readChildNodes(node, output); │ │ │ │ + processOutputs.push(output) │ │ │ │ + }, │ │ │ │ + ComplexOutput: function(node, output) { │ │ │ │ + output.complexOutput = {}; │ │ │ │ + this.readChildNodes(node, output.complexOutput) │ │ │ │ + }, │ │ │ │ + LiteralOutput: function(node, output) { │ │ │ │ + output.literalOutput = {}; │ │ │ │ + this.readChildNodes(node, output.literalOutput) │ │ │ │ + }, │ │ │ │ + Input: function(node, dataInputs) { │ │ │ │ + var input = { │ │ │ │ + maxOccurs: parseInt(node.getAttribute("maxOccurs")), │ │ │ │ + minOccurs: parseInt(node.getAttribute("minOccurs")) │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, input); │ │ │ │ + dataInputs.push(input) │ │ │ │ + }, │ │ │ │ + BoundingBoxData: function(node, input) { │ │ │ │ + input.boundingBoxData = {}; │ │ │ │ + this.readChildNodes(node, input.boundingBoxData) │ │ │ │ + }, │ │ │ │ + CRS: function(node, obj) { │ │ │ │ + if (!obj.CRSs) { │ │ │ │ + obj.CRSs = {} │ │ │ │ } │ │ │ │ - this.maxExtent = this.calculateMaxExtentWithLOD(this.lods[0]); │ │ │ │ - this.serverResolutions = this.resolutions; │ │ │ │ - if (this.overrideDPI && info.tileInfo.dpi) { │ │ │ │ - OpenLayers.DOTS_PER_INCH = info.tileInfo.dpi │ │ │ │ + obj.CRSs[this.getChildValue(node)] = true │ │ │ │ + }, │ │ │ │ + LiteralData: function(node, input) { │ │ │ │ + input.literalData = {}; │ │ │ │ + this.readChildNodes(node, input.literalData) │ │ │ │ + }, │ │ │ │ + ComplexData: function(node, input) { │ │ │ │ + input.complexData = {}; │ │ │ │ + this.readChildNodes(node, input.complexData) │ │ │ │ + }, │ │ │ │ + Default: function(node, complexData) { │ │ │ │ + complexData["default"] = {}; │ │ │ │ + this.readChildNodes(node, complexData["default"]) │ │ │ │ + }, │ │ │ │ + Supported: function(node, complexData) { │ │ │ │ + complexData["supported"] = {}; │ │ │ │ + this.readChildNodes(node, complexData["supported"]) │ │ │ │ + }, │ │ │ │ + Format: function(node, obj) { │ │ │ │ + var format = {}; │ │ │ │ + this.readChildNodes(node, format); │ │ │ │ + if (!obj.formats) { │ │ │ │ + obj.formats = {} │ │ │ │ } │ │ │ │ + obj.formats[format.mimeType] = true │ │ │ │ + }, │ │ │ │ + MimeType: function(node, format) { │ │ │ │ + format.mimeType = this.getChildValue(node) │ │ │ │ } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getContainingTileCoords: function(point, res) { │ │ │ │ - return new OpenLayers.Pixel(Math.max(Math.floor((point.x - this.tileOrigin.lon) / (this.tileSize.w * res)), 0), Math.max(Math.floor((this.tileOrigin.lat - point.y) / (this.tileSize.h * res)), 0)) │ │ │ │ + }, │ │ │ │ + ows: OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ }, │ │ │ │ - calculateMaxExtentWithLOD: function(lod) { │ │ │ │ - var numTileCols = lod.endTileCol - lod.startTileCol + 1; │ │ │ │ - var numTileRows = lod.endTileRow - lod.startTileRow + 1; │ │ │ │ - var minX = this.tileOrigin.lon + lod.startTileCol * this.tileSize.w * lod.resolution; │ │ │ │ - var maxX = minX + numTileCols * this.tileSize.w * lod.resolution; │ │ │ │ - var maxY = this.tileOrigin.lat - lod.startTileRow * this.tileSize.h * lod.resolution; │ │ │ │ - var minY = maxY - numTileRows * this.tileSize.h * lod.resolution; │ │ │ │ - return new OpenLayers.Bounds(minX, minY, maxX, maxY) │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WPSDescribeProcess" │ │ │ │ +}); │ │ │ │ +OpenLayers.WPSClient = OpenLayers.Class({ │ │ │ │ + servers: null, │ │ │ │ + version: "1.0.0", │ │ │ │ + lazy: false, │ │ │ │ + events: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + this.events = new OpenLayers.Events(this); │ │ │ │ + this.servers = {}; │ │ │ │ + for (var s in options.servers) { │ │ │ │ + this.servers[s] = typeof options.servers[s] == "string" ? { │ │ │ │ + url: options.servers[s], │ │ │ │ + version: this.version, │ │ │ │ + processDescription: {} │ │ │ │ + } : options.servers[s] │ │ │ │ + } │ │ │ │ }, │ │ │ │ - calculateMaxExtentWithExtent: function(extent, res) { │ │ │ │ - var upperLeft = new OpenLayers.Geometry.Point(extent.left, extent.top); │ │ │ │ - var bottomRight = new OpenLayers.Geometry.Point(extent.right, extent.bottom); │ │ │ │ - var start = this.getContainingTileCoords(upperLeft, res); │ │ │ │ - var end = this.getContainingTileCoords(bottomRight, res); │ │ │ │ - var lod = { │ │ │ │ - resolution: res, │ │ │ │ - startTileCol: start.x, │ │ │ │ - startTileRow: start.y, │ │ │ │ - endTileCol: end.x, │ │ │ │ - endTileRow: end.y │ │ │ │ - }; │ │ │ │ - return this.calculateMaxExtentWithLOD(lod) │ │ │ │ + execute: function(options) { │ │ │ │ + var process = this.getProcess(options.server, options.process); │ │ │ │ + process.execute({ │ │ │ │ + inputs: options.inputs, │ │ │ │ + success: options.success, │ │ │ │ + scope: options.scope │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - getUpperLeftTileCoord: function(res) { │ │ │ │ - var upperLeft = new OpenLayers.Geometry.Point(this.maxExtent.left, this.maxExtent.top); │ │ │ │ - return this.getContainingTileCoords(upperLeft, res) │ │ │ │ + getProcess: function(serverID, processID) { │ │ │ │ + var process = new OpenLayers.WPSProcess({ │ │ │ │ + client: this, │ │ │ │ + server: serverID, │ │ │ │ + identifier: processID │ │ │ │ + }); │ │ │ │ + if (!this.lazy) { │ │ │ │ + process.describe() │ │ │ │ + } │ │ │ │ + return process │ │ │ │ }, │ │ │ │ - getLowerRightTileCoord: function(res) { │ │ │ │ - var bottomRight = new OpenLayers.Geometry.Point(this.maxExtent.right, this.maxExtent.bottom); │ │ │ │ - return this.getContainingTileCoords(bottomRight, res) │ │ │ │ + describeProcess: function(serverID, processID, callback, scope) { │ │ │ │ + var server = this.servers[serverID]; │ │ │ │ + if (!server.processDescription[processID]) { │ │ │ │ + if (!(processID in server.processDescription)) { │ │ │ │ + server.processDescription[processID] = null; │ │ │ │ + OpenLayers.Request.GET({ │ │ │ │ + url: server.url, │ │ │ │ + params: { │ │ │ │ + SERVICE: "WPS", │ │ │ │ + VERSION: server.version, │ │ │ │ + REQUEST: "DescribeProcess", │ │ │ │ + IDENTIFIER: processID │ │ │ │ + }, │ │ │ │ + success: function(response) { │ │ │ │ + server.processDescription[processID] = response.responseText; │ │ │ │ + this.events.triggerEvent("describeprocess", { │ │ │ │ + identifier: processID, │ │ │ │ + raw: response.responseText │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } else { │ │ │ │ + this.events.register("describeprocess", this, function describe(evt) { │ │ │ │ + if (evt.identifier === processID) { │ │ │ │ + this.events.unregister("describeprocess", this, describe); │ │ │ │ + callback.call(scope, evt.raw) │ │ │ │ + } │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + window.setTimeout(function() { │ │ │ │ + callback.call(scope, server.processDescription[processID]) │ │ │ │ + }, 0) │ │ │ │ + } │ │ │ │ }, │ │ │ │ - getMaxExtentForResolution: function(res) { │ │ │ │ - var start = this.getUpperLeftTileCoord(res); │ │ │ │ - var end = this.getLowerRightTileCoord(res); │ │ │ │ - var numTileCols = end.x - start.x + 1; │ │ │ │ - var numTileRows = end.y - start.y + 1; │ │ │ │ - var minX = this.tileOrigin.lon + start.x * this.tileSize.w * res; │ │ │ │ - var maxX = minX + numTileCols * this.tileSize.w * res; │ │ │ │ - var maxY = this.tileOrigin.lat - start.y * this.tileSize.h * res; │ │ │ │ - var minY = maxY - numTileRows * this.tileSize.h * res; │ │ │ │ - return new OpenLayers.Bounds(minX, minY, maxX, maxY) │ │ │ │ + destroy: function() { │ │ │ │ + this.events.destroy(); │ │ │ │ + this.events = null; │ │ │ │ + this.servers = null │ │ │ │ }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.ArcGISCache(this.name, this.url, this.options) │ │ │ │ - } │ │ │ │ - return OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]) │ │ │ │ + CLASS_NAME: "OpenLayers.WPSClient" │ │ │ │ +}); │ │ │ │ +OpenLayers.Symbolizer = OpenLayers.Class({ │ │ │ │ + zIndex: 0, │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Util.extend(this, config) │ │ │ │ }, │ │ │ │ - initGriddedTiles: function(bounds) { │ │ │ │ - delete this._tileOrigin; │ │ │ │ - OpenLayers.Layer.XYZ.prototype.initGriddedTiles.apply(this, arguments) │ │ │ │ + clone: function() { │ │ │ │ + var Type = eval(this.CLASS_NAME); │ │ │ │ + return new Type(OpenLayers.Util.extend({}, this)) │ │ │ │ }, │ │ │ │ - getMaxExtent: function() { │ │ │ │ - var resolution = this.map.getResolution(); │ │ │ │ - return this.maxExtent = this.getMaxExtentForResolution(resolution) │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer" │ │ │ │ +}); │ │ │ │ +OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ }, │ │ │ │ - getTileOrigin: function() { │ │ │ │ - if (!this._tileOrigin) { │ │ │ │ - var extent = this.getMaxExtent(); │ │ │ │ - this._tileOrigin = new OpenLayers.LonLat(extent.left, extent.bottom) │ │ │ │ - } │ │ │ │ - return this._tileOrigin │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Point" │ │ │ │ +}); │ │ │ │ +OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - var res = this.getResolution(); │ │ │ │ - var originTileX = this.tileOrigin.lon + res * this.tileSize.w / 2; │ │ │ │ - var originTileY = this.tileOrigin.lat - res * this.tileSize.h / 2; │ │ │ │ - var center = bounds.getCenterLonLat(); │ │ │ │ - var point = { │ │ │ │ - x: center.lon, │ │ │ │ - y: center.lat │ │ │ │ - }; │ │ │ │ - var x = Math.round(Math.abs((center.lon - originTileX) / (res * this.tileSize.w))); │ │ │ │ - var y = Math.round(Math.abs((originTileY - center.lat) / (res * this.tileSize.h))); │ │ │ │ - var z = this.map.getZoom(); │ │ │ │ - if (this.lods) { │ │ │ │ - var lod = this.lods[this.map.getZoom()]; │ │ │ │ - if (x < lod.startTileCol || x > lod.endTileCol || (y < lod.startTileRow || y > lod.endTileRow)) { │ │ │ │ - return null │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - var start = this.getUpperLeftTileCoord(res); │ │ │ │ - var end = this.getLowerRightTileCoord(res); │ │ │ │ - if (x < start.x || x >= end.x || (y < start.y || y >= end.y)) { │ │ │ │ - return null │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var url = this.url; │ │ │ │ - var s = "" + x + y + z; │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(s, url) │ │ │ │ - } │ │ │ │ - if (this.useArcGISServer) { │ │ │ │ - url = url + "/tile/${z}/${y}/${x}" │ │ │ │ - } else { │ │ │ │ - x = "C" + OpenLayers.Number.zeroPad(x, 8, 16); │ │ │ │ - y = "R" + OpenLayers.Number.zeroPad(y, 8, 16); │ │ │ │ - z = "L" + OpenLayers.Number.zeroPad(z, 2, 10); │ │ │ │ - url = url + "/${z}/${y}/${x}." + this.type │ │ │ │ - } │ │ │ │ - url = OpenLayers.String.format(url, { │ │ │ │ - x: x, │ │ │ │ - y: y, │ │ │ │ - z: z │ │ │ │ - }); │ │ │ │ - return OpenLayers.Util.urlAppend(url, OpenLayers.Util.getParameterString(this.params)) │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Line" │ │ │ │ +}); │ │ │ │ +OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.ArcGISCache" │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Polygon" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ - key: null, │ │ │ │ - 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, .5971642833948135, .29858214169740677, .14929107084870338, .07464553542435169], │ │ │ │ - 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>", │ │ │ │ - metadata: null, │ │ │ │ - protocolRegex: /^http:/i, │ │ │ │ - type: "Road", │ │ │ │ - culture: "en-US", │ │ │ │ - metadataParams: null, │ │ │ │ - tileOptions: null, │ │ │ │ - protocol: ~window.location.href.indexOf("http") ? "" : "http:", │ │ │ │ - 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() │ │ │ │ +OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ }, │ │ │ │ - loadMetadata: function() { │ │ │ │ - this._callbackId = "_callback_" + this.id.replace(/\./g, "_"); │ │ │ │ - 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) │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Text" │ │ │ │ +}); │ │ │ │ +OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ }, │ │ │ │ - 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() │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Raster" │ │ │ │ +}); │ │ │ │ +OpenLayers.Style2 = OpenLayers.Class({ │ │ │ │ + id: null, │ │ │ │ + name: null, │ │ │ │ + title: null, │ │ │ │ + description: null, │ │ │ │ + layerName: null, │ │ │ │ + isDefault: false, │ │ │ │ + rules: null, │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Util.extend(this, config); │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ }, │ │ │ │ - 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) │ │ │ │ + destroy: function() { │ │ │ │ + for (var i = 0, len = this.rules.length; i < len; i++) { │ │ │ │ + this.rules[i].destroy() │ │ │ │ } │ │ │ │ - var quadKey = quadDigits.join(""); │ │ │ │ - var url = this.selectUrl("" + x + y + z, this.url); │ │ │ │ - return OpenLayers.String.format(url, { │ │ │ │ - quadkey: quadKey │ │ │ │ - }) │ │ │ │ + delete this.rules │ │ │ │ }, │ │ │ │ - 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]; │ │ │ │ - bbox = OpenLayers.Bounds.fromArray(coverage.bbox, true); │ │ │ │ - if (extent.intersectsBounds(bbox) && zoom <= coverage.zoomMax && zoom >= coverage.zoomMin) { │ │ │ │ - copyrights += provider.attribution + " " │ │ │ │ - } │ │ │ │ + clone: function() { │ │ │ │ + var config = OpenLayers.Util.extend({}, this); │ │ │ │ + if (this.rules) { │ │ │ │ + config.rules = []; │ │ │ │ + for (var i = 0, len = this.rules.length; i < len; ++i) { │ │ │ │ + config.rules.push(this.rules[i].clone()) │ │ │ │ } │ │ │ │ } │ │ │ │ - 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" │ │ │ │ - }) │ │ │ │ + return new OpenLayers.Style2(config) │ │ │ │ }, │ │ │ │ - setMap: function() { │ │ │ │ - OpenLayers.Layer.XYZ.prototype.setMap.apply(this, arguments); │ │ │ │ - this.map.events.register("moveend", this, this.updateAttribution) │ │ │ │ + CLASS_NAME: "OpenLayers.Style2" │ │ │ │ +}); │ │ │ │ +OpenLayers.Protocol = OpenLayers.Class({ │ │ │ │ + format: null, │ │ │ │ + options: null, │ │ │ │ + autoDestroy: true, │ │ │ │ + defaultFilter: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + this.options = options │ │ │ │ }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.Bing(this.options) │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ + return merged │ │ │ │ }, │ │ │ │ destroy: function() { │ │ │ │ - this.map && this.map.events.unregister("moveend", this, this.updateAttribution); │ │ │ │ - OpenLayers.Layer.XYZ.prototype.destroy.apply(this, arguments) │ │ │ │ + this.options = null; │ │ │ │ + this.format = null │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Bing" │ │ │ │ -}); │ │ │ │ -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; │ │ │ │ - delete this._callbackId │ │ │ │ -}; │ │ │ │ -OpenLayers.Layer.SphericalMercator = { │ │ │ │ - getExtent: function() { │ │ │ │ - var extent = null; │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - extent = this.map.calculateBounds() │ │ │ │ - } else { │ │ │ │ - extent = OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this) │ │ │ │ - } │ │ │ │ - return extent │ │ │ │ + read: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + options.filter = this.mergeWithDefaultFilter(options.filter) │ │ │ │ }, │ │ │ │ - getLonLatFromViewPortPx: function(viewPortPx) { │ │ │ │ - return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this, arguments) │ │ │ │ + create: function() {}, │ │ │ │ + update: function() {}, │ │ │ │ + delete: function() {}, │ │ │ │ + commit: function() {}, │ │ │ │ + abort: function(response) {}, │ │ │ │ + createCallback: function(method, response, options) { │ │ │ │ + return OpenLayers.Function.bind(function() { │ │ │ │ + method.apply(this, [response, options]) │ │ │ │ + }, this) │ │ │ │ }, │ │ │ │ - getViewPortPxFromLonLat: function(lonlat) { │ │ │ │ - return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this, arguments) │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol" │ │ │ │ +}); │ │ │ │ +OpenLayers.Protocol.Response = OpenLayers.Class({ │ │ │ │ + code: null, │ │ │ │ + requestType: null, │ │ │ │ + last: true, │ │ │ │ + features: null, │ │ │ │ + data: null, │ │ │ │ + reqFeatures: null, │ │ │ │ + priv: null, │ │ │ │ + error: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Util.extend(this, options) │ │ │ │ }, │ │ │ │ - initMercatorParameters: function() { │ │ │ │ - this.RESOLUTIONS = []; │ │ │ │ - var maxResolution = 156543.03390625; │ │ │ │ - for (var zoom = 0; zoom <= this.MAX_ZOOM_LEVEL; ++zoom) { │ │ │ │ - this.RESOLUTIONS[zoom] = maxResolution / Math.pow(2, zoom) │ │ │ │ - } │ │ │ │ - this.units = "m"; │ │ │ │ - this.projection = this.projection || "EPSG:900913" │ │ │ │ + success: function() { │ │ │ │ + return this.code > 0 │ │ │ │ }, │ │ │ │ - forwardMercator: function() { │ │ │ │ - var gg = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ - var sm = new OpenLayers.Projection("EPSG:900913"); │ │ │ │ - return function(lon, lat) { │ │ │ │ - var point = OpenLayers.Projection.transform({ │ │ │ │ - x: lon, │ │ │ │ - y: lat │ │ │ │ - }, gg, sm); │ │ │ │ - return new OpenLayers.LonLat(point.x, point.y) │ │ │ │ - } │ │ │ │ - }(), │ │ │ │ - inverseMercator: function() { │ │ │ │ - var gg = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ - var sm = new OpenLayers.Projection("EPSG:900913"); │ │ │ │ - return function(x, y) { │ │ │ │ - var point = OpenLayers.Projection.transform({ │ │ │ │ - x: x, │ │ │ │ - y: y │ │ │ │ - }, sm, gg); │ │ │ │ - return new OpenLayers.LonLat(point.x, point.y) │ │ │ │ - } │ │ │ │ - }() │ │ │ │ -}; │ │ │ │ -OpenLayers.Layer.EventPane = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ - smoothDragPan: true, │ │ │ │ - isBaseLayer: true, │ │ │ │ - isFixed: true, │ │ │ │ - pane: null, │ │ │ │ - mapObject: null, │ │ │ │ - initialize: function(name, options) { │ │ │ │ - OpenLayers.Layer.prototype.initialize.apply(this, arguments); │ │ │ │ - if (this.pane == null) { │ │ │ │ - this.pane = OpenLayers.Util.createDiv(this.div.id + "_EventPane") │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.Response" │ │ │ │ +}); │ │ │ │ +OpenLayers.Protocol.Response.SUCCESS = 1; │ │ │ │ +OpenLayers.Protocol.Response.FAILURE = 0; │ │ │ │ +OpenLayers.StyleMap = OpenLayers.Class({ │ │ │ │ + styles: null, │ │ │ │ + extendDefault: true, │ │ │ │ + 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"]) │ │ │ │ + }; │ │ │ │ + if (style instanceof OpenLayers.Style) { │ │ │ │ + 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) { │ │ │ │ + this.styles[key] = style[key] │ │ │ │ + } else if (typeof style[key] == "object") { │ │ │ │ + this.styles[key] = new OpenLayers.Style(style[key]) │ │ │ │ + } else { │ │ │ │ + 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) │ │ │ │ }, │ │ │ │ destroy: function() { │ │ │ │ - this.mapObject = null; │ │ │ │ - this.pane = null; │ │ │ │ - OpenLayers.Layer.prototype.destroy.apply(this, arguments) │ │ │ │ + for (var key in this.styles) { │ │ │ │ + this.styles[key].destroy() │ │ │ │ + } │ │ │ │ + this.styles = null │ │ │ │ }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.prototype.setMap.apply(this, arguments); │ │ │ │ - this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1; │ │ │ │ - this.pane.style.display = this.div.style.display; │ │ │ │ - this.pane.style.width = "100%"; │ │ │ │ - this.pane.style.height = "100%"; │ │ │ │ - if (OpenLayers.BROWSER_NAME == "msie") { │ │ │ │ - this.pane.style.background = "url(" + OpenLayers.Util.getImageLocation("blank.gif") + ")" │ │ │ │ + createSymbolizer: function(feature, intent) { │ │ │ │ + if (!feature) { │ │ │ │ + feature = new OpenLayers.Feature.Vector │ │ │ │ } │ │ │ │ - if (this.isFixed) { │ │ │ │ - this.map.viewPortDiv.appendChild(this.pane) │ │ │ │ - } else { │ │ │ │ - this.map.layerContainerDiv.appendChild(this.pane) │ │ │ │ + if (!this.styles[intent]) { │ │ │ │ + intent = "default" │ │ │ │ } │ │ │ │ - this.loadMapObject(); │ │ │ │ - if (this.mapObject == null) { │ │ │ │ - this.loadWarningMessage() │ │ │ │ + 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)) │ │ │ │ }, │ │ │ │ - removeMap: function(map) { │ │ │ │ - if (this.pane && this.pane.parentNode) { │ │ │ │ - this.pane.parentNode.removeChild(this.pane) │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + })) │ │ │ │ } │ │ │ │ - OpenLayers.Layer.prototype.removeMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - loadWarningMessage: function() { │ │ │ │ - this.div.style.backgroundColor = "darkblue"; │ │ │ │ - var viewSize = this.map.getSize(); │ │ │ │ - var msgW = Math.min(viewSize.w, 300); │ │ │ │ - var msgH = Math.min(viewSize.h, 200); │ │ │ │ - var size = new OpenLayers.Size(msgW, msgH); │ │ │ │ - var centerPx = new OpenLayers.Pixel(viewSize.w / 2, viewSize.h / 2); │ │ │ │ - var topLeft = centerPx.add(-size.w / 2, -size.h / 2); │ │ │ │ - var div = OpenLayers.Util.createDiv(this.name + "_warning", topLeft, size, null, null, null, "auto"); │ │ │ │ - div.style.padding = "7px"; │ │ │ │ - div.style.backgroundColor = "yellow"; │ │ │ │ - div.innerHTML = this.getWarningHTML(); │ │ │ │ - this.div.appendChild(div) │ │ │ │ - }, │ │ │ │ - getWarningHTML: function() { │ │ │ │ - return "" │ │ │ │ - }, │ │ │ │ - display: function(display) { │ │ │ │ - OpenLayers.Layer.prototype.display.apply(this, arguments); │ │ │ │ - this.pane.style.display = this.div.style.display │ │ │ │ + this.styles[renderIntent].addRules(rules) │ │ │ │ }, │ │ │ │ - setZIndex: function(zIndex) { │ │ │ │ - OpenLayers.Layer.prototype.setZIndex.apply(this, arguments); │ │ │ │ - this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1 │ │ │ │ + CLASS_NAME: "OpenLayers.StyleMap" │ │ │ │ +}); │ │ │ │ +OpenLayers.Tile.UTFGrid = OpenLayers.Class(OpenLayers.Tile, { │ │ │ │ + url: null, │ │ │ │ + utfgridResolution: 2, │ │ │ │ + json: null, │ │ │ │ + format: null, │ │ │ │ + destroy: function() { │ │ │ │ + this.clear(); │ │ │ │ + OpenLayers.Tile.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ - moveByPx: function(dx, dy) { │ │ │ │ - OpenLayers.Layer.prototype.moveByPx.apply(this, arguments); │ │ │ │ - if (this.dragPanMapObject) { │ │ │ │ - this.dragPanMapObject(dx, -dy) │ │ │ │ + draw: function() { │ │ │ │ + var drawn = OpenLayers.Tile.prototype.draw.apply(this, arguments); │ │ │ │ + if (drawn) { │ │ │ │ + if (this.isLoading) { │ │ │ │ + this.abortLoading(); │ │ │ │ + this.events.triggerEvent("reload") │ │ │ │ + } else { │ │ │ │ + this.isLoading = true; │ │ │ │ + this.events.triggerEvent("loadstart") │ │ │ │ + } │ │ │ │ + this.url = this.layer.getURL(this.bounds); │ │ │ │ + if (this.layer.useJSONP) { │ │ │ │ + var ols = new OpenLayers.Protocol.Script({ │ │ │ │ + url: this.url, │ │ │ │ + callback: function(response) { │ │ │ │ + this.isLoading = false; │ │ │ │ + this.events.triggerEvent("loadend"); │ │ │ │ + this.json = response.data │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + ols.read(); │ │ │ │ + this.request = ols │ │ │ │ + } else { │ │ │ │ + this.request = OpenLayers.Request.GET({ │ │ │ │ + url: this.url, │ │ │ │ + callback: function(response) { │ │ │ │ + this.isLoading = false; │ │ │ │ + this.events.triggerEvent("loadend"); │ │ │ │ + if (response.status === 200) { │ │ │ │ + this.parseData(response.responseText) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ } else { │ │ │ │ - this.moveTo(this.map.getCachedCenter()) │ │ │ │ + this.unload() │ │ │ │ } │ │ │ │ + return drawn │ │ │ │ }, │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ - if (this.mapObject != null) { │ │ │ │ - var newCenter = this.map.getCenter(); │ │ │ │ - var newZoom = this.map.getZoom(); │ │ │ │ - if (newCenter != null) { │ │ │ │ - var moOldCenter = this.getMapObjectCenter(); │ │ │ │ - var oldCenter = this.getOLLonLatFromMapObjectLonLat(moOldCenter); │ │ │ │ - var moOldZoom = this.getMapObjectZoom(); │ │ │ │ - var oldZoom = this.getOLZoomFromMapObjectZoom(moOldZoom); │ │ │ │ - if (!newCenter.equals(oldCenter) || newZoom != oldZoom) { │ │ │ │ - if (!zoomChanged && oldCenter && this.dragPanMapObject && this.smoothDragPan) { │ │ │ │ - var oldPx = this.map.getViewPortPxFromLonLat(oldCenter); │ │ │ │ - var newPx = this.map.getViewPortPxFromLonLat(newCenter); │ │ │ │ - this.dragPanMapObject(newPx.x - oldPx.x, oldPx.y - newPx.y) │ │ │ │ - } else { │ │ │ │ - var center = this.getMapObjectLonLatFromOLLonLat(newCenter); │ │ │ │ - var zoom = this.getMapObjectZoomFromOLZoom(newZoom); │ │ │ │ - this.setMapObjectCenter(center, zoom, dragging) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + abortLoading: function() { │ │ │ │ + if (this.request) { │ │ │ │ + this.request.abort(); │ │ │ │ + delete this.request │ │ │ │ } │ │ │ │ + this.isLoading = false │ │ │ │ }, │ │ │ │ - getLonLatFromViewPortPx: function(viewPortPx) { │ │ │ │ - var lonlat = null; │ │ │ │ - if (this.mapObject != null && this.getMapObjectCenter() != null) { │ │ │ │ - var moPixel = this.getMapObjectPixelFromOLPixel(viewPortPx); │ │ │ │ - var moLonLat = this.getMapObjectLonLatFromMapObjectPixel(moPixel); │ │ │ │ - lonlat = this.getOLLonLatFromMapObjectLonLat(moLonLat) │ │ │ │ + getFeatureInfo: function(i, j) { │ │ │ │ + var info = null; │ │ │ │ + if (this.json) { │ │ │ │ + var id = this.getFeatureId(i, j); │ │ │ │ + if (id !== null) { │ │ │ │ + info = { │ │ │ │ + id: id, │ │ │ │ + data: this.json.data[id] │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - return lonlat │ │ │ │ + return info │ │ │ │ }, │ │ │ │ - getViewPortPxFromLonLat: function(lonlat) { │ │ │ │ - var viewPortPx = null; │ │ │ │ - if (this.mapObject != null && this.getMapObjectCenter() != null) { │ │ │ │ - var moLonLat = this.getMapObjectLonLatFromOLLonLat(lonlat); │ │ │ │ - var moPixel = this.getMapObjectPixelFromMapObjectLonLat(moLonLat); │ │ │ │ - viewPortPx = this.getOLPixelFromMapObjectPixel(moPixel) │ │ │ │ + getFeatureId: function(i, j) { │ │ │ │ + var id = null; │ │ │ │ + if (this.json) { │ │ │ │ + var resolution = this.utfgridResolution; │ │ │ │ + var row = Math.floor(j / resolution); │ │ │ │ + var col = Math.floor(i / resolution); │ │ │ │ + var charCode = this.json.grid[row].charCodeAt(col); │ │ │ │ + var index = this.indexFromCharCode(charCode); │ │ │ │ + var keys = this.json.keys; │ │ │ │ + if (!isNaN(index) && index in keys) { │ │ │ │ + id = keys[index] │ │ │ │ + } │ │ │ │ } │ │ │ │ - return viewPortPx │ │ │ │ + return id │ │ │ │ }, │ │ │ │ - getOLLonLatFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - var olLonLat = null; │ │ │ │ - if (moLonLat != null) { │ │ │ │ - var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); │ │ │ │ - var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); │ │ │ │ - olLonLat = new OpenLayers.LonLat(lon, lat) │ │ │ │ + indexFromCharCode: function(charCode) { │ │ │ │ + if (charCode >= 93) { │ │ │ │ + charCode-- │ │ │ │ } │ │ │ │ - return olLonLat │ │ │ │ - }, │ │ │ │ - getMapObjectLonLatFromOLLonLat: function(olLonLat) { │ │ │ │ - var moLatLng = null; │ │ │ │ - if (olLonLat != null) { │ │ │ │ - moLatLng = this.getMapObjectLonLatFromLonLat(olLonLat.lon, olLonLat.lat) │ │ │ │ + if (charCode >= 35) { │ │ │ │ + charCode-- │ │ │ │ } │ │ │ │ - return moLatLng │ │ │ │ + return charCode - 32 │ │ │ │ }, │ │ │ │ - getOLPixelFromMapObjectPixel: function(moPixel) { │ │ │ │ - var olPixel = null; │ │ │ │ - if (moPixel != null) { │ │ │ │ - var x = this.getXFromMapObjectPixel(moPixel); │ │ │ │ - var y = this.getYFromMapObjectPixel(moPixel); │ │ │ │ - olPixel = new OpenLayers.Pixel(x, y) │ │ │ │ + parseData: function(str) { │ │ │ │ + if (!this.format) { │ │ │ │ + this.format = new OpenLayers.Format.JSON │ │ │ │ } │ │ │ │ - return olPixel │ │ │ │ + this.json = this.format.read(str) │ │ │ │ }, │ │ │ │ - getMapObjectPixelFromOLPixel: function(olPixel) { │ │ │ │ - var moPixel = null; │ │ │ │ - if (olPixel != null) { │ │ │ │ - moPixel = this.getMapObjectPixelFromXY(olPixel.x, olPixel.y) │ │ │ │ - } │ │ │ │ - return moPixel │ │ │ │ + clear: function() { │ │ │ │ + this.json = null │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.EventPane" │ │ │ │ + CLASS_NAME: "OpenLayers.Tile.UTFGrid" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.FixedZoomLevels = OpenLayers.Class({ │ │ │ │ - initialize: function() {}, │ │ │ │ - initResolutions: function() { │ │ │ │ - var props = ["minZoomLevel", "maxZoomLevel", "numZoomLevels"]; │ │ │ │ - for (var i = 0, len = props.length; i < len; i++) { │ │ │ │ - var property = props[i]; │ │ │ │ - this[property] = this.options[property] != null ? this.options[property] : this.map[property] │ │ │ │ - } │ │ │ │ - if (this.minZoomLevel == null || this.minZoomLevel < this.MIN_ZOOM_LEVEL) { │ │ │ │ - this.minZoomLevel = this.MIN_ZOOM_LEVEL │ │ │ │ - } │ │ │ │ - var desiredZoomLevels; │ │ │ │ - var limitZoomLevels = this.MAX_ZOOM_LEVEL - this.minZoomLevel + 1; │ │ │ │ - if (this.options.numZoomLevels == null && this.options.maxZoomLevel != null || this.numZoomLevels == null && this.maxZoomLevel != null) { │ │ │ │ - desiredZoomLevels = this.maxZoomLevel - this.minZoomLevel + 1 │ │ │ │ - } else { │ │ │ │ - desiredZoomLevels = this.numZoomLevels │ │ │ │ - } │ │ │ │ - if (desiredZoomLevels != null) { │ │ │ │ - this.numZoomLevels = Math.min(desiredZoomLevels, limitZoomLevels) │ │ │ │ - } else { │ │ │ │ - this.numZoomLevels = limitZoomLevels │ │ │ │ - } │ │ │ │ - this.maxZoomLevel = this.minZoomLevel + this.numZoomLevels - 1; │ │ │ │ - if (this.RESOLUTIONS != null) { │ │ │ │ - var resolutionsIndex = 0; │ │ │ │ - this.resolutions = []; │ │ │ │ - for (var i = this.minZoomLevel; i <= this.maxZoomLevel; i++) { │ │ │ │ - this.resolutions[resolutionsIndex++] = this.RESOLUTIONS[i] │ │ │ │ +OpenLayers.Tile.Image.IFrame = { │ │ │ │ + useIFrame: null, │ │ │ │ + blankImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7", │ │ │ │ + draw: function() { │ │ │ │ + var draw = OpenLayers.Tile.Image.prototype.shouldDraw.call(this); │ │ │ │ + if (draw) { │ │ │ │ + var url = this.layer.getURL(this.bounds); │ │ │ │ + var usedIFrame = this.useIFrame; │ │ │ │ + this.useIFrame = this.maxGetUrlLength !== null && !this.layer.async && url.length > this.maxGetUrlLength; │ │ │ │ + var fromIFrame = usedIFrame && !this.useIFrame; │ │ │ │ + var toIFrame = !usedIFrame && this.useIFrame; │ │ │ │ + if (fromIFrame || toIFrame) { │ │ │ │ + if (this.imgDiv && this.imgDiv.parentNode === this.frame) { │ │ │ │ + this.frame.removeChild(this.imgDiv) │ │ │ │ + } │ │ │ │ + this.imgDiv = null; │ │ │ │ + if (fromIFrame) { │ │ │ │ + this.frame.removeChild(this.frame.firstChild) │ │ │ │ + } │ │ │ │ } │ │ │ │ - this.maxResolution = this.resolutions[0]; │ │ │ │ - this.minResolution = this.resolutions[this.resolutions.length - 1] │ │ │ │ } │ │ │ │ + return OpenLayers.Tile.Image.prototype.draw.apply(this, arguments) │ │ │ │ }, │ │ │ │ - getResolution: function() { │ │ │ │ - if (this.resolutions != null) { │ │ │ │ - return OpenLayers.Layer.prototype.getResolution.apply(this, arguments) │ │ │ │ - } else { │ │ │ │ - var resolution = null; │ │ │ │ - var viewSize = this.map.getSize(); │ │ │ │ - var extent = this.getExtent(); │ │ │ │ - if (viewSize != null && extent != null) { │ │ │ │ - resolution = Math.max(extent.getWidth() / viewSize.w, extent.getHeight() / viewSize.h) │ │ │ │ + getImage: function() { │ │ │ │ + if (this.useIFrame === true) { │ │ │ │ + if (!this.frame.childNodes.length) { │ │ │ │ + var eventPane = document.createElement("div"), │ │ │ │ + style = eventPane.style; │ │ │ │ + style.position = "absolute"; │ │ │ │ + style.width = "100%"; │ │ │ │ + style.height = "100%"; │ │ │ │ + style.zIndex = 1; │ │ │ │ + style.backgroundImage = "url(" + this.blankImageUrl + ")"; │ │ │ │ + this.frame.appendChild(eventPane) │ │ │ │ } │ │ │ │ - return resolution │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getExtent: function() { │ │ │ │ - var size = this.map.getSize(); │ │ │ │ - var tl = this.getLonLatFromViewPortPx({ │ │ │ │ - x: 0, │ │ │ │ - y: 0 │ │ │ │ - }); │ │ │ │ - var br = this.getLonLatFromViewPortPx({ │ │ │ │ - x: size.w, │ │ │ │ - y: size.h │ │ │ │ - }); │ │ │ │ - if (tl != null && br != null) { │ │ │ │ - return new OpenLayers.Bounds(tl.lon, br.lat, br.lon, tl.lat) │ │ │ │ + var id = this.id + "_iFrame", │ │ │ │ + iframe; │ │ │ │ + if (parseFloat(navigator.appVersion.split("MSIE")[1]) < 9) { │ │ │ │ + iframe = document.createElement('<iframe name="' + id + '">'); │ │ │ │ + iframe.style.backgroundColor = "#FFFFFF"; │ │ │ │ + iframe.style.filter = "chroma(color=#FFFFFF)" │ │ │ │ + } else { │ │ │ │ + iframe = document.createElement("iframe"); │ │ │ │ + iframe.style.backgroundColor = "transparent"; │ │ │ │ + iframe.name = id │ │ │ │ + } │ │ │ │ + iframe.scrolling = "no"; │ │ │ │ + iframe.marginWidth = "0px"; │ │ │ │ + iframe.marginHeight = "0px"; │ │ │ │ + iframe.frameBorder = "0"; │ │ │ │ + iframe.style.position = "absolute"; │ │ │ │ + iframe.style.width = "100%"; │ │ │ │ + iframe.style.height = "100%"; │ │ │ │ + if (this.layer.opacity < 1) { │ │ │ │ + OpenLayers.Util.modifyDOMElement(iframe, null, null, null, null, null, null, this.layer.opacity) │ │ │ │ + } │ │ │ │ + this.frame.appendChild(iframe); │ │ │ │ + this.imgDiv = iframe; │ │ │ │ + return iframe │ │ │ │ } else { │ │ │ │ - return null │ │ │ │ + return OpenLayers.Tile.Image.prototype.getImage.apply(this, arguments) │ │ │ │ } │ │ │ │ }, │ │ │ │ - getZoomForResolution: function(resolution) { │ │ │ │ - if (this.resolutions != null) { │ │ │ │ - return OpenLayers.Layer.prototype.getZoomForResolution.apply(this, arguments) │ │ │ │ - } else { │ │ │ │ - var extent = OpenLayers.Layer.prototype.getExtent.apply(this, []); │ │ │ │ - return this.getZoomForExtent(extent) │ │ │ │ + createRequestForm: function() { │ │ │ │ + var form = document.createElement("form"); │ │ │ │ + form.method = "POST"; │ │ │ │ + var cacheId = this.layer.params["_OLSALT"]; │ │ │ │ + cacheId = (cacheId ? cacheId + "_" : "") + this.bounds.toBBOX(); │ │ │ │ + form.action = OpenLayers.Util.urlAppend(this.layer.url, cacheId); │ │ │ │ + form.target = this.id + "_iFrame"; │ │ │ │ + var imageSize = this.layer.getImageSize(), │ │ │ │ + params = OpenLayers.Util.getParameters(this.url), │ │ │ │ + field; │ │ │ │ + for (var par in params) { │ │ │ │ + field = document.createElement("input"); │ │ │ │ + field.type = "hidden"; │ │ │ │ + field.name = par; │ │ │ │ + field.value = params[par]; │ │ │ │ + form.appendChild(field) │ │ │ │ } │ │ │ │ + return form │ │ │ │ }, │ │ │ │ - getOLZoomFromMapObjectZoom: function(moZoom) { │ │ │ │ - var zoom = null; │ │ │ │ - if (moZoom != null) { │ │ │ │ - zoom = moZoom - this.minZoomLevel; │ │ │ │ - if (this.map.baseLayer !== this) { │ │ │ │ - zoom = this.map.baseLayer.getZoomForResolution(this.getResolutionForZoom(zoom)) │ │ │ │ + setImgSrc: function(url) { │ │ │ │ + if (this.useIFrame === true) { │ │ │ │ + if (url) { │ │ │ │ + var form = this.createRequestForm(); │ │ │ │ + this.frame.appendChild(form); │ │ │ │ + form.submit(); │ │ │ │ + this.frame.removeChild(form) │ │ │ │ + } else if (this.imgDiv.parentNode === this.frame) { │ │ │ │ + this.frame.removeChild(this.imgDiv); │ │ │ │ + this.imgDiv = null │ │ │ │ } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Tile.Image.prototype.setImgSrc.apply(this, arguments) │ │ │ │ } │ │ │ │ - return zoom │ │ │ │ }, │ │ │ │ - getMapObjectZoomFromOLZoom: function(olZoom) { │ │ │ │ - var zoom = null; │ │ │ │ - if (olZoom != null) { │ │ │ │ - zoom = olZoom + this.minZoomLevel; │ │ │ │ - if (this.map.baseLayer !== this) { │ │ │ │ - zoom = this.getZoomForResolution(this.map.baseLayer.getResolutionForZoom(zoom)) │ │ │ │ - } │ │ │ │ + onImageLoad: function() { │ │ │ │ + OpenLayers.Tile.Image.prototype.onImageLoad.apply(this, arguments); │ │ │ │ + if (this.useIFrame === true) { │ │ │ │ + this.imgDiv.style.opacity = 1; │ │ │ │ + this.frame.style.opacity = this.layer.opacity │ │ │ │ } │ │ │ │ - return zoom │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.FixedZoomLevels" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.Google = OpenLayers.Class(OpenLayers.Layer.EventPane, OpenLayers.Layer.FixedZoomLevels, { │ │ │ │ - MIN_ZOOM_LEVEL: 0, │ │ │ │ - MAX_ZOOM_LEVEL: 21, │ │ │ │ - RESOLUTIONS: [1.40625, .703125, .3515625, .17578125, .087890625, .0439453125, .02197265625, .010986328125, .0054931640625, .00274658203125, .001373291015625, .0006866455078125, .00034332275390625, .000171661376953125, 858306884765625e-19, 4291534423828125e-20, 2145767211914062e-20, 1072883605957031e-20, 536441802978515e-20, 268220901489257e-20, 1341104507446289e-21, 6.705522537231445e-7], │ │ │ │ - type: null, │ │ │ │ - wrapDateLine: true, │ │ │ │ - sphericalMercator: false, │ │ │ │ - version: null, │ │ │ │ - initialize: function(name, options) { │ │ │ │ - options = options || {}; │ │ │ │ - if (!options.version) { │ │ │ │ - options.version = typeof GMap2 === "function" ? "2" : "3" │ │ │ │ - } │ │ │ │ - var mixin = OpenLayers.Layer.Google["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (mixin) { │ │ │ │ - OpenLayers.Util.applyDefaults(options, mixin) │ │ │ │ - } else { │ │ │ │ - throw "Unsupported Google Maps API version: " + options.version │ │ │ │ - } │ │ │ │ - OpenLayers.Util.applyDefaults(options, mixin.DEFAULTS); │ │ │ │ - if (options.maxExtent) { │ │ │ │ - options.maxExtent = options.maxExtent.clone() │ │ │ │ - } │ │ │ │ - OpenLayers.Layer.EventPane.prototype.initialize.apply(this, [name, options]); │ │ │ │ - OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, [name, options]); │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator); │ │ │ │ - this.initMercatorParameters() │ │ │ │ + createBackBuffer: function() { │ │ │ │ + var backBuffer; │ │ │ │ + if (this.useIFrame === false) { │ │ │ │ + backBuffer = OpenLayers.Tile.Image.prototype.createBackBuffer.call(this) │ │ │ │ } │ │ │ │ + return backBuffer │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, { │ │ │ │ + bounds: null, │ │ │ │ + div: null, │ │ │ │ + initialize: function(bounds, borderColor, borderWidth) { │ │ │ │ + this.bounds = bounds; │ │ │ │ + this.div = OpenLayers.Util.createDiv(); │ │ │ │ + this.div.style.overflow = "hidden"; │ │ │ │ + this.events = new OpenLayers.Events(this, this.div); │ │ │ │ + this.setBorder(borderColor, borderWidth) │ │ │ │ }, │ │ │ │ - clone: function() { │ │ │ │ - return new OpenLayers.Layer.Google(this.name, this.getOptions()) │ │ │ │ - }, │ │ │ │ - setVisibility: function(visible) { │ │ │ │ - var opacity = this.opacity == null ? 1 : this.opacity; │ │ │ │ - OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this, arguments); │ │ │ │ - this.setOpacity(opacity) │ │ │ │ + destroy: function() { │ │ │ │ + this.bounds = null; │ │ │ │ + this.div = null; │ │ │ │ + OpenLayers.Marker.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ - display: function(visible) { │ │ │ │ - if (!this._dragging) { │ │ │ │ - this.setGMapVisibility(visible) │ │ │ │ + setBorder: function(color, width) { │ │ │ │ + if (!color) { │ │ │ │ + color = "red" │ │ │ │ } │ │ │ │ - OpenLayers.Layer.EventPane.prototype.display.apply(this, arguments) │ │ │ │ + if (!width) { │ │ │ │ + width = 2 │ │ │ │ + } │ │ │ │ + this.div.style.border = width + "px solid " + color │ │ │ │ }, │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - this._dragging = dragging; │ │ │ │ - OpenLayers.Layer.EventPane.prototype.moveTo.apply(this, arguments); │ │ │ │ - delete this._dragging │ │ │ │ + draw: function(px, sz) { │ │ │ │ + OpenLayers.Util.modifyDOMElement(this.div, null, px, sz); │ │ │ │ + return this.div │ │ │ │ }, │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ - if (opacity !== this.opacity) { │ │ │ │ - if (this.map != null) { │ │ │ │ - this.map.events.triggerEvent("changelayer", { │ │ │ │ - layer: this, │ │ │ │ - property: "opacity" │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - this.opacity = opacity │ │ │ │ - } │ │ │ │ - if (this.getVisibility()) { │ │ │ │ - var container = this.getMapContainer(); │ │ │ │ - OpenLayers.Util.modifyDOMElement(container, null, null, null, null, null, null, opacity) │ │ │ │ + onScreen: function() { │ │ │ │ + var onScreen = false; │ │ │ │ + if (this.map) { │ │ │ │ + var screenBounds = this.map.getExtent(); │ │ │ │ + onScreen = screenBounds.containsBounds(this.bounds, true, true) │ │ │ │ + } │ │ │ │ + return onScreen │ │ │ │ + }, │ │ │ │ + display: function(display) { │ │ │ │ + this.div.style.display = display ? "" : "none" │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Marker.Box" │ │ │ │ +}); │ │ │ │ +OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ + hitDetection: true, │ │ │ │ + hitOverflow: 0, │ │ │ │ + canvas: null, │ │ │ │ + features: null, │ │ │ │ + pendingRedraw: false, │ │ │ │ + cachedSymbolBounds: {}, │ │ │ │ + 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") │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setExtent: function() { │ │ │ │ + OpenLayers.Renderer.prototype.setExtent.apply(this, arguments); │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + eraseGeometry: function(geometry, featureId) { │ │ │ │ + this.eraseFeatures(this.features[featureId][0]) │ │ │ │ + }, │ │ │ │ + supported: function() { │ │ │ │ + return OpenLayers.CANVAS_SUPPORTED │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawFeature: function(feature, style) { │ │ │ │ + var rendered; │ │ │ │ + if (feature.geometry) { │ │ │ │ + style = this.applyDefaultSymbolizer(style || feature.style); │ │ │ │ + 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) { │ │ │ │ + this.features[feature.id] = [feature, style] │ │ │ │ + } else { │ │ │ │ + delete this.features[feature.id] │ │ │ │ + } │ │ │ │ + this.pendingRedraw = true │ │ │ │ + } │ │ │ │ + if (this.pendingRedraw && !this.locked) { │ │ │ │ + this.redraw(); │ │ │ │ + this.pendingRedraw = false │ │ │ │ + } │ │ │ │ + return rendered │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 : -(.5 * width); │ │ │ │ + var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.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 / 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 │ │ │ │ + }, │ │ │ │ + drawNamedSymbol: function(geometry, style, featureId) { │ │ │ │ + var x, y, cx, cy, i, symbolBounds, scaling, angle; │ │ │ │ + var unscaledStrokeWidth; │ │ │ │ + var deg2rad = Math.PI / 180; │ │ │ │ + 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; │ │ │ │ + this.canvas.lineCap = "round"; │ │ │ │ + this.canvas.lineJoin = "round"; │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.lineCap = "round"; │ │ │ │ + this.hitContext.lineJoin = "round" │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + this.canvas.save(); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.save() │ │ │ │ + } │ │ │ │ + this.canvas.translate(p0, p1); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.translate(p0, p1) │ │ │ │ + } │ │ │ │ + angle = deg2rad * style.rotation; │ │ │ │ + if (!isNaN(angle)) { │ │ │ │ + this.canvas.rotate(angle); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.rotate(angle) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + scaling = 2 * style.pointRadius / Math.max(symbolBounds.getWidth(), symbolBounds.getHeight()); │ │ │ │ + this.canvas.scale(scaling, scaling); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.scale(scaling, scaling) │ │ │ │ + } │ │ │ │ + cx = symbolBounds.getCenterLonLat().lon; │ │ │ │ + cy = symbolBounds.getCenterLonLat().lat; │ │ │ │ + this.canvas.translate(-cx, -cy); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.translate(-cx, -cy) │ │ │ │ + } │ │ │ │ + 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") │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + featureIdToHex: function(featureId) { │ │ │ │ + var id = Number(featureId.split("_").pop()) + 1; │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + setHitContextStyle: function(type, featureId, symbolizer, strokeScaling) { │ │ │ │ + var hex = this.featureIdToHex(featureId); │ │ │ │ + if (type == "fill") { │ │ │ │ + this.hitContext.globalAlpha = 1; │ │ │ │ + this.hitContext.fillStyle = hex │ │ │ │ + } else if (type == "stroke") { │ │ │ │ + this.hitContext.globalAlpha = 1; │ │ │ │ + this.hitContext.strokeStyle = hex; │ │ │ │ + if (typeof strokeScaling === "undefined") { │ │ │ │ + this.hitContext.lineWidth = symbolizer.strokeWidth + 2 │ │ │ │ + } else { │ │ │ │ + if (!isNaN(strokeScaling)) { │ │ │ │ + this.hitContext.lineWidth = symbolizer.strokeWidth + 2 / strokeScaling │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.hitContext.globalAlpha = 0; │ │ │ │ + this.hitContext.lineWidth = 1 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawLineString: function(geometry, style, featureId) { │ │ │ │ + style = OpenLayers.Util.applyDefaults({ │ │ │ │ + fill: false │ │ │ │ + }, style); │ │ │ │ + this.drawLinearRing(geometry, style, featureId) │ │ │ │ + }, │ │ │ │ + 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") │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawPolygon: function(geometry, style, featureId) { │ │ │ │ + var components = geometry.components; │ │ │ │ + var len = components.length; │ │ │ │ + this.drawLinearRing(components[0], style, featureId); │ │ │ │ + for (var i = 1; i < len; ++i) { │ │ │ │ + this.canvas.globalCompositeOperation = "destination-out"; │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.globalCompositeOperation = "destination-out" │ │ │ │ + } │ │ │ │ + this.drawLinearRing(components[i], OpenLayers.Util.applyDefaults({ │ │ │ │ + stroke: false, │ │ │ │ + fillOpacity: 1 │ │ │ │ + }, 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawText: function(location, style) { │ │ │ │ + var pt = this.getLocalXY(location); │ │ │ │ + this.setCanvasStyle("reset"); │ │ │ │ + this.canvas.fillStyle = style.fontColor; │ │ │ │ + this.canvas.globalAlpha = style.fontOpacity || 1; │ │ │ │ + var fontStyle = [style.fontStyle ? style.fontStyle : "normal", "normal", 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) { │ │ │ │ + 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; │ │ │ │ + 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) { │ │ │ │ + this.canvas.mozTextStyle = fontStyle; │ │ │ │ + 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") │ │ │ │ + }, │ │ │ │ + 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] │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getFeatureIdFromEvent: function(evt) { │ │ │ │ + var featureId, feature; │ │ │ │ + if (this.hitDetection && this.root.style.display !== "none") { │ │ │ │ + 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) { │ │ │ │ + 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) {} │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return feature │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +OpenLayers.Renderer.Canvas.LABEL_ALIGN = { │ │ │ │ + l: "left", │ │ │ │ + r: "right", │ │ │ │ + t: "top", │ │ │ │ + b: "bottom" │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.Canvas.LABEL_FACTOR = { │ │ │ │ + l: 0, │ │ │ │ + r: -1, │ │ │ │ + t: 0, │ │ │ │ + b: -1 │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.Canvas.drawImageScaleFactor = null; │ │ │ │ +OpenLayers.ElementsIndexer = OpenLayers.Class({ │ │ │ │ + maxZIndex: null, │ │ │ │ + order: null, │ │ │ │ + indices: null, │ │ │ │ + compare: null, │ │ │ │ + initialize: function(yOrdering) { │ │ │ │ + this.compare = yOrdering ? OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER : OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER; │ │ │ │ + this.clear() │ │ │ │ + }, │ │ │ │ + insert: function(newNode) { │ │ │ │ + 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); │ │ │ │ + return this.getNextElement(rightIndex) │ │ │ │ + }, │ │ │ │ + remove: function(node) { │ │ │ │ + var nodeId = node.id; │ │ │ │ + var arrayIndex = OpenLayers.Util.indexOf(this.order, nodeId); │ │ │ │ + if (arrayIndex >= 0) { │ │ │ │ + this.order.splice(arrayIndex, 1); │ │ │ │ + delete this.indices[nodeId]; │ │ │ │ + if (this.order.length > 0) { │ │ │ │ + var lastId = this.order[this.order.length - 1]; │ │ │ │ + this.maxZIndex = this.indices[lastId] │ │ │ │ + } else { │ │ │ │ + this.maxZIndex = 0 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + clear: function() { │ │ │ │ + this.order = []; │ │ │ │ + this.indices = {}; │ │ │ │ + this.maxZIndex = 0 │ │ │ │ + }, │ │ │ │ + exists: function(node) { │ │ │ │ + return this.indices[node.id] != null │ │ │ │ + }, │ │ │ │ + getZIndex: function(node) { │ │ │ │ + return node._style.graphicZIndex │ │ │ │ + }, │ │ │ │ + determineZIndex: function(node) { │ │ │ │ + var zIndex = node._style.graphicZIndex; │ │ │ │ + if (zIndex == null) { │ │ │ │ + zIndex = this.maxZIndex; │ │ │ │ + node._style.graphicZIndex = zIndex │ │ │ │ + } else if (zIndex > this.maxZIndex) { │ │ │ │ + this.maxZIndex = zIndex │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +OpenLayers.ElementsIndexer.IndexingMethods = { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + Z_ORDER_DRAWING_ORDER: function(indexer, newNode, nextNode) { │ │ │ │ + var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(indexer, newNode, nextNode); │ │ │ │ + if (nextNode && returnVal == 0) { │ │ │ │ + returnVal = 1 │ │ │ │ + } │ │ │ │ + return returnVal │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ + rendererRoot: null, │ │ │ │ + root: null, │ │ │ │ + vectorRoot: null, │ │ │ │ + textRoot: null, │ │ │ │ + xmlns: null, │ │ │ │ + xOffset: 0, │ │ │ │ + indexer: null, │ │ │ │ + BACKGROUND_ID_SUFFIX: "_background", │ │ │ │ + LABEL_ID_SUFFIX: "_label", │ │ │ │ + LABEL_OUTLINE_SUFFIX: "_outline", │ │ │ │ + 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) │ │ │ │ } │ │ │ │ }, │ │ │ │ destroy: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.setGMapVisibility(false); │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache && cache.count <= 1) { │ │ │ │ - this.removeGMapElements() │ │ │ │ + this.clear(); │ │ │ │ + this.rendererRoot = null; │ │ │ │ + this.root = null; │ │ │ │ + this.xmlns = null; │ │ │ │ + OpenLayers.Renderer.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + clear: function() { │ │ │ │ + var child; │ │ │ │ + var root = this.vectorRoot; │ │ │ │ + if (root) { │ │ │ │ + while (child = root.firstChild) { │ │ │ │ + root.removeChild(child) │ │ │ │ } │ │ │ │ } │ │ │ │ - OpenLayers.Layer.EventPane.prototype.destroy.apply(this, arguments) │ │ │ │ + root = this.textRoot; │ │ │ │ + if (root) { │ │ │ │ + while (child = root.firstChild) { │ │ │ │ + root.removeChild(child) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.indexer) { │ │ │ │ + this.indexer.clear() │ │ │ │ + } │ │ │ │ }, │ │ │ │ - removeGMapElements: function() { │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - var container = this.mapObject && this.getMapContainer(); │ │ │ │ - if (container && container.parentNode) { │ │ │ │ - container.parentNode.removeChild(container) │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - var termsOfUse = cache.termsOfUse; │ │ │ │ - if (termsOfUse && termsOfUse.parentNode) { │ │ │ │ - termsOfUse.parentNode.removeChild(termsOfUse) │ │ │ │ + if (rightOfDateLine !== this.rightOfDateLine || resolutionChanged) { │ │ │ │ + coordSysUnchanged = false; │ │ │ │ + this.xOffset = rightOfDateLine === true ? world.getWidth() / resolution : 0 │ │ │ │ } │ │ │ │ - var poweredBy = cache.poweredBy; │ │ │ │ - if (poweredBy && poweredBy.parentNode) { │ │ │ │ - poweredBy.parentNode.removeChild(poweredBy) │ │ │ │ + this.rightOfDateLine = rightOfDateLine │ │ │ │ + } │ │ │ │ + return coordSysUnchanged │ │ │ │ + }, │ │ │ │ + getNodeType: function(geometry, style) {}, │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - if (this.mapObject && window.google && google.maps && google.maps.event && google.maps.event.clearListeners) { │ │ │ │ - google.maps.event.clearListeners(this.mapObject, "tilesloaded") │ │ │ │ + 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 │ │ │ │ }, │ │ │ │ - removeMap: function(map) { │ │ │ │ - if (this.visibility && this.mapObject) { │ │ │ │ - this.setGMapVisibility(false) │ │ │ │ + redrawNode: function(id, geometry, style, featureId) { │ │ │ │ + style = this.applyDefaultSymbolizer(style); │ │ │ │ + var node = this.nodeFactory(id, this.getNodeType(geometry, style)); │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[map.id]; │ │ │ │ - if (cache) { │ │ │ │ - if (cache.count <= 1) { │ │ │ │ - this.removeGMapElements(); │ │ │ │ - delete OpenLayers.Layer.Google.cache[map.id] │ │ │ │ + node = drawResult.node; │ │ │ │ + if (this.indexer) { │ │ │ │ + var insert = this.indexer.insert(node); │ │ │ │ + if (insert) { │ │ │ │ + this.vectorRoot.insertBefore(node, insert) │ │ │ │ } else { │ │ │ │ - --cache.count │ │ │ │ + this.vectorRoot.appendChild(node) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (node.parentNode !== this.vectorRoot) { │ │ │ │ + this.vectorRoot.appendChild(node) │ │ │ │ } │ │ │ │ } │ │ │ │ - delete this.termsOfUse; │ │ │ │ - delete this.poweredBy; │ │ │ │ - delete this.mapObject; │ │ │ │ - delete this.dragObject; │ │ │ │ - OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments) │ │ │ │ + this.postDraw(node); │ │ │ │ + return drawResult.complete │ │ │ │ }, │ │ │ │ - getOLBoundsFromMapObjectBounds: function(moBounds) { │ │ │ │ - var olBounds = null; │ │ │ │ - if (moBounds != null) { │ │ │ │ - var sw = moBounds.getSouthWest(); │ │ │ │ - var ne = moBounds.getNorthEast(); │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - sw = this.forwardMercator(sw.lng(), sw.lat()); │ │ │ │ - ne = this.forwardMercator(ne.lng(), ne.lat()) │ │ │ │ + redrawBackgroundNode: function(id, geometry, style, featureId) { │ │ │ │ + var backgroundStyle = OpenLayers.Util.extend({}, style); │ │ │ │ + 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; │ │ │ │ + backgroundStyle.backgroundGraphic = null; │ │ │ │ + backgroundStyle.backgroundXOffset = null; │ │ │ │ + backgroundStyle.backgroundYOffset = null; │ │ │ │ + backgroundStyle.backgroundGraphicZIndex = null; │ │ │ │ + return this.redrawNode(id + this.BACKGROUND_ID_SUFFIX, geometry, backgroundStyle, null) │ │ │ │ + }, │ │ │ │ + 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; │ │ │ │ + if (drawn != false) { │ │ │ │ + return { │ │ │ │ + node: this.setStyle(node, style, options, geometry), │ │ │ │ + complete: drawn │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + postDraw: function(node) {}, │ │ │ │ + drawPoint: function(node, geometry) {}, │ │ │ │ + drawLineString: function(node, geometry) {}, │ │ │ │ + drawLinearRing: function(node, geometry) {}, │ │ │ │ + drawPolygon: function(node, geometry) {}, │ │ │ │ + drawRectangle: function(node, geometry) {}, │ │ │ │ + drawCircle: function(node, geometry) {}, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getFeatureIdFromEvent: function(evt) { │ │ │ │ + var target = evt.target; │ │ │ │ + var useElement = target && target.correspondingUseElement; │ │ │ │ + var node = useElement ? useElement : target || evt.srcElement; │ │ │ │ + return node._featureId │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + bElem.parentNode.removeChild(bElem) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + nodeTypeCompare: function(node, type) {}, │ │ │ │ + createNode: function(type, id) {}, │ │ │ │ + moveRoot: function(renderer) { │ │ │ │ + var root = this.root; │ │ │ │ + if (renderer.root.parentNode == this.rendererRoot) { │ │ │ │ + root = renderer.root │ │ │ │ + } │ │ │ │ + root.parentNode.removeChild(root); │ │ │ │ + renderer.rendererRoot.appendChild(root) │ │ │ │ + }, │ │ │ │ + getRenderLayerId: function() { │ │ │ │ + return this.root.parentNode.parentNode.id │ │ │ │ + }, │ │ │ │ + isComplexSymbol: function(graphicName) { │ │ │ │ + return graphicName != "circle" && !!graphicName │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Renderer.Elements" │ │ │ │ +}); │ │ │ │ +OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ + xmlns: "http://www.w3.org/2000/svg", │ │ │ │ + xlinkns: "http://www.w3.org/1999/xlink", │ │ │ │ + MAX_PIXEL: 15e3, │ │ │ │ + translationParameters: null, │ │ │ │ + symbolMetrics: null, │ │ │ │ + initialize: function(containerID) { │ │ │ │ + if (!this.supported()) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + OpenLayers.Renderer.Elements.prototype.initialize.apply(this, arguments); │ │ │ │ + this.translationParameters = { │ │ │ │ + x: 0, │ │ │ │ + y: 0 │ │ │ │ + }; │ │ │ │ + this.symbolMetrics = {} │ │ │ │ + }, │ │ │ │ + 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")) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 (resolutionChanged) { │ │ │ │ + this.left = left; │ │ │ │ + this.top = top; │ │ │ │ + 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) { │ │ │ │ + this.setExtent(extent, true) │ │ │ │ + } │ │ │ │ + return coordSysUnchanged && inRange │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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); │ │ │ │ + var titleNode = node.getElementsByTagName("title"); │ │ │ │ + if (titleNode.length > 0) { │ │ │ │ + titleNode[0].firstChild.textContent = title │ │ │ │ } else { │ │ │ │ - sw = new OpenLayers.LonLat(sw.lng(), sw.lat()); │ │ │ │ - ne = new OpenLayers.LonLat(ne.lng(), ne.lat()) │ │ │ │ + var label = this.nodeFactory(null, "title"); │ │ │ │ + label.textContent = title; │ │ │ │ + node.appendChild(label) │ │ │ │ } │ │ │ │ - olBounds = new OpenLayers.Bounds(sw.lon, sw.lat, ne.lon, ne.lat) │ │ │ │ } │ │ │ │ - return olBounds │ │ │ │ + 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 : -(.5 * width); │ │ │ │ + var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.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)) { │ │ │ │ + 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; │ │ │ │ + var parent = node.parentNode; │ │ │ │ + var nextSibling = node.nextSibling; │ │ │ │ + if (parent) { │ │ │ │ + parent.removeChild(node) │ │ │ │ + } │ │ │ │ + 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); │ │ │ │ + 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"); │ │ │ │ + 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 │ │ │ │ }, │ │ │ │ - getWarningHTML: function() { │ │ │ │ - return OpenLayers.i18n("googleWarning") │ │ │ │ + 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, ",") │ │ │ │ + } │ │ │ │ }, │ │ │ │ - getMapObjectCenter: function() { │ │ │ │ - return this.mapObject.getCenter() │ │ │ │ + createNode: function(type, id) { │ │ │ │ + var node = document.createElementNS(this.xmlns, type); │ │ │ │ + if (id) { │ │ │ │ + node.setAttributeNS(null, "id", id) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - getMapObjectZoom: function() { │ │ │ │ - return this.mapObject.getZoom() │ │ │ │ + nodeTypeCompare: function(node, type) { │ │ │ │ + return type == node.nodeName │ │ │ │ }, │ │ │ │ - getLongitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - return this.sphericalMercator ? this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon : moLonLat.lng() │ │ │ │ + createRenderRoot: function() { │ │ │ │ + var svg = this.nodeFactory(this.container.id + "_svgRoot", "svg"); │ │ │ │ + svg.style.display = "block"; │ │ │ │ + return svg │ │ │ │ }, │ │ │ │ - getLatitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - var lat = this.sphericalMercator ? this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat : moLonLat.lat(); │ │ │ │ - return lat │ │ │ │ + createRoot: function(suffix) { │ │ │ │ + return this.nodeFactory(this.container.id + suffix, "g") │ │ │ │ }, │ │ │ │ - getXFromMapObjectPixel: function(moPixel) { │ │ │ │ - return moPixel.x │ │ │ │ + createDefs: function() { │ │ │ │ + var defs = this.nodeFactory(this.container.id + "_defs", "defs"); │ │ │ │ + this.rendererRoot.appendChild(defs); │ │ │ │ + return defs │ │ │ │ }, │ │ │ │ - getYFromMapObjectPixel: function(moPixel) { │ │ │ │ - return moPixel.y │ │ │ │ + drawPoint: function(node, geometry) { │ │ │ │ + return this.drawCircle(node, geometry, 1) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Google" │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawText: function(featureId, style, location) { │ │ │ │ + var drawOutline = !!style.labelOutlineWidth; │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 { │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getPosition: function(node) { │ │ │ │ + return { │ │ │ │ + x: parseFloat(node.getAttributeNS(null, "cx")), │ │ │ │ + y: parseFloat(node.getAttributeNS(null, "cy")) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + importSymbol: function(graphicName) { │ │ │ │ + if (!this.defs) { │ │ │ │ + this.defs = this.createDefs() │ │ │ │ + } │ │ │ │ + var id = this.container.id + "-" + graphicName; │ │ │ │ + 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(); │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.Google.cache = {}; │ │ │ │ -OpenLayers.Layer.Google.v2 = { │ │ │ │ - termsOfUse: null, │ │ │ │ - poweredBy: null, │ │ │ │ - dragObject: null, │ │ │ │ - loadMapObject: function() { │ │ │ │ - if (!this.type) { │ │ │ │ - this.type = G_NORMAL_MAP │ │ │ │ +OpenLayers.Renderer.SVG.LABEL_ALIGN = { │ │ │ │ + l: "start", │ │ │ │ + r: "end", │ │ │ │ + b: "bottom", │ │ │ │ + t: "hanging" │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.SVG.LABEL_VSHIFT = { │ │ │ │ + t: "-70%", │ │ │ │ + b: "0" │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.SVG.LABEL_VFACTOR = { │ │ │ │ + t: 0, │ │ │ │ + b: -1 │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.SVG.preventDefault = function(e) { │ │ │ │ + OpenLayers.Event.preventDefault(e) │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ + xmlns: "urn:schemas-microsoft-com:vml", │ │ │ │ + symbolCache: {}, │ │ │ │ + offset: null, │ │ │ │ + initialize: function(containerID) { │ │ │ │ + if (!this.supported()) { │ │ │ │ + return │ │ │ │ } │ │ │ │ - var mapObject, termsOfUse, poweredBy; │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (!document.namespaces.olv) { │ │ │ │ + document.namespaces.add("olv", this.xmlns); │ │ │ │ + var style = document.createStyleSheet(); │ │ │ │ + var shapes = ["shape", "rect", "oval", "fill", "stroke", "imagedata", "group", "textbox"]; │ │ │ │ + for (var i = 0, len = shapes.length; i < len; i++) { │ │ │ │ + style.addRule("olv\\:" + shapes[i], "behavior: url(#default#VML); " + "position: absolute; display: inline-block;") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + OpenLayers.Renderer.Elements.prototype.initialize.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + supported: function() { │ │ │ │ + return !!document.namespaces │ │ │ │ + }, │ │ │ │ + setExtent: function(extent, resolutionChanged) { │ │ │ │ + var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var left = extent.left / resolution | 0; │ │ │ │ + var top = extent.top / resolution - this.size.h | 0; │ │ │ │ + if (resolutionChanged || !this.offset) { │ │ │ │ + this.offset = { │ │ │ │ + x: left, │ │ │ │ + y: top │ │ │ │ + }; │ │ │ │ + left = 0; │ │ │ │ + top = 0 │ │ │ │ + } else { │ │ │ │ + left = left - this.offset.x; │ │ │ │ + top = top - this.offset.y │ │ │ │ + } │ │ │ │ + var org = left - this.xOffset + " " + top; │ │ │ │ + this.root.coordorigin = org; │ │ │ │ + var roots = [this.root, this.vectorRoot, this.textRoot]; │ │ │ │ + var root; │ │ │ │ + for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ + root = roots[i]; │ │ │ │ + var size = this.size.w + " " + this.size.h; │ │ │ │ + root.coordsize = size │ │ │ │ + } │ │ │ │ + this.root.style.flip = "y"; │ │ │ │ + return coordSysUnchanged │ │ │ │ + }, │ │ │ │ + setSize: function(size) { │ │ │ │ + OpenLayers.Renderer.prototype.setSize.apply(this, arguments); │ │ │ │ + var roots = [this.rendererRoot, this.root, this.vectorRoot, this.textRoot]; │ │ │ │ + var w = this.size.w + "px"; │ │ │ │ + var h = this.size.h + "px"; │ │ │ │ + var root; │ │ │ │ + for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ + root = roots[i]; │ │ │ │ + root.style.width = w; │ │ │ │ + root.style.height = h │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getNodeType: function(geometry, style) { │ │ │ │ + var nodeType = null; │ │ │ │ + switch (geometry.CLASS_NAME) { │ │ │ │ + case "OpenLayers.Geometry.Point": │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + nodeType = "olv:rect" │ │ │ │ + } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ + nodeType = "olv:shape" │ │ │ │ + } else { │ │ │ │ + nodeType = "olv:oval" │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case "OpenLayers.Geometry.Rectangle": │ │ │ │ + nodeType = "olv:rect"; │ │ │ │ + break; │ │ │ │ + case "OpenLayers.Geometry.LineString": │ │ │ │ + case "OpenLayers.Geometry.LinearRing": │ │ │ │ + case "OpenLayers.Geometry.Polygon": │ │ │ │ + case "OpenLayers.Geometry.Curve": │ │ │ │ + nodeType = "olv:shape"; │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + break │ │ │ │ + } │ │ │ │ + return nodeType │ │ │ │ + }, │ │ │ │ + setStyle: function(node, style, options, geometry) { │ │ │ │ + style = style || node._style; │ │ │ │ + options = options || node._options; │ │ │ │ + var fillColor = style.fillColor; │ │ │ │ + var title = style.title || style.graphicTitle; │ │ │ │ + if (title) { │ │ │ │ + node.title = title │ │ │ │ + } │ │ │ │ + if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + options.isFilled = true; │ │ │ │ + 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 resolution = this.getResolution(); │ │ │ │ + var xOffset = style.graphicXOffset != undefined ? style.graphicXOffset : -(.5 * width); │ │ │ │ + var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.5 * height); │ │ │ │ + node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x + xOffset | 0) + "px"; │ │ │ │ + node.style.top = (geometry.y / resolution - this.offset.y - (yOffset + height) | 0) + "px"; │ │ │ │ + node.style.width = width + "px"; │ │ │ │ + node.style.height = height + "px"; │ │ │ │ + node.style.flip = "y"; │ │ │ │ + fillColor = "none"; │ │ │ │ + options.isStroked = false │ │ │ │ + } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ + var cache = this.importSymbol(style.graphicName); │ │ │ │ + node.path = cache.path; │ │ │ │ + node.coordorigin = cache.left + "," + cache.bottom; │ │ │ │ + var size = cache.size; │ │ │ │ + node.coordsize = size + "," + size; │ │ │ │ + this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ + node.style.flip = "y" │ │ │ │ + } else { │ │ │ │ + this.drawCircle(node, geometry, style.pointRadius) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (options.isFilled) { │ │ │ │ + node.fillcolor = fillColor │ │ │ │ + } else { │ │ │ │ + node.filled = "false" │ │ │ │ + } │ │ │ │ + var fills = node.getElementsByTagName("fill"); │ │ │ │ + var fill = fills.length == 0 ? null : fills[0]; │ │ │ │ + if (!options.isFilled) { │ │ │ │ + if (fill) { │ │ │ │ + node.removeChild(fill) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (!fill) { │ │ │ │ + fill = this.createNode("olv:fill", node.id + "_fill") │ │ │ │ + } │ │ │ │ + fill.opacity = style.fillOpacity; │ │ │ │ + if (node._geometryClass === "OpenLayers.Geometry.Point" && style.externalGraphic) { │ │ │ │ + if (style.graphicOpacity) { │ │ │ │ + fill.opacity = style.graphicOpacity │ │ │ │ + } │ │ │ │ + fill.src = style.externalGraphic; │ │ │ │ + fill.type = "frame"; │ │ │ │ + if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ + fill.aspect = "atmost" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (fill.parentNode != node) { │ │ │ │ + node.appendChild(fill) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var rotation = style.rotation; │ │ │ │ + if (rotation !== undefined || node._rotation !== undefined) { │ │ │ │ + node._rotation = rotation; │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ + fill.opacity = 0 │ │ │ │ + } else if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ + node.style.rotation = rotation || 0 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var strokes = node.getElementsByTagName("stroke"); │ │ │ │ + var stroke = strokes.length == 0 ? null : strokes[0]; │ │ │ │ + if (!options.isStroked) { │ │ │ │ + node.stroked = false; │ │ │ │ + if (stroke) { │ │ │ │ + stroke.on = false │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (!stroke) { │ │ │ │ + stroke = this.createNode("olv:stroke", node.id + "_stroke"); │ │ │ │ + node.appendChild(stroke) │ │ │ │ + } │ │ │ │ + stroke.on = true; │ │ │ │ + stroke.color = style.strokeColor; │ │ │ │ + stroke.weight = style.strokeWidth + "px"; │ │ │ │ + stroke.opacity = style.strokeOpacity; │ │ │ │ + stroke.endcap = style.strokeLinecap == "butt" ? "flat" : style.strokeLinecap || "round"; │ │ │ │ + if (style.strokeDashstyle) { │ │ │ │ + stroke.dashstyle = this.dashStyle(style) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ + node.style.cursor = style.cursor │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + graphicRotate: function(node, xOffset, yOffset, style) { │ │ │ │ + var style = style || node._style; │ │ │ │ + var rotation = style.rotation || 0; │ │ │ │ + var aspectRatio, size; │ │ │ │ + if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ + var img = new Image; │ │ │ │ + img.onreadystatechange = OpenLayers.Function.bind(function() { │ │ │ │ + if (img.readyState == "complete" || img.readyState == "interactive") { │ │ │ │ + aspectRatio = img.width / img.height; │ │ │ │ + size = Math.max(style.pointRadius * 2, style.graphicWidth || 0, style.graphicHeight || 0); │ │ │ │ + xOffset = xOffset * aspectRatio; │ │ │ │ + style.graphicWidth = size * aspectRatio; │ │ │ │ + style.graphicHeight = size; │ │ │ │ + this.graphicRotate(node, xOffset, yOffset, style) │ │ │ │ + } │ │ │ │ + }, this); │ │ │ │ + img.src = style.externalGraphic; │ │ │ │ + return │ │ │ │ + } else { │ │ │ │ + size = Math.max(style.graphicWidth, style.graphicHeight); │ │ │ │ + aspectRatio = style.graphicWidth / style.graphicHeight │ │ │ │ + } │ │ │ │ + var width = Math.round(style.graphicWidth || size * aspectRatio); │ │ │ │ + var height = Math.round(style.graphicHeight || size); │ │ │ │ + node.style.width = width + "px"; │ │ │ │ + node.style.height = height + "px"; │ │ │ │ + var image = document.getElementById(node.id + "_image"); │ │ │ │ + if (!image) { │ │ │ │ + image = this.createNode("olv:imagedata", node.id + "_image"); │ │ │ │ + node.appendChild(image) │ │ │ │ + } │ │ │ │ + image.style.width = width + "px"; │ │ │ │ + image.style.height = height + "px"; │ │ │ │ + image.src = style.externalGraphic; │ │ │ │ + image.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + "src='', sizingMethod='scale')"; │ │ │ │ + var rot = rotation * Math.PI / 180; │ │ │ │ + var sintheta = Math.sin(rot); │ │ │ │ + var costheta = Math.cos(rot); │ │ │ │ + var filter = "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta + ",M12=" + -sintheta + ",M21=" + sintheta + ",M22=" + costheta + ",SizingMethod='auto expand')\n"; │ │ │ │ + var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ + if (opacity && opacity != 1) { │ │ │ │ + filter += "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + opacity + ")\n" │ │ │ │ + } │ │ │ │ + node.style.filter = filter; │ │ │ │ + var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset); │ │ │ │ + var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry(); │ │ │ │ + imgBox.rotate(style.rotation, centerPoint); │ │ │ │ + var imgBounds = imgBox.getBounds(); │ │ │ │ + node.style.left = Math.round(parseInt(node.style.left) + imgBounds.left) + "px"; │ │ │ │ + node.style.top = Math.round(parseInt(node.style.top) - imgBounds.bottom) + "px" │ │ │ │ + }, │ │ │ │ + postDraw: function(node) { │ │ │ │ + node.style.visibility = "visible"; │ │ │ │ + var fillColor = node._style.fillColor; │ │ │ │ + var strokeColor = node._style.strokeColor; │ │ │ │ + if (fillColor == "none" && node.fillcolor != fillColor) { │ │ │ │ + node.fillcolor = fillColor │ │ │ │ + } │ │ │ │ + if (strokeColor == "none" && node.strokecolor != strokeColor) { │ │ │ │ + node.strokecolor = strokeColor │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setNodeDimension: function(node, geometry) { │ │ │ │ + var bbox = geometry.getBounds(); │ │ │ │ + if (bbox) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var scaledBox = new OpenLayers.Bounds((bbox.left - this.featureDx) / resolution - this.offset.x | 0, bbox.bottom / resolution - this.offset.y | 0, (bbox.right - this.featureDx) / resolution - this.offset.x | 0, bbox.top / resolution - this.offset.y | 0); │ │ │ │ + node.style.left = scaledBox.left + "px"; │ │ │ │ + node.style.top = scaledBox.top + "px"; │ │ │ │ + node.style.width = scaledBox.getWidth() + "px"; │ │ │ │ + node.style.height = scaledBox.getHeight() + "px"; │ │ │ │ + node.coordorigin = scaledBox.left + " " + scaledBox.top; │ │ │ │ + node.coordsize = scaledBox.getWidth() + " " + scaledBox.getHeight() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + dashStyle: function(style) { │ │ │ │ + var dash = style.strokeDashstyle; │ │ │ │ + switch (dash) { │ │ │ │ + case "solid": │ │ │ │ + case "dot": │ │ │ │ + case "dash": │ │ │ │ + case "dashdot": │ │ │ │ + case "longdash": │ │ │ │ + case "longdashdot": │ │ │ │ + return dash; │ │ │ │ + default: │ │ │ │ + var parts = dash.split(/[ ,]/); │ │ │ │ + if (parts.length == 2) { │ │ │ │ + if (1 * parts[0] >= 2 * parts[1]) { │ │ │ │ + return "longdash" │ │ │ │ + } │ │ │ │ + return parts[0] == 1 || parts[1] == 1 ? "dot" : "dash" │ │ │ │ + } else if (parts.length == 4) { │ │ │ │ + return 1 * parts[0] >= 2 * parts[1] ? "longdashdot" : "dashdot" │ │ │ │ + } │ │ │ │ + return "solid" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + createNode: function(type, id) { │ │ │ │ + var node = document.createElement(type); │ │ │ │ + if (id) { │ │ │ │ + node.id = id │ │ │ │ + } │ │ │ │ + node.unselectable = "on"; │ │ │ │ + node.onselectstart = OpenLayers.Function.False; │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + nodeTypeCompare: function(node, type) { │ │ │ │ + var subType = type; │ │ │ │ + var splitIndex = subType.indexOf(":"); │ │ │ │ + if (splitIndex != -1) { │ │ │ │ + subType = subType.substr(splitIndex + 1) │ │ │ │ + } │ │ │ │ + var nodeName = node.nodeName; │ │ │ │ + splitIndex = nodeName.indexOf(":"); │ │ │ │ + if (splitIndex != -1) { │ │ │ │ + nodeName = nodeName.substr(splitIndex + 1) │ │ │ │ + } │ │ │ │ + return subType == nodeName │ │ │ │ + }, │ │ │ │ + createRenderRoot: function() { │ │ │ │ + return this.nodeFactory(this.container.id + "_vmlRoot", "div") │ │ │ │ + }, │ │ │ │ + createRoot: function(suffix) { │ │ │ │ + return this.nodeFactory(this.container.id + suffix, "olv:group") │ │ │ │ + }, │ │ │ │ + drawPoint: function(node, geometry) { │ │ │ │ + return this.drawCircle(node, geometry, 1) │ │ │ │ + }, │ │ │ │ + drawCircle: function(node, geometry, radius) { │ │ │ │ + if (!isNaN(geometry.x) && !isNaN(geometry.y)) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x | 0) - radius + "px"; │ │ │ │ + node.style.top = (geometry.y / resolution - this.offset.y | 0) - radius + "px"; │ │ │ │ + var diameter = radius * 2; │ │ │ │ + node.style.width = diameter + "px"; │ │ │ │ + node.style.height = diameter + "px"; │ │ │ │ + return node │ │ │ │ + } │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + drawLineString: function(node, geometry) { │ │ │ │ + return this.drawLine(node, geometry, false) │ │ │ │ + }, │ │ │ │ + drawLinearRing: function(node, geometry) { │ │ │ │ + return this.drawLine(node, geometry, true) │ │ │ │ + }, │ │ │ │ + drawLine: function(node, geometry, closeLine) { │ │ │ │ + this.setNodeDimension(node, geometry); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var numComponents = geometry.components.length; │ │ │ │ + var parts = new Array(numComponents); │ │ │ │ + var comp, x, y; │ │ │ │ + for (var i = 0; i < numComponents; i++) { │ │ │ │ + comp = geometry.components[i]; │ │ │ │ + x = (comp.x - this.featureDx) / resolution - this.offset.x | 0; │ │ │ │ + y = comp.y / resolution - this.offset.y | 0; │ │ │ │ + parts[i] = " " + x + "," + y + " l " │ │ │ │ + } │ │ │ │ + var end = closeLine ? " x e" : " e"; │ │ │ │ + node.path = "m" + parts.join("") + end; │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + drawPolygon: function(node, geometry) { │ │ │ │ + this.setNodeDimension(node, geometry); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var path = []; │ │ │ │ + var j, jj, points, area, first, second, i, ii, comp, pathComp, x, y; │ │ │ │ + for (j = 0, jj = geometry.components.length; j < jj; j++) { │ │ │ │ + path.push("m"); │ │ │ │ + points = geometry.components[j].components; │ │ │ │ + area = j === 0; │ │ │ │ + first = null; │ │ │ │ + second = null; │ │ │ │ + for (i = 0, ii = points.length; i < ii; i++) { │ │ │ │ + comp = points[i]; │ │ │ │ + x = (comp.x - this.featureDx) / resolution - this.offset.x | 0; │ │ │ │ + y = comp.y / resolution - this.offset.y | 0; │ │ │ │ + pathComp = " " + x + "," + y; │ │ │ │ + path.push(pathComp); │ │ │ │ + if (i == 0) { │ │ │ │ + path.push(" l") │ │ │ │ + } │ │ │ │ + if (!area) { │ │ │ │ + if (!first) { │ │ │ │ + first = pathComp │ │ │ │ + } else if (first != pathComp) { │ │ │ │ + if (!second) { │ │ │ │ + second = pathComp │ │ │ │ + } else if (second != pathComp) { │ │ │ │ + area = true │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + path.push(area ? " x " : " ") │ │ │ │ + } │ │ │ │ + path.push("e"); │ │ │ │ + node.path = path.join(""); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + drawRectangle: function(node, geometry) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x | 0) + "px"; │ │ │ │ + node.style.top = (geometry.y / resolution - this.offset.y | 0) + "px"; │ │ │ │ + node.style.width = (geometry.width / resolution | 0) + "px"; │ │ │ │ + node.style.height = (geometry.height / resolution | 0) + "px"; │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + drawText: function(featureId, style, location) { │ │ │ │ + var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect"); │ │ │ │ + var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox"); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + label.style.left = ((location.x - this.featureDx) / resolution - this.offset.x | 0) + "px"; │ │ │ │ + label.style.top = (location.y / resolution - this.offset.y | 0) + "px"; │ │ │ │ + label.style.flip = "y"; │ │ │ │ + textbox.innerText = style.label; │ │ │ │ + if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ + textbox.style.cursor = style.cursor │ │ │ │ + } │ │ │ │ + if (style.fontColor) { │ │ │ │ + textbox.style.color = style.fontColor │ │ │ │ + } │ │ │ │ + if (style.fontOpacity) { │ │ │ │ + textbox.style.filter = "alpha(opacity=" + style.fontOpacity * 100 + ")" │ │ │ │ + } │ │ │ │ + if (style.fontFamily) { │ │ │ │ + textbox.style.fontFamily = style.fontFamily │ │ │ │ + } │ │ │ │ + if (style.fontSize) { │ │ │ │ + textbox.style.fontSize = style.fontSize │ │ │ │ + } │ │ │ │ + if (style.fontWeight) { │ │ │ │ + textbox.style.fontWeight = style.fontWeight │ │ │ │ + } │ │ │ │ + if (style.fontStyle) { │ │ │ │ + textbox.style.fontStyle = style.fontStyle │ │ │ │ + } │ │ │ │ + if (style.labelSelect === true) { │ │ │ │ + label._featureId = featureId; │ │ │ │ + textbox._featureId = featureId; │ │ │ │ + textbox._geometry = location; │ │ │ │ + textbox._geometryClass = location.CLASS_NAME │ │ │ │ + } │ │ │ │ + textbox.style.whiteSpace = "nowrap"; │ │ │ │ + textbox.inset = "1px,0px,0px,0px"; │ │ │ │ + if (!label.parentNode) { │ │ │ │ + label.appendChild(textbox); │ │ │ │ + this.textRoot.appendChild(label) │ │ │ │ + } │ │ │ │ + var align = style.labelAlign || "cm"; │ │ │ │ + if (align.length == 1) { │ │ │ │ + align += "m" │ │ │ │ + } │ │ │ │ + var xshift = textbox.clientWidth * OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0, 1)]; │ │ │ │ + var yshift = textbox.clientHeight * OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1, 1)]; │ │ │ │ + label.style.left = parseInt(label.style.left) - xshift - 1 + "px"; │ │ │ │ + label.style.top = parseInt(label.style.top) + yshift + "px" │ │ │ │ + }, │ │ │ │ + moveRoot: function(renderer) { │ │ │ │ + var layer = this.map.getLayer(renderer.container.id); │ │ │ │ + if (layer instanceof OpenLayers.Layer.Vector.RootContainer) { │ │ │ │ + layer = this.map.getLayer(this.container.id) │ │ │ │ + } │ │ │ │ + layer && layer.renderer.clear(); │ │ │ │ + OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments); │ │ │ │ + layer && layer.redraw() │ │ │ │ + }, │ │ │ │ + importSymbol: function(graphicName) { │ │ │ │ + var id = this.container.id + "-" + graphicName; │ │ │ │ + var cache = this.symbolCache[id]; │ │ │ │ if (cache) { │ │ │ │ - mapObject = cache.mapObject; │ │ │ │ - termsOfUse = cache.termsOfUse; │ │ │ │ - poweredBy = cache.poweredBy; │ │ │ │ - ++cache.count │ │ │ │ + return cache │ │ │ │ + } │ │ │ │ + var symbol = OpenLayers.Renderer.symbol[graphicName]; │ │ │ │ + if (!symbol) { │ │ │ │ + throw new Error(graphicName + " is not a valid symbol name") │ │ │ │ + } │ │ │ │ + var symbolExtent = new OpenLayers.Bounds(Number.MAX_VALUE, Number.MAX_VALUE, 0, 0); │ │ │ │ + var pathitems = ["m"]; │ │ │ │ + for (var i = 0; i < symbol.length; i = i + 2) { │ │ │ │ + var x = symbol[i]; │ │ │ │ + var 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); │ │ │ │ + pathitems.push(x); │ │ │ │ + pathitems.push(y); │ │ │ │ + if (i == 0) { │ │ │ │ + pathitems.push("l") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + pathitems.push("x e"); │ │ │ │ + var path = pathitems.join(" "); │ │ │ │ + var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2; │ │ │ │ + if (diff > 0) { │ │ │ │ + symbolExtent.bottom = symbolExtent.bottom - diff; │ │ │ │ + symbolExtent.top = symbolExtent.top + diff │ │ │ │ } else { │ │ │ │ - var container = this.map.viewPortDiv; │ │ │ │ - var div = document.createElement("div"); │ │ │ │ - div.id = this.map.id + "_GMap2Container"; │ │ │ │ - div.style.position = "absolute"; │ │ │ │ - div.style.width = "100%"; │ │ │ │ - div.style.height = "100%"; │ │ │ │ - container.appendChild(div); │ │ │ │ - try { │ │ │ │ - mapObject = new GMap2(div); │ │ │ │ - termsOfUse = div.lastChild; │ │ │ │ - container.appendChild(termsOfUse); │ │ │ │ - termsOfUse.style.zIndex = "1100"; │ │ │ │ - termsOfUse.style.right = ""; │ │ │ │ - termsOfUse.style.bottom = ""; │ │ │ │ - termsOfUse.className = "olLayerGoogleCopyright"; │ │ │ │ - poweredBy = div.lastChild; │ │ │ │ - container.appendChild(poweredBy); │ │ │ │ - poweredBy.style.zIndex = "1100"; │ │ │ │ - poweredBy.style.right = ""; │ │ │ │ - poweredBy.style.bottom = ""; │ │ │ │ - poweredBy.className = "olLayerGooglePoweredBy gmnoprint" │ │ │ │ - } catch (e) { │ │ │ │ - throw e │ │ │ │ + symbolExtent.left = symbolExtent.left + diff; │ │ │ │ + symbolExtent.right = symbolExtent.right - diff │ │ │ │ + } │ │ │ │ + cache = { │ │ │ │ + path: path, │ │ │ │ + size: symbolExtent.getWidth(), │ │ │ │ + left: symbolExtent.left, │ │ │ │ + bottom: symbolExtent.bottom │ │ │ │ + }; │ │ │ │ + this.symbolCache[id] = cache; │ │ │ │ + return cache │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Renderer.VML" │ │ │ │ +}); │ │ │ │ +OpenLayers.Renderer.VML.LABEL_SHIFT = { │ │ │ │ + l: 0, │ │ │ │ + c: .5, │ │ │ │ + r: 1, │ │ │ │ + t: 0, │ │ │ │ + m: .5, │ │ │ │ + b: 1 │ │ │ │ +}; │ │ │ │ +OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + distance: 20, │ │ │ │ + threshold: null, │ │ │ │ + features: null, │ │ │ │ + clusters: null, │ │ │ │ + clustering: false, │ │ │ │ + resolution: null, │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + beforefeaturesadded: this.cacheFeatures, │ │ │ │ + featuresremoved: this.clearCache, │ │ │ │ + moveend: this.cluster, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.clearCache(); │ │ │ │ + this.layer.events.un({ │ │ │ │ + beforefeaturesadded: this.cacheFeatures, │ │ │ │ + featuresremoved: this.clearCache, │ │ │ │ + moveend: this.cluster, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + return deactivated │ │ │ │ + }, │ │ │ │ + cacheFeatures: function(event) { │ │ │ │ + var propagate = true; │ │ │ │ + if (!this.clustering) { │ │ │ │ + this.clearCache(); │ │ │ │ + this.features = event.features; │ │ │ │ + this.cluster(); │ │ │ │ + propagate = false │ │ │ │ + } │ │ │ │ + return propagate │ │ │ │ + }, │ │ │ │ + clearCache: function() { │ │ │ │ + if (!this.clustering) { │ │ │ │ + this.features = null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + cluster: function(event) { │ │ │ │ + if ((!event || event.zoomChanged) && this.features) { │ │ │ │ + var resolution = this.layer.map.getResolution(); │ │ │ │ + if (resolution != this.resolution || !this.clustersExist()) { │ │ │ │ + this.resolution = resolution; │ │ │ │ + var clusters = []; │ │ │ │ + var feature, clustered, cluster; │ │ │ │ + for (var i = 0; i < this.features.length; ++i) { │ │ │ │ + feature = this.features[i]; │ │ │ │ + if (feature.geometry) { │ │ │ │ + clustered = false; │ │ │ │ + for (var j = clusters.length - 1; j >= 0; --j) { │ │ │ │ + cluster = clusters[j]; │ │ │ │ + if (this.shouldCluster(cluster, feature)) { │ │ │ │ + this.addToCluster(cluster, feature); │ │ │ │ + clustered = true; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (!clustered) { │ │ │ │ + clusters.push(this.createCluster(this.features[i])) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.clustering = true; │ │ │ │ + this.layer.removeAllFeatures(); │ │ │ │ + this.clustering = false; │ │ │ │ + if (clusters.length > 0) { │ │ │ │ + if (this.threshold > 1) { │ │ │ │ + var clone = clusters.slice(); │ │ │ │ + clusters = []; │ │ │ │ + var candidate; │ │ │ │ + for (var i = 0, len = clone.length; i < len; ++i) { │ │ │ │ + candidate = clone[i]; │ │ │ │ + if (candidate.attributes.count < this.threshold) { │ │ │ │ + Array.prototype.push.apply(clusters, candidate.cluster) │ │ │ │ + } else { │ │ │ │ + clusters.push(candidate) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.clustering = true; │ │ │ │ + this.layer.addFeatures(clusters); │ │ │ │ + this.clustering = false │ │ │ │ + } │ │ │ │ + this.clusters = clusters │ │ │ │ } │ │ │ │ - OpenLayers.Layer.Google.cache[this.map.id] = { │ │ │ │ - mapObject: mapObject, │ │ │ │ - termsOfUse: termsOfUse, │ │ │ │ - poweredBy: poweredBy, │ │ │ │ - count: 1 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + clustersExist: function() { │ │ │ │ + var exist = false; │ │ │ │ + if (this.clusters && this.clusters.length > 0 && this.clusters.length == this.layer.features.length) { │ │ │ │ + exist = true; │ │ │ │ + for (var i = 0; i < this.clusters.length; ++i) { │ │ │ │ + if (this.clusters[i] != this.layer.features[i]) { │ │ │ │ + exist = false; │ │ │ │ + break │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ - this.mapObject = mapObject; │ │ │ │ - this.termsOfUse = termsOfUse; │ │ │ │ - this.poweredBy = poweredBy; │ │ │ │ - if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(), this.type) === -1) { │ │ │ │ - this.mapObject.addMapType(this.type) │ │ │ │ + return exist │ │ │ │ + }, │ │ │ │ + shouldCluster: function(cluster, feature) { │ │ │ │ + var cc = cluster.geometry.getBounds().getCenterLonLat(); │ │ │ │ + var fc = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ + var distance = Math.sqrt(Math.pow(cc.lon - fc.lon, 2) + Math.pow(cc.lat - fc.lat, 2)) / this.resolution; │ │ │ │ + return distance <= this.distance │ │ │ │ + }, │ │ │ │ + addToCluster: function(cluster, feature) { │ │ │ │ + cluster.cluster.push(feature); │ │ │ │ + cluster.attributes.count += 1 │ │ │ │ + }, │ │ │ │ + createCluster: function(feature) { │ │ │ │ + var center = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ + var cluster = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(center.lon, center.lat), { │ │ │ │ + count: 1 │ │ │ │ + }); │ │ │ │ + cluster.cluster = [feature]; │ │ │ │ + return cluster │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Cluster" │ │ │ │ +}); │ │ │ │ +OpenLayers.Strategy.Filter = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + filter: null, │ │ │ │ + cache: null, │ │ │ │ + caching: false, │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments); │ │ │ │ + if (activated) { │ │ │ │ + this.cache = []; │ │ │ │ + this.layer.events.on({ │ │ │ │ + beforefeaturesadded: this.handleAdd, │ │ │ │ + beforefeaturesremoved: this.handleRemove, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ } │ │ │ │ - if (typeof mapObject.getDragObject == "function") { │ │ │ │ - this.dragObject = mapObject.getDragObject() │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + this.cache = null; │ │ │ │ + if (this.layer && this.layer.events) { │ │ │ │ + this.layer.events.un({ │ │ │ │ + beforefeaturesadded: this.handleAdd, │ │ │ │ + beforefeaturesremoved: this.handleRemove, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + return OpenLayers.Strategy.prototype.deactivate.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + handleAdd: function(event) { │ │ │ │ + if (!this.caching && this.filter) { │ │ │ │ + var features = event.features; │ │ │ │ + event.features = []; │ │ │ │ + var feature; │ │ │ │ + for (var i = 0, ii = features.length; i < ii; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + if (this.filter.evaluate(feature)) { │ │ │ │ + event.features.push(feature) │ │ │ │ + } else { │ │ │ │ + this.cache.push(feature) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + handleRemove: function(event) { │ │ │ │ + if (!this.caching) { │ │ │ │ + this.cache = [] │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setFilter: function(filter) { │ │ │ │ + this.filter = filter; │ │ │ │ + var previousCache = this.cache; │ │ │ │ + this.cache = []; │ │ │ │ + this.handleAdd({ │ │ │ │ + features: this.layer.features │ │ │ │ + }); │ │ │ │ + if (this.cache.length > 0) { │ │ │ │ + this.caching = true; │ │ │ │ + this.layer.removeFeatures(this.cache.slice()); │ │ │ │ + this.caching = false │ │ │ │ + } │ │ │ │ + if (previousCache.length > 0) { │ │ │ │ + var event = { │ │ │ │ + features: previousCache │ │ │ │ + }; │ │ │ │ + this.handleAdd(event); │ │ │ │ + if (event.features.length > 0) { │ │ │ │ + this.caching = true; │ │ │ │ + this.layer.addFeatures(event.features); │ │ │ │ + this.caching = false │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Filter" │ │ │ │ +}); │ │ │ │ +OpenLayers.Strategy.Refresh = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + force: false, │ │ │ │ + interval: 0, │ │ │ │ + timer: null, │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + if (this.layer.visibility === true) { │ │ │ │ + this.start() │ │ │ │ + } │ │ │ │ + this.layer.events.on({ │ │ │ │ + visibilitychanged: this.reset, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.stop(); │ │ │ │ + this.layer.events.un({ │ │ │ │ + visibilitychanged: this.reset, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + return deactivated │ │ │ │ + }, │ │ │ │ + reset: function() { │ │ │ │ + if (this.layer.visibility === true) { │ │ │ │ + this.start() │ │ │ │ } else { │ │ │ │ - this.dragPanMapObject = null │ │ │ │ + this.stop() │ │ │ │ } │ │ │ │ - if (this.isBaseLayer === false) { │ │ │ │ - this.setGMapVisibility(this.div.style.display !== "none") │ │ │ │ + }, │ │ │ │ + start: function() { │ │ │ │ + if (this.interval && typeof this.interval === "number" && this.interval > 0) { │ │ │ │ + this.timer = window.setInterval(OpenLayers.Function.bind(this.refresh, this), this.interval) │ │ │ │ } │ │ │ │ }, │ │ │ │ - onMapResize: function() { │ │ │ │ - if (this.visibility && this.mapObject.isLoaded()) { │ │ │ │ - this.mapObject.checkResize() │ │ │ │ + refresh: function() { │ │ │ │ + if (this.layer && this.layer.refresh && typeof this.layer.refresh == "function") { │ │ │ │ + this.layer.refresh({ │ │ │ │ + force: this.force │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + stop: function() { │ │ │ │ + if (this.timer !== null) { │ │ │ │ + window.clearInterval(this.timer); │ │ │ │ + this.timer = null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Refresh" │ │ │ │ +}); │ │ │ │ +OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + features: null, │ │ │ │ + length: 10, │ │ │ │ + num: null, │ │ │ │ + paging: false, │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + beforefeaturesadded: this.cacheFeatures, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.clearCache(); │ │ │ │ + this.layer.events.un({ │ │ │ │ + beforefeaturesadded: this.cacheFeatures, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + return deactivated │ │ │ │ + }, │ │ │ │ + cacheFeatures: function(event) { │ │ │ │ + if (!this.paging) { │ │ │ │ + this.clearCache(); │ │ │ │ + this.features = event.features; │ │ │ │ + this.pageNext(event) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + clearCache: function() { │ │ │ │ + if (this.features) { │ │ │ │ + for (var i = 0; i < this.features.length; ++i) { │ │ │ │ + this.features[i].destroy() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.features = null; │ │ │ │ + this.num = null │ │ │ │ + }, │ │ │ │ + pageCount: function() { │ │ │ │ + var numFeatures = this.features ? this.features.length : 0; │ │ │ │ + return Math.ceil(numFeatures / this.length) │ │ │ │ + }, │ │ │ │ + pageNum: function() { │ │ │ │ + return this.num │ │ │ │ + }, │ │ │ │ + pageLength: function(newLength) { │ │ │ │ + if (newLength && newLength > 0) { │ │ │ │ + this.length = newLength │ │ │ │ + } │ │ │ │ + return this.length │ │ │ │ + }, │ │ │ │ + pageNext: function(event) { │ │ │ │ + var changed = false; │ │ │ │ + if (this.features) { │ │ │ │ + if (this.num === null) { │ │ │ │ + this.num = -1 │ │ │ │ + } │ │ │ │ + var start = (this.num + 1) * this.length; │ │ │ │ + changed = this.page(start, event) │ │ │ │ + } │ │ │ │ + return changed │ │ │ │ + }, │ │ │ │ + pagePrevious: function() { │ │ │ │ + var changed = false; │ │ │ │ + if (this.features) { │ │ │ │ + if (this.num === null) { │ │ │ │ + this.num = this.pageCount() │ │ │ │ + } │ │ │ │ + var start = (this.num - 1) * this.length; │ │ │ │ + changed = this.page(start) │ │ │ │ + } │ │ │ │ + return changed │ │ │ │ + }, │ │ │ │ + page: function(start, event) { │ │ │ │ + var changed = false; │ │ │ │ + if (this.features) { │ │ │ │ + if (start >= 0 && start < this.features.length) { │ │ │ │ + var num = Math.floor(start / this.length); │ │ │ │ + if (num != this.num) { │ │ │ │ + this.paging = true; │ │ │ │ + var features = this.features.slice(start, start + this.length); │ │ │ │ + this.layer.removeFeatures(this.layer.features); │ │ │ │ + this.num = num; │ │ │ │ + if (event && event.features) { │ │ │ │ + event.features = features │ │ │ │ + } else { │ │ │ │ + this.layer.addFeatures(features) │ │ │ │ + } │ │ │ │ + this.paging = false; │ │ │ │ + changed = true │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return changed │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Paging" │ │ │ │ +}); │ │ │ │ +OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + preload: false, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + 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.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + events: null, │ │ │ │ + auto: false, │ │ │ │ + timer: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Strategy.prototype.initialize.apply(this, [options]); │ │ │ │ + this.events = new OpenLayers.Events(this) │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + if (this.auto) { │ │ │ │ + if (typeof this.auto === "number") { │ │ │ │ + this.timer = window.setInterval(OpenLayers.Function.bind(this.save, this), this.auto * 1e3) │ │ │ │ + } else { │ │ │ │ + this.layer.events.on({ │ │ │ │ + featureadded: this.triggerSave, │ │ │ │ + afterfeaturemodified: this.triggerSave, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + if (this.auto) { │ │ │ │ + if (typeof this.auto === "number") { │ │ │ │ + window.clearInterval(this.timer) │ │ │ │ + } else { │ │ │ │ + this.layer.events.un({ │ │ │ │ + featureadded: this.triggerSave, │ │ │ │ + afterfeaturemodified: this.triggerSave, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return deactivated │ │ │ │ + }, │ │ │ │ + triggerSave: function(event) { │ │ │ │ + var feature = event.feature; │ │ │ │ + if (feature.state === OpenLayers.State.INSERT || feature.state === OpenLayers.State.UPDATE || feature.state === OpenLayers.State.DELETE) { │ │ │ │ + this.save([event.feature]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + save: function(features) { │ │ │ │ + if (!features) { │ │ │ │ + features = this.layer.features │ │ │ │ + } │ │ │ │ + this.events.triggerEvent("start", { │ │ │ │ + features: features │ │ │ │ + }); │ │ │ │ + var remote = this.layer.projection; │ │ │ │ + var local = this.layer.map.getProjectionObject(); │ │ │ │ + if (!local.equals(remote)) { │ │ │ │ + var len = features.length; │ │ │ │ + var clones = new Array(len); │ │ │ │ + var orig, clone; │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ + orig = features[i]; │ │ │ │ + clone = orig.clone(); │ │ │ │ + clone.fid = orig.fid; │ │ │ │ + clone.state = orig.state; │ │ │ │ + if (orig.url) { │ │ │ │ + clone.url = orig.url │ │ │ │ + } │ │ │ │ + clone._original = orig; │ │ │ │ + clone.geometry.transform(local, remote); │ │ │ │ + clones[i] = clone │ │ │ │ + } │ │ │ │ + features = clones │ │ │ │ + } │ │ │ │ + this.layer.protocol.commit(features, { │ │ │ │ + callback: this.onCommit, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + onCommit: function(response) { │ │ │ │ + var evt = { │ │ │ │ + response: response │ │ │ │ + }; │ │ │ │ + if (response.success()) { │ │ │ │ + var features = response.reqFeatures; │ │ │ │ + var state, feature; │ │ │ │ + var destroys = []; │ │ │ │ + var insertIds = response.insertIds || []; │ │ │ │ + var j = 0; │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + feature = feature._original || feature; │ │ │ │ + state = feature.state; │ │ │ │ + if (state) { │ │ │ │ + if (state == OpenLayers.State.DELETE) { │ │ │ │ + destroys.push(feature) │ │ │ │ + } else if (state == OpenLayers.State.INSERT) { │ │ │ │ + feature.fid = insertIds[j]; │ │ │ │ + ++j │ │ │ │ + } │ │ │ │ + feature.state = null │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (destroys.length > 0) { │ │ │ │ + this.layer.destroyFeatures(destroys) │ │ │ │ + } │ │ │ │ + this.events.triggerEvent("success", evt) │ │ │ │ } else { │ │ │ │ - if (!this._resized) { │ │ │ │ - var layer = this; │ │ │ │ - var handle = GEvent.addListener(this.mapObject, "load", function() { │ │ │ │ - GEvent.removeListener(handle); │ │ │ │ - delete layer._resized; │ │ │ │ - layer.mapObject.checkResize(); │ │ │ │ - layer.moveTo(layer.map.getCenter(), layer.map.getZoom()) │ │ │ │ + this.events.triggerEvent("fail", evt) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Save" │ │ │ │ +}); │ │ │ │ +OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + bounds: null, │ │ │ │ + resolution: null, │ │ │ │ + ratio: 2, │ │ │ │ + resFactor: null, │ │ │ │ + response: null, │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + moveend: this.update, │ │ │ │ + refresh: this.update, │ │ │ │ + visibilitychanged: this.update, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.update() │ │ │ │ + } │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.layer.events.un({ │ │ │ │ + moveend: this.update, │ │ │ │ + refresh: this.update, │ │ │ │ + visibilitychanged: this.update, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + return deactivated │ │ │ │ + }, │ │ │ │ + update: function(options) { │ │ │ │ + var mapBounds = this.getMapBounds(); │ │ │ │ + if (mapBounds !== null && (options && options.force || this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds))) { │ │ │ │ + this.calculateBounds(mapBounds); │ │ │ │ + this.resolution = this.layer.map.getResolution(); │ │ │ │ + this.triggerRead(options) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getMapBounds: function() { │ │ │ │ + if (this.layer.map === null) { │ │ │ │ + return null │ │ │ │ + } │ │ │ │ + var bounds = this.layer.map.getExtent(); │ │ │ │ + if (bounds && !this.layer.projection.equals(this.layer.map.getProjectionObject())) { │ │ │ │ + bounds = bounds.clone().transform(this.layer.map.getProjectionObject(), this.layer.projection) │ │ │ │ + } │ │ │ │ + return bounds │ │ │ │ + }, │ │ │ │ + invalidBounds: function(mapBounds) { │ │ │ │ + if (!mapBounds) { │ │ │ │ + mapBounds = this.getMapBounds() │ │ │ │ + } │ │ │ │ + var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds); │ │ │ │ + if (!invalid && this.resFactor) { │ │ │ │ + var ratio = this.resolution / this.layer.map.getResolution(); │ │ │ │ + invalid = ratio >= this.resFactor || ratio <= 1 / this.resFactor │ │ │ │ + } │ │ │ │ + return invalid │ │ │ │ + }, │ │ │ │ + calculateBounds: function(mapBounds) { │ │ │ │ + if (!mapBounds) { │ │ │ │ + mapBounds = this.getMapBounds() │ │ │ │ + } │ │ │ │ + var center = mapBounds.getCenterLonLat(); │ │ │ │ + var dataWidth = mapBounds.getWidth() * this.ratio; │ │ │ │ + var dataHeight = mapBounds.getHeight() * this.ratio; │ │ │ │ + this.bounds = new OpenLayers.Bounds(center.lon - dataWidth / 2, center.lat - dataHeight / 2, center.lon + dataWidth / 2, center.lat + dataHeight / 2) │ │ │ │ + }, │ │ │ │ + triggerRead: function(options) { │ │ │ │ + if (this.response && !(options && options.noAbort === true)) { │ │ │ │ + this.layer.protocol.abort(this.response); │ │ │ │ + this.layer.events.triggerEvent("loadend") │ │ │ │ + } │ │ │ │ + var evt = { │ │ │ │ + filter: this.createFilter() │ │ │ │ + }; │ │ │ │ + this.layer.events.triggerEvent("loadstart", evt); │ │ │ │ + this.response = this.layer.protocol.read(OpenLayers.Util.applyDefaults({ │ │ │ │ + filter: evt.filter, │ │ │ │ + callback: this.merge, │ │ │ │ + scope: this │ │ │ │ + }, options)) │ │ │ │ + }, │ │ │ │ + createFilter: function() { │ │ │ │ + var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ + value: this.bounds, │ │ │ │ + projection: this.layer.projection │ │ │ │ + }); │ │ │ │ + if (this.layer.filter) { │ │ │ │ + filter = new OpenLayers.Filter.Logical({ │ │ │ │ + type: OpenLayers.Filter.Logical.AND, │ │ │ │ + filters: [this.layer.filter, filter] │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + return filter │ │ │ │ + }, │ │ │ │ + merge: function(resp) { │ │ │ │ + this.layer.destroyFeatures(); │ │ │ │ + if (resp.success()) { │ │ │ │ + var features = resp.features; │ │ │ │ + if (features && features.length > 0) { │ │ │ │ + var remote = this.layer.projection; │ │ │ │ + var local = this.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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.layer.addFeatures(features) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.bounds = null │ │ │ │ + } │ │ │ │ + this.response = null; │ │ │ │ + this.layer.events.triggerEvent("loadend", { │ │ │ │ + response: resp │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.BBOX" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + point: null, │ │ │ │ + layer: null, │ │ │ │ + multi: false, │ │ │ │ + citeCompliant: false, │ │ │ │ + mouseDown: false, │ │ │ │ + stoppedDown: null, │ │ │ │ + lastDown: null, │ │ │ │ + lastUp: null, │ │ │ │ + persist: false, │ │ │ │ + stopDown: false, │ │ │ │ + stopUp: false, │ │ │ │ + layerOptions: null, │ │ │ │ + pixelTolerance: 5, │ │ │ │ + lastTouchPx: null, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (!OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + var options = OpenLayers.Util.extend({ │ │ │ │ + displayInLayerSwitcher: false, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (!OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + this.cancel(); │ │ │ │ + if (this.layer.map != null) { │ │ │ │ + this.destroyFeature(true); │ │ │ │ + this.layer.destroy(false) │ │ │ │ + } │ │ │ │ + this.layer = null; │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + destroyFeature: function(force) { │ │ │ │ + if (this.layer && (force || !this.persist)) { │ │ │ │ + this.layer.destroyFeatures() │ │ │ │ + } │ │ │ │ + this.point = null │ │ │ │ + }, │ │ │ │ + destroyPersistedFeature: function() { │ │ │ │ + var layer = this.layer; │ │ │ │ + if (layer && layer.features.length > 1) { │ │ │ │ + this.layer.features[0].destroy() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + cancel: function() { │ │ │ │ + this.finalize(true) │ │ │ │ + }, │ │ │ │ + click: function(evt) { │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + dblclick: function(evt) { │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + }, │ │ │ │ + drawFeature: function() { │ │ │ │ + this.layer.drawFeature(this.point, this.style) │ │ │ │ + }, │ │ │ │ + getGeometry: function() { │ │ │ │ + var geometry = this.point && this.point.geometry; │ │ │ │ + if (geometry && this.multi) { │ │ │ │ + geometry = new OpenLayers.Geometry.MultiPoint([geometry]) │ │ │ │ + } │ │ │ │ + return geometry │ │ │ │ + }, │ │ │ │ + geometryClone: function() { │ │ │ │ + var geom = this.getGeometry(); │ │ │ │ + return geom && geom.clone() │ │ │ │ + }, │ │ │ │ + mousedown: function(evt) { │ │ │ │ + return this.down(evt) │ │ │ │ + }, │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + this.lastTouchPx = evt.xy; │ │ │ │ + return this.down(evt) │ │ │ │ + }, │ │ │ │ + mousemove: function(evt) { │ │ │ │ + return this.move(evt) │ │ │ │ + }, │ │ │ │ + touchmove: function(evt) { │ │ │ │ + this.lastTouchPx = evt.xy; │ │ │ │ + return this.move(evt) │ │ │ │ + }, │ │ │ │ + mouseup: function(evt) { │ │ │ │ + return this.up(evt) │ │ │ │ + }, │ │ │ │ + touchend: function(evt) { │ │ │ │ + evt.xy = this.lastTouchPx; │ │ │ │ + return this.up(evt) │ │ │ │ + }, │ │ │ │ + down: function(evt) { │ │ │ │ + this.mouseDown = true; │ │ │ │ + this.lastDown = evt.xy; │ │ │ │ + if (!this.touch) { │ │ │ │ + this.modifyFeature(evt.xy) │ │ │ │ + } │ │ │ │ + this.stoppedDown = this.stopDown; │ │ │ │ + return !this.stopDown │ │ │ │ + }, │ │ │ │ + move: function(evt) { │ │ │ │ + if (!this.touch && (!this.mouseDown || this.stoppedDown)) { │ │ │ │ + this.modifyFeature(evt.xy) │ │ │ │ + } │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + up: function(evt) { │ │ │ │ + this.mouseDown = false; │ │ │ │ + this.stoppedDown = this.stopDown; │ │ │ │ + if (!this.checkModifiers(evt)) { │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + mouseout: function(evt) { │ │ │ │ + if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ + this.stoppedDown = this.stopDown; │ │ │ │ + this.mouseDown = false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 = OpenLayers.Class(OpenLayers.Handler.Point, { │ │ │ │ + line: null, │ │ │ │ + maxVertices: null, │ │ │ │ + doubleTouchTolerance: 20, │ │ │ │ + freehand: false, │ │ │ │ + freehandToggle: "shiftKey", │ │ │ │ + timerId: null, │ │ │ │ + redoStack: null, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + destroyFeature: function(force) { │ │ │ │ + OpenLayers.Handler.Point.prototype.destroyFeature.call(this, force); │ │ │ │ + this.line = null │ │ │ │ + }, │ │ │ │ + destroyPersistedFeature: function() { │ │ │ │ + var layer = this.layer; │ │ │ │ + if (layer && layer.features.length > 2) { │ │ │ │ + this.layer.features[0].destroy() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + removePoint: function() { │ │ │ │ + if (this.point) { │ │ │ │ + this.layer.removeFeatures([this.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 │ │ │ │ + }, │ │ │ │ + insertXY: function(x, y) { │ │ │ │ + this.line.geometry.addComponent(new OpenLayers.Geometry.Point(x, y), this.getCurrentPointIndex()); │ │ │ │ + this.drawFeature(); │ │ │ │ + delete this.redoStack │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + insertDirectionLength: function(direction, length) { │ │ │ │ + direction *= Math.PI / 180; │ │ │ │ + var dx = length * Math.cos(direction); │ │ │ │ + var dy = length * Math.sin(direction); │ │ │ │ + this.insertDeltaXY(dx, dy) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getCurrentPointIndex: function() { │ │ │ │ + return this.line.geometry.components.length - 1 │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + if (this.touch && index > 0) { │ │ │ │ + components = geometry.components; │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + redo: function() { │ │ │ │ + var target = this.redoStack && this.redoStack.pop(); │ │ │ │ + if (target) { │ │ │ │ + this.line.geometry.addComponent(target, this.getCurrentPointIndex()); │ │ │ │ + this.drawFeature() │ │ │ │ + } │ │ │ │ + return !!target │ │ │ │ + }, │ │ │ │ + freehandMode: function(evt) { │ │ │ │ + return this.freehandToggle && evt[this.freehandToggle] ? !this.freehand : this.freehand │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + }, │ │ │ │ + drawFeature: function() { │ │ │ │ + this.layer.drawFeature(this.line, this.style); │ │ │ │ + this.layer.drawFeature(this.point, this.style) │ │ │ │ + }, │ │ │ │ + getSketch: function() { │ │ │ │ + return this.line │ │ │ │ + }, │ │ │ │ + getGeometry: function() { │ │ │ │ + var geometry = this.line && this.line.geometry; │ │ │ │ + if (geometry && this.multi) { │ │ │ │ + geometry = new OpenLayers.Geometry.MultiLineString([geometry]) │ │ │ │ + } │ │ │ │ + return geometry │ │ │ │ + }, │ │ │ │ + touchstart: function(evt) { │ │ │ │ + if (this.timerId && this.passesTolerance(this.lastTouchPx, evt.xy, this.doubleTouchTolerance)) { │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + finishGeometry: function() { │ │ │ │ + var index = this.line.geometry.components.length - 1; │ │ │ │ + this.line.geometry.removeComponent(this.line.geometry.components[index]); │ │ │ │ + this.removePoint(); │ │ │ │ + this.finalize() │ │ │ │ + }, │ │ │ │ + dblclick: function(evt) { │ │ │ │ + if (!this.freehandMode(evt)) { │ │ │ │ + this.finishGeometry() │ │ │ │ + } │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Path" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.Polygon = OpenLayers.Class(OpenLayers.Handler.Path, { │ │ │ │ + holeModifier: null, │ │ │ │ + drawingHole: false, │ │ │ │ + polygon: null, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + 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; │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + getCurrentPointIndex: function() { │ │ │ │ + return this.line.geometry.components.length - 2 │ │ │ │ + }, │ │ │ │ + enforceTopology: function(event) { │ │ │ │ + var point = event.vertex; │ │ │ │ + var components = this.line.geometry.components; │ │ │ │ + if (!this.polygon.geometry.intersects(point)) { │ │ │ │ + var last = components[components.length - 3]; │ │ │ │ + point.x = last.x; │ │ │ │ + point.y = last.y │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + finishGeometry: function() { │ │ │ │ + var index = this.line.geometry.components.length - 2; │ │ │ │ + this.line.geometry.removeComponent(this.line.geometry.components[index]); │ │ │ │ + this.removePoint(); │ │ │ │ + this.finalize() │ │ │ │ + }, │ │ │ │ + finalizeInteriorRing: function() { │ │ │ │ + var ring = this.line.geometry; │ │ │ │ + var modified = ring.getArea() !== 0; │ │ │ │ + if (modified) { │ │ │ │ + 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) { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + cancel: function() { │ │ │ │ + if (this.drawingHole) { │ │ │ │ + this.polygon.geometry.removeComponent(this.line.geometry); │ │ │ │ + this.restoreFeature(true) │ │ │ │ + } │ │ │ │ + return OpenLayers.Handler.Path.prototype.cancel.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + this.control.layer.events.triggerEvent("sketchcomplete", { │ │ │ │ + feature: this.polygon │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroyFeature: function(force) { │ │ │ │ + OpenLayers.Handler.Path.prototype.destroyFeature.call(this, force); │ │ │ │ + this.polygon = null │ │ │ │ + }, │ │ │ │ + drawFeature: function() { │ │ │ │ + this.layer.drawFeature(this.polygon, this.style); │ │ │ │ + this.layer.drawFeature(this.point, this.style) │ │ │ │ + }, │ │ │ │ + getSketch: function() { │ │ │ │ + return this.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.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + delay: 500, │ │ │ │ + pixelTolerance: null, │ │ │ │ + stopMove: false, │ │ │ │ + px: null, │ │ │ │ + timerId: null, │ │ │ │ + mousemove: function(evt) { │ │ │ │ + if (this.passesTolerance(evt.xy)) { │ │ │ │ + this.clearTimer(); │ │ │ │ + this.callback("move", [evt]); │ │ │ │ + this.px = evt.xy; │ │ │ │ + evt = OpenLayers.Util.extend({}, evt); │ │ │ │ + this.timerId = window.setTimeout(OpenLayers.Function.bind(this.delayedCall, this, evt), this.delay) │ │ │ │ + } │ │ │ │ + return !this.stopMove │ │ │ │ + }, │ │ │ │ + mouseout: function(evt) { │ │ │ │ + if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ + this.clearTimer(); │ │ │ │ + this.callback("move", [evt]) │ │ │ │ + } │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + passesTolerance: function(px) { │ │ │ │ + var passes = true; │ │ │ │ + if (this.pixelTolerance && this.px) { │ │ │ │ + var dpx = Math.sqrt(Math.pow(this.px.x - px.x, 2) + Math.pow(this.px.y - px.y, 2)); │ │ │ │ + if (dpx < this.pixelTolerance) { │ │ │ │ + passes = false │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return passes │ │ │ │ + }, │ │ │ │ + clearTimer: function() { │ │ │ │ + if (this.timerId != null) { │ │ │ │ + window.clearTimeout(this.timerId); │ │ │ │ + this.timerId = null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + delayedCall: function(evt) { │ │ │ │ + this.callback("pause", [evt]) │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = false; │ │ │ │ + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + this.clearTimer(); │ │ │ │ + deactivated = true │ │ │ │ + } │ │ │ │ + return deactivated │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Hover" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + started: false, │ │ │ │ + stopDown: true, │ │ │ │ + dragging: false, │ │ │ │ + last: null, │ │ │ │ + start: null, │ │ │ │ + lastMoveEvt: null, │ │ │ │ + oldOnselectstart: null, │ │ │ │ + interval: 0, │ │ │ │ + timeoutId: null, │ │ │ │ + documentDrag: false, │ │ │ │ + documentEvents: null, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ }) │ │ │ │ } │ │ │ │ - this._resized = true │ │ │ │ } │ │ │ │ }, │ │ │ │ - setGMapVisibility: function(visible) { │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - var container = this.mapObject.getContainer(); │ │ │ │ - if (visible === true) { │ │ │ │ - this.mapObject.setMapType(this.type); │ │ │ │ - container.style.display = ""; │ │ │ │ - this.termsOfUse.style.left = ""; │ │ │ │ - this.termsOfUse.style.display = ""; │ │ │ │ - this.poweredBy.style.display = ""; │ │ │ │ - cache.displayed = this.id │ │ │ │ + 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]); │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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); │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + down: function(evt) {}, │ │ │ │ + move: function(evt) {}, │ │ │ │ + up: function(evt) {}, │ │ │ │ + out: function(evt) {}, │ │ │ │ + mousedown: function(evt) { │ │ │ │ + return this.dragstart(evt) │ │ │ │ + }, │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + return this.dragstart(evt) │ │ │ │ + }, │ │ │ │ + mousemove: function(evt) { │ │ │ │ + return this.dragmove(evt) │ │ │ │ + }, │ │ │ │ + touchmove: function(evt) { │ │ │ │ + return this.dragmove(evt) │ │ │ │ + }, │ │ │ │ + removeTimeout: function() { │ │ │ │ + this.timeoutId = null; │ │ │ │ + if (this.dragging) { │ │ │ │ + this.mousemove(this.lastMoveEvt) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + mouseup: function(evt) { │ │ │ │ + return this.dragend(evt) │ │ │ │ + }, │ │ │ │ + touchend: function(evt) { │ │ │ │ + evt.xy = this.last; │ │ │ │ + return this.dragend(evt) │ │ │ │ + }, │ │ │ │ + mouseout: function(evt) { │ │ │ │ + if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ + if (this.documentDrag === true) { │ │ │ │ + this.addDocumentEvents() │ │ │ │ } else { │ │ │ │ - if (cache.displayed === this.id) { │ │ │ │ - delete cache.displayed │ │ │ │ + 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 (!cache.displayed) { │ │ │ │ - container.style.display = "none"; │ │ │ │ - this.termsOfUse.style.display = "none"; │ │ │ │ - this.termsOfUse.style.left = "-9999px"; │ │ │ │ - this.poweredBy.style.display = "none" │ │ │ │ + if (document.onselectstart) { │ │ │ │ + document.onselectstart = this.oldOnselectstart │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ + return true │ │ │ │ }, │ │ │ │ - getMapContainer: function() { │ │ │ │ - return this.mapObject.getContainer() │ │ │ │ + click: function(evt) { │ │ │ │ + return this.start == this.last │ │ │ │ }, │ │ │ │ - getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ - var moBounds = null; │ │ │ │ - if (olBounds != null) { │ │ │ │ - var sw = this.sphericalMercator ? this.inverseMercator(olBounds.bottom, olBounds.left) : new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ - var ne = this.sphericalMercator ? this.inverseMercator(olBounds.top, olBounds.right) : new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ - moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon), new GLatLng(ne.lat, ne.lon)) │ │ │ │ + activate: function() { │ │ │ │ + var activated = false; │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.dragging = false; │ │ │ │ + activated = true │ │ │ │ } │ │ │ │ - return moBounds │ │ │ │ + return activated │ │ │ │ }, │ │ │ │ - setMapObjectCenter: function(center, zoom) { │ │ │ │ - this.mapObject.setCenter(center, zoom) │ │ │ │ + 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 │ │ │ │ }, │ │ │ │ - dragPanMapObject: function(dX, dY) { │ │ │ │ - this.dragObject.moveBy(new GSize(-dX, dY)) │ │ │ │ + adjustXY: function(evt) { │ │ │ │ + var pos = OpenLayers.Util.pagePosition(this.map.viewPortDiv); │ │ │ │ + evt.xy.x -= pos[0]; │ │ │ │ + evt.xy.y -= pos[1] │ │ │ │ }, │ │ │ │ - getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ - return this.mapObject.fromContainerPixelToLatLng(moPixel) │ │ │ │ + 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) │ │ │ │ }, │ │ │ │ - getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - return this.mapObject.fromLatLngToContainerPixel(moLonLat) │ │ │ │ + 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) │ │ │ │ }, │ │ │ │ - getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ - return this.mapObject.getBoundsZoomLevel(moBounds) │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Drag" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.RegularPolygon = OpenLayers.Class(OpenLayers.Handler.Drag, { │ │ │ │ + sides: 4, │ │ │ │ + radius: null, │ │ │ │ + snapAngle: null, │ │ │ │ + snapToggle: "shiftKey", │ │ │ │ + layerOptions: null, │ │ │ │ + persist: false, │ │ │ │ + irregular: false, │ │ │ │ + citeCompliant: false, │ │ │ │ + angle: null, │ │ │ │ + fixedRadius: false, │ │ │ │ + feature: null, │ │ │ │ + layer: null, │ │ │ │ + origin: null, │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + if (!(options && options.layerOptions && options.layerOptions.styleMap)) { │ │ │ │ + this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style["default"], {}) │ │ │ │ + } │ │ │ │ + OpenLayers.Handler.Drag.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ + this.options = options ? options : {} │ │ │ │ }, │ │ │ │ - getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ - var gLatLng; │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - var lonlat = this.inverseMercator(lon, lat); │ │ │ │ - gLatLng = new GLatLng(lonlat.lat, lonlat.lon) │ │ │ │ + setOptions: function(newOptions) { │ │ │ │ + OpenLayers.Util.extend(this.options, newOptions); │ │ │ │ + OpenLayers.Util.extend(this, newOptions) │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + var activated = false; │ │ │ │ + if (OpenLayers.Handler.Drag.prototype.activate.apply(this, arguments)) { │ │ │ │ + var options = OpenLayers.Util.extend({ │ │ │ │ + displayInLayerSwitcher: false, │ │ │ │ + calculateInRange: OpenLayers.Function.True, │ │ │ │ + wrapDateLine: this.citeCompliant │ │ │ │ + }, this.layerOptions); │ │ │ │ + this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options); │ │ │ │ + this.map.addLayer(this.layer); │ │ │ │ + activated = true │ │ │ │ + } │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = false; │ │ │ │ + if (OpenLayers.Handler.Drag.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + if (this.dragging) { │ │ │ │ + this.cancel() │ │ │ │ + } │ │ │ │ + if (this.layer.map != null) { │ │ │ │ + this.layer.destroy(false); │ │ │ │ + if (this.feature) { │ │ │ │ + this.feature.destroy() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.layer = null; │ │ │ │ + this.feature = null; │ │ │ │ + deactivated = true │ │ │ │ + } │ │ │ │ + return deactivated │ │ │ │ + }, │ │ │ │ + down: function(evt) { │ │ │ │ + this.fixedRadius = !!this.radius; │ │ │ │ + var maploc = this.layer.getLonLatFromViewPortPx(evt.xy); │ │ │ │ + this.origin = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat); │ │ │ │ + if (!this.fixedRadius || this.irregular) { │ │ │ │ + this.radius = this.map.getResolution() │ │ │ │ + } │ │ │ │ + if (this.persist) { │ │ │ │ + this.clear() │ │ │ │ + } │ │ │ │ + this.feature = new OpenLayers.Feature.Vector; │ │ │ │ + this.createGeometry(); │ │ │ │ + this.callback("create", [this.origin, this.feature]); │ │ │ │ + this.layer.addFeatures([this.feature], { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + this.layer.drawFeature(this.feature, this.style) │ │ │ │ + }, │ │ │ │ + move: function(evt) { │ │ │ │ + var maploc = this.layer.getLonLatFromViewPortPx(evt.xy); │ │ │ │ + var point = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat); │ │ │ │ + if (this.irregular) { │ │ │ │ + var ry = Math.sqrt(2) * Math.abs(point.y - this.origin.y) / 2; │ │ │ │ + this.radius = Math.max(this.map.getResolution() / 2, ry) │ │ │ │ + } else if (this.fixedRadius) { │ │ │ │ + this.origin = point │ │ │ │ } else { │ │ │ │ - gLatLng = new GLatLng(lat, lon) │ │ │ │ + this.calculateAngle(point, evt); │ │ │ │ + this.radius = Math.max(this.map.getResolution() / 2, point.distanceTo(this.origin)) │ │ │ │ } │ │ │ │ - return gLatLng │ │ │ │ + this.modifyGeometry(); │ │ │ │ + if (this.irregular) { │ │ │ │ + var dx = point.x - this.origin.x; │ │ │ │ + var dy = point.y - this.origin.y; │ │ │ │ + var ratio; │ │ │ │ + if (dy == 0) { │ │ │ │ + ratio = dx / (this.radius * Math.sqrt(2)) │ │ │ │ + } else { │ │ │ │ + ratio = dx / dy │ │ │ │ + } │ │ │ │ + this.feature.geometry.resize(1, this.origin, ratio); │ │ │ │ + this.feature.geometry.move(dx / 2, dy / 2) │ │ │ │ + } │ │ │ │ + this.layer.drawFeature(this.feature, this.style) │ │ │ │ }, │ │ │ │ - getMapObjectPixelFromXY: function(x, y) { │ │ │ │ - return new GPoint(x, y) │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -OpenLayers.Layer.WorldWind = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - DEFAULT_PARAMS: {}, │ │ │ │ - isBaseLayer: true, │ │ │ │ - lzd: null, │ │ │ │ - zoomLevels: null, │ │ │ │ - initialize: function(name, url, lzd, zoomLevels, params, options) { │ │ │ │ - this.lzd = lzd; │ │ │ │ - this.zoomLevels = zoomLevels; │ │ │ │ - var newArguments = []; │ │ │ │ - newArguments.push(name, url, params, options); │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments); │ │ │ │ - this.params = OpenLayers.Util.applyDefaults(this.params, this.DEFAULT_PARAMS) │ │ │ │ + up: function(evt) { │ │ │ │ + this.finalize(); │ │ │ │ + if (this.start == this.last) { │ │ │ │ + this.callback("done", [evt.xy]) │ │ │ │ + } │ │ │ │ }, │ │ │ │ - getZoom: function() { │ │ │ │ - var zoom = this.map.getZoom(); │ │ │ │ - var extent = this.map.getMaxExtent(); │ │ │ │ - zoom = zoom - Math.log(this.maxResolution / (this.lzd / 512)) / Math.log(2); │ │ │ │ - return zoom │ │ │ │ + out: function(evt) { │ │ │ │ + this.finalize() │ │ │ │ + }, │ │ │ │ + createGeometry: function() { │ │ │ │ + this.angle = Math.PI * (1 / this.sides - 1 / 2); │ │ │ │ + if (this.snapAngle) { │ │ │ │ + this.angle += this.snapAngle * (Math.PI / 180) │ │ │ │ + } │ │ │ │ + this.feature.geometry = OpenLayers.Geometry.Polygon.createRegularPolygon(this.origin, this.radius, this.sides, this.snapAngle) │ │ │ │ + }, │ │ │ │ + modifyGeometry: function() { │ │ │ │ + var angle, point; │ │ │ │ + var ring = this.feature.geometry.components[0]; │ │ │ │ + if (ring.components.length != this.sides + 1) { │ │ │ │ + this.createGeometry(); │ │ │ │ + ring = this.feature.geometry.components[0] │ │ │ │ + } │ │ │ │ + for (var i = 0; i < this.sides; ++i) { │ │ │ │ + point = ring.components[i]; │ │ │ │ + angle = this.angle + i * 2 * Math.PI / this.sides; │ │ │ │ + point.x = this.origin.x + this.radius * Math.cos(angle); │ │ │ │ + point.y = this.origin.y + this.radius * Math.sin(angle); │ │ │ │ + point.clearBounds() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + calculateAngle: function(point, evt) { │ │ │ │ + var alpha = Math.atan2(point.y - this.origin.y, point.x - this.origin.x); │ │ │ │ + if (this.snapAngle && (this.snapToggle && !evt[this.snapToggle])) { │ │ │ │ + var snapAngleRad = Math.PI / 180 * this.snapAngle; │ │ │ │ + this.angle = Math.round(alpha / snapAngleRad) * snapAngleRad │ │ │ │ + } else { │ │ │ │ + this.angle = alpha │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + cancel: function() { │ │ │ │ + this.callback("cancel", null); │ │ │ │ + this.finalize() │ │ │ │ + }, │ │ │ │ + finalize: function() { │ │ │ │ + this.origin = null; │ │ │ │ + this.radius = this.options.radius │ │ │ │ + }, │ │ │ │ + clear: function() { │ │ │ │ + if (this.layer) { │ │ │ │ + this.layer.renderer.clear(); │ │ │ │ + this.layer.destroyFeatures() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + callback: function(name, args) { │ │ │ │ + if (this.callbacks[name]) { │ │ │ │ + this.callbacks[name].apply(this.control, [this.feature.geometry.clone()]) │ │ │ │ + } │ │ │ │ + if (!this.persist && (name == "done" || name == "cancel")) { │ │ │ │ + this.clear() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.RegularPolygon" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + 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" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + feature: null, │ │ │ │ + lastFeature: null, │ │ │ │ + down: null, │ │ │ │ + up: null, │ │ │ │ + clickTolerance: 4, │ │ │ │ + geometryTypes: null, │ │ │ │ + stopClick: true, │ │ │ │ + stopDown: true, │ │ │ │ + stopUp: false, │ │ │ │ + initialize: function(control, layer, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ + this.layer = layer │ │ │ │ + }, │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + return OpenLayers.Event.isMultiTouch(evt) ? true : this.mousedown(evt) │ │ │ │ + }, │ │ │ │ + touchmove: function(evt) { │ │ │ │ + OpenLayers.Event.preventDefault(evt) │ │ │ │ + }, │ │ │ │ + mousedown: function(evt) { │ │ │ │ + if (OpenLayers.Event.isLeftClick(evt) || OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ + this.down = evt.xy │ │ │ │ + } │ │ │ │ + return this.handle(evt) ? !this.stopDown : true │ │ │ │ + }, │ │ │ │ + mouseup: function(evt) { │ │ │ │ + this.up = evt.xy; │ │ │ │ + return this.handle(evt) ? !this.stopUp : true │ │ │ │ + }, │ │ │ │ + click: function(evt) { │ │ │ │ + return this.handle(evt) ? !this.stopClick : true │ │ │ │ + }, │ │ │ │ + mousemove: function(evt) { │ │ │ │ + if (!this.callbacks["over"] && !this.callbacks["out"]) { │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + this.handle(evt); │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + dblclick: function(evt) { │ │ │ │ + return !this.handle(evt) │ │ │ │ + }, │ │ │ │ + geometryTypeMatches: function(feature) { │ │ │ │ + return this.geometryTypes == null || OpenLayers.Util.indexOf(this.geometryTypes, feature.geometry.CLASS_NAME) > -1 │ │ │ │ + }, │ │ │ │ + handle: function(evt) { │ │ │ │ + if (this.feature && !this.feature.layer) { │ │ │ │ + this.feature = null │ │ │ │ + } │ │ │ │ + var type = evt.type; │ │ │ │ + var handled = false; │ │ │ │ + var previouslyIn = !!this.feature; │ │ │ │ + var click = type == "click" || type == "dblclick" || type == "touchstart"; │ │ │ │ + this.feature = this.layer.getFeatureFromEvent(evt); │ │ │ │ + if (this.feature && !this.feature.layer) { │ │ │ │ + this.feature = null │ │ │ │ + } │ │ │ │ + if (this.lastFeature && !this.lastFeature.layer) { │ │ │ │ + this.lastFeature = null │ │ │ │ + } │ │ │ │ + if (this.feature) { │ │ │ │ + if (type === "touchstart") { │ │ │ │ + OpenLayers.Event.preventDefault(evt) │ │ │ │ + } │ │ │ │ + var inNew = this.feature != this.lastFeature; │ │ │ │ + if (this.geometryTypeMatches(this.feature)) { │ │ │ │ + if (previouslyIn && inNew) { │ │ │ │ + if (this.lastFeature) { │ │ │ │ + this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ + } │ │ │ │ + this.triggerCallback(type, "in", [this.feature]) │ │ │ │ + } else if (!previouslyIn || click) { │ │ │ │ + this.triggerCallback(type, "in", [this.feature]) │ │ │ │ + } │ │ │ │ + this.lastFeature = this.feature; │ │ │ │ + handled = true │ │ │ │ + } else { │ │ │ │ + if (this.lastFeature && (previouslyIn && inNew || click)) { │ │ │ │ + this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ + } │ │ │ │ + this.feature = null │ │ │ │ + } │ │ │ │ + } else if (this.lastFeature && (previouslyIn || click)) { │ │ │ │ + this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ + } │ │ │ │ + return handled │ │ │ │ + }, │ │ │ │ + triggerCallback: function(type, mode, args) { │ │ │ │ + var key = this.EVENTMAP[type][mode]; │ │ │ │ + if (key) { │ │ │ │ + if (type == "click" && this.up && this.down) { │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + this.up = this.down = null │ │ │ │ + } else { │ │ │ │ + this.callback(key, args) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleMapEvents: function(evt) { │ │ │ │ + if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ + this.moveLayerToTop() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + moveLayerToTop: function() { │ │ │ │ + var index = Math.max(this.map.Z_INDEX_BASE["Feature"] - 1, this.layer.getZIndex()) + 1; │ │ │ │ + this.layer.setZIndex(index) │ │ │ │ + }, │ │ │ │ + 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.Handler.Click = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + delay: 300, │ │ │ │ + single: true, │ │ │ │ + double: false, │ │ │ │ + pixelTolerance: 0, │ │ │ │ + dblclickTolerance: 13, │ │ │ │ + stopSingle: false, │ │ │ │ + stopDouble: false, │ │ │ │ + timerId: null, │ │ │ │ + down: null, │ │ │ │ + last: null, │ │ │ │ + first: null, │ │ │ │ + rightclickTimerId: null, │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + this.down = this.getEventInfo(evt); │ │ │ │ + this.last = this.getEventInfo(evt); │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + touchmove: function(evt) { │ │ │ │ + this.last = this.getEventInfo(evt); │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + touchend: function(evt) { │ │ │ │ + if (this.down) { │ │ │ │ + evt.xy = this.last.xy; │ │ │ │ + evt.lastTouches = this.last.touches; │ │ │ │ + this.handleSingle(evt); │ │ │ │ + this.down = null │ │ │ │ + } │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + mousedown: function(evt) { │ │ │ │ + this.down = this.getEventInfo(evt); │ │ │ │ + this.last = this.getEventInfo(evt); │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + mouseup: function(evt) { │ │ │ │ + var propagate = true; │ │ │ │ + if (this.checkModifiers(evt) && this.control.handleRightClicks && OpenLayers.Event.isRightClick(evt)) { │ │ │ │ + propagate = this.rightclick(evt) │ │ │ │ + } │ │ │ │ + return propagate │ │ │ │ + }, │ │ │ │ + rightclick: function(evt) { │ │ │ │ + if (this.passesTolerance(evt)) { │ │ │ │ + if (this.rightclickTimerId != null) { │ │ │ │ + this.clearTimer(); │ │ │ │ + this.callback("dblrightclick", [evt]); │ │ │ │ + return !this.stopDouble │ │ │ │ + } else { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + delayedRightCall: function(evt) { │ │ │ │ + this.rightclickTimerId = null; │ │ │ │ + if (evt) { │ │ │ │ + this.callback("rightclick", [evt]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + click: function(evt) { │ │ │ │ + if (!this.last) { │ │ │ │ + this.last = this.getEventInfo(evt) │ │ │ │ + } │ │ │ │ + this.handleSingle(evt); │ │ │ │ + return !this.stopSingle │ │ │ │ + }, │ │ │ │ + dblclick: function(evt) { │ │ │ │ + this.handleDouble(evt); │ │ │ │ + return !this.stopDouble │ │ │ │ + }, │ │ │ │ + handleDouble: function(evt) { │ │ │ │ + if (this.passesDblclickTolerance(evt)) { │ │ │ │ + if (this["double"]) { │ │ │ │ + this.callback("dblclick", [evt]) │ │ │ │ + } │ │ │ │ + this.clearTimer() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + handleSingle: function(evt) { │ │ │ │ + if (this.passesTolerance(evt)) { │ │ │ │ + if (this.timerId != null) { │ │ │ │ + if (this.last.touches && this.last.touches.length === 1) { │ │ │ │ + if (this["double"]) { │ │ │ │ + OpenLayers.Event.preventDefault(evt) │ │ │ │ + } │ │ │ │ + this.handleDouble(evt) │ │ │ │ + } │ │ │ │ + if (!this.last.touches || this.last.touches.length !== 2) { │ │ │ │ + this.clearTimer() │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.first = this.getEventInfo(evt); │ │ │ │ + var clickEvent = this.single ? OpenLayers.Util.extend({}, evt) : null; │ │ │ │ + this.queuePotentialClick(clickEvent) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + queuePotentialClick: function(evt) { │ │ │ │ + this.timerId = window.setTimeout(OpenLayers.Function.bind(this.delayedCall, this, evt), this.delay) │ │ │ │ + }, │ │ │ │ + passesTolerance: function(evt) { │ │ │ │ + var passes = true; │ │ │ │ + if (this.pixelTolerance != null && this.down && this.down.xy) { │ │ │ │ + passes = this.pixelTolerance >= this.down.xy.distanceTo(evt.xy); │ │ │ │ + if (passes && this.touch && this.down.touches.length === this.last.touches.length) { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + getTouchDistance: function(from, to) { │ │ │ │ + return Math.sqrt(Math.pow(from.clientX - to.clientX, 2) + Math.pow(from.clientY - to.clientY, 2)) │ │ │ │ + }, │ │ │ │ + passesDblclickTolerance: function(evt) { │ │ │ │ + var passes = true; │ │ │ │ + if (this.down && this.first) { │ │ │ │ + passes = this.down.xy.distanceTo(this.first.xy) <= this.dblclickTolerance │ │ │ │ + } │ │ │ │ + return passes │ │ │ │ + }, │ │ │ │ + clearTimer: function() { │ │ │ │ + if (this.timerId != null) { │ │ │ │ + window.clearTimeout(this.timerId); │ │ │ │ + this.timerId = null │ │ │ │ + } │ │ │ │ + if (this.rightclickTimerId != null) { │ │ │ │ + window.clearTimeout(this.rightclickTimerId); │ │ │ │ + this.rightclickTimerId = null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + delayedCall: function(evt) { │ │ │ │ + this.timerId = null; │ │ │ │ + if (evt) { │ │ │ │ + this.callback("click", [evt]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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.Handler.Keyboard = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + KEY_EVENTS: ["keydown", "keyup"], │ │ │ │ + eventListener: null, │ │ │ │ + observeElement: null, │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ + this.eventListener = OpenLayers.Function.bindAsEventListener(this.handleKeyEvent, this) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + this.eventListener = null; │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleKeyEvent: function(evt) { │ │ │ │ + if (this.checkModifiers(evt)) { │ │ │ │ + this.callback(evt.type, [evt]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Keyboard" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + dragHandler: null, │ │ │ │ + boxDivClassName: "olHandlerBoxZoomBox", │ │ │ │ + boxOffsets: null, │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ + this.dragHandler = new OpenLayers.Handler.Drag(this, { │ │ │ │ + down: this.startBox, │ │ │ │ + move: this.moveBox, │ │ │ │ + out: this.removeBox, │ │ │ │ + up: this.endBox │ │ │ │ + }, { │ │ │ │ + keyMask: this.keyMask │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ + if (this.dragHandler) { │ │ │ │ + this.dragHandler.destroy(); │ │ │ │ + this.dragHandler = null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Handler.prototype.setMap.apply(this, arguments); │ │ │ │ + if (this.dragHandler) { │ │ │ │ + this.dragHandler.setMap(map) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + startBox: function(xy) { │ │ │ │ + this.callback("start", []); │ │ │ │ + this.zoomBox = OpenLayers.Util.createDiv("zoomBox", { │ │ │ │ + x: -9999, │ │ │ │ + y: -9999 │ │ │ │ + }); │ │ │ │ + this.zoomBox.className = this.boxDivClassName; │ │ │ │ + this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1; │ │ │ │ + this.map.viewPortDiv.appendChild(this.zoomBox); │ │ │ │ + OpenLayers.Element.addClass(this.map.viewPortDiv, "olDrawBox") │ │ │ │ + }, │ │ │ │ + moveBox: function(xy) { │ │ │ │ + var startX = this.dragHandler.start.x; │ │ │ │ + var startY = this.dragHandler.start.y; │ │ │ │ + var deltaX = Math.abs(startX - xy.x); │ │ │ │ + var deltaY = Math.abs(startY - xy.y); │ │ │ │ + var offset = this.getBoxOffsets(); │ │ │ │ + this.zoomBox.style.width = deltaX + offset.width + 1 + "px"; │ │ │ │ + this.zoomBox.style.height = deltaY + offset.height + 1 + "px"; │ │ │ │ + this.zoomBox.style.left = (xy.x < startX ? startX - deltaX - offset.left : startX - offset.left) + "px"; │ │ │ │ + this.zoomBox.style.top = (xy.y < startY ? startY - deltaY - offset.top : startY - offset.top) + "px" │ │ │ │ + }, │ │ │ │ + endBox: function(end) { │ │ │ │ + var result; │ │ │ │ + if (Math.abs(this.dragHandler.start.x - end.x) > 5 || Math.abs(this.dragHandler.start.y - end.y) > 5) { │ │ │ │ + var start = this.dragHandler.start; │ │ │ │ + var top = Math.min(start.y, end.y); │ │ │ │ + var bottom = Math.max(start.y, end.y); │ │ │ │ + var left = Math.min(start.x, end.x); │ │ │ │ + var right = Math.max(start.x, end.x); │ │ │ │ + result = new OpenLayers.Bounds(left, bottom, right, top) │ │ │ │ + } else { │ │ │ │ + result = this.dragHandler.start.clone() │ │ │ │ + } │ │ │ │ + this.removeBox(); │ │ │ │ + this.callback("done", [result]) │ │ │ │ + }, │ │ │ │ + removeBox: function() { │ │ │ │ + this.map.viewPortDiv.removeChild(this.zoomBox); │ │ │ │ + this.zoomBox = null; │ │ │ │ + this.boxOffsets = null; │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olDrawBox") │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.dragHandler.activate(); │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + if (this.dragHandler.deactivate()) { │ │ │ │ + if (this.zoomBox) { │ │ │ │ + this.removeBox() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getBoxOffsets: function() { │ │ │ │ + if (!this.boxOffsets) { │ │ │ │ + var testDiv = document.createElement("div"); │ │ │ │ + testDiv.style.position = "absolute"; │ │ │ │ + testDiv.style.border = "1px solid black"; │ │ │ │ + testDiv.style.width = "3px"; │ │ │ │ + document.body.appendChild(testDiv); │ │ │ │ + var w3cBoxModel = testDiv.clientWidth == 3; │ │ │ │ + document.body.removeChild(testDiv); │ │ │ │ + var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-left-width")); │ │ │ │ + var right = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-right-width")); │ │ │ │ + var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-top-width")); │ │ │ │ + var bottom = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-bottom-width")); │ │ │ │ + this.boxOffsets = { │ │ │ │ + left: left, │ │ │ │ + right: right, │ │ │ │ + top: top, │ │ │ │ + bottom: bottom, │ │ │ │ + width: w3cBoxModel === false ? left + right : 0, │ │ │ │ + height: w3cBoxModel === false ? top + bottom : 0 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return this.boxOffsets │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Box" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + wheelListener: null, │ │ │ │ + interval: 0, │ │ │ │ + maxDelta: Number.POSITIVE_INFINITY, │ │ │ │ + delta: 0, │ │ │ │ + cumulative: true, │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ + this.wheelListener = OpenLayers.Function.bindAsEventListener(this.onWheelEvent, this) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ + this.wheelListener = null │ │ │ │ + }, │ │ │ │ + onWheelEvent: function(e) { │ │ │ │ + if (!this.map || !this.checkModifiers(e)) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + var overScrollableDiv = false; │ │ │ │ + var allowScroll = false; │ │ │ │ + var overMapDiv = false; │ │ │ │ + var elem = OpenLayers.Event.element(e); │ │ │ │ + while (elem != null && !overMapDiv && !overScrollableDiv) { │ │ │ │ + if (!overScrollableDiv) { │ │ │ │ + try { │ │ │ │ + var overflow; │ │ │ │ + if (elem.currentStyle) { │ │ │ │ + overflow = elem.currentStyle["overflow"] │ │ │ │ + } else { │ │ │ │ + var style = document.defaultView.getComputedStyle(elem, null); │ │ │ │ + overflow = style.getPropertyValue("overflow") │ │ │ │ + } │ │ │ │ + overScrollableDiv = overflow && overflow == "auto" || overflow == "scroll" │ │ │ │ + } catch (err) {} │ │ │ │ + } │ │ │ │ + if (!allowScroll) { │ │ │ │ + allowScroll = OpenLayers.Element.hasClass(elem, "olScrollable"); │ │ │ │ + if (!allowScroll) { │ │ │ │ + for (var i = 0, len = this.map.layers.length; i < len; i++) { │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + if (elem == layer.div || elem == layer.pane) { │ │ │ │ + allowScroll = true; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + overMapDiv = elem == this.map.div; │ │ │ │ + elem = elem.parentNode │ │ │ │ + } │ │ │ │ + if (!overScrollableDiv && overMapDiv) { │ │ │ │ + if (allowScroll) { │ │ │ │ + var delta = 0; │ │ │ │ + if (e.wheelDelta) { │ │ │ │ + delta = e.wheelDelta; │ │ │ │ + if (delta % 160 === 0) { │ │ │ │ + delta = delta * .75 │ │ │ │ + } │ │ │ │ + delta = delta / 120 │ │ │ │ + } else if (e.detail) { │ │ │ │ + delta = -(e.detail / Math.abs(e.detail)) │ │ │ │ + } │ │ │ │ + this.delta += delta; │ │ │ │ + window.clearTimeout(this._timeoutId); │ │ │ │ + if (this.interval && Math.abs(this.delta) < this.maxDelta) { │ │ │ │ + var evt = OpenLayers.Util.extend({}, e); │ │ │ │ + this._timeoutId = window.setTimeout(OpenLayers.Function.bind(function() { │ │ │ │ + this.wheelZoom(evt) │ │ │ │ + }, this), this.interval) │ │ │ │ + } else { │ │ │ │ + this.wheelZoom(e) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + OpenLayers.Event.stop(e) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + wheelZoom: function(e) { │ │ │ │ + var delta = this.delta; │ │ │ │ + this.delta = 0; │ │ │ │ + if (delta) { │ │ │ │ + e.xy = this.map.events.getMousePosition(e); │ │ │ │ + if (delta < 0) { │ │ │ │ + this.callback("down", [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]) │ │ │ │ + } else { │ │ │ │ + this.callback("up", [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + activate: function(evt) { │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + var wheelListener = this.wheelListener; │ │ │ │ + OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener); │ │ │ │ + OpenLayers.Event.observe(window, "mousewheel", wheelListener); │ │ │ │ + OpenLayers.Event.observe(document, "mousewheel", wheelListener); │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + deactivate: function(evt) { │ │ │ │ + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + var wheelListener = this.wheelListener; │ │ │ │ + OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener); │ │ │ │ + OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener); │ │ │ │ + OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener); │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.MouseWheel" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.Pinch = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + started: false, │ │ │ │ + stopDown: false, │ │ │ │ + pinching: false, │ │ │ │ + last: null, │ │ │ │ + start: null, │ │ │ │ + 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) { │ │ │ │ + return false │ │ │ │ + } else { │ │ │ │ + this.started = false; │ │ │ │ + this.start = null; │ │ │ │ + this.last = null │ │ │ │ + } │ │ │ │ + OpenLayers.Event.preventDefault(evt); │ │ │ │ + return 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; │ │ │ │ + OpenLayers.Event.stop(evt) │ │ │ │ + } else if (this.started) { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + var activated = false; │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.pinching = false; │ │ │ │ + activated = true │ │ │ │ + } │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var zoom = this.getZoom(); │ │ │ │ - var extent = this.map.getMaxExtent(); │ │ │ │ - var deg = this.lzd / Math.pow(2, this.getZoom()); │ │ │ │ - var x = Math.floor((bounds.left - extent.left) / deg); │ │ │ │ - var y = Math.floor((bounds.bottom - extent.bottom) / deg); │ │ │ │ - if (this.map.getResolution() <= this.lzd / 512 && this.getZoom() <= this.zoomLevels) { │ │ │ │ - return this.getFullRequestString({ │ │ │ │ - L: zoom, │ │ │ │ - X: x, │ │ │ │ - Y: y │ │ │ │ - }) │ │ │ │ - } else { │ │ │ │ - return OpenLayers.Util.getImageLocation("blank.gif") │ │ │ │ + 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)) │ │ │ │ + }, │ │ │ │ + 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.Layer.WorldWind" │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Pinch" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.TileCache = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ +OpenLayers.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ isBaseLayer: true, │ │ │ │ - format: "image/png", │ │ │ │ + sphericalMercator: false, │ │ │ │ + zoomOffset: 0, │ │ │ │ serverResolutions: null, │ │ │ │ - initialize: function(name, url, layername, options) { │ │ │ │ - this.layername = layername; │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, [name, url, {}, options]); │ │ │ │ - this.extension = this.format.split("/")[1].toLowerCase(); │ │ │ │ - this.extension = this.extension == "jpg" ? "jpeg" : this.extension │ │ │ │ + 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]) │ │ │ │ }, │ │ │ │ clone: function(obj) { │ │ │ │ if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.TileCache(this.name, this.url, this.layername, this.getOptions()) │ │ │ │ + obj = new OpenLayers.Layer.XYZ(this.name, this.url, this.getOptions()) │ │ │ │ } │ │ │ │ obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ return obj │ │ │ │ }, │ │ │ │ getURL: function(bounds) { │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var bbox = this.maxExtent; │ │ │ │ - var size = this.tileSize; │ │ │ │ - var tileX = Math.round((bounds.left - bbox.left) / (res * size.w)); │ │ │ │ - var tileY = Math.round((bounds.bottom - bbox.bottom) / (res * size.h)); │ │ │ │ - var tileZ = this.serverResolutions != null ? OpenLayers.Util.indexOf(this.serverResolutions, res) : this.map.getZoom(); │ │ │ │ - var components = [this.layername, OpenLayers.Number.zeroPad(tileZ, 2), OpenLayers.Number.zeroPad(parseInt(tileX / 1e6), 3), OpenLayers.Number.zeroPad(parseInt(tileX / 1e3) % 1e3, 3), OpenLayers.Number.zeroPad(parseInt(tileX) % 1e3, 3), OpenLayers.Number.zeroPad(parseInt(tileY / 1e6), 3), OpenLayers.Number.zeroPad(parseInt(tileY / 1e3) % 1e3, 3), OpenLayers.Number.zeroPad(parseInt(tileY) % 1e3, 3) + "." + this.extension]; │ │ │ │ - var path = components.join("/"); │ │ │ │ + var xyz = this.getXYZ(bounds); │ │ │ │ var url = this.url; │ │ │ │ if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(path, url) │ │ │ │ + var s = "" + xyz.x + xyz.y + xyz.z; │ │ │ │ + url = this.selectUrl(s, url) │ │ │ │ } │ │ │ │ - url = url.charAt(url.length - 1) == "/" ? url : url + "/"; │ │ │ │ - return url + path │ │ │ │ + return OpenLayers.String.format(url, xyz) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.TileCache" │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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.Format.Text = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ - defaultStyle: null, │ │ │ │ - extractStyles: true, │ │ │ │ +OpenLayers.Layer.UTFGrid = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ + isBaseLayer: false, │ │ │ │ + projection: new OpenLayers.Projection("EPSG:900913"), │ │ │ │ + useJSONP: false, │ │ │ │ + tileClass: OpenLayers.Tile.UTFGrid, │ │ │ │ initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - if (options.extractStyles !== false) { │ │ │ │ - options.defaultStyle = { │ │ │ │ - externalGraphic: OpenLayers.Util.getImageLocation("marker.png"), │ │ │ │ - graphicWidth: 21, │ │ │ │ - graphicHeight: 25, │ │ │ │ - graphicXOffset: -10.5, │ │ │ │ - graphicYOffset: -12.5 │ │ │ │ - } │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, [options.name, options.url, {}, options]); │ │ │ │ + this.tileOptions = OpenLayers.Util.extend({ │ │ │ │ + utfgridResolution: this.utfgridResolution │ │ │ │ + }, this.tileOptions) │ │ │ │ + }, │ │ │ │ + createBackBuffer: function() {}, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.UTFGrid(this.getOptions()) │ │ │ │ } │ │ │ │ - OpenLayers.Format.prototype.initialize.apply(this, [options]) │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ }, │ │ │ │ - read: function(text) { │ │ │ │ - var lines = text.split("\n"); │ │ │ │ - var columns; │ │ │ │ - var features = []; │ │ │ │ - for (var lcv = 0; lcv < lines.length - 1; lcv++) { │ │ │ │ - var currLine = lines[lcv].replace(/^\s*/, "").replace(/\s*$/, ""); │ │ │ │ - if (currLine.charAt(0) != "#") { │ │ │ │ - if (!columns) { │ │ │ │ - columns = currLine.split("\t") │ │ │ │ - } else { │ │ │ │ - var vals = currLine.split("\t"); │ │ │ │ - var geometry = new OpenLayers.Geometry.Point(0, 0); │ │ │ │ - var attributes = {}; │ │ │ │ - var style = this.defaultStyle ? OpenLayers.Util.applyDefaults({}, this.defaultStyle) : null; │ │ │ │ - var icon, iconSize, iconOffset, overflow; │ │ │ │ - var set = false; │ │ │ │ - for (var valIndex = 0; valIndex < vals.length; valIndex++) { │ │ │ │ - if (vals[valIndex]) { │ │ │ │ - if (columns[valIndex] == "point") { │ │ │ │ - var coords = vals[valIndex].split(","); │ │ │ │ - geometry.y = parseFloat(coords[0]); │ │ │ │ - geometry.x = parseFloat(coords[1]); │ │ │ │ - set = true │ │ │ │ - } else if (columns[valIndex] == "lat") { │ │ │ │ - geometry.y = parseFloat(vals[valIndex]); │ │ │ │ - set = true │ │ │ │ - } else if (columns[valIndex] == "lon") { │ │ │ │ - geometry.x = parseFloat(vals[valIndex]); │ │ │ │ - set = true │ │ │ │ - } else if (columns[valIndex] == "title") attributes["title"] = vals[valIndex]; │ │ │ │ - else if (columns[valIndex] == "image" || columns[valIndex] == "icon" && style) { │ │ │ │ - style["externalGraphic"] = vals[valIndex] │ │ │ │ - } else if (columns[valIndex] == "iconSize" && style) { │ │ │ │ - var size = vals[valIndex].split(","); │ │ │ │ - style["graphicWidth"] = parseFloat(size[0]); │ │ │ │ - style["graphicHeight"] = parseFloat(size[1]) │ │ │ │ - } else if (columns[valIndex] == "iconOffset" && style) { │ │ │ │ - var offset = vals[valIndex].split(","); │ │ │ │ - style["graphicXOffset"] = parseFloat(offset[0]); │ │ │ │ - style["graphicYOffset"] = parseFloat(offset[1]) │ │ │ │ - } else if (columns[valIndex] == "description") { │ │ │ │ - attributes["description"] = vals[valIndex] │ │ │ │ - } else if (columns[valIndex] == "overflow") { │ │ │ │ - attributes["overflow"] = vals[valIndex] │ │ │ │ - } else { │ │ │ │ - attributes[columns[valIndex]] = vals[valIndex] │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (set) { │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - geometry.transform(this.externalProjection, this.internalProjection) │ │ │ │ - } │ │ │ │ - var feature = new OpenLayers.Feature.Vector(geometry, attributes, style); │ │ │ │ - features.push(feature) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + getFeatureInfo: function(location) { │ │ │ │ + var info = null; │ │ │ │ + var tileInfo = this.getTileData(location); │ │ │ │ + if (tileInfo && tileInfo.tile) { │ │ │ │ + info = tileInfo.tile.getFeatureInfo(tileInfo.i, tileInfo.j) │ │ │ │ } │ │ │ │ - return features │ │ │ │ + return info │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.Text" │ │ │ │ + getFeatureId: function(location) { │ │ │ │ + var id = null; │ │ │ │ + var info = this.getTileData(location); │ │ │ │ + if (info.tile) { │ │ │ │ + id = info.tile.getFeatureId(info.i, info.j) │ │ │ │ + } │ │ │ │ + return id │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.UTFGrid" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.Text = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ - location: null, │ │ │ │ - features: null, │ │ │ │ - formatOptions: null, │ │ │ │ - selectedFeature: null, │ │ │ │ - initialize: function(name, options) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.initialize.apply(this, arguments); │ │ │ │ - this.features = [] │ │ │ │ +OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ + key: null, │ │ │ │ + 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, .5971642833948135, .29858214169740677, .14929107084870338, .07464553542435169], │ │ │ │ + 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>", │ │ │ │ + metadata: null, │ │ │ │ + protocolRegex: /^http:/i, │ │ │ │ + type: "Road", │ │ │ │ + culture: "en-US", │ │ │ │ + metadataParams: null, │ │ │ │ + tileOptions: null, │ │ │ │ + protocol: ~window.location.href.indexOf("http") ? "" : "http:", │ │ │ │ + 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() │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ - this.clearFeatures(); │ │ │ │ - this.features = null │ │ │ │ + loadMetadata: function() { │ │ │ │ + this._callbackId = "_callback_" + this.id.replace(/\./g, "_"); │ │ │ │ + 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) │ │ │ │ }, │ │ │ │ - loadText: function() { │ │ │ │ - if (!this.loaded) { │ │ │ │ - if (this.location != null) { │ │ │ │ - var onFail = function(e) { │ │ │ │ - this.events.triggerEvent("loadend") │ │ │ │ - }; │ │ │ │ - this.events.triggerEvent("loadstart"); │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ - url: this.location, │ │ │ │ - success: this.parseData, │ │ │ │ - failure: onFail, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.loaded = true │ │ │ │ - } │ │ │ │ + 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])) │ │ │ │ } │ │ │ │ - }, │ │ │ │ - moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ - if (this.visibility && !this.loaded) { │ │ │ │ - this.loadText() │ │ │ │ + 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() │ │ │ │ }, │ │ │ │ - parseData: function(ajaxRequest) { │ │ │ │ - var text = ajaxRequest.responseText; │ │ │ │ - var options = {}; │ │ │ │ - OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ - if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ - options.externalProjection = this.projection; │ │ │ │ - options.internalProjection = this.map.getProjectionObject() │ │ │ │ + getURL: function(bounds) { │ │ │ │ + if (!this.url) { │ │ │ │ + return │ │ │ │ } │ │ │ │ - var parser = new OpenLayers.Format.Text(options); │ │ │ │ - var features = parser.read(text); │ │ │ │ - for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ - var data = {}; │ │ │ │ - var feature = features[i]; │ │ │ │ - var location; │ │ │ │ - var iconSize, iconOffset; │ │ │ │ - location = new OpenLayers.LonLat(feature.geometry.x, feature.geometry.y); │ │ │ │ - if (feature.style.graphicWidth && feature.style.graphicHeight) { │ │ │ │ - iconSize = new OpenLayers.Size(feature.style.graphicWidth, feature.style.graphicHeight) │ │ │ │ + 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 (feature.style.graphicXOffset !== undefined && feature.style.graphicYOffset !== undefined) { │ │ │ │ - iconOffset = new OpenLayers.Pixel(feature.style.graphicXOffset, feature.style.graphicYOffset) │ │ │ │ + if ((y & mask) != 0) { │ │ │ │ + digit++; │ │ │ │ + digit++ │ │ │ │ } │ │ │ │ - if (feature.style.externalGraphic != null) { │ │ │ │ - data.icon = new OpenLayers.Icon(feature.style.externalGraphic, iconSize, iconOffset) │ │ │ │ - } else { │ │ │ │ - data.icon = OpenLayers.Marker.defaultIcon(); │ │ │ │ - if (iconSize != null) { │ │ │ │ - data.icon.setSize(iconSize) │ │ │ │ + quadDigits.push(digit) │ │ │ │ + } │ │ │ │ + var quadKey = quadDigits.join(""); │ │ │ │ + var url = this.selectUrl("" + x + y + z, this.url); │ │ │ │ + return OpenLayers.String.format(url, { │ │ │ │ + quadkey: quadKey │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + 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]; │ │ │ │ + bbox = OpenLayers.Bounds.fromArray(coverage.bbox, true); │ │ │ │ + if (extent.intersectsBounds(bbox) && zoom <= coverage.zoomMax && zoom >= coverage.zoomMin) { │ │ │ │ + copyrights += provider.attribution + " " │ │ │ │ } │ │ │ │ } │ │ │ │ - if (feature.attributes.title != null && feature.attributes.description != null) { │ │ │ │ - data["popupContentHTML"] = "<h2>" + feature.attributes.title + "</h2>" + "<p>" + feature.attributes.description + "</p>" │ │ │ │ - } │ │ │ │ - data["overflow"] = feature.attributes.overflow || "auto"; │ │ │ │ - var markerFeature = new OpenLayers.Feature(this, location, data); │ │ │ │ - this.features.push(markerFeature); │ │ │ │ - var marker = markerFeature.createMarker(); │ │ │ │ - if (feature.attributes.title != null && feature.attributes.description != null) { │ │ │ │ - marker.events.register("click", markerFeature, this.markerClick) │ │ │ │ - } │ │ │ │ - this.addMarker(marker) │ │ │ │ } │ │ │ │ - this.events.triggerEvent("loadend") │ │ │ │ + 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" │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - markerClick: function(evt) { │ │ │ │ - var sameMarkerClicked = this == this.layer.selectedFeature; │ │ │ │ - this.layer.selectedFeature = !sameMarkerClicked ? this : null; │ │ │ │ - for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ - this.layer.map.removePopup(this.layer.map.popups[i]) │ │ │ │ + setMap: function() { │ │ │ │ + OpenLayers.Layer.XYZ.prototype.setMap.apply(this, arguments); │ │ │ │ + this.map.events.register("moveend", this, this.updateAttribution) │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.Bing(this.options) │ │ │ │ } │ │ │ │ - if (!sameMarkerClicked) { │ │ │ │ - this.layer.map.addPopup(this.createPopup()) │ │ │ │ + obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +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; │ │ │ │ + delete this._callbackId │ │ │ │ +}; │ │ │ │ +OpenLayers.Layer.FixedZoomLevels = OpenLayers.Class({ │ │ │ │ + initialize: function() {}, │ │ │ │ + initResolutions: function() { │ │ │ │ + var props = ["minZoomLevel", "maxZoomLevel", "numZoomLevels"]; │ │ │ │ + for (var i = 0, len = props.length; i < len; i++) { │ │ │ │ + var property = props[i]; │ │ │ │ + this[property] = this.options[property] != null ? this.options[property] : this.map[property] │ │ │ │ + } │ │ │ │ + if (this.minZoomLevel == null || this.minZoomLevel < this.MIN_ZOOM_LEVEL) { │ │ │ │ + this.minZoomLevel = this.MIN_ZOOM_LEVEL │ │ │ │ + } │ │ │ │ + var desiredZoomLevels; │ │ │ │ + var limitZoomLevels = this.MAX_ZOOM_LEVEL - this.minZoomLevel + 1; │ │ │ │ + if (this.options.numZoomLevels == null && this.options.maxZoomLevel != null || this.numZoomLevels == null && this.maxZoomLevel != null) { │ │ │ │ + desiredZoomLevels = this.maxZoomLevel - this.minZoomLevel + 1 │ │ │ │ + } else { │ │ │ │ + desiredZoomLevels = this.numZoomLevels │ │ │ │ + } │ │ │ │ + if (desiredZoomLevels != null) { │ │ │ │ + this.numZoomLevels = Math.min(desiredZoomLevels, limitZoomLevels) │ │ │ │ + } else { │ │ │ │ + this.numZoomLevels = limitZoomLevels │ │ │ │ + } │ │ │ │ + this.maxZoomLevel = this.minZoomLevel + this.numZoomLevels - 1; │ │ │ │ + if (this.RESOLUTIONS != null) { │ │ │ │ + var resolutionsIndex = 0; │ │ │ │ + this.resolutions = []; │ │ │ │ + for (var i = this.minZoomLevel; i <= this.maxZoomLevel; i++) { │ │ │ │ + this.resolutions[resolutionsIndex++] = this.RESOLUTIONS[i] │ │ │ │ + } │ │ │ │ + this.maxResolution = this.resolutions[0]; │ │ │ │ + this.minResolution = this.resolutions[this.resolutions.length - 1] │ │ │ │ } │ │ │ │ - OpenLayers.Event.stop(evt) │ │ │ │ }, │ │ │ │ - clearFeatures: function() { │ │ │ │ - if (this.features != null) { │ │ │ │ - while (this.features.length > 0) { │ │ │ │ - var feature = this.features[0]; │ │ │ │ - OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ - feature.destroy() │ │ │ │ + getResolution: function() { │ │ │ │ + if (this.resolutions != null) { │ │ │ │ + return OpenLayers.Layer.prototype.getResolution.apply(this, arguments) │ │ │ │ + } else { │ │ │ │ + var resolution = null; │ │ │ │ + var viewSize = this.map.getSize(); │ │ │ │ + var extent = this.getExtent(); │ │ │ │ + if (viewSize != null && extent != null) { │ │ │ │ + resolution = Math.max(extent.getWidth() / viewSize.w, extent.getHeight() / viewSize.h) │ │ │ │ } │ │ │ │ + return resolution │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Text" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.Boxes = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ - drawMarker: function(marker) { │ │ │ │ - var topleft = this.map.getLayerPxFromLonLat({ │ │ │ │ - lon: marker.bounds.left, │ │ │ │ - lat: marker.bounds.top │ │ │ │ + getExtent: function() { │ │ │ │ + var size = this.map.getSize(); │ │ │ │ + var tl = this.getLonLatFromViewPortPx({ │ │ │ │ + x: 0, │ │ │ │ + y: 0 │ │ │ │ }); │ │ │ │ - var botright = this.map.getLayerPxFromLonLat({ │ │ │ │ - lon: marker.bounds.right, │ │ │ │ - lat: marker.bounds.bottom │ │ │ │ + var br = this.getLonLatFromViewPortPx({ │ │ │ │ + x: size.w, │ │ │ │ + y: size.h │ │ │ │ }); │ │ │ │ - if (botright == null || topleft == null) { │ │ │ │ - marker.display(false) │ │ │ │ + if (tl != null && br != null) { │ │ │ │ + return new OpenLayers.Bounds(tl.lon, br.lat, br.lon, tl.lat) │ │ │ │ } else { │ │ │ │ - var markerDiv = marker.draw(topleft, { │ │ │ │ - w: Math.max(1, botright.x - topleft.x), │ │ │ │ - h: Math.max(1, botright.y - topleft.y) │ │ │ │ + return null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getZoomForResolution: function(resolution) { │ │ │ │ + if (this.resolutions != null) { │ │ │ │ + return OpenLayers.Layer.prototype.getZoomForResolution.apply(this, arguments) │ │ │ │ + } else { │ │ │ │ + var extent = OpenLayers.Layer.prototype.getExtent.apply(this, []); │ │ │ │ + return this.getZoomForExtent(extent) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getOLZoomFromMapObjectZoom: function(moZoom) { │ │ │ │ + var zoom = null; │ │ │ │ + if (moZoom != null) { │ │ │ │ + zoom = moZoom - this.minZoomLevel; │ │ │ │ + if (this.map.baseLayer !== this) { │ │ │ │ + zoom = this.map.baseLayer.getZoomForResolution(this.getResolutionForZoom(zoom)) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return zoom │ │ │ │ + }, │ │ │ │ + getMapObjectZoomFromOLZoom: function(olZoom) { │ │ │ │ + var zoom = null; │ │ │ │ + if (olZoom != null) { │ │ │ │ + zoom = olZoom + this.minZoomLevel; │ │ │ │ + if (this.map.baseLayer !== this) { │ │ │ │ + zoom = this.getZoomForResolution(this.map.baseLayer.getResolutionForZoom(zoom)) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return zoom │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.FixedZoomLevels" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.Image = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ + isBaseLayer: true, │ │ │ │ + url: null, │ │ │ │ + extent: null, │ │ │ │ + size: null, │ │ │ │ + tile: null, │ │ │ │ + aspectRatio: null, │ │ │ │ + initialize: function(name, url, extent, size, options) { │ │ │ │ + this.url = url; │ │ │ │ + this.extent = extent; │ │ │ │ + this.maxExtent = extent; │ │ │ │ + this.size = size; │ │ │ │ + OpenLayers.Layer.prototype.initialize.apply(this, [name, options]); │ │ │ │ + this.aspectRatio = this.extent.getHeight() / this.size.h / (this.extent.getWidth() / this.size.w) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.tile) { │ │ │ │ + this.removeTileMonitoringHooks(this.tile); │ │ │ │ + this.tile.destroy(); │ │ │ │ + this.tile = null │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.Image(this.name, this.url, this.extent, this.size, this.getOptions()) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + if (this.options.maxResolution == null) { │ │ │ │ + this.options.maxResolution = this.aspectRatio * this.extent.getWidth() / this.size.w │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.prototype.setMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ + OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ + var firstRendering = this.tile == null; │ │ │ │ + if (zoomChanged || firstRendering) { │ │ │ │ + this.setTileSize(); │ │ │ │ + var ulPx = this.map.getLayerPxFromLonLat({ │ │ │ │ + lon: this.extent.left, │ │ │ │ + lat: this.extent.top │ │ │ │ }); │ │ │ │ - if (!marker.drawn) { │ │ │ │ - this.div.appendChild(markerDiv); │ │ │ │ - marker.drawn = true │ │ │ │ + if (firstRendering) { │ │ │ │ + this.tile = new OpenLayers.Tile.Image(this, ulPx, this.extent, null, this.tileSize); │ │ │ │ + this.addTileMonitoringHooks(this.tile) │ │ │ │ + } else { │ │ │ │ + this.tile.size = this.tileSize.clone(); │ │ │ │ + this.tile.position = ulPx.clone() │ │ │ │ } │ │ │ │ + this.tile.draw() │ │ │ │ } │ │ │ │ }, │ │ │ │ - removeMarker: function(marker) { │ │ │ │ - OpenLayers.Util.removeItem(this.markers, marker); │ │ │ │ - if (marker.div != null && marker.div.parentNode == this.div) { │ │ │ │ - this.div.removeChild(marker.div) │ │ │ │ + setTileSize: function() { │ │ │ │ + var tileWidth = this.extent.getWidth() / this.map.getResolution(); │ │ │ │ + var tileHeight = this.extent.getHeight() / this.map.getResolution(); │ │ │ │ + this.tileSize = new OpenLayers.Size(tileWidth, tileHeight) │ │ │ │ + }, │ │ │ │ + addTileMonitoringHooks: function(tile) { │ │ │ │ + tile.onLoadStart = function() { │ │ │ │ + this.events.triggerEvent("loadstart") │ │ │ │ + }; │ │ │ │ + tile.events.register("loadstart", this, tile.onLoadStart); │ │ │ │ + tile.onLoadEnd = function() { │ │ │ │ + this.events.triggerEvent("loadend") │ │ │ │ + }; │ │ │ │ + tile.events.register("loadend", this, tile.onLoadEnd); │ │ │ │ + tile.events.register("unload", this, tile.onLoadEnd) │ │ │ │ + }, │ │ │ │ + removeTileMonitoringHooks: function(tile) { │ │ │ │ + tile.unload(); │ │ │ │ + tile.events.un({ │ │ │ │ + loadstart: tile.onLoadStart, │ │ │ │ + loadend: tile.onLoadEnd, │ │ │ │ + unload: tile.onLoadEnd, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + setUrl: function(newUrl) { │ │ │ │ + this.url = newUrl; │ │ │ │ + this.tile.draw() │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + return this.url │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Image" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.KaMap = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + isBaseLayer: true, │ │ │ │ + DEFAULT_PARAMS: { │ │ │ │ + i: "jpeg", │ │ │ │ + map: "" │ │ │ │ + }, │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ + this.params = OpenLayers.Util.applyDefaults(this.params, this.DEFAULT_PARAMS) │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ + var scale = Math.round(this.map.getScale() * 1e4) / 1e4; │ │ │ │ + var pX = Math.round(bounds.left / mapRes); │ │ │ │ + var pY = -Math.round(bounds.top / mapRes); │ │ │ │ + return this.getFullRequestString({ │ │ │ │ + t: pY, │ │ │ │ + l: pX, │ │ │ │ + s: scale │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + calculateGridLayout: function(bounds, origin, resolution) { │ │ │ │ + var tilelon = resolution * this.tileSize.w; │ │ │ │ + var tilelat = resolution * this.tileSize.h; │ │ │ │ + var offsetlon = bounds.left; │ │ │ │ + var tilecol = Math.floor(offsetlon / tilelon) - this.buffer; │ │ │ │ + var offsetlat = bounds.top; │ │ │ │ + var tilerow = Math.floor(offsetlat / tilelat) + this.buffer; │ │ │ │ + return { │ │ │ │ + tilelon: tilelon, │ │ │ │ + tilelat: tilelat, │ │ │ │ + startcol: tilecol, │ │ │ │ + startrow: tilerow │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Boxes" │ │ │ │ + getTileBoundsForGridIndex: function(row, col) { │ │ │ │ + var origin = this.getTileOrigin(); │ │ │ │ + var tileLayout = this.gridLayout; │ │ │ │ + var tilelon = tileLayout.tilelon; │ │ │ │ + var tilelat = tileLayout.tilelat; │ │ │ │ + var minX = (tileLayout.startcol + col) * tilelon; │ │ │ │ + var minY = (tileLayout.startrow - row) * tilelat; │ │ │ │ + return new OpenLayers.Bounds(minX, minY, minX + tilelon, minY + tilelat) │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.KaMap(this.name, this.url, this.params, this.getOptions()) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + if (this.tileSize != null) { │ │ │ │ + obj.tileSize = this.tileSize.clone() │ │ │ │ + } │ │ │ │ + obj.grid = []; │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + getTileBounds: function(viewPortPx) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var tileMapWidth = resolution * this.tileSize.w; │ │ │ │ + var tileMapHeight = resolution * this.tileSize.h; │ │ │ │ + var mapPoint = this.getLonLatFromViewPortPx(viewPortPx); │ │ │ │ + var tileLeft = tileMapWidth * Math.floor(mapPoint.lon / tileMapWidth); │ │ │ │ + var tileBottom = tileMapHeight * Math.floor(mapPoint.lat / tileMapHeight); │ │ │ │ + return new OpenLayers.Bounds(tileLeft, tileBottom, tileLeft + tileMapWidth, tileBottom + tileMapHeight) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.KaMap" │ │ │ │ }); │ │ │ │ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ isBaseLayer: false, │ │ │ │ isFixed: false, │ │ │ │ features: null, │ │ │ │ filter: null, │ │ │ │ selectedFeatures: null, │ │ │ │ @@ -16153,192 +19299,14 @@ │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ return maxExtent │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Layer.Vector" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.PointTrack = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ - dataFrom: null, │ │ │ │ - styleFrom: null, │ │ │ │ - addNodes: function(pointFeatures, options) { │ │ │ │ - if (pointFeatures.length < 2) { │ │ │ │ - throw new Error("At least two point features have to be added to " + "create a line from") │ │ │ │ - } │ │ │ │ - var lines = new Array(pointFeatures.length - 1); │ │ │ │ - var pointFeature, startPoint, endPoint; │ │ │ │ - for (var i = 0, len = pointFeatures.length; i < len; i++) { │ │ │ │ - pointFeature = pointFeatures[i]; │ │ │ │ - endPoint = pointFeature.geometry; │ │ │ │ - if (!endPoint) { │ │ │ │ - var lonlat = pointFeature.lonlat; │ │ │ │ - endPoint = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat) │ │ │ │ - } else if (endPoint.CLASS_NAME != "OpenLayers.Geometry.Point") { │ │ │ │ - throw new TypeError("Only features with point geometries are supported.") │ │ │ │ - } │ │ │ │ - if (i > 0) { │ │ │ │ - var attributes = this.dataFrom != null ? pointFeatures[i + this.dataFrom].data || pointFeatures[i + this.dataFrom].attributes : null; │ │ │ │ - var style = this.styleFrom != null ? pointFeatures[i + this.styleFrom].style : null; │ │ │ │ - var line = new OpenLayers.Geometry.LineString([startPoint, endPoint]); │ │ │ │ - lines[i - 1] = new OpenLayers.Feature.Vector(line, attributes, style) │ │ │ │ - } │ │ │ │ - startPoint = endPoint │ │ │ │ - } │ │ │ │ - this.addFeatures(lines, options) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.PointTrack" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.PointTrack.SOURCE_NODE = -1; │ │ │ │ -OpenLayers.Layer.PointTrack.TARGET_NODE = 0; │ │ │ │ -OpenLayers.Layer.PointTrack.dataFrom = { │ │ │ │ - SOURCE_NODE: -1, │ │ │ │ - TARGET_NODE: 0 │ │ │ │ -}; │ │ │ │ -OpenLayers.Tile.UTFGrid = OpenLayers.Class(OpenLayers.Tile, { │ │ │ │ - url: null, │ │ │ │ - utfgridResolution: 2, │ │ │ │ - json: null, │ │ │ │ - format: null, │ │ │ │ - destroy: function() { │ │ │ │ - this.clear(); │ │ │ │ - OpenLayers.Tile.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - draw: function() { │ │ │ │ - var drawn = OpenLayers.Tile.prototype.draw.apply(this, arguments); │ │ │ │ - if (drawn) { │ │ │ │ - if (this.isLoading) { │ │ │ │ - this.abortLoading(); │ │ │ │ - this.events.triggerEvent("reload") │ │ │ │ - } else { │ │ │ │ - this.isLoading = true; │ │ │ │ - this.events.triggerEvent("loadstart") │ │ │ │ - } │ │ │ │ - this.url = this.layer.getURL(this.bounds); │ │ │ │ - if (this.layer.useJSONP) { │ │ │ │ - var ols = new OpenLayers.Protocol.Script({ │ │ │ │ - url: this.url, │ │ │ │ - callback: function(response) { │ │ │ │ - this.isLoading = false; │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ - this.json = response.data │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - ols.read(); │ │ │ │ - this.request = ols │ │ │ │ - } else { │ │ │ │ - this.request = OpenLayers.Request.GET({ │ │ │ │ - url: this.url, │ │ │ │ - callback: function(response) { │ │ │ │ - this.isLoading = false; │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ - if (response.status === 200) { │ │ │ │ - this.parseData(response.responseText) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.unload() │ │ │ │ - } │ │ │ │ - return drawn │ │ │ │ - }, │ │ │ │ - abortLoading: function() { │ │ │ │ - if (this.request) { │ │ │ │ - this.request.abort(); │ │ │ │ - delete this.request │ │ │ │ - } │ │ │ │ - this.isLoading = false │ │ │ │ - }, │ │ │ │ - getFeatureInfo: function(i, j) { │ │ │ │ - var info = null; │ │ │ │ - if (this.json) { │ │ │ │ - var id = this.getFeatureId(i, j); │ │ │ │ - if (id !== null) { │ │ │ │ - info = { │ │ │ │ - id: id, │ │ │ │ - data: this.json.data[id] │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return info │ │ │ │ - }, │ │ │ │ - getFeatureId: function(i, j) { │ │ │ │ - var id = null; │ │ │ │ - if (this.json) { │ │ │ │ - var resolution = this.utfgridResolution; │ │ │ │ - var row = Math.floor(j / resolution); │ │ │ │ - var col = Math.floor(i / resolution); │ │ │ │ - var charCode = this.json.grid[row].charCodeAt(col); │ │ │ │ - var index = this.indexFromCharCode(charCode); │ │ │ │ - var keys = this.json.keys; │ │ │ │ - if (!isNaN(index) && index in keys) { │ │ │ │ - id = keys[index] │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return id │ │ │ │ - }, │ │ │ │ - indexFromCharCode: function(charCode) { │ │ │ │ - if (charCode >= 93) { │ │ │ │ - charCode-- │ │ │ │ - } │ │ │ │ - if (charCode >= 35) { │ │ │ │ - charCode-- │ │ │ │ - } │ │ │ │ - return charCode - 32 │ │ │ │ - }, │ │ │ │ - parseData: function(str) { │ │ │ │ - if (!this.format) { │ │ │ │ - this.format = new OpenLayers.Format.JSON │ │ │ │ - } │ │ │ │ - this.json = this.format.read(str) │ │ │ │ - }, │ │ │ │ - clear: function() { │ │ │ │ - this.json = null │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Tile.UTFGrid" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.UTFGrid = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ - isBaseLayer: false, │ │ │ │ - projection: new OpenLayers.Projection("EPSG:900913"), │ │ │ │ - useJSONP: false, │ │ │ │ - tileClass: OpenLayers.Tile.UTFGrid, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, [options.name, options.url, {}, options]); │ │ │ │ - this.tileOptions = OpenLayers.Util.extend({ │ │ │ │ - utfgridResolution: this.utfgridResolution │ │ │ │ - }, this.tileOptions) │ │ │ │ - }, │ │ │ │ - createBackBuffer: function() {}, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.UTFGrid(this.getOptions()) │ │ │ │ - } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ - }, │ │ │ │ - getFeatureInfo: function(location) { │ │ │ │ - var info = null; │ │ │ │ - var tileInfo = this.getTileData(location); │ │ │ │ - if (tileInfo && tileInfo.tile) { │ │ │ │ - info = tileInfo.tile.getFeatureInfo(tileInfo.i, tileInfo.j) │ │ │ │ - } │ │ │ │ - return info │ │ │ │ - }, │ │ │ │ - getFeatureId: function(location) { │ │ │ │ - var id = null; │ │ │ │ - var info = this.getTileData(location); │ │ │ │ - if (info.tile) { │ │ │ │ - id = info.tile.getFeatureId(info.i, info.j) │ │ │ │ - } │ │ │ │ - return id │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.UTFGrid" │ │ │ │ -}); │ │ │ │ OpenLayers.Layer.PointGrid = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ dx: null, │ │ │ │ dy: null, │ │ │ │ ratio: 1.5, │ │ │ │ maxFeatures: 250, │ │ │ │ rotation: 0, │ │ │ │ origin: null, │ │ │ │ @@ -16436,218 +19404,743 @@ │ │ │ │ } │ │ │ │ }, │ │ │ │ invalidBounds: function() { │ │ │ │ return !this.gridBounds || !this.gridBounds.containsBounds(this.getViewBounds()) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Layer.PointGrid" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.Zoomify = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - size: null, │ │ │ │ - isBaseLayer: true, │ │ │ │ - standardTileSize: 256, │ │ │ │ - tileOriginCorner: "tl", │ │ │ │ - numberOfTiers: 0, │ │ │ │ - tileCountUpToTier: null, │ │ │ │ - tierSizeInTiles: null, │ │ │ │ - tierImageSize: null, │ │ │ │ - initialize: function(name, url, size, options) { │ │ │ │ - this.initializeZoomify(size); │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, [name, url, size, {}, options]) │ │ │ │ - }, │ │ │ │ - initializeZoomify: function(size) { │ │ │ │ - var imageSize = size.clone(); │ │ │ │ - this.size = size.clone(); │ │ │ │ - var tiles = new OpenLayers.Size(Math.ceil(imageSize.w / this.standardTileSize), Math.ceil(imageSize.h / this.standardTileSize)); │ │ │ │ - this.tierSizeInTiles = [tiles]; │ │ │ │ - this.tierImageSize = [imageSize]; │ │ │ │ - while (imageSize.w > this.standardTileSize || imageSize.h > this.standardTileSize) { │ │ │ │ - imageSize = new OpenLayers.Size(Math.floor(imageSize.w / 2), Math.floor(imageSize.h / 2)); │ │ │ │ - tiles = new OpenLayers.Size(Math.ceil(imageSize.w / this.standardTileSize), Math.ceil(imageSize.h / this.standardTileSize)); │ │ │ │ - this.tierSizeInTiles.push(tiles); │ │ │ │ - this.tierImageSize.push(imageSize) │ │ │ │ - } │ │ │ │ - this.tierSizeInTiles.reverse(); │ │ │ │ - this.tierImageSize.reverse(); │ │ │ │ - this.numberOfTiers = this.tierSizeInTiles.length; │ │ │ │ - var resolutions = [1]; │ │ │ │ - this.tileCountUpToTier = [0]; │ │ │ │ - for (var i = 1; i < this.numberOfTiers; i++) { │ │ │ │ - resolutions.unshift(Math.pow(2, i)); │ │ │ │ - this.tileCountUpToTier.push(this.tierSizeInTiles[i - 1].w * this.tierSizeInTiles[i - 1].h + this.tileCountUpToTier[i - 1]) │ │ │ │ +OpenLayers.Layer.ArcGISCache = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ + url: null, │ │ │ │ + tileOrigin: null, │ │ │ │ + tileSize: new OpenLayers.Size(256, 256), │ │ │ │ + useArcGISServer: true, │ │ │ │ + type: "png", │ │ │ │ + useScales: false, │ │ │ │ + overrideDPI: false, │ │ │ │ + initialize: function(name, url, options) { │ │ │ │ + OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments); │ │ │ │ + if (this.resolutions) { │ │ │ │ + this.serverResolutions = this.resolutions; │ │ │ │ + this.maxExtent = this.getMaxExtentForResolution(this.resolutions[0]) │ │ │ │ } │ │ │ │ - if (!this.serverResolutions) { │ │ │ │ - this.serverResolutions = resolutions │ │ │ │ + if (this.layerInfo) { │ │ │ │ + var info = this.layerInfo; │ │ │ │ + var startingTileExtent = new OpenLayers.Bounds(info.fullExtent.xmin, info.fullExtent.ymin, info.fullExtent.xmax, info.fullExtent.ymax); │ │ │ │ + this.projection = "EPSG:" + info.spatialReference.wkid; │ │ │ │ + this.sphericalMercator = info.spatialReference.wkid == 102100; │ │ │ │ + this.units = info.units == "esriFeet" ? "ft" : "m"; │ │ │ │ + if (!!info.tileInfo) { │ │ │ │ + this.tileSize = new OpenLayers.Size(info.tileInfo.width || info.tileInfo.cols, info.tileInfo.height || info.tileInfo.rows); │ │ │ │ + this.tileOrigin = new OpenLayers.LonLat(info.tileInfo.origin.x, info.tileInfo.origin.y); │ │ │ │ + var upperLeft = new OpenLayers.Geometry.Point(startingTileExtent.left, startingTileExtent.top); │ │ │ │ + var bottomRight = new OpenLayers.Geometry.Point(startingTileExtent.right, startingTileExtent.bottom); │ │ │ │ + if (this.useScales) { │ │ │ │ + this.scales = [] │ │ │ │ + } else { │ │ │ │ + this.resolutions = [] │ │ │ │ + } │ │ │ │ + this.lods = []; │ │ │ │ + for (var key in info.tileInfo.lods) { │ │ │ │ + if (info.tileInfo.lods.hasOwnProperty(key)) { │ │ │ │ + var lod = info.tileInfo.lods[key]; │ │ │ │ + if (this.useScales) { │ │ │ │ + this.scales.push(lod.scale) │ │ │ │ + } else { │ │ │ │ + this.resolutions.push(lod.resolution) │ │ │ │ + } │ │ │ │ + var start = this.getContainingTileCoords(upperLeft, lod.resolution); │ │ │ │ + lod.startTileCol = start.x; │ │ │ │ + lod.startTileRow = start.y; │ │ │ │ + var end = this.getContainingTileCoords(bottomRight, lod.resolution); │ │ │ │ + lod.endTileCol = end.x; │ │ │ │ + lod.endTileRow = end.y; │ │ │ │ + this.lods.push(lod) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.maxExtent = this.calculateMaxExtentWithLOD(this.lods[0]); │ │ │ │ + this.serverResolutions = this.resolutions; │ │ │ │ + if (this.overrideDPI && info.tileInfo.dpi) { │ │ │ │ + OpenLayers.DOTS_PER_INCH = info.tileInfo.dpi │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments); │ │ │ │ - this.tileCountUpToTier.length = 0; │ │ │ │ - this.tierSizeInTiles.length = 0; │ │ │ │ - this.tierImageSize.length = 0 │ │ │ │ + getContainingTileCoords: function(point, res) { │ │ │ │ + return new OpenLayers.Pixel(Math.max(Math.floor((point.x - this.tileOrigin.lon) / (this.tileSize.w * res)), 0), Math.max(Math.floor((this.tileOrigin.lat - point.y) / (this.tileSize.h * res)), 0)) │ │ │ │ + }, │ │ │ │ + calculateMaxExtentWithLOD: function(lod) { │ │ │ │ + var numTileCols = lod.endTileCol - lod.startTileCol + 1; │ │ │ │ + var numTileRows = lod.endTileRow - lod.startTileRow + 1; │ │ │ │ + var minX = this.tileOrigin.lon + lod.startTileCol * this.tileSize.w * lod.resolution; │ │ │ │ + var maxX = minX + numTileCols * this.tileSize.w * lod.resolution; │ │ │ │ + var maxY = this.tileOrigin.lat - lod.startTileRow * this.tileSize.h * lod.resolution; │ │ │ │ + var minY = maxY - numTileRows * this.tileSize.h * lod.resolution; │ │ │ │ + return new OpenLayers.Bounds(minX, minY, maxX, maxY) │ │ │ │ + }, │ │ │ │ + calculateMaxExtentWithExtent: function(extent, res) { │ │ │ │ + var upperLeft = new OpenLayers.Geometry.Point(extent.left, extent.top); │ │ │ │ + var bottomRight = new OpenLayers.Geometry.Point(extent.right, extent.bottom); │ │ │ │ + var start = this.getContainingTileCoords(upperLeft, res); │ │ │ │ + var end = this.getContainingTileCoords(bottomRight, res); │ │ │ │ + var lod = { │ │ │ │ + resolution: res, │ │ │ │ + startTileCol: start.x, │ │ │ │ + startTileRow: start.y, │ │ │ │ + endTileCol: end.x, │ │ │ │ + endTileRow: end.y │ │ │ │ + }; │ │ │ │ + return this.calculateMaxExtentWithLOD(lod) │ │ │ │ + }, │ │ │ │ + getUpperLeftTileCoord: function(res) { │ │ │ │ + var upperLeft = new OpenLayers.Geometry.Point(this.maxExtent.left, this.maxExtent.top); │ │ │ │ + return this.getContainingTileCoords(upperLeft, res) │ │ │ │ + }, │ │ │ │ + getLowerRightTileCoord: function(res) { │ │ │ │ + var bottomRight = new OpenLayers.Geometry.Point(this.maxExtent.right, this.maxExtent.bottom); │ │ │ │ + return this.getContainingTileCoords(bottomRight, res) │ │ │ │ + }, │ │ │ │ + getMaxExtentForResolution: function(res) { │ │ │ │ + var start = this.getUpperLeftTileCoord(res); │ │ │ │ + var end = this.getLowerRightTileCoord(res); │ │ │ │ + var numTileCols = end.x - start.x + 1; │ │ │ │ + var numTileRows = end.y - start.y + 1; │ │ │ │ + var minX = this.tileOrigin.lon + start.x * this.tileSize.w * res; │ │ │ │ + var maxX = minX + numTileCols * this.tileSize.w * res; │ │ │ │ + var maxY = this.tileOrigin.lat - start.y * this.tileSize.h * res; │ │ │ │ + var minY = maxY - numTileRows * this.tileSize.h * res; │ │ │ │ + return new OpenLayers.Bounds(minX, minY, maxX, maxY) │ │ │ │ }, │ │ │ │ clone: function(obj) { │ │ │ │ if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.Zoomify(this.name, this.url, this.size, this.options) │ │ │ │ + obj = new OpenLayers.Layer.ArcGISCache(this.name, this.url, this.options) │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ + return OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]) │ │ │ │ + }, │ │ │ │ + initGriddedTiles: function(bounds) { │ │ │ │ + delete this._tileOrigin; │ │ │ │ + OpenLayers.Layer.XYZ.prototype.initGriddedTiles.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + getMaxExtent: function() { │ │ │ │ + var resolution = this.map.getResolution(); │ │ │ │ + return this.maxExtent = this.getMaxExtentForResolution(resolution) │ │ │ │ + }, │ │ │ │ + getTileOrigin: function() { │ │ │ │ + if (!this._tileOrigin) { │ │ │ │ + var extent = this.getMaxExtent(); │ │ │ │ + this._tileOrigin = new OpenLayers.LonLat(extent.left, extent.bottom) │ │ │ │ + } │ │ │ │ + return this._tileOrigin │ │ │ │ }, │ │ │ │ getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ - var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ - var z = this.getZoomForResolution(res); │ │ │ │ - var tileIndex = x + y * this.tierSizeInTiles[z].w + this.tileCountUpToTier[z]; │ │ │ │ - var path = "TileGroup" + Math.floor(tileIndex / 256) + "/" + z + "-" + x + "-" + y + ".jpg"; │ │ │ │ + var res = this.getResolution(); │ │ │ │ + var originTileX = this.tileOrigin.lon + res * this.tileSize.w / 2; │ │ │ │ + var originTileY = this.tileOrigin.lat - res * this.tileSize.h / 2; │ │ │ │ + var center = bounds.getCenterLonLat(); │ │ │ │ + var point = { │ │ │ │ + x: center.lon, │ │ │ │ + y: center.lat │ │ │ │ + }; │ │ │ │ + var x = Math.round(Math.abs((center.lon - originTileX) / (res * this.tileSize.w))); │ │ │ │ + var y = Math.round(Math.abs((originTileY - center.lat) / (res * this.tileSize.h))); │ │ │ │ + var z = this.map.getZoom(); │ │ │ │ + if (this.lods) { │ │ │ │ + var lod = this.lods[this.map.getZoom()]; │ │ │ │ + if (x < lod.startTileCol || x > lod.endTileCol || (y < lod.startTileRow || y > lod.endTileRow)) { │ │ │ │ + return null │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + var start = this.getUpperLeftTileCoord(res); │ │ │ │ + var end = this.getLowerRightTileCoord(res); │ │ │ │ + if (x < start.x || x >= end.x || (y < start.y || y >= end.y)) { │ │ │ │ + return null │ │ │ │ + } │ │ │ │ + } │ │ │ │ var url = this.url; │ │ │ │ + var s = "" + x + y + z; │ │ │ │ if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(path, url) │ │ │ │ + url = this.selectUrl(s, url) │ │ │ │ } │ │ │ │ - return url + path │ │ │ │ + if (this.useArcGISServer) { │ │ │ │ + url = url + "/tile/${z}/${y}/${x}" │ │ │ │ + } else { │ │ │ │ + x = "C" + OpenLayers.Number.zeroPad(x, 8, 16); │ │ │ │ + y = "R" + OpenLayers.Number.zeroPad(y, 8, 16); │ │ │ │ + z = "L" + OpenLayers.Number.zeroPad(z, 2, 10); │ │ │ │ + url = url + "/${z}/${y}/${x}." + this.type │ │ │ │ + } │ │ │ │ + url = OpenLayers.String.format(url, { │ │ │ │ + x: x, │ │ │ │ + y: y, │ │ │ │ + z: z │ │ │ │ + }); │ │ │ │ + return OpenLayers.Util.urlAppend(url, OpenLayers.Util.getParameterString(this.params)) │ │ │ │ }, │ │ │ │ - getImageSize: function() { │ │ │ │ - if (arguments.length > 0) { │ │ │ │ - var bounds = this.adjustBounds(arguments[0]); │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ - var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ - var z = this.getZoomForResolution(res); │ │ │ │ - var w = this.standardTileSize; │ │ │ │ - var h = this.standardTileSize; │ │ │ │ - if (x == this.tierSizeInTiles[z].w - 1) { │ │ │ │ - var w = this.tierImageSize[z].w % this.standardTileSize │ │ │ │ - } │ │ │ │ - if (y == this.tierSizeInTiles[z].h - 1) { │ │ │ │ - var h = this.tierImageSize[z].h % this.standardTileSize │ │ │ │ - } │ │ │ │ - return new OpenLayers.Size(w, h) │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.ArcGISCache" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.SphericalMercator = { │ │ │ │ + getExtent: function() { │ │ │ │ + var extent = null; │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + extent = this.map.calculateBounds() │ │ │ │ } else { │ │ │ │ - return this.tileSize │ │ │ │ + extent = OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this) │ │ │ │ + } │ │ │ │ + return extent │ │ │ │ + }, │ │ │ │ + getLonLatFromViewPortPx: function(viewPortPx) { │ │ │ │ + return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + getViewPortPxFromLonLat: function(lonlat) { │ │ │ │ + return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + initMercatorParameters: function() { │ │ │ │ + this.RESOLUTIONS = []; │ │ │ │ + var maxResolution = 156543.03390625; │ │ │ │ + for (var zoom = 0; zoom <= this.MAX_ZOOM_LEVEL; ++zoom) { │ │ │ │ + this.RESOLUTIONS[zoom] = maxResolution / Math.pow(2, zoom) │ │ │ │ + } │ │ │ │ + this.units = "m"; │ │ │ │ + this.projection = this.projection || "EPSG:900913" │ │ │ │ + }, │ │ │ │ + forwardMercator: function() { │ │ │ │ + var gg = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ + var sm = new OpenLayers.Projection("EPSG:900913"); │ │ │ │ + return function(lon, lat) { │ │ │ │ + var point = OpenLayers.Projection.transform({ │ │ │ │ + x: lon, │ │ │ │ + y: lat │ │ │ │ + }, gg, sm); │ │ │ │ + return new OpenLayers.LonLat(point.x, point.y) │ │ │ │ + } │ │ │ │ + }(), │ │ │ │ + inverseMercator: function() { │ │ │ │ + var gg = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ + var sm = new OpenLayers.Projection("EPSG:900913"); │ │ │ │ + return function(x, y) { │ │ │ │ + var point = OpenLayers.Projection.transform({ │ │ │ │ + x: x, │ │ │ │ + y: y │ │ │ │ + }, sm, gg); │ │ │ │ + return new OpenLayers.LonLat(point.x, point.y) │ │ │ │ } │ │ │ │ + }() │ │ │ │ +}; │ │ │ │ +OpenLayers.Layer.EventPane = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ + smoothDragPan: true, │ │ │ │ + isBaseLayer: true, │ │ │ │ + isFixed: true, │ │ │ │ + pane: null, │ │ │ │ + mapObject: null, │ │ │ │ + initialize: function(name, options) { │ │ │ │ + OpenLayers.Layer.prototype.initialize.apply(this, arguments); │ │ │ │ + if (this.pane == null) { │ │ │ │ + this.pane = OpenLayers.Util.createDiv(this.div.id + "_EventPane") │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.mapObject = null; │ │ │ │ + this.pane = null; │ │ │ │ + OpenLayers.Layer.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ setMap: function(map) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left, this.map.maxExtent.top) │ │ │ │ + OpenLayers.Layer.prototype.setMap.apply(this, arguments); │ │ │ │ + this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1; │ │ │ │ + this.pane.style.display = this.div.style.display; │ │ │ │ + this.pane.style.width = "100%"; │ │ │ │ + this.pane.style.height = "100%"; │ │ │ │ + if (OpenLayers.BROWSER_NAME == "msie") { │ │ │ │ + this.pane.style.background = "url(" + OpenLayers.Util.getImageLocation("blank.gif") + ")" │ │ │ │ + } │ │ │ │ + if (this.isFixed) { │ │ │ │ + this.map.viewPortDiv.appendChild(this.pane) │ │ │ │ + } else { │ │ │ │ + this.map.layerContainerDiv.appendChild(this.pane) │ │ │ │ + } │ │ │ │ + this.loadMapObject(); │ │ │ │ + if (this.mapObject == null) { │ │ │ │ + this.loadWarningMessage() │ │ │ │ + } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Zoomify" │ │ │ │ + removeMap: function(map) { │ │ │ │ + if (this.pane && this.pane.parentNode) { │ │ │ │ + this.pane.parentNode.removeChild(this.pane) │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.prototype.removeMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + loadWarningMessage: function() { │ │ │ │ + this.div.style.backgroundColor = "darkblue"; │ │ │ │ + var viewSize = this.map.getSize(); │ │ │ │ + var msgW = Math.min(viewSize.w, 300); │ │ │ │ + var msgH = Math.min(viewSize.h, 200); │ │ │ │ + var size = new OpenLayers.Size(msgW, msgH); │ │ │ │ + var centerPx = new OpenLayers.Pixel(viewSize.w / 2, viewSize.h / 2); │ │ │ │ + var topLeft = centerPx.add(-size.w / 2, -size.h / 2); │ │ │ │ + var div = OpenLayers.Util.createDiv(this.name + "_warning", topLeft, size, null, null, null, "auto"); │ │ │ │ + div.style.padding = "7px"; │ │ │ │ + div.style.backgroundColor = "yellow"; │ │ │ │ + div.innerHTML = this.getWarningHTML(); │ │ │ │ + this.div.appendChild(div) │ │ │ │ + }, │ │ │ │ + getWarningHTML: function() { │ │ │ │ + return "" │ │ │ │ + }, │ │ │ │ + display: function(display) { │ │ │ │ + OpenLayers.Layer.prototype.display.apply(this, arguments); │ │ │ │ + this.pane.style.display = this.div.style.display │ │ │ │ + }, │ │ │ │ + setZIndex: function(zIndex) { │ │ │ │ + OpenLayers.Layer.prototype.setZIndex.apply(this, arguments); │ │ │ │ + this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1 │ │ │ │ + }, │ │ │ │ + moveByPx: function(dx, dy) { │ │ │ │ + OpenLayers.Layer.prototype.moveByPx.apply(this, arguments); │ │ │ │ + if (this.dragPanMapObject) { │ │ │ │ + this.dragPanMapObject(dx, -dy) │ │ │ │ + } else { │ │ │ │ + this.moveTo(this.map.getCachedCenter()) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ + OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ + if (this.mapObject != null) { │ │ │ │ + var newCenter = this.map.getCenter(); │ │ │ │ + var newZoom = this.map.getZoom(); │ │ │ │ + if (newCenter != null) { │ │ │ │ + var moOldCenter = this.getMapObjectCenter(); │ │ │ │ + var oldCenter = this.getOLLonLatFromMapObjectLonLat(moOldCenter); │ │ │ │ + var moOldZoom = this.getMapObjectZoom(); │ │ │ │ + var oldZoom = this.getOLZoomFromMapObjectZoom(moOldZoom); │ │ │ │ + if (!newCenter.equals(oldCenter) || newZoom != oldZoom) { │ │ │ │ + if (!zoomChanged && oldCenter && this.dragPanMapObject && this.smoothDragPan) { │ │ │ │ + var oldPx = this.map.getViewPortPxFromLonLat(oldCenter); │ │ │ │ + var newPx = this.map.getViewPortPxFromLonLat(newCenter); │ │ │ │ + this.dragPanMapObject(newPx.x - oldPx.x, oldPx.y - newPx.y) │ │ │ │ + } else { │ │ │ │ + var center = this.getMapObjectLonLatFromOLLonLat(newCenter); │ │ │ │ + var zoom = this.getMapObjectZoomFromOLZoom(newZoom); │ │ │ │ + this.setMapObjectCenter(center, zoom, dragging) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getLonLatFromViewPortPx: function(viewPortPx) { │ │ │ │ + var lonlat = null; │ │ │ │ + if (this.mapObject != null && this.getMapObjectCenter() != null) { │ │ │ │ + var moPixel = this.getMapObjectPixelFromOLPixel(viewPortPx); │ │ │ │ + var moLonLat = this.getMapObjectLonLatFromMapObjectPixel(moPixel); │ │ │ │ + lonlat = this.getOLLonLatFromMapObjectLonLat(moLonLat) │ │ │ │ + } │ │ │ │ + return lonlat │ │ │ │ + }, │ │ │ │ + getViewPortPxFromLonLat: function(lonlat) { │ │ │ │ + var viewPortPx = null; │ │ │ │ + if (this.mapObject != null && this.getMapObjectCenter() != null) { │ │ │ │ + var moLonLat = this.getMapObjectLonLatFromOLLonLat(lonlat); │ │ │ │ + var moPixel = this.getMapObjectPixelFromMapObjectLonLat(moLonLat); │ │ │ │ + viewPortPx = this.getOLPixelFromMapObjectPixel(moPixel) │ │ │ │ + } │ │ │ │ + return viewPortPx │ │ │ │ + }, │ │ │ │ + getOLLonLatFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + var olLonLat = null; │ │ │ │ + if (moLonLat != null) { │ │ │ │ + var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); │ │ │ │ + var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); │ │ │ │ + olLonLat = new OpenLayers.LonLat(lon, lat) │ │ │ │ + } │ │ │ │ + return olLonLat │ │ │ │ + }, │ │ │ │ + getMapObjectLonLatFromOLLonLat: function(olLonLat) { │ │ │ │ + var moLatLng = null; │ │ │ │ + if (olLonLat != null) { │ │ │ │ + moLatLng = this.getMapObjectLonLatFromLonLat(olLonLat.lon, olLonLat.lat) │ │ │ │ + } │ │ │ │ + return moLatLng │ │ │ │ + }, │ │ │ │ + getOLPixelFromMapObjectPixel: function(moPixel) { │ │ │ │ + var olPixel = null; │ │ │ │ + if (moPixel != null) { │ │ │ │ + var x = this.getXFromMapObjectPixel(moPixel); │ │ │ │ + var y = this.getYFromMapObjectPixel(moPixel); │ │ │ │ + olPixel = new OpenLayers.Pixel(x, y) │ │ │ │ + } │ │ │ │ + return olPixel │ │ │ │ + }, │ │ │ │ + getMapObjectPixelFromOLPixel: function(olPixel) { │ │ │ │ + var moPixel = null; │ │ │ │ + if (olPixel != null) { │ │ │ │ + moPixel = this.getMapObjectPixelFromXY(olPixel.x, olPixel.y) │ │ │ │ + } │ │ │ │ + return moPixel │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.EventPane" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.TMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - serviceVersion: "1.0.0", │ │ │ │ - layername: null, │ │ │ │ +OpenLayers.Layer.Google = OpenLayers.Class(OpenLayers.Layer.EventPane, OpenLayers.Layer.FixedZoomLevels, { │ │ │ │ + MIN_ZOOM_LEVEL: 0, │ │ │ │ + MAX_ZOOM_LEVEL: 21, │ │ │ │ + RESOLUTIONS: [1.40625, .703125, .3515625, .17578125, .087890625, .0439453125, .02197265625, .010986328125, .0054931640625, .00274658203125, .001373291015625, .0006866455078125, .00034332275390625, .000171661376953125, 858306884765625e-19, 4291534423828125e-20, 2145767211914062e-20, 1072883605957031e-20, 536441802978515e-20, 268220901489257e-20, 1341104507446289e-21, 6.705522537231445e-7], │ │ │ │ type: null, │ │ │ │ - isBaseLayer: true, │ │ │ │ - tileOrigin: null, │ │ │ │ - serverResolutions: null, │ │ │ │ - zoomOffset: 0, │ │ │ │ - initialize: function(name, url, options) { │ │ │ │ - var newArguments = []; │ │ │ │ - newArguments.push(name, url, {}, options); │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments) │ │ │ │ + wrapDateLine: true, │ │ │ │ + sphericalMercator: false, │ │ │ │ + version: null, │ │ │ │ + initialize: function(name, options) { │ │ │ │ + options = options || {}; │ │ │ │ + if (!options.version) { │ │ │ │ + options.version = typeof GMap2 === "function" ? "2" : "3" │ │ │ │ + } │ │ │ │ + var mixin = OpenLayers.Layer.Google["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (mixin) { │ │ │ │ + OpenLayers.Util.applyDefaults(options, mixin) │ │ │ │ + } else { │ │ │ │ + throw "Unsupported Google Maps API version: " + options.version │ │ │ │ + } │ │ │ │ + OpenLayers.Util.applyDefaults(options, mixin.DEFAULTS); │ │ │ │ + if (options.maxExtent) { │ │ │ │ + options.maxExtent = options.maxExtent.clone() │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.EventPane.prototype.initialize.apply(this, [name, options]); │ │ │ │ + OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, [name, options]); │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator); │ │ │ │ + this.initMercatorParameters() │ │ │ │ + } │ │ │ │ }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.TMS(this.name, this.url, this.getOptions()) │ │ │ │ + clone: function() { │ │ │ │ + return new OpenLayers.Layer.Google(this.name, this.getOptions()) │ │ │ │ + }, │ │ │ │ + setVisibility: function(visible) { │ │ │ │ + var opacity = this.opacity == null ? 1 : this.opacity; │ │ │ │ + OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this, arguments); │ │ │ │ + this.setOpacity(opacity) │ │ │ │ + }, │ │ │ │ + display: function(visible) { │ │ │ │ + if (!this._dragging) { │ │ │ │ + this.setGMapVisibility(visible) │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ + OpenLayers.Layer.EventPane.prototype.display.apply(this, arguments) │ │ │ │ }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ - var y = Math.round((bounds.bottom - this.tileOrigin.lat) / (res * this.tileSize.h)); │ │ │ │ - var z = this.getServerZoom(); │ │ │ │ - var path = this.serviceVersion + "/" + this.layername + "/" + z + "/" + x + "/" + y + "." + this.type; │ │ │ │ - var url = this.url; │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(path, url) │ │ │ │ + moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ + this._dragging = dragging; │ │ │ │ + OpenLayers.Layer.EventPane.prototype.moveTo.apply(this, arguments); │ │ │ │ + delete this._dragging │ │ │ │ + }, │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ + if (opacity !== this.opacity) { │ │ │ │ + if (this.map != null) { │ │ │ │ + this.map.events.triggerEvent("changelayer", { │ │ │ │ + layer: this, │ │ │ │ + property: "opacity" │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + this.opacity = opacity │ │ │ │ + } │ │ │ │ + if (this.getVisibility()) { │ │ │ │ + var container = this.getMapContainer(); │ │ │ │ + OpenLayers.Util.modifyDOMElement(container, null, null, null, null, null, null, opacity) │ │ │ │ } │ │ │ │ - return url + path │ │ │ │ }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); │ │ │ │ - if (!this.tileOrigin) { │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left, this.map.maxExtent.bottom) │ │ │ │ + destroy: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.setGMapVisibility(false); │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache && cache.count <= 1) { │ │ │ │ + this.removeGMapElements() │ │ │ │ + } │ │ │ │ } │ │ │ │ + OpenLayers.Layer.EventPane.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.TMS" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.WMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - DEFAULT_PARAMS: { │ │ │ │ - service: "WMS", │ │ │ │ - version: "1.1.1", │ │ │ │ - request: "GetMap", │ │ │ │ - styles: "", │ │ │ │ - format: "image/jpeg" │ │ │ │ + removeGMapElements: function() { │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + var container = this.mapObject && this.getMapContainer(); │ │ │ │ + if (container && container.parentNode) { │ │ │ │ + container.parentNode.removeChild(container) │ │ │ │ + } │ │ │ │ + var termsOfUse = cache.termsOfUse; │ │ │ │ + if (termsOfUse && termsOfUse.parentNode) { │ │ │ │ + termsOfUse.parentNode.removeChild(termsOfUse) │ │ │ │ + } │ │ │ │ + var poweredBy = cache.poweredBy; │ │ │ │ + if (poweredBy && poweredBy.parentNode) { │ │ │ │ + poweredBy.parentNode.removeChild(poweredBy) │ │ │ │ + } │ │ │ │ + if (this.mapObject && window.google && google.maps && google.maps.event && google.maps.event.clearListeners) { │ │ │ │ + google.maps.event.clearListeners(this.mapObject, "tilesloaded") │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ - isBaseLayer: true, │ │ │ │ - encodeBBOX: false, │ │ │ │ - noMagic: false, │ │ │ │ - yx: {}, │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - var newArguments = []; │ │ │ │ - params = OpenLayers.Util.upperCaseObject(params); │ │ │ │ - if (parseFloat(params.VERSION) >= 1.3 && !params.EXCEPTIONS) { │ │ │ │ - params.EXCEPTIONS = "INIMAGE" │ │ │ │ + removeMap: function(map) { │ │ │ │ + if (this.visibility && this.mapObject) { │ │ │ │ + this.setGMapVisibility(false) │ │ │ │ } │ │ │ │ - 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)); │ │ │ │ - if (!this.noMagic && this.params.TRANSPARENT && this.params.TRANSPARENT.toString().toLowerCase() == "true") { │ │ │ │ - if (options == null || !options.isBaseLayer) { │ │ │ │ - this.isBaseLayer = false │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[map.id]; │ │ │ │ + if (cache) { │ │ │ │ + if (cache.count <= 1) { │ │ │ │ + this.removeGMapElements(); │ │ │ │ + delete OpenLayers.Layer.Google.cache[map.id] │ │ │ │ + } else { │ │ │ │ + --cache.count │ │ │ │ } │ │ │ │ - if (this.params.FORMAT == "image/jpeg") { │ │ │ │ - this.params.FORMAT = OpenLayers.Util.alphaHack() ? "image/gif" : "image/png" │ │ │ │ + } │ │ │ │ + delete this.termsOfUse; │ │ │ │ + delete this.poweredBy; │ │ │ │ + delete this.mapObject; │ │ │ │ + delete this.dragObject; │ │ │ │ + OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + getOLBoundsFromMapObjectBounds: function(moBounds) { │ │ │ │ + var olBounds = null; │ │ │ │ + if (moBounds != null) { │ │ │ │ + var sw = moBounds.getSouthWest(); │ │ │ │ + var ne = moBounds.getNorthEast(); │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + sw = this.forwardMercator(sw.lng(), sw.lat()); │ │ │ │ + ne = this.forwardMercator(ne.lng(), ne.lat()) │ │ │ │ + } else { │ │ │ │ + sw = new OpenLayers.LonLat(sw.lng(), sw.lat()); │ │ │ │ + ne = new OpenLayers.LonLat(ne.lng(), ne.lat()) │ │ │ │ + } │ │ │ │ + olBounds = new OpenLayers.Bounds(sw.lon, sw.lat, ne.lon, ne.lat) │ │ │ │ + } │ │ │ │ + return olBounds │ │ │ │ + }, │ │ │ │ + getWarningHTML: function() { │ │ │ │ + return OpenLayers.i18n("googleWarning") │ │ │ │ + }, │ │ │ │ + getMapObjectCenter: function() { │ │ │ │ + return this.mapObject.getCenter() │ │ │ │ + }, │ │ │ │ + getMapObjectZoom: function() { │ │ │ │ + return this.mapObject.getZoom() │ │ │ │ + }, │ │ │ │ + getLongitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + return this.sphericalMercator ? this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon : moLonLat.lng() │ │ │ │ + }, │ │ │ │ + getLatitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + var lat = this.sphericalMercator ? this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat : moLonLat.lat(); │ │ │ │ + return lat │ │ │ │ + }, │ │ │ │ + getXFromMapObjectPixel: function(moPixel) { │ │ │ │ + return moPixel.x │ │ │ │ + }, │ │ │ │ + getYFromMapObjectPixel: function(moPixel) { │ │ │ │ + return moPixel.y │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Google" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.Google.cache = {}; │ │ │ │ +OpenLayers.Layer.Google.v2 = { │ │ │ │ + termsOfUse: null, │ │ │ │ + poweredBy: null, │ │ │ │ + dragObject: null, │ │ │ │ + loadMapObject: function() { │ │ │ │ + if (!this.type) { │ │ │ │ + this.type = G_NORMAL_MAP │ │ │ │ + } │ │ │ │ + var mapObject, termsOfUse, poweredBy; │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + mapObject = cache.mapObject; │ │ │ │ + termsOfUse = cache.termsOfUse; │ │ │ │ + poweredBy = cache.poweredBy; │ │ │ │ + ++cache.count │ │ │ │ + } else { │ │ │ │ + var container = this.map.viewPortDiv; │ │ │ │ + var div = document.createElement("div"); │ │ │ │ + div.id = this.map.id + "_GMap2Container"; │ │ │ │ + div.style.position = "absolute"; │ │ │ │ + div.style.width = "100%"; │ │ │ │ + div.style.height = "100%"; │ │ │ │ + container.appendChild(div); │ │ │ │ + try { │ │ │ │ + mapObject = new GMap2(div); │ │ │ │ + termsOfUse = div.lastChild; │ │ │ │ + container.appendChild(termsOfUse); │ │ │ │ + termsOfUse.style.zIndex = "1100"; │ │ │ │ + termsOfUse.style.right = ""; │ │ │ │ + termsOfUse.style.bottom = ""; │ │ │ │ + termsOfUse.className = "olLayerGoogleCopyright"; │ │ │ │ + poweredBy = div.lastChild; │ │ │ │ + container.appendChild(poweredBy); │ │ │ │ + poweredBy.style.zIndex = "1100"; │ │ │ │ + poweredBy.style.right = ""; │ │ │ │ + poweredBy.style.bottom = ""; │ │ │ │ + poweredBy.className = "olLayerGooglePoweredBy gmnoprint" │ │ │ │ + } catch (e) { │ │ │ │ + throw e │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.Google.cache[this.map.id] = { │ │ │ │ + mapObject: mapObject, │ │ │ │ + termsOfUse: termsOfUse, │ │ │ │ + poweredBy: poweredBy, │ │ │ │ + count: 1 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.mapObject = mapObject; │ │ │ │ + this.termsOfUse = termsOfUse; │ │ │ │ + this.poweredBy = poweredBy; │ │ │ │ + if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(), this.type) === -1) { │ │ │ │ + this.mapObject.addMapType(this.type) │ │ │ │ + } │ │ │ │ + if (typeof mapObject.getDragObject == "function") { │ │ │ │ + this.dragObject = mapObject.getDragObject() │ │ │ │ + } else { │ │ │ │ + this.dragPanMapObject = null │ │ │ │ + } │ │ │ │ + if (this.isBaseLayer === false) { │ │ │ │ + this.setGMapVisibility(this.div.style.display !== "none") │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + onMapResize: function() { │ │ │ │ + if (this.visibility && this.mapObject.isLoaded()) { │ │ │ │ + this.mapObject.checkResize() │ │ │ │ + } else { │ │ │ │ + if (!this._resized) { │ │ │ │ + var layer = this; │ │ │ │ + var handle = GEvent.addListener(this.mapObject, "load", function() { │ │ │ │ + GEvent.removeListener(handle); │ │ │ │ + delete layer._resized; │ │ │ │ + layer.mapObject.checkResize(); │ │ │ │ + layer.moveTo(layer.map.getCenter(), layer.map.getZoom()) │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + this._resized = true │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setGMapVisibility: function(visible) { │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + var container = this.mapObject.getContainer(); │ │ │ │ + if (visible === true) { │ │ │ │ + this.mapObject.setMapType(this.type); │ │ │ │ + container.style.display = ""; │ │ │ │ + this.termsOfUse.style.left = ""; │ │ │ │ + this.termsOfUse.style.display = ""; │ │ │ │ + this.poweredBy.style.display = ""; │ │ │ │ + cache.displayed = this.id │ │ │ │ + } else { │ │ │ │ + if (cache.displayed === this.id) { │ │ │ │ + delete cache.displayed │ │ │ │ + } │ │ │ │ + if (!cache.displayed) { │ │ │ │ + container.style.display = "none"; │ │ │ │ + this.termsOfUse.style.display = "none"; │ │ │ │ + this.termsOfUse.style.left = "-9999px"; │ │ │ │ + this.poweredBy.style.display = "none" │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ + getMapContainer: function() { │ │ │ │ + return this.mapObject.getContainer() │ │ │ │ + }, │ │ │ │ + getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ + var moBounds = null; │ │ │ │ + if (olBounds != null) { │ │ │ │ + var sw = this.sphericalMercator ? this.inverseMercator(olBounds.bottom, olBounds.left) : new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ + var ne = this.sphericalMercator ? this.inverseMercator(olBounds.top, olBounds.right) : new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ + moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon), new GLatLng(ne.lat, ne.lon)) │ │ │ │ + } │ │ │ │ + return moBounds │ │ │ │ + }, │ │ │ │ + setMapObjectCenter: function(center, zoom) { │ │ │ │ + this.mapObject.setCenter(center, zoom) │ │ │ │ + }, │ │ │ │ + dragPanMapObject: function(dX, dY) { │ │ │ │ + this.dragObject.moveBy(new GSize(-dX, dY)) │ │ │ │ + }, │ │ │ │ + getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ + return this.mapObject.fromContainerPixelToLatLng(moPixel) │ │ │ │ + }, │ │ │ │ + getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + return this.mapObject.fromLatLngToContainerPixel(moLonLat) │ │ │ │ + }, │ │ │ │ + getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ + return this.mapObject.getBoundsZoomLevel(moBounds) │ │ │ │ + }, │ │ │ │ + getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ + var gLatLng; │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + var lonlat = this.inverseMercator(lon, lat); │ │ │ │ + gLatLng = new GLatLng(lonlat.lat, lonlat.lon) │ │ │ │ + } else { │ │ │ │ + gLatLng = new GLatLng(lat, lon) │ │ │ │ + } │ │ │ │ + return gLatLng │ │ │ │ + }, │ │ │ │ + getMapObjectPixelFromXY: function(x, y) { │ │ │ │ + return new GPoint(x, y) │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.Layer.MapServer = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + DEFAULT_PARAMS: { │ │ │ │ + mode: "map", │ │ │ │ + map_imagetype: "png" │ │ │ │ + }, │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ + this.params = OpenLayers.Util.applyDefaults(this.params, this.DEFAULT_PARAMS); │ │ │ │ + if (options == null || options.isBaseLayer == null) { │ │ │ │ + this.isBaseLayer = this.params.transparent != "true" && this.params.transparent != true │ │ │ │ + } │ │ │ │ + }, │ │ │ │ clone: function(obj) { │ │ │ │ if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.WMS(this.name, this.url, this.params, this.getOptions()) │ │ │ │ + obj = new OpenLayers.Layer.MapServer(this.name, this.url, this.params, this.getOptions()) │ │ │ │ } │ │ │ │ obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ return obj │ │ │ │ }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ getURL: function(bounds) { │ │ │ │ bounds = this.adjustBounds(bounds); │ │ │ │ + var extent = [bounds.left, bounds.bottom, bounds.right, bounds.top]; │ │ │ │ var imageSize = this.getImageSize(); │ │ │ │ - var newParams = {}; │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - mergeNewParams: function(newParams) { │ │ │ │ - var upperParams = OpenLayers.Util.upperCaseObject(newParams); │ │ │ │ - var newArguments = [upperParams]; │ │ │ │ - return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, newArguments) │ │ │ │ + var url = this.getFullRequestString({ │ │ │ │ + mapext: extent, │ │ │ │ + imgext: extent, │ │ │ │ + map_size: [imageSize.w, imageSize.h], │ │ │ │ + imgx: imageSize.w / 2, │ │ │ │ + imgy: imageSize.h / 2, │ │ │ │ + imgxy: [imageSize.w, imageSize.h] │ │ │ │ + }); │ │ │ │ + return url │ │ │ │ }, │ │ │ │ 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 │ │ │ │ + var url = altUrl == null ? this.url : altUrl; │ │ │ │ + var allParams = OpenLayers.Util.extend({}, this.params); │ │ │ │ + allParams = OpenLayers.Util.extend(allParams, newParams); │ │ │ │ + var paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(paramsString, url) │ │ │ │ } │ │ │ │ - if (typeof this.params.TRANSPARENT == "boolean") { │ │ │ │ - newParams.TRANSPARENT = this.params.TRANSPARENT ? "TRUE" : "FALSE" │ │ │ │ + var urlParams = OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url)); │ │ │ │ + for (var key in allParams) { │ │ │ │ + if (key.toUpperCase() in urlParams) { │ │ │ │ + delete allParams[key] │ │ │ │ + } │ │ │ │ } │ │ │ │ - return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this, arguments) │ │ │ │ + paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ + var requestString = url; │ │ │ │ + paramsString = paramsString.replace(/,/g, "+"); │ │ │ │ + if (paramsString != "") { │ │ │ │ + var lastServerChar = url.charAt(url.length - 1); │ │ │ │ + if (lastServerChar == "&" || lastServerChar == "?") { │ │ │ │ + requestString += paramsString │ │ │ │ + } else { │ │ │ │ + if (url.indexOf("?") == -1) { │ │ │ │ + requestString += "?" + paramsString │ │ │ │ + } else { │ │ │ │ + requestString += "&" + paramsString │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return requestString │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.WMS" │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.MapServer" │ │ │ │ }); │ │ │ │ OpenLayers.Format.ArcXML = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ fontStyleKeys: ["antialiasing", "blockout", "font", "fontcolor", "fontsize", "fontstyle", "glowing", "interval", "outline", "printmode", "shadow", "transparency"], │ │ │ │ request: null, │ │ │ │ response: null, │ │ │ │ initialize: function(options) { │ │ │ │ this.request = new OpenLayers.Format.ArcXML.Request; │ │ │ │ @@ -17508,14 +21001,1007 @@ │ │ │ │ obj = new OpenLayers.Layer.ArcIMS(this.name, this.url, this.getOptions()) │ │ │ │ } │ │ │ │ obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ return obj │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Layer.ArcIMS" │ │ │ │ }); │ │ │ │ +OpenLayers.Layer.TMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + serviceVersion: "1.0.0", │ │ │ │ + layername: null, │ │ │ │ + type: null, │ │ │ │ + isBaseLayer: true, │ │ │ │ + tileOrigin: null, │ │ │ │ + serverResolutions: null, │ │ │ │ + zoomOffset: 0, │ │ │ │ + initialize: function(name, url, options) { │ │ │ │ + var newArguments = []; │ │ │ │ + newArguments.push(name, url, {}, options); │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments) │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.TMS(this.name, this.url, this.getOptions()) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ + var y = Math.round((bounds.bottom - this.tileOrigin.lat) / (res * this.tileSize.h)); │ │ │ │ + var z = this.getServerZoom(); │ │ │ │ + var path = this.serviceVersion + "/" + this.layername + "/" + z + "/" + x + "/" + y + "." + this.type; │ │ │ │ + var url = this.url; │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(path, url) │ │ │ │ + } │ │ │ │ + return url + path │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); │ │ │ │ + if (!this.tileOrigin) { │ │ │ │ + this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left, this.map.maxExtent.bottom) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.TMS" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.KaMapCache = OpenLayers.Class(OpenLayers.Layer.KaMap, { │ │ │ │ + IMAGE_EXTENSIONS: { │ │ │ │ + jpeg: "jpg", │ │ │ │ + gif: "gif", │ │ │ │ + png: "png", │ │ │ │ + png8: "png", │ │ │ │ + png24: "png", │ │ │ │ + dithered: "png" │ │ │ │ + }, │ │ │ │ + DEFAULT_FORMAT: "jpeg", │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + OpenLayers.Layer.KaMap.prototype.initialize.apply(this, arguments); │ │ │ │ + this.extension = this.IMAGE_EXTENSIONS[this.params.i.toLowerCase() || this.DEFAULT_FORMAT] │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ + var scale = Math.round(this.map.getScale() * 1e4) / 1e4; │ │ │ │ + var pX = Math.round(bounds.left / mapRes); │ │ │ │ + var pY = -Math.round(bounds.top / mapRes); │ │ │ │ + var metaX = Math.floor(pX / this.tileSize.w / this.params.metaTileSize.w) * this.tileSize.w * this.params.metaTileSize.w; │ │ │ │ + var metaY = Math.floor(pY / this.tileSize.h / this.params.metaTileSize.h) * this.tileSize.h * this.params.metaTileSize.h; │ │ │ │ + var components = ["/", this.params.map, "/", scale, "/", this.params.g.replace(/\s/g, "_"), "/def/t", metaY, "/l", metaX, "/t", pY, "l", pX, ".", this.extension]; │ │ │ │ + var url = this.url; │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(components.join(""), url) │ │ │ │ + } │ │ │ │ + return url + components.join("") │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.KaMapCache" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ + name: "OpenStreetMap", │ │ │ │ + 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"], │ │ │ │ + attribution: "© <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors", │ │ │ │ + sphericalMercator: true, │ │ │ │ + wrapDateLine: true, │ │ │ │ + tileOptions: null, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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.Layer.Markers = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ + isBaseLayer: false, │ │ │ │ + markers: null, │ │ │ │ + drawn: false, │ │ │ │ + initialize: function(name, options) { │ │ │ │ + OpenLayers.Layer.prototype.initialize.apply(this, arguments); │ │ │ │ + this.markers = [] │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.clearMarkers(); │ │ │ │ + this.markers = null; │ │ │ │ + OpenLayers.Layer.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ + if (opacity != this.opacity) { │ │ │ │ + this.opacity = opacity; │ │ │ │ + for (var i = 0, len = this.markers.length; i < len; i++) { │ │ │ │ + this.markers[i].setOpacity(this.opacity) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ + OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ + if (zoomChanged || !this.drawn) { │ │ │ │ + for (var i = 0, len = this.markers.length; i < len; i++) { │ │ │ │ + this.drawMarker(this.markers[i]) │ │ │ │ + } │ │ │ │ + this.drawn = true │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + addMarker: function(marker) { │ │ │ │ + this.markers.push(marker); │ │ │ │ + if (this.opacity < 1) { │ │ │ │ + marker.setOpacity(this.opacity) │ │ │ │ + } │ │ │ │ + if (this.map && this.map.getExtent()) { │ │ │ │ + marker.map = this.map; │ │ │ │ + this.drawMarker(marker) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + removeMarker: function(marker) { │ │ │ │ + if (this.markers && this.markers.length) { │ │ │ │ + OpenLayers.Util.removeItem(this.markers, marker); │ │ │ │ + marker.erase() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + clearMarkers: function() { │ │ │ │ + if (this.markers != null) { │ │ │ │ + while (this.markers.length > 0) { │ │ │ │ + this.removeMarker(this.markers[0]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawMarker: function(marker) { │ │ │ │ + var px = this.map.getLayerPxFromLonLat(marker.lonlat); │ │ │ │ + if (px == null) { │ │ │ │ + marker.display(false) │ │ │ │ + } else { │ │ │ │ + if (!marker.isDrawn()) { │ │ │ │ + var markerImg = marker.draw(px); │ │ │ │ + this.div.appendChild(markerImg) │ │ │ │ + } else if (marker.icon) { │ │ │ │ + marker.icon.moveTo(px) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getDataExtent: function() { │ │ │ │ + var maxExtent = null; │ │ │ │ + if (this.markers && this.markers.length > 0) { │ │ │ │ + var maxExtent = new OpenLayers.Bounds; │ │ │ │ + for (var i = 0, len = this.markers.length; i < len; i++) { │ │ │ │ + var marker = this.markers[i]; │ │ │ │ + maxExtent.extend(marker.lonlat) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return maxExtent │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Markers" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.Text = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ + defaultStyle: null, │ │ │ │ + extractStyles: true, │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + if (options.extractStyles !== false) { │ │ │ │ + options.defaultStyle = { │ │ │ │ + externalGraphic: OpenLayers.Util.getImageLocation("marker.png"), │ │ │ │ + graphicWidth: 21, │ │ │ │ + graphicHeight: 25, │ │ │ │ + graphicXOffset: -10.5, │ │ │ │ + graphicYOffset: -12.5 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + OpenLayers.Format.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + read: function(text) { │ │ │ │ + var lines = text.split("\n"); │ │ │ │ + var columns; │ │ │ │ + var features = []; │ │ │ │ + for (var lcv = 0; lcv < lines.length - 1; lcv++) { │ │ │ │ + var currLine = lines[lcv].replace(/^\s*/, "").replace(/\s*$/, ""); │ │ │ │ + if (currLine.charAt(0) != "#") { │ │ │ │ + if (!columns) { │ │ │ │ + columns = currLine.split("\t") │ │ │ │ + } else { │ │ │ │ + var vals = currLine.split("\t"); │ │ │ │ + var geometry = new OpenLayers.Geometry.Point(0, 0); │ │ │ │ + var attributes = {}; │ │ │ │ + var style = this.defaultStyle ? OpenLayers.Util.applyDefaults({}, this.defaultStyle) : null; │ │ │ │ + var icon, iconSize, iconOffset, overflow; │ │ │ │ + var set = false; │ │ │ │ + for (var valIndex = 0; valIndex < vals.length; valIndex++) { │ │ │ │ + if (vals[valIndex]) { │ │ │ │ + if (columns[valIndex] == "point") { │ │ │ │ + var coords = vals[valIndex].split(","); │ │ │ │ + geometry.y = parseFloat(coords[0]); │ │ │ │ + geometry.x = parseFloat(coords[1]); │ │ │ │ + set = true │ │ │ │ + } else if (columns[valIndex] == "lat") { │ │ │ │ + geometry.y = parseFloat(vals[valIndex]); │ │ │ │ + set = true │ │ │ │ + } else if (columns[valIndex] == "lon") { │ │ │ │ + geometry.x = parseFloat(vals[valIndex]); │ │ │ │ + set = true │ │ │ │ + } else if (columns[valIndex] == "title") attributes["title"] = vals[valIndex]; │ │ │ │ + else if (columns[valIndex] == "image" || columns[valIndex] == "icon" && style) { │ │ │ │ + style["externalGraphic"] = vals[valIndex] │ │ │ │ + } else if (columns[valIndex] == "iconSize" && style) { │ │ │ │ + var size = vals[valIndex].split(","); │ │ │ │ + style["graphicWidth"] = parseFloat(size[0]); │ │ │ │ + style["graphicHeight"] = parseFloat(size[1]) │ │ │ │ + } else if (columns[valIndex] == "iconOffset" && style) { │ │ │ │ + var offset = vals[valIndex].split(","); │ │ │ │ + style["graphicXOffset"] = parseFloat(offset[0]); │ │ │ │ + style["graphicYOffset"] = parseFloat(offset[1]) │ │ │ │ + } else if (columns[valIndex] == "description") { │ │ │ │ + attributes["description"] = vals[valIndex] │ │ │ │ + } else if (columns[valIndex] == "overflow") { │ │ │ │ + attributes["overflow"] = vals[valIndex] │ │ │ │ + } else { │ │ │ │ + attributes[columns[valIndex]] = vals[valIndex] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (set) { │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + geometry.transform(this.externalProjection, this.internalProjection) │ │ │ │ + } │ │ │ │ + var feature = new OpenLayers.Feature.Vector(geometry, attributes, style); │ │ │ │ + features.push(feature) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return features │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.Text" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.Text = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ + location: null, │ │ │ │ + features: null, │ │ │ │ + formatOptions: null, │ │ │ │ + selectedFeature: null, │ │ │ │ + initialize: function(name, options) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.initialize.apply(this, arguments); │ │ │ │ + this.features = [] │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ + this.clearFeatures(); │ │ │ │ + this.features = null │ │ │ │ + }, │ │ │ │ + loadText: function() { │ │ │ │ + if (!this.loaded) { │ │ │ │ + if (this.location != null) { │ │ │ │ + var onFail = function(e) { │ │ │ │ + this.events.triggerEvent("loadend") │ │ │ │ + }; │ │ │ │ + this.events.triggerEvent("loadstart"); │ │ │ │ + OpenLayers.Request.GET({ │ │ │ │ + url: this.location, │ │ │ │ + success: this.parseData, │ │ │ │ + failure: onFail, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.loaded = true │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ + if (this.visibility && !this.loaded) { │ │ │ │ + this.loadText() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + parseData: function(ajaxRequest) { │ │ │ │ + var text = ajaxRequest.responseText; │ │ │ │ + var options = {}; │ │ │ │ + OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ + if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ + options.externalProjection = this.projection; │ │ │ │ + options.internalProjection = this.map.getProjectionObject() │ │ │ │ + } │ │ │ │ + var parser = new OpenLayers.Format.Text(options); │ │ │ │ + var features = parser.read(text); │ │ │ │ + for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ + var data = {}; │ │ │ │ + var feature = features[i]; │ │ │ │ + var location; │ │ │ │ + var iconSize, iconOffset; │ │ │ │ + location = new OpenLayers.LonLat(feature.geometry.x, feature.geometry.y); │ │ │ │ + if (feature.style.graphicWidth && feature.style.graphicHeight) { │ │ │ │ + iconSize = new OpenLayers.Size(feature.style.graphicWidth, feature.style.graphicHeight) │ │ │ │ + } │ │ │ │ + if (feature.style.graphicXOffset !== undefined && feature.style.graphicYOffset !== undefined) { │ │ │ │ + iconOffset = new OpenLayers.Pixel(feature.style.graphicXOffset, feature.style.graphicYOffset) │ │ │ │ + } │ │ │ │ + if (feature.style.externalGraphic != null) { │ │ │ │ + data.icon = new OpenLayers.Icon(feature.style.externalGraphic, iconSize, iconOffset) │ │ │ │ + } else { │ │ │ │ + data.icon = OpenLayers.Marker.defaultIcon(); │ │ │ │ + if (iconSize != null) { │ │ │ │ + data.icon.setSize(iconSize) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (feature.attributes.title != null && feature.attributes.description != null) { │ │ │ │ + data["popupContentHTML"] = "<h2>" + feature.attributes.title + "</h2>" + "<p>" + feature.attributes.description + "</p>" │ │ │ │ + } │ │ │ │ + data["overflow"] = feature.attributes.overflow || "auto"; │ │ │ │ + var markerFeature = new OpenLayers.Feature(this, location, data); │ │ │ │ + this.features.push(markerFeature); │ │ │ │ + var marker = markerFeature.createMarker(); │ │ │ │ + if (feature.attributes.title != null && feature.attributes.description != null) { │ │ │ │ + marker.events.register("click", markerFeature, this.markerClick) │ │ │ │ + } │ │ │ │ + this.addMarker(marker) │ │ │ │ + } │ │ │ │ + this.events.triggerEvent("loadend") │ │ │ │ + }, │ │ │ │ + markerClick: function(evt) { │ │ │ │ + var sameMarkerClicked = this == this.layer.selectedFeature; │ │ │ │ + this.layer.selectedFeature = !sameMarkerClicked ? this : null; │ │ │ │ + for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ + this.layer.map.removePopup(this.layer.map.popups[i]) │ │ │ │ + } │ │ │ │ + if (!sameMarkerClicked) { │ │ │ │ + this.layer.map.addPopup(this.createPopup()) │ │ │ │ + } │ │ │ │ + OpenLayers.Event.stop(evt) │ │ │ │ + }, │ │ │ │ + clearFeatures: function() { │ │ │ │ + if (this.features != null) { │ │ │ │ + while (this.features.length > 0) { │ │ │ │ + var feature = this.features[0]; │ │ │ │ + OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ + feature.destroy() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Text" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + isBaseLayer: true, │ │ │ │ + useHttpTile: false, │ │ │ │ + singleTile: false, │ │ │ │ + useOverlay: false, │ │ │ │ + useAsyncOverlay: true, │ │ │ │ + TILE_PARAMS: { │ │ │ │ + operation: "GETTILEIMAGE", │ │ │ │ + version: "1.2.0" │ │ │ │ + }, │ │ │ │ + SINGLE_TILE_PARAMS: { │ │ │ │ + operation: "GETMAPIMAGE", │ │ │ │ + format: "PNG", │ │ │ │ + locale: "en", │ │ │ │ + clip: "1", │ │ │ │ + version: "1.0.0" │ │ │ │ + }, │ │ │ │ + OVERLAY_PARAMS: { │ │ │ │ + operation: "GETDYNAMICMAPOVERLAYIMAGE", │ │ │ │ + format: "PNG", │ │ │ │ + locale: "en", │ │ │ │ + clip: "1", │ │ │ │ + version: "2.0.0" │ │ │ │ + }, │ │ │ │ + FOLDER_PARAMS: { │ │ │ │ + tileColumnsPerFolder: 30, │ │ │ │ + tileRowsPerFolder: 30, │ │ │ │ + format: "png", │ │ │ │ + querystring: null │ │ │ │ + }, │ │ │ │ + defaultSize: new OpenLayers.Size(300, 300), │ │ │ │ + tileOriginCorner: "tl", │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ + if (options == null || options.isBaseLayer == null) { │ │ │ │ + this.isBaseLayer = this.transparent != "true" && this.transparent != true │ │ │ │ + } │ │ │ │ + if (options && options.useOverlay != null) { │ │ │ │ + this.useOverlay = options.useOverlay │ │ │ │ + } │ │ │ │ + if (this.singleTile) { │ │ │ │ + if (this.useOverlay) { │ │ │ │ + OpenLayers.Util.applyDefaults(this.params, this.OVERLAY_PARAMS); │ │ │ │ + if (!this.useAsyncOverlay) { │ │ │ │ + this.params.version = "1.0.0" │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Util.applyDefaults(this.params, this.SINGLE_TILE_PARAMS) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (this.useHttpTile) { │ │ │ │ + OpenLayers.Util.applyDefaults(this.params, this.FOLDER_PARAMS) │ │ │ │ + } else { │ │ │ │ + OpenLayers.Util.applyDefaults(this.params, this.TILE_PARAMS) │ │ │ │ + } │ │ │ │ + this.setTileSize(this.defaultSize) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.MapGuide(this.name, this.url, this.params, this.getOptions()) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + var url; │ │ │ │ + var center = bounds.getCenterLonLat(); │ │ │ │ + var mapSize = this.map.getSize(); │ │ │ │ + if (this.singleTile) { │ │ │ │ + var params = { │ │ │ │ + setdisplaydpi: OpenLayers.DOTS_PER_INCH, │ │ │ │ + setdisplayheight: mapSize.h * this.ratio, │ │ │ │ + setdisplaywidth: mapSize.w * this.ratio, │ │ │ │ + setviewcenterx: center.lon, │ │ │ │ + setviewcentery: center.lat, │ │ │ │ + setviewscale: this.map.getScale() │ │ │ │ + }; │ │ │ │ + if (this.useOverlay && !this.useAsyncOverlay) { │ │ │ │ + var getVisParams = {}; │ │ │ │ + getVisParams = OpenLayers.Util.extend(getVisParams, params); │ │ │ │ + getVisParams.operation = "GETVISIBLEMAPEXTENT"; │ │ │ │ + getVisParams.version = "1.0.0"; │ │ │ │ + getVisParams.session = this.params.session; │ │ │ │ + getVisParams.mapName = this.params.mapName; │ │ │ │ + getVisParams.format = "text/xml"; │ │ │ │ + url = this.getFullRequestString(getVisParams); │ │ │ │ + OpenLayers.Request.GET({ │ │ │ │ + url: url, │ │ │ │ + async: false │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + url = this.getFullRequestString(params) │ │ │ │ + } else { │ │ │ │ + var currentRes = this.map.getResolution(); │ │ │ │ + var colidx = Math.floor((bounds.left - this.maxExtent.left) / currentRes); │ │ │ │ + colidx = Math.round(colidx / this.tileSize.w); │ │ │ │ + var rowidx = Math.floor((this.maxExtent.top - bounds.top) / currentRes); │ │ │ │ + rowidx = Math.round(rowidx / this.tileSize.h); │ │ │ │ + if (this.useHttpTile) { │ │ │ │ + url = this.getImageFilePath({ │ │ │ │ + tilecol: colidx, │ │ │ │ + tilerow: rowidx, │ │ │ │ + scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ + }) │ │ │ │ + } else { │ │ │ │ + url = this.getFullRequestString({ │ │ │ │ + tilecol: colidx, │ │ │ │ + tilerow: rowidx, │ │ │ │ + scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return url │ │ │ │ + }, │ │ │ │ + getFullRequestString: function(newParams, altUrl) { │ │ │ │ + var url = altUrl == null ? this.url : altUrl; │ │ │ │ + if (typeof url == "object") { │ │ │ │ + url = url[Math.floor(Math.random() * url.length)] │ │ │ │ + } │ │ │ │ + var requestString = url; │ │ │ │ + var allParams = OpenLayers.Util.extend({}, this.params); │ │ │ │ + allParams = OpenLayers.Util.extend(allParams, newParams); │ │ │ │ + var urlParams = OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url)); │ │ │ │ + for (var key in allParams) { │ │ │ │ + if (key.toUpperCase() in urlParams) { │ │ │ │ + delete allParams[key] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ + paramsString = paramsString.replace(/,/g, "+"); │ │ │ │ + if (paramsString != "") { │ │ │ │ + var lastServerChar = url.charAt(url.length - 1); │ │ │ │ + if (lastServerChar == "&" || lastServerChar == "?") { │ │ │ │ + requestString += paramsString │ │ │ │ + } else { │ │ │ │ + if (url.indexOf("?") == -1) { │ │ │ │ + requestString += "?" + paramsString │ │ │ │ + } else { │ │ │ │ + requestString += "&" + paramsString │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return requestString │ │ │ │ + }, │ │ │ │ + getImageFilePath: function(newParams, altUrl) { │ │ │ │ + var url = altUrl == null ? this.url : altUrl; │ │ │ │ + if (typeof url == "object") { │ │ │ │ + url = url[Math.floor(Math.random() * url.length)] │ │ │ │ + } │ │ │ │ + var requestString = url; │ │ │ │ + var tileRowGroup = ""; │ │ │ │ + var tileColGroup = ""; │ │ │ │ + if (newParams.tilerow < 0) { │ │ │ │ + tileRowGroup = "-" │ │ │ │ + } │ │ │ │ + if (newParams.tilerow == 0) { │ │ │ │ + tileRowGroup += "0" │ │ │ │ + } else { │ │ │ │ + tileRowGroup += Math.floor(Math.abs(newParams.tilerow / this.params.tileRowsPerFolder)) * this.params.tileRowsPerFolder │ │ │ │ + } │ │ │ │ + if (newParams.tilecol < 0) { │ │ │ │ + tileColGroup = "-" │ │ │ │ + } │ │ │ │ + if (newParams.tilecol == 0) { │ │ │ │ + tileColGroup += "0" │ │ │ │ + } else { │ │ │ │ + tileColGroup += Math.floor(Math.abs(newParams.tilecol / this.params.tileColumnsPerFolder)) * this.params.tileColumnsPerFolder │ │ │ │ + } │ │ │ │ + var tilePath = "/S" + Math.floor(newParams.scaleindex) + "/" + this.params.basemaplayergroupname + "/R" + tileRowGroup + "/C" + tileColGroup + "/" + newParams.tilerow % this.params.tileRowsPerFolder + "_" + newParams.tilecol % this.params.tileColumnsPerFolder + "." + this.params.format; │ │ │ │ + if (this.params.querystring) { │ │ │ │ + tilePath += "?" + this.params.querystring │ │ │ │ + } │ │ │ │ + requestString += tilePath; │ │ │ │ + return requestString │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.MapGuide" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.Zoomify = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + size: null, │ │ │ │ + isBaseLayer: true, │ │ │ │ + standardTileSize: 256, │ │ │ │ + tileOriginCorner: "tl", │ │ │ │ + numberOfTiers: 0, │ │ │ │ + tileCountUpToTier: null, │ │ │ │ + tierSizeInTiles: null, │ │ │ │ + tierImageSize: null, │ │ │ │ + initialize: function(name, url, size, options) { │ │ │ │ + this.initializeZoomify(size); │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, [name, url, size, {}, options]) │ │ │ │ + }, │ │ │ │ + initializeZoomify: function(size) { │ │ │ │ + var imageSize = size.clone(); │ │ │ │ + this.size = size.clone(); │ │ │ │ + var tiles = new OpenLayers.Size(Math.ceil(imageSize.w / this.standardTileSize), Math.ceil(imageSize.h / this.standardTileSize)); │ │ │ │ + this.tierSizeInTiles = [tiles]; │ │ │ │ + this.tierImageSize = [imageSize]; │ │ │ │ + while (imageSize.w > this.standardTileSize || imageSize.h > this.standardTileSize) { │ │ │ │ + imageSize = new OpenLayers.Size(Math.floor(imageSize.w / 2), Math.floor(imageSize.h / 2)); │ │ │ │ + tiles = new OpenLayers.Size(Math.ceil(imageSize.w / this.standardTileSize), Math.ceil(imageSize.h / this.standardTileSize)); │ │ │ │ + this.tierSizeInTiles.push(tiles); │ │ │ │ + this.tierImageSize.push(imageSize) │ │ │ │ + } │ │ │ │ + this.tierSizeInTiles.reverse(); │ │ │ │ + this.tierImageSize.reverse(); │ │ │ │ + this.numberOfTiers = this.tierSizeInTiles.length; │ │ │ │ + var resolutions = [1]; │ │ │ │ + this.tileCountUpToTier = [0]; │ │ │ │ + for (var i = 1; i < this.numberOfTiers; i++) { │ │ │ │ + resolutions.unshift(Math.pow(2, i)); │ │ │ │ + this.tileCountUpToTier.push(this.tierSizeInTiles[i - 1].w * this.tierSizeInTiles[i - 1].h + this.tileCountUpToTier[i - 1]) │ │ │ │ + } │ │ │ │ + if (!this.serverResolutions) { │ │ │ │ + this.serverResolutions = resolutions │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments); │ │ │ │ + this.tileCountUpToTier.length = 0; │ │ │ │ + this.tierSizeInTiles.length = 0; │ │ │ │ + this.tierImageSize.length = 0 │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.Zoomify(this.name, this.url, this.size, this.options) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ + var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ + var z = this.getZoomForResolution(res); │ │ │ │ + var tileIndex = x + y * this.tierSizeInTiles[z].w + this.tileCountUpToTier[z]; │ │ │ │ + var path = "TileGroup" + Math.floor(tileIndex / 256) + "/" + z + "-" + x + "-" + y + ".jpg"; │ │ │ │ + var url = this.url; │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(path, url) │ │ │ │ + } │ │ │ │ + return url + path │ │ │ │ + }, │ │ │ │ + getImageSize: function() { │ │ │ │ + if (arguments.length > 0) { │ │ │ │ + var bounds = this.adjustBounds(arguments[0]); │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ + var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ + var z = this.getZoomForResolution(res); │ │ │ │ + var w = this.standardTileSize; │ │ │ │ + var h = this.standardTileSize; │ │ │ │ + if (x == this.tierSizeInTiles[z].w - 1) { │ │ │ │ + var w = this.tierImageSize[z].w % this.standardTileSize │ │ │ │ + } │ │ │ │ + if (y == this.tierSizeInTiles[z].h - 1) { │ │ │ │ + var h = this.tierImageSize[z].h % this.standardTileSize │ │ │ │ + } │ │ │ │ + return new OpenLayers.Size(w, h) │ │ │ │ + } else { │ │ │ │ + return this.tileSize │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); │ │ │ │ + this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left, this.map.maxExtent.top) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Zoomify" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.TileCache = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + isBaseLayer: true, │ │ │ │ + format: "image/png", │ │ │ │ + serverResolutions: null, │ │ │ │ + initialize: function(name, url, layername, options) { │ │ │ │ + this.layername = layername; │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, [name, url, {}, options]); │ │ │ │ + this.extension = this.format.split("/")[1].toLowerCase(); │ │ │ │ + this.extension = this.extension == "jpg" ? "jpeg" : this.extension │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.TileCache(this.name, this.url, this.layername, this.getOptions()) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var bbox = this.maxExtent; │ │ │ │ + var size = this.tileSize; │ │ │ │ + var tileX = Math.round((bounds.left - bbox.left) / (res * size.w)); │ │ │ │ + var tileY = Math.round((bounds.bottom - bbox.bottom) / (res * size.h)); │ │ │ │ + var tileZ = this.serverResolutions != null ? OpenLayers.Util.indexOf(this.serverResolutions, res) : this.map.getZoom(); │ │ │ │ + var components = [this.layername, OpenLayers.Number.zeroPad(tileZ, 2), OpenLayers.Number.zeroPad(parseInt(tileX / 1e6), 3), OpenLayers.Number.zeroPad(parseInt(tileX / 1e3) % 1e3, 3), OpenLayers.Number.zeroPad(parseInt(tileX) % 1e3, 3), OpenLayers.Number.zeroPad(parseInt(tileY / 1e6), 3), OpenLayers.Number.zeroPad(parseInt(tileY / 1e3) % 1e3, 3), OpenLayers.Number.zeroPad(parseInt(tileY) % 1e3, 3) + "." + this.extension]; │ │ │ │ + var path = components.join("/"); │ │ │ │ + var url = this.url; │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(path, url) │ │ │ │ + } │ │ │ │ + url = url.charAt(url.length - 1) == "/" ? url : url + "/"; │ │ │ │ + return url + path │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.TileCache" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.WMTS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + isBaseLayer: true, │ │ │ │ + version: "1.0.0", │ │ │ │ + requestEncoding: "KVP", │ │ │ │ + url: null, │ │ │ │ + layer: null, │ │ │ │ + matrixSet: null, │ │ │ │ + style: null, │ │ │ │ + format: "image/jpeg", │ │ │ │ + tileOrigin: null, │ │ │ │ + tileFullExtent: null, │ │ │ │ + formatSuffix: null, │ │ │ │ + matrixIds: null, │ │ │ │ + dimensions: null, │ │ │ │ + params: null, │ │ │ │ + zoomOffset: 0, │ │ │ │ + serverResolutions: null, │ │ │ │ + formatSuffixMap: { │ │ │ │ + "image/png": "png", │ │ │ │ + "image/png8": "png", │ │ │ │ + "image/png24": "png", │ │ │ │ + "image/png32": "png", │ │ │ │ + png: "png", │ │ │ │ + "image/jpeg": "jpg", │ │ │ │ + "image/jpg": "jpg", │ │ │ │ + jpeg: "jpg", │ │ │ │ + jpg: "jpg" │ │ │ │ + }, │ │ │ │ + matrix: null, │ │ │ │ + initialize: function(config) { │ │ │ │ + var required = { │ │ │ │ + url: true, │ │ │ │ + layer: true, │ │ │ │ + style: true, │ │ │ │ + matrixSet: true │ │ │ │ + }; │ │ │ │ + for (var prop in required) { │ │ │ │ + if (!(prop in config)) { │ │ │ │ + throw new Error("Missing property '" + prop + "' in layer configuration.") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + config.params = OpenLayers.Util.upperCaseObject(config.params); │ │ │ │ + var args = [config.name, config.url, config.params, config]; │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, args); │ │ │ │ + if (!this.formatSuffix) { │ │ │ │ + this.formatSuffix = this.formatSuffixMap[this.format] || this.format.split("/").pop() │ │ │ │ + } │ │ │ │ + if (this.matrixIds) { │ │ │ │ + var len = this.matrixIds.length; │ │ │ │ + if (len && typeof this.matrixIds[0] === "string") { │ │ │ │ + var ids = this.matrixIds; │ │ │ │ + this.matrixIds = new Array(len); │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ + this.matrixIds[i] = { │ │ │ │ + identifier: ids[i] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setMap: function() { │ │ │ │ + OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + updateMatrixProperties: function() { │ │ │ │ + this.matrix = this.getMatrix(); │ │ │ │ + if (this.matrix) { │ │ │ │ + if (this.matrix.topLeftCorner) { │ │ │ │ + this.tileOrigin = this.matrix.topLeftCorner │ │ │ │ + } │ │ │ │ + if (this.matrix.tileWidth && this.matrix.tileHeight) { │ │ │ │ + this.tileSize = new OpenLayers.Size(this.matrix.tileWidth, this.matrix.tileHeight) │ │ │ │ + } │ │ │ │ + if (!this.tileOrigin) { │ │ │ │ + this.tileOrigin = new OpenLayers.LonLat(this.maxExtent.left, this.maxExtent.top) │ │ │ │ + } │ │ │ │ + if (!this.tileFullExtent) { │ │ │ │ + this.tileFullExtent = this.maxExtent │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ + if (zoomChanged || !this.matrix) { │ │ │ │ + this.updateMatrixProperties() │ │ │ │ + } │ │ │ │ + return OpenLayers.Layer.Grid.prototype.moveTo.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.WMTS(this.options) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + getIdentifier: function() { │ │ │ │ + return this.getServerZoom() │ │ │ │ + }, │ │ │ │ + getMatrix: function() { │ │ │ │ + var matrix; │ │ │ │ + if (!this.matrixIds || this.matrixIds.length === 0) { │ │ │ │ + matrix = { │ │ │ │ + identifier: this.getIdentifier() │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if ("scaleDenominator" in this.matrixIds[0]) { │ │ │ │ + var denom = OpenLayers.METERS_PER_INCH * OpenLayers.INCHES_PER_UNIT[this.units] * this.getServerResolution() / 28e-5; │ │ │ │ + var diff = Number.POSITIVE_INFINITY; │ │ │ │ + var delta; │ │ │ │ + for (var i = 0, ii = this.matrixIds.length; i < ii; ++i) { │ │ │ │ + delta = Math.abs(1 - this.matrixIds[i].scaleDenominator / denom); │ │ │ │ + if (delta < diff) { │ │ │ │ + diff = delta; │ │ │ │ + matrix = this.matrixIds[i] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + matrix = this.matrixIds[this.getIdentifier()] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return matrix │ │ │ │ + }, │ │ │ │ + getTileInfo: function(loc) { │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var fx = (loc.lon - this.tileOrigin.lon) / (res * this.tileSize.w); │ │ │ │ + var fy = (this.tileOrigin.lat - loc.lat) / (res * this.tileSize.h); │ │ │ │ + var col = Math.floor(fx); │ │ │ │ + var row = Math.floor(fy); │ │ │ │ + return { │ │ │ │ + col: col, │ │ │ │ + row: row, │ │ │ │ + i: Math.floor((fx - col) * this.tileSize.w), │ │ │ │ + j: Math.floor((fy - row) * this.tileSize.h) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var url = ""; │ │ │ │ + if (!this.tileFullExtent || this.tileFullExtent.intersectsBounds(bounds)) { │ │ │ │ + var center = bounds.getCenterLonLat(); │ │ │ │ + var info = this.getTileInfo(center); │ │ │ │ + var matrixId = this.matrix.identifier; │ │ │ │ + var dimensions = this.dimensions, │ │ │ │ + params; │ │ │ │ + if (OpenLayers.Util.isArray(this.url)) { │ │ │ │ + url = this.selectUrl([this.version, this.style, this.matrixSet, this.matrix.identifier, info.row, info.col].join(","), this.url) │ │ │ │ + } else { │ │ │ │ + url = this.url │ │ │ │ + } │ │ │ │ + if (this.requestEncoding.toUpperCase() === "REST") { │ │ │ │ + params = this.params; │ │ │ │ + if (url.indexOf("{") !== -1) { │ │ │ │ + var template = url.replace(/\{/g, "${"); │ │ │ │ + var context = { │ │ │ │ + style: this.style, │ │ │ │ + Style: this.style, │ │ │ │ + TileMatrixSet: this.matrixSet, │ │ │ │ + TileMatrix: this.matrix.identifier, │ │ │ │ + TileRow: info.row, │ │ │ │ + TileCol: info.col │ │ │ │ + }; │ │ │ │ + if (dimensions) { │ │ │ │ + var dimension, i; │ │ │ │ + for (i = dimensions.length - 1; i >= 0; --i) { │ │ │ │ + dimension = dimensions[i]; │ │ │ │ + context[dimension] = params[dimension.toUpperCase()] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + url = OpenLayers.String.format(template, context) │ │ │ │ + } else { │ │ │ │ + var path = this.version + "/" + this.layer + "/" + this.style + "/"; │ │ │ │ + if (dimensions) { │ │ │ │ + for (var i = 0; i < dimensions.length; i++) { │ │ │ │ + if (params[dimensions[i]]) { │ │ │ │ + path = path + params[dimensions[i]] + "/" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + path = path + this.matrixSet + "/" + this.matrix.identifier + "/" + info.row + "/" + info.col + "." + this.formatSuffix; │ │ │ │ + if (!url.match(/\/$/)) { │ │ │ │ + url = url + "/" │ │ │ │ + } │ │ │ │ + url = url + path │ │ │ │ + } │ │ │ │ + } else if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ + params = { │ │ │ │ + SERVICE: "WMTS", │ │ │ │ + REQUEST: "GetTile", │ │ │ │ + VERSION: this.version, │ │ │ │ + LAYER: this.layer, │ │ │ │ + STYLE: this.style, │ │ │ │ + TILEMATRIXSET: this.matrixSet, │ │ │ │ + TILEMATRIX: this.matrix.identifier, │ │ │ │ + TILEROW: info.row, │ │ │ │ + TILECOL: info.col, │ │ │ │ + FORMAT: this.format │ │ │ │ + }; │ │ │ │ + url = OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this, [params]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return url │ │ │ │ + }, │ │ │ │ + mergeNewParams: function(newParams) { │ │ │ │ + if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ + return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, [OpenLayers.Util.upperCaseObject(newParams)]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.WMTS" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.GeoRSS = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ + location: null, │ │ │ │ + features: null, │ │ │ │ + formatOptions: null, │ │ │ │ + selectedFeature: null, │ │ │ │ + icon: null, │ │ │ │ + popupSize: null, │ │ │ │ + useFeedTitle: true, │ │ │ │ + initialize: function(name, location, options) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.initialize.apply(this, [name, options]); │ │ │ │ + this.location = location; │ │ │ │ + this.features = [] │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ + this.clearFeatures(); │ │ │ │ + this.features = null │ │ │ │ + }, │ │ │ │ + loadRSS: function() { │ │ │ │ + if (!this.loaded) { │ │ │ │ + this.events.triggerEvent("loadstart"); │ │ │ │ + OpenLayers.Request.GET({ │ │ │ │ + url: this.location, │ │ │ │ + success: this.parseData, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.loaded = true │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ + if (this.visibility && !this.loaded) { │ │ │ │ + this.loadRSS() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + parseData: function(ajaxRequest) { │ │ │ │ + var doc = ajaxRequest.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = OpenLayers.Format.XML.prototype.read(ajaxRequest.responseText) │ │ │ │ + } │ │ │ │ + if (this.useFeedTitle) { │ │ │ │ + var name = null; │ │ │ │ + try { │ │ │ │ + name = doc.getElementsByTagNameNS("*", "title")[0].firstChild.nodeValue │ │ │ │ + } catch (e) { │ │ │ │ + try { │ │ │ │ + name = doc.getElementsByTagName("title")[0].firstChild.nodeValue │ │ │ │ + } catch (e) {} │ │ │ │ + } │ │ │ │ + if (name) { │ │ │ │ + this.setName(name) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var options = {}; │ │ │ │ + OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ + if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ + options.externalProjection = this.projection; │ │ │ │ + options.internalProjection = this.map.getProjectionObject() │ │ │ │ + } │ │ │ │ + var format = new OpenLayers.Format.GeoRSS(options); │ │ │ │ + var features = format.read(doc); │ │ │ │ + for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ + var data = {}; │ │ │ │ + var feature = features[i]; │ │ │ │ + if (!feature.geometry) { │ │ │ │ + continue │ │ │ │ + } │ │ │ │ + var title = feature.attributes.title ? feature.attributes.title : "Untitled"; │ │ │ │ + var description = feature.attributes.description ? feature.attributes.description : "No description."; │ │ │ │ + var link = feature.attributes.link ? feature.attributes.link : ""; │ │ │ │ + var location = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ + data.icon = this.icon == null ? OpenLayers.Marker.defaultIcon() : this.icon.clone(); │ │ │ │ + data.popupSize = this.popupSize ? this.popupSize.clone() : new OpenLayers.Size(250, 120); │ │ │ │ + if (title || description) { │ │ │ │ + data.title = title; │ │ │ │ + data.description = description; │ │ │ │ + var contentHTML = '<div class="olLayerGeoRSSClose">[x]</div>'; │ │ │ │ + contentHTML += '<div class="olLayerGeoRSSTitle">'; │ │ │ │ + if (link) { │ │ │ │ + contentHTML += '<a class="link" href="' + link + '" target="_blank">' │ │ │ │ + } │ │ │ │ + contentHTML += title; │ │ │ │ + if (link) { │ │ │ │ + contentHTML += "</a>" │ │ │ │ + } │ │ │ │ + contentHTML += "</div>"; │ │ │ │ + contentHTML += '<div style="" class="olLayerGeoRSSDescription">'; │ │ │ │ + contentHTML += description; │ │ │ │ + contentHTML += "</div>"; │ │ │ │ + data["popupContentHTML"] = contentHTML │ │ │ │ + } │ │ │ │ + var feature = new OpenLayers.Feature(this, location, data); │ │ │ │ + this.features.push(feature); │ │ │ │ + var marker = feature.createMarker(); │ │ │ │ + marker.events.register("click", feature, this.markerClick); │ │ │ │ + this.addMarker(marker) │ │ │ │ + } │ │ │ │ + this.events.triggerEvent("loadend") │ │ │ │ + }, │ │ │ │ + markerClick: function(evt) { │ │ │ │ + var sameMarkerClicked = this == this.layer.selectedFeature; │ │ │ │ + this.layer.selectedFeature = !sameMarkerClicked ? this : null; │ │ │ │ + for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ + this.layer.map.removePopup(this.layer.map.popups[i]) │ │ │ │ + } │ │ │ │ + if (!sameMarkerClicked) { │ │ │ │ + var popup = this.createPopup(); │ │ │ │ + OpenLayers.Event.observe(popup.div, "click", OpenLayers.Function.bind(function() { │ │ │ │ + for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ + this.layer.map.removePopup(this.layer.map.popups[i]) │ │ │ │ + } │ │ │ │ + }, this)); │ │ │ │ + this.layer.map.addPopup(popup) │ │ │ │ + } │ │ │ │ + OpenLayers.Event.stop(evt) │ │ │ │ + }, │ │ │ │ + clearFeatures: function() { │ │ │ │ + if (this.features != null) { │ │ │ │ + while (this.features.length > 0) { │ │ │ │ + var feature = this.features[0]; │ │ │ │ + OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ + feature.destroy() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.GeoRSS" │ │ │ │ +}); │ │ │ │ OpenLayers.Layer.ArcGIS93Rest = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ DEFAULT_PARAMS: { │ │ │ │ format: "png" │ │ │ │ }, │ │ │ │ isBaseLayer: true, │ │ │ │ initialize: function(name, url, params, options) { │ │ │ │ var newArguments = []; │ │ │ │ @@ -17591,876 +22077,1957 @@ │ │ │ │ mergeNewParams: function(newParams) { │ │ │ │ var upperParams = OpenLayers.Util.upperCaseObject(newParams); │ │ │ │ var newArguments = [upperParams]; │ │ │ │ return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, newArguments) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Layer.ArcGIS93Rest" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ - name: "OpenStreetMap", │ │ │ │ - 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"], │ │ │ │ - attribution: "© <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors", │ │ │ │ - sphericalMercator: true, │ │ │ │ - wrapDateLine: true, │ │ │ │ - tileOptions: null, │ │ │ │ - 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) │ │ │ │ +OpenLayers.Layer.Boxes = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ + drawMarker: function(marker) { │ │ │ │ + var topleft = this.map.getLayerPxFromLonLat({ │ │ │ │ + lon: marker.bounds.left, │ │ │ │ + lat: marker.bounds.top │ │ │ │ + }); │ │ │ │ + var botright = this.map.getLayerPxFromLonLat({ │ │ │ │ + lon: marker.bounds.right, │ │ │ │ + lat: marker.bounds.bottom │ │ │ │ + }); │ │ │ │ + if (botright == null || topleft == null) { │ │ │ │ + marker.display(false) │ │ │ │ + } else { │ │ │ │ + var markerDiv = marker.draw(topleft, { │ │ │ │ + w: Math.max(1, botright.x - topleft.x), │ │ │ │ + h: Math.max(1, botright.y - topleft.y) │ │ │ │ + }); │ │ │ │ + if (!marker.drawn) { │ │ │ │ + this.div.appendChild(markerDiv); │ │ │ │ + marker.drawn = true │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.OSM(this.name, this.url, this.getOptions()) │ │ │ │ + removeMarker: function(marker) { │ │ │ │ + OpenLayers.Util.removeItem(this.markers, marker); │ │ │ │ + if (marker.div != null && marker.div.parentNode == this.div) { │ │ │ │ + this.div.removeChild(marker.div) │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.OSM" │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Boxes" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.MapServer = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ +OpenLayers.Layer.WorldWind = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + DEFAULT_PARAMS: {}, │ │ │ │ + isBaseLayer: true, │ │ │ │ + lzd: null, │ │ │ │ + zoomLevels: null, │ │ │ │ + initialize: function(name, url, lzd, zoomLevels, params, options) { │ │ │ │ + this.lzd = lzd; │ │ │ │ + this.zoomLevels = zoomLevels; │ │ │ │ + var newArguments = []; │ │ │ │ + newArguments.push(name, url, params, options); │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments); │ │ │ │ + this.params = OpenLayers.Util.applyDefaults(this.params, this.DEFAULT_PARAMS) │ │ │ │ + }, │ │ │ │ + getZoom: function() { │ │ │ │ + var zoom = this.map.getZoom(); │ │ │ │ + var extent = this.map.getMaxExtent(); │ │ │ │ + zoom = zoom - Math.log(this.maxResolution / (this.lzd / 512)) / Math.log(2); │ │ │ │ + return zoom │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var zoom = this.getZoom(); │ │ │ │ + var extent = this.map.getMaxExtent(); │ │ │ │ + var deg = this.lzd / Math.pow(2, this.getZoom()); │ │ │ │ + var x = Math.floor((bounds.left - extent.left) / deg); │ │ │ │ + var y = Math.floor((bounds.bottom - extent.bottom) / deg); │ │ │ │ + if (this.map.getResolution() <= this.lzd / 512 && this.getZoom() <= this.zoomLevels) { │ │ │ │ + return this.getFullRequestString({ │ │ │ │ + L: zoom, │ │ │ │ + X: x, │ │ │ │ + Y: y │ │ │ │ + }) │ │ │ │ + } else { │ │ │ │ + return OpenLayers.Util.getImageLocation("blank.gif") │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.WorldWind" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.WMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ DEFAULT_PARAMS: { │ │ │ │ - mode: "map", │ │ │ │ - map_imagetype: "png" │ │ │ │ + service: "WMS", │ │ │ │ + version: "1.1.1", │ │ │ │ + request: "GetMap", │ │ │ │ + styles: "", │ │ │ │ + format: "image/jpeg" │ │ │ │ }, │ │ │ │ + isBaseLayer: true, │ │ │ │ + encodeBBOX: false, │ │ │ │ + noMagic: false, │ │ │ │ + yx: {}, │ │ │ │ initialize: function(name, url, params, options) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ - this.params = OpenLayers.Util.applyDefaults(this.params, this.DEFAULT_PARAMS); │ │ │ │ - if (options == null || options.isBaseLayer == null) { │ │ │ │ - this.isBaseLayer = this.params.transparent != "true" && this.params.transparent != true │ │ │ │ + var newArguments = []; │ │ │ │ + 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)); │ │ │ │ + if (!this.noMagic && this.params.TRANSPARENT && this.params.TRANSPARENT.toString().toLowerCase() == "true") { │ │ │ │ + if (options == null || !options.isBaseLayer) { │ │ │ │ + this.isBaseLayer = false │ │ │ │ + } │ │ │ │ + if (this.params.FORMAT == "image/jpeg") { │ │ │ │ + this.params.FORMAT = OpenLayers.Util.alphaHack() ? "image/gif" : "image/png" │ │ │ │ + } │ │ │ │ } │ │ │ │ }, │ │ │ │ clone: function(obj) { │ │ │ │ if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.MapServer(this.name, this.url, this.params, this.getOptions()) │ │ │ │ + obj = new OpenLayers.Layer.WMS(this.name, this.url, this.params, this.getOptions()) │ │ │ │ } │ │ │ │ obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ return obj │ │ │ │ }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ getURL: function(bounds) { │ │ │ │ bounds = this.adjustBounds(bounds); │ │ │ │ - var extent = [bounds.left, bounds.bottom, bounds.right, bounds.top]; │ │ │ │ var imageSize = this.getImageSize(); │ │ │ │ - var url = this.getFullRequestString({ │ │ │ │ - mapext: extent, │ │ │ │ - imgext: extent, │ │ │ │ - map_size: [imageSize.w, imageSize.h], │ │ │ │ - imgx: imageSize.w / 2, │ │ │ │ - imgy: imageSize.h / 2, │ │ │ │ - imgxy: [imageSize.w, imageSize.h] │ │ │ │ - }); │ │ │ │ - return url │ │ │ │ + var newParams = {}; │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + mergeNewParams: function(newParams) { │ │ │ │ + var upperParams = OpenLayers.Util.upperCaseObject(newParams); │ │ │ │ + var newArguments = [upperParams]; │ │ │ │ + return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, newArguments) │ │ │ │ }, │ │ │ │ getFullRequestString: function(newParams, altUrl) { │ │ │ │ - var url = altUrl == null ? this.url : altUrl; │ │ │ │ - var allParams = OpenLayers.Util.extend({}, this.params); │ │ │ │ - allParams = OpenLayers.Util.extend(allParams, newParams); │ │ │ │ - var paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(paramsString, url) │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - var urlParams = OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url)); │ │ │ │ - for (var key in allParams) { │ │ │ │ - if (key.toUpperCase() in urlParams) { │ │ │ │ - delete allParams[key] │ │ │ │ + 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.Layer.PointTrack = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ + dataFrom: null, │ │ │ │ + styleFrom: null, │ │ │ │ + addNodes: function(pointFeatures, options) { │ │ │ │ + if (pointFeatures.length < 2) { │ │ │ │ + throw new Error("At least two point features have to be added to " + "create a line from") │ │ │ │ + } │ │ │ │ + var lines = new Array(pointFeatures.length - 1); │ │ │ │ + var pointFeature, startPoint, endPoint; │ │ │ │ + for (var i = 0, len = pointFeatures.length; i < len; i++) { │ │ │ │ + pointFeature = pointFeatures[i]; │ │ │ │ + endPoint = pointFeature.geometry; │ │ │ │ + if (!endPoint) { │ │ │ │ + var lonlat = pointFeature.lonlat; │ │ │ │ + endPoint = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat) │ │ │ │ + } else if (endPoint.CLASS_NAME != "OpenLayers.Geometry.Point") { │ │ │ │ + throw new TypeError("Only features with point geometries are supported.") │ │ │ │ + } │ │ │ │ + if (i > 0) { │ │ │ │ + var attributes = this.dataFrom != null ? pointFeatures[i + this.dataFrom].data || pointFeatures[i + this.dataFrom].attributes : null; │ │ │ │ + var style = this.styleFrom != null ? pointFeatures[i + this.styleFrom].style : null; │ │ │ │ + var line = new OpenLayers.Geometry.LineString([startPoint, endPoint]); │ │ │ │ + lines[i - 1] = new OpenLayers.Feature.Vector(line, attributes, style) │ │ │ │ } │ │ │ │ + startPoint = endPoint │ │ │ │ } │ │ │ │ - paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ - var requestString = url; │ │ │ │ - paramsString = paramsString.replace(/,/g, "+"); │ │ │ │ - if (paramsString != "") { │ │ │ │ - var lastServerChar = url.charAt(url.length - 1); │ │ │ │ - if (lastServerChar == "&" || lastServerChar == "?") { │ │ │ │ - requestString += paramsString │ │ │ │ - } else { │ │ │ │ - if (url.indexOf("?") == -1) { │ │ │ │ - requestString += "?" + paramsString │ │ │ │ - } else { │ │ │ │ - requestString += "&" + paramsString │ │ │ │ + this.addFeatures(lines, options) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.PointTrack" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.PointTrack.SOURCE_NODE = -1; │ │ │ │ +OpenLayers.Layer.PointTrack.TARGET_NODE = 0; │ │ │ │ +OpenLayers.Layer.PointTrack.dataFrom = { │ │ │ │ + SOURCE_NODE: -1, │ │ │ │ + TARGET_NODE: 0 │ │ │ │ +}; │ │ │ │ +OpenLayers.Layer.Google.v3 = { │ │ │ │ + DEFAULTS: { │ │ │ │ + sphericalMercator: true, │ │ │ │ + projection: "EPSG:900913" │ │ │ │ + }, │ │ │ │ + animationEnabled: true, │ │ │ │ + loadMapObject: function() { │ │ │ │ + if (!this.type) { │ │ │ │ + this.type = google.maps.MapTypeId.ROADMAP │ │ │ │ + } │ │ │ │ + var mapObject; │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + mapObject = cache.mapObject; │ │ │ │ + ++cache.count │ │ │ │ + } else { │ │ │ │ + var center = this.map.getCenter(); │ │ │ │ + var container = document.createElement("div"); │ │ │ │ + container.className = "olForeignContainer"; │ │ │ │ + container.style.width = "100%"; │ │ │ │ + container.style.height = "100%"; │ │ │ │ + mapObject = new google.maps.Map(container, { │ │ │ │ + center: center ? new google.maps.LatLng(center.lat, center.lon) : new google.maps.LatLng(0, 0), │ │ │ │ + zoom: this.map.getZoom() || 0, │ │ │ │ + mapTypeId: this.type, │ │ │ │ + disableDefaultUI: true, │ │ │ │ + keyboardShortcuts: false, │ │ │ │ + draggable: false, │ │ │ │ + disableDoubleClickZoom: true, │ │ │ │ + scrollwheel: false, │ │ │ │ + streetViewControl: false │ │ │ │ + }); │ │ │ │ + var googleControl = document.createElement("div"); │ │ │ │ + googleControl.style.width = "100%"; │ │ │ │ + googleControl.style.height = "100%"; │ │ │ │ + mapObject.controls[google.maps.ControlPosition.TOP_LEFT].push(googleControl); │ │ │ │ + cache = { │ │ │ │ + googleControl: googleControl, │ │ │ │ + mapObject: mapObject, │ │ │ │ + count: 1 │ │ │ │ + }; │ │ │ │ + OpenLayers.Layer.Google.cache[this.map.id] = cache │ │ │ │ + } │ │ │ │ + this.mapObject = mapObject; │ │ │ │ + this.setGMapVisibility(this.visibility) │ │ │ │ + }, │ │ │ │ + onMapResize: function() { │ │ │ │ + if (this.visibility) { │ │ │ │ + google.maps.event.trigger(this.mapObject, "resize") │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setGMapVisibility: function(visible) { │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + var map = this.map; │ │ │ │ + if (cache) { │ │ │ │ + var type = this.type; │ │ │ │ + var layers = map.layers; │ │ │ │ + var layer; │ │ │ │ + for (var i = layers.length - 1; i >= 0; --i) { │ │ │ │ + layer = layers[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.Google && layer.visibility === true && layer.inRange === true) { │ │ │ │ + type = layer.type; │ │ │ │ + visible = true; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var container = this.mapObject.getDiv(); │ │ │ │ + if (visible === true) { │ │ │ │ + if (container.parentNode !== map.div) { │ │ │ │ + if (!cache.rendered) { │ │ │ │ + var me = this; │ │ │ │ + google.maps.event.addListenerOnce(this.mapObject, "tilesloaded", function() { │ │ │ │ + cache.rendered = true; │ │ │ │ + me.setGMapVisibility(me.getVisibility()); │ │ │ │ + me.moveTo(me.map.getCenter()) │ │ │ │ + }) │ │ │ │ + } else { │ │ │ │ + map.div.appendChild(container); │ │ │ │ + cache.googleControl.appendChild(map.viewPortDiv); │ │ │ │ + google.maps.event.trigger(this.mapObject, "resize") │ │ │ │ + } │ │ │ │ } │ │ │ │ + this.mapObject.setMapTypeId(type) │ │ │ │ + } else if (cache.googleControl.hasChildNodes()) { │ │ │ │ + map.div.appendChild(map.viewPortDiv); │ │ │ │ + map.div.removeChild(container) │ │ │ │ } │ │ │ │ } │ │ │ │ - return requestString │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.MapServer" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.KaMap = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - isBaseLayer: true, │ │ │ │ - DEFAULT_PARAMS: { │ │ │ │ - i: "jpeg", │ │ │ │ - map: "" │ │ │ │ + getMapContainer: function() { │ │ │ │ + return this.mapObject.getDiv() │ │ │ │ }, │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ - this.params = OpenLayers.Util.applyDefaults(this.params, this.DEFAULT_PARAMS) │ │ │ │ + getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ + var moBounds = null; │ │ │ │ + if (olBounds != null) { │ │ │ │ + var sw = this.sphericalMercator ? this.inverseMercator(olBounds.bottom, olBounds.left) : new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ + var ne = this.sphericalMercator ? this.inverseMercator(olBounds.top, olBounds.right) : new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ + moBounds = new google.maps.LatLngBounds(new google.maps.LatLng(sw.lat, sw.lon), new google.maps.LatLng(ne.lat, ne.lon)) │ │ │ │ + } │ │ │ │ + return moBounds │ │ │ │ }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ - var scale = Math.round(this.map.getScale() * 1e4) / 1e4; │ │ │ │ - var pX = Math.round(bounds.left / mapRes); │ │ │ │ - var pY = -Math.round(bounds.top / mapRes); │ │ │ │ - return this.getFullRequestString({ │ │ │ │ - t: pY, │ │ │ │ - l: pX, │ │ │ │ - s: scale │ │ │ │ - }) │ │ │ │ + getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ + var size = this.map.getSize(); │ │ │ │ + var lon = this.getLongitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ + var lat = this.getLatitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ + var delta_x = moPixel.x - size.w / 2; │ │ │ │ + var delta_y = moPixel.y - size.h / 2; │ │ │ │ + var lonlat = new OpenLayers.LonLat(lon + delta_x * res, lat - delta_y * res); │ │ │ │ + if (this.wrapDateLine) { │ │ │ │ + lonlat = lonlat.wrapDateLine(this.maxExtent) │ │ │ │ + } │ │ │ │ + return this.getMapObjectLonLatFromLonLat(lonlat.lon, lonlat.lat) │ │ │ │ }, │ │ │ │ - calculateGridLayout: function(bounds, origin, resolution) { │ │ │ │ - var tilelon = resolution * this.tileSize.w; │ │ │ │ - var tilelat = resolution * this.tileSize.h; │ │ │ │ - var offsetlon = bounds.left; │ │ │ │ - var tilecol = Math.floor(offsetlon / tilelon) - this.buffer; │ │ │ │ - var offsetlat = bounds.top; │ │ │ │ - var tilerow = Math.floor(offsetlat / tilelat) + this.buffer; │ │ │ │ - return { │ │ │ │ - tilelon: tilelon, │ │ │ │ - tilelat: tilelat, │ │ │ │ - startcol: tilecol, │ │ │ │ - startrow: tilerow │ │ │ │ + getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); │ │ │ │ + var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ + var extent = this.map.getExtent(); │ │ │ │ + return this.getMapObjectPixelFromXY(1 / res * (lon - extent.left), 1 / res * (extent.top - lat)) │ │ │ │ + }, │ │ │ │ + setMapObjectCenter: function(center, zoom) { │ │ │ │ + if (this.animationEnabled === false && zoom != this.mapObject.zoom) { │ │ │ │ + var mapContainer = this.getMapContainer(); │ │ │ │ + google.maps.event.addListenerOnce(this.mapObject, "idle", function() { │ │ │ │ + mapContainer.style.visibility = "" │ │ │ │ + }); │ │ │ │ + mapContainer.style.visibility = "hidden" │ │ │ │ } │ │ │ │ + this.mapObject.setOptions({ │ │ │ │ + center: center, │ │ │ │ + zoom: zoom │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - getTileBoundsForGridIndex: function(row, col) { │ │ │ │ - var origin = this.getTileOrigin(); │ │ │ │ - var tileLayout = this.gridLayout; │ │ │ │ - var tilelon = tileLayout.tilelon; │ │ │ │ - var tilelat = tileLayout.tilelat; │ │ │ │ - var minX = (tileLayout.startcol + col) * tilelon; │ │ │ │ - var minY = (tileLayout.startrow - row) * tilelat; │ │ │ │ - return new OpenLayers.Bounds(minX, minY, minX + tilelon, minY + tilelat) │ │ │ │ + getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ + return this.mapObject.getBoundsZoomLevel(moBounds) │ │ │ │ }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.KaMap(this.name, this.url, this.params, this.getOptions()) │ │ │ │ + getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ + var gLatLng; │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + var lonlat = this.inverseMercator(lon, lat); │ │ │ │ + gLatLng = new google.maps.LatLng(lonlat.lat, lonlat.lon) │ │ │ │ + } else { │ │ │ │ + gLatLng = new google.maps.LatLng(lat, lon) │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - if (this.tileSize != null) { │ │ │ │ - obj.tileSize = this.tileSize.clone() │ │ │ │ + return gLatLng │ │ │ │ + }, │ │ │ │ + getMapObjectPixelFromXY: function(x, y) { │ │ │ │ + return new google.maps.Point(x, y) │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ + displayInLayerSwitcher: false, │ │ │ │ + layers: null, │ │ │ │ + display: function() {}, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ } │ │ │ │ - obj.grid = []; │ │ │ │ - return obj │ │ │ │ }, │ │ │ │ - getTileBounds: function(viewPortPx) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var tileMapWidth = resolution * this.tileSize.w; │ │ │ │ - var tileMapHeight = resolution * this.tileSize.h; │ │ │ │ - var mapPoint = this.getLonLatFromViewPortPx(viewPortPx); │ │ │ │ - var tileLeft = tileMapWidth * Math.floor(mapPoint.lon / tileMapWidth); │ │ │ │ - var tileBottom = tileMapHeight * Math.floor(mapPoint.lat / tileMapHeight); │ │ │ │ - return new OpenLayers.Bounds(tileLeft, tileBottom, tileLeft + tileMapWidth, tileBottom + tileMapHeight) │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ + this.collectRoots(); │ │ │ │ + map.events.register("changelayer", this, this.handleChangeLayer) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.KaMap" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.KaMapCache = OpenLayers.Class(OpenLayers.Layer.KaMap, { │ │ │ │ - IMAGE_EXTENSIONS: { │ │ │ │ - jpeg: "jpg", │ │ │ │ - gif: "gif", │ │ │ │ - png: "png", │ │ │ │ - png8: "png", │ │ │ │ - png24: "png", │ │ │ │ - dithered: "png" │ │ │ │ + removeMap: function(map) { │ │ │ │ + map.events.unregister("changelayer", this, this.handleChangeLayer); │ │ │ │ + this.resetRoots(); │ │ │ │ + OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments) │ │ │ │ }, │ │ │ │ - DEFAULT_FORMAT: "jpeg", │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - OpenLayers.Layer.KaMap.prototype.initialize.apply(this, arguments); │ │ │ │ - this.extension = this.IMAGE_EXTENSIONS[this.params.i.toLowerCase() || this.DEFAULT_FORMAT] │ │ │ │ + collectRoots: function() { │ │ │ │ + var layer; │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ - var scale = Math.round(this.map.getScale() * 1e4) / 1e4; │ │ │ │ - var pX = Math.round(bounds.left / mapRes); │ │ │ │ - var pY = -Math.round(bounds.top / mapRes); │ │ │ │ - var metaX = Math.floor(pX / this.tileSize.w / this.params.metaTileSize.w) * this.tileSize.w * this.params.metaTileSize.w; │ │ │ │ - var metaY = Math.floor(pY / this.tileSize.h / this.params.metaTileSize.h) * this.tileSize.h * this.params.metaTileSize.h; │ │ │ │ - var components = ["/", this.params.map, "/", scale, "/", this.params.g.replace(/\s/g, "_"), "/def/t", metaY, "/l", metaX, "/t", pY, "l", pX, ".", this.extension]; │ │ │ │ - var url = this.url; │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(components.join(""), url) │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ } │ │ │ │ - return url + components.join("") │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.KaMapCache" │ │ │ │ + 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.Layer.Image = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ - isBaseLayer: true, │ │ │ │ +OpenLayers.Protocol.SOS = function(options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, OpenLayers.Protocol.SOS.DEFAULTS); │ │ │ │ + var cls = OpenLayers.Protocol.SOS["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (!cls) { │ │ │ │ + throw "Unsupported SOS version: " + options.version │ │ │ │ + } │ │ │ │ + return new cls(options) │ │ │ │ +}; │ │ │ │ +OpenLayers.Protocol.SOS.DEFAULTS = { │ │ │ │ + version: "1.0.0" │ │ │ │ +}; │ │ │ │ +OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ url: null, │ │ │ │ - extent: null, │ │ │ │ - size: null, │ │ │ │ - tile: null, │ │ │ │ - aspectRatio: null, │ │ │ │ - initialize: function(name, url, extent, size, options) { │ │ │ │ - this.url = url; │ │ │ │ - this.extent = extent; │ │ │ │ - this.maxExtent = extent; │ │ │ │ - this.size = size; │ │ │ │ - OpenLayers.Layer.prototype.initialize.apply(this, [name, options]); │ │ │ │ - this.aspectRatio = this.extent.getHeight() / this.size.h / (this.extent.getWidth() / this.size.w) │ │ │ │ + headers: null, │ │ │ │ + params: null, │ │ │ │ + callback: null, │ │ │ │ + scope: null, │ │ │ │ + readWithPOST: false, │ │ │ │ + updateWithPOST: false, │ │ │ │ + deleteWithPOST: false, │ │ │ │ + wildcarded: false, │ │ │ │ + srsInBBOX: false, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ destroy: function() { │ │ │ │ - if (this.tile) { │ │ │ │ - this.removeTileMonitoringHooks(this.tile); │ │ │ │ - this.tile.destroy(); │ │ │ │ - this.tile = null │ │ │ │ + this.params = null; │ │ │ │ + this.headers = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - OpenLayers.Layer.prototype.destroy.apply(this, arguments) │ │ │ │ + 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 │ │ │ │ }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.Image(this.name, this.url, this.extent, this.size, this.getOptions()) │ │ │ │ + handleRead: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleCreate: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleUpdate: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ + resp.priv = OpenLayers.Request[method](requestOptions); │ │ │ │ + return resp │ │ │ │ }, │ │ │ │ - setMap: function(map) { │ │ │ │ - if (this.options.maxResolution == null) { │ │ │ │ - this.options.maxResolution = this.aspectRatio * this.extent.getWidth() / this.size.w │ │ │ │ + handleDelete: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options) │ │ │ │ + }, │ │ │ │ + handleResponse: function(resp, options) { │ │ │ │ + var request = resp.priv; │ │ │ │ + if (options.callback) { │ │ │ │ + if (request.status >= 200 && request.status < 300) { │ │ │ │ + if (resp.requestType != "delete") { │ │ │ │ + resp.features = this.parseFeatures(request) │ │ │ │ + } │ │ │ │ + resp.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ + } else { │ │ │ │ + resp.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ + } │ │ │ │ + options.callback.call(options.scope, resp) │ │ │ │ } │ │ │ │ - OpenLayers.Layer.prototype.setMap.apply(this, arguments) │ │ │ │ }, │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ - var firstRendering = this.tile == null; │ │ │ │ - if (zoomChanged || firstRendering) { │ │ │ │ - this.setTileSize(); │ │ │ │ - var ulPx = this.map.getLayerPxFromLonLat({ │ │ │ │ - lon: this.extent.left, │ │ │ │ - lat: this.extent.top │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + commit: function(features, options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ + var resp = [], │ │ │ │ + nResponses = 0; │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var nRequests = (types[OpenLayers.State.INSERT].length > 0 ? 1 : 0) + types[OpenLayers.State.UPDATE].length + types[OpenLayers.State.DELETE].length; │ │ │ │ + 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]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + response.priv.abort() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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.Protocol.CSW = function(options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, OpenLayers.Protocol.CSW.DEFAULTS); │ │ │ │ + var cls = OpenLayers.Protocol.CSW["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (!cls) { │ │ │ │ + throw "Unsupported CSW version: " + options.version │ │ │ │ + } │ │ │ │ + return new cls(options) │ │ │ │ +}; │ │ │ │ +OpenLayers.Protocol.CSW.DEFAULTS = { │ │ │ │ + version: "2.0.2" │ │ │ │ +}; │ │ │ │ +OpenLayers.Protocol.Script = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ + url: null, │ │ │ │ + params: null, │ │ │ │ + callback: null, │ │ │ │ + callbackTemplate: "OpenLayers.Protocol.Script.registry.${id}", │ │ │ │ + callbackKey: "callback", │ │ │ │ + callbackPrefix: "", │ │ │ │ + scope: null, │ │ │ │ + format: null, │ │ │ │ + pendingRequests: null, │ │ │ │ + srsInBBOX: false, │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + this.params = {}; │ │ │ │ + this.pendingRequests = {}; │ │ │ │ + OpenLayers.Protocol.prototype.initialize.apply(this, arguments); │ │ │ │ + if (!this.format) { │ │ │ │ + this.format = new OpenLayers.Format.GeoJSON │ │ │ │ + } │ │ │ │ + if (!this.filterToParams && OpenLayers.Format.QueryStringFilter) { │ │ │ │ + var format = new OpenLayers.Format.QueryStringFilter({ │ │ │ │ + srsInBBOX: this.srsInBBOX │ │ │ │ }); │ │ │ │ - if (firstRendering) { │ │ │ │ - this.tile = new OpenLayers.Tile.Image(this, ulPx, this.extent, null, this.tileSize); │ │ │ │ - this.addTileMonitoringHooks(this.tile) │ │ │ │ + this.filterToParams = function(filter, params) { │ │ │ │ + return format.write(filter, params) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + read: function(options) { │ │ │ │ + OpenLayers.Protocol.prototype.read.apply(this, arguments); │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ + options.params = OpenLayers.Util.applyDefaults(options.params, this.options.params); │ │ │ │ + if (options.filter && this.filterToParams) { │ │ │ │ + options.params = this.filterToParams(options.filter, options.params) │ │ │ │ + } │ │ │ │ + var response = new OpenLayers.Protocol.Response({ │ │ │ │ + requestType: "read" │ │ │ │ + }); │ │ │ │ + var request = this.createRequest(options.url, options.params, OpenLayers.Function.bind(function(data) { │ │ │ │ + response.data = data; │ │ │ │ + this.handleRead(response, options) │ │ │ │ + }, this)); │ │ │ │ + response.priv = request; │ │ │ │ + return response │ │ │ │ + }, │ │ │ │ + createRequest: function(url, params, callback) { │ │ │ │ + var id = OpenLayers.Protocol.Script.register(callback); │ │ │ │ + var name = OpenLayers.String.format(this.callbackTemplate, { │ │ │ │ + id: id │ │ │ │ + }); │ │ │ │ + params = OpenLayers.Util.extend({}, params); │ │ │ │ + params[this.callbackKey] = this.callbackPrefix + name; │ │ │ │ + url = OpenLayers.Util.urlAppend(url, OpenLayers.Util.getParameterString(params)); │ │ │ │ + var script = document.createElement("script"); │ │ │ │ + script.type = "text/javascript"; │ │ │ │ + script.src = url; │ │ │ │ + script.id = "OpenLayers_Protocol_Script_" + id; │ │ │ │ + this.pendingRequests[script.id] = script; │ │ │ │ + var head = document.getElementsByTagName("head")[0]; │ │ │ │ + head.appendChild(script); │ │ │ │ + return script │ │ │ │ + }, │ │ │ │ + destroyRequest: function(script) { │ │ │ │ + OpenLayers.Protocol.Script.unregister(script.id.split("_").pop()); │ │ │ │ + delete this.pendingRequests[script.id]; │ │ │ │ + if (script.parentNode) { │ │ │ │ + script.parentNode.removeChild(script) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + handleRead: function(response, options) { │ │ │ │ + this.handleResponse(response, options) │ │ │ │ + }, │ │ │ │ + handleResponse: function(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + if (response.data) { │ │ │ │ + response.features = this.parseFeatures(response.data); │ │ │ │ + response.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ } else { │ │ │ │ - this.tile.size = this.tileSize.clone(); │ │ │ │ - this.tile.position = ulPx.clone() │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ } │ │ │ │ - this.tile.draw() │ │ │ │ + this.destroyRequest(response.priv); │ │ │ │ + options.callback.call(options.scope, response) │ │ │ │ } │ │ │ │ }, │ │ │ │ - setTileSize: function() { │ │ │ │ - var tileWidth = this.extent.getWidth() / this.map.getResolution(); │ │ │ │ - var tileHeight = this.extent.getHeight() / this.map.getResolution(); │ │ │ │ - this.tileSize = new OpenLayers.Size(tileWidth, tileHeight) │ │ │ │ + parseFeatures: function(data) { │ │ │ │ + return this.format.read(data) │ │ │ │ }, │ │ │ │ - addTileMonitoringHooks: function(tile) { │ │ │ │ - tile.onLoadStart = function() { │ │ │ │ - this.events.triggerEvent("loadstart") │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + this.destroyRequest(response.priv) │ │ │ │ + } else { │ │ │ │ + for (var key in this.pendingRequests) { │ │ │ │ + this.destroyRequest(this.pendingRequests[key]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.abort(); │ │ │ │ + delete this.params; │ │ │ │ + delete this.format; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.Script" │ │ │ │ +}); │ │ │ │ +(function() { │ │ │ │ + var o = OpenLayers.Protocol.Script; │ │ │ │ + var counter = 0; │ │ │ │ + o.registry = {}; │ │ │ │ + o.register = function(callback) { │ │ │ │ + var id = "c" + ++counter; │ │ │ │ + o.registry[id] = function() { │ │ │ │ + callback.apply(this, arguments) │ │ │ │ }; │ │ │ │ - tile.events.register("loadstart", this, tile.onLoadStart); │ │ │ │ - tile.onLoadEnd = function() { │ │ │ │ - this.events.triggerEvent("loadend") │ │ │ │ + return id │ │ │ │ + }; │ │ │ │ + o.unregister = function(id) { │ │ │ │ + delete o.registry[id] │ │ │ │ + } │ │ │ │ +})(); │ │ │ │ +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) │ │ │ │ +}; │ │ │ │ +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)) │ │ │ │ +}; │ │ │ │ +OpenLayers.Protocol.WFS.DEFAULTS = { │ │ │ │ + version: "1.0.0" │ │ │ │ +}; │ │ │ │ +OpenLayers.Format.SOSGetFeatureOfInterest = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + VERSION: "1.0.0", │ │ │ │ + namespaces: { │ │ │ │ + sos: "http://www.opengis.net/sos/1.0", │ │ │ │ + gml: "http://www.opengis.net/gml", │ │ │ │ + sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + }, │ │ │ │ + schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosAll.xsd", │ │ │ │ + defaultPrefix: "sos", │ │ │ │ + regExes: { │ │ │ │ + trimSpace: /^\s*|\s*$/g, │ │ │ │ + removeSpace: /\s*/g, │ │ │ │ + splitSpace: /\s+/, │ │ │ │ + trimComma: /\s*,\s*/g │ │ │ │ + }, │ │ │ │ + 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 info = { │ │ │ │ + features: [] │ │ │ │ }; │ │ │ │ - tile.events.register("loadend", this, tile.onLoadEnd); │ │ │ │ - tile.events.register("unload", this, tile.onLoadEnd) │ │ │ │ + this.readNode(data, info); │ │ │ │ + var features = []; │ │ │ │ + for (var i = 0, len = info.features.length; i < len; i++) { │ │ │ │ + var container = info.features[i]; │ │ │ │ + if (this.internalProjection && this.externalProjection && container.components[0]) { │ │ │ │ + container.components[0].transform(this.externalProjection, this.internalProjection) │ │ │ │ + } │ │ │ │ + var feature = new OpenLayers.Feature.Vector(container.components[0], container.attributes); │ │ │ │ + features.push(feature) │ │ │ │ + } │ │ │ │ + return features │ │ │ │ }, │ │ │ │ - removeTileMonitoringHooks: function(tile) { │ │ │ │ - tile.unload(); │ │ │ │ - tile.events.un({ │ │ │ │ - loadstart: tile.onLoadStart, │ │ │ │ - loadend: tile.onLoadEnd, │ │ │ │ - unload: tile.onLoadEnd, │ │ │ │ - scope: this │ │ │ │ + readers: { │ │ │ │ + sa: { │ │ │ │ + SamplingPoint: function(node, obj) { │ │ │ │ + if (!obj.attributes) { │ │ │ │ + var feature = { │ │ │ │ + attributes: {} │ │ │ │ + }; │ │ │ │ + obj.features.push(feature); │ │ │ │ + obj = feature │ │ │ │ + } │ │ │ │ + obj.attributes.id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + position: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + gml: OpenLayers.Util.applyDefaults({ │ │ │ │ + FeatureCollection: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + featureMember: function(node, obj) { │ │ │ │ + var feature = { │ │ │ │ + attributes: {} │ │ │ │ + }; │ │ │ │ + obj.features.push(feature); │ │ │ │ + this.readChildNodes(node, feature) │ │ │ │ + }, │ │ │ │ + name: function(node, obj) { │ │ │ │ + obj.attributes.name = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + pos: function(node, obj) { │ │ │ │ + if (!this.externalProjection) { │ │ │ │ + this.externalProjection = new OpenLayers.Projection(node.getAttribute("srsName")) │ │ │ │ + } │ │ │ │ + OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply(this, [node, obj]) │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.GML.v3.prototype.readers.gml) │ │ │ │ + }, │ │ │ │ + writers: { │ │ │ │ + sos: { │ │ │ │ + GetFeatureOfInterest: function(options) { │ │ │ │ + var node = this.createElementNSPlus("GetFeatureOfInterest", { │ │ │ │ + attributes: { │ │ │ │ + version: this.VERSION, │ │ │ │ + service: "SOS", │ │ │ │ + "xsi:schemaLocation": this.schemaLocation │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + for (var i = 0, len = options.fois.length; i < len; i++) { │ │ │ │ + this.writeNode("FeatureOfInterestId", { │ │ │ │ + foi: options.fois[i] │ │ │ │ + }, node) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + FeatureOfInterestId: function(options) { │ │ │ │ + var node = this.createElementNSPlus("FeatureOfInterestId", { │ │ │ │ + value: options.foi │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SOSGetFeatureOfInterest" │ │ │ │ +}); │ │ │ │ +OpenLayers.Protocol.SOS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ + fois: null, │ │ │ │ + formatOptions: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ + if (!options.format) { │ │ │ │ + this.format = new OpenLayers.Format.SOSGetFeatureOfInterest(this.formatOptions) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.options && !this.options.format) { │ │ │ │ + this.format.destroy() │ │ │ │ + } │ │ │ │ + this.format = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ + }, │ │ │ │ + read: function(options) { │ │ │ │ + options = OpenLayers.Util.extend({}, options); │ │ │ │ + OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ + var response = new OpenLayers.Protocol.Response({ │ │ │ │ + requestType: "read" │ │ │ │ + }); │ │ │ │ + var format = this.format; │ │ │ │ + var data = OpenLayers.Format.XML.prototype.write.apply(format, [format.writeNode("sos:GetFeatureOfInterest", { │ │ │ │ + fois: this.fois │ │ │ │ + })]); │ │ │ │ + response.priv = OpenLayers.Request.POST({ │ │ │ │ + url: options.url, │ │ │ │ + callback: this.createCallback(this.handleRead, response, options), │ │ │ │ + data: data │ │ │ │ + }); │ │ │ │ + return response │ │ │ │ + }, │ │ │ │ + handleRead: function(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + var request = response.priv; │ │ │ │ + if (request.status >= 200 && request.status < 300) { │ │ │ │ + response.features = this.parseFeatures(request); │ │ │ │ + response.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ + } else { │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ + } │ │ │ │ + options.callback.call(options.scope, response) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.SOS.v1_0_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ + version: null, │ │ │ │ + srsName: "EPSG:4326", │ │ │ │ + featureType: null, │ │ │ │ + featureNS: null, │ │ │ │ + geometryName: "the_geom", │ │ │ │ + schema: null, │ │ │ │ + featurePrefix: "feature", │ │ │ │ + formatOptions: null, │ │ │ │ + readFormat: null, │ │ │ │ + readOptions: null, │ │ │ │ + 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) { │ │ │ │ + this.setGeometryName(null) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.options && !this.options.format) { │ │ │ │ + this.format.destroy() │ │ │ │ + } │ │ │ │ + this.format = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + setFeatureType: function(featureType) { │ │ │ │ + this.featureType = featureType; │ │ │ │ + this.format.featureType = featureType │ │ │ │ + }, │ │ │ │ + setGeometryName: function(geometryName) { │ │ │ │ + this.geometryName = geometryName; │ │ │ │ + this.format.geometryName = geometryName │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + 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 { │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ + response.error = result │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ + } │ │ │ │ + options.callback.call(options.scope, response) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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; │ │ │ │ + format.autoConfig = false; │ │ │ │ + if (!this.geometryName) { │ │ │ │ + this.setGeometryName(format.geometryName) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return result │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleCommit: function(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + var request = response.priv; │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ }) │ │ │ │ }, │ │ │ │ - setUrl: function(newUrl) { │ │ │ │ - this.url = newUrl; │ │ │ │ - this.tile.draw() │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + response.priv.abort() │ │ │ │ + } │ │ │ │ }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - return this.url │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.WFS.v1" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, { │ │ │ │ + schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd", │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Image" │ │ │ │ + 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"] │ │ │ │ + }, │ │ │ │ + write: function(features) { │ │ │ │ + var name; │ │ │ │ + if (OpenLayers.Util.isArray(features)) { │ │ │ │ + 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]) │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + 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); │ │ │ │ + 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.Layer.WMTS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - isBaseLayer: true, │ │ │ │ - version: "1.0.0", │ │ │ │ - requestEncoding: "KVP", │ │ │ │ - url: null, │ │ │ │ - layer: null, │ │ │ │ - matrixSet: null, │ │ │ │ - style: null, │ │ │ │ - format: "image/jpeg", │ │ │ │ - tileOrigin: null, │ │ │ │ - tileFullExtent: null, │ │ │ │ - formatSuffix: null, │ │ │ │ - matrixIds: null, │ │ │ │ - dimensions: null, │ │ │ │ - params: null, │ │ │ │ - zoomOffset: 0, │ │ │ │ - serverResolutions: null, │ │ │ │ - formatSuffixMap: { │ │ │ │ - "image/png": "png", │ │ │ │ - "image/png8": "png", │ │ │ │ - "image/png24": "png", │ │ │ │ - "image/png32": "png", │ │ │ │ - png: "png", │ │ │ │ - "image/jpeg": "jpg", │ │ │ │ - "image/jpg": "jpg", │ │ │ │ - jpeg: "jpg", │ │ │ │ - jpg: "jpg" │ │ │ │ +OpenLayers.Format.Filter.v1_0_0 = OpenLayers.Class(OpenLayers.Format.GML.v2, OpenLayers.Format.Filter.v1, { │ │ │ │ + VERSION: "1.0.0", │ │ │ │ + schemaLocation: "http://www.opengis.net/ogc/filter/1.0.0/filter.xsd", │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.GML.v2.prototype.initialize.apply(this, [options]) │ │ │ │ }, │ │ │ │ - matrix: null, │ │ │ │ - initialize: function(config) { │ │ │ │ - var required = { │ │ │ │ - url: true, │ │ │ │ - layer: true, │ │ │ │ - style: true, │ │ │ │ - matrixSet: true │ │ │ │ - }; │ │ │ │ - for (var prop in required) { │ │ │ │ - if (!(prop in config)) { │ │ │ │ - throw new Error("Missing property '" + prop + "' in layer configuration.") │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - } │ │ │ │ - config.params = OpenLayers.Util.upperCaseObject(config.params); │ │ │ │ - var args = [config.name, config.url, config.params, config]; │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, args); │ │ │ │ - if (!this.formatSuffix) { │ │ │ │ - this.formatSuffix = this.formatSuffixMap[this.format] || this.format.split("/").pop() │ │ │ │ - } │ │ │ │ - if (this.matrixIds) { │ │ │ │ - var len = this.matrixIds.length; │ │ │ │ - if (len && typeof this.matrixIds[0] === "string") { │ │ │ │ - var ids = this.matrixIds; │ │ │ │ - this.matrixIds = new Array(len); │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ - this.matrixIds[i] = { │ │ │ │ - identifier: ids[i] │ │ │ │ + }, OpenLayers.Format.Filter.v1.prototype.readers["ogc"]), │ │ │ │ + gml: OpenLayers.Format.GML.v2.prototype.readers["gml"], │ │ │ │ + feature: OpenLayers.Format.GML.v2.prototype.readers["feature"] │ │ │ │ + }, │ │ │ │ + writers: { │ │ │ │ + ogc: OpenLayers.Util.applyDefaults({ │ │ │ │ + PropertyIsEqualTo: function(filter) { │ │ │ │ + var node = this.createElementNSPlus("ogc:PropertyIsEqualTo"); │ │ │ │ + this.writeNode("PropertyName", filter, node); │ │ │ │ + this.writeOgcExpression(filter.value, node); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + PropertyIsNotEqualTo: function(filter) { │ │ │ │ + var node = this.createElementNSPlus("ogc:PropertyIsNotEqualTo"); │ │ │ │ + this.writeNode("PropertyName", filter, node); │ │ │ │ + this.writeOgcExpression(filter.value, node); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + PropertyIsLike: function(filter) { │ │ │ │ + var node = this.createElementNSPlus("ogc:PropertyIsLike", { │ │ │ │ + attributes: { │ │ │ │ + wildCard: "*", │ │ │ │ + singleChar: ".", │ │ │ │ + escape: "!" │ │ │ │ } │ │ │ │ + }); │ │ │ │ + this.writeNode("PropertyName", filter, node); │ │ │ │ + this.writeNode("Literal", filter.regex2value(), node); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + BBOX: function(filter) { │ │ │ │ + var node = this.createElementNSPlus("ogc:BBOX"); │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setMap: function() { │ │ │ │ - OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments) │ │ │ │ + }, OpenLayers.Format.Filter.v1.prototype.writers["ogc"]), │ │ │ │ + gml: OpenLayers.Format.GML.v2.prototype.writers["gml"], │ │ │ │ + feature: OpenLayers.Format.GML.v2.prototype.writers["feature"] │ │ │ │ }, │ │ │ │ - updateMatrixProperties: function() { │ │ │ │ - this.matrix = this.getMatrix(); │ │ │ │ - if (this.matrix) { │ │ │ │ - if (this.matrix.topLeftCorner) { │ │ │ │ - this.tileOrigin = this.matrix.topLeftCorner │ │ │ │ - } │ │ │ │ - if (this.matrix.tileWidth && this.matrix.tileHeight) { │ │ │ │ - this.tileSize = new OpenLayers.Size(this.matrix.tileWidth, this.matrix.tileHeight) │ │ │ │ - } │ │ │ │ - if (!this.tileOrigin) { │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat(this.maxExtent.left, this.maxExtent.top) │ │ │ │ + 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 (!this.tileFullExtent) { │ │ │ │ - this.tileFullExtent = this.maxExtent │ │ │ │ + if (filter.projection) { │ │ │ │ + child.setAttribute("srsName", filter.projection) │ │ │ │ } │ │ │ │ + node.appendChild(child) │ │ │ │ } │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - if (zoomChanged || !this.matrix) { │ │ │ │ - this.updateMatrixProperties() │ │ │ │ - } │ │ │ │ - return OpenLayers.Layer.Grid.prototype.moveTo.apply(this, arguments) │ │ │ │ + CLASS_NAME: "OpenLayers.Format.Filter.v1_0_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WFST.v1_0_0 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, OpenLayers.Format.WFST.v1, { │ │ │ │ + version: "1.0.0", │ │ │ │ + srsNameInQuery: false, │ │ │ │ + schemaLocations: { │ │ │ │ + wfs: "http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd" │ │ │ │ }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.WMTS(this.options) │ │ │ │ - } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this, [options]); │ │ │ │ + OpenLayers.Format.WFST.v1.prototype.initialize.apply(this, [options]) │ │ │ │ }, │ │ │ │ - getIdentifier: function() { │ │ │ │ - return this.getServerZoom() │ │ │ │ + readNode: function(node, obj, first) { │ │ │ │ + return OpenLayers.Format.GML.v2.prototype.readNode.apply(this, arguments) │ │ │ │ }, │ │ │ │ - getMatrix: function() { │ │ │ │ - var matrix; │ │ │ │ - if (!this.matrixIds || this.matrixIds.length === 0) { │ │ │ │ - matrix = { │ │ │ │ - identifier: this.getIdentifier() │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if ("scaleDenominator" in this.matrixIds[0]) { │ │ │ │ - var denom = OpenLayers.METERS_PER_INCH * OpenLayers.INCHES_PER_UNIT[this.units] * this.getServerResolution() / 28e-5; │ │ │ │ - var diff = Number.POSITIVE_INFINITY; │ │ │ │ - var delta; │ │ │ │ - for (var i = 0, ii = this.matrixIds.length; i < ii; ++i) { │ │ │ │ - delta = Math.abs(1 - this.matrixIds[i].scaleDenominator / denom); │ │ │ │ - if (delta < diff) { │ │ │ │ - diff = delta; │ │ │ │ - matrix = this.matrixIds[i] │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - matrix = this.matrixIds[this.getIdentifier()] │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - } │ │ │ │ - return matrix │ │ │ │ - }, │ │ │ │ - getTileInfo: function(loc) { │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var fx = (loc.lon - this.tileOrigin.lon) / (res * this.tileSize.w); │ │ │ │ - var fy = (this.tileOrigin.lat - loc.lat) / (res * this.tileSize.h); │ │ │ │ - var col = Math.floor(fx); │ │ │ │ - var row = Math.floor(fy); │ │ │ │ - return { │ │ │ │ - col: col, │ │ │ │ - row: row, │ │ │ │ - i: Math.floor((fx - col) * this.tileSize.w), │ │ │ │ - j: Math.floor((fy - row) * this.tileSize.h) │ │ │ │ - } │ │ │ │ + }, 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"] │ │ │ │ }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var url = ""; │ │ │ │ - if (!this.tileFullExtent || this.tileFullExtent.intersectsBounds(bounds)) { │ │ │ │ - var center = bounds.getCenterLonLat(); │ │ │ │ - var info = this.getTileInfo(center); │ │ │ │ - var matrixId = this.matrix.identifier; │ │ │ │ - var dimensions = this.dimensions, │ │ │ │ - params; │ │ │ │ - if (OpenLayers.Util.isArray(this.url)) { │ │ │ │ - url = this.selectUrl([this.version, this.style, this.matrixSet, this.matrix.identifier, info.row, info.col].join(","), this.url) │ │ │ │ - } else { │ │ │ │ - url = this.url │ │ │ │ - } │ │ │ │ - if (this.requestEncoding.toUpperCase() === "REST") { │ │ │ │ - params = this.params; │ │ │ │ - if (url.indexOf("{") !== -1) { │ │ │ │ - var template = url.replace(/\{/g, "${"); │ │ │ │ - var context = { │ │ │ │ - style: this.style, │ │ │ │ - Style: this.style, │ │ │ │ - TileMatrixSet: this.matrixSet, │ │ │ │ - TileMatrix: this.matrix.identifier, │ │ │ │ - TileRow: info.row, │ │ │ │ - TileCol: info.col │ │ │ │ - }; │ │ │ │ - if (dimensions) { │ │ │ │ - var dimension, i; │ │ │ │ - for (i = dimensions.length - 1; i >= 0; --i) { │ │ │ │ - dimension = dimensions[i]; │ │ │ │ - context[dimension] = params[dimension.toUpperCase()] │ │ │ │ - } │ │ │ │ - } │ │ │ │ - url = OpenLayers.String.format(template, context) │ │ │ │ - } else { │ │ │ │ - var path = this.version + "/" + this.layer + "/" + this.style + "/"; │ │ │ │ - if (dimensions) { │ │ │ │ - for (var i = 0; i < dimensions.length; i++) { │ │ │ │ - if (params[dimensions[i]]) { │ │ │ │ - path = path + params[dimensions[i]] + "/" │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - path = path + this.matrixSet + "/" + this.matrix.identifier + "/" + info.row + "/" + info.col + "." + this.formatSuffix; │ │ │ │ - if (!url.match(/\/$/)) { │ │ │ │ - url = url + "/" │ │ │ │ + }); │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - url = url + path │ │ │ │ } │ │ │ │ - } else if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ - params = { │ │ │ │ - SERVICE: "WMTS", │ │ │ │ - REQUEST: "GetTile", │ │ │ │ - VERSION: this.version, │ │ │ │ - LAYER: this.layer, │ │ │ │ - STYLE: this.style, │ │ │ │ - TILEMATRIXSET: this.matrixSet, │ │ │ │ - TILEMATRIX: this.matrix.identifier, │ │ │ │ - TILEROW: info.row, │ │ │ │ - TILECOL: info.col, │ │ │ │ - FORMAT: this.format │ │ │ │ - }; │ │ │ │ - url = OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this, [params]) │ │ │ │ + if (options.filter) { │ │ │ │ + this.setFilterProperty(options.filter); │ │ │ │ + this.writeNode("ogc:Filter", options.filter, node) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ } │ │ │ │ - } │ │ │ │ - return url │ │ │ │ + }, 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"] │ │ │ │ }, │ │ │ │ - mergeNewParams: function(newParams) { │ │ │ │ - if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ - return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, [OpenLayers.Util.upperCaseObject(newParams)]) │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFST.v1_0_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Protocol.WFS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ + version: "1.0.0", │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.WFS.v1_0_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Protocol.WFS.v1_1_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ + version: "1.1.0", │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Protocol.WFS.v1.prototype.initialize.apply(this, arguments); │ │ │ │ + if (this.outputFormat && !this.readFormat) { │ │ │ │ + if (this.outputFormat.toLowerCase() == "gml2") { │ │ │ │ + this.readFormat = new OpenLayers.Format.GML.v2({ │ │ │ │ + featureType: this.featureType, │ │ │ │ + featureNS: this.featureNS, │ │ │ │ + geometryName: this.geometryName │ │ │ │ + }) │ │ │ │ + } else if (this.outputFormat.toLowerCase() == "json") { │ │ │ │ + this.readFormat = new OpenLayers.Format.GeoJSON │ │ │ │ + } │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.WMTS" │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.WFS.v1_1_0" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - isBaseLayer: true, │ │ │ │ - useHttpTile: false, │ │ │ │ - singleTile: false, │ │ │ │ - useOverlay: false, │ │ │ │ - useAsyncOverlay: true, │ │ │ │ - TILE_PARAMS: { │ │ │ │ - operation: "GETTILEIMAGE", │ │ │ │ - version: "1.2.0" │ │ │ │ - }, │ │ │ │ - SINGLE_TILE_PARAMS: { │ │ │ │ - operation: "GETMAPIMAGE", │ │ │ │ - format: "PNG", │ │ │ │ - locale: "en", │ │ │ │ - clip: "1", │ │ │ │ - version: "1.0.0" │ │ │ │ +OpenLayers.Format.CSWGetRecords = function(options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, OpenLayers.Format.CSWGetRecords.DEFAULTS); │ │ │ │ + var cls = OpenLayers.Format.CSWGetRecords["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (!cls) { │ │ │ │ + throw "Unsupported CSWGetRecords version: " + options.version │ │ │ │ + } │ │ │ │ + return new cls(options) │ │ │ │ +}; │ │ │ │ +OpenLayers.Format.CSWGetRecords.DEFAULTS = { │ │ │ │ + version: "2.0.2" │ │ │ │ +}; │ │ │ │ +OpenLayers.Format.CSWGetRecords.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + namespaces: { │ │ │ │ + csw: "http://www.opengis.net/cat/csw/2.0.2", │ │ │ │ + dc: "http://purl.org/dc/elements/1.1/", │ │ │ │ + dct: "http://purl.org/dc/terms/", │ │ │ │ + gmd: "http://www.isotc211.org/2005/gmd", │ │ │ │ + geonet: "http://www.fao.org/geonetwork", │ │ │ │ + ogc: "http://www.opengis.net/ogc", │ │ │ │ + ows: "http://www.opengis.net/ows", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ }, │ │ │ │ - OVERLAY_PARAMS: { │ │ │ │ - operation: "GETDYNAMICMAPOVERLAYIMAGE", │ │ │ │ - format: "PNG", │ │ │ │ - locale: "en", │ │ │ │ - clip: "1", │ │ │ │ - version: "2.0.0" │ │ │ │ + defaultPrefix: "csw", │ │ │ │ + version: "2.0.2", │ │ │ │ + schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ + requestId: null, │ │ │ │ + resultType: null, │ │ │ │ + outputFormat: null, │ │ │ │ + outputSchema: null, │ │ │ │ + startPosition: null, │ │ │ │ + maxRecords: null, │ │ │ │ + DistributedSearch: null, │ │ │ │ + ResponseHandler: null, │ │ │ │ + Query: null, │ │ │ │ + regExes: { │ │ │ │ + trimSpace: /^\s*|\s*$/g, │ │ │ │ + removeSpace: /\s*/g, │ │ │ │ + splitSpace: /\s+/, │ │ │ │ + trimComma: /\s*,\s*/g │ │ │ │ }, │ │ │ │ - FOLDER_PARAMS: { │ │ │ │ - tileColumnsPerFolder: 30, │ │ │ │ - tileRowsPerFolder: 30, │ │ │ │ - format: "png", │ │ │ │ - querystring: null │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]) │ │ │ │ }, │ │ │ │ - defaultSize: new OpenLayers.Size(300, 300), │ │ │ │ - tileOriginCorner: "tl", │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ - if (options == null || options.isBaseLayer == null) { │ │ │ │ - this.isBaseLayer = this.transparent != "true" && this.transparent != true │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ } │ │ │ │ - if (options && options.useOverlay != null) { │ │ │ │ - this.useOverlay = options.useOverlay │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement │ │ │ │ } │ │ │ │ - if (this.singleTile) { │ │ │ │ - if (this.useOverlay) { │ │ │ │ - OpenLayers.Util.applyDefaults(this.params, this.OVERLAY_PARAMS); │ │ │ │ - if (!this.useAsyncOverlay) { │ │ │ │ - this.params.version = "1.0.0" │ │ │ │ + var obj = {}; │ │ │ │ + this.readNode(data, obj); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + readers: { │ │ │ │ + csw: { │ │ │ │ + GetRecordsResponse: function(node, obj) { │ │ │ │ + obj.records = []; │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + var version = this.getAttributeNS(node, "", "version"); │ │ │ │ + if (version != "") { │ │ │ │ + obj.version = version │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Util.applyDefaults(this.params, this.SINGLE_TILE_PARAMS) │ │ │ │ + }, │ │ │ │ + RequestId: function(node, obj) { │ │ │ │ + obj.RequestId = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + SearchStatus: function(node, obj) { │ │ │ │ + obj.SearchStatus = {}; │ │ │ │ + var timestamp = this.getAttributeNS(node, "", "timestamp"); │ │ │ │ + if (timestamp != "") { │ │ │ │ + obj.SearchStatus.timestamp = timestamp │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + SearchResults: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var SearchResults = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + if (attrs[i].name == "numberOfRecordsMatched" || attrs[i].name == "numberOfRecordsReturned" || attrs[i].name == "nextRecord") { │ │ │ │ + SearchResults[attrs[i].name] = parseInt(attrs[i].nodeValue) │ │ │ │ + } else { │ │ │ │ + SearchResults[attrs[i].name] = attrs[i].nodeValue │ │ │ │ + } │ │ │ │ + } │ │ │ │ + obj.SearchResults = SearchResults │ │ │ │ + }, │ │ │ │ + SummaryRecord: function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "SummaryRecord" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record) │ │ │ │ + }, │ │ │ │ + BriefRecord: function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "BriefRecord" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record) │ │ │ │ + }, │ │ │ │ + DCMIRecord: function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "DCMIRecord" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record) │ │ │ │ + }, │ │ │ │ + Record: function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "Record" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record) │ │ │ │ + }, │ │ │ │ + "*": function(node, obj) { │ │ │ │ + var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ + obj[name] = this.getChildValue(node) │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - if (this.useHttpTile) { │ │ │ │ - OpenLayers.Util.applyDefaults(this.params, this.FOLDER_PARAMS) │ │ │ │ - } else { │ │ │ │ - OpenLayers.Util.applyDefaults(this.params, this.TILE_PARAMS) │ │ │ │ + }, │ │ │ │ + geonet: { │ │ │ │ + info: function(node, obj) { │ │ │ │ + var gninfo = {}; │ │ │ │ + this.readChildNodes(node, gninfo); │ │ │ │ + obj.gninfo = gninfo │ │ │ │ } │ │ │ │ - this.setTileSize(this.defaultSize) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.MapGuide(this.name, this.url, this.params, this.getOptions()) │ │ │ │ - } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ - }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - var url; │ │ │ │ - var center = bounds.getCenterLonLat(); │ │ │ │ - var mapSize = this.map.getSize(); │ │ │ │ - if (this.singleTile) { │ │ │ │ - var params = { │ │ │ │ - setdisplaydpi: OpenLayers.DOTS_PER_INCH, │ │ │ │ - setdisplayheight: mapSize.h * this.ratio, │ │ │ │ - setdisplaywidth: mapSize.w * this.ratio, │ │ │ │ - setviewcenterx: center.lon, │ │ │ │ - setviewcentery: center.lat, │ │ │ │ - setviewscale: this.map.getScale() │ │ │ │ - }; │ │ │ │ - if (this.useOverlay && !this.useAsyncOverlay) { │ │ │ │ - var getVisParams = {}; │ │ │ │ - getVisParams = OpenLayers.Util.extend(getVisParams, params); │ │ │ │ - getVisParams.operation = "GETVISIBLEMAPEXTENT"; │ │ │ │ - getVisParams.version = "1.0.0"; │ │ │ │ - getVisParams.session = this.params.session; │ │ │ │ - getVisParams.mapName = this.params.mapName; │ │ │ │ - getVisParams.format = "text/xml"; │ │ │ │ - url = this.getFullRequestString(getVisParams); │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ - url: url, │ │ │ │ - async: false │ │ │ │ - }) │ │ │ │ + }, │ │ │ │ + dc: { │ │ │ │ + "*": function(node, obj) { │ │ │ │ + var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ + if (!OpenLayers.Util.isArray(obj[name])) { │ │ │ │ + obj[name] = [] │ │ │ │ + } │ │ │ │ + var dc_element = {}; │ │ │ │ + var attrs = node.attributes; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + dc_element[attrs[i].name] = attrs[i].nodeValue │ │ │ │ + } │ │ │ │ + dc_element.value = this.getChildValue(node); │ │ │ │ + if (dc_element.value != "") { │ │ │ │ + obj[name].push(dc_element) │ │ │ │ + } │ │ │ │ } │ │ │ │ - url = this.getFullRequestString(params) │ │ │ │ - } else { │ │ │ │ - var currentRes = this.map.getResolution(); │ │ │ │ - var colidx = Math.floor((bounds.left - this.maxExtent.left) / currentRes); │ │ │ │ - colidx = Math.round(colidx / this.tileSize.w); │ │ │ │ - var rowidx = Math.floor((this.maxExtent.top - bounds.top) / currentRes); │ │ │ │ - rowidx = Math.round(rowidx / this.tileSize.h); │ │ │ │ - if (this.useHttpTile) { │ │ │ │ - url = this.getImageFilePath({ │ │ │ │ - tilecol: colidx, │ │ │ │ - tilerow: rowidx, │ │ │ │ - scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ - }) │ │ │ │ - } else { │ │ │ │ - url = this.getFullRequestString({ │ │ │ │ - tilecol: colidx, │ │ │ │ - tilerow: rowidx, │ │ │ │ - scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ - }) │ │ │ │ + }, │ │ │ │ + dct: { │ │ │ │ + "*": function(node, obj) { │ │ │ │ + var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ + if (!OpenLayers.Util.isArray(obj[name])) { │ │ │ │ + obj[name] = [] │ │ │ │ + } │ │ │ │ + obj[name].push(this.getChildValue(node)) │ │ │ │ } │ │ │ │ - } │ │ │ │ - return url │ │ │ │ - }, │ │ │ │ - getFullRequestString: function(newParams, altUrl) { │ │ │ │ - var url = altUrl == null ? this.url : altUrl; │ │ │ │ - if (typeof url == "object") { │ │ │ │ - url = url[Math.floor(Math.random() * url.length)] │ │ │ │ - } │ │ │ │ - var requestString = url; │ │ │ │ - var allParams = OpenLayers.Util.extend({}, this.params); │ │ │ │ - allParams = OpenLayers.Util.extend(allParams, newParams); │ │ │ │ - var urlParams = OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url)); │ │ │ │ - for (var key in allParams) { │ │ │ │ - if (key.toUpperCase() in urlParams) { │ │ │ │ - delete allParams[key] │ │ │ │ + }, │ │ │ │ + ows: OpenLayers.Util.applyDefaults({ │ │ │ │ + BoundingBox: function(node, obj) { │ │ │ │ + if (obj.bounds) { │ │ │ │ + obj.BoundingBox = [{ │ │ │ │ + crs: obj.projection, │ │ │ │ + value: [obj.bounds.left, obj.bounds.bottom, obj.bounds.right, obj.bounds.top] │ │ │ │ + }]; │ │ │ │ + delete obj.projection; │ │ │ │ + delete obj.bounds │ │ │ │ + } │ │ │ │ + OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]["BoundingBox"].apply(this, arguments) │ │ │ │ } │ │ │ │ - } │ │ │ │ - var paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ - paramsString = paramsString.replace(/,/g, "+"); │ │ │ │ - if (paramsString != "") { │ │ │ │ - var lastServerChar = url.charAt(url.length - 1); │ │ │ │ - if (lastServerChar == "&" || lastServerChar == "?") { │ │ │ │ - requestString += paramsString │ │ │ │ - } else { │ │ │ │ - if (url.indexOf("?") == -1) { │ │ │ │ - requestString += "?" + paramsString │ │ │ │ + }, OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]) │ │ │ │ + }, │ │ │ │ + write: function(options) { │ │ │ │ + var node = this.writeNode("csw:GetRecords", options); │ │ │ │ + node.setAttribute("xmlns:gmd", this.namespaces.gmd); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [node]) │ │ │ │ + }, │ │ │ │ + writers: { │ │ │ │ + csw: { │ │ │ │ + GetRecords: function(options) { │ │ │ │ + if (!options) { │ │ │ │ + options = {} │ │ │ │ + } │ │ │ │ + var node = this.createElementNSPlus("csw:GetRecords", { │ │ │ │ + attributes: { │ │ │ │ + service: "CSW", │ │ │ │ + version: this.version, │ │ │ │ + requestId: options.requestId || this.requestId, │ │ │ │ + resultType: options.resultType || this.resultType, │ │ │ │ + outputFormat: options.outputFormat || this.outputFormat, │ │ │ │ + outputSchema: options.outputSchema || this.outputSchema, │ │ │ │ + startPosition: options.startPosition || this.startPosition, │ │ │ │ + maxRecords: options.maxRecords || this.maxRecords │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (options.DistributedSearch || this.DistributedSearch) { │ │ │ │ + this.writeNode("csw:DistributedSearch", options.DistributedSearch || this.DistributedSearch, node) │ │ │ │ + } │ │ │ │ + var ResponseHandler = options.ResponseHandler || this.ResponseHandler; │ │ │ │ + if (OpenLayers.Util.isArray(ResponseHandler) && ResponseHandler.length > 0) { │ │ │ │ + for (var i = 0, len = ResponseHandler.length; i < len; i++) { │ │ │ │ + this.writeNode("csw:ResponseHandler", ResponseHandler[i], node) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.writeNode("Query", options.Query || this.Query, node); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + DistributedSearch: function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:DistributedSearch", { │ │ │ │ + attributes: { │ │ │ │ + hopCount: options.hopCount │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + ResponseHandler: function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:ResponseHandler", { │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + Query: function(options) { │ │ │ │ + if (!options) { │ │ │ │ + options = {} │ │ │ │ + } │ │ │ │ + var node = this.createElementNSPlus("csw:Query", { │ │ │ │ + attributes: { │ │ │ │ + typeNames: options.typeNames || "csw:Record" │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + var ElementName = options.ElementName; │ │ │ │ + if (OpenLayers.Util.isArray(ElementName) && ElementName.length > 0) { │ │ │ │ + for (var i = 0, len = ElementName.length; i < len; i++) { │ │ │ │ + this.writeNode("csw:ElementName", ElementName[i], node) │ │ │ │ + } │ │ │ │ } else { │ │ │ │ - requestString += "&" + paramsString │ │ │ │ + this.writeNode("csw:ElementSetName", options.ElementSetName || { │ │ │ │ + value: "summary" │ │ │ │ + }, node) │ │ │ │ + } │ │ │ │ + if (options.Constraint) { │ │ │ │ + this.writeNode("csw:Constraint", options.Constraint, node) │ │ │ │ + } │ │ │ │ + if (options.SortBy) { │ │ │ │ + this.writeNode("ogc:SortBy", options.SortBy, node) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + ElementName: function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:ElementName", { │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + ElementSetName: function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:ElementSetName", { │ │ │ │ + attributes: { │ │ │ │ + typeNames: options.typeNames │ │ │ │ + }, │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + Constraint: function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:Constraint", { │ │ │ │ + attributes: { │ │ │ │ + version: options.version │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (options.Filter) { │ │ │ │ + var format = new OpenLayers.Format.Filter({ │ │ │ │ + version: options.version │ │ │ │ + }); │ │ │ │ + node.appendChild(format.write(options.Filter)) │ │ │ │ + } else if (options.CqlText) { │ │ │ │ + var child = this.createElementNSPlus("CqlText", { │ │ │ │ + value: options.CqlText.value │ │ │ │ + }); │ │ │ │ + node.appendChild(child) │ │ │ │ } │ │ │ │ + return node │ │ │ │ } │ │ │ │ - } │ │ │ │ - return requestString │ │ │ │ + }, │ │ │ │ + ogc: OpenLayers.Format.Filter.v1_1_0.prototype.writers["ogc"] │ │ │ │ }, │ │ │ │ - getImageFilePath: function(newParams, altUrl) { │ │ │ │ - var url = altUrl == null ? this.url : altUrl; │ │ │ │ - if (typeof url == "object") { │ │ │ │ - url = url[Math.floor(Math.random() * url.length)] │ │ │ │ - } │ │ │ │ - var requestString = url; │ │ │ │ - var tileRowGroup = ""; │ │ │ │ - var tileColGroup = ""; │ │ │ │ - if (newParams.tilerow < 0) { │ │ │ │ - tileRowGroup = "-" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.CSWGetRecords.v2_0_2" │ │ │ │ +}); │ │ │ │ +OpenLayers.Protocol.CSW.v2_0_2 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ + formatOptions: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ + if (!options.format) { │ │ │ │ + this.format = new OpenLayers.Format.CSWGetRecords.v2_0_2(OpenLayers.Util.extend({}, this.formatOptions)) │ │ │ │ } │ │ │ │ - if (newParams.tilerow == 0) { │ │ │ │ - tileRowGroup += "0" │ │ │ │ - } else { │ │ │ │ - tileRowGroup += Math.floor(Math.abs(newParams.tilerow / this.params.tileRowsPerFolder)) * this.params.tileRowsPerFolder │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.options && !this.options.format) { │ │ │ │ + this.format.destroy() │ │ │ │ } │ │ │ │ - if (newParams.tilecol < 0) { │ │ │ │ - tileColGroup = "-" │ │ │ │ + this.format = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ + }, │ │ │ │ + read: function(options) { │ │ │ │ + options = OpenLayers.Util.extend({}, options); │ │ │ │ + OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ + var response = new OpenLayers.Protocol.Response({ │ │ │ │ + requestType: "read" │ │ │ │ + }); │ │ │ │ + var data = this.format.write(options.params || 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 │ │ │ │ + }, │ │ │ │ + handleRead: function(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + var request = response.priv; │ │ │ │ + if (request.status >= 200 && request.status < 300) { │ │ │ │ + response.data = this.parseData(request); │ │ │ │ + response.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ + } else { │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ + } │ │ │ │ + options.callback.call(options.scope, response) │ │ │ │ } │ │ │ │ - if (newParams.tilecol == 0) { │ │ │ │ - tileColGroup += "0" │ │ │ │ - } else { │ │ │ │ - tileColGroup += Math.floor(Math.abs(newParams.tilecol / this.params.tileColumnsPerFolder)) * this.params.tileColumnsPerFolder │ │ │ │ + }, │ │ │ │ + parseData: function(request) { │ │ │ │ + var doc = request.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = request.responseText │ │ │ │ } │ │ │ │ - var tilePath = "/S" + Math.floor(newParams.scaleindex) + "/" + this.params.basemaplayergroupname + "/R" + tileRowGroup + "/C" + tileColGroup + "/" + newParams.tilerow % this.params.tileRowsPerFolder + "_" + newParams.tilecol % this.params.tileColumnsPerFolder + "." + this.params.format; │ │ │ │ - if (this.params.querystring) { │ │ │ │ - tilePath += "?" + this.params.querystring │ │ │ │ + if (!doc || doc.length <= 0) { │ │ │ │ + return null │ │ │ │ } │ │ │ │ - requestString += tilePath; │ │ │ │ - return requestString │ │ │ │ + return this.format.read(doc) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.MapGuide" │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.CSW.v2_0_2" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ - displayInLayerSwitcher: false, │ │ │ │ - layers: null, │ │ │ │ - display: function() {}, │ │ │ │ - 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 │ │ │ │ +OpenLayers.Control.ScaleLine = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + maxWidth: 100, │ │ │ │ + topOutUnits: "km", │ │ │ │ + topInUnits: "m", │ │ │ │ + bottomOutUnits: "mi", │ │ │ │ + bottomInUnits: "ft", │ │ │ │ + eTop: null, │ │ │ │ + eBottom: null, │ │ │ │ + geodesic: false, │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (!this.eTop) { │ │ │ │ + this.eTop = document.createElement("div"); │ │ │ │ + this.eTop.className = this.displayClass + "Top"; │ │ │ │ + var theLen = this.topInUnits.length; │ │ │ │ + this.div.appendChild(this.eTop); │ │ │ │ + if (this.topOutUnits == "" || this.topInUnits == "") { │ │ │ │ + this.eTop.style.visibility = "hidden" │ │ │ │ + } else { │ │ │ │ + this.eTop.style.visibility = "visible" │ │ │ │ } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ - this.collectRoots(); │ │ │ │ - map.events.register("changelayer", this, this.handleChangeLayer) │ │ │ │ - }, │ │ │ │ - removeMap: function(map) { │ │ │ │ - map.events.unregister("changelayer", this, this.handleChangeLayer); │ │ │ │ - this.resetRoots(); │ │ │ │ - OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - collectRoots: function() { │ │ │ │ - var layer; │ │ │ │ - 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) │ │ │ │ + this.eBottom = document.createElement("div"); │ │ │ │ + this.eBottom.className = this.displayClass + "Bottom"; │ │ │ │ + this.div.appendChild(this.eBottom); │ │ │ │ + if (this.bottomOutUnits == "" || this.bottomInUnits == "") { │ │ │ │ + this.eBottom.style.visibility = "hidden" │ │ │ │ + } else { │ │ │ │ + this.eBottom.style.visibility = "visible" │ │ │ │ } │ │ │ │ } │ │ │ │ + this.map.events.register("moveend", this, this.update); │ │ │ │ + this.update(); │ │ │ │ + return this.div │ │ │ │ }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ + getBarLen: function(maxLen) { │ │ │ │ + var digits = parseInt(Math.log(maxLen) / Math.log(10)); │ │ │ │ + var pow10 = Math.pow(10, digits); │ │ │ │ + var firstChar = parseInt(maxLen / pow10); │ │ │ │ + var barLen; │ │ │ │ + if (firstChar > 5) { │ │ │ │ + barLen = 5 │ │ │ │ + } else if (firstChar > 2) { │ │ │ │ + barLen = 2 │ │ │ │ + } else { │ │ │ │ + barLen = 1 │ │ │ │ } │ │ │ │ + return barLen * pow10 │ │ │ │ }, │ │ │ │ - handleChangeLayer: function(evt) { │ │ │ │ - var layer = evt.layer; │ │ │ │ - if (evt.property == "order" && OpenLayers.Util.indexOf(this.layers, layer) != -1) { │ │ │ │ - this.resetRoots(); │ │ │ │ - this.collectRoots() │ │ │ │ + update: function() { │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ + if (!res) { │ │ │ │ + return │ │ │ │ } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Vector.RootContainer" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.Google.v3 = { │ │ │ │ - DEFAULTS: { │ │ │ │ - sphericalMercator: true, │ │ │ │ - projection: "EPSG:900913" │ │ │ │ - }, │ │ │ │ - animationEnabled: true, │ │ │ │ - loadMapObject: function() { │ │ │ │ - if (!this.type) { │ │ │ │ - this.type = google.maps.MapTypeId.ROADMAP │ │ │ │ + var curMapUnits = this.map.getUnits(); │ │ │ │ + var inches = OpenLayers.INCHES_PER_UNIT; │ │ │ │ + var maxSizeData = this.maxWidth * res * inches[curMapUnits]; │ │ │ │ + var geodesicRatio = 1; │ │ │ │ + if (this.geodesic === true) { │ │ │ │ + var maxSizeGeodesic = (this.map.getGeodesicPixelSize().w || 1e-6) * this.maxWidth; │ │ │ │ + var maxSizeKilometers = maxSizeData / inches["km"]; │ │ │ │ + geodesicRatio = maxSizeGeodesic / maxSizeKilometers; │ │ │ │ + maxSizeData *= geodesicRatio │ │ │ │ } │ │ │ │ - var mapObject; │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - mapObject = cache.mapObject; │ │ │ │ - ++cache.count │ │ │ │ + var topUnits; │ │ │ │ + var bottomUnits; │ │ │ │ + if (maxSizeData > 1e5) { │ │ │ │ + topUnits = this.topOutUnits; │ │ │ │ + bottomUnits = this.bottomOutUnits │ │ │ │ } else { │ │ │ │ - var center = this.map.getCenter(); │ │ │ │ - var container = document.createElement("div"); │ │ │ │ - container.className = "olForeignContainer"; │ │ │ │ - container.style.width = "100%"; │ │ │ │ - container.style.height = "100%"; │ │ │ │ - mapObject = new google.maps.Map(container, { │ │ │ │ - center: center ? new google.maps.LatLng(center.lat, center.lon) : new google.maps.LatLng(0, 0), │ │ │ │ - zoom: this.map.getZoom() || 0, │ │ │ │ - mapTypeId: this.type, │ │ │ │ - disableDefaultUI: true, │ │ │ │ - keyboardShortcuts: false, │ │ │ │ - draggable: false, │ │ │ │ - disableDoubleClickZoom: true, │ │ │ │ - scrollwheel: false, │ │ │ │ - streetViewControl: false │ │ │ │ - }); │ │ │ │ - var googleControl = document.createElement("div"); │ │ │ │ - googleControl.style.width = "100%"; │ │ │ │ - googleControl.style.height = "100%"; │ │ │ │ - mapObject.controls[google.maps.ControlPosition.TOP_LEFT].push(googleControl); │ │ │ │ - cache = { │ │ │ │ - googleControl: googleControl, │ │ │ │ - mapObject: mapObject, │ │ │ │ - count: 1 │ │ │ │ - }; │ │ │ │ - OpenLayers.Layer.Google.cache[this.map.id] = cache │ │ │ │ + topUnits = this.topInUnits; │ │ │ │ + bottomUnits = this.bottomInUnits │ │ │ │ } │ │ │ │ - this.mapObject = mapObject; │ │ │ │ - this.setGMapVisibility(this.visibility) │ │ │ │ - }, │ │ │ │ - onMapResize: function() { │ │ │ │ - if (this.visibility) { │ │ │ │ - google.maps.event.trigger(this.mapObject, "resize") │ │ │ │ + var topMax = maxSizeData / inches[topUnits]; │ │ │ │ + var bottomMax = maxSizeData / inches[bottomUnits]; │ │ │ │ + var topRounded = this.getBarLen(topMax); │ │ │ │ + var bottomRounded = this.getBarLen(bottomMax); │ │ │ │ + topMax = topRounded / inches[curMapUnits] * inches[topUnits]; │ │ │ │ + bottomMax = bottomRounded / inches[curMapUnits] * inches[bottomUnits]; │ │ │ │ + var topPx = topMax / res / geodesicRatio; │ │ │ │ + var bottomPx = bottomMax / res / geodesicRatio; │ │ │ │ + if (this.eBottom.style.visibility == "visible") { │ │ │ │ + this.eBottom.style.width = Math.round(bottomPx) + "px"; │ │ │ │ + this.eBottom.innerHTML = bottomRounded + " " + bottomUnits │ │ │ │ + } │ │ │ │ + if (this.eTop.style.visibility == "visible") { │ │ │ │ + this.eTop.style.width = Math.round(topPx) + "px"; │ │ │ │ + this.eTop.innerHTML = topRounded + " " + topUnits │ │ │ │ } │ │ │ │ }, │ │ │ │ - setGMapVisibility: function(visible) { │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - var map = this.map; │ │ │ │ - if (cache) { │ │ │ │ - var type = this.type; │ │ │ │ - var layers = map.layers; │ │ │ │ - var layer; │ │ │ │ - for (var i = layers.length - 1; i >= 0; --i) { │ │ │ │ - layer = layers[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.Google && layer.visibility === true && layer.inRange === true) { │ │ │ │ - type = layer.type; │ │ │ │ - visible = true; │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var container = this.mapObject.getDiv(); │ │ │ │ - if (visible === true) { │ │ │ │ - if (container.parentNode !== map.div) { │ │ │ │ - if (!cache.rendered) { │ │ │ │ - var me = this; │ │ │ │ - google.maps.event.addListenerOnce(this.mapObject, "tilesloaded", function() { │ │ │ │ - cache.rendered = true; │ │ │ │ - me.setGMapVisibility(me.getVisibility()); │ │ │ │ - me.moveTo(me.map.getCenter()) │ │ │ │ - }) │ │ │ │ - } else { │ │ │ │ - map.div.appendChild(container); │ │ │ │ - cache.googleControl.appendChild(map.viewPortDiv); │ │ │ │ - google.maps.event.trigger(this.mapObject, "resize") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.mapObject.setMapTypeId(type) │ │ │ │ - } else if (cache.googleControl.hasChildNodes()) { │ │ │ │ - map.div.appendChild(map.viewPortDiv); │ │ │ │ - map.div.removeChild(container) │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ScaleLine" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ + panned: false, │ │ │ │ + interval: 0, │ │ │ │ + documentDrag: false, │ │ │ │ + kinetic: null, │ │ │ │ + enableKinetic: true, │ │ │ │ + kineticInterval: 10, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - getMapContainer: function() { │ │ │ │ - return this.mapObject.getDiv() │ │ │ │ - }, │ │ │ │ - getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ - var moBounds = null; │ │ │ │ - if (olBounds != null) { │ │ │ │ - var sw = this.sphericalMercator ? this.inverseMercator(olBounds.bottom, olBounds.left) : new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ - var ne = this.sphericalMercator ? this.inverseMercator(olBounds.top, olBounds.right) : new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ - moBounds = new google.maps.LatLngBounds(new google.maps.LatLng(sw.lat, sw.lon), new google.maps.LatLng(ne.lat, ne.lon)) │ │ │ │ + panMapStart: function() { │ │ │ │ + if (this.kinetic) { │ │ │ │ + this.kinetic.begin() │ │ │ │ } │ │ │ │ - return moBounds │ │ │ │ }, │ │ │ │ - getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ - var size = this.map.getSize(); │ │ │ │ - var lon = this.getLongitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ - var lat = this.getLatitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - var delta_x = moPixel.x - size.w / 2; │ │ │ │ - var delta_y = moPixel.y - size.h / 2; │ │ │ │ - var lonlat = new OpenLayers.LonLat(lon + delta_x * res, lat - delta_y * res); │ │ │ │ - if (this.wrapDateLine) { │ │ │ │ - lonlat = lonlat.wrapDateLine(this.maxExtent) │ │ │ │ + panMap: function(xy) { │ │ │ │ + if (this.kinetic) { │ │ │ │ + this.kinetic.update(xy) │ │ │ │ } │ │ │ │ - return this.getMapObjectLonLatFromLonLat(lonlat.lon, lonlat.lat) │ │ │ │ - }, │ │ │ │ - getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); │ │ │ │ - var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - var extent = this.map.getExtent(); │ │ │ │ - return this.getMapObjectPixelFromXY(1 / res * (lon - extent.left), 1 / res * (extent.top - lat)) │ │ │ │ + this.panned = true; │ │ │ │ + this.map.pan(this.handler.last.x - xy.x, this.handler.last.y - xy.y, { │ │ │ │ + dragging: true, │ │ │ │ + animate: false │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - setMapObjectCenter: function(center, zoom) { │ │ │ │ - if (this.animationEnabled === false && zoom != this.mapObject.zoom) { │ │ │ │ - var mapContainer = this.getMapContainer(); │ │ │ │ - google.maps.event.addListenerOnce(this.mapObject, "idle", function() { │ │ │ │ - mapContainer.style.visibility = "" │ │ │ │ + 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 │ │ │ │ }); │ │ │ │ - mapContainer.style.visibility = "hidden" │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - this.mapObject.setOptions({ │ │ │ │ - center: center, │ │ │ │ - zoom: zoom │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ - return this.mapObject.getBoundsZoomLevel(moBounds) │ │ │ │ }, │ │ │ │ - getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ - var gLatLng; │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - var lonlat = this.inverseMercator(lon, lat); │ │ │ │ - gLatLng = new google.maps.LatLng(lonlat.lat, lonlat.lon) │ │ │ │ - } else { │ │ │ │ - gLatLng = new google.maps.LatLng(lat, lon) │ │ │ │ + CLASS_NAME: "OpenLayers.Control.DragPan" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Button = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + type: OpenLayers.Control.TYPE_BUTTON, │ │ │ │ + trigger: function() {}, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Button" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.ZoomIn = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ + trigger: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.zoomIn() │ │ │ │ } │ │ │ │ - return gLatLng │ │ │ │ }, │ │ │ │ - getMapObjectPixelFromXY: function(x, y) { │ │ │ │ - return new google.maps.Point(x, y) │ │ │ │ - } │ │ │ │ -}; │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomIn" │ │ │ │ +}); │ │ │ │ OpenLayers.Events.buttonclick = OpenLayers.Class({ │ │ │ │ target: null, │ │ │ │ events: ["mousedown", "mouseup", "click", "dblclick", "touchstart", "touchmove", "touchend", "keydown"], │ │ │ │ startRegEx: /^mousedown|touchstart$/, │ │ │ │ cancelRegEx: /^touchmove$/, │ │ │ │ completeRegEx: /^mouseup|touchend$/, │ │ │ │ initialize: function(target) { │ │ │ │ @@ -18736,2013 +24303,330 @@ │ │ │ │ return this.getControlsBy("name", match) │ │ │ │ }, │ │ │ │ getControlsByClass: function(match) { │ │ │ │ return this.getControlsBy("CLASS_NAME", match) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.Panel" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.Snapping = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - DEFAULTS: { │ │ │ │ - tolerance: 10, │ │ │ │ - node: true, │ │ │ │ - edge: true, │ │ │ │ - vertex: true │ │ │ │ - }, │ │ │ │ - greedy: true, │ │ │ │ - precedence: ["node", "vertex", "edge"], │ │ │ │ - resolution: null, │ │ │ │ - geoToleranceCache: null, │ │ │ │ - layer: null, │ │ │ │ - feature: null, │ │ │ │ - point: null, │ │ │ │ +OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + slideFactor: 50, │ │ │ │ + slideRatio: null, │ │ │ │ + buttons: null, │ │ │ │ + position: null, │ │ │ │ initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.options = options || {}; │ │ │ │ - if (this.options.layer) { │ │ │ │ - this.setLayer(this.options.layer) │ │ │ │ - } │ │ │ │ - var defaults = OpenLayers.Util.extend({}, this.options.defaults); │ │ │ │ - this.defaults = OpenLayers.Util.applyDefaults(defaults, this.DEFAULTS); │ │ │ │ - this.setTargets(this.options.targets); │ │ │ │ - if (this.targets.length === 0 && this.layer) { │ │ │ │ - this.addTargetLayer(this.layer) │ │ │ │ - } │ │ │ │ - this.geoToleranceCache = {} │ │ │ │ - }, │ │ │ │ - setLayer: function(layer) { │ │ │ │ - if (this.active) { │ │ │ │ - this.deactivate(); │ │ │ │ - this.layer = layer; │ │ │ │ - this.activate() │ │ │ │ - } else { │ │ │ │ - this.layer = layer │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setTargets: function(targets) { │ │ │ │ - this.targets = []; │ │ │ │ - if (targets && targets.length) { │ │ │ │ - var target; │ │ │ │ - for (var i = 0, len = targets.length; i < len; ++i) { │ │ │ │ - target = targets[i]; │ │ │ │ - if (target instanceof OpenLayers.Layer.Vector) { │ │ │ │ - this.addTargetLayer(target) │ │ │ │ - } else { │ │ │ │ - this.addTarget(target) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - addTargetLayer: function(layer) { │ │ │ │ - this.addTarget({ │ │ │ │ - layer: layer │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - addTarget: function(target) { │ │ │ │ - target = OpenLayers.Util.applyDefaults(target, this.defaults); │ │ │ │ - target.nodeTolerance = target.nodeTolerance || target.tolerance; │ │ │ │ - target.vertexTolerance = target.vertexTolerance || target.tolerance; │ │ │ │ - target.edgeTolerance = target.edgeTolerance || target.tolerance; │ │ │ │ - this.targets.push(target) │ │ │ │ - }, │ │ │ │ - removeTargetLayer: function(layer) { │ │ │ │ - var target; │ │ │ │ - for (var i = this.targets.length - 1; i >= 0; --i) { │ │ │ │ - target = this.targets[i]; │ │ │ │ - if (target.layer === layer) { │ │ │ │ - this.removeTarget(target) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - removeTarget: function(target) { │ │ │ │ - return OpenLayers.Util.removeItem(this.targets, target) │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - if (this.layer && this.layer.events) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - sketchstarted: this.onSketchModified, │ │ │ │ - sketchmodified: this.onSketchModified, │ │ │ │ - vertexmodified: this.onVertexModified, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - if (this.layer && this.layer.events) { │ │ │ │ - this.layer.events.un({ │ │ │ │ - sketchstarted: this.onSketchModified, │ │ │ │ - sketchmodified: this.onSketchModified, │ │ │ │ - vertexmodified: this.onVertexModified, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.feature = null; │ │ │ │ - this.point = null; │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - onSketchModified: function(event) { │ │ │ │ - this.feature = event.feature; │ │ │ │ - this.considerSnapping(event.vertex, event.vertex) │ │ │ │ - }, │ │ │ │ - onVertexModified: function(event) { │ │ │ │ - this.feature = event.feature; │ │ │ │ - var loc = this.layer.map.getLonLatFromViewPortPx(event.pixel); │ │ │ │ - this.considerSnapping(event.vertex, new OpenLayers.Geometry.Point(loc.lon, loc.lat)) │ │ │ │ - }, │ │ │ │ - considerSnapping: function(point, loc) { │ │ │ │ - var best = { │ │ │ │ - rank: Number.POSITIVE_INFINITY, │ │ │ │ - dist: Number.POSITIVE_INFINITY, │ │ │ │ - x: null, │ │ │ │ - y: null │ │ │ │ - }; │ │ │ │ - var snapped = false; │ │ │ │ - var result, target; │ │ │ │ - for (var i = 0, len = this.targets.length; i < len; ++i) { │ │ │ │ - target = this.targets[i]; │ │ │ │ - result = this.testTarget(target, loc); │ │ │ │ - if (result) { │ │ │ │ - if (this.greedy) { │ │ │ │ - best = result; │ │ │ │ - best.target = target; │ │ │ │ - snapped = true; │ │ │ │ - break │ │ │ │ - } else { │ │ │ │ - if (result.rank < best.rank || result.rank === best.rank && result.dist < best.dist) { │ │ │ │ - best = result; │ │ │ │ - best.target = target; │ │ │ │ - snapped = true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (snapped) { │ │ │ │ - var proceed = this.events.triggerEvent("beforesnap", { │ │ │ │ - point: point, │ │ │ │ - x: best.x, │ │ │ │ - y: best.y, │ │ │ │ - distance: best.dist, │ │ │ │ - layer: best.target.layer, │ │ │ │ - snapType: this.precedence[best.rank] │ │ │ │ - }); │ │ │ │ - if (proceed !== false) { │ │ │ │ - point.x = best.x; │ │ │ │ - point.y = best.y; │ │ │ │ - this.point = point; │ │ │ │ - this.events.triggerEvent("snap", { │ │ │ │ - point: point, │ │ │ │ - snapType: this.precedence[best.rank], │ │ │ │ - layer: best.target.layer, │ │ │ │ - distance: best.dist │ │ │ │ - }) │ │ │ │ - } else { │ │ │ │ - snapped = false │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.point && !snapped) { │ │ │ │ - point.x = loc.x; │ │ │ │ - point.y = loc.y; │ │ │ │ - this.point = null; │ │ │ │ - this.events.triggerEvent("unsnap", { │ │ │ │ - point: point │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - testTarget: function(target, loc) { │ │ │ │ - var resolution = this.layer.map.getResolution(); │ │ │ │ - if ("minResolution" in target) { │ │ │ │ - if (resolution < target.minResolution) { │ │ │ │ - return null │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if ("maxResolution" in target) { │ │ │ │ - if (resolution >= target.maxResolution) { │ │ │ │ - return null │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var tolerance = { │ │ │ │ - node: this.getGeoTolerance(target.nodeTolerance, resolution), │ │ │ │ - vertex: this.getGeoTolerance(target.vertexTolerance, resolution), │ │ │ │ - edge: this.getGeoTolerance(target.edgeTolerance, resolution) │ │ │ │ - }; │ │ │ │ - var maxTolerance = Math.max(tolerance.node, tolerance.vertex, tolerance.edge); │ │ │ │ - var result = { │ │ │ │ - rank: Number.POSITIVE_INFINITY, │ │ │ │ - dist: Number.POSITIVE_INFINITY │ │ │ │ - }; │ │ │ │ - var eligible = false; │ │ │ │ - var features = target.layer.features; │ │ │ │ - var feature, type, vertices, vertex, closest, dist, found; │ │ │ │ - var numTypes = this.precedence.length; │ │ │ │ - var ll = new OpenLayers.LonLat(loc.x, loc.y); │ │ │ │ - for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - if (feature !== this.feature && !feature._sketch && feature.state !== OpenLayers.State.DELETE && (!target.filter || target.filter.evaluate(feature))) { │ │ │ │ - if (feature.atPoint(ll, maxTolerance, maxTolerance)) { │ │ │ │ - for (var j = 0, stop = Math.min(result.rank + 1, numTypes); j < stop; ++j) { │ │ │ │ - type = this.precedence[j]; │ │ │ │ - if (target[type]) { │ │ │ │ - if (type === "edge") { │ │ │ │ - closest = feature.geometry.distanceTo(loc, { │ │ │ │ - details: true │ │ │ │ - }); │ │ │ │ - dist = closest.distance; │ │ │ │ - if (dist <= tolerance[type] && dist < result.dist) { │ │ │ │ - result = { │ │ │ │ - rank: j, │ │ │ │ - dist: dist, │ │ │ │ - x: closest.x0, │ │ │ │ - y: closest.y0 │ │ │ │ - }; │ │ │ │ - eligible = true; │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - vertices = feature.geometry.getVertices(type === "node"); │ │ │ │ - found = false; │ │ │ │ - for (var k = 0, klen = vertices.length; k < klen; ++k) { │ │ │ │ - vertex = vertices[k]; │ │ │ │ - dist = vertex.distanceTo(loc); │ │ │ │ - if (dist <= tolerance[type] && (j < result.rank || j === result.rank && dist < result.dist)) { │ │ │ │ - result = { │ │ │ │ - rank: j, │ │ │ │ - dist: dist, │ │ │ │ - x: vertex.x, │ │ │ │ - y: vertex.y │ │ │ │ - }; │ │ │ │ - eligible = true; │ │ │ │ - found = true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (found) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return eligible ? result : null │ │ │ │ - }, │ │ │ │ - getGeoTolerance: function(tolerance, resolution) { │ │ │ │ - if (resolution !== this.resolution) { │ │ │ │ - this.resolution = resolution; │ │ │ │ - this.geoToleranceCache = {} │ │ │ │ - } │ │ │ │ - var geoTolerance = this.geoToleranceCache[tolerance]; │ │ │ │ - if (geoTolerance === undefined) { │ │ │ │ - geoTolerance = tolerance * resolution; │ │ │ │ - this.geoToleranceCache[tolerance] = geoTolerance │ │ │ │ - } │ │ │ │ - return geoTolerance │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.active) { │ │ │ │ - this.deactivate() │ │ │ │ - } │ │ │ │ - delete this.layer; │ │ │ │ - delete this.targets; │ │ │ │ - OpenLayers.Control.prototype.destroy.call(this) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Snapping" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - layers: null, │ │ │ │ - imageFormat: "image/png", │ │ │ │ - quotaRegEx: /quota/i, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - var i, layers = this.layers || map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.addLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - if (!this.layers) { │ │ │ │ - map.events.on({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - addLayer: function(evt) { │ │ │ │ - evt.layer.events.on({ │ │ │ │ - tileloadstart: this.makeSameOrigin, │ │ │ │ - tileloaded: this.onTileLoaded, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - removeLayer: function(evt) { │ │ │ │ - evt.layer.events.un({ │ │ │ │ - tileloadstart: this.makeSameOrigin, │ │ │ │ - tileloaded: this.onTileLoaded, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - makeSameOrigin: function(evt) { │ │ │ │ - if (this.active) { │ │ │ │ - var tile = evt.tile; │ │ │ │ - if (tile instanceof OpenLayers.Tile.Image && !tile.crossOriginKeyword && tile.url.substr(0, 5) !== "data:") { │ │ │ │ - var sameOriginUrl = OpenLayers.Request.makeSameOrigin(tile.url, OpenLayers.ProxyHost); │ │ │ │ - OpenLayers.Control.CacheWrite.urlMap[sameOriginUrl] = tile.url; │ │ │ │ - tile.url = sameOriginUrl │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - onTileLoaded: function(evt) { │ │ │ │ - if (this.active && !evt.aborted && evt.tile instanceof OpenLayers.Tile.Image && evt.tile.url.substr(0, 5) !== "data:") { │ │ │ │ - this.cache({ │ │ │ │ - tile: evt.tile │ │ │ │ - }); │ │ │ │ - delete OpenLayers.Control.CacheWrite.urlMap[evt.tile.url] │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - cache: function(obj) { │ │ │ │ - if (window.localStorage) { │ │ │ │ - var tile = obj.tile; │ │ │ │ - try { │ │ │ │ - var canvasContext = tile.getCanvasContext(); │ │ │ │ - if (canvasContext) { │ │ │ │ - var urlMap = OpenLayers.Control.CacheWrite.urlMap; │ │ │ │ - var url = urlMap[tile.url] || tile.url; │ │ │ │ - window.localStorage.setItem("olCache_" + url, canvasContext.canvas.toDataURL(this.imageFormat)) │ │ │ │ - } │ │ │ │ - } catch (e) { │ │ │ │ - var reason = e.name || e.message; │ │ │ │ - if (reason && this.quotaRegEx.test(reason)) { │ │ │ │ - this.events.triggerEvent("cachefull", { │ │ │ │ - tile: tile │ │ │ │ - }) │ │ │ │ - } else { │ │ │ │ - OpenLayers.Console.error(e.toString()) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X, OpenLayers.Control.PanZoom.Y); │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments) │ │ │ │ }, │ │ │ │ destroy: function() { │ │ │ │ - if (this.layers || this.map) { │ │ │ │ - var i, layers = this.layers || this.map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.removeLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ if (this.map) { │ │ │ │ - this.map.events.un({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ + this.map.events.unregister("buttonclick", this, this.onButtonClick) │ │ │ │ } │ │ │ │ + this.removeButtons(); │ │ │ │ + this.buttons = null; │ │ │ │ + this.position = null; │ │ │ │ OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.CacheWrite" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.CacheWrite.clearCache = function() { │ │ │ │ - if (!window.localStorage) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - var i, key; │ │ │ │ - for (i = window.localStorage.length - 1; i >= 0; --i) { │ │ │ │ - key = window.localStorage.key(i); │ │ │ │ - if (key.substr(0, 8) === "olCache_") { │ │ │ │ - window.localStorage.removeItem(key) │ │ │ │ - } │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -OpenLayers.Control.CacheWrite.urlMap = {}; │ │ │ │ -OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - started: false, │ │ │ │ - stopDown: true, │ │ │ │ - dragging: false, │ │ │ │ - last: null, │ │ │ │ - start: null, │ │ │ │ - lastMoveEvt: null, │ │ │ │ - oldOnselectstart: null, │ │ │ │ - interval: 0, │ │ │ │ - timeoutId: null, │ │ │ │ - documentDrag: false, │ │ │ │ - documentEvents: null, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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]); │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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); │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - down: function(evt) {}, │ │ │ │ - move: function(evt) {}, │ │ │ │ - up: function(evt) {}, │ │ │ │ - out: function(evt) {}, │ │ │ │ - mousedown: function(evt) { │ │ │ │ - return this.dragstart(evt) │ │ │ │ - }, │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - return this.dragstart(evt) │ │ │ │ - }, │ │ │ │ - mousemove: function(evt) { │ │ │ │ - return this.dragmove(evt) │ │ │ │ - }, │ │ │ │ - touchmove: function(evt) { │ │ │ │ - return this.dragmove(evt) │ │ │ │ - }, │ │ │ │ - removeTimeout: function() { │ │ │ │ - this.timeoutId = null; │ │ │ │ - if (this.dragging) { │ │ │ │ - this.mousemove(this.lastMoveEvt) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - mouseup: function(evt) { │ │ │ │ - return this.dragend(evt) │ │ │ │ - }, │ │ │ │ - touchend: function(evt) { │ │ │ │ - evt.xy = this.last; │ │ │ │ - return this.dragend(evt) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - click: function(evt) { │ │ │ │ - return this.start == this.last │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.dragging = false; │ │ │ │ - activated = true │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - adjustXY: function(evt) { │ │ │ │ - var pos = OpenLayers.Util.pagePosition(this.map.viewPortDiv); │ │ │ │ - evt.xy.x -= pos[0]; │ │ │ │ - evt.xy.y -= pos[1] │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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.Feature = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - 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" │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - feature: null, │ │ │ │ - lastFeature: null, │ │ │ │ - down: null, │ │ │ │ - up: null, │ │ │ │ - clickTolerance: 4, │ │ │ │ - geometryTypes: null, │ │ │ │ - stopClick: true, │ │ │ │ - stopDown: true, │ │ │ │ - stopUp: false, │ │ │ │ - initialize: function(control, layer, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ - this.layer = layer │ │ │ │ - }, │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - return OpenLayers.Event.isMultiTouch(evt) ? true : this.mousedown(evt) │ │ │ │ - }, │ │ │ │ - touchmove: function(evt) { │ │ │ │ - OpenLayers.Event.preventDefault(evt) │ │ │ │ - }, │ │ │ │ - mousedown: function(evt) { │ │ │ │ - if (OpenLayers.Event.isLeftClick(evt) || OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ - this.down = evt.xy │ │ │ │ - } │ │ │ │ - return this.handle(evt) ? !this.stopDown : true │ │ │ │ - }, │ │ │ │ - mouseup: function(evt) { │ │ │ │ - this.up = evt.xy; │ │ │ │ - return this.handle(evt) ? !this.stopUp : true │ │ │ │ - }, │ │ │ │ - click: function(evt) { │ │ │ │ - return this.handle(evt) ? !this.stopClick : true │ │ │ │ - }, │ │ │ │ - mousemove: function(evt) { │ │ │ │ - if (!this.callbacks["over"] && !this.callbacks["out"]) { │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - this.handle(evt); │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - dblclick: function(evt) { │ │ │ │ - return !this.handle(evt) │ │ │ │ - }, │ │ │ │ - geometryTypeMatches: function(feature) { │ │ │ │ - return this.geometryTypes == null || OpenLayers.Util.indexOf(this.geometryTypes, feature.geometry.CLASS_NAME) > -1 │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + this.map.events.register("buttonclick", this, this.onButtonClick) │ │ │ │ }, │ │ │ │ - handle: function(evt) { │ │ │ │ - if (this.feature && !this.feature.layer) { │ │ │ │ - this.feature = null │ │ │ │ - } │ │ │ │ - var type = evt.type; │ │ │ │ - var handled = false; │ │ │ │ - var previouslyIn = !!this.feature; │ │ │ │ - var click = type == "click" || type == "dblclick" || type == "touchstart"; │ │ │ │ - this.feature = this.layer.getFeatureFromEvent(evt); │ │ │ │ - if (this.feature && !this.feature.layer) { │ │ │ │ - this.feature = null │ │ │ │ - } │ │ │ │ - if (this.lastFeature && !this.lastFeature.layer) { │ │ │ │ - this.lastFeature = null │ │ │ │ - } │ │ │ │ - if (this.feature) { │ │ │ │ - if (type === "touchstart") { │ │ │ │ - OpenLayers.Event.preventDefault(evt) │ │ │ │ - } │ │ │ │ - var inNew = this.feature != this.lastFeature; │ │ │ │ - if (this.geometryTypeMatches(this.feature)) { │ │ │ │ - if (previouslyIn && inNew) { │ │ │ │ - if (this.lastFeature) { │ │ │ │ - this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ - } │ │ │ │ - this.triggerCallback(type, "in", [this.feature]) │ │ │ │ - } else if (!previouslyIn || click) { │ │ │ │ - this.triggerCallback(type, "in", [this.feature]) │ │ │ │ - } │ │ │ │ - this.lastFeature = this.feature; │ │ │ │ - handled = true │ │ │ │ - } else { │ │ │ │ - if (this.lastFeature && (previouslyIn && inNew || click)) { │ │ │ │ - this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ - } │ │ │ │ - this.feature = null │ │ │ │ - } │ │ │ │ - } else if (this.lastFeature && (previouslyIn || click)) { │ │ │ │ - this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ - } │ │ │ │ - return handled │ │ │ │ + draw: function(px) { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + px = this.position; │ │ │ │ + this.buttons = []; │ │ │ │ + var sz = { │ │ │ │ + w: 18, │ │ │ │ + h: 18 │ │ │ │ + }; │ │ │ │ + var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ + this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ + px.y = centered.y + sz.h; │ │ │ │ + this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ + this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz); │ │ │ │ + this._addButton("pandown", "south-mini.png", centered.add(0, sz.h * 2), sz); │ │ │ │ + this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ + this._addButton("zoomworld", "zoom-world-mini.png", centered.add(0, sz.h * 4 + 5), sz); │ │ │ │ + this._addButton("zoomout", "zoom-minus-mini.png", centered.add(0, sz.h * 5 + 5), sz); │ │ │ │ + return this.div │ │ │ │ }, │ │ │ │ - triggerCallback: function(type, mode, args) { │ │ │ │ - var key = this.EVENTMAP[type][mode]; │ │ │ │ - if (key) { │ │ │ │ - if (type == "click" && this.up && this.down) { │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - this.up = this.down = null │ │ │ │ - } else { │ │ │ │ - this.callback(key, args) │ │ │ │ - } │ │ │ │ - } │ │ │ │ + _addButton: function(id, img, xy, sz) { │ │ │ │ + var imgLocation = OpenLayers.Util.getImageLocation(img); │ │ │ │ + var btn = OpenLayers.Util.createAlphaImageDiv(this.id + "_" + id, xy, sz, imgLocation, "absolute"); │ │ │ │ + btn.style.cursor = "pointer"; │ │ │ │ + this.div.appendChild(btn); │ │ │ │ + btn.action = id; │ │ │ │ + btn.className = "olButton"; │ │ │ │ + this.buttons.push(btn); │ │ │ │ + return btn │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + _removeButton: function(btn) { │ │ │ │ + this.div.removeChild(btn); │ │ │ │ + OpenLayers.Util.removeItem(this.buttons, btn) │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + removeButtons: function() { │ │ │ │ + for (var i = this.buttons.length - 1; i >= 0; --i) { │ │ │ │ + this._removeButton(this.buttons[i]) │ │ │ │ } │ │ │ │ - return deactivated │ │ │ │ }, │ │ │ │ - handleMapEvents: function(evt) { │ │ │ │ - if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ - this.moveLayerToTop() │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + var btn = evt.buttonElement; │ │ │ │ + switch (btn.action) { │ │ │ │ + case "panup": │ │ │ │ + this.map.pan(0, -this.getSlideFactor("h")); │ │ │ │ + break; │ │ │ │ + case "pandown": │ │ │ │ + this.map.pan(0, this.getSlideFactor("h")); │ │ │ │ + break; │ │ │ │ + case "panleft": │ │ │ │ + this.map.pan(-this.getSlideFactor("w"), 0); │ │ │ │ + break; │ │ │ │ + case "panright": │ │ │ │ + this.map.pan(this.getSlideFactor("w"), 0); │ │ │ │ + break; │ │ │ │ + case "zoomin": │ │ │ │ + this.map.zoomIn(); │ │ │ │ + break; │ │ │ │ + case "zoomout": │ │ │ │ + this.map.zoomOut(); │ │ │ │ + break; │ │ │ │ + case "zoomworld": │ │ │ │ + this.map.zoomToMaxExtent(); │ │ │ │ + break │ │ │ │ } │ │ │ │ }, │ │ │ │ - moveLayerToTop: function() { │ │ │ │ - var index = Math.max(this.map.Z_INDEX_BASE["Feature"] - 1, this.layer.getZIndex()) + 1; │ │ │ │ - this.layer.setZIndex(index) │ │ │ │ - }, │ │ │ │ - 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)) │ │ │ │ - } │ │ │ │ + getSlideFactor: function(dim) { │ │ │ │ + return this.slideRatio ? this.map.getSize()[dim] * this.slideRatio : this.slideFactor │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Feature" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.PanZoom" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.DragFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - geometryTypes: null, │ │ │ │ - onStart: function(feature, pixel) {}, │ │ │ │ - onDrag: function(feature, pixel) {}, │ │ │ │ - onComplete: function(feature, pixel) {}, │ │ │ │ - onEnter: function(feature) {}, │ │ │ │ - onLeave: function(feature) {}, │ │ │ │ - documentDrag: false, │ │ │ │ - layer: null, │ │ │ │ - feature: null, │ │ │ │ - dragCallbacks: {}, │ │ │ │ - featureCallbacks: {}, │ │ │ │ - lastPixel: null, │ │ │ │ - initialize: function(layer, options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.layer = layer; │ │ │ │ - this.handlers = { │ │ │ │ - drag: new OpenLayers.Handler.Drag(this, OpenLayers.Util.extend({ │ │ │ │ - down: this.downFeature, │ │ │ │ - move: this.moveFeature, │ │ │ │ - up: this.upFeature, │ │ │ │ - out: this.cancel, │ │ │ │ - done: this.doneDragging │ │ │ │ - }, this.dragCallbacks), { │ │ │ │ - documentDrag: this.documentDrag │ │ │ │ - }), │ │ │ │ - feature: new OpenLayers.Handler.Feature(this, this.layer, OpenLayers.Util.extend({ │ │ │ │ - click: this.clickFeature, │ │ │ │ - clickout: this.clickoutFeature, │ │ │ │ - over: this.overFeature, │ │ │ │ - out: this.outFeature │ │ │ │ - }, this.featureCallbacks), { │ │ │ │ - geometryTypes: this.geometryTypes │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clickFeature: function(feature) { │ │ │ │ - if (this.handlers.feature.touch && !this.over && this.overFeature(feature)) { │ │ │ │ - this.handlers.drag.dragstart(this.handlers.feature.evt); │ │ │ │ - this.handlers.drag.stopDown = false │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clickoutFeature: function(feature) { │ │ │ │ - if (this.handlers.feature.touch && this.over) { │ │ │ │ - this.outFeature(feature); │ │ │ │ - this.handlers.drag.stopDown = true │ │ │ │ - } │ │ │ │ - }, │ │ │ │ +OpenLayers.Control.PanZoom.X = 4; │ │ │ │ +OpenLayers.Control.PanZoom.Y = 4; │ │ │ │ +OpenLayers.Control.PanZoomBar = OpenLayers.Class(OpenLayers.Control.PanZoom, { │ │ │ │ + zoomStopWidth: 18, │ │ │ │ + zoomStopHeight: 11, │ │ │ │ + slider: null, │ │ │ │ + sliderEvents: null, │ │ │ │ + zoombarDiv: null, │ │ │ │ + zoomWorldIcon: false, │ │ │ │ + panIcons: true, │ │ │ │ + forceFixedZoomLevel: false, │ │ │ │ + mouseDragStart: null, │ │ │ │ + deltaY: null, │ │ │ │ + zoomStart: null, │ │ │ │ destroy: function() { │ │ │ │ - this.layer = null; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, []) │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - return this.handlers.feature.activate() && OpenLayers.Control.prototype.activate.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ - this.handlers.feature.deactivate(); │ │ │ │ - this.feature = null; │ │ │ │ - this.dragging = false; │ │ │ │ - this.lastPixel = null; │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - overFeature: function(feature) { │ │ │ │ - var activated = false; │ │ │ │ - if (!this.handlers.drag.dragging) { │ │ │ │ - this.feature = feature; │ │ │ │ - this.handlers.drag.activate(); │ │ │ │ - activated = true; │ │ │ │ - this.over = true; │ │ │ │ - OpenLayers.Element.addClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ - this.onEnter(feature) │ │ │ │ - } else { │ │ │ │ - if (this.feature.id == feature.id) { │ │ │ │ - this.over = true │ │ │ │ - } else { │ │ │ │ - this.over = false │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - downFeature: function(pixel) { │ │ │ │ - this.lastPixel = pixel; │ │ │ │ - this.onStart(this.feature, pixel) │ │ │ │ - }, │ │ │ │ - moveFeature: function(pixel) { │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - this.feature.geometry.move(res * (pixel.x - this.lastPixel.x), res * (this.lastPixel.y - pixel.y)); │ │ │ │ - this.layer.drawFeature(this.feature); │ │ │ │ - this.lastPixel = pixel; │ │ │ │ - this.onDrag(this.feature, pixel) │ │ │ │ - }, │ │ │ │ - upFeature: function(pixel) { │ │ │ │ - if (!this.over) { │ │ │ │ - this.handlers.drag.deactivate() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - doneDragging: function(pixel) { │ │ │ │ - this.onComplete(this.feature, pixel) │ │ │ │ - }, │ │ │ │ - outFeature: function(feature) { │ │ │ │ - if (!this.handlers.drag.dragging) { │ │ │ │ - this.over = false; │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ - this.onLeave(feature); │ │ │ │ - this.feature = null │ │ │ │ - } else { │ │ │ │ - if (this.feature.id == feature.id) { │ │ │ │ - this.over = false │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - cancel: function() { │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ - this.over = false │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - this.handlers.drag.setMap(map); │ │ │ │ - this.handlers.feature.setMap(map); │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.DragFeature" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.RegularPolygon = OpenLayers.Class(OpenLayers.Handler.Drag, { │ │ │ │ - sides: 4, │ │ │ │ - radius: null, │ │ │ │ - snapAngle: null, │ │ │ │ - snapToggle: "shiftKey", │ │ │ │ - layerOptions: null, │ │ │ │ - persist: false, │ │ │ │ - irregular: false, │ │ │ │ - citeCompliant: false, │ │ │ │ - angle: null, │ │ │ │ - fixedRadius: false, │ │ │ │ - feature: null, │ │ │ │ - layer: null, │ │ │ │ - origin: null, │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - if (!(options && options.layerOptions && options.layerOptions.styleMap)) { │ │ │ │ - this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style["default"], {}) │ │ │ │ - } │ │ │ │ - OpenLayers.Handler.Drag.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ - this.options = options ? options : {} │ │ │ │ - }, │ │ │ │ - setOptions: function(newOptions) { │ │ │ │ - OpenLayers.Util.extend(this.options, newOptions); │ │ │ │ - OpenLayers.Util.extend(this, newOptions) │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (OpenLayers.Handler.Drag.prototype.activate.apply(this, arguments)) { │ │ │ │ - var options = OpenLayers.Util.extend({ │ │ │ │ - displayInLayerSwitcher: false, │ │ │ │ - calculateInRange: OpenLayers.Function.True, │ │ │ │ - wrapDateLine: this.citeCompliant │ │ │ │ - }, this.layerOptions); │ │ │ │ - this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options); │ │ │ │ - this.map.addLayer(this.layer); │ │ │ │ - activated = true │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = false; │ │ │ │ - if (OpenLayers.Handler.Drag.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - if (this.dragging) { │ │ │ │ - this.cancel() │ │ │ │ - } │ │ │ │ - if (this.layer.map != null) { │ │ │ │ - this.layer.destroy(false); │ │ │ │ - if (this.feature) { │ │ │ │ - this.feature.destroy() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.layer = null; │ │ │ │ - this.feature = null; │ │ │ │ - deactivated = true │ │ │ │ - } │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - down: function(evt) { │ │ │ │ - this.fixedRadius = !!this.radius; │ │ │ │ - var maploc = this.layer.getLonLatFromViewPortPx(evt.xy); │ │ │ │ - this.origin = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat); │ │ │ │ - if (!this.fixedRadius || this.irregular) { │ │ │ │ - this.radius = this.map.getResolution() │ │ │ │ - } │ │ │ │ - if (this.persist) { │ │ │ │ - this.clear() │ │ │ │ - } │ │ │ │ - this.feature = new OpenLayers.Feature.Vector; │ │ │ │ - this.createGeometry(); │ │ │ │ - this.callback("create", [this.origin, this.feature]); │ │ │ │ - this.layer.addFeatures([this.feature], { │ │ │ │ - silent: true │ │ │ │ + this._removeZoomBar(); │ │ │ │ + this.map.events.un({ │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ + updatesize: this.redraw, │ │ │ │ + scope: this │ │ │ │ }); │ │ │ │ - this.layer.drawFeature(this.feature, this.style) │ │ │ │ - }, │ │ │ │ - move: function(evt) { │ │ │ │ - var maploc = this.layer.getLonLatFromViewPortPx(evt.xy); │ │ │ │ - var point = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat); │ │ │ │ - if (this.irregular) { │ │ │ │ - var ry = Math.sqrt(2) * Math.abs(point.y - this.origin.y) / 2; │ │ │ │ - this.radius = Math.max(this.map.getResolution() / 2, ry) │ │ │ │ - } else if (this.fixedRadius) { │ │ │ │ - this.origin = point │ │ │ │ - } else { │ │ │ │ - this.calculateAngle(point, evt); │ │ │ │ - this.radius = Math.max(this.map.getResolution() / 2, point.distanceTo(this.origin)) │ │ │ │ - } │ │ │ │ - this.modifyGeometry(); │ │ │ │ - if (this.irregular) { │ │ │ │ - var dx = point.x - this.origin.x; │ │ │ │ - var dy = point.y - this.origin.y; │ │ │ │ - var ratio; │ │ │ │ - if (dy == 0) { │ │ │ │ - ratio = dx / (this.radius * Math.sqrt(2)) │ │ │ │ - } else { │ │ │ │ - ratio = dx / dy │ │ │ │ - } │ │ │ │ - this.feature.geometry.resize(1, this.origin, ratio); │ │ │ │ - this.feature.geometry.move(dx / 2, dy / 2) │ │ │ │ - } │ │ │ │ - this.layer.drawFeature(this.feature, this.style) │ │ │ │ - }, │ │ │ │ - up: function(evt) { │ │ │ │ - this.finalize(); │ │ │ │ - if (this.start == this.last) { │ │ │ │ - this.callback("done", [evt.xy]) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - out: function(evt) { │ │ │ │ - this.finalize() │ │ │ │ - }, │ │ │ │ - createGeometry: function() { │ │ │ │ - this.angle = Math.PI * (1 / this.sides - 1 / 2); │ │ │ │ - if (this.snapAngle) { │ │ │ │ - this.angle += this.snapAngle * (Math.PI / 180) │ │ │ │ - } │ │ │ │ - this.feature.geometry = OpenLayers.Geometry.Polygon.createRegularPolygon(this.origin, this.radius, this.sides, this.snapAngle) │ │ │ │ - }, │ │ │ │ - modifyGeometry: function() { │ │ │ │ - var angle, point; │ │ │ │ - var ring = this.feature.geometry.components[0]; │ │ │ │ - if (ring.components.length != this.sides + 1) { │ │ │ │ - this.createGeometry(); │ │ │ │ - ring = this.feature.geometry.components[0] │ │ │ │ - } │ │ │ │ - for (var i = 0; i < this.sides; ++i) { │ │ │ │ - point = ring.components[i]; │ │ │ │ - angle = this.angle + i * 2 * Math.PI / this.sides; │ │ │ │ - point.x = this.origin.x + this.radius * Math.cos(angle); │ │ │ │ - point.y = this.origin.y + this.radius * Math.sin(angle); │ │ │ │ - point.clearBounds() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - calculateAngle: function(point, evt) { │ │ │ │ - var alpha = Math.atan2(point.y - this.origin.y, point.x - this.origin.x); │ │ │ │ - if (this.snapAngle && (this.snapToggle && !evt[this.snapToggle])) { │ │ │ │ - var snapAngleRad = Math.PI / 180 * this.snapAngle; │ │ │ │ - this.angle = Math.round(alpha / snapAngleRad) * snapAngleRad │ │ │ │ - } else { │ │ │ │ - this.angle = alpha │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - cancel: function() { │ │ │ │ - this.callback("cancel", null); │ │ │ │ - this.finalize() │ │ │ │ - }, │ │ │ │ - finalize: function() { │ │ │ │ - this.origin = null; │ │ │ │ - this.radius = this.options.radius │ │ │ │ - }, │ │ │ │ - clear: function() { │ │ │ │ - if (this.layer) { │ │ │ │ - this.layer.renderer.clear(); │ │ │ │ - this.layer.destroyFeatures() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - callback: function(name, args) { │ │ │ │ - if (this.callbacks[name]) { │ │ │ │ - this.callbacks[name].apply(this.control, [this.feature.geometry.clone()]) │ │ │ │ - } │ │ │ │ - if (!this.persist && (name == "done" || name == "cancel")) { │ │ │ │ - this.clear() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.RegularPolygon" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - point: null, │ │ │ │ - layer: null, │ │ │ │ - multi: false, │ │ │ │ - citeCompliant: false, │ │ │ │ - mouseDown: false, │ │ │ │ - stoppedDown: null, │ │ │ │ - lastDown: null, │ │ │ │ - lastUp: null, │ │ │ │ - persist: false, │ │ │ │ - stopDown: false, │ │ │ │ - stopUp: false, │ │ │ │ - layerOptions: null, │ │ │ │ - pixelTolerance: 5, │ │ │ │ - lastTouchPx: null, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (!OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - var options = OpenLayers.Util.extend({ │ │ │ │ - displayInLayerSwitcher: false, │ │ │ │ - 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 │ │ │ │ + OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments); │ │ │ │ + delete this.mouseDragStart; │ │ │ │ + delete this.zoomStart │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments); │ │ │ │ + this.map.events.on({ │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ + updatesize: this.redraw, │ │ │ │ + scope: this │ │ │ │ }) │ │ │ │ }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (!OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - this.cancel(); │ │ │ │ - if (this.layer.map != null) { │ │ │ │ - this.destroyFeature(true); │ │ │ │ - this.layer.destroy(false) │ │ │ │ - } │ │ │ │ - this.layer = null; │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - destroyFeature: function(force) { │ │ │ │ - if (this.layer && (force || !this.persist)) { │ │ │ │ - this.layer.destroyFeatures() │ │ │ │ - } │ │ │ │ - this.point = null │ │ │ │ - }, │ │ │ │ - destroyPersistedFeature: function() { │ │ │ │ - var layer = this.layer; │ │ │ │ - if (layer && layer.features.length > 1) { │ │ │ │ - this.layer.features[0].destroy() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - cancel: function() { │ │ │ │ - this.finalize(true) │ │ │ │ - }, │ │ │ │ - click: function(evt) { │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - dblclick: function(evt) { │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - }, │ │ │ │ - drawFeature: function() { │ │ │ │ - this.layer.drawFeature(this.point, this.style) │ │ │ │ - }, │ │ │ │ - getGeometry: function() { │ │ │ │ - var geometry = this.point && this.point.geometry; │ │ │ │ - if (geometry && this.multi) { │ │ │ │ - geometry = new OpenLayers.Geometry.MultiPoint([geometry]) │ │ │ │ - } │ │ │ │ - return geometry │ │ │ │ - }, │ │ │ │ - geometryClone: function() { │ │ │ │ - var geom = this.getGeometry(); │ │ │ │ - return geom && geom.clone() │ │ │ │ - }, │ │ │ │ - mousedown: function(evt) { │ │ │ │ - return this.down(evt) │ │ │ │ - }, │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - this.lastTouchPx = evt.xy; │ │ │ │ - return this.down(evt) │ │ │ │ - }, │ │ │ │ - mousemove: function(evt) { │ │ │ │ - return this.move(evt) │ │ │ │ - }, │ │ │ │ - touchmove: function(evt) { │ │ │ │ - this.lastTouchPx = evt.xy; │ │ │ │ - return this.move(evt) │ │ │ │ - }, │ │ │ │ - mouseup: function(evt) { │ │ │ │ - return this.up(evt) │ │ │ │ - }, │ │ │ │ - touchend: function(evt) { │ │ │ │ - evt.xy = this.lastTouchPx; │ │ │ │ - return this.up(evt) │ │ │ │ - }, │ │ │ │ - down: function(evt) { │ │ │ │ - this.mouseDown = true; │ │ │ │ - this.lastDown = evt.xy; │ │ │ │ - if (!this.touch) { │ │ │ │ - this.modifyFeature(evt.xy) │ │ │ │ - } │ │ │ │ - this.stoppedDown = this.stopDown; │ │ │ │ - return !this.stopDown │ │ │ │ - }, │ │ │ │ - move: function(evt) { │ │ │ │ - if (!this.touch && (!this.mouseDown || this.stoppedDown)) { │ │ │ │ - this.modifyFeature(evt.xy) │ │ │ │ + redraw: function() { │ │ │ │ + if (this.div != null) { │ │ │ │ + this.removeButtons(); │ │ │ │ + this._removeZoomBar() │ │ │ │ } │ │ │ │ - return true │ │ │ │ + this.draw() │ │ │ │ }, │ │ │ │ - up: function(evt) { │ │ │ │ - this.mouseDown = false; │ │ │ │ - this.stoppedDown = this.stopDown; │ │ │ │ - if (!this.checkModifiers(evt)) { │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - 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) │ │ │ │ + draw: function(px) { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + px = this.position.clone(); │ │ │ │ + this.buttons = []; │ │ │ │ + var sz = { │ │ │ │ + w: 18, │ │ │ │ + h: 18 │ │ │ │ + }; │ │ │ │ + if (this.panIcons) { │ │ │ │ + var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ + var wposition = sz.w; │ │ │ │ + if (this.zoomWorldIcon) { │ │ │ │ + centered = new OpenLayers.Pixel(px.x + sz.w, px.y) │ │ │ │ } │ │ │ │ - if (this.persist) { │ │ │ │ - this.destroyPersistedFeature() │ │ │ │ + this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ + px.y = centered.y + sz.h; │ │ │ │ + this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ + if (this.zoomWorldIcon) { │ │ │ │ + this._addButton("zoomworld", "zoom-world-mini.png", px.add(sz.w, 0), sz); │ │ │ │ + wposition *= 2 │ │ │ │ } │ │ │ │ - this.lastUp = evt.xy; │ │ │ │ - this.finalize(); │ │ │ │ - return !this.stopUp │ │ │ │ + this._addButton("panright", "east-mini.png", px.add(wposition, 0), sz); │ │ │ │ + this._addButton("pandown", "south-mini.png", centered.add(0, sz.h * 2), sz); │ │ │ │ + this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ + centered = this._addZoomBar(centered.add(0, sz.h * 4 + 5)); │ │ │ │ + this._addButton("zoomout", "zoom-minus-mini.png", centered, sz) │ │ │ │ } else { │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - mouseout: function(evt) { │ │ │ │ - if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ - this.stoppedDown = this.stopDown; │ │ │ │ - this.mouseDown = false │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 = OpenLayers.Class(OpenLayers.Handler.Point, { │ │ │ │ - line: null, │ │ │ │ - maxVertices: null, │ │ │ │ - doubleTouchTolerance: 20, │ │ │ │ - freehand: false, │ │ │ │ - freehandToggle: "shiftKey", │ │ │ │ - timerId: null, │ │ │ │ - redoStack: null, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - destroyFeature: function(force) { │ │ │ │ - OpenLayers.Handler.Point.prototype.destroyFeature.call(this, force); │ │ │ │ - this.line = null │ │ │ │ - }, │ │ │ │ - destroyPersistedFeature: function() { │ │ │ │ - var layer = this.layer; │ │ │ │ - if (layer && layer.features.length > 2) { │ │ │ │ - this.layer.features[0].destroy() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - removePoint: function() { │ │ │ │ - if (this.point) { │ │ │ │ - this.layer.removeFeatures([this.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 │ │ │ │ - }, │ │ │ │ - insertXY: function(x, y) { │ │ │ │ - this.line.geometry.addComponent(new OpenLayers.Geometry.Point(x, y), this.getCurrentPointIndex()); │ │ │ │ - this.drawFeature(); │ │ │ │ - delete this.redoStack │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - insertDirectionLength: function(direction, length) { │ │ │ │ - direction *= Math.PI / 180; │ │ │ │ - var dx = length * Math.cos(direction); │ │ │ │ - var dy = length * Math.sin(direction); │ │ │ │ - this.insertDeltaXY(dx, dy) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getCurrentPointIndex: function() { │ │ │ │ - return this.line.geometry.components.length - 1 │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - if (this.touch && index > 0) { │ │ │ │ - components = geometry.components; │ │ │ │ - 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._addButton("zoomin", "zoom-plus-mini.png", px, sz); │ │ │ │ + centered = this._addZoomBar(px.add(0, sz.h)); │ │ │ │ + this._addButton("zoomout", "zoom-minus-mini.png", centered, sz); │ │ │ │ + if (this.zoomWorldIcon) { │ │ │ │ + centered = centered.add(0, sz.h + 3); │ │ │ │ + this._addButton("zoomworld", "zoom-world-mini.png", centered, sz) │ │ │ │ } │ │ │ │ - this.redoStack.push(target); │ │ │ │ - this.drawFeature() │ │ │ │ - } │ │ │ │ - return undone │ │ │ │ - }, │ │ │ │ - redo: function() { │ │ │ │ - var target = this.redoStack && this.redoStack.pop(); │ │ │ │ - if (target) { │ │ │ │ - this.line.geometry.addComponent(target, this.getCurrentPointIndex()); │ │ │ │ - this.drawFeature() │ │ │ │ - } │ │ │ │ - return !!target │ │ │ │ - }, │ │ │ │ - freehandMode: function(evt) { │ │ │ │ - return this.freehandToggle && evt[this.freehandToggle] ? !this.freehand : this.freehand │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - }, │ │ │ │ - drawFeature: function() { │ │ │ │ - this.layer.drawFeature(this.line, this.style); │ │ │ │ - this.layer.drawFeature(this.point, this.style) │ │ │ │ - }, │ │ │ │ - getSketch: function() { │ │ │ │ - return this.line │ │ │ │ - }, │ │ │ │ - getGeometry: function() { │ │ │ │ - var geometry = this.line && this.line.geometry; │ │ │ │ - if (geometry && this.multi) { │ │ │ │ - geometry = new OpenLayers.Geometry.MultiLineString([geometry]) │ │ │ │ } │ │ │ │ - return geometry │ │ │ │ + return this.div │ │ │ │ }, │ │ │ │ - touchstart: function(evt) { │ │ │ │ - if (this.timerId && this.passesTolerance(this.lastTouchPx, evt.xy, this.doubleTouchTolerance)) { │ │ │ │ - this.finishGeometry(); │ │ │ │ - window.clearTimeout(this.timerId); │ │ │ │ - this.timerId = null; │ │ │ │ - return false │ │ │ │ + _addZoomBar: function(centered) { │ │ │ │ + var imgLocation = OpenLayers.Util.getImageLocation("slider.png"); │ │ │ │ + var id = this.id + "_" + this.map.id; │ │ │ │ + var minZoom = this.map.getMinZoom(); │ │ │ │ + var zoomsToEnd = this.map.getNumZoomLevels() - 1 - this.map.getZoom(); │ │ │ │ + var slider = OpenLayers.Util.createAlphaImageDiv(id, centered.add(-1, zoomsToEnd * this.zoomStopHeight), { │ │ │ │ + w: 20, │ │ │ │ + h: 9 │ │ │ │ + }, imgLocation, "absolute"); │ │ │ │ + slider.style.cursor = "move"; │ │ │ │ + this.slider = slider; │ │ │ │ + this.sliderEvents = new OpenLayers.Events(this, slider, null, true, { │ │ │ │ + includeXY: true │ │ │ │ + }); │ │ │ │ + this.sliderEvents.on({ │ │ │ │ + touchstart: this.zoomBarDown, │ │ │ │ + touchmove: this.zoomBarDrag, │ │ │ │ + touchend: this.zoomBarUp, │ │ │ │ + mousedown: this.zoomBarDown, │ │ │ │ + mousemove: this.zoomBarDrag, │ │ │ │ + mouseup: this.zoomBarUp │ │ │ │ + }); │ │ │ │ + var sz = { │ │ │ │ + w: this.zoomStopWidth, │ │ │ │ + h: this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom) │ │ │ │ + }; │ │ │ │ + var imgLocation = OpenLayers.Util.getImageLocation("zoombar.png"); │ │ │ │ + var div = null; │ │ │ │ + if (OpenLayers.Util.alphaHack()) { │ │ │ │ + var id = this.id + "_" + this.map.id; │ │ │ │ + div = OpenLayers.Util.createAlphaImageDiv(id, centered, { │ │ │ │ + w: sz.w, │ │ │ │ + h: this.zoomStopHeight │ │ │ │ + }, imgLocation, "absolute", null, "crop"); │ │ │ │ + div.style.height = sz.h + "px" │ │ │ │ } 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - finishGeometry: function() { │ │ │ │ - var index = this.line.geometry.components.length - 1; │ │ │ │ - this.line.geometry.removeComponent(this.line.geometry.components[index]); │ │ │ │ - this.removePoint(); │ │ │ │ - this.finalize() │ │ │ │ - }, │ │ │ │ - dblclick: function(evt) { │ │ │ │ - if (!this.freehandMode(evt)) { │ │ │ │ - this.finishGeometry() │ │ │ │ + div = OpenLayers.Util.createDiv("OpenLayers_Control_PanZoomBar_Zoombar" + this.map.id, centered, sz, imgLocation) │ │ │ │ } │ │ │ │ - return false │ │ │ │ + div.style.cursor = "pointer"; │ │ │ │ + div.className = "olButton"; │ │ │ │ + this.zoombarDiv = div; │ │ │ │ + this.div.appendChild(div); │ │ │ │ + this.startTop = parseInt(div.style.top); │ │ │ │ + this.div.appendChild(slider); │ │ │ │ + this.map.events.register("zoomend", this, this.moveZoomBar); │ │ │ │ + centered = centered.add(0, this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom)); │ │ │ │ + return centered │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Path" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.Polygon = OpenLayers.Class(OpenLayers.Handler.Path, { │ │ │ │ - holeModifier: null, │ │ │ │ - drawingHole: false, │ │ │ │ - polygon: null, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ + _removeZoomBar: function() { │ │ │ │ + this.sliderEvents.un({ │ │ │ │ + touchstart: this.zoomBarDown, │ │ │ │ + touchmove: this.zoomBarDrag, │ │ │ │ + touchend: this.zoomBarUp, │ │ │ │ + mousedown: this.zoomBarDown, │ │ │ │ + mousemove: this.zoomBarDrag, │ │ │ │ + mouseup: this.zoomBarUp │ │ │ │ + }); │ │ │ │ + this.sliderEvents.destroy(); │ │ │ │ + this.div.removeChild(this.zoombarDiv); │ │ │ │ + this.zoombarDiv = null; │ │ │ │ + this.div.removeChild(this.slider); │ │ │ │ + this.slider = null; │ │ │ │ + this.map.events.unregister("zoomend", this, this.moveZoomBar) │ │ │ │ }, │ │ │ │ - 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; │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this, arguments); │ │ │ │ + if (evt.buttonElement === this.zoombarDiv) { │ │ │ │ + var levels = evt.buttonXY.y / this.zoomStopHeight; │ │ │ │ + if (this.forceFixedZoomLevel || !this.map.fractionalZoom) { │ │ │ │ + levels = Math.floor(levels) │ │ │ │ } │ │ │ │ - } │ │ │ │ - OpenLayers.Handler.Path.prototype.addPoint.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - getCurrentPointIndex: function() { │ │ │ │ - return this.line.geometry.components.length - 2 │ │ │ │ - }, │ │ │ │ - enforceTopology: function(event) { │ │ │ │ - var point = event.vertex; │ │ │ │ - var components = this.line.geometry.components; │ │ │ │ - if (!this.polygon.geometry.intersects(point)) { │ │ │ │ - var last = components[components.length - 3]; │ │ │ │ - point.x = last.x; │ │ │ │ - point.y = last.y │ │ │ │ + var zoom = this.map.getNumZoomLevels() - 1 - levels; │ │ │ │ + zoom = Math.min(Math.max(zoom, 0), this.map.getNumZoomLevels() - 1); │ │ │ │ + this.map.zoomTo(zoom) │ │ │ │ } │ │ │ │ }, │ │ │ │ - finishGeometry: function() { │ │ │ │ - var index = this.line.geometry.components.length - 2; │ │ │ │ - this.line.geometry.removeComponent(this.line.geometry.components[index]); │ │ │ │ - this.removePoint(); │ │ │ │ - this.finalize() │ │ │ │ - }, │ │ │ │ - finalizeInteriorRing: function() { │ │ │ │ - var ring = this.line.geometry; │ │ │ │ - var modified = ring.getArea() !== 0; │ │ │ │ - if (modified) { │ │ │ │ - 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) { │ │ │ │ - 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 │ │ │ │ + passEventToSlider: function(evt) { │ │ │ │ + this.sliderEvents.handleBrowserEvent(evt) │ │ │ │ }, │ │ │ │ - cancel: function() { │ │ │ │ - if (this.drawingHole) { │ │ │ │ - this.polygon.geometry.removeComponent(this.line.geometry); │ │ │ │ - this.restoreFeature(true) │ │ │ │ + zoomBarDown: function(evt) { │ │ │ │ + if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ + return │ │ │ │ } │ │ │ │ - return OpenLayers.Handler.Path.prototype.cancel.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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.map.events.on({ │ │ │ │ + touchmove: this.passEventToSlider, │ │ │ │ + mousemove: this.passEventToSlider, │ │ │ │ + mouseup: this.passEventToSlider, │ │ │ │ + scope: this │ │ │ │ }); │ │ │ │ - this.drawingHole = false; │ │ │ │ - if (!cancel) { │ │ │ │ - this.control.layer.events.triggerEvent("sketchcomplete", { │ │ │ │ - feature: this.polygon │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroyFeature: function(force) { │ │ │ │ - OpenLayers.Handler.Path.prototype.destroyFeature.call(this, force); │ │ │ │ - this.polygon = null │ │ │ │ - }, │ │ │ │ - drawFeature: function() { │ │ │ │ - this.layer.drawFeature(this.polygon, this.style); │ │ │ │ - this.layer.drawFeature(this.point, this.style) │ │ │ │ - }, │ │ │ │ - getSketch: function() { │ │ │ │ - return this.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.Handler.Click = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - delay: 300, │ │ │ │ - single: true, │ │ │ │ - double: false, │ │ │ │ - pixelTolerance: 0, │ │ │ │ - dblclickTolerance: 13, │ │ │ │ - stopSingle: false, │ │ │ │ - stopDouble: false, │ │ │ │ - timerId: null, │ │ │ │ - down: null, │ │ │ │ - last: null, │ │ │ │ - first: null, │ │ │ │ - rightclickTimerId: null, │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - this.down = this.getEventInfo(evt); │ │ │ │ - this.last = this.getEventInfo(evt); │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - touchmove: function(evt) { │ │ │ │ - this.last = this.getEventInfo(evt); │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - touchend: function(evt) { │ │ │ │ - if (this.down) { │ │ │ │ - evt.xy = this.last.xy; │ │ │ │ - evt.lastTouches = this.last.touches; │ │ │ │ - this.handleSingle(evt); │ │ │ │ - this.down = null │ │ │ │ - } │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - mousedown: function(evt) { │ │ │ │ - this.down = this.getEventInfo(evt); │ │ │ │ - this.last = this.getEventInfo(evt); │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - mouseup: function(evt) { │ │ │ │ - var propagate = true; │ │ │ │ - if (this.checkModifiers(evt) && this.control.handleRightClicks && OpenLayers.Event.isRightClick(evt)) { │ │ │ │ - propagate = this.rightclick(evt) │ │ │ │ - } │ │ │ │ - return propagate │ │ │ │ + this.mouseDragStart = evt.xy.clone(); │ │ │ │ + this.zoomStart = evt.xy.clone(); │ │ │ │ + this.div.style.cursor = "move"; │ │ │ │ + this.zoombarDiv.offsets = null; │ │ │ │ + OpenLayers.Event.stop(evt) │ │ │ │ }, │ │ │ │ - rightclick: function(evt) { │ │ │ │ - if (this.passesTolerance(evt)) { │ │ │ │ - if (this.rightclickTimerId != null) { │ │ │ │ - this.clearTimer(); │ │ │ │ - this.callback("dblrightclick", [evt]); │ │ │ │ - return !this.stopDouble │ │ │ │ - } else { │ │ │ │ - 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) │ │ │ │ + zoomBarDrag: function(evt) { │ │ │ │ + if (this.mouseDragStart != null) { │ │ │ │ + var deltaY = this.mouseDragStart.y - evt.xy.y; │ │ │ │ + var offsets = OpenLayers.Util.pagePosition(this.zoombarDiv); │ │ │ │ + if (evt.clientY - offsets[1] > 0 && evt.clientY - offsets[1] < parseInt(this.zoombarDiv.style.height) - 2) { │ │ │ │ + var newTop = parseInt(this.slider.style.top) - deltaY; │ │ │ │ + this.slider.style.top = newTop + "px"; │ │ │ │ + this.mouseDragStart = evt.xy.clone() │ │ │ │ } │ │ │ │ + this.deltaY = this.zoomStart.y - evt.xy.y; │ │ │ │ + OpenLayers.Event.stop(evt) │ │ │ │ } │ │ │ │ - return !this.stopSingle │ │ │ │ - }, │ │ │ │ - delayedRightCall: function(evt) { │ │ │ │ - this.rightclickTimerId = null; │ │ │ │ - if (evt) { │ │ │ │ - this.callback("rightclick", [evt]) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - click: function(evt) { │ │ │ │ - if (!this.last) { │ │ │ │ - this.last = this.getEventInfo(evt) │ │ │ │ - } │ │ │ │ - this.handleSingle(evt); │ │ │ │ - return !this.stopSingle │ │ │ │ - }, │ │ │ │ - dblclick: function(evt) { │ │ │ │ - this.handleDouble(evt); │ │ │ │ - return !this.stopDouble │ │ │ │ }, │ │ │ │ - handleDouble: function(evt) { │ │ │ │ - if (this.passesDblclickTolerance(evt)) { │ │ │ │ - if (this["double"]) { │ │ │ │ - this.callback("dblclick", [evt]) │ │ │ │ - } │ │ │ │ - this.clearTimer() │ │ │ │ + zoomBarUp: function(evt) { │ │ │ │ + if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") { │ │ │ │ + return │ │ │ │ } │ │ │ │ - }, │ │ │ │ - handleSingle: function(evt) { │ │ │ │ - if (this.passesTolerance(evt)) { │ │ │ │ - if (this.timerId != null) { │ │ │ │ - if (this.last.touches && this.last.touches.length === 1) { │ │ │ │ - if (this["double"]) { │ │ │ │ - OpenLayers.Event.preventDefault(evt) │ │ │ │ - } │ │ │ │ - this.handleDouble(evt) │ │ │ │ - } │ │ │ │ - if (!this.last.touches || this.last.touches.length !== 2) { │ │ │ │ - this.clearTimer() │ │ │ │ - } │ │ │ │ + if (this.mouseDragStart) { │ │ │ │ + this.div.style.cursor = ""; │ │ │ │ + this.map.events.un({ │ │ │ │ + touchmove: this.passEventToSlider, │ │ │ │ + mouseup: this.passEventToSlider, │ │ │ │ + mousemove: this.passEventToSlider, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + var zoomLevel = this.map.zoom; │ │ │ │ + if (!this.forceFixedZoomLevel && this.map.fractionalZoom) { │ │ │ │ + zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ + zoomLevel = Math.min(Math.max(zoomLevel, 0), this.map.getNumZoomLevels() - 1) │ │ │ │ } else { │ │ │ │ - this.first = this.getEventInfo(evt); │ │ │ │ - var clickEvent = this.single ? OpenLayers.Util.extend({}, evt) : null; │ │ │ │ - this.queuePotentialClick(clickEvent) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - queuePotentialClick: function(evt) { │ │ │ │ - this.timerId = window.setTimeout(OpenLayers.Function.bind(this.delayedCall, this, evt), this.delay) │ │ │ │ - }, │ │ │ │ - passesTolerance: function(evt) { │ │ │ │ - var passes = true; │ │ │ │ - if (this.pixelTolerance != null && this.down && this.down.xy) { │ │ │ │ - passes = this.pixelTolerance >= this.down.xy.distanceTo(evt.xy); │ │ │ │ - if (passes && this.touch && this.down.touches.length === this.last.touches.length) { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - getTouchDistance: function(from, to) { │ │ │ │ - return Math.sqrt(Math.pow(from.clientX - to.clientX, 2) + Math.pow(from.clientY - to.clientY, 2)) │ │ │ │ - }, │ │ │ │ - passesDblclickTolerance: function(evt) { │ │ │ │ - var passes = true; │ │ │ │ - if (this.down && this.first) { │ │ │ │ - passes = this.down.xy.distanceTo(this.first.xy) <= this.dblclickTolerance │ │ │ │ - } │ │ │ │ - return passes │ │ │ │ - }, │ │ │ │ - clearTimer: function() { │ │ │ │ - if (this.timerId != null) { │ │ │ │ - window.clearTimeout(this.timerId); │ │ │ │ - this.timerId = null │ │ │ │ - } │ │ │ │ - if (this.rightclickTimerId != null) { │ │ │ │ - window.clearTimeout(this.rightclickTimerId); │ │ │ │ - this.rightclickTimerId = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - delayedCall: function(evt) { │ │ │ │ - this.timerId = null; │ │ │ │ - if (evt) { │ │ │ │ - this.callback("click", [evt]) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ + zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ + zoomLevel = Math.max(Math.round(zoomLevel), 0) │ │ │ │ } │ │ │ │ - } │ │ │ │ - return { │ │ │ │ - xy: evt.xy, │ │ │ │ - touches: touches │ │ │ │ + this.map.zoomTo(zoomLevel); │ │ │ │ + this.mouseDragStart = null; │ │ │ │ + this.zoomStart = null; │ │ │ │ + this.deltaY = 0; │ │ │ │ + OpenLayers.Event.stop(evt) │ │ │ │ } │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + moveZoomBar: function() { │ │ │ │ + var newTop = (this.map.getNumZoomLevels() - 1 - this.map.getZoom()) * this.zoomStopHeight + this.startTop + 1; │ │ │ │ + this.slider.style.top = newTop + "px" │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Click" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.PanZoomBar" │ │ │ │ }); │ │ │ │ OpenLayers.Format.SLD = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ profile: null, │ │ │ │ defaultVersion: "1.0.0", │ │ │ │ stringifyOutput: true, │ │ │ │ namedLayersAsArray: false, │ │ │ │ CLASS_NAME: "OpenLayers.Format.SLD" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, { │ │ │ │ - schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd", │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - 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"] │ │ │ │ - }, │ │ │ │ - write: function(features) { │ │ │ │ - var name; │ │ │ │ - if (OpenLayers.Util.isArray(features)) { │ │ │ │ - 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]) │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - 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); │ │ │ │ - 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.Format.Filter.v1_0_0 = OpenLayers.Class(OpenLayers.Format.GML.v2, OpenLayers.Format.Filter.v1, { │ │ │ │ - VERSION: "1.0.0", │ │ │ │ - schemaLocation: "http://www.opengis.net/ogc/filter/1.0.0/filter.xsd", │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.GML.v2.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - 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"] │ │ │ │ - }, │ │ │ │ - writers: { │ │ │ │ - ogc: OpenLayers.Util.applyDefaults({ │ │ │ │ - PropertyIsEqualTo: function(filter) { │ │ │ │ - var node = this.createElementNSPlus("ogc:PropertyIsEqualTo"); │ │ │ │ - this.writeNode("PropertyName", filter, node); │ │ │ │ - this.writeOgcExpression(filter.value, node); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - PropertyIsNotEqualTo: function(filter) { │ │ │ │ - var node = this.createElementNSPlus("ogc:PropertyIsNotEqualTo"); │ │ │ │ - this.writeNode("PropertyName", filter, node); │ │ │ │ - this.writeOgcExpression(filter.value, node); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - PropertyIsLike: function(filter) { │ │ │ │ - var node = this.createElementNSPlus("ogc:PropertyIsLike", { │ │ │ │ - attributes: { │ │ │ │ - wildCard: "*", │ │ │ │ - singleChar: ".", │ │ │ │ - escape: "!" │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.writeNode("PropertyName", filter, node); │ │ │ │ - this.writeNode("Literal", filter.regex2value(), node); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - BBOX: function(filter) { │ │ │ │ - var node = this.createElementNSPlus("ogc:BBOX"); │ │ │ │ - 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"] │ │ │ │ - }, │ │ │ │ - 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.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { │ │ │ │ namespaces: { │ │ │ │ sld: "http://www.opengis.net/sld", │ │ │ │ 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" │ │ │ │ @@ -22049,204 +25933,14 @@ │ │ │ │ break │ │ │ │ } │ │ │ │ } │ │ │ │ canApply && this._queue.call(this) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.SLDSelect" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.Button = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - type: OpenLayers.Control.TYPE_BUTTON, │ │ │ │ - trigger: function() {}, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Button" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.NavigationHistory = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - type: OpenLayers.Control.TYPE_TOGGLE, │ │ │ │ - previous: null, │ │ │ │ - previousOptions: null, │ │ │ │ - next: null, │ │ │ │ - nextOptions: null, │ │ │ │ - limit: 50, │ │ │ │ - autoActivate: true, │ │ │ │ - clearOnDeactivate: false, │ │ │ │ - registry: null, │ │ │ │ - nextStack: null, │ │ │ │ - previousStack: null, │ │ │ │ - listeners: null, │ │ │ │ - restoring: false, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.registry = OpenLayers.Util.extend({ │ │ │ │ - moveend: this.getState │ │ │ │ - }, this.registry); │ │ │ │ - var previousOptions = { │ │ │ │ - trigger: OpenLayers.Function.bind(this.previousTrigger, this), │ │ │ │ - displayClass: this.displayClass + " " + this.displayClass + "Previous" │ │ │ │ - }; │ │ │ │ - OpenLayers.Util.extend(previousOptions, this.previousOptions); │ │ │ │ - this.previous = new OpenLayers.Control.Button(previousOptions); │ │ │ │ - var nextOptions = { │ │ │ │ - trigger: OpenLayers.Function.bind(this.nextTrigger, this), │ │ │ │ - displayClass: this.displayClass + " " + this.displayClass + "Next" │ │ │ │ - }; │ │ │ │ - OpenLayers.Util.extend(nextOptions, this.nextOptions); │ │ │ │ - this.next = new OpenLayers.Control.Button(nextOptions); │ │ │ │ - this.clear() │ │ │ │ - }, │ │ │ │ - onPreviousChange: function(state, length) { │ │ │ │ - if (state && !this.previous.active) { │ │ │ │ - this.previous.activate() │ │ │ │ - } else if (!state && this.previous.active) { │ │ │ │ - this.previous.deactivate() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - onNextChange: function(state, length) { │ │ │ │ - if (state && !this.next.active) { │ │ │ │ - this.next.activate() │ │ │ │ - } else if (!state && this.next.active) { │ │ │ │ - this.next.deactivate() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this); │ │ │ │ - this.previous.destroy(); │ │ │ │ - this.next.destroy(); │ │ │ │ - this.deactivate(); │ │ │ │ - for (var prop in this) { │ │ │ │ - this[prop] = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - this.map = map; │ │ │ │ - this.next.setMap(map); │ │ │ │ - this.previous.setMap(map) │ │ │ │ - }, │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - this.next.draw(); │ │ │ │ - this.previous.draw() │ │ │ │ - }, │ │ │ │ - previousTrigger: function() { │ │ │ │ - var current = this.previousStack.shift(); │ │ │ │ - var state = this.previousStack.shift(); │ │ │ │ - if (state != undefined) { │ │ │ │ - this.nextStack.unshift(current); │ │ │ │ - this.previousStack.unshift(state); │ │ │ │ - this.restoring = true; │ │ │ │ - this.restore(state); │ │ │ │ - this.restoring = false; │ │ │ │ - this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ - this.onPreviousChange(this.previousStack[1], this.previousStack.length - 1) │ │ │ │ - } else { │ │ │ │ - this.previousStack.unshift(current) │ │ │ │ - } │ │ │ │ - return state │ │ │ │ - }, │ │ │ │ - nextTrigger: function() { │ │ │ │ - var state = this.nextStack.shift(); │ │ │ │ - if (state != undefined) { │ │ │ │ - this.previousStack.unshift(state); │ │ │ │ - this.restoring = true; │ │ │ │ - this.restore(state); │ │ │ │ - this.restoring = false; │ │ │ │ - this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ - this.onPreviousChange(this.previousStack[1], this.previousStack.length - 1) │ │ │ │ - } │ │ │ │ - return state │ │ │ │ - }, │ │ │ │ - clear: function() { │ │ │ │ - this.previousStack = []; │ │ │ │ - this.previous.deactivate(); │ │ │ │ - this.nextStack = []; │ │ │ │ - this.next.deactivate() │ │ │ │ - }, │ │ │ │ - getState: function() { │ │ │ │ - return { │ │ │ │ - center: this.map.getCenter(), │ │ │ │ - resolution: this.map.getResolution(), │ │ │ │ - projection: this.map.getProjectionObject(), │ │ │ │ - units: this.map.getProjectionObject().getUnits() || this.map.units || this.map.baseLayer.units │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - restore: function(state) { │ │ │ │ - var center, zoom; │ │ │ │ - if (this.map.getProjectionObject() == state.projection) { │ │ │ │ - zoom = this.map.getZoomForResolution(state.resolution); │ │ │ │ - center = state.center │ │ │ │ - } else { │ │ │ │ - center = state.center.clone(); │ │ │ │ - center.transform(state.projection, this.map.getProjectionObject()); │ │ │ │ - var sourceUnits = state.units; │ │ │ │ - var targetUnits = this.map.getProjectionObject().getUnits() || this.map.units || this.map.baseLayer.units; │ │ │ │ - var resolutionFactor = sourceUnits && targetUnits ? OpenLayers.INCHES_PER_UNIT[sourceUnits] / OpenLayers.INCHES_PER_UNIT[targetUnits] : 1; │ │ │ │ - zoom = this.map.getZoomForResolution(resolutionFactor * state.resolution) │ │ │ │ - } │ │ │ │ - this.map.setCenter(center, zoom) │ │ │ │ - }, │ │ │ │ - setListeners: function() { │ │ │ │ - this.listeners = {}; │ │ │ │ - for (var type in this.registry) { │ │ │ │ - this.listeners[type] = OpenLayers.Function.bind(function() { │ │ │ │ - if (!this.restoring) { │ │ │ │ - var state = this.registry[type].apply(this, arguments); │ │ │ │ - this.previousStack.unshift(state); │ │ │ │ - if (this.previousStack.length > 1) { │ │ │ │ - this.onPreviousChange(this.previousStack[1], this.previousStack.length - 1) │ │ │ │ - } │ │ │ │ - if (this.previousStack.length > this.limit + 1) { │ │ │ │ - this.previousStack.pop() │ │ │ │ - } │ │ │ │ - if (this.nextStack.length > 0) { │ │ │ │ - this.nextStack = []; │ │ │ │ - this.onNextChange(null, 0) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return true │ │ │ │ - }, this) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (this.map) { │ │ │ │ - if (OpenLayers.Control.prototype.activate.apply(this)) { │ │ │ │ - if (this.listeners == null) { │ │ │ │ - this.setListeners() │ │ │ │ - } │ │ │ │ - for (var type in this.listeners) { │ │ │ │ - this.map.events.register(type, this, this.listeners[type]) │ │ │ │ - } │ │ │ │ - activated = true; │ │ │ │ - if (this.previousStack.length == 0) { │ │ │ │ - this.initStack() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - initStack: function() { │ │ │ │ - if (this.map.getCenter()) { │ │ │ │ - this.listeners.moveend() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = false; │ │ │ │ - if (this.map) { │ │ │ │ - if (OpenLayers.Control.prototype.deactivate.apply(this)) { │ │ │ │ - for (var type in this.listeners) { │ │ │ │ - this.map.events.unregister(type, this, this.listeners[type]) │ │ │ │ - } │ │ │ │ - if (this.clearOnDeactivate) { │ │ │ │ - this.clear() │ │ │ │ - } │ │ │ │ - deactivated = true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.NavigationHistory" │ │ │ │ -}); │ │ │ │ OpenLayers.Control.Geolocate = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ geolocation: null, │ │ │ │ available: "geolocation" in navigator, │ │ │ │ bind: true, │ │ │ │ watch: false, │ │ │ │ geolocationOptions: null, │ │ │ │ destroy: function() { │ │ │ │ @@ -22297,604 +25991,395 @@ │ │ │ │ failure: function(error) { │ │ │ │ this.events.triggerEvent("locationfailed", { │ │ │ │ error: error │ │ │ │ }) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.Geolocate" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - slideFactor: 50, │ │ │ │ - slideRatio: null, │ │ │ │ - buttons: null, │ │ │ │ - position: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X, OpenLayers.Control.PanZoom.Y); │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.unregister("buttonclick", this, this.onButtonClick) │ │ │ │ +OpenLayers.Control.Zoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + zoomInText: "+", │ │ │ │ + zoomInId: "olZoomInLink", │ │ │ │ + zoomOutText: "−", │ │ │ │ + zoomOutId: "olZoomOutLink", │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - this.removeButtons(); │ │ │ │ - this.buttons = null; │ │ │ │ - this.position = null; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - this.map.events.register("buttonclick", this, this.onButtonClick) │ │ │ │ - }, │ │ │ │ - draw: function(px) { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - px = this.position; │ │ │ │ - this.buttons = []; │ │ │ │ - var sz = { │ │ │ │ - w: 18, │ │ │ │ - h: 18 │ │ │ │ - }; │ │ │ │ - var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ - this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ - px.y = centered.y + sz.h; │ │ │ │ - this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ - this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz); │ │ │ │ - this._addButton("pandown", "south-mini.png", centered.add(0, sz.h * 2), sz); │ │ │ │ - this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ - this._addButton("zoomworld", "zoom-world-mini.png", centered.add(0, sz.h * 4 + 5), sz); │ │ │ │ - this._addButton("zoomout", "zoom-minus-mini.png", centered.add(0, sz.h * 5 + 5), sz); │ │ │ │ - return this.div │ │ │ │ - }, │ │ │ │ - _addButton: function(id, img, xy, sz) { │ │ │ │ - var imgLocation = OpenLayers.Util.getImageLocation(img); │ │ │ │ - var btn = OpenLayers.Util.createAlphaImageDiv(this.id + "_" + id, xy, sz, imgLocation, "absolute"); │ │ │ │ - btn.style.cursor = "pointer"; │ │ │ │ - this.div.appendChild(btn); │ │ │ │ - btn.action = id; │ │ │ │ - btn.className = "olButton"; │ │ │ │ - this.buttons.push(btn); │ │ │ │ - return btn │ │ │ │ - }, │ │ │ │ - _removeButton: function(btn) { │ │ │ │ - this.div.removeChild(btn); │ │ │ │ - OpenLayers.Util.removeItem(this.buttons, btn) │ │ │ │ + eventsInstance.register("buttonclick", this, this.onZoomClick); │ │ │ │ + this.zoomInLink = zoomIn; │ │ │ │ + this.zoomOutLink = zoomOut; │ │ │ │ + return div │ │ │ │ }, │ │ │ │ - removeButtons: function() { │ │ │ │ - for (var i = this.buttons.length - 1; i >= 0; --i) { │ │ │ │ - this._removeButton(this.buttons[i]) │ │ │ │ + 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 │ │ │ │ } │ │ │ │ }, │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - var btn = evt.buttonElement; │ │ │ │ - switch (btn.action) { │ │ │ │ - case "panup": │ │ │ │ - this.map.pan(0, -this.getSlideFactor("h")); │ │ │ │ - break; │ │ │ │ - case "pandown": │ │ │ │ - this.map.pan(0, this.getSlideFactor("h")); │ │ │ │ - break; │ │ │ │ - case "panleft": │ │ │ │ - this.map.pan(-this.getSlideFactor("w"), 0); │ │ │ │ - break; │ │ │ │ - case "panright": │ │ │ │ - this.map.pan(this.getSlideFactor("w"), 0); │ │ │ │ - break; │ │ │ │ - case "zoomin": │ │ │ │ - this.map.zoomIn(); │ │ │ │ - break; │ │ │ │ - case "zoomout": │ │ │ │ - this.map.zoomOut(); │ │ │ │ - break; │ │ │ │ - case "zoomworld": │ │ │ │ - this.map.zoomToMaxExtent(); │ │ │ │ - break │ │ │ │ + onZoomClick: function(evt) { │ │ │ │ + var button = evt.buttonElement; │ │ │ │ + if (button === this.zoomInLink) { │ │ │ │ + this.map.zoomIn() │ │ │ │ + } else if (button === this.zoomOutLink) { │ │ │ │ + this.map.zoomOut() │ │ │ │ } │ │ │ │ }, │ │ │ │ - getSlideFactor: function(dim) { │ │ │ │ - return this.slideRatio ? this.map.getSize()[dim] * this.slideRatio : this.slideFactor │ │ │ │ + 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.PanZoom" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Zoom" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.PanZoom.X = 4; │ │ │ │ -OpenLayers.Control.PanZoom.Y = 4; │ │ │ │ -OpenLayers.Control.PanZoomBar = OpenLayers.Class(OpenLayers.Control.PanZoom, { │ │ │ │ - zoomStopWidth: 18, │ │ │ │ - zoomStopHeight: 11, │ │ │ │ - slider: null, │ │ │ │ - sliderEvents: null, │ │ │ │ - zoombarDiv: null, │ │ │ │ - zoomWorldIcon: false, │ │ │ │ - panIcons: true, │ │ │ │ - forceFixedZoomLevel: false, │ │ │ │ - mouseDragStart: null, │ │ │ │ - deltaY: null, │ │ │ │ - zoomStart: null, │ │ │ │ - destroy: function() { │ │ │ │ - this._removeZoomBar(); │ │ │ │ - this.map.events.un({ │ │ │ │ - changebaselayer: this.redraw, │ │ │ │ - updatesize: this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments); │ │ │ │ - delete this.mouseDragStart; │ │ │ │ - delete this.zoomStart │ │ │ │ +OpenLayers.Control.UTFGrid = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + autoActivate: true, │ │ │ │ + layers: null, │ │ │ │ + defaultHandlerOptions: { │ │ │ │ + delay: 300, │ │ │ │ + pixelTolerance: 4, │ │ │ │ + stopMove: false, │ │ │ │ + single: true, │ │ │ │ + double: false, │ │ │ │ + stopSingle: false, │ │ │ │ + stopDouble: false │ │ │ │ }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments); │ │ │ │ - this.map.events.on({ │ │ │ │ - changebaselayer: this.redraw, │ │ │ │ - updatesize: this.redraw, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ + handlerMode: "click", │ │ │ │ + setHandler: function(hm) { │ │ │ │ + this.handlerMode = hm; │ │ │ │ + this.resetHandler() │ │ │ │ }, │ │ │ │ - redraw: function() { │ │ │ │ - if (this.div != null) { │ │ │ │ - this.removeButtons(); │ │ │ │ - this._removeZoomBar() │ │ │ │ + resetHandler: function() { │ │ │ │ + if (this.handler) { │ │ │ │ + this.handler.deactivate(); │ │ │ │ + this.handler.destroy(); │ │ │ │ + this.handler = null │ │ │ │ } │ │ │ │ - this.draw() │ │ │ │ - }, │ │ │ │ - draw: function(px) { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - px = this.position.clone(); │ │ │ │ - this.buttons = []; │ │ │ │ - var sz = { │ │ │ │ - w: 18, │ │ │ │ - h: 18 │ │ │ │ - }; │ │ │ │ - if (this.panIcons) { │ │ │ │ - var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ - var wposition = sz.w; │ │ │ │ - if (this.zoomWorldIcon) { │ │ │ │ - centered = new OpenLayers.Pixel(px.x + sz.w, px.y) │ │ │ │ - } │ │ │ │ - this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ - px.y = centered.y + sz.h; │ │ │ │ - this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ - if (this.zoomWorldIcon) { │ │ │ │ - this._addButton("zoomworld", "zoom-world-mini.png", px.add(sz.w, 0), sz); │ │ │ │ - wposition *= 2 │ │ │ │ - } │ │ │ │ - this._addButton("panright", "east-mini.png", px.add(wposition, 0), sz); │ │ │ │ - this._addButton("pandown", "south-mini.png", centered.add(0, sz.h * 2), sz); │ │ │ │ - this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ - centered = this._addZoomBar(centered.add(0, sz.h * 4 + 5)); │ │ │ │ - this._addButton("zoomout", "zoom-minus-mini.png", centered, sz) │ │ │ │ - } else { │ │ │ │ - this._addButton("zoomin", "zoom-plus-mini.png", px, sz); │ │ │ │ - centered = this._addZoomBar(px.add(0, sz.h)); │ │ │ │ - this._addButton("zoomout", "zoom-minus-mini.png", centered, sz); │ │ │ │ - if (this.zoomWorldIcon) { │ │ │ │ - centered = centered.add(0, sz.h + 3); │ │ │ │ - this._addButton("zoomworld", "zoom-world-mini.png", centered, sz) │ │ │ │ - } │ │ │ │ + if (this.handlerMode == "hover") { │ │ │ │ + this.handler = new OpenLayers.Handler.Hover(this, { │ │ │ │ + pause: this.handleEvent, │ │ │ │ + move: this.reset │ │ │ │ + }, this.handlerOptions) │ │ │ │ + } else if (this.handlerMode == "click") { │ │ │ │ + this.handler = new OpenLayers.Handler.Click(this, { │ │ │ │ + click: this.handleEvent │ │ │ │ + }, this.handlerOptions) │ │ │ │ + } else if (this.handlerMode == "move") { │ │ │ │ + this.handler = new OpenLayers.Handler.Hover(this, { │ │ │ │ + pause: this.handleEvent, │ │ │ │ + move: this.handleEvent │ │ │ │ + }, this.handlerOptions) │ │ │ │ } │ │ │ │ - return this.div │ │ │ │ - }, │ │ │ │ - _addZoomBar: function(centered) { │ │ │ │ - var imgLocation = OpenLayers.Util.getImageLocation("slider.png"); │ │ │ │ - var id = this.id + "_" + this.map.id; │ │ │ │ - var minZoom = this.map.getMinZoom(); │ │ │ │ - var zoomsToEnd = this.map.getNumZoomLevels() - 1 - this.map.getZoom(); │ │ │ │ - var slider = OpenLayers.Util.createAlphaImageDiv(id, centered.add(-1, zoomsToEnd * this.zoomStopHeight), { │ │ │ │ - w: 20, │ │ │ │ - h: 9 │ │ │ │ - }, imgLocation, "absolute"); │ │ │ │ - slider.style.cursor = "move"; │ │ │ │ - this.slider = slider; │ │ │ │ - this.sliderEvents = new OpenLayers.Events(this, slider, null, true, { │ │ │ │ - includeXY: true │ │ │ │ - }); │ │ │ │ - this.sliderEvents.on({ │ │ │ │ - touchstart: this.zoomBarDown, │ │ │ │ - touchmove: this.zoomBarDrag, │ │ │ │ - touchend: this.zoomBarUp, │ │ │ │ - mousedown: this.zoomBarDown, │ │ │ │ - mousemove: this.zoomBarDrag, │ │ │ │ - mouseup: this.zoomBarUp │ │ │ │ - }); │ │ │ │ - var sz = { │ │ │ │ - w: this.zoomStopWidth, │ │ │ │ - h: this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom) │ │ │ │ - }; │ │ │ │ - var imgLocation = OpenLayers.Util.getImageLocation("zoombar.png"); │ │ │ │ - var div = null; │ │ │ │ - if (OpenLayers.Util.alphaHack()) { │ │ │ │ - var id = this.id + "_" + this.map.id; │ │ │ │ - div = OpenLayers.Util.createAlphaImageDiv(id, centered, { │ │ │ │ - w: sz.w, │ │ │ │ - h: this.zoomStopHeight │ │ │ │ - }, imgLocation, "absolute", null, "crop"); │ │ │ │ - div.style.height = sz.h + "px" │ │ │ │ + if (this.handler) { │ │ │ │ + return true │ │ │ │ } else { │ │ │ │ - div = OpenLayers.Util.createDiv("OpenLayers_Control_PanZoomBar_Zoombar" + this.map.id, centered, sz, imgLocation) │ │ │ │ - } │ │ │ │ - div.style.cursor = "pointer"; │ │ │ │ - div.className = "olButton"; │ │ │ │ - this.zoombarDiv = div; │ │ │ │ - this.div.appendChild(div); │ │ │ │ - this.startTop = parseInt(div.style.top); │ │ │ │ - this.div.appendChild(slider); │ │ │ │ - this.map.events.register("zoomend", this, this.moveZoomBar); │ │ │ │ - centered = centered.add(0, this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom)); │ │ │ │ - return centered │ │ │ │ - }, │ │ │ │ - _removeZoomBar: function() { │ │ │ │ - this.sliderEvents.un({ │ │ │ │ - touchstart: this.zoomBarDown, │ │ │ │ - touchmove: this.zoomBarDrag, │ │ │ │ - touchend: this.zoomBarUp, │ │ │ │ - mousedown: this.zoomBarDown, │ │ │ │ - mousemove: this.zoomBarDrag, │ │ │ │ - mouseup: this.zoomBarUp │ │ │ │ - }); │ │ │ │ - this.sliderEvents.destroy(); │ │ │ │ - this.div.removeChild(this.zoombarDiv); │ │ │ │ - this.zoombarDiv = null; │ │ │ │ - this.div.removeChild(this.slider); │ │ │ │ - this.slider = null; │ │ │ │ - this.map.events.unregister("zoomend", this, this.moveZoomBar) │ │ │ │ - }, │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this, arguments); │ │ │ │ - if (evt.buttonElement === this.zoombarDiv) { │ │ │ │ - var levels = evt.buttonXY.y / this.zoomStopHeight; │ │ │ │ - if (this.forceFixedZoomLevel || !this.map.fractionalZoom) { │ │ │ │ - levels = Math.floor(levels) │ │ │ │ - } │ │ │ │ - var zoom = this.map.getNumZoomLevels() - 1 - levels; │ │ │ │ - zoom = Math.min(Math.max(zoom, 0), this.map.getNumZoomLevels() - 1); │ │ │ │ - this.map.zoomTo(zoom) │ │ │ │ + return false │ │ │ │ } │ │ │ │ }, │ │ │ │ - passEventToSlider: function(evt) { │ │ │ │ - this.sliderEvents.handleBrowserEvent(evt) │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + options.handlerOptions = options.handlerOptions || this.defaultHandlerOptions; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.resetHandler() │ │ │ │ }, │ │ │ │ - zoomBarDown: function(evt) { │ │ │ │ - if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ + handleEvent: function(evt) { │ │ │ │ + if (evt == null) { │ │ │ │ + this.reset(); │ │ │ │ return │ │ │ │ } │ │ │ │ - this.map.events.on({ │ │ │ │ - touchmove: this.passEventToSlider, │ │ │ │ - mousemove: this.passEventToSlider, │ │ │ │ - mouseup: this.passEventToSlider, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.mouseDragStart = evt.xy.clone(); │ │ │ │ - this.zoomStart = evt.xy.clone(); │ │ │ │ - this.div.style.cursor = "move"; │ │ │ │ - this.zoombarDiv.offsets = null; │ │ │ │ - OpenLayers.Event.stop(evt) │ │ │ │ - }, │ │ │ │ - zoomBarDrag: function(evt) { │ │ │ │ - if (this.mouseDragStart != null) { │ │ │ │ - var deltaY = this.mouseDragStart.y - evt.xy.y; │ │ │ │ - var offsets = OpenLayers.Util.pagePosition(this.zoombarDiv); │ │ │ │ - if (evt.clientY - offsets[1] > 0 && evt.clientY - offsets[1] < parseInt(this.zoombarDiv.style.height) - 2) { │ │ │ │ - var newTop = parseInt(this.slider.style.top) - deltaY; │ │ │ │ - this.slider.style.top = newTop + "px"; │ │ │ │ - this.mouseDragStart = evt.xy.clone() │ │ │ │ - } │ │ │ │ - this.deltaY = this.zoomStart.y - evt.xy.y; │ │ │ │ - OpenLayers.Event.stop(evt) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - zoomBarUp: function(evt) { │ │ │ │ - if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") { │ │ │ │ + var lonLat = this.map.getLonLatFromPixel(evt.xy); │ │ │ │ + if (!lonLat) { │ │ │ │ return │ │ │ │ } │ │ │ │ - if (this.mouseDragStart) { │ │ │ │ - this.div.style.cursor = ""; │ │ │ │ - this.map.events.un({ │ │ │ │ - touchmove: this.passEventToSlider, │ │ │ │ - mouseup: this.passEventToSlider, │ │ │ │ - mousemove: this.passEventToSlider, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - var zoomLevel = this.map.zoom; │ │ │ │ - if (!this.forceFixedZoomLevel && this.map.fractionalZoom) { │ │ │ │ - zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ - zoomLevel = Math.min(Math.max(zoomLevel, 0), this.map.getNumZoomLevels() - 1) │ │ │ │ - } else { │ │ │ │ - zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ - zoomLevel = Math.max(Math.round(zoomLevel), 0) │ │ │ │ + var layers = this.findLayers(); │ │ │ │ + if (layers.length > 0) { │ │ │ │ + var infoLookup = {}; │ │ │ │ + var layer, idx; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + layer = layers[i]; │ │ │ │ + idx = OpenLayers.Util.indexOf(this.map.layers, layer); │ │ │ │ + infoLookup[idx] = layer.getFeatureInfo(lonLat) │ │ │ │ } │ │ │ │ - this.map.zoomTo(zoomLevel); │ │ │ │ - this.mouseDragStart = null; │ │ │ │ - this.zoomStart = null; │ │ │ │ - this.deltaY = 0; │ │ │ │ - OpenLayers.Event.stop(evt) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - moveZoomBar: function() { │ │ │ │ - var newTop = (this.map.getNumZoomLevels() - 1 - this.map.getZoom()) * this.zoomStopHeight + this.startTop + 1; │ │ │ │ - this.slider.style.top = newTop + "px" │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.PanZoomBar" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.Pinch = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - started: false, │ │ │ │ - stopDown: false, │ │ │ │ - pinching: false, │ │ │ │ - last: null, │ │ │ │ - start: null, │ │ │ │ - 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) { │ │ │ │ - return false │ │ │ │ - } else { │ │ │ │ - this.started = false; │ │ │ │ - this.start = null; │ │ │ │ - this.last = null │ │ │ │ - } │ │ │ │ - OpenLayers.Event.preventDefault(evt); │ │ │ │ - return 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; │ │ │ │ - OpenLayers.Event.stop(evt) │ │ │ │ - } else if (this.started) { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.pinching = false; │ │ │ │ - activated = true │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ + this.callback(infoLookup, lonLat, evt.xy) │ │ │ │ } │ │ │ │ - return deactivated │ │ │ │ }, │ │ │ │ - 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)) │ │ │ │ + callback: function(infoLookup) {}, │ │ │ │ + reset: function(evt) { │ │ │ │ + this.callback(null) │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + findLayers: function() { │ │ │ │ + var candidates = this.layers || this.map.layers; │ │ │ │ + var layers = []; │ │ │ │ + var layer; │ │ │ │ + for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ + layer = candidates[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.UTFGrid) { │ │ │ │ + layers.push(layer) │ │ │ │ + } │ │ │ │ } │ │ │ │ + return layers │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Pinch" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.UTFGrid" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ - pinchOrigin: null, │ │ │ │ - currentCenter: null, │ │ │ │ - autoActivate: true, │ │ │ │ - preserveCenter: false, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - pinchStart: function(evt, pinchData) { │ │ │ │ - var xy = this.preserveCenter ? this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; │ │ │ │ - this.pinchOrigin = xy; │ │ │ │ - this.currentCenter = xy │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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); │ │ │ │ - this.map.div.clientWidth = this.map.div.clientWidth; │ │ │ │ - this.map.setCenter(location, zoom) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.PinchZoom" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.ZoomIn = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ - trigger: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.zoomIn() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomIn" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.ScaleLine = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - maxWidth: 100, │ │ │ │ - topOutUnits: "km", │ │ │ │ - topInUnits: "m", │ │ │ │ - bottomOutUnits: "mi", │ │ │ │ - bottomInUnits: "ft", │ │ │ │ - eTop: null, │ │ │ │ - eBottom: null, │ │ │ │ - geodesic: false, │ │ │ │ + out: false, │ │ │ │ + keyMask: null, │ │ │ │ + alwaysZoom: false, │ │ │ │ + zoomOnClick: true, │ │ │ │ draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (!this.eTop) { │ │ │ │ - this.eTop = document.createElement("div"); │ │ │ │ - this.eTop.className = this.displayClass + "Top"; │ │ │ │ - var theLen = this.topInUnits.length; │ │ │ │ - this.div.appendChild(this.eTop); │ │ │ │ - if (this.topOutUnits == "" || this.topInUnits == "") { │ │ │ │ - this.eTop.style.visibility = "hidden" │ │ │ │ + this.handler = new OpenLayers.Handler.Box(this, { │ │ │ │ + done: this.zoomBox │ │ │ │ + }, { │ │ │ │ + keyMask: this.keyMask │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + zoomBox: function(position) { │ │ │ │ + if (position instanceof OpenLayers.Bounds) { │ │ │ │ + var bounds, targetCenterPx = position.getCenterPixel(); │ │ │ │ + if (!this.out) { │ │ │ │ + var minXY = this.map.getLonLatFromPixel({ │ │ │ │ + x: position.left, │ │ │ │ + y: position.bottom │ │ │ │ + }); │ │ │ │ + var maxXY = this.map.getLonLatFromPixel({ │ │ │ │ + x: position.right, │ │ │ │ + y: position.top │ │ │ │ + }); │ │ │ │ + bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat, maxXY.lon, maxXY.lat) │ │ │ │ + } else { │ │ │ │ + var pixWidth = position.right - position.left; │ │ │ │ + var pixHeight = position.bottom - position.top; │ │ │ │ + var zoomFactor = Math.min(this.map.size.h / pixHeight, this.map.size.w / pixWidth); │ │ │ │ + var extent = this.map.getExtent(); │ │ │ │ + var center = this.map.getLonLatFromPixel(targetCenterPx); │ │ │ │ + var xmin = center.lon - extent.getWidth() / 2 * zoomFactor; │ │ │ │ + var xmax = center.lon + extent.getWidth() / 2 * zoomFactor; │ │ │ │ + var ymin = center.lat - extent.getHeight() / 2 * zoomFactor; │ │ │ │ + var ymax = center.lat + extent.getHeight() / 2 * zoomFactor; │ │ │ │ + bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax) │ │ │ │ + } │ │ │ │ + var lastZoom = this.map.getZoom(), │ │ │ │ + size = this.map.getSize(), │ │ │ │ + centerPx = { │ │ │ │ + x: size.w / 2, │ │ │ │ + y: size.h / 2 │ │ │ │ + }, │ │ │ │ + zoom = this.map.getZoomForExtent(bounds), │ │ │ │ + oldRes = this.map.getResolution(), │ │ │ │ + newRes = this.map.getResolutionForZoom(zoom); │ │ │ │ + if (oldRes == newRes) { │ │ │ │ + this.map.setCenter(this.map.getLonLatFromPixel(targetCenterPx)) │ │ │ │ } else { │ │ │ │ - this.eTop.style.visibility = "visible" │ │ │ │ + var zoomOriginPx = { │ │ │ │ + x: (oldRes * targetCenterPx.x - newRes * centerPx.x) / (oldRes - newRes), │ │ │ │ + y: (oldRes * targetCenterPx.y - newRes * centerPx.y) / (oldRes - newRes) │ │ │ │ + }; │ │ │ │ + this.map.zoomTo(zoom, zoomOriginPx) │ │ │ │ } │ │ │ │ - this.eBottom = document.createElement("div"); │ │ │ │ - this.eBottom.className = this.displayClass + "Bottom"; │ │ │ │ - this.div.appendChild(this.eBottom); │ │ │ │ - if (this.bottomOutUnits == "" || this.bottomInUnits == "") { │ │ │ │ - this.eBottom.style.visibility = "hidden" │ │ │ │ + if (lastZoom == this.map.getZoom() && this.alwaysZoom == true) { │ │ │ │ + this.map.zoomTo(lastZoom + (this.out ? -1 : 1)) │ │ │ │ + } │ │ │ │ + } else if (this.zoomOnClick) { │ │ │ │ + if (!this.out) { │ │ │ │ + this.map.zoomTo(this.map.getZoom() + 1, position) │ │ │ │ } else { │ │ │ │ - this.eBottom.style.visibility = "visible" │ │ │ │ + this.map.zoomTo(this.map.getZoom() - 1, position) │ │ │ │ } │ │ │ │ } │ │ │ │ - this.map.events.register("moveend", this, this.update); │ │ │ │ - this.update(); │ │ │ │ - return this.div │ │ │ │ }, │ │ │ │ - getBarLen: function(maxLen) { │ │ │ │ - var digits = parseInt(Math.log(maxLen) / Math.log(10)); │ │ │ │ - var pow10 = Math.pow(10, digits); │ │ │ │ - var firstChar = parseInt(maxLen / pow10); │ │ │ │ - var barLen; │ │ │ │ - if (firstChar > 5) { │ │ │ │ - barLen = 5 │ │ │ │ - } else if (firstChar > 2) { │ │ │ │ - barLen = 2 │ │ │ │ - } else { │ │ │ │ - barLen = 1 │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomBox" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + dragPan: null, │ │ │ │ + dragPanOptions: null, │ │ │ │ + pinchZoom: null, │ │ │ │ + pinchZoomOptions: null, │ │ │ │ + documentDrag: false, │ │ │ │ + zoomBox: null, │ │ │ │ + zoomBoxEnabled: true, │ │ │ │ + zoomWheelEnabled: true, │ │ │ │ + mouseWheelOptions: null, │ │ │ │ + handleRightClicks: false, │ │ │ │ + zoomBoxKeyMask: OpenLayers.Handler.MOD_SHIFT, │ │ │ │ + autoActivate: true, │ │ │ │ + initialize: function(options) { │ │ │ │ + this.handlers = {}; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + if (this.dragPan) { │ │ │ │ + this.dragPan.destroy() │ │ │ │ } │ │ │ │ - return barLen * pow10 │ │ │ │ + this.dragPan = null; │ │ │ │ + if (this.zoomBox) { │ │ │ │ + this.zoomBox.destroy() │ │ │ │ + } │ │ │ │ + this.zoomBox = null; │ │ │ │ + if (this.pinchZoom) { │ │ │ │ + this.pinchZoom.destroy() │ │ │ │ + } │ │ │ │ + this.pinchZoom = null; │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ - update: function() { │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - if (!res) { │ │ │ │ - return │ │ │ │ + activate: function() { │ │ │ │ + this.dragPan.activate(); │ │ │ │ + if (this.zoomWheelEnabled) { │ │ │ │ + this.handlers.wheel.activate() │ │ │ │ } │ │ │ │ - var curMapUnits = this.map.getUnits(); │ │ │ │ - var inches = OpenLayers.INCHES_PER_UNIT; │ │ │ │ - var maxSizeData = this.maxWidth * res * inches[curMapUnits]; │ │ │ │ - var geodesicRatio = 1; │ │ │ │ - if (this.geodesic === true) { │ │ │ │ - var maxSizeGeodesic = (this.map.getGeodesicPixelSize().w || 1e-6) * this.maxWidth; │ │ │ │ - var maxSizeKilometers = maxSizeData / inches["km"]; │ │ │ │ - geodesicRatio = maxSizeGeodesic / maxSizeKilometers; │ │ │ │ - maxSizeData *= geodesicRatio │ │ │ │ + this.handlers.click.activate(); │ │ │ │ + if (this.zoomBoxEnabled) { │ │ │ │ + this.zoomBox.activate() │ │ │ │ } │ │ │ │ - var topUnits; │ │ │ │ - var bottomUnits; │ │ │ │ - if (maxSizeData > 1e5) { │ │ │ │ - topUnits = this.topOutUnits; │ │ │ │ - bottomUnits = this.bottomOutUnits │ │ │ │ - } else { │ │ │ │ - topUnits = this.topInUnits; │ │ │ │ - bottomUnits = this.bottomInUnits │ │ │ │ + if (this.pinchZoom) { │ │ │ │ + this.pinchZoom.activate() │ │ │ │ } │ │ │ │ - var topMax = maxSizeData / inches[topUnits]; │ │ │ │ - var bottomMax = maxSizeData / inches[bottomUnits]; │ │ │ │ - var topRounded = this.getBarLen(topMax); │ │ │ │ - var bottomRounded = this.getBarLen(bottomMax); │ │ │ │ - topMax = topRounded / inches[curMapUnits] * inches[topUnits]; │ │ │ │ - bottomMax = bottomRounded / inches[curMapUnits] * inches[bottomUnits]; │ │ │ │ - var topPx = topMax / res / geodesicRatio; │ │ │ │ - var bottomPx = bottomMax / res / geodesicRatio; │ │ │ │ - if (this.eBottom.style.visibility == "visible") { │ │ │ │ - this.eBottom.style.width = Math.round(bottomPx) + "px"; │ │ │ │ - this.eBottom.innerHTML = bottomRounded + " " + bottomUnits │ │ │ │ + return OpenLayers.Control.prototype.activate.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (this.pinchZoom) { │ │ │ │ + this.pinchZoom.deactivate() │ │ │ │ } │ │ │ │ - if (this.eTop.style.visibility == "visible") { │ │ │ │ - this.eTop.style.width = Math.round(topPx) + "px"; │ │ │ │ - this.eTop.innerHTML = topRounded + " " + topUnits │ │ │ │ + this.zoomBox.deactivate(); │ │ │ │ + this.dragPan.deactivate(); │ │ │ │ + this.handlers.click.deactivate(); │ │ │ │ + this.handlers.wheel.deactivate(); │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + draw: function() { │ │ │ │ + if (this.handleRightClicks) { │ │ │ │ + this.map.viewPortDiv.oncontextmenu = OpenLayers.Function.False │ │ │ │ + } │ │ │ │ + var clickCallbacks = { │ │ │ │ + click: this.defaultClick, │ │ │ │ + dblclick: this.defaultDblClick, │ │ │ │ + dblrightclick: this.defaultDblRightClick │ │ │ │ + }; │ │ │ │ + var clickOptions = { │ │ │ │ + double: true, │ │ │ │ + stopDouble: true │ │ │ │ + }; │ │ │ │ + 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.zoomBox = new OpenLayers.Control.ZoomBox({ │ │ │ │ + map: this.map, │ │ │ │ + keyMask: this.zoomBoxKeyMask │ │ │ │ + }); │ │ │ │ + this.dragPan.draw(); │ │ │ │ + this.zoomBox.draw(); │ │ │ │ + var wheelOptions = this.map.fractionalZoom ? {} : { │ │ │ │ + cumulative: false, │ │ │ │ + interval: 50, │ │ │ │ + maxDelta: 6 │ │ │ │ + }; │ │ │ │ + this.handlers.wheel = new OpenLayers.Handler.MouseWheel(this, { │ │ │ │ + up: this.wheelUp, │ │ │ │ + down: this.wheelDown │ │ │ │ + }, OpenLayers.Util.extend(wheelOptions, this.mouseWheelOptions)); │ │ │ │ + if (OpenLayers.Control.PinchZoom) { │ │ │ │ + this.pinchZoom = new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({ │ │ │ │ + map: this.map │ │ │ │ + }, this.pinchZoomOptions)) │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ScaleLine" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - delay: 500, │ │ │ │ - pixelTolerance: null, │ │ │ │ - stopMove: false, │ │ │ │ - px: null, │ │ │ │ - timerId: null, │ │ │ │ - mousemove: function(evt) { │ │ │ │ - if (this.passesTolerance(evt.xy)) { │ │ │ │ - this.clearTimer(); │ │ │ │ - this.callback("move", [evt]); │ │ │ │ - this.px = evt.xy; │ │ │ │ - evt = OpenLayers.Util.extend({}, evt); │ │ │ │ - this.timerId = window.setTimeout(OpenLayers.Function.bind(this.delayedCall, this, evt), this.delay) │ │ │ │ + defaultClick: function(evt) { │ │ │ │ + if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ + this.map.zoomOut() │ │ │ │ } │ │ │ │ - return !this.stopMove │ │ │ │ }, │ │ │ │ - mouseout: function(evt) { │ │ │ │ - if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ - this.clearTimer(); │ │ │ │ - this.callback("move", [evt]) │ │ │ │ + defaultDblClick: function(evt) { │ │ │ │ + this.map.zoomTo(this.map.zoom + 1, evt.xy) │ │ │ │ + }, │ │ │ │ + defaultDblRightClick: function(evt) { │ │ │ │ + this.map.zoomTo(this.map.zoom - 1, evt.xy) │ │ │ │ + }, │ │ │ │ + wheelChange: function(evt, deltaZ) { │ │ │ │ + if (!this.map.fractionalZoom) { │ │ │ │ + deltaZ = Math.round(deltaZ) │ │ │ │ } │ │ │ │ - return true │ │ │ │ + var currentZoom = this.map.getZoom(), │ │ │ │ + newZoom = currentZoom + deltaZ; │ │ │ │ + newZoom = Math.max(newZoom, 0); │ │ │ │ + newZoom = Math.min(newZoom, this.map.getNumZoomLevels()); │ │ │ │ + if (newZoom === currentZoom) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + this.map.zoomTo(newZoom, evt.xy) │ │ │ │ }, │ │ │ │ - passesTolerance: function(px) { │ │ │ │ - var passes = true; │ │ │ │ - if (this.pixelTolerance && this.px) { │ │ │ │ - var dpx = Math.sqrt(Math.pow(this.px.x - px.x, 2) + Math.pow(this.px.y - px.y, 2)); │ │ │ │ - if (dpx < this.pixelTolerance) { │ │ │ │ - passes = false │ │ │ │ - } │ │ │ │ + wheelUp: function(evt, delta) { │ │ │ │ + this.wheelChange(evt, delta || 1) │ │ │ │ + }, │ │ │ │ + wheelDown: function(evt, delta) { │ │ │ │ + this.wheelChange(evt, delta || -1) │ │ │ │ + }, │ │ │ │ + disableZoomBox: function() { │ │ │ │ + this.zoomBoxEnabled = false; │ │ │ │ + this.zoomBox.deactivate() │ │ │ │ + }, │ │ │ │ + enableZoomBox: function() { │ │ │ │ + this.zoomBoxEnabled = true; │ │ │ │ + if (this.active) { │ │ │ │ + this.zoomBox.activate() │ │ │ │ } │ │ │ │ - return passes │ │ │ │ }, │ │ │ │ - clearTimer: function() { │ │ │ │ - if (this.timerId != null) { │ │ │ │ - window.clearTimeout(this.timerId); │ │ │ │ - this.timerId = null │ │ │ │ + disableZoomWheel: function() { │ │ │ │ + this.zoomWheelEnabled = false; │ │ │ │ + this.handlers.wheel.deactivate() │ │ │ │ + }, │ │ │ │ + enableZoomWheel: function() { │ │ │ │ + this.zoomWheelEnabled = true; │ │ │ │ + if (this.active) { │ │ │ │ + this.handlers.wheel.activate() │ │ │ │ } │ │ │ │ }, │ │ │ │ - delayedCall: function(evt) { │ │ │ │ - this.callback("pause", [evt]) │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Navigation" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.NavToolbar = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ + this.addControls([new OpenLayers.Control.Navigation, new OpenLayers.Control.ZoomBox]) │ │ │ │ }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = false; │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - this.clearTimer(); │ │ │ │ - deactivated = true │ │ │ │ + draw: function() { │ │ │ │ + var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments); │ │ │ │ + if (this.defaultControl === null) { │ │ │ │ + this.defaultControl = this.controls[0] │ │ │ │ } │ │ │ │ - return deactivated │ │ │ │ + return div │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Hover" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.NavToolbar" │ │ │ │ }); │ │ │ │ OpenLayers.Format.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ layerIdentifier: "_layer", │ │ │ │ featureIdentifier: "_feature", │ │ │ │ regExes: { │ │ │ │ trimSpace: /^\s*|\s*$/g, │ │ │ │ removeSpace: /\s*/g, │ │ │ │ @@ -23269,380 +26754,138 @@ │ │ │ │ delete this._requestCount; │ │ │ │ delete this._numRequests │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.WMSGetFeatureInfo" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - element: null, │ │ │ │ - ovmap: null, │ │ │ │ - size: { │ │ │ │ - w: 180, │ │ │ │ - h: 90 │ │ │ │ - }, │ │ │ │ - layers: null, │ │ │ │ - minRectSize: 15, │ │ │ │ - minRectDisplayClass: "RectReplacement", │ │ │ │ - minRatio: 8, │ │ │ │ - maxRatio: 32, │ │ │ │ - mapOptions: null, │ │ │ │ - autoPan: false, │ │ │ │ - handlers: null, │ │ │ │ - resolutionFactor: 1, │ │ │ │ - maximized: false, │ │ │ │ - maximizeTitle: "", │ │ │ │ - minimizeTitle: "", │ │ │ │ - initialize: function(options) { │ │ │ │ - this.layers = []; │ │ │ │ - this.handlers = {}; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (!this.mapDiv) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - if (this.handlers.click) { │ │ │ │ - this.handlers.click.destroy() │ │ │ │ - } │ │ │ │ - if (this.handlers.drag) { │ │ │ │ - this.handlers.drag.destroy() │ │ │ │ - } │ │ │ │ - this.ovmap && this.ovmap.viewPortDiv.removeChild(this.extentRectangle); │ │ │ │ - this.extentRectangle = null; │ │ │ │ - if (this.rectEvents) { │ │ │ │ - this.rectEvents.destroy(); │ │ │ │ - this.rectEvents = null │ │ │ │ - } │ │ │ │ - if (this.ovmap) { │ │ │ │ - this.ovmap.destroy(); │ │ │ │ - this.ovmap = null │ │ │ │ - } │ │ │ │ - this.element.removeChild(this.mapDiv); │ │ │ │ - this.mapDiv = null; │ │ │ │ - this.div.removeChild(this.element); │ │ │ │ - this.element = null; │ │ │ │ - if (this.maximizeDiv) { │ │ │ │ - this.div.removeChild(this.maximizeDiv); │ │ │ │ - this.maximizeDiv = null │ │ │ │ - } │ │ │ │ - if (this.minimizeDiv) { │ │ │ │ - this.div.removeChild(this.minimizeDiv); │ │ │ │ - this.minimizeDiv = null │ │ │ │ - } │ │ │ │ - this.map.events.un({ │ │ │ │ - buttonclick: this.onButtonClick, │ │ │ │ - moveend: this.update, │ │ │ │ - changebaselayer: this.baseLayerDraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (this.layers.length === 0) { │ │ │ │ - if (this.map.baseLayer) { │ │ │ │ - var layer = this.map.baseLayer.clone(); │ │ │ │ - this.layers = [layer] │ │ │ │ - } else { │ │ │ │ - this.map.events.register("changebaselayer", this, this.baseLayerDraw); │ │ │ │ - return this.div │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.element = document.createElement("div"); │ │ │ │ - this.element.className = this.displayClass + "Element"; │ │ │ │ - this.element.style.display = "none"; │ │ │ │ - this.mapDiv = document.createElement("div"); │ │ │ │ - this.mapDiv.style.width = this.size.w + "px"; │ │ │ │ - this.mapDiv.style.height = this.size.h + "px"; │ │ │ │ - this.mapDiv.style.position = "relative"; │ │ │ │ - this.mapDiv.style.overflow = "hidden"; │ │ │ │ - this.mapDiv.id = OpenLayers.Util.createUniqueID("overviewMap"); │ │ │ │ - this.extentRectangle = document.createElement("div"); │ │ │ │ - this.extentRectangle.style.position = "absolute"; │ │ │ │ - this.extentRectangle.style.zIndex = 1e3; │ │ │ │ - this.extentRectangle.className = this.displayClass + "ExtentRectangle"; │ │ │ │ - this.element.appendChild(this.mapDiv); │ │ │ │ - this.div.appendChild(this.element); │ │ │ │ - if (!this.outsideViewport) { │ │ │ │ - this.div.className += " " + this.displayClass + "Container"; │ │ │ │ - var img = OpenLayers.Util.getImageLocation("layer-switcher-maximize.png"); │ │ │ │ - this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(this.displayClass + "MaximizeButton", null, null, img, "absolute"); │ │ │ │ - this.maximizeDiv.style.display = "none"; │ │ │ │ - this.maximizeDiv.className = this.displayClass + "MaximizeButton olButton"; │ │ │ │ - if (this.maximizeTitle) { │ │ │ │ - this.maximizeDiv.title = this.maximizeTitle │ │ │ │ - } │ │ │ │ - this.div.appendChild(this.maximizeDiv); │ │ │ │ - var img = OpenLayers.Util.getImageLocation("layer-switcher-minimize.png"); │ │ │ │ - this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_minimizeDiv", null, null, img, "absolute"); │ │ │ │ - this.minimizeDiv.style.display = "none"; │ │ │ │ - this.minimizeDiv.className = this.displayClass + "MinimizeButton olButton"; │ │ │ │ - if (this.minimizeTitle) { │ │ │ │ - this.minimizeDiv.title = this.minimizeTitle │ │ │ │ - } │ │ │ │ - this.div.appendChild(this.minimizeDiv); │ │ │ │ - this.minimizeControl() │ │ │ │ - } else { │ │ │ │ - this.element.style.display = "" │ │ │ │ - } │ │ │ │ - if (this.map.getExtent()) { │ │ │ │ - this.update() │ │ │ │ - } │ │ │ │ - this.map.events.on({ │ │ │ │ - buttonclick: this.onButtonClick, │ │ │ │ - moveend: this.update, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - if (this.maximized) { │ │ │ │ - this.maximizeControl() │ │ │ │ - } │ │ │ │ - return this.div │ │ │ │ - }, │ │ │ │ - baseLayerDraw: function() { │ │ │ │ - this.draw(); │ │ │ │ - this.map.events.unregister("changebaselayer", this, this.baseLayerDraw) │ │ │ │ - }, │ │ │ │ - rectDrag: function(px) { │ │ │ │ - var deltaX = this.handlers.drag.last.x - px.x; │ │ │ │ - var deltaY = this.handlers.drag.last.y - px.y; │ │ │ │ - if (deltaX != 0 || deltaY != 0) { │ │ │ │ - var rectTop = this.rectPxBounds.top; │ │ │ │ - var rectLeft = this.rectPxBounds.left; │ │ │ │ - var rectHeight = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ - var rectWidth = this.rectPxBounds.getWidth(); │ │ │ │ - var newTop = Math.max(0, rectTop - deltaY); │ │ │ │ - newTop = Math.min(newTop, this.ovmap.size.h - this.hComp - rectHeight); │ │ │ │ - var newLeft = Math.max(0, rectLeft - deltaX); │ │ │ │ - newLeft = Math.min(newLeft, this.ovmap.size.w - this.wComp - rectWidth); │ │ │ │ - this.setRectPxBounds(new OpenLayers.Bounds(newLeft, newTop + rectHeight, newLeft + rectWidth, newTop)) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - mapDivClick: function(evt) { │ │ │ │ - var pxCenter = this.rectPxBounds.getCenterPixel(); │ │ │ │ - var deltaX = evt.xy.x - pxCenter.x; │ │ │ │ - var deltaY = evt.xy.y - pxCenter.y; │ │ │ │ - var top = this.rectPxBounds.top; │ │ │ │ - var left = this.rectPxBounds.left; │ │ │ │ - var height = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ - var width = this.rectPxBounds.getWidth(); │ │ │ │ - var newTop = Math.max(0, top + deltaY); │ │ │ │ - newTop = Math.min(newTop, this.ovmap.size.h - height); │ │ │ │ - var newLeft = Math.max(0, left + deltaX); │ │ │ │ - newLeft = Math.min(newLeft, this.ovmap.size.w - width); │ │ │ │ - this.setRectPxBounds(new OpenLayers.Bounds(newLeft, newTop + height, newLeft + width, newTop)); │ │ │ │ - this.updateMapToRect() │ │ │ │ - }, │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - if (evt.buttonElement === this.minimizeDiv) { │ │ │ │ - this.minimizeControl() │ │ │ │ - } else if (evt.buttonElement === this.maximizeDiv) { │ │ │ │ - this.maximizeControl() │ │ │ │ +OpenLayers.Control.DragFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + geometryTypes: null, │ │ │ │ + onStart: function(feature, pixel) {}, │ │ │ │ + onDrag: function(feature, pixel) {}, │ │ │ │ + onComplete: function(feature, pixel) {}, │ │ │ │ + onEnter: function(feature) {}, │ │ │ │ + onLeave: function(feature) {}, │ │ │ │ + documentDrag: false, │ │ │ │ + layer: null, │ │ │ │ + feature: null, │ │ │ │ + dragCallbacks: {}, │ │ │ │ + featureCallbacks: {}, │ │ │ │ + lastPixel: null, │ │ │ │ + initialize: function(layer, options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.layer = layer; │ │ │ │ + this.handlers = { │ │ │ │ + drag: new OpenLayers.Handler.Drag(this, OpenLayers.Util.extend({ │ │ │ │ + down: this.downFeature, │ │ │ │ + move: this.moveFeature, │ │ │ │ + up: this.upFeature, │ │ │ │ + out: this.cancel, │ │ │ │ + done: this.doneDragging │ │ │ │ + }, this.dragCallbacks), { │ │ │ │ + documentDrag: this.documentDrag │ │ │ │ + }), │ │ │ │ + feature: new OpenLayers.Handler.Feature(this, this.layer, OpenLayers.Util.extend({ │ │ │ │ + click: this.clickFeature, │ │ │ │ + clickout: this.clickoutFeature, │ │ │ │ + over: this.overFeature, │ │ │ │ + out: this.outFeature │ │ │ │ + }, this.featureCallbacks), { │ │ │ │ + geometryTypes: this.geometryTypes │ │ │ │ + }) │ │ │ │ } │ │ │ │ }, │ │ │ │ - maximizeControl: function(e) { │ │ │ │ - this.element.style.display = ""; │ │ │ │ - this.showToggle(false); │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e) │ │ │ │ + clickFeature: function(feature) { │ │ │ │ + if (this.handlers.feature.touch && !this.over && this.overFeature(feature)) { │ │ │ │ + this.handlers.drag.dragstart(this.handlers.feature.evt); │ │ │ │ + this.handlers.drag.stopDown = false │ │ │ │ } │ │ │ │ }, │ │ │ │ - minimizeControl: function(e) { │ │ │ │ - this.element.style.display = "none"; │ │ │ │ - this.showToggle(true); │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e) │ │ │ │ + clickoutFeature: function(feature) { │ │ │ │ + if (this.handlers.feature.touch && this.over) { │ │ │ │ + this.outFeature(feature); │ │ │ │ + this.handlers.drag.stopDown = true │ │ │ │ } │ │ │ │ }, │ │ │ │ - showToggle: function(minimize) { │ │ │ │ - if (this.maximizeDiv) { │ │ │ │ - this.maximizeDiv.style.display = minimize ? "" : "none" │ │ │ │ - } │ │ │ │ - if (this.minimizeDiv) { │ │ │ │ - this.minimizeDiv.style.display = minimize ? "none" : "" │ │ │ │ - } │ │ │ │ + destroy: function() { │ │ │ │ + this.layer = null; │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, []) │ │ │ │ }, │ │ │ │ - update: function() { │ │ │ │ - if (this.ovmap == null) { │ │ │ │ - this.createMap() │ │ │ │ - } │ │ │ │ - if (this.autoPan || !this.isSuitableOverview()) { │ │ │ │ - this.updateOverview() │ │ │ │ - } │ │ │ │ - this.updateRectToMap() │ │ │ │ + activate: function() { │ │ │ │ + return this.handlers.feature.activate() && OpenLayers.Control.prototype.activate.apply(this, arguments) │ │ │ │ }, │ │ │ │ - isSuitableOverview: function() { │ │ │ │ - var mapExtent = this.map.getExtent(); │ │ │ │ - var maxExtent = this.map.getMaxExtent(); │ │ │ │ - var testExtent = new OpenLayers.Bounds(Math.max(mapExtent.left, maxExtent.left), Math.max(mapExtent.bottom, maxExtent.bottom), Math.min(mapExtent.right, maxExtent.right), Math.min(mapExtent.top, maxExtent.top)); │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - testExtent = testExtent.transform(this.map.getProjectionObject(), this.ovmap.getProjectionObject()) │ │ │ │ - } │ │ │ │ - var resRatio = this.ovmap.getResolution() / this.map.getResolution(); │ │ │ │ - return resRatio > this.minRatio && resRatio <= this.maxRatio && this.ovmap.getExtent().containsBounds(testExtent) │ │ │ │ + deactivate: function() { │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ + this.handlers.feature.deactivate(); │ │ │ │ + this.feature = null; │ │ │ │ + this.dragging = false; │ │ │ │ + this.lastPixel = null; │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ }, │ │ │ │ - updateOverview: function() { │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ - var targetRes = this.ovmap.getResolution(); │ │ │ │ - var resRatio = targetRes / mapRes; │ │ │ │ - if (resRatio > this.maxRatio) { │ │ │ │ - targetRes = this.minRatio * mapRes │ │ │ │ - } else if (resRatio <= this.minRatio) { │ │ │ │ - targetRes = this.maxRatio * mapRes │ │ │ │ - } │ │ │ │ - var center; │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - center = this.map.center.clone(); │ │ │ │ - center.transform(this.map.getProjectionObject(), this.ovmap.getProjectionObject()) │ │ │ │ + overFeature: function(feature) { │ │ │ │ + var activated = false; │ │ │ │ + if (!this.handlers.drag.dragging) { │ │ │ │ + this.feature = feature; │ │ │ │ + this.handlers.drag.activate(); │ │ │ │ + activated = true; │ │ │ │ + this.over = true; │ │ │ │ + OpenLayers.Element.addClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ + this.onEnter(feature) │ │ │ │ } else { │ │ │ │ - center = this.map.center │ │ │ │ - } │ │ │ │ - this.ovmap.setCenter(center, this.ovmap.getZoomForResolution(targetRes * this.resolutionFactor)); │ │ │ │ - this.updateRectToMap() │ │ │ │ - }, │ │ │ │ - createMap: function() { │ │ │ │ - var options = OpenLayers.Util.extend({ │ │ │ │ - controls: [], │ │ │ │ - maxResolution: "auto", │ │ │ │ - fallThrough: false │ │ │ │ - }, this.mapOptions); │ │ │ │ - this.ovmap = new OpenLayers.Map(this.mapDiv, options); │ │ │ │ - this.ovmap.viewPortDiv.appendChild(this.extentRectangle); │ │ │ │ - OpenLayers.Event.stopObserving(window, "unload", this.ovmap.unloadDestroy); │ │ │ │ - this.ovmap.addLayers(this.layers); │ │ │ │ - this.ovmap.zoomToMaxExtent(); │ │ │ │ - this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-left-width")) + parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-right-width")); │ │ │ │ - this.wComp = this.wComp ? this.wComp : 2; │ │ │ │ - this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-top-width")) + parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-bottom-width")); │ │ │ │ - this.hComp = this.hComp ? this.hComp : 2; │ │ │ │ - this.handlers.drag = new OpenLayers.Handler.Drag(this, { │ │ │ │ - move: this.rectDrag, │ │ │ │ - done: this.updateMapToRect │ │ │ │ - }, { │ │ │ │ - map: this.ovmap │ │ │ │ - }); │ │ │ │ - this.handlers.click = new OpenLayers.Handler.Click(this, { │ │ │ │ - click: this.mapDivClick │ │ │ │ - }, { │ │ │ │ - single: true, │ │ │ │ - double: false, │ │ │ │ - stopSingle: true, │ │ │ │ - stopDouble: true, │ │ │ │ - pixelTolerance: 1, │ │ │ │ - map: this.ovmap │ │ │ │ - }); │ │ │ │ - this.handlers.click.activate(); │ │ │ │ - this.rectEvents = new OpenLayers.Events(this, this.extentRectangle, null, true); │ │ │ │ - this.rectEvents.register("mouseover", this, function(e) { │ │ │ │ - if (!this.handlers.drag.active && !this.map.dragging) { │ │ │ │ - this.handlers.drag.activate() │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.rectEvents.register("mouseout", this, function(e) { │ │ │ │ - if (!this.handlers.drag.dragging) { │ │ │ │ - this.handlers.drag.deactivate() │ │ │ │ + if (this.feature.id == feature.id) { │ │ │ │ + this.over = true │ │ │ │ + } else { │ │ │ │ + this.over = false │ │ │ │ } │ │ │ │ - }); │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - var sourceUnits = this.map.getProjectionObject().getUnits() || this.map.units || this.map.baseLayer.units; │ │ │ │ - var targetUnits = this.ovmap.getProjectionObject().getUnits() || this.ovmap.units || this.ovmap.baseLayer.units; │ │ │ │ - this.resolutionFactor = sourceUnits && targetUnits ? OpenLayers.INCHES_PER_UNIT[sourceUnits] / OpenLayers.INCHES_PER_UNIT[targetUnits] : 1 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - updateRectToMap: function() { │ │ │ │ - var bounds; │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - bounds = this.map.getExtent().transform(this.map.getProjectionObject(), this.ovmap.getProjectionObject()) │ │ │ │ - } else { │ │ │ │ - bounds = this.map.getExtent() │ │ │ │ - } │ │ │ │ - var pxBounds = this.getRectBoundsFromMapBounds(bounds); │ │ │ │ - if (pxBounds) { │ │ │ │ - this.setRectPxBounds(pxBounds) │ │ │ │ } │ │ │ │ + return activated │ │ │ │ }, │ │ │ │ - updateMapToRect: function() { │ │ │ │ - var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds); │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - lonLatBounds = lonLatBounds.transform(this.ovmap.getProjectionObject(), this.map.getProjectionObject()) │ │ │ │ - } │ │ │ │ - this.map.panTo(lonLatBounds.getCenterLonLat()) │ │ │ │ + downFeature: function(pixel) { │ │ │ │ + this.lastPixel = pixel; │ │ │ │ + this.onStart(this.feature, pixel) │ │ │ │ }, │ │ │ │ - setRectPxBounds: function(pxBounds) { │ │ │ │ - var top = Math.max(pxBounds.top, 0); │ │ │ │ - var left = Math.max(pxBounds.left, 0); │ │ │ │ - var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()), this.ovmap.size.h - this.hComp); │ │ │ │ - var right = Math.min(pxBounds.left + pxBounds.getWidth(), this.ovmap.size.w - this.wComp); │ │ │ │ - var width = Math.max(right - left, 0); │ │ │ │ - var height = Math.max(bottom - top, 0); │ │ │ │ - if (width < this.minRectSize || height < this.minRectSize) { │ │ │ │ - this.extentRectangle.className = this.displayClass + this.minRectDisplayClass; │ │ │ │ - var rLeft = left + width / 2 - this.minRectSize / 2; │ │ │ │ - var rTop = top + height / 2 - this.minRectSize / 2; │ │ │ │ - this.extentRectangle.style.top = Math.round(rTop) + "px"; │ │ │ │ - this.extentRectangle.style.left = Math.round(rLeft) + "px"; │ │ │ │ - this.extentRectangle.style.height = this.minRectSize + "px"; │ │ │ │ - this.extentRectangle.style.width = this.minRectSize + "px" │ │ │ │ - } else { │ │ │ │ - this.extentRectangle.className = this.displayClass + "ExtentRectangle"; │ │ │ │ - this.extentRectangle.style.top = Math.round(top) + "px"; │ │ │ │ - this.extentRectangle.style.left = Math.round(left) + "px"; │ │ │ │ - this.extentRectangle.style.height = Math.round(height) + "px"; │ │ │ │ - this.extentRectangle.style.width = Math.round(width) + "px" │ │ │ │ - } │ │ │ │ - this.rectPxBounds = new OpenLayers.Bounds(Math.round(left), Math.round(bottom), Math.round(right), Math.round(top)) │ │ │ │ + moveFeature: function(pixel) { │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ + this.feature.geometry.move(res * (pixel.x - this.lastPixel.x), res * (this.lastPixel.y - pixel.y)); │ │ │ │ + this.layer.drawFeature(this.feature); │ │ │ │ + this.lastPixel = pixel; │ │ │ │ + this.onDrag(this.feature, pixel) │ │ │ │ }, │ │ │ │ - getRectBoundsFromMapBounds: function(lonLatBounds) { │ │ │ │ - var leftBottomPx = this.getOverviewPxFromLonLat({ │ │ │ │ - lon: lonLatBounds.left, │ │ │ │ - lat: lonLatBounds.bottom │ │ │ │ - }); │ │ │ │ - var rightTopPx = this.getOverviewPxFromLonLat({ │ │ │ │ - lon: lonLatBounds.right, │ │ │ │ - lat: lonLatBounds.top │ │ │ │ - }); │ │ │ │ - var bounds = null; │ │ │ │ - if (leftBottomPx && rightTopPx) { │ │ │ │ - bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y, rightTopPx.x, rightTopPx.y) │ │ │ │ + upFeature: function(pixel) { │ │ │ │ + if (!this.over) { │ │ │ │ + this.handlers.drag.deactivate() │ │ │ │ } │ │ │ │ - return bounds │ │ │ │ - }, │ │ │ │ - getMapBoundsFromRectBounds: function(pxBounds) { │ │ │ │ - var leftBottomLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ - x: pxBounds.left, │ │ │ │ - y: pxBounds.bottom │ │ │ │ - }); │ │ │ │ - var rightTopLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ - x: pxBounds.right, │ │ │ │ - y: pxBounds.top │ │ │ │ - }); │ │ │ │ - return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat, rightTopLonLat.lon, rightTopLonLat.lat) │ │ │ │ }, │ │ │ │ - getLonLatFromOverviewPx: function(overviewMapPx) { │ │ │ │ - var size = this.ovmap.size; │ │ │ │ - var res = this.ovmap.getResolution(); │ │ │ │ - var center = this.ovmap.getExtent().getCenterLonLat(); │ │ │ │ - var deltaX = overviewMapPx.x - size.w / 2; │ │ │ │ - var deltaY = overviewMapPx.y - size.h / 2; │ │ │ │ - return { │ │ │ │ - lon: center.lon + deltaX * res, │ │ │ │ - lat: center.lat - deltaY * res │ │ │ │ - } │ │ │ │ + doneDragging: function(pixel) { │ │ │ │ + this.onComplete(this.feature, pixel) │ │ │ │ }, │ │ │ │ - getOverviewPxFromLonLat: function(lonlat) { │ │ │ │ - var res = this.ovmap.getResolution(); │ │ │ │ - var extent = this.ovmap.getExtent(); │ │ │ │ - if (extent) { │ │ │ │ - return { │ │ │ │ - x: Math.round(1 / res * (lonlat.lon - extent.left)), │ │ │ │ - y: Math.round(1 / res * (extent.top - lonlat.lat)) │ │ │ │ + outFeature: function(feature) { │ │ │ │ + if (!this.handlers.drag.dragging) { │ │ │ │ + this.over = false; │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ + this.onLeave(feature); │ │ │ │ + this.feature = null │ │ │ │ + } else { │ │ │ │ + if (this.feature.id == feature.id) { │ │ │ │ + this.over = false │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.OverviewMap" │ │ │ │ + cancel: function() { │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ + this.over = false │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + this.handlers.drag.setMap(map); │ │ │ │ + this.handlers.feature.setMap(map); │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.DragFeature" │ │ │ │ }); │ │ │ │ OpenLayers.Control.Scale = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ element: null, │ │ │ │ geodesic: false, │ │ │ │ initialize: function(element, options) { │ │ │ │ OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ this.element = OpenLayers.Util.getElement(element) │ │ │ │ @@ -23681,1105 +26924,425 @@ │ │ │ │ } │ │ │ │ this.element.innerHTML = OpenLayers.i18n("Scale = 1 : ${scaleDenom}", { │ │ │ │ scaleDenom: scale │ │ │ │ }) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.Scale" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.Graticule = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ + pinchOrigin: null, │ │ │ │ + currentCenter: null, │ │ │ │ autoActivate: true, │ │ │ │ - intervals: [45, 30, 20, 10, 5, 2, 1, .5, .2, .1, .05, .01, .005, .002, .001], │ │ │ │ - displayInLayerSwitcher: true, │ │ │ │ - visible: true, │ │ │ │ - numPoints: 50, │ │ │ │ - targetSize: 200, │ │ │ │ - layerName: null, │ │ │ │ - labelled: true, │ │ │ │ - labelFormat: "dm", │ │ │ │ - lineSymbolizer: { │ │ │ │ - strokeColor: "#333", │ │ │ │ - strokeWidth: 1, │ │ │ │ - strokeOpacity: .5 │ │ │ │ + preserveCenter: false, │ │ │ │ + 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) │ │ │ │ }, │ │ │ │ - labelSymbolizer: {}, │ │ │ │ - gratLayer: null, │ │ │ │ + pinchStart: function(evt, pinchData) { │ │ │ │ + var xy = this.preserveCenter ? this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; │ │ │ │ + this.pinchOrigin = xy; │ │ │ │ + this.currentCenter = xy │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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); │ │ │ │ + this.map.div.clientWidth = this.map.div.clientWidth; │ │ │ │ + this.map.setCenter(location, zoom) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.PinchZoom" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.TouchNavigation = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + dragPan: null, │ │ │ │ + dragPanOptions: null, │ │ │ │ + pinchZoom: null, │ │ │ │ + pinchZoomOptions: null, │ │ │ │ + clickHandlerOptions: null, │ │ │ │ + documentDrag: false, │ │ │ │ + autoActivate: true, │ │ │ │ initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.layerName = options.layerName || OpenLayers.i18n("Graticule"); │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.labelSymbolizer.stroke = false; │ │ │ │ - this.labelSymbolizer.fill = false; │ │ │ │ - this.labelSymbolizer.label = "${label}"; │ │ │ │ - this.labelSymbolizer.labelAlign = "${labelAlign}"; │ │ │ │ - this.labelSymbolizer.labelXOffset = "${xOffset}"; │ │ │ │ - this.labelSymbolizer.labelYOffset = "${yOffset}" │ │ │ │ + this.handlers = {}; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments) │ │ │ │ }, │ │ │ │ destroy: function() { │ │ │ │ this.deactivate(); │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - if (this.gratLayer) { │ │ │ │ - this.gratLayer.destroy(); │ │ │ │ - this.gratLayer = null │ │ │ │ + if (this.dragPan) { │ │ │ │ + this.dragPan.destroy() │ │ │ │ } │ │ │ │ - }, │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (!this.gratLayer) { │ │ │ │ - var gratStyle = new OpenLayers.Style({}, { │ │ │ │ - rules: [new OpenLayers.Rule({ │ │ │ │ - symbolizer: { │ │ │ │ - Point: this.labelSymbolizer, │ │ │ │ - Line: this.lineSymbolizer │ │ │ │ - } │ │ │ │ - })] │ │ │ │ - }); │ │ │ │ - this.gratLayer = new OpenLayers.Layer.Vector(this.layerName, { │ │ │ │ - styleMap: new OpenLayers.StyleMap({ │ │ │ │ - default: gratStyle │ │ │ │ - }), │ │ │ │ - visibility: this.visible, │ │ │ │ - displayInLayerSwitcher: this.displayInLayerSwitcher │ │ │ │ - }) │ │ │ │ + this.dragPan = null; │ │ │ │ + if (this.pinchZoom) { │ │ │ │ + this.pinchZoom.destroy(); │ │ │ │ + delete this.pinchZoom │ │ │ │ } │ │ │ │ - return this.div │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ activate: function() { │ │ │ │ if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.map.addLayer(this.gratLayer); │ │ │ │ - this.map.events.register("moveend", this, this.update); │ │ │ │ - this.update(); │ │ │ │ + this.dragPan.activate(); │ │ │ │ + this.handlers.click.activate(); │ │ │ │ + this.pinchZoom.activate(); │ │ │ │ return true │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ } │ │ │ │ + return false │ │ │ │ }, │ │ │ │ deactivate: function() { │ │ │ │ if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - this.map.events.unregister("moveend", this, this.update); │ │ │ │ - this.map.removeLayer(this.gratLayer); │ │ │ │ + this.dragPan.deactivate(); │ │ │ │ + this.handlers.click.deactivate(); │ │ │ │ + this.pinchZoom.deactivate(); │ │ │ │ return true │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - update: function() { │ │ │ │ - var mapBounds = this.map.getExtent(); │ │ │ │ - if (!mapBounds) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - this.gratLayer.destroyFeatures(); │ │ │ │ - var llProj = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ - var mapProj = this.map.getProjectionObject(); │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ - if (mapProj.proj && mapProj.proj.projName == "longlat") { │ │ │ │ - this.numPoints = 1 │ │ │ │ - } │ │ │ │ - var mapCenter = this.map.getCenter(); │ │ │ │ - var mapCenterLL = new OpenLayers.Pixel(mapCenter.lon, mapCenter.lat); │ │ │ │ - OpenLayers.Projection.transform(mapCenterLL, mapProj, llProj); │ │ │ │ - var testSq = this.targetSize * mapRes; │ │ │ │ - testSq *= testSq; │ │ │ │ - var llInterval; │ │ │ │ - for (var i = 0; i < this.intervals.length; ++i) { │ │ │ │ - llInterval = this.intervals[i]; │ │ │ │ - var delta = llInterval / 2; │ │ │ │ - var p1 = mapCenterLL.offset({ │ │ │ │ - x: -delta, │ │ │ │ - y: -delta │ │ │ │ - }); │ │ │ │ - var p2 = mapCenterLL.offset({ │ │ │ │ - x: delta, │ │ │ │ - y: delta │ │ │ │ - }); │ │ │ │ - OpenLayers.Projection.transform(p1, llProj, mapProj); │ │ │ │ - OpenLayers.Projection.transform(p2, llProj, mapProj); │ │ │ │ - var distSq = (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y); │ │ │ │ - if (distSq <= testSq) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - mapCenterLL.x = Math.floor(mapCenterLL.x / llInterval) * llInterval; │ │ │ │ - mapCenterLL.y = Math.floor(mapCenterLL.y / llInterval) * llInterval; │ │ │ │ - var iter = 0; │ │ │ │ - var centerLonPoints = [mapCenterLL.clone()]; │ │ │ │ - var newPoint = mapCenterLL.clone(); │ │ │ │ - var mapXY; │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: 0, │ │ │ │ - y: llInterval │ │ │ │ - }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLonPoints.unshift(newPoint) │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ - newPoint = mapCenterLL.clone(); │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: 0, │ │ │ │ - y: -llInterval │ │ │ │ - }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLonPoints.push(newPoint) │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ - iter = 0; │ │ │ │ - var centerLatPoints = [mapCenterLL.clone()]; │ │ │ │ - newPoint = mapCenterLL.clone(); │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: -llInterval, │ │ │ │ - y: 0 │ │ │ │ - }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLatPoints.unshift(newPoint) │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ - newPoint = mapCenterLL.clone(); │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: llInterval, │ │ │ │ - y: 0 │ │ │ │ - }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLatPoints.push(newPoint) │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ - var lines = []; │ │ │ │ - for (var i = 0; i < centerLatPoints.length; ++i) { │ │ │ │ - var lon = centerLatPoints[i].x; │ │ │ │ - var pointList = []; │ │ │ │ - var labelPoint = null; │ │ │ │ - var latEnd = Math.min(centerLonPoints[0].y, 90); │ │ │ │ - var latStart = Math.max(centerLonPoints[centerLonPoints.length - 1].y, -90); │ │ │ │ - var latDelta = (latEnd - latStart) / this.numPoints; │ │ │ │ - var lat = latStart; │ │ │ │ - for (var j = 0; j <= this.numPoints; ++j) { │ │ │ │ - var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ - gridPoint.transform(llProj, mapProj); │ │ │ │ - pointList.push(gridPoint); │ │ │ │ - lat += latDelta; │ │ │ │ - if (gridPoint.y >= mapBounds.bottom && !labelPoint) { │ │ │ │ - labelPoint = gridPoint │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.labelled) { │ │ │ │ - var labelPos = new OpenLayers.Geometry.Point(labelPoint.x, mapBounds.bottom); │ │ │ │ - var labelAttrs = { │ │ │ │ - value: lon, │ │ │ │ - label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lon, "lon", this.labelFormat) : "", │ │ │ │ - labelAlign: "cb", │ │ │ │ - xOffset: 0, │ │ │ │ - yOffset: 2 │ │ │ │ - }; │ │ │ │ - this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)) │ │ │ │ - } │ │ │ │ - var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ - lines.push(new OpenLayers.Feature.Vector(geom)) │ │ │ │ - } │ │ │ │ - for (var j = 0; j < centerLonPoints.length; ++j) { │ │ │ │ - lat = centerLonPoints[j].y; │ │ │ │ - if (lat < -90 || lat > 90) { │ │ │ │ - continue │ │ │ │ - } │ │ │ │ - var pointList = []; │ │ │ │ - var lonStart = centerLatPoints[0].x; │ │ │ │ - var lonEnd = centerLatPoints[centerLatPoints.length - 1].x; │ │ │ │ - var lonDelta = (lonEnd - lonStart) / this.numPoints; │ │ │ │ - var lon = lonStart; │ │ │ │ - var labelPoint = null; │ │ │ │ - for (var i = 0; i <= this.numPoints; ++i) { │ │ │ │ - var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ - gridPoint.transform(llProj, mapProj); │ │ │ │ - pointList.push(gridPoint); │ │ │ │ - lon += lonDelta; │ │ │ │ - if (gridPoint.x < mapBounds.right) { │ │ │ │ - labelPoint = gridPoint │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.labelled) { │ │ │ │ - var labelPos = new OpenLayers.Geometry.Point(mapBounds.right, labelPoint.y); │ │ │ │ - var labelAttrs = { │ │ │ │ - value: lat, │ │ │ │ - label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lat, "lat", this.labelFormat) : "", │ │ │ │ - labelAlign: "rb", │ │ │ │ - xOffset: -2, │ │ │ │ - yOffset: 2 │ │ │ │ - }; │ │ │ │ - this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)) │ │ │ │ - } │ │ │ │ - var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ - lines.push(new OpenLayers.Feature.Vector(geom)) │ │ │ │ - } │ │ │ │ - this.gratLayer.addFeatures(lines) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Graticule" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - center: null, │ │ │ │ - zoom: null, │ │ │ │ - layers: null, │ │ │ │ - displayProjection: null, │ │ │ │ - getParameters: function(url) { │ │ │ │ - url = url || window.location.href; │ │ │ │ - var parameters = OpenLayers.Util.getParameters(url); │ │ │ │ - var index = url.indexOf("#"); │ │ │ │ - if (index > 0) { │ │ │ │ - url = "?" + url.substring(index + 1, url.length); │ │ │ │ - OpenLayers.Util.extend(parameters, OpenLayers.Util.getParameters(url)) │ │ │ │ - } │ │ │ │ - return parameters │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ - var control = this.map.controls[i]; │ │ │ │ - if (control != this && control.CLASS_NAME == "OpenLayers.Control.ArgParser") { │ │ │ │ - if (control.displayProjection != this.displayProjection) { │ │ │ │ - this.displayProjection = control.displayProjection │ │ │ │ - } │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (i == this.map.controls.length) { │ │ │ │ - var args = this.getParameters(); │ │ │ │ - if (args.layers) { │ │ │ │ - this.layers = args.layers; │ │ │ │ - this.map.events.register("addlayer", this, this.configureLayers); │ │ │ │ - this.configureLayers() │ │ │ │ - } │ │ │ │ - if (args.lat && args.lon) { │ │ │ │ - this.center = new OpenLayers.LonLat(parseFloat(args.lon), parseFloat(args.lat)); │ │ │ │ - if (args.zoom) { │ │ │ │ - this.zoom = parseFloat(args.zoom) │ │ │ │ - } │ │ │ │ - this.map.events.register("changebaselayer", this, this.setCenter); │ │ │ │ - this.setCenter() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setCenter: function() { │ │ │ │ - if (this.map.baseLayer) { │ │ │ │ - this.map.events.unregister("changebaselayer", this, this.setCenter); │ │ │ │ - if (this.displayProjection) { │ │ │ │ - this.center.transform(this.displayProjection, this.map.getProjectionObject()) │ │ │ │ - } │ │ │ │ - this.map.setCenter(this.center, this.zoom) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - configureLayers: function() { │ │ │ │ - if (this.layers.length == this.map.layers.length) { │ │ │ │ - this.map.events.unregister("addlayer", this, this.configureLayers); │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - var c = this.layers.charAt(i); │ │ │ │ - if (c == "B") { │ │ │ │ - this.map.setBaseLayer(layer) │ │ │ │ - } else if (c == "T" || c == "F") { │ │ │ │ - layer.setVisibility(c == "T") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ArgParser" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - argParserClass: OpenLayers.Control.ArgParser, │ │ │ │ - element: null, │ │ │ │ - anchor: false, │ │ │ │ - base: "", │ │ │ │ - displayProjection: null, │ │ │ │ - initialize: function(element, base, options) { │ │ │ │ - if (element !== null && typeof element == "object" && !OpenLayers.Util.isElement(element)) { │ │ │ │ - options = element; │ │ │ │ - this.base = document.location.href; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - if (this.element != null) { │ │ │ │ - this.element = OpenLayers.Util.getElement(this.element) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.element = OpenLayers.Util.getElement(element); │ │ │ │ - this.base = base || document.location.href │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.element && this.element.parentNode == this.div) { │ │ │ │ - this.div.removeChild(this.element); │ │ │ │ - this.element = null │ │ │ │ - } │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.unregister("moveend", this, this.updateLink) │ │ │ │ - } │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ - var control = this.map.controls[i]; │ │ │ │ - if (control.CLASS_NAME == this.argParserClass.CLASS_NAME) { │ │ │ │ - if (control.displayProjection != this.displayProjection) { │ │ │ │ - this.displayProjection = control.displayProjection │ │ │ │ - } │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (i == this.map.controls.length) { │ │ │ │ - this.map.addControl(new this.argParserClass({ │ │ │ │ - displayProjection: this.displayProjection │ │ │ │ - })) │ │ │ │ } │ │ │ │ + return false │ │ │ │ }, │ │ │ │ draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (!this.element && !this.anchor) { │ │ │ │ - this.element = document.createElement("a"); │ │ │ │ - this.element.innerHTML = OpenLayers.i18n("Permalink"); │ │ │ │ - this.element.href = ""; │ │ │ │ - this.div.appendChild(this.element) │ │ │ │ - } │ │ │ │ - this.map.events.on({ │ │ │ │ - moveend: this.updateLink, │ │ │ │ - changelayer: this.updateLink, │ │ │ │ - changebaselayer: this.updateLink, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.updateLink(); │ │ │ │ - return this.div │ │ │ │ + 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)) │ │ │ │ }, │ │ │ │ - updateLink: function() { │ │ │ │ - var separator = this.anchor ? "#" : "?"; │ │ │ │ - var href = this.base; │ │ │ │ - var anchor = null; │ │ │ │ - if (href.indexOf("#") != -1 && this.anchor == false) { │ │ │ │ - anchor = href.substring(href.indexOf("#"), href.length) │ │ │ │ - } │ │ │ │ - if (href.indexOf(separator) != -1) { │ │ │ │ - href = href.substring(0, href.indexOf(separator)) │ │ │ │ - } │ │ │ │ - var splits = href.split("#"); │ │ │ │ - href = splits[0] + separator + OpenLayers.Util.getParameterString(this.createParams()); │ │ │ │ - if (anchor) { │ │ │ │ - href += anchor │ │ │ │ - } │ │ │ │ - if (this.anchor && !this.element) { │ │ │ │ - window.location.href = href │ │ │ │ - } else { │ │ │ │ - this.element.href = href │ │ │ │ + defaultClick: function(evt) { │ │ │ │ + if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ + this.map.zoomOut() │ │ │ │ } │ │ │ │ }, │ │ │ │ - createParams: function(center, zoom, layers) { │ │ │ │ - center = center || this.map.getCenter(); │ │ │ │ - var params = OpenLayers.Util.getParameters(this.base); │ │ │ │ - if (center) { │ │ │ │ - params.zoom = zoom || this.map.getZoom(); │ │ │ │ - var lat = center.lat; │ │ │ │ - var lon = center.lon; │ │ │ │ - if (this.displayProjection) { │ │ │ │ - var mapPosition = OpenLayers.Projection.transform({ │ │ │ │ - x: lon, │ │ │ │ - y: lat │ │ │ │ - }, this.map.getProjectionObject(), this.displayProjection); │ │ │ │ - lon = mapPosition.x; │ │ │ │ - lat = mapPosition.y │ │ │ │ - } │ │ │ │ - params.lat = Math.round(lat * 1e5) / 1e5; │ │ │ │ - params.lon = Math.round(lon * 1e5) / 1e5; │ │ │ │ - layers = layers || this.map.layers; │ │ │ │ - params.layers = ""; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - var layer = layers[i]; │ │ │ │ - if (layer.isBaseLayer) { │ │ │ │ - params.layers += layer == this.map.baseLayer ? "B" : "0" │ │ │ │ - } else { │ │ │ │ - params.layers += layer.getVisibility() ? "T" : "F" │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return params │ │ │ │ + defaultDblClick: function(evt) { │ │ │ │ + this.map.zoomTo(this.map.zoom + 1, evt.xy) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Permalink" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.TouchNavigation" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + multipleKey: null, │ │ │ │ + toggleKey: null, │ │ │ │ + multiple: false, │ │ │ │ + clickout: true, │ │ │ │ + toggle: false, │ │ │ │ + hover: false, │ │ │ │ + highlightOnly: false, │ │ │ │ + box: false, │ │ │ │ + onBeforeSelect: function() {}, │ │ │ │ + onSelect: function() {}, │ │ │ │ + onUnselect: function() {}, │ │ │ │ + scope: null, │ │ │ │ + geometryTypes: null, │ │ │ │ + layer: null, │ │ │ │ + layers: null, │ │ │ │ callbacks: null, │ │ │ │ - displaySystem: "metric", │ │ │ │ - geodesic: false, │ │ │ │ - displaySystemUnits: { │ │ │ │ - geographic: ["dd"], │ │ │ │ - english: ["mi", "ft", "in"], │ │ │ │ - metric: ["km", "m"] │ │ │ │ - }, │ │ │ │ - partialDelay: 300, │ │ │ │ - delayedTrigger: null, │ │ │ │ - persist: false, │ │ │ │ - immediate: false, │ │ │ │ - initialize: function(handler, options) { │ │ │ │ + selectStyle: null, │ │ │ │ + renderIntent: "select", │ │ │ │ + handlers: null, │ │ │ │ + initialize: function(layers, options) { │ │ │ │ OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + if (this.scope === null) { │ │ │ │ + this.scope = this │ │ │ │ + } │ │ │ │ + this.initLayer(layers); │ │ │ │ var callbacks = { │ │ │ │ - done: this.measureComplete, │ │ │ │ - point: this.measurePartial │ │ │ │ + click: this.clickFeature, │ │ │ │ + clickout: this.clickoutFeature │ │ │ │ }; │ │ │ │ - if (this.immediate) { │ │ │ │ - callbacks.modify = this.measureImmediate │ │ │ │ + if (this.hover) { │ │ │ │ + callbacks.over = this.overFeature; │ │ │ │ + callbacks.out = this.outFeature │ │ │ │ } │ │ │ │ this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks); │ │ │ │ - this.handlerOptions = OpenLayers.Util.extend({ │ │ │ │ - persist: this.persist │ │ │ │ - }, this.handlerOptions); │ │ │ │ - this.handler = new handler(this, this.callbacks, this.handlerOptions) │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - this.cancelDelay(); │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - cancel: function() { │ │ │ │ - this.cancelDelay(); │ │ │ │ - this.handler.cancel() │ │ │ │ - }, │ │ │ │ - setImmediate: function(immediate) { │ │ │ │ - this.immediate = immediate; │ │ │ │ - if (this.immediate) { │ │ │ │ - this.callbacks.modify = this.measureImmediate │ │ │ │ - } else { │ │ │ │ - delete this.callbacks.modify │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - updateHandler: function(handler, options) { │ │ │ │ - var active = this.active; │ │ │ │ - if (active) { │ │ │ │ - this.deactivate() │ │ │ │ - } │ │ │ │ - this.handler = new handler(this, this.callbacks, options); │ │ │ │ - if (active) { │ │ │ │ - this.activate() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - measureComplete: function(geometry) { │ │ │ │ - this.cancelDelay(); │ │ │ │ - this.measure(geometry, "measure") │ │ │ │ - }, │ │ │ │ - measurePartial: function(point, geometry) { │ │ │ │ - this.cancelDelay(); │ │ │ │ - geometry = geometry.clone(); │ │ │ │ - if (this.handler.freehandMode(this.handler.evt)) { │ │ │ │ - this.measure(geometry, "measurepartial") │ │ │ │ - } else { │ │ │ │ - this.delayedTrigger = window.setTimeout(OpenLayers.Function.bind(function() { │ │ │ │ - this.delayedTrigger = null; │ │ │ │ - this.measure(geometry, "measurepartial") │ │ │ │ - }, this), this.partialDelay) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - measureImmediate: function(point, feature, drawing) { │ │ │ │ - if (drawing && !this.handler.freehandMode(this.handler.evt)) { │ │ │ │ - this.cancelDelay(); │ │ │ │ - this.measure(feature.geometry, "measurepartial") │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - cancelDelay: function() { │ │ │ │ - if (this.delayedTrigger !== null) { │ │ │ │ - window.clearTimeout(this.delayedTrigger); │ │ │ │ - this.delayedTrigger = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - measure: function(geometry, eventType) { │ │ │ │ - var stat, order; │ │ │ │ - if (geometry.CLASS_NAME.indexOf("LineString") > -1) { │ │ │ │ - stat = this.getBestLength(geometry); │ │ │ │ - order = 1 │ │ │ │ - } else { │ │ │ │ - stat = this.getBestArea(geometry); │ │ │ │ - order = 2 │ │ │ │ - } │ │ │ │ - this.events.triggerEvent(eventType, { │ │ │ │ - measure: stat[0], │ │ │ │ - units: stat[1], │ │ │ │ - order: order, │ │ │ │ - geometry: geometry │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - getBestArea: function(geometry) { │ │ │ │ - var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ - var unit, area; │ │ │ │ - for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ - unit = units[i]; │ │ │ │ - area = this.getArea(geometry, unit); │ │ │ │ - if (area > 1) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return [area, unit] │ │ │ │ - }, │ │ │ │ - getArea: function(geometry, units) { │ │ │ │ - var area, geomUnits; │ │ │ │ - if (this.geodesic) { │ │ │ │ - area = geometry.getGeodesicArea(this.map.getProjectionObject()); │ │ │ │ - geomUnits = "m" │ │ │ │ - } else { │ │ │ │ - area = geometry.getArea(); │ │ │ │ - geomUnits = this.map.getUnits() │ │ │ │ - } │ │ │ │ - var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ - if (inPerDisplayUnit) { │ │ │ │ - var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ - area *= Math.pow(inPerMapUnit / inPerDisplayUnit, 2) │ │ │ │ - } │ │ │ │ - return area │ │ │ │ - }, │ │ │ │ - getBestLength: function(geometry) { │ │ │ │ - var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ - var unit, length; │ │ │ │ - for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ - unit = units[i]; │ │ │ │ - length = this.getLength(geometry, unit); │ │ │ │ - if (length > 1) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ + 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" │ │ │ │ + }) │ │ │ │ } │ │ │ │ - return [length, unit] │ │ │ │ }, │ │ │ │ - getLength: function(geometry, units) { │ │ │ │ - var length, geomUnits; │ │ │ │ - if (this.geodesic) { │ │ │ │ - length = geometry.getGeodesicLength(this.map.getProjectionObject()); │ │ │ │ - geomUnits = "m" │ │ │ │ + initLayer: function(layers) { │ │ │ │ + if (OpenLayers.Util.isArray(layers)) { │ │ │ │ + this.layers = layers; │ │ │ │ + this.layer = new OpenLayers.Layer.Vector.RootContainer(this.id + "_container", { │ │ │ │ + layers: layers │ │ │ │ + }) │ │ │ │ } else { │ │ │ │ - length = geometry.getLength(); │ │ │ │ - geomUnits = this.map.getUnits() │ │ │ │ - } │ │ │ │ - var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ - if (inPerDisplayUnit) { │ │ │ │ - var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ - length *= inPerMapUnit / inPerDisplayUnit │ │ │ │ + this.layer = layers │ │ │ │ } │ │ │ │ - return length │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Measure" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - dragHandler: null, │ │ │ │ - boxDivClassName: "olHandlerBoxZoomBox", │ │ │ │ - boxOffsets: null, │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ - this.dragHandler = new OpenLayers.Handler.Drag(this, { │ │ │ │ - down: this.startBox, │ │ │ │ - move: this.moveBox, │ │ │ │ - out: this.removeBox, │ │ │ │ - up: this.endBox │ │ │ │ - }, { │ │ │ │ - keyMask: this.keyMask │ │ │ │ - }) │ │ │ │ }, │ │ │ │ destroy: function() { │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ - if (this.dragHandler) { │ │ │ │ - this.dragHandler.destroy(); │ │ │ │ - this.dragHandler = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Handler.prototype.setMap.apply(this, arguments); │ │ │ │ - if (this.dragHandler) { │ │ │ │ - this.dragHandler.setMap(map) │ │ │ │ + if (this.active && this.layers) { │ │ │ │ + this.map.removeLayer(this.layer) │ │ │ │ } │ │ │ │ - }, │ │ │ │ - startBox: function(xy) { │ │ │ │ - this.callback("start", []); │ │ │ │ - this.zoomBox = OpenLayers.Util.createDiv("zoomBox", { │ │ │ │ - x: -9999, │ │ │ │ - y: -9999 │ │ │ │ - }); │ │ │ │ - this.zoomBox.className = this.boxDivClassName; │ │ │ │ - this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1; │ │ │ │ - this.map.viewPortDiv.appendChild(this.zoomBox); │ │ │ │ - OpenLayers.Element.addClass(this.map.viewPortDiv, "olDrawBox") │ │ │ │ - }, │ │ │ │ - moveBox: function(xy) { │ │ │ │ - var startX = this.dragHandler.start.x; │ │ │ │ - var startY = this.dragHandler.start.y; │ │ │ │ - var deltaX = Math.abs(startX - xy.x); │ │ │ │ - var deltaY = Math.abs(startY - xy.y); │ │ │ │ - var offset = this.getBoxOffsets(); │ │ │ │ - this.zoomBox.style.width = deltaX + offset.width + 1 + "px"; │ │ │ │ - this.zoomBox.style.height = deltaY + offset.height + 1 + "px"; │ │ │ │ - this.zoomBox.style.left = (xy.x < startX ? startX - deltaX - offset.left : startX - offset.left) + "px"; │ │ │ │ - this.zoomBox.style.top = (xy.y < startY ? startY - deltaY - offset.top : startY - offset.top) + "px" │ │ │ │ - }, │ │ │ │ - endBox: function(end) { │ │ │ │ - var result; │ │ │ │ - if (Math.abs(this.dragHandler.start.x - end.x) > 5 || Math.abs(this.dragHandler.start.y - end.y) > 5) { │ │ │ │ - var start = this.dragHandler.start; │ │ │ │ - var top = Math.min(start.y, end.y); │ │ │ │ - var bottom = Math.max(start.y, end.y); │ │ │ │ - var left = Math.min(start.x, end.x); │ │ │ │ - var right = Math.max(start.x, end.x); │ │ │ │ - result = new OpenLayers.Bounds(left, bottom, right, top) │ │ │ │ - } else { │ │ │ │ - result = this.dragHandler.start.clone() │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + if (this.layers) { │ │ │ │ + this.layer.destroy() │ │ │ │ } │ │ │ │ - this.removeBox(); │ │ │ │ - this.callback("done", [result]) │ │ │ │ - }, │ │ │ │ - removeBox: function() { │ │ │ │ - this.map.viewPortDiv.removeChild(this.zoomBox); │ │ │ │ - this.zoomBox = null; │ │ │ │ - this.boxOffsets = null; │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olDrawBox") │ │ │ │ }, │ │ │ │ activate: function() { │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.dragHandler.activate(); │ │ │ │ - return true │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ + 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) │ │ │ │ }, │ │ │ │ deactivate: function() { │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - if (this.dragHandler.deactivate()) { │ │ │ │ - if (this.zoomBox) { │ │ │ │ - this.removeBox() │ │ │ │ - } │ │ │ │ + if (this.active) { │ │ │ │ + this.handlers.feature.deactivate(); │ │ │ │ + if (this.handlers.box) { │ │ │ │ + this.handlers.box.deactivate() │ │ │ │ + } │ │ │ │ + if (this.layers) { │ │ │ │ + this.map.removeLayer(this.layer) │ │ │ │ } │ │ │ │ - return true │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ } │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ }, │ │ │ │ - getBoxOffsets: function() { │ │ │ │ - if (!this.boxOffsets) { │ │ │ │ - var testDiv = document.createElement("div"); │ │ │ │ - testDiv.style.position = "absolute"; │ │ │ │ - testDiv.style.border = "1px solid black"; │ │ │ │ - testDiv.style.width = "3px"; │ │ │ │ - document.body.appendChild(testDiv); │ │ │ │ - var w3cBoxModel = testDiv.clientWidth == 3; │ │ │ │ - document.body.removeChild(testDiv); │ │ │ │ - var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-left-width")); │ │ │ │ - var right = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-right-width")); │ │ │ │ - var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-top-width")); │ │ │ │ - var bottom = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-bottom-width")); │ │ │ │ - this.boxOffsets = { │ │ │ │ - left: left, │ │ │ │ - right: right, │ │ │ │ - top: top, │ │ │ │ - bottom: bottom, │ │ │ │ - width: w3cBoxModel === false ? left + right : 0, │ │ │ │ - height: w3cBoxModel === false ? top + bottom : 0 │ │ │ │ + unselectAll: function(options) { │ │ │ │ + var layers = this.layers || [this.layer], │ │ │ │ + layer, feature, l, numExcept; │ │ │ │ + for (l = 0; l < layers.length; ++l) { │ │ │ │ + layer = layers[l]; │ │ │ │ + numExcept = 0; │ │ │ │ + if (layer.selectedFeatures != null) { │ │ │ │ + while (layer.selectedFeatures.length > numExcept) { │ │ │ │ + feature = layer.selectedFeatures[numExcept]; │ │ │ │ + if (!options || options.except != feature) { │ │ │ │ + this.unselect(feature) │ │ │ │ + } else { │ │ │ │ + ++numExcept │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ - return this.boxOffsets │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Box" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ - out: false, │ │ │ │ - keyMask: null, │ │ │ │ - alwaysZoom: false, │ │ │ │ - zoomOnClick: true, │ │ │ │ - draw: function() { │ │ │ │ - this.handler = new OpenLayers.Handler.Box(this, { │ │ │ │ - done: this.zoomBox │ │ │ │ - }, { │ │ │ │ - keyMask: this.keyMask │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - zoomBox: function(position) { │ │ │ │ - if (position instanceof OpenLayers.Bounds) { │ │ │ │ - var bounds, targetCenterPx = position.getCenterPixel(); │ │ │ │ - if (!this.out) { │ │ │ │ - var minXY = this.map.getLonLatFromPixel({ │ │ │ │ - x: position.left, │ │ │ │ - y: position.bottom │ │ │ │ - }); │ │ │ │ - var maxXY = this.map.getLonLatFromPixel({ │ │ │ │ - x: position.right, │ │ │ │ - y: position.top │ │ │ │ - }); │ │ │ │ - bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat, maxXY.lon, maxXY.lat) │ │ │ │ - } else { │ │ │ │ - var pixWidth = position.right - position.left; │ │ │ │ - var pixHeight = position.bottom - position.top; │ │ │ │ - var zoomFactor = Math.min(this.map.size.h / pixHeight, this.map.size.w / pixWidth); │ │ │ │ - var extent = this.map.getExtent(); │ │ │ │ - var center = this.map.getLonLatFromPixel(targetCenterPx); │ │ │ │ - var xmin = center.lon - extent.getWidth() / 2 * zoomFactor; │ │ │ │ - var xmax = center.lon + extent.getWidth() / 2 * zoomFactor; │ │ │ │ - var ymin = center.lat - extent.getHeight() / 2 * zoomFactor; │ │ │ │ - var ymax = center.lat + extent.getHeight() / 2 * zoomFactor; │ │ │ │ - bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax) │ │ │ │ - } │ │ │ │ - var lastZoom = this.map.getZoom(), │ │ │ │ - size = this.map.getSize(), │ │ │ │ - centerPx = { │ │ │ │ - x: size.w / 2, │ │ │ │ - y: size.h / 2 │ │ │ │ - }, │ │ │ │ - zoom = this.map.getZoomForExtent(bounds), │ │ │ │ - oldRes = this.map.getResolution(), │ │ │ │ - newRes = this.map.getResolutionForZoom(zoom); │ │ │ │ - if (oldRes == newRes) { │ │ │ │ - this.map.setCenter(this.map.getLonLatFromPixel(targetCenterPx)) │ │ │ │ - } else { │ │ │ │ - var zoomOriginPx = { │ │ │ │ - x: (oldRes * targetCenterPx.x - newRes * centerPx.x) / (oldRes - newRes), │ │ │ │ - y: (oldRes * targetCenterPx.y - newRes * centerPx.y) / (oldRes - newRes) │ │ │ │ - }; │ │ │ │ - this.map.zoomTo(zoom, zoomOriginPx) │ │ │ │ - } │ │ │ │ - if (lastZoom == this.map.getZoom() && this.alwaysZoom == true) { │ │ │ │ - this.map.zoomTo(lastZoom + (this.out ? -1 : 1)) │ │ │ │ - } │ │ │ │ - } else if (this.zoomOnClick) { │ │ │ │ - if (!this.out) { │ │ │ │ - this.map.zoomTo(this.map.getZoom() + 1, position) │ │ │ │ + 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 { │ │ │ │ - this.map.zoomTo(this.map.getZoom() - 1, position) │ │ │ │ + if (!this.multipleSelect()) { │ │ │ │ + this.unselectAll({ │ │ │ │ + except: feature │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + this.select(feature) │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomBox" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ - panned: false, │ │ │ │ - interval: 0, │ │ │ │ - documentDrag: false, │ │ │ │ - kinetic: null, │ │ │ │ - enableKinetic: true, │ │ │ │ - kineticInterval: 10, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ + multipleSelect: function() { │ │ │ │ + return this.multiple || this.handlers.feature.evt && this.handlers.feature.evt[this.multipleKey] │ │ │ │ }, │ │ │ │ - panMapStart: function() { │ │ │ │ - if (this.kinetic) { │ │ │ │ - this.kinetic.begin() │ │ │ │ - } │ │ │ │ + toggleSelect: function() { │ │ │ │ + return this.toggle || this.handlers.feature.evt && this.handlers.feature.evt[this.toggleKey] │ │ │ │ }, │ │ │ │ - panMap: function(xy) { │ │ │ │ - if (this.kinetic) { │ │ │ │ - this.kinetic.update(xy) │ │ │ │ + clickoutFeature: function(feature) { │ │ │ │ + if (!this.hover && this.clickout) { │ │ │ │ + this.unselectAll() │ │ │ │ } │ │ │ │ - this.panned = true; │ │ │ │ - this.map.pan(this.handler.last.x - xy.x, this.handler.last.y - xy.y, { │ │ │ │ - dragging: true, │ │ │ │ - animate: false │ │ │ │ - }) │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }) │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - this.panned = false │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.DragPan" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - wheelListener: null, │ │ │ │ - interval: 0, │ │ │ │ - maxDelta: Number.POSITIVE_INFINITY, │ │ │ │ - delta: 0, │ │ │ │ - cumulative: true, │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ - this.wheelListener = OpenLayers.Function.bindAsEventListener(this.onWheelEvent, this) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ - this.wheelListener = null │ │ │ │ - }, │ │ │ │ - onWheelEvent: function(e) { │ │ │ │ - if (!this.map || !this.checkModifiers(e)) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - var overScrollableDiv = false; │ │ │ │ - var allowScroll = false; │ │ │ │ - var overMapDiv = false; │ │ │ │ - var elem = OpenLayers.Event.element(e); │ │ │ │ - while (elem != null && !overMapDiv && !overScrollableDiv) { │ │ │ │ - if (!overScrollableDiv) { │ │ │ │ - try { │ │ │ │ - var overflow; │ │ │ │ - if (elem.currentStyle) { │ │ │ │ - overflow = elem.currentStyle["overflow"] │ │ │ │ - } else { │ │ │ │ - var style = document.defaultView.getComputedStyle(elem, null); │ │ │ │ - overflow = style.getPropertyValue("overflow") │ │ │ │ - } │ │ │ │ - overScrollableDiv = overflow && overflow == "auto" || overflow == "scroll" │ │ │ │ - } catch (err) {} │ │ │ │ - } │ │ │ │ - if (!allowScroll) { │ │ │ │ - allowScroll = OpenLayers.Element.hasClass(elem, "olScrollable"); │ │ │ │ - if (!allowScroll) { │ │ │ │ - for (var i = 0, len = this.map.layers.length; i < len; i++) { │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - if (elem == layer.div || elem == layer.pane) { │ │ │ │ - allowScroll = true; │ │ │ │ - break │ │ │ │ + outFeature: function(feature) { │ │ │ │ + if (this.hover) { │ │ │ │ + if (this.highlightOnly) { │ │ │ │ + if (feature._lastHighlighter == this.id) { │ │ │ │ + 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) │ │ │ │ } │ │ │ │ } │ │ │ │ - } │ │ │ │ - overMapDiv = elem == this.map.div; │ │ │ │ - elem = elem.parentNode │ │ │ │ - } │ │ │ │ - if (!overScrollableDiv && overMapDiv) { │ │ │ │ - if (allowScroll) { │ │ │ │ - var delta = 0; │ │ │ │ - if (e.wheelDelta) { │ │ │ │ - delta = e.wheelDelta; │ │ │ │ - if (delta % 160 === 0) { │ │ │ │ - delta = delta * .75 │ │ │ │ - } │ │ │ │ - delta = delta / 120 │ │ │ │ - } else if (e.detail) { │ │ │ │ - delta = -(e.detail / Math.abs(e.detail)) │ │ │ │ - } │ │ │ │ - this.delta += delta; │ │ │ │ - window.clearTimeout(this._timeoutId); │ │ │ │ - if (this.interval && Math.abs(this.delta) < this.maxDelta) { │ │ │ │ - var evt = OpenLayers.Util.extend({}, e); │ │ │ │ - this._timeoutId = window.setTimeout(OpenLayers.Function.bind(function() { │ │ │ │ - this.wheelZoom(evt) │ │ │ │ - }, this), this.interval) │ │ │ │ - } else { │ │ │ │ - this.wheelZoom(e) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - OpenLayers.Event.stop(e) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - wheelZoom: function(e) { │ │ │ │ - var delta = this.delta; │ │ │ │ - this.delta = 0; │ │ │ │ - if (delta) { │ │ │ │ - e.xy = this.map.events.getMousePosition(e); │ │ │ │ - if (delta < 0) { │ │ │ │ - this.callback("down", [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]) │ │ │ │ } else { │ │ │ │ - this.callback("up", [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]) │ │ │ │ + this.unselect(feature) │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ - activate: function(evt) { │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - var wheelListener = this.wheelListener; │ │ │ │ - OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener); │ │ │ │ - OpenLayers.Event.observe(window, "mousewheel", wheelListener); │ │ │ │ - OpenLayers.Event.observe(document, "mousewheel", wheelListener); │ │ │ │ - return true │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ } │ │ │ │ }, │ │ │ │ - deactivate: function(evt) { │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - var wheelListener = this.wheelListener; │ │ │ │ - OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener); │ │ │ │ - OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener); │ │ │ │ - OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener); │ │ │ │ - return true │ │ │ │ + unhighlight: function(feature) { │ │ │ │ + var layer = feature.layer; │ │ │ │ + if (feature._prevHighlighter == undefined) { │ │ │ │ + delete feature._lastHighlighter │ │ │ │ + } else if (feature._prevHighlighter == this.id) { │ │ │ │ + delete feature._prevHighlighter │ │ │ │ } else { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.MouseWheel" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - dragPan: null, │ │ │ │ - dragPanOptions: null, │ │ │ │ - pinchZoom: null, │ │ │ │ - pinchZoomOptions: null, │ │ │ │ - documentDrag: false, │ │ │ │ - zoomBox: null, │ │ │ │ - zoomBoxEnabled: true, │ │ │ │ - zoomWheelEnabled: true, │ │ │ │ - mouseWheelOptions: null, │ │ │ │ - handleRightClicks: false, │ │ │ │ - zoomBoxKeyMask: OpenLayers.Handler.MOD_SHIFT, │ │ │ │ - autoActivate: true, │ │ │ │ - initialize: function(options) { │ │ │ │ - this.handlers = {}; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - if (this.dragPan) { │ │ │ │ - this.dragPan.destroy() │ │ │ │ - } │ │ │ │ - this.dragPan = null; │ │ │ │ - if (this.zoomBox) { │ │ │ │ - this.zoomBox.destroy() │ │ │ │ - } │ │ │ │ - this.zoomBox = null; │ │ │ │ - if (this.pinchZoom) { │ │ │ │ - this.pinchZoom.destroy() │ │ │ │ - } │ │ │ │ - this.pinchZoom = null; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - this.dragPan.activate(); │ │ │ │ - if (this.zoomWheelEnabled) { │ │ │ │ - this.handlers.wheel.activate() │ │ │ │ - } │ │ │ │ - this.handlers.click.activate(); │ │ │ │ - if (this.zoomBoxEnabled) { │ │ │ │ - this.zoomBox.activate() │ │ │ │ - } │ │ │ │ - if (this.pinchZoom) { │ │ │ │ - this.pinchZoom.activate() │ │ │ │ + feature._lastHighlighter = feature._prevHighlighter; │ │ │ │ + delete feature._prevHighlighter │ │ │ │ } │ │ │ │ - return OpenLayers.Control.prototype.activate.apply(this, arguments) │ │ │ │ + layer.drawFeature(feature, feature.style || feature.layer.style || "default"); │ │ │ │ + this.events.triggerEvent("featureunhighlighted", { │ │ │ │ + feature: feature │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (this.pinchZoom) { │ │ │ │ - this.pinchZoom.deactivate() │ │ │ │ + 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 (!this.handlers.feature.lastFeature) { │ │ │ │ + this.handlers.feature.lastFeature = layer.selectedFeatures[0] │ │ │ │ + } │ │ │ │ + layer.events.triggerEvent("featureselected", { │ │ │ │ + feature: feature │ │ │ │ + }); │ │ │ │ + this.onSelect.call(this.scope, feature) │ │ │ │ + } │ │ │ │ } │ │ │ │ - this.zoomBox.deactivate(); │ │ │ │ - this.dragPan.deactivate(); │ │ │ │ - this.handlers.click.deactivate(); │ │ │ │ - this.handlers.wheel.deactivate(); │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ }, │ │ │ │ - draw: function() { │ │ │ │ - if (this.handleRightClicks) { │ │ │ │ - this.map.viewPortDiv.oncontextmenu = OpenLayers.Function.False │ │ │ │ - } │ │ │ │ - var clickCallbacks = { │ │ │ │ - click: this.defaultClick, │ │ │ │ - dblclick: this.defaultDblClick, │ │ │ │ - dblrightclick: this.defaultDblRightClick │ │ │ │ - }; │ │ │ │ - var clickOptions = { │ │ │ │ - double: true, │ │ │ │ - stopDouble: true │ │ │ │ - }; │ │ │ │ - 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.zoomBox = new OpenLayers.Control.ZoomBox({ │ │ │ │ - map: this.map, │ │ │ │ - keyMask: this.zoomBoxKeyMask │ │ │ │ + unselect: function(feature) { │ │ │ │ + var layer = feature.layer; │ │ │ │ + this.unhighlight(feature); │ │ │ │ + OpenLayers.Util.removeItem(layer.selectedFeatures, feature); │ │ │ │ + layer.events.triggerEvent("featureunselected", { │ │ │ │ + feature: feature │ │ │ │ }); │ │ │ │ - this.dragPan.draw(); │ │ │ │ - this.zoomBox.draw(); │ │ │ │ - var wheelOptions = this.map.fractionalZoom ? {} : { │ │ │ │ - cumulative: false, │ │ │ │ - interval: 50, │ │ │ │ - maxDelta: 6 │ │ │ │ - }; │ │ │ │ - this.handlers.wheel = new OpenLayers.Handler.MouseWheel(this, { │ │ │ │ - up: this.wheelUp, │ │ │ │ - down: this.wheelDown │ │ │ │ - }, OpenLayers.Util.extend(wheelOptions, this.mouseWheelOptions)); │ │ │ │ - if (OpenLayers.Control.PinchZoom) { │ │ │ │ - this.pinchZoom = new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({ │ │ │ │ - map: this.map │ │ │ │ - }, this.pinchZoomOptions)) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - defaultClick: function(evt) { │ │ │ │ - if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ - this.map.zoomOut() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - defaultDblClick: function(evt) { │ │ │ │ - this.map.zoomTo(this.map.zoom + 1, evt.xy) │ │ │ │ - }, │ │ │ │ - defaultDblRightClick: function(evt) { │ │ │ │ - this.map.zoomTo(this.map.zoom - 1, evt.xy) │ │ │ │ + this.onUnselect.call(this.scope, feature) │ │ │ │ }, │ │ │ │ - wheelChange: function(evt, deltaZ) { │ │ │ │ - if (!this.map.fractionalZoom) { │ │ │ │ - deltaZ = Math.round(deltaZ) │ │ │ │ - } │ │ │ │ - var currentZoom = this.map.getZoom(), │ │ │ │ - newZoom = currentZoom + deltaZ; │ │ │ │ - newZoom = Math.max(newZoom, 0); │ │ │ │ - newZoom = Math.min(newZoom, this.map.getNumZoomLevels()); │ │ │ │ - if (newZoom === currentZoom) { │ │ │ │ - return │ │ │ │ + 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 (!this.multipleSelect()) { │ │ │ │ + this.unselectAll() │ │ │ │ + } │ │ │ │ + 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]; │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ } │ │ │ │ - this.map.zoomTo(newZoom, evt.xy) │ │ │ │ - }, │ │ │ │ - wheelUp: function(evt, delta) { │ │ │ │ - this.wheelChange(evt, delta || 1) │ │ │ │ - }, │ │ │ │ - wheelDown: function(evt, delta) { │ │ │ │ - this.wheelChange(evt, delta || -1) │ │ │ │ }, │ │ │ │ - disableZoomBox: function() { │ │ │ │ - this.zoomBoxEnabled = false; │ │ │ │ - this.zoomBox.deactivate() │ │ │ │ - }, │ │ │ │ - enableZoomBox: function() { │ │ │ │ - this.zoomBoxEnabled = true; │ │ │ │ - if (this.active) { │ │ │ │ - this.zoomBox.activate() │ │ │ │ + setMap: function(map) { │ │ │ │ + this.handlers.feature.setMap(map); │ │ │ │ + if (this.box) { │ │ │ │ + this.handlers.box.setMap(map) │ │ │ │ } │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ }, │ │ │ │ - disableZoomWheel: function() { │ │ │ │ - this.zoomWheelEnabled = false; │ │ │ │ - this.handlers.wheel.deactivate() │ │ │ │ - }, │ │ │ │ - enableZoomWheel: function() { │ │ │ │ - this.zoomWheelEnabled = true; │ │ │ │ - if (this.active) { │ │ │ │ - this.handlers.wheel.activate() │ │ │ │ + setLayer: function(layers) { │ │ │ │ + var isActive = this.active; │ │ │ │ + this.unselectAll(); │ │ │ │ + this.deactivate(); │ │ │ │ + if (this.layers) { │ │ │ │ + this.layer.destroy(); │ │ │ │ + this.layers = null │ │ │ │ } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Navigation" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.NavToolbar = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ - this.addControls([new OpenLayers.Control.Navigation, new OpenLayers.Control.ZoomBox]) │ │ │ │ - }, │ │ │ │ - draw: function() { │ │ │ │ - var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments); │ │ │ │ - if (this.defaultControl === null) { │ │ │ │ - this.defaultControl = this.controls[0] │ │ │ │ + this.initLayer(layers); │ │ │ │ + this.handlers.feature.layer = this.layer; │ │ │ │ + if (isActive) { │ │ │ │ + this.activate() │ │ │ │ } │ │ │ │ - return div │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.NavToolbar" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.SelectFeature" │ │ │ │ }); │ │ │ │ OpenLayers.Control.TransformFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ geometryTypes: null, │ │ │ │ layer: null, │ │ │ │ preserveAspectRatio: false, │ │ │ │ rotate: true, │ │ │ │ feature: null, │ │ │ │ @@ -25105,14 +27668,1673 @@ │ │ │ │ this.layer = null; │ │ │ │ this.dragControl.destroy(); │ │ │ │ this.dragControl = null; │ │ │ │ OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.TransformFeature" │ │ │ │ }); │ │ │ │ +OpenLayers.Control.KeyboardDefaults = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + autoActivate: true, │ │ │ │ + slideFactor: 75, │ │ │ │ + observeElement: null, │ │ │ │ + draw: function() { │ │ │ │ + var observeElement = this.observeElement || document; │ │ │ │ + this.handler = new OpenLayers.Handler.Keyboard(this, { │ │ │ │ + keydown: this.defaultKeyPress │ │ │ │ + }, { │ │ │ │ + observeElement: observeElement │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + defaultKeyPress: function(evt) { │ │ │ │ + var size, handled = true; │ │ │ │ + var target = OpenLayers.Event.element(evt); │ │ │ │ + if (target && (target.tagName == "INPUT" || target.tagName == "TEXTAREA" || target.tagName == "SELECT")) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + switch (evt.keyCode) { │ │ │ │ + case OpenLayers.Event.KEY_LEFT: │ │ │ │ + this.map.pan(-this.slideFactor, 0); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Event.KEY_RIGHT: │ │ │ │ + this.map.pan(this.slideFactor, 0); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Event.KEY_UP: │ │ │ │ + this.map.pan(0, -this.slideFactor); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Event.KEY_DOWN: │ │ │ │ + this.map.pan(0, this.slideFactor); │ │ │ │ + break; │ │ │ │ + case 33: │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(0, -.75 * size.h); │ │ │ │ + break; │ │ │ │ + case 34: │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(0, .75 * size.h); │ │ │ │ + break; │ │ │ │ + case 35: │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(.75 * size.w, 0); │ │ │ │ + break; │ │ │ │ + case 36: │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(-.75 * size.w, 0); │ │ │ │ + break; │ │ │ │ + case 43: │ │ │ │ + case 61: │ │ │ │ + case 187: │ │ │ │ + case 107: │ │ │ │ + this.map.zoomIn(); │ │ │ │ + break; │ │ │ │ + case 45: │ │ │ │ + case 109: │ │ │ │ + case 189: │ │ │ │ + case 95: │ │ │ │ + this.map.zoomOut(); │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + handled = false │ │ │ │ + } │ │ │ │ + if (handled) { │ │ │ │ + OpenLayers.Event.stop(evt) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.KeyboardDefaults" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.ZoomToMaxExtent = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ + trigger: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.zoomToMaxExtent() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomToMaxExtent" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.WMTSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + hover: false, │ │ │ │ + requestEncoding: "KVP", │ │ │ │ + drillDown: false, │ │ │ │ + maxFeatures: 10, │ │ │ │ + clickCallback: "click", │ │ │ │ + layers: null, │ │ │ │ + queryVisible: true, │ │ │ │ + infoFormat: "text/html", │ │ │ │ + vendorParams: {}, │ │ │ │ + format: null, │ │ │ │ + formatOptions: null, │ │ │ │ + handler: null, │ │ │ │ + hoverRequest: null, │ │ │ │ + pending: 0, │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + options.handlerOptions = options.handlerOptions || {}; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + if (!this.format) { │ │ │ │ + this.format = new OpenLayers.Format.WMSGetFeatureInfo(options.formatOptions) │ │ │ │ + } │ │ │ │ + if (this.drillDown === true) { │ │ │ │ + this.hover = false │ │ │ │ + } │ │ │ │ + if (this.hover) { │ │ │ │ + this.handler = new OpenLayers.Handler.Hover(this, { │ │ │ │ + move: this.cancelHover, │ │ │ │ + pause: this.getInfoForHover │ │ │ │ + }, OpenLayers.Util.extend(this.handlerOptions.hover || {}, { │ │ │ │ + delay: 250 │ │ │ │ + })) │ │ │ │ + } else { │ │ │ │ + var callbacks = {}; │ │ │ │ + callbacks[this.clickCallback] = this.getInfoForClick; │ │ │ │ + this.handler = new OpenLayers.Handler.Click(this, callbacks, this.handlerOptions.click || {}) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getInfoForClick: function(evt) { │ │ │ │ + this.request(evt.xy, {}) │ │ │ │ + }, │ │ │ │ + getInfoForHover: function(evt) { │ │ │ │ + this.request(evt.xy, { │ │ │ │ + hover: true │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + cancelHover: function() { │ │ │ │ + if (this.hoverRequest) { │ │ │ │ + --this.pending; │ │ │ │ + if (this.pending <= 0) { │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + this.pending = 0 │ │ │ │ + } │ │ │ │ + this.hoverRequest.abort(); │ │ │ │ + this.hoverRequest = null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + findLayers: function() { │ │ │ │ + var candidates = this.layers || this.map.layers; │ │ │ │ + var layers = []; │ │ │ │ + var layer; │ │ │ │ + for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ + layer = candidates[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.WMTS && layer.requestEncoding === this.requestEncoding && (!this.queryVisible || layer.getVisibility())) { │ │ │ │ + layers.push(layer); │ │ │ │ + if (!this.drillDown || this.hover) { │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return layers │ │ │ │ + }, │ │ │ │ + buildRequestOptions: function(layer, xy) { │ │ │ │ + var loc = this.map.getLonLatFromPixel(xy); │ │ │ │ + var getTileUrl = layer.getURL(new OpenLayers.Bounds(loc.lon, loc.lat, loc.lon, loc.lat)); │ │ │ │ + var params = OpenLayers.Util.getParameters(getTileUrl); │ │ │ │ + var tileInfo = layer.getTileInfo(loc); │ │ │ │ + OpenLayers.Util.extend(params, { │ │ │ │ + service: "WMTS", │ │ │ │ + version: layer.version, │ │ │ │ + request: "GetFeatureInfo", │ │ │ │ + infoFormat: this.infoFormat, │ │ │ │ + i: tileInfo.i, │ │ │ │ + j: tileInfo.j │ │ │ │ + }); │ │ │ │ + OpenLayers.Util.applyDefaults(params, this.vendorParams); │ │ │ │ + return { │ │ │ │ + url: OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url, │ │ │ │ + params: OpenLayers.Util.upperCaseObject(params), │ │ │ │ + callback: function(request) { │ │ │ │ + this.handleResponse(xy, request, layer) │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + request: function(xy, options) { │ │ │ │ + options = options || {}; │ │ │ │ + var layers = this.findLayers(); │ │ │ │ + if (layers.length > 0) { │ │ │ │ + var issue, layer; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + layer = layers[i]; │ │ │ │ + issue = this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ + xy: xy, │ │ │ │ + layer: layer │ │ │ │ + }); │ │ │ │ + if (issue !== false) { │ │ │ │ + ++this.pending; │ │ │ │ + var requestOptions = this.buildRequestOptions(layer, xy); │ │ │ │ + var request = OpenLayers.Request.GET(requestOptions); │ │ │ │ + if (options.hover === true) { │ │ │ │ + this.hoverRequest = request │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.pending > 0) { │ │ │ │ + OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + handleResponse: function(xy, request, layer) { │ │ │ │ + --this.pending; │ │ │ │ + if (this.pending <= 0) { │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + this.pending = 0 │ │ │ │ + } │ │ │ │ + if (request.status && (request.status < 200 || request.status >= 300)) { │ │ │ │ + this.events.triggerEvent("exception", { │ │ │ │ + xy: xy, │ │ │ │ + request: request, │ │ │ │ + layer: layer │ │ │ │ + }) │ │ │ │ + } else { │ │ │ │ + var doc = request.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = request.responseText │ │ │ │ + } │ │ │ │ + var features, except; │ │ │ │ + try { │ │ │ │ + features = this.format.read(doc) │ │ │ │ + } catch (error) { │ │ │ │ + except = true; │ │ │ │ + this.events.triggerEvent("exception", { │ │ │ │ + xy: xy, │ │ │ │ + request: request, │ │ │ │ + error: error, │ │ │ │ + layer: layer │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + if (!except) { │ │ │ │ + this.events.triggerEvent("getfeatureinfo", { │ │ │ │ + text: request.responseText, │ │ │ │ + features: features, │ │ │ │ + request: request, │ │ │ │ + xy: xy, │ │ │ │ + layer: layer │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.WMTSGetFeatureInfo" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Pan = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ + slideFactor: 50, │ │ │ │ + slideRatio: null, │ │ │ │ + direction: null, │ │ │ │ + initialize: function(direction, options) { │ │ │ │ + this.direction = direction; │ │ │ │ + this.CLASS_NAME += this.direction; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + trigger: function() { │ │ │ │ + if (this.map) { │ │ │ │ + var getSlideFactor = OpenLayers.Function.bind(function(dim) { │ │ │ │ + return this.slideRatio ? this.map.getSize()[dim] * this.slideRatio : this.slideFactor │ │ │ │ + }, this); │ │ │ │ + switch (this.direction) { │ │ │ │ + case OpenLayers.Control.Pan.NORTH: │ │ │ │ + this.map.pan(0, -getSlideFactor("h")); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Control.Pan.SOUTH: │ │ │ │ + this.map.pan(0, getSlideFactor("h")); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Control.Pan.WEST: │ │ │ │ + this.map.pan(-getSlideFactor("w"), 0); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Control.Pan.EAST: │ │ │ │ + this.map.pan(getSlideFactor("w"), 0); │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Pan" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Pan.NORTH = "North"; │ │ │ │ +OpenLayers.Control.Pan.SOUTH = "South"; │ │ │ │ +OpenLayers.Control.Pan.EAST = "East"; │ │ │ │ +OpenLayers.Control.Pan.WEST = "West"; │ │ │ │ +OpenLayers.Control.PanPanel = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ + slideFactor: 50, │ │ │ │ + slideRatio: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ + var options = { │ │ │ │ + slideFactor: this.slideFactor, │ │ │ │ + slideRatio: this.slideRatio │ │ │ │ + }; │ │ │ │ + this.addControls([new OpenLayers.Control.Pan(OpenLayers.Control.Pan.NORTH, options), new OpenLayers.Control.Pan(OpenLayers.Control.Pan.SOUTH, options), new OpenLayers.Control.Pan(OpenLayers.Control.Pan.EAST, options), new OpenLayers.Control.Pan(OpenLayers.Control.Pan.WEST, options)]) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.PanPanel" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + center: null, │ │ │ │ + zoom: null, │ │ │ │ + layers: null, │ │ │ │ + displayProjection: null, │ │ │ │ + getParameters: function(url) { │ │ │ │ + url = url || window.location.href; │ │ │ │ + var parameters = OpenLayers.Util.getParameters(url); │ │ │ │ + var index = url.indexOf("#"); │ │ │ │ + if (index > 0) { │ │ │ │ + url = "?" + url.substring(index + 1, url.length); │ │ │ │ + OpenLayers.Util.extend(parameters, OpenLayers.Util.getParameters(url)) │ │ │ │ + } │ │ │ │ + return parameters │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ + var control = this.map.controls[i]; │ │ │ │ + if (control != this && control.CLASS_NAME == "OpenLayers.Control.ArgParser") { │ │ │ │ + if (control.displayProjection != this.displayProjection) { │ │ │ │ + this.displayProjection = control.displayProjection │ │ │ │ + } │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (i == this.map.controls.length) { │ │ │ │ + var args = this.getParameters(); │ │ │ │ + if (args.layers) { │ │ │ │ + this.layers = args.layers; │ │ │ │ + this.map.events.register("addlayer", this, this.configureLayers); │ │ │ │ + this.configureLayers() │ │ │ │ + } │ │ │ │ + if (args.lat && args.lon) { │ │ │ │ + this.center = new OpenLayers.LonLat(parseFloat(args.lon), parseFloat(args.lat)); │ │ │ │ + if (args.zoom) { │ │ │ │ + this.zoom = parseFloat(args.zoom) │ │ │ │ + } │ │ │ │ + this.map.events.register("changebaselayer", this, this.setCenter); │ │ │ │ + this.setCenter() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setCenter: function() { │ │ │ │ + if (this.map.baseLayer) { │ │ │ │ + this.map.events.unregister("changebaselayer", this, this.setCenter); │ │ │ │ + if (this.displayProjection) { │ │ │ │ + this.center.transform(this.displayProjection, this.map.getProjectionObject()) │ │ │ │ + } │ │ │ │ + this.map.setCenter(this.center, this.zoom) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + configureLayers: function() { │ │ │ │ + if (this.layers.length == this.map.layers.length) { │ │ │ │ + this.map.events.unregister("addlayer", this, this.configureLayers); │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + var c = this.layers.charAt(i); │ │ │ │ + if (c == "B") { │ │ │ │ + this.map.setBaseLayer(layer) │ │ │ │ + } else if (c == "T" || c == "F") { │ │ │ │ + layer.setVisibility(c == "T") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ArgParser" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + argParserClass: OpenLayers.Control.ArgParser, │ │ │ │ + element: null, │ │ │ │ + anchor: false, │ │ │ │ + base: "", │ │ │ │ + displayProjection: null, │ │ │ │ + initialize: function(element, base, options) { │ │ │ │ + if (element !== null && typeof element == "object" && !OpenLayers.Util.isElement(element)) { │ │ │ │ + options = element; │ │ │ │ + this.base = document.location.href; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + if (this.element != null) { │ │ │ │ + this.element = OpenLayers.Util.getElement(this.element) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.element = OpenLayers.Util.getElement(element); │ │ │ │ + this.base = base || document.location.href │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.element && this.element.parentNode == this.div) { │ │ │ │ + this.div.removeChild(this.element); │ │ │ │ + this.element = null │ │ │ │ + } │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.unregister("moveend", this, this.updateLink) │ │ │ │ + } │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ + var control = this.map.controls[i]; │ │ │ │ + if (control.CLASS_NAME == this.argParserClass.CLASS_NAME) { │ │ │ │ + if (control.displayProjection != this.displayProjection) { │ │ │ │ + this.displayProjection = control.displayProjection │ │ │ │ + } │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (i == this.map.controls.length) { │ │ │ │ + this.map.addControl(new this.argParserClass({ │ │ │ │ + displayProjection: this.displayProjection │ │ │ │ + })) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (!this.element && !this.anchor) { │ │ │ │ + this.element = document.createElement("a"); │ │ │ │ + this.element.innerHTML = OpenLayers.i18n("Permalink"); │ │ │ │ + this.element.href = ""; │ │ │ │ + this.div.appendChild(this.element) │ │ │ │ + } │ │ │ │ + this.map.events.on({ │ │ │ │ + moveend: this.updateLink, │ │ │ │ + changelayer: this.updateLink, │ │ │ │ + changebaselayer: this.updateLink, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.updateLink(); │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + updateLink: function() { │ │ │ │ + var separator = this.anchor ? "#" : "?"; │ │ │ │ + var href = this.base; │ │ │ │ + var anchor = null; │ │ │ │ + if (href.indexOf("#") != -1 && this.anchor == false) { │ │ │ │ + anchor = href.substring(href.indexOf("#"), href.length) │ │ │ │ + } │ │ │ │ + if (href.indexOf(separator) != -1) { │ │ │ │ + href = href.substring(0, href.indexOf(separator)) │ │ │ │ + } │ │ │ │ + var splits = href.split("#"); │ │ │ │ + href = splits[0] + separator + OpenLayers.Util.getParameterString(this.createParams()); │ │ │ │ + if (anchor) { │ │ │ │ + href += anchor │ │ │ │ + } │ │ │ │ + if (this.anchor && !this.element) { │ │ │ │ + window.location.href = href │ │ │ │ + } else { │ │ │ │ + this.element.href = href │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + createParams: function(center, zoom, layers) { │ │ │ │ + center = center || this.map.getCenter(); │ │ │ │ + var params = OpenLayers.Util.getParameters(this.base); │ │ │ │ + if (center) { │ │ │ │ + params.zoom = zoom || this.map.getZoom(); │ │ │ │ + var lat = center.lat; │ │ │ │ + var lon = center.lon; │ │ │ │ + if (this.displayProjection) { │ │ │ │ + var mapPosition = OpenLayers.Projection.transform({ │ │ │ │ + x: lon, │ │ │ │ + y: lat │ │ │ │ + }, this.map.getProjectionObject(), this.displayProjection); │ │ │ │ + lon = mapPosition.x; │ │ │ │ + lat = mapPosition.y │ │ │ │ + } │ │ │ │ + params.lat = Math.round(lat * 1e5) / 1e5; │ │ │ │ + params.lon = Math.round(lon * 1e5) / 1e5; │ │ │ │ + layers = layers || this.map.layers; │ │ │ │ + params.layers = ""; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + var layer = layers[i]; │ │ │ │ + if (layer.isBaseLayer) { │ │ │ │ + params.layers += layer == this.map.baseLayer ? "B" : "0" │ │ │ │ + } else { │ │ │ │ + params.layers += layer.getVisibility() ? "T" : "F" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return params │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Permalink" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.GetFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + protocol: null, │ │ │ │ + multipleKey: null, │ │ │ │ + toggleKey: null, │ │ │ │ + modifiers: null, │ │ │ │ + multiple: false, │ │ │ │ + click: true, │ │ │ │ + single: true, │ │ │ │ + clickout: true, │ │ │ │ + toggle: false, │ │ │ │ + clickTolerance: 5, │ │ │ │ + hover: false, │ │ │ │ + box: false, │ │ │ │ + maxFeatures: 10, │ │ │ │ + features: null, │ │ │ │ + hoverFeature: null, │ │ │ │ + handlers: null, │ │ │ │ + hoverResponse: null, │ │ │ │ + filterType: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ + initialize: function(options) { │ │ │ │ + options.handlerOptions = options.handlerOptions || {}; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.features = {}; │ │ │ │ + this.handlers = {}; │ │ │ │ + if (this.click) { │ │ │ │ + this.handlers.click = new OpenLayers.Handler.Click(this, { │ │ │ │ + click: this.selectClick │ │ │ │ + }, this.handlerOptions.click || {}) │ │ │ │ + } │ │ │ │ + if (this.box) { │ │ │ │ + this.handlers.box = new OpenLayers.Handler.Box(this, { │ │ │ │ + done: this.selectBox │ │ │ │ + }, OpenLayers.Util.extend(this.handlerOptions.box, { │ │ │ │ + boxDivClassName: "olHandlerBoxSelectFeature" │ │ │ │ + })) │ │ │ │ + } │ │ │ │ + if (this.hover) { │ │ │ │ + this.handlers.hover = new OpenLayers.Handler.Hover(this, { │ │ │ │ + move: this.cancelHover, │ │ │ │ + pause: this.selectHover │ │ │ │ + }, OpenLayers.Util.extend(this.handlerOptions.hover, { │ │ │ │ + delay: 250, │ │ │ │ + pixelTolerance: 2 │ │ │ │ + })) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (!this.active) { │ │ │ │ + for (var i in this.handlers) { │ │ │ │ + this.handlers[i].activate() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return OpenLayers.Control.prototype.activate.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (this.active) { │ │ │ │ + for (var i in this.handlers) { │ │ │ │ + this.handlers[i].deactivate() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + selectClick: function(evt) { │ │ │ │ + var bounds = this.pixelToBounds(evt.xy); │ │ │ │ + this.setModifiers(evt); │ │ │ │ + this.request(bounds, { │ │ │ │ + single: this.single │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + selectBox: function(position) { │ │ │ │ + var bounds; │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ + bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat, maxXY.lon, maxXY.lat) │ │ │ │ + } else { │ │ │ │ + if (this.click) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + bounds = this.pixelToBounds(position) │ │ │ │ + } │ │ │ │ + this.setModifiers(this.handlers.box.dragHandler.evt); │ │ │ │ + this.request(bounds) │ │ │ │ + }, │ │ │ │ + selectHover: function(evt) { │ │ │ │ + var bounds = this.pixelToBounds(evt.xy); │ │ │ │ + this.request(bounds, { │ │ │ │ + single: true, │ │ │ │ + hover: true │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + cancelHover: function() { │ │ │ │ + if (this.hoverResponse) { │ │ │ │ + this.protocol.abort(this.hoverResponse); │ │ │ │ + this.hoverResponse = null; │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait") │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + request: function(bounds, options) { │ │ │ │ + options = options || {}; │ │ │ │ + var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: this.filterType, │ │ │ │ + value: bounds │ │ │ │ + }); │ │ │ │ + OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + var response = this.protocol.read({ │ │ │ │ + maxFeatures: options.single == true ? this.maxFeatures : undefined, │ │ │ │ + filter: filter, │ │ │ │ + callback: function(result) { │ │ │ │ + if (result.success()) { │ │ │ │ + if (result.features.length) { │ │ │ │ + if (options.single == true) { │ │ │ │ + this.selectBestFeature(result.features, bounds.getCenterLonLat(), options) │ │ │ │ + } else { │ │ │ │ + this.select(result.features) │ │ │ │ + } │ │ │ │ + } else if (options.hover) { │ │ │ │ + this.hoverSelect() │ │ │ │ + } else { │ │ │ │ + this.events.triggerEvent("clickout"); │ │ │ │ + if (this.clickout) { │ │ │ │ + this.unselectAll() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait") │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + if (options.hover == true) { │ │ │ │ + this.hoverResponse = response │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + selectBestFeature: function(features, clickPosition, options) { │ │ │ │ + options = options || {}; │ │ │ │ + if (features.length) { │ │ │ │ + var point = new OpenLayers.Geometry.Point(clickPosition.lon, clickPosition.lat); │ │ │ │ + var feature, resultFeature, dist; │ │ │ │ + var minDist = Number.MAX_VALUE; │ │ │ │ + for (var i = 0; i < features.length; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + if (feature.geometry) { │ │ │ │ + dist = point.distanceTo(feature.geometry, { │ │ │ │ + edge: false │ │ │ │ + }); │ │ │ │ + if (dist < minDist) { │ │ │ │ + minDist = dist; │ │ │ │ + resultFeature = feature; │ │ │ │ + if (minDist == 0) { │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (options.hover == true) { │ │ │ │ + this.hoverSelect(resultFeature) │ │ │ │ + } else { │ │ │ │ + this.select(resultFeature || features) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setModifiers: function(evt) { │ │ │ │ + this.modifiers = { │ │ │ │ + multiple: this.multiple || this.multipleKey && evt[this.multipleKey], │ │ │ │ + toggle: this.toggle || this.toggleKey && evt[this.toggleKey] │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + select: function(features) { │ │ │ │ + if (!this.modifiers.multiple && !this.modifiers.toggle) { │ │ │ │ + this.unselectAll() │ │ │ │ + } │ │ │ │ + if (!OpenLayers.Util.isArray(features)) { │ │ │ │ + features = [features] │ │ │ │ + } │ │ │ │ + var cont = this.events.triggerEvent("beforefeaturesselected", { │ │ │ │ + features: features │ │ │ │ + }); │ │ │ │ + if (cont !== false) { │ │ │ │ + var selectedFeatures = []; │ │ │ │ + var feature; │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + if (this.features[feature.fid || feature.id]) { │ │ │ │ + if (this.modifiers.toggle) { │ │ │ │ + this.unselect(this.features[feature.fid || feature.id]) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + cont = this.events.triggerEvent("beforefeatureselected", { │ │ │ │ + feature: feature │ │ │ │ + }); │ │ │ │ + if (cont !== false) { │ │ │ │ + this.features[feature.fid || feature.id] = feature; │ │ │ │ + selectedFeatures.push(feature); │ │ │ │ + this.events.triggerEvent("featureselected", { │ │ │ │ + feature: feature │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.events.triggerEvent("featuresselected", { │ │ │ │ + features: selectedFeatures │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + hoverSelect: function(feature) { │ │ │ │ + var fid = feature ? feature.fid || feature.id : null; │ │ │ │ + var hfid = this.hoverFeature ? this.hoverFeature.fid || this.hoverFeature.id : null; │ │ │ │ + if (hfid && hfid != fid) { │ │ │ │ + this.events.triggerEvent("outfeature", { │ │ │ │ + feature: this.hoverFeature │ │ │ │ + }); │ │ │ │ + this.hoverFeature = null │ │ │ │ + } │ │ │ │ + if (fid && fid != hfid) { │ │ │ │ + this.events.triggerEvent("hoverfeature", { │ │ │ │ + feature: feature │ │ │ │ + }); │ │ │ │ + this.hoverFeature = feature │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + unselect: function(feature) { │ │ │ │ + delete this.features[feature.fid || feature.id]; │ │ │ │ + this.events.triggerEvent("featureunselected", { │ │ │ │ + feature: feature │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + unselectAll: function() { │ │ │ │ + for (var fid in this.features) { │ │ │ │ + this.unselect(this.features[fid]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + for (var i in this.handlers) { │ │ │ │ + this.handlers[i].setMap(map) │ │ │ │ + } │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + pixelToBounds: function(pixel) { │ │ │ │ + var llPx = pixel.add(-this.clickTolerance / 2, this.clickTolerance / 2); │ │ │ │ + var urPx = pixel.add(this.clickTolerance / 2, -this.clickTolerance / 2); │ │ │ │ + var ll = this.map.getLonLatFromPixel(llPx); │ │ │ │ + var ur = this.map.getLonLatFromPixel(urPx); │ │ │ │ + return new OpenLayers.Bounds(ll.lon, ll.lat, ur.lon, ur.lat) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.GetFeature" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Graticule = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + autoActivate: true, │ │ │ │ + intervals: [45, 30, 20, 10, 5, 2, 1, .5, .2, .1, .05, .01, .005, .002, .001], │ │ │ │ + displayInLayerSwitcher: true, │ │ │ │ + visible: true, │ │ │ │ + numPoints: 50, │ │ │ │ + targetSize: 200, │ │ │ │ + layerName: null, │ │ │ │ + labelled: true, │ │ │ │ + labelFormat: "dm", │ │ │ │ + lineSymbolizer: { │ │ │ │ + strokeColor: "#333", │ │ │ │ + strokeWidth: 1, │ │ │ │ + strokeOpacity: .5 │ │ │ │ + }, │ │ │ │ + labelSymbolizer: {}, │ │ │ │ + gratLayer: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + options.layerName = options.layerName || OpenLayers.i18n("Graticule"); │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.labelSymbolizer.stroke = false; │ │ │ │ + this.labelSymbolizer.fill = false; │ │ │ │ + this.labelSymbolizer.label = "${label}"; │ │ │ │ + this.labelSymbolizer.labelAlign = "${labelAlign}"; │ │ │ │ + this.labelSymbolizer.labelXOffset = "${xOffset}"; │ │ │ │ + this.labelSymbolizer.labelYOffset = "${yOffset}" │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + if (this.gratLayer) { │ │ │ │ + this.gratLayer.destroy(); │ │ │ │ + this.gratLayer = null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (!this.gratLayer) { │ │ │ │ + var gratStyle = new OpenLayers.Style({}, { │ │ │ │ + rules: [new OpenLayers.Rule({ │ │ │ │ + symbolizer: { │ │ │ │ + Point: this.labelSymbolizer, │ │ │ │ + Line: this.lineSymbolizer │ │ │ │ + } │ │ │ │ + })] │ │ │ │ + }); │ │ │ │ + this.gratLayer = new OpenLayers.Layer.Vector(this.layerName, { │ │ │ │ + styleMap: new OpenLayers.StyleMap({ │ │ │ │ + default: gratStyle │ │ │ │ + }), │ │ │ │ + visibility: this.visible, │ │ │ │ + displayInLayerSwitcher: this.displayInLayerSwitcher │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.map.addLayer(this.gratLayer); │ │ │ │ + this.map.events.register("moveend", this, this.update); │ │ │ │ + this.update(); │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + this.map.events.unregister("moveend", this, this.update); │ │ │ │ + this.map.removeLayer(this.gratLayer); │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + update: function() { │ │ │ │ + var mapBounds = this.map.getExtent(); │ │ │ │ + if (!mapBounds) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + this.gratLayer.destroyFeatures(); │ │ │ │ + var llProj = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ + var mapProj = this.map.getProjectionObject(); │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ + if (mapProj.proj && mapProj.proj.projName == "longlat") { │ │ │ │ + this.numPoints = 1 │ │ │ │ + } │ │ │ │ + var mapCenter = this.map.getCenter(); │ │ │ │ + var mapCenterLL = new OpenLayers.Pixel(mapCenter.lon, mapCenter.lat); │ │ │ │ + OpenLayers.Projection.transform(mapCenterLL, mapProj, llProj); │ │ │ │ + var testSq = this.targetSize * mapRes; │ │ │ │ + testSq *= testSq; │ │ │ │ + var llInterval; │ │ │ │ + for (var i = 0; i < this.intervals.length; ++i) { │ │ │ │ + llInterval = this.intervals[i]; │ │ │ │ + var delta = llInterval / 2; │ │ │ │ + var p1 = mapCenterLL.offset({ │ │ │ │ + x: -delta, │ │ │ │ + y: -delta │ │ │ │ + }); │ │ │ │ + var p2 = mapCenterLL.offset({ │ │ │ │ + x: delta, │ │ │ │ + y: delta │ │ │ │ + }); │ │ │ │ + OpenLayers.Projection.transform(p1, llProj, mapProj); │ │ │ │ + OpenLayers.Projection.transform(p2, llProj, mapProj); │ │ │ │ + var distSq = (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y); │ │ │ │ + if (distSq <= testSq) { │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + mapCenterLL.x = Math.floor(mapCenterLL.x / llInterval) * llInterval; │ │ │ │ + mapCenterLL.y = Math.floor(mapCenterLL.y / llInterval) * llInterval; │ │ │ │ + var iter = 0; │ │ │ │ + var centerLonPoints = [mapCenterLL.clone()]; │ │ │ │ + var newPoint = mapCenterLL.clone(); │ │ │ │ + var mapXY; │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: 0, │ │ │ │ + y: llInterval │ │ │ │ + }); │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLonPoints.unshift(newPoint) │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ + newPoint = mapCenterLL.clone(); │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: 0, │ │ │ │ + y: -llInterval │ │ │ │ + }); │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLonPoints.push(newPoint) │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ + iter = 0; │ │ │ │ + var centerLatPoints = [mapCenterLL.clone()]; │ │ │ │ + newPoint = mapCenterLL.clone(); │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: -llInterval, │ │ │ │ + y: 0 │ │ │ │ + }); │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLatPoints.unshift(newPoint) │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ + newPoint = mapCenterLL.clone(); │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: llInterval, │ │ │ │ + y: 0 │ │ │ │ + }); │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLatPoints.push(newPoint) │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ + var lines = []; │ │ │ │ + for (var i = 0; i < centerLatPoints.length; ++i) { │ │ │ │ + var lon = centerLatPoints[i].x; │ │ │ │ + var pointList = []; │ │ │ │ + var labelPoint = null; │ │ │ │ + var latEnd = Math.min(centerLonPoints[0].y, 90); │ │ │ │ + var latStart = Math.max(centerLonPoints[centerLonPoints.length - 1].y, -90); │ │ │ │ + var latDelta = (latEnd - latStart) / this.numPoints; │ │ │ │ + var lat = latStart; │ │ │ │ + for (var j = 0; j <= this.numPoints; ++j) { │ │ │ │ + var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ + gridPoint.transform(llProj, mapProj); │ │ │ │ + pointList.push(gridPoint); │ │ │ │ + lat += latDelta; │ │ │ │ + if (gridPoint.y >= mapBounds.bottom && !labelPoint) { │ │ │ │ + labelPoint = gridPoint │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.labelled) { │ │ │ │ + var labelPos = new OpenLayers.Geometry.Point(labelPoint.x, mapBounds.bottom); │ │ │ │ + var labelAttrs = { │ │ │ │ + value: lon, │ │ │ │ + label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lon, "lon", this.labelFormat) : "", │ │ │ │ + labelAlign: "cb", │ │ │ │ + xOffset: 0, │ │ │ │ + yOffset: 2 │ │ │ │ + }; │ │ │ │ + this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)) │ │ │ │ + } │ │ │ │ + var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ + lines.push(new OpenLayers.Feature.Vector(geom)) │ │ │ │ + } │ │ │ │ + for (var j = 0; j < centerLonPoints.length; ++j) { │ │ │ │ + lat = centerLonPoints[j].y; │ │ │ │ + if (lat < -90 || lat > 90) { │ │ │ │ + continue │ │ │ │ + } │ │ │ │ + var pointList = []; │ │ │ │ + var lonStart = centerLatPoints[0].x; │ │ │ │ + var lonEnd = centerLatPoints[centerLatPoints.length - 1].x; │ │ │ │ + var lonDelta = (lonEnd - lonStart) / this.numPoints; │ │ │ │ + var lon = lonStart; │ │ │ │ + var labelPoint = null; │ │ │ │ + for (var i = 0; i <= this.numPoints; ++i) { │ │ │ │ + var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ + gridPoint.transform(llProj, mapProj); │ │ │ │ + pointList.push(gridPoint); │ │ │ │ + lon += lonDelta; │ │ │ │ + if (gridPoint.x < mapBounds.right) { │ │ │ │ + labelPoint = gridPoint │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.labelled) { │ │ │ │ + var labelPos = new OpenLayers.Geometry.Point(mapBounds.right, labelPoint.y); │ │ │ │ + var labelAttrs = { │ │ │ │ + value: lat, │ │ │ │ + label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lat, "lat", this.labelFormat) : "", │ │ │ │ + labelAlign: "rb", │ │ │ │ + xOffset: -2, │ │ │ │ + yOffset: 2 │ │ │ │ + }; │ │ │ │ + this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)) │ │ │ │ + } │ │ │ │ + var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ + lines.push(new OpenLayers.Feature.Vector(geom)) │ │ │ │ + } │ │ │ │ + this.gratLayer.addFeatures(lines) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Graticule" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Snapping = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + DEFAULTS: { │ │ │ │ + tolerance: 10, │ │ │ │ + node: true, │ │ │ │ + edge: true, │ │ │ │ + vertex: true │ │ │ │ + }, │ │ │ │ + greedy: true, │ │ │ │ + precedence: ["node", "vertex", "edge"], │ │ │ │ + resolution: null, │ │ │ │ + geoToleranceCache: null, │ │ │ │ + layer: null, │ │ │ │ + feature: null, │ │ │ │ + point: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.options = options || {}; │ │ │ │ + if (this.options.layer) { │ │ │ │ + this.setLayer(this.options.layer) │ │ │ │ + } │ │ │ │ + var defaults = OpenLayers.Util.extend({}, this.options.defaults); │ │ │ │ + this.defaults = OpenLayers.Util.applyDefaults(defaults, this.DEFAULTS); │ │ │ │ + this.setTargets(this.options.targets); │ │ │ │ + if (this.targets.length === 0 && this.layer) { │ │ │ │ + this.addTargetLayer(this.layer) │ │ │ │ + } │ │ │ │ + this.geoToleranceCache = {} │ │ │ │ + }, │ │ │ │ + setLayer: function(layer) { │ │ │ │ + if (this.active) { │ │ │ │ + this.deactivate(); │ │ │ │ + this.layer = layer; │ │ │ │ + this.activate() │ │ │ │ + } else { │ │ │ │ + this.layer = layer │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setTargets: function(targets) { │ │ │ │ + this.targets = []; │ │ │ │ + if (targets && targets.length) { │ │ │ │ + var target; │ │ │ │ + for (var i = 0, len = targets.length; i < len; ++i) { │ │ │ │ + target = targets[i]; │ │ │ │ + if (target instanceof OpenLayers.Layer.Vector) { │ │ │ │ + this.addTargetLayer(target) │ │ │ │ + } else { │ │ │ │ + this.addTarget(target) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + addTargetLayer: function(layer) { │ │ │ │ + this.addTarget({ │ │ │ │ + layer: layer │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + addTarget: function(target) { │ │ │ │ + target = OpenLayers.Util.applyDefaults(target, this.defaults); │ │ │ │ + target.nodeTolerance = target.nodeTolerance || target.tolerance; │ │ │ │ + target.vertexTolerance = target.vertexTolerance || target.tolerance; │ │ │ │ + target.edgeTolerance = target.edgeTolerance || target.tolerance; │ │ │ │ + this.targets.push(target) │ │ │ │ + }, │ │ │ │ + removeTargetLayer: function(layer) { │ │ │ │ + var target; │ │ │ │ + for (var i = this.targets.length - 1; i >= 0; --i) { │ │ │ │ + target = this.targets[i]; │ │ │ │ + if (target.layer === layer) { │ │ │ │ + this.removeTarget(target) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + removeTarget: function(target) { │ │ │ │ + return OpenLayers.Util.removeItem(this.targets, target) │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + if (this.layer && this.layer.events) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + sketchstarted: this.onSketchModified, │ │ │ │ + sketchmodified: this.onSketchModified, │ │ │ │ + vertexmodified: this.onVertexModified, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + if (this.layer && this.layer.events) { │ │ │ │ + this.layer.events.un({ │ │ │ │ + sketchstarted: this.onSketchModified, │ │ │ │ + sketchmodified: this.onSketchModified, │ │ │ │ + vertexmodified: this.onVertexModified, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.feature = null; │ │ │ │ + this.point = null; │ │ │ │ + return deactivated │ │ │ │ + }, │ │ │ │ + onSketchModified: function(event) { │ │ │ │ + this.feature = event.feature; │ │ │ │ + this.considerSnapping(event.vertex, event.vertex) │ │ │ │ + }, │ │ │ │ + onVertexModified: function(event) { │ │ │ │ + this.feature = event.feature; │ │ │ │ + var loc = this.layer.map.getLonLatFromViewPortPx(event.pixel); │ │ │ │ + this.considerSnapping(event.vertex, new OpenLayers.Geometry.Point(loc.lon, loc.lat)) │ │ │ │ + }, │ │ │ │ + considerSnapping: function(point, loc) { │ │ │ │ + var best = { │ │ │ │ + rank: Number.POSITIVE_INFINITY, │ │ │ │ + dist: Number.POSITIVE_INFINITY, │ │ │ │ + x: null, │ │ │ │ + y: null │ │ │ │ + }; │ │ │ │ + var snapped = false; │ │ │ │ + var result, target; │ │ │ │ + for (var i = 0, len = this.targets.length; i < len; ++i) { │ │ │ │ + target = this.targets[i]; │ │ │ │ + result = this.testTarget(target, loc); │ │ │ │ + if (result) { │ │ │ │ + if (this.greedy) { │ │ │ │ + best = result; │ │ │ │ + best.target = target; │ │ │ │ + snapped = true; │ │ │ │ + break │ │ │ │ + } else { │ │ │ │ + if (result.rank < best.rank || result.rank === best.rank && result.dist < best.dist) { │ │ │ │ + best = result; │ │ │ │ + best.target = target; │ │ │ │ + snapped = true │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (snapped) { │ │ │ │ + var proceed = this.events.triggerEvent("beforesnap", { │ │ │ │ + point: point, │ │ │ │ + x: best.x, │ │ │ │ + y: best.y, │ │ │ │ + distance: best.dist, │ │ │ │ + layer: best.target.layer, │ │ │ │ + snapType: this.precedence[best.rank] │ │ │ │ + }); │ │ │ │ + if (proceed !== false) { │ │ │ │ + point.x = best.x; │ │ │ │ + point.y = best.y; │ │ │ │ + this.point = point; │ │ │ │ + this.events.triggerEvent("snap", { │ │ │ │ + point: point, │ │ │ │ + snapType: this.precedence[best.rank], │ │ │ │ + layer: best.target.layer, │ │ │ │ + distance: best.dist │ │ │ │ + }) │ │ │ │ + } else { │ │ │ │ + snapped = false │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.point && !snapped) { │ │ │ │ + point.x = loc.x; │ │ │ │ + point.y = loc.y; │ │ │ │ + this.point = null; │ │ │ │ + this.events.triggerEvent("unsnap", { │ │ │ │ + point: point │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + testTarget: function(target, loc) { │ │ │ │ + var resolution = this.layer.map.getResolution(); │ │ │ │ + if ("minResolution" in target) { │ │ │ │ + if (resolution < target.minResolution) { │ │ │ │ + return null │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if ("maxResolution" in target) { │ │ │ │ + if (resolution >= target.maxResolution) { │ │ │ │ + return null │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var tolerance = { │ │ │ │ + node: this.getGeoTolerance(target.nodeTolerance, resolution), │ │ │ │ + vertex: this.getGeoTolerance(target.vertexTolerance, resolution), │ │ │ │ + edge: this.getGeoTolerance(target.edgeTolerance, resolution) │ │ │ │ + }; │ │ │ │ + var maxTolerance = Math.max(tolerance.node, tolerance.vertex, tolerance.edge); │ │ │ │ + var result = { │ │ │ │ + rank: Number.POSITIVE_INFINITY, │ │ │ │ + dist: Number.POSITIVE_INFINITY │ │ │ │ + }; │ │ │ │ + var eligible = false; │ │ │ │ + var features = target.layer.features; │ │ │ │ + var feature, type, vertices, vertex, closest, dist, found; │ │ │ │ + var numTypes = this.precedence.length; │ │ │ │ + var ll = new OpenLayers.LonLat(loc.x, loc.y); │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + if (feature !== this.feature && !feature._sketch && feature.state !== OpenLayers.State.DELETE && (!target.filter || target.filter.evaluate(feature))) { │ │ │ │ + if (feature.atPoint(ll, maxTolerance, maxTolerance)) { │ │ │ │ + for (var j = 0, stop = Math.min(result.rank + 1, numTypes); j < stop; ++j) { │ │ │ │ + type = this.precedence[j]; │ │ │ │ + if (target[type]) { │ │ │ │ + if (type === "edge") { │ │ │ │ + closest = feature.geometry.distanceTo(loc, { │ │ │ │ + details: true │ │ │ │ + }); │ │ │ │ + dist = closest.distance; │ │ │ │ + if (dist <= tolerance[type] && dist < result.dist) { │ │ │ │ + result = { │ │ │ │ + rank: j, │ │ │ │ + dist: dist, │ │ │ │ + x: closest.x0, │ │ │ │ + y: closest.y0 │ │ │ │ + }; │ │ │ │ + eligible = true; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + vertices = feature.geometry.getVertices(type === "node"); │ │ │ │ + found = false; │ │ │ │ + for (var k = 0, klen = vertices.length; k < klen; ++k) { │ │ │ │ + vertex = vertices[k]; │ │ │ │ + dist = vertex.distanceTo(loc); │ │ │ │ + if (dist <= tolerance[type] && (j < result.rank || j === result.rank && dist < result.dist)) { │ │ │ │ + result = { │ │ │ │ + rank: j, │ │ │ │ + dist: dist, │ │ │ │ + x: vertex.x, │ │ │ │ + y: vertex.y │ │ │ │ + }; │ │ │ │ + eligible = true; │ │ │ │ + found = true │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (found) { │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return eligible ? result : null │ │ │ │ + }, │ │ │ │ + getGeoTolerance: function(tolerance, resolution) { │ │ │ │ + if (resolution !== this.resolution) { │ │ │ │ + this.resolution = resolution; │ │ │ │ + this.geoToleranceCache = {} │ │ │ │ + } │ │ │ │ + var geoTolerance = this.geoToleranceCache[tolerance]; │ │ │ │ + if (geoTolerance === undefined) { │ │ │ │ + geoTolerance = tolerance * resolution; │ │ │ │ + this.geoToleranceCache[tolerance] = geoTolerance │ │ │ │ + } │ │ │ │ + return geoTolerance │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.active) { │ │ │ │ + this.deactivate() │ │ │ │ + } │ │ │ │ + delete this.layer; │ │ │ │ + delete this.targets; │ │ │ │ + OpenLayers.Control.prototype.destroy.call(this) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Snapping" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.MousePosition = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + autoActivate: true, │ │ │ │ + element: null, │ │ │ │ + prefix: "", │ │ │ │ + separator: ", ", │ │ │ │ + suffix: "", │ │ │ │ + numDigits: 5, │ │ │ │ + granularity: 10, │ │ │ │ + emptyString: null, │ │ │ │ + lastXy: null, │ │ │ │ + displayProjection: null, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.map.events.register("mousemove", this, this.redraw); │ │ │ │ + this.map.events.register("mouseout", this, this.reset); │ │ │ │ + this.redraw(); │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + this.map.events.unregister("mousemove", this, this.redraw); │ │ │ │ + this.map.events.unregister("mouseout", this, this.reset); │ │ │ │ + this.element.innerHTML = ""; │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (!this.element) { │ │ │ │ + this.div.left = ""; │ │ │ │ + this.div.top = ""; │ │ │ │ + this.element = this.div │ │ │ │ + } │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + redraw: function(evt) { │ │ │ │ + var lonLat; │ │ │ │ + if (evt == null) { │ │ │ │ + this.reset(); │ │ │ │ + return │ │ │ │ + } else { │ │ │ │ + if (this.lastXy == null || Math.abs(evt.xy.x - this.lastXy.x) > this.granularity || Math.abs(evt.xy.y - this.lastXy.y) > this.granularity) { │ │ │ │ + this.lastXy = evt.xy; │ │ │ │ + return │ │ │ │ + } │ │ │ │ + lonLat = this.map.getLonLatFromPixel(evt.xy); │ │ │ │ + if (!lonLat) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + if (this.displayProjection) { │ │ │ │ + lonLat.transform(this.map.getProjectionObject(), this.displayProjection) │ │ │ │ + } │ │ │ │ + this.lastXy = evt.xy │ │ │ │ + } │ │ │ │ + var newHtml = this.formatOutput(lonLat); │ │ │ │ + if (newHtml != this.element.innerHTML) { │ │ │ │ + this.element.innerHTML = newHtml │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + reset: function(evt) { │ │ │ │ + if (this.emptyString != null) { │ │ │ │ + this.element.innerHTML = this.emptyString │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + formatOutput: function(lonLat) { │ │ │ │ + var digits = parseInt(this.numDigits); │ │ │ │ + var newHtml = this.prefix + lonLat.lon.toFixed(digits) + this.separator + lonLat.lat.toFixed(digits) + this.suffix; │ │ │ │ + return newHtml │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.MousePosition" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Attribution = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + separator: ", ", │ │ │ │ + template: "${layers}", │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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()) { │ │ │ │ + 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.Control.LayerSwitcher = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + layerStates: null, │ │ │ │ + layersDiv: null, │ │ │ │ + baseLayersDiv: null, │ │ │ │ + baseLayers: null, │ │ │ │ + dataLbl: null, │ │ │ │ + dataLayersDiv: null, │ │ │ │ + dataLayers: null, │ │ │ │ + minimizeDiv: null, │ │ │ │ + maximizeDiv: null, │ │ │ │ + ascending: true, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ + this.layerStates = [] │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.clearLayersArray("base"); │ │ │ │ + this.clearLayersArray("data"); │ │ │ │ + this.map.events.un({ │ │ │ │ + buttonclick: this.onButtonClick, │ │ │ │ + addlayer: this.redraw, │ │ │ │ + changelayer: this.redraw, │ │ │ │ + removelayer: this.redraw, │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + this.map.events.on({ │ │ │ │ + addlayer: this.redraw, │ │ │ │ + changelayer: this.redraw, │ │ │ │ + removelayer: this.redraw, │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + if (this.outsideViewport) { │ │ │ │ + this.events.attachToElement(this.div); │ │ │ │ + this.events.register("buttonclick", this, this.onButtonClick) │ │ │ │ + } else { │ │ │ │ + this.map.events.register("buttonclick", this, this.onButtonClick) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this); │ │ │ │ + this.loadContents(); │ │ │ │ + if (!this.outsideViewport) { │ │ │ │ + this.minimizeControl() │ │ │ │ + } │ │ │ │ + this.redraw(); │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + var button = evt.buttonElement; │ │ │ │ + if (button === this.minimizeDiv) { │ │ │ │ + this.minimizeControl() │ │ │ │ + } else if (button === this.maximizeDiv) { │ │ │ │ + this.maximizeControl() │ │ │ │ + } else if (button._layerSwitcher === this.id) { │ │ │ │ + if (button["for"]) { │ │ │ │ + button = document.getElementById(button["for"]) │ │ │ │ + } │ │ │ │ + if (!button.disabled) { │ │ │ │ + if (button.type == "radio") { │ │ │ │ + button.checked = true; │ │ │ │ + this.map.setBaseLayer(this.map.getLayer(button._layer)) │ │ │ │ + } else { │ │ │ │ + button.checked = !button.checked; │ │ │ │ + this.updateMap() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + clearLayersArray: function(layersType) { │ │ │ │ + this[layersType + "LayersDiv"].innerHTML = ""; │ │ │ │ + this[layersType + "Layers"] = [] │ │ │ │ + }, │ │ │ │ + checkRedraw: function() { │ │ │ │ + if (!this.layerStates.length || this.map.layers.length != this.layerStates.length) { │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + for (var i = 0, len = this.layerStates.length; i < len; i++) { │ │ │ │ + var layerState = this.layerStates[i]; │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + if (layerState.name != layer.name || layerState.inRange != layer.inRange || layerState.id != layer.id || layerState.visibility != layer.visibility) { │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + redraw: function() { │ │ │ │ + if (!this.checkRedraw()) { │ │ │ │ + return this.div │ │ │ │ + } │ │ │ │ + this.clearLayersArray("base"); │ │ │ │ + this.clearLayersArray("data"); │ │ │ │ + var containsOverlays = false; │ │ │ │ + var containsBaseLayers = false; │ │ │ │ + var len = this.map.layers.length; │ │ │ │ + this.layerStates = new Array(len); │ │ │ │ + for (var i = 0; i < len; i++) { │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + this.layerStates[i] = { │ │ │ │ + name: layer.name, │ │ │ │ + visibility: layer.visibility, │ │ │ │ + inRange: layer.inRange, │ │ │ │ + id: layer.id │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var layers = this.map.layers.slice(); │ │ │ │ + if (!this.ascending) { │ │ │ │ + layers.reverse() │ │ │ │ + } │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + var layer = layers[i]; │ │ │ │ + var baseLayer = layer.isBaseLayer; │ │ │ │ + if (layer.displayInLayerSwitcher) { │ │ │ │ + if (baseLayer) { │ │ │ │ + containsBaseLayers = true │ │ │ │ + } else { │ │ │ │ + containsOverlays = true │ │ │ │ + } │ │ │ │ + var checked = baseLayer ? layer == this.map.baseLayer : layer.getVisibility(); │ │ │ │ + var inputElem = document.createElement("input"), │ │ │ │ + inputId = OpenLayers.Util.createUniqueID(this.id + "_input_"); │ │ │ │ + inputElem.id = inputId; │ │ │ │ + inputElem.name = baseLayer ? this.id + "_baseLayers" : layer.name; │ │ │ │ + inputElem.type = baseLayer ? "radio" : "checkbox"; │ │ │ │ + inputElem.value = layer.name; │ │ │ │ + inputElem.checked = checked; │ │ │ │ + inputElem.defaultChecked = checked; │ │ │ │ + inputElem.className = "olButton"; │ │ │ │ + inputElem._layer = layer.id; │ │ │ │ + inputElem._layerSwitcher = this.id; │ │ │ │ + if (!baseLayer && !layer.inRange) { │ │ │ │ + inputElem.disabled = true │ │ │ │ + } │ │ │ │ + var labelSpan = document.createElement("label"); │ │ │ │ + labelSpan["for"] = inputElem.id; │ │ │ │ + OpenLayers.Element.addClass(labelSpan, "labelSpan olButton"); │ │ │ │ + labelSpan._layer = layer.id; │ │ │ │ + labelSpan._layerSwitcher = this.id; │ │ │ │ + if (!baseLayer && !layer.inRange) { │ │ │ │ + labelSpan.style.color = "gray" │ │ │ │ + } │ │ │ │ + labelSpan.innerHTML = layer.name; │ │ │ │ + labelSpan.style.verticalAlign = baseLayer ? "bottom" : "baseline"; │ │ │ │ + var br = document.createElement("br"); │ │ │ │ + var groupArray = baseLayer ? this.baseLayers : this.dataLayers; │ │ │ │ + groupArray.push({ │ │ │ │ + layer: layer, │ │ │ │ + inputElem: inputElem, │ │ │ │ + labelSpan: labelSpan │ │ │ │ + }); │ │ │ │ + var groupDiv = baseLayer ? this.baseLayersDiv : this.dataLayersDiv; │ │ │ │ + groupDiv.appendChild(inputElem); │ │ │ │ + groupDiv.appendChild(labelSpan); │ │ │ │ + groupDiv.appendChild(br) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.dataLbl.style.display = containsOverlays ? "" : "none"; │ │ │ │ + this.baseLbl.style.display = containsBaseLayers ? "" : "none"; │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + updateMap: function() { │ │ │ │ + for (var i = 0, len = this.baseLayers.length; i < len; i++) { │ │ │ │ + var layerEntry = this.baseLayers[i]; │ │ │ │ + if (layerEntry.inputElem.checked) { │ │ │ │ + this.map.setBaseLayer(layerEntry.layer, false) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + for (var i = 0, len = this.dataLayers.length; i < len; i++) { │ │ │ │ + var layerEntry = this.dataLayers[i]; │ │ │ │ + layerEntry.layer.setVisibility(layerEntry.inputElem.checked) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + maximizeControl: function(e) { │ │ │ │ + this.div.style.width = ""; │ │ │ │ + this.div.style.height = ""; │ │ │ │ + this.showControls(false); │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + minimizeControl: function(e) { │ │ │ │ + this.div.style.width = "0px"; │ │ │ │ + this.div.style.height = "0px"; │ │ │ │ + this.showControls(true); │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + showControls: function(minimize) { │ │ │ │ + this.maximizeDiv.style.display = minimize ? "" : "none"; │ │ │ │ + this.minimizeDiv.style.display = minimize ? "none" : ""; │ │ │ │ + this.layersDiv.style.display = minimize ? "none" : "" │ │ │ │ + }, │ │ │ │ + loadContents: function() { │ │ │ │ + this.layersDiv = document.createElement("div"); │ │ │ │ + this.layersDiv.id = this.id + "_layersDiv"; │ │ │ │ + OpenLayers.Element.addClass(this.layersDiv, "layersDiv"); │ │ │ │ + this.baseLbl = document.createElement("div"); │ │ │ │ + this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer"); │ │ │ │ + OpenLayers.Element.addClass(this.baseLbl, "baseLbl"); │ │ │ │ + this.baseLayersDiv = document.createElement("div"); │ │ │ │ + OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv"); │ │ │ │ + this.dataLbl = document.createElement("div"); │ │ │ │ + this.dataLbl.innerHTML = OpenLayers.i18n("Overlays"); │ │ │ │ + OpenLayers.Element.addClass(this.dataLbl, "dataLbl"); │ │ │ │ + this.dataLayersDiv = document.createElement("div"); │ │ │ │ + OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv"); │ │ │ │ + if (this.ascending) { │ │ │ │ + this.layersDiv.appendChild(this.baseLbl); │ │ │ │ + this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ + this.layersDiv.appendChild(this.dataLbl); │ │ │ │ + this.layersDiv.appendChild(this.dataLayersDiv) │ │ │ │ + } else { │ │ │ │ + this.layersDiv.appendChild(this.dataLbl); │ │ │ │ + this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ + this.layersDiv.appendChild(this.baseLbl); │ │ │ │ + this.layersDiv.appendChild(this.baseLayersDiv) │ │ │ │ + } │ │ │ │ + this.div.appendChild(this.layersDiv); │ │ │ │ + var img = OpenLayers.Util.getImageLocation("layer-switcher-maximize.png"); │ │ │ │ + this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MaximizeDiv", null, null, img, "absolute"); │ │ │ │ + OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv olButton"); │ │ │ │ + this.maximizeDiv.style.display = "none"; │ │ │ │ + this.div.appendChild(this.maximizeDiv); │ │ │ │ + var img = OpenLayers.Util.getImageLocation("layer-switcher-minimize.png"); │ │ │ │ + this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MinimizeDiv", null, null, img, "absolute"); │ │ │ │ + OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton"); │ │ │ │ + this.minimizeDiv.style.display = "none"; │ │ │ │ + this.div.appendChild(this.minimizeDiv) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.LayerSwitcher" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.ZoomOut = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ + trigger: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.zoomOut() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomOut" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.ZoomPanel = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ + this.addControls([new OpenLayers.Control.ZoomIn, new OpenLayers.Control.ZoomToMaxExtent, new OpenLayers.Control.ZoomOut]) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomPanel" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.CacheRead = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + fetchEvent: "tileloadstart", │ │ │ │ + layers: null, │ │ │ │ + autoActivate: true, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + var i, layers = this.layers || map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.addLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + if (!this.layers) { │ │ │ │ + map.events.on({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + addLayer: function(evt) { │ │ │ │ + evt.layer.events.register(this.fetchEvent, this, this.fetch) │ │ │ │ + }, │ │ │ │ + removeLayer: function(evt) { │ │ │ │ + evt.layer.events.unregister(this.fetchEvent, this, this.fetch) │ │ │ │ + }, │ │ │ │ + fetch: function(evt) { │ │ │ │ + if (this.active && window.localStorage && evt.tile instanceof OpenLayers.Tile.Image) { │ │ │ │ + var tile = evt.tile, │ │ │ │ + url = tile.url; │ │ │ │ + if (!tile.layer.crossOriginKeyword && OpenLayers.ProxyHost && url.indexOf(OpenLayers.ProxyHost) === 0) { │ │ │ │ + url = OpenLayers.Control.CacheWrite.urlMap[url] │ │ │ │ + } │ │ │ │ + var dataURI = window.localStorage.getItem("olCache_" + url); │ │ │ │ + if (dataURI) { │ │ │ │ + tile.url = dataURI; │ │ │ │ + if (evt.type === "tileerror") { │ │ │ │ + tile.setImgSrc(dataURI) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.layers || this.map) { │ │ │ │ + var i, layers = this.layers || this.map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.removeLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.un({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.CacheRead" │ │ │ │ +}); │ │ │ │ OpenLayers.Control.DrawFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ layer: null, │ │ │ │ callbacks: null, │ │ │ │ multi: false, │ │ │ │ featureAdded: function() {}, │ │ │ │ initialize: function(layer, handler, options) { │ │ │ │ OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ @@ -25194,245 +29416,568 @@ │ │ │ │ this.handler.finishGeometry() │ │ │ │ }, │ │ │ │ cancel: function() { │ │ │ │ this.handler.cancel() │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.DrawFeature" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.ZoomOut = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ - trigger: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.zoomOut() │ │ │ │ +OpenLayers.Control.EditingToolbar = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ + citeCompliant: false, │ │ │ │ + initialize: function(layer, options) { │ │ │ │ + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ + this.addControls([new OpenLayers.Control.Navigation]); │ │ │ │ + var controls = [new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Point, { │ │ │ │ + displayClass: "olControlDrawFeaturePoint", │ │ │ │ + handlerOptions: { │ │ │ │ + citeCompliant: this.citeCompliant │ │ │ │ + } │ │ │ │ + }), new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Path, { │ │ │ │ + displayClass: "olControlDrawFeaturePath", │ │ │ │ + handlerOptions: { │ │ │ │ + citeCompliant: this.citeCompliant │ │ │ │ + } │ │ │ │ + }), new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Polygon, { │ │ │ │ + displayClass: "olControlDrawFeaturePolygon", │ │ │ │ + handlerOptions: { │ │ │ │ + citeCompliant: this.citeCompliant │ │ │ │ + } │ │ │ │ + })]; │ │ │ │ + this.addControls(controls) │ │ │ │ + }, │ │ │ │ + draw: function() { │ │ │ │ + var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments); │ │ │ │ + if (this.defaultControl === null) { │ │ │ │ + this.defaultControl = this.controls[0] │ │ │ │ } │ │ │ │ + return div │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomOut" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.EditingToolbar" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.UTFGrid = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - autoActivate: true, │ │ │ │ +OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + element: null, │ │ │ │ + ovmap: null, │ │ │ │ + size: { │ │ │ │ + w: 180, │ │ │ │ + h: 90 │ │ │ │ + }, │ │ │ │ layers: null, │ │ │ │ - defaultHandlerOptions: { │ │ │ │ - delay: 300, │ │ │ │ - pixelTolerance: 4, │ │ │ │ - stopMove: false, │ │ │ │ - single: true, │ │ │ │ - double: false, │ │ │ │ - stopSingle: false, │ │ │ │ - stopDouble: false │ │ │ │ + minRectSize: 15, │ │ │ │ + minRectDisplayClass: "RectReplacement", │ │ │ │ + minRatio: 8, │ │ │ │ + maxRatio: 32, │ │ │ │ + mapOptions: null, │ │ │ │ + autoPan: false, │ │ │ │ + handlers: null, │ │ │ │ + resolutionFactor: 1, │ │ │ │ + maximized: false, │ │ │ │ + maximizeTitle: "", │ │ │ │ + minimizeTitle: "", │ │ │ │ + initialize: function(options) { │ │ │ │ + this.layers = []; │ │ │ │ + this.handlers = {}; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]) │ │ │ │ }, │ │ │ │ - handlerMode: "click", │ │ │ │ - setHandler: function(hm) { │ │ │ │ - this.handlerMode = hm; │ │ │ │ - this.resetHandler() │ │ │ │ + destroy: function() { │ │ │ │ + if (!this.mapDiv) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + if (this.handlers.click) { │ │ │ │ + this.handlers.click.destroy() │ │ │ │ + } │ │ │ │ + if (this.handlers.drag) { │ │ │ │ + this.handlers.drag.destroy() │ │ │ │ + } │ │ │ │ + this.ovmap && this.ovmap.viewPortDiv.removeChild(this.extentRectangle); │ │ │ │ + this.extentRectangle = null; │ │ │ │ + if (this.rectEvents) { │ │ │ │ + this.rectEvents.destroy(); │ │ │ │ + this.rectEvents = null │ │ │ │ + } │ │ │ │ + if (this.ovmap) { │ │ │ │ + this.ovmap.destroy(); │ │ │ │ + this.ovmap = null │ │ │ │ + } │ │ │ │ + this.element.removeChild(this.mapDiv); │ │ │ │ + this.mapDiv = null; │ │ │ │ + this.div.removeChild(this.element); │ │ │ │ + this.element = null; │ │ │ │ + if (this.maximizeDiv) { │ │ │ │ + this.div.removeChild(this.maximizeDiv); │ │ │ │ + this.maximizeDiv = null │ │ │ │ + } │ │ │ │ + if (this.minimizeDiv) { │ │ │ │ + this.div.removeChild(this.minimizeDiv); │ │ │ │ + this.minimizeDiv = null │ │ │ │ + } │ │ │ │ + this.map.events.un({ │ │ │ │ + buttonclick: this.onButtonClick, │ │ │ │ + moveend: this.update, │ │ │ │ + changebaselayer: this.baseLayerDraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ - resetHandler: function() { │ │ │ │ - if (this.handler) { │ │ │ │ - this.handler.deactivate(); │ │ │ │ - this.handler.destroy(); │ │ │ │ - this.handler = null │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (this.layers.length === 0) { │ │ │ │ + if (this.map.baseLayer) { │ │ │ │ + var layer = this.map.baseLayer.clone(); │ │ │ │ + this.layers = [layer] │ │ │ │ + } else { │ │ │ │ + this.map.events.register("changebaselayer", this, this.baseLayerDraw); │ │ │ │ + return this.div │ │ │ │ + } │ │ │ │ } │ │ │ │ - if (this.handlerMode == "hover") { │ │ │ │ - this.handler = new OpenLayers.Handler.Hover(this, { │ │ │ │ - pause: this.handleEvent, │ │ │ │ - move: this.reset │ │ │ │ - }, this.handlerOptions) │ │ │ │ - } else if (this.handlerMode == "click") { │ │ │ │ - this.handler = new OpenLayers.Handler.Click(this, { │ │ │ │ - click: this.handleEvent │ │ │ │ - }, this.handlerOptions) │ │ │ │ - } else if (this.handlerMode == "move") { │ │ │ │ - this.handler = new OpenLayers.Handler.Hover(this, { │ │ │ │ - pause: this.handleEvent, │ │ │ │ - move: this.handleEvent │ │ │ │ - }, this.handlerOptions) │ │ │ │ + this.element = document.createElement("div"); │ │ │ │ + this.element.className = this.displayClass + "Element"; │ │ │ │ + this.element.style.display = "none"; │ │ │ │ + this.mapDiv = document.createElement("div"); │ │ │ │ + this.mapDiv.style.width = this.size.w + "px"; │ │ │ │ + this.mapDiv.style.height = this.size.h + "px"; │ │ │ │ + this.mapDiv.style.position = "relative"; │ │ │ │ + this.mapDiv.style.overflow = "hidden"; │ │ │ │ + this.mapDiv.id = OpenLayers.Util.createUniqueID("overviewMap"); │ │ │ │ + this.extentRectangle = document.createElement("div"); │ │ │ │ + this.extentRectangle.style.position = "absolute"; │ │ │ │ + this.extentRectangle.style.zIndex = 1e3; │ │ │ │ + this.extentRectangle.className = this.displayClass + "ExtentRectangle"; │ │ │ │ + this.element.appendChild(this.mapDiv); │ │ │ │ + this.div.appendChild(this.element); │ │ │ │ + if (!this.outsideViewport) { │ │ │ │ + this.div.className += " " + this.displayClass + "Container"; │ │ │ │ + var img = OpenLayers.Util.getImageLocation("layer-switcher-maximize.png"); │ │ │ │ + this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(this.displayClass + "MaximizeButton", null, null, img, "absolute"); │ │ │ │ + this.maximizeDiv.style.display = "none"; │ │ │ │ + this.maximizeDiv.className = this.displayClass + "MaximizeButton olButton"; │ │ │ │ + if (this.maximizeTitle) { │ │ │ │ + this.maximizeDiv.title = this.maximizeTitle │ │ │ │ + } │ │ │ │ + this.div.appendChild(this.maximizeDiv); │ │ │ │ + var img = OpenLayers.Util.getImageLocation("layer-switcher-minimize.png"); │ │ │ │ + this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_minimizeDiv", null, null, img, "absolute"); │ │ │ │ + this.minimizeDiv.style.display = "none"; │ │ │ │ + this.minimizeDiv.className = this.displayClass + "MinimizeButton olButton"; │ │ │ │ + if (this.minimizeTitle) { │ │ │ │ + this.minimizeDiv.title = this.minimizeTitle │ │ │ │ + } │ │ │ │ + this.div.appendChild(this.minimizeDiv); │ │ │ │ + this.minimizeControl() │ │ │ │ + } else { │ │ │ │ + this.element.style.display = "" │ │ │ │ } │ │ │ │ - if (this.handler) { │ │ │ │ - return true │ │ │ │ + if (this.map.getExtent()) { │ │ │ │ + this.update() │ │ │ │ + } │ │ │ │ + this.map.events.on({ │ │ │ │ + buttonclick: this.onButtonClick, │ │ │ │ + moveend: this.update, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + if (this.maximized) { │ │ │ │ + this.maximizeControl() │ │ │ │ + } │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + baseLayerDraw: function() { │ │ │ │ + this.draw(); │ │ │ │ + this.map.events.unregister("changebaselayer", this, this.baseLayerDraw) │ │ │ │ + }, │ │ │ │ + rectDrag: function(px) { │ │ │ │ + var deltaX = this.handlers.drag.last.x - px.x; │ │ │ │ + var deltaY = this.handlers.drag.last.y - px.y; │ │ │ │ + if (deltaX != 0 || deltaY != 0) { │ │ │ │ + var rectTop = this.rectPxBounds.top; │ │ │ │ + var rectLeft = this.rectPxBounds.left; │ │ │ │ + var rectHeight = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ + var rectWidth = this.rectPxBounds.getWidth(); │ │ │ │ + var newTop = Math.max(0, rectTop - deltaY); │ │ │ │ + newTop = Math.min(newTop, this.ovmap.size.h - this.hComp - rectHeight); │ │ │ │ + var newLeft = Math.max(0, rectLeft - deltaX); │ │ │ │ + newLeft = Math.min(newLeft, this.ovmap.size.w - this.wComp - rectWidth); │ │ │ │ + this.setRectPxBounds(new OpenLayers.Bounds(newLeft, newTop + rectHeight, newLeft + rectWidth, newTop)) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + mapDivClick: function(evt) { │ │ │ │ + var pxCenter = this.rectPxBounds.getCenterPixel(); │ │ │ │ + var deltaX = evt.xy.x - pxCenter.x; │ │ │ │ + var deltaY = evt.xy.y - pxCenter.y; │ │ │ │ + var top = this.rectPxBounds.top; │ │ │ │ + var left = this.rectPxBounds.left; │ │ │ │ + var height = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ + var width = this.rectPxBounds.getWidth(); │ │ │ │ + var newTop = Math.max(0, top + deltaY); │ │ │ │ + newTop = Math.min(newTop, this.ovmap.size.h - height); │ │ │ │ + var newLeft = Math.max(0, left + deltaX); │ │ │ │ + newLeft = Math.min(newLeft, this.ovmap.size.w - width); │ │ │ │ + this.setRectPxBounds(new OpenLayers.Bounds(newLeft, newTop + height, newLeft + width, newTop)); │ │ │ │ + this.updateMapToRect() │ │ │ │ + }, │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + if (evt.buttonElement === this.minimizeDiv) { │ │ │ │ + this.minimizeControl() │ │ │ │ + } else if (evt.buttonElement === this.maximizeDiv) { │ │ │ │ + this.maximizeControl() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + maximizeControl: function(e) { │ │ │ │ + this.element.style.display = ""; │ │ │ │ + this.showToggle(false); │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + minimizeControl: function(e) { │ │ │ │ + this.element.style.display = "none"; │ │ │ │ + this.showToggle(true); │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + showToggle: function(minimize) { │ │ │ │ + if (this.maximizeDiv) { │ │ │ │ + this.maximizeDiv.style.display = minimize ? "" : "none" │ │ │ │ + } │ │ │ │ + if (this.minimizeDiv) { │ │ │ │ + this.minimizeDiv.style.display = minimize ? "none" : "" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + update: function() { │ │ │ │ + if (this.ovmap == null) { │ │ │ │ + this.createMap() │ │ │ │ + } │ │ │ │ + if (this.autoPan || !this.isSuitableOverview()) { │ │ │ │ + this.updateOverview() │ │ │ │ + } │ │ │ │ + this.updateRectToMap() │ │ │ │ + }, │ │ │ │ + isSuitableOverview: function() { │ │ │ │ + var mapExtent = this.map.getExtent(); │ │ │ │ + var maxExtent = this.map.getMaxExtent(); │ │ │ │ + var testExtent = new OpenLayers.Bounds(Math.max(mapExtent.left, maxExtent.left), Math.max(mapExtent.bottom, maxExtent.bottom), Math.min(mapExtent.right, maxExtent.right), Math.min(mapExtent.top, maxExtent.top)); │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + testExtent = testExtent.transform(this.map.getProjectionObject(), this.ovmap.getProjectionObject()) │ │ │ │ + } │ │ │ │ + var resRatio = this.ovmap.getResolution() / this.map.getResolution(); │ │ │ │ + return resRatio > this.minRatio && resRatio <= this.maxRatio && this.ovmap.getExtent().containsBounds(testExtent) │ │ │ │ + }, │ │ │ │ + updateOverview: function() { │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ + var targetRes = this.ovmap.getResolution(); │ │ │ │ + var resRatio = targetRes / mapRes; │ │ │ │ + if (resRatio > this.maxRatio) { │ │ │ │ + targetRes = this.minRatio * mapRes │ │ │ │ + } else if (resRatio <= this.minRatio) { │ │ │ │ + targetRes = this.maxRatio * mapRes │ │ │ │ + } │ │ │ │ + var center; │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + center = this.map.center.clone(); │ │ │ │ + center.transform(this.map.getProjectionObject(), this.ovmap.getProjectionObject()) │ │ │ │ } else { │ │ │ │ - return false │ │ │ │ + center = this.map.center │ │ │ │ + } │ │ │ │ + this.ovmap.setCenter(center, this.ovmap.getZoomForResolution(targetRes * this.resolutionFactor)); │ │ │ │ + this.updateRectToMap() │ │ │ │ + }, │ │ │ │ + createMap: function() { │ │ │ │ + var options = OpenLayers.Util.extend({ │ │ │ │ + controls: [], │ │ │ │ + maxResolution: "auto", │ │ │ │ + fallThrough: false │ │ │ │ + }, this.mapOptions); │ │ │ │ + this.ovmap = new OpenLayers.Map(this.mapDiv, options); │ │ │ │ + this.ovmap.viewPortDiv.appendChild(this.extentRectangle); │ │ │ │ + OpenLayers.Event.stopObserving(window, "unload", this.ovmap.unloadDestroy); │ │ │ │ + this.ovmap.addLayers(this.layers); │ │ │ │ + this.ovmap.zoomToMaxExtent(); │ │ │ │ + this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-left-width")) + parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-right-width")); │ │ │ │ + this.wComp = this.wComp ? this.wComp : 2; │ │ │ │ + this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-top-width")) + parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-bottom-width")); │ │ │ │ + this.hComp = this.hComp ? this.hComp : 2; │ │ │ │ + this.handlers.drag = new OpenLayers.Handler.Drag(this, { │ │ │ │ + move: this.rectDrag, │ │ │ │ + done: this.updateMapToRect │ │ │ │ + }, { │ │ │ │ + map: this.ovmap │ │ │ │ + }); │ │ │ │ + this.handlers.click = new OpenLayers.Handler.Click(this, { │ │ │ │ + click: this.mapDivClick │ │ │ │ + }, { │ │ │ │ + single: true, │ │ │ │ + double: false, │ │ │ │ + stopSingle: true, │ │ │ │ + stopDouble: true, │ │ │ │ + pixelTolerance: 1, │ │ │ │ + map: this.ovmap │ │ │ │ + }); │ │ │ │ + this.handlers.click.activate(); │ │ │ │ + this.rectEvents = new OpenLayers.Events(this, this.extentRectangle, null, true); │ │ │ │ + this.rectEvents.register("mouseover", this, function(e) { │ │ │ │ + if (!this.handlers.drag.active && !this.map.dragging) { │ │ │ │ + this.handlers.drag.activate() │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.rectEvents.register("mouseout", this, function(e) { │ │ │ │ + if (!this.handlers.drag.dragging) { │ │ │ │ + this.handlers.drag.deactivate() │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + var sourceUnits = this.map.getProjectionObject().getUnits() || this.map.units || this.map.baseLayer.units; │ │ │ │ + var targetUnits = this.ovmap.getProjectionObject().getUnits() || this.ovmap.units || this.ovmap.baseLayer.units; │ │ │ │ + this.resolutionFactor = sourceUnits && targetUnits ? OpenLayers.INCHES_PER_UNIT[sourceUnits] / OpenLayers.INCHES_PER_UNIT[targetUnits] : 1 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + updateRectToMap: function() { │ │ │ │ + var bounds; │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + bounds = this.map.getExtent().transform(this.map.getProjectionObject(), this.ovmap.getProjectionObject()) │ │ │ │ + } else { │ │ │ │ + bounds = this.map.getExtent() │ │ │ │ + } │ │ │ │ + var pxBounds = this.getRectBoundsFromMapBounds(bounds); │ │ │ │ + if (pxBounds) { │ │ │ │ + this.setRectPxBounds(pxBounds) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + updateMapToRect: function() { │ │ │ │ + var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds); │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + lonLatBounds = lonLatBounds.transform(this.ovmap.getProjectionObject(), this.map.getProjectionObject()) │ │ │ │ + } │ │ │ │ + this.map.panTo(lonLatBounds.getCenterLonLat()) │ │ │ │ + }, │ │ │ │ + setRectPxBounds: function(pxBounds) { │ │ │ │ + var top = Math.max(pxBounds.top, 0); │ │ │ │ + var left = Math.max(pxBounds.left, 0); │ │ │ │ + var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()), this.ovmap.size.h - this.hComp); │ │ │ │ + var right = Math.min(pxBounds.left + pxBounds.getWidth(), this.ovmap.size.w - this.wComp); │ │ │ │ + var width = Math.max(right - left, 0); │ │ │ │ + var height = Math.max(bottom - top, 0); │ │ │ │ + if (width < this.minRectSize || height < this.minRectSize) { │ │ │ │ + this.extentRectangle.className = this.displayClass + this.minRectDisplayClass; │ │ │ │ + var rLeft = left + width / 2 - this.minRectSize / 2; │ │ │ │ + var rTop = top + height / 2 - this.minRectSize / 2; │ │ │ │ + this.extentRectangle.style.top = Math.round(rTop) + "px"; │ │ │ │ + this.extentRectangle.style.left = Math.round(rLeft) + "px"; │ │ │ │ + this.extentRectangle.style.height = this.minRectSize + "px"; │ │ │ │ + this.extentRectangle.style.width = this.minRectSize + "px" │ │ │ │ + } else { │ │ │ │ + this.extentRectangle.className = this.displayClass + "ExtentRectangle"; │ │ │ │ + this.extentRectangle.style.top = Math.round(top) + "px"; │ │ │ │ + this.extentRectangle.style.left = Math.round(left) + "px"; │ │ │ │ + this.extentRectangle.style.height = Math.round(height) + "px"; │ │ │ │ + this.extentRectangle.style.width = Math.round(width) + "px" │ │ │ │ + } │ │ │ │ + this.rectPxBounds = new OpenLayers.Bounds(Math.round(left), Math.round(bottom), Math.round(right), Math.round(top)) │ │ │ │ + }, │ │ │ │ + getRectBoundsFromMapBounds: function(lonLatBounds) { │ │ │ │ + var leftBottomPx = this.getOverviewPxFromLonLat({ │ │ │ │ + lon: lonLatBounds.left, │ │ │ │ + lat: lonLatBounds.bottom │ │ │ │ + }); │ │ │ │ + var rightTopPx = this.getOverviewPxFromLonLat({ │ │ │ │ + lon: lonLatBounds.right, │ │ │ │ + lat: lonLatBounds.top │ │ │ │ + }); │ │ │ │ + var bounds = null; │ │ │ │ + if (leftBottomPx && rightTopPx) { │ │ │ │ + bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y, rightTopPx.x, rightTopPx.y) │ │ │ │ } │ │ │ │ + return bounds │ │ │ │ }, │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.handlerOptions = options.handlerOptions || this.defaultHandlerOptions; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.resetHandler() │ │ │ │ + getMapBoundsFromRectBounds: function(pxBounds) { │ │ │ │ + var leftBottomLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ + x: pxBounds.left, │ │ │ │ + y: pxBounds.bottom │ │ │ │ + }); │ │ │ │ + var rightTopLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ + x: pxBounds.right, │ │ │ │ + y: pxBounds.top │ │ │ │ + }); │ │ │ │ + return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat, rightTopLonLat.lon, rightTopLonLat.lat) │ │ │ │ }, │ │ │ │ - handleEvent: function(evt) { │ │ │ │ - if (evt == null) { │ │ │ │ - this.reset(); │ │ │ │ - return │ │ │ │ - } │ │ │ │ - var lonLat = this.map.getLonLatFromPixel(evt.xy); │ │ │ │ - if (!lonLat) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - var layers = this.findLayers(); │ │ │ │ - if (layers.length > 0) { │ │ │ │ - var infoLookup = {}; │ │ │ │ - var layer, idx; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - layer = layers[i]; │ │ │ │ - idx = OpenLayers.Util.indexOf(this.map.layers, layer); │ │ │ │ - infoLookup[idx] = layer.getFeatureInfo(lonLat) │ │ │ │ - } │ │ │ │ - this.callback(infoLookup, lonLat, evt.xy) │ │ │ │ + getLonLatFromOverviewPx: function(overviewMapPx) { │ │ │ │ + var size = this.ovmap.size; │ │ │ │ + var res = this.ovmap.getResolution(); │ │ │ │ + var center = this.ovmap.getExtent().getCenterLonLat(); │ │ │ │ + var deltaX = overviewMapPx.x - size.w / 2; │ │ │ │ + var deltaY = overviewMapPx.y - size.h / 2; │ │ │ │ + return { │ │ │ │ + lon: center.lon + deltaX * res, │ │ │ │ + lat: center.lat - deltaY * res │ │ │ │ } │ │ │ │ }, │ │ │ │ - callback: function(infoLookup) {}, │ │ │ │ - reset: function(evt) { │ │ │ │ - this.callback(null) │ │ │ │ - }, │ │ │ │ - findLayers: function() { │ │ │ │ - var candidates = this.layers || this.map.layers; │ │ │ │ - var layers = []; │ │ │ │ - var layer; │ │ │ │ - for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ - layer = candidates[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.UTFGrid) { │ │ │ │ - layers.push(layer) │ │ │ │ + getOverviewPxFromLonLat: function(lonlat) { │ │ │ │ + var res = this.ovmap.getResolution(); │ │ │ │ + var extent = this.ovmap.getExtent(); │ │ │ │ + if (extent) { │ │ │ │ + return { │ │ │ │ + x: Math.round(1 / res * (lonlat.lon - extent.left)), │ │ │ │ + y: Math.round(1 / res * (extent.top - lonlat.lat)) │ │ │ │ } │ │ │ │ } │ │ │ │ - return layers │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.UTFGrid" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.OverviewMap" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.EditingToolbar = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ - citeCompliant: false, │ │ │ │ - initialize: function(layer, options) { │ │ │ │ - OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ - this.addControls([new OpenLayers.Control.Navigation]); │ │ │ │ - var controls = [new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Point, { │ │ │ │ - displayClass: "olControlDrawFeaturePoint", │ │ │ │ - handlerOptions: { │ │ │ │ - citeCompliant: this.citeCompliant │ │ │ │ - } │ │ │ │ - }), new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Path, { │ │ │ │ - displayClass: "olControlDrawFeaturePath", │ │ │ │ - handlerOptions: { │ │ │ │ - citeCompliant: this.citeCompliant │ │ │ │ - } │ │ │ │ - }), new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Polygon, { │ │ │ │ - displayClass: "olControlDrawFeaturePolygon", │ │ │ │ - handlerOptions: { │ │ │ │ - citeCompliant: this.citeCompliant │ │ │ │ - } │ │ │ │ - })]; │ │ │ │ - this.addControls(controls) │ │ │ │ +OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + callbacks: null, │ │ │ │ + displaySystem: "metric", │ │ │ │ + geodesic: false, │ │ │ │ + displaySystemUnits: { │ │ │ │ + geographic: ["dd"], │ │ │ │ + english: ["mi", "ft", "in"], │ │ │ │ + metric: ["km", "m"] │ │ │ │ }, │ │ │ │ - draw: function() { │ │ │ │ - var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments); │ │ │ │ - if (this.defaultControl === null) { │ │ │ │ - this.defaultControl = this.controls[0] │ │ │ │ + partialDelay: 300, │ │ │ │ + delayedTrigger: null, │ │ │ │ + persist: false, │ │ │ │ + immediate: false, │ │ │ │ + initialize: function(handler, options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + var callbacks = { │ │ │ │ + done: this.measureComplete, │ │ │ │ + point: this.measurePartial │ │ │ │ + }; │ │ │ │ + if (this.immediate) { │ │ │ │ + callbacks.modify = this.measureImmediate │ │ │ │ } │ │ │ │ - return div │ │ │ │ + this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks); │ │ │ │ + this.handlerOptions = OpenLayers.Util.extend({ │ │ │ │ + persist: this.persist │ │ │ │ + }, this.handlerOptions); │ │ │ │ + this.handler = new handler(this, this.callbacks, this.handlerOptions) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.EditingToolbar" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.Zoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - zoomInText: "+", │ │ │ │ - zoomInId: "olZoomInLink", │ │ │ │ - zoomOutText: "−", │ │ │ │ - zoomOutId: "olZoomOutLink", │ │ │ │ - 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 │ │ │ │ + deactivate: function() { │ │ │ │ + this.cancelDelay(); │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ }, │ │ │ │ - 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) │ │ │ │ + cancel: function() { │ │ │ │ + this.cancelDelay(); │ │ │ │ + this.handler.cancel() │ │ │ │ + }, │ │ │ │ + setImmediate: function(immediate) { │ │ │ │ + this.immediate = immediate; │ │ │ │ + if (this.immediate) { │ │ │ │ + this.callbacks.modify = this.measureImmediate │ │ │ │ + } else { │ │ │ │ + delete this.callbacks.modify │ │ │ │ } │ │ │ │ - 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) │ │ │ │ + }, │ │ │ │ + updateHandler: function(handler, options) { │ │ │ │ + var active = this.active; │ │ │ │ + if (active) { │ │ │ │ + this.deactivate() │ │ │ │ } │ │ │ │ - OpenLayers.Element.addClass(zoomOut, "olButton"); │ │ │ │ - return { │ │ │ │ - zoomIn: zoomIn, │ │ │ │ - zoomOut: zoomOut │ │ │ │ + this.handler = new handler(this, this.callbacks, options); │ │ │ │ + if (active) { │ │ │ │ + this.activate() │ │ │ │ } │ │ │ │ }, │ │ │ │ - onZoomClick: function(evt) { │ │ │ │ - var button = evt.buttonElement; │ │ │ │ - if (button === this.zoomInLink) { │ │ │ │ - this.map.zoomIn() │ │ │ │ - } else if (button === this.zoomOutLink) { │ │ │ │ - this.map.zoomOut() │ │ │ │ + measureComplete: function(geometry) { │ │ │ │ + this.cancelDelay(); │ │ │ │ + this.measure(geometry, "measure") │ │ │ │ + }, │ │ │ │ + measurePartial: function(point, geometry) { │ │ │ │ + this.cancelDelay(); │ │ │ │ + geometry = geometry.clone(); │ │ │ │ + if (this.handler.freehandMode(this.handler.evt)) { │ │ │ │ + this.measure(geometry, "measurepartial") │ │ │ │ + } else { │ │ │ │ + this.delayedTrigger = window.setTimeout(OpenLayers.Function.bind(function() { │ │ │ │ + this.delayedTrigger = null; │ │ │ │ + this.measure(geometry, "measurepartial") │ │ │ │ + }, this), this.partialDelay) │ │ │ │ } │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.unregister("buttonclick", this, this.onZoomClick) │ │ │ │ + measureImmediate: function(point, feature, drawing) { │ │ │ │ + if (drawing && !this.handler.freehandMode(this.handler.evt)) { │ │ │ │ + this.cancelDelay(); │ │ │ │ + this.measure(feature.geometry, "measurepartial") │ │ │ │ } │ │ │ │ - delete this.zoomInLink; │ │ │ │ - delete this.zoomOutLink; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Zoom" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.Keyboard = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - KEY_EVENTS: ["keydown", "keyup"], │ │ │ │ - eventListener: null, │ │ │ │ - observeElement: null, │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ - this.eventListener = OpenLayers.Function.bindAsEventListener(this.handleKeyEvent, this) │ │ │ │ + cancelDelay: function() { │ │ │ │ + if (this.delayedTrigger !== null) { │ │ │ │ + window.clearTimeout(this.delayedTrigger); │ │ │ │ + this.delayedTrigger = null │ │ │ │ + } │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - this.eventListener = null; │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments) │ │ │ │ + measure: function(geometry, eventType) { │ │ │ │ + var stat, order; │ │ │ │ + if (geometry.CLASS_NAME.indexOf("LineString") > -1) { │ │ │ │ + stat = this.getBestLength(geometry); │ │ │ │ + order = 1 │ │ │ │ + } else { │ │ │ │ + stat = this.getBestArea(geometry); │ │ │ │ + order = 2 │ │ │ │ + } │ │ │ │ + this.events.triggerEvent(eventType, { │ │ │ │ + measure: stat[0], │ │ │ │ + units: stat[1], │ │ │ │ + order: order, │ │ │ │ + geometry: geometry │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - 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) │ │ │ │ + getBestArea: function(geometry) { │ │ │ │ + var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ + var unit, area; │ │ │ │ + for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ + unit = units[i]; │ │ │ │ + area = this.getArea(geometry, unit); │ │ │ │ + if (area > 1) { │ │ │ │ + break │ │ │ │ } │ │ │ │ - return true │ │ │ │ + } │ │ │ │ + return [area, unit] │ │ │ │ + }, │ │ │ │ + getArea: function(geometry, units) { │ │ │ │ + var area, geomUnits; │ │ │ │ + if (this.geodesic) { │ │ │ │ + area = geometry.getGeodesicArea(this.map.getProjectionObject()); │ │ │ │ + geomUnits = "m" │ │ │ │ } else { │ │ │ │ - return false │ │ │ │ + area = geometry.getArea(); │ │ │ │ + geomUnits = this.map.getUnits() │ │ │ │ } │ │ │ │ + var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ + if (inPerDisplayUnit) { │ │ │ │ + var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ + area *= Math.pow(inPerMapUnit / inPerDisplayUnit, 2) │ │ │ │ + } │ │ │ │ + return area │ │ │ │ }, │ │ │ │ - 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) │ │ │ │ + getBestLength: function(geometry) { │ │ │ │ + var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ + var unit, length; │ │ │ │ + for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ + unit = units[i]; │ │ │ │ + length = this.getLength(geometry, unit); │ │ │ │ + if (length > 1) { │ │ │ │ + break │ │ │ │ } │ │ │ │ - deactivated = true │ │ │ │ } │ │ │ │ - return deactivated │ │ │ │ + return [length, unit] │ │ │ │ }, │ │ │ │ - handleKeyEvent: function(evt) { │ │ │ │ - if (this.checkModifiers(evt)) { │ │ │ │ - this.callback(evt.type, [evt]) │ │ │ │ + getLength: function(geometry, units) { │ │ │ │ + var length, geomUnits; │ │ │ │ + if (this.geodesic) { │ │ │ │ + length = geometry.getGeodesicLength(this.map.getProjectionObject()); │ │ │ │ + geomUnits = "m" │ │ │ │ + } else { │ │ │ │ + length = geometry.getLength(); │ │ │ │ + geomUnits = this.map.getUnits() │ │ │ │ + } │ │ │ │ + var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ + if (inPerDisplayUnit) { │ │ │ │ + var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ + length *= inPerMapUnit / inPerDisplayUnit │ │ │ │ } │ │ │ │ + return length │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Keyboard" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Measure" │ │ │ │ }); │ │ │ │ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ documentDrag: false, │ │ │ │ geometryTypes: null, │ │ │ │ clickout: true, │ │ │ │ toggle: true, │ │ │ │ standalone: false, │ │ │ │ @@ -25884,835 +30429,14 @@ │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.ModifyFeature" │ │ │ │ }); │ │ │ │ OpenLayers.Control.ModifyFeature.RESHAPE = 1; │ │ │ │ OpenLayers.Control.ModifyFeature.RESIZE = 2; │ │ │ │ OpenLayers.Control.ModifyFeature.ROTATE = 4; │ │ │ │ OpenLayers.Control.ModifyFeature.DRAG = 8; │ │ │ │ -OpenLayers.Control.Pan = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ - slideFactor: 50, │ │ │ │ - slideRatio: null, │ │ │ │ - direction: null, │ │ │ │ - initialize: function(direction, options) { │ │ │ │ - this.direction = direction; │ │ │ │ - this.CLASS_NAME += this.direction; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - trigger: function() { │ │ │ │ - if (this.map) { │ │ │ │ - var getSlideFactor = OpenLayers.Function.bind(function(dim) { │ │ │ │ - return this.slideRatio ? this.map.getSize()[dim] * this.slideRatio : this.slideFactor │ │ │ │ - }, this); │ │ │ │ - switch (this.direction) { │ │ │ │ - case OpenLayers.Control.Pan.NORTH: │ │ │ │ - this.map.pan(0, -getSlideFactor("h")); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Control.Pan.SOUTH: │ │ │ │ - this.map.pan(0, getSlideFactor("h")); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Control.Pan.WEST: │ │ │ │ - this.map.pan(-getSlideFactor("w"), 0); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Control.Pan.EAST: │ │ │ │ - this.map.pan(getSlideFactor("w"), 0); │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Pan" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.Pan.NORTH = "North"; │ │ │ │ -OpenLayers.Control.Pan.SOUTH = "South"; │ │ │ │ -OpenLayers.Control.Pan.EAST = "East"; │ │ │ │ -OpenLayers.Control.Pan.WEST = "West"; │ │ │ │ -OpenLayers.Control.PanPanel = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ - slideFactor: 50, │ │ │ │ - slideRatio: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ - var options = { │ │ │ │ - slideFactor: this.slideFactor, │ │ │ │ - slideRatio: this.slideRatio │ │ │ │ - }; │ │ │ │ - this.addControls([new OpenLayers.Control.Pan(OpenLayers.Control.Pan.NORTH, options), new OpenLayers.Control.Pan(OpenLayers.Control.Pan.SOUTH, options), new OpenLayers.Control.Pan(OpenLayers.Control.Pan.EAST, options), new OpenLayers.Control.Pan(OpenLayers.Control.Pan.WEST, options)]) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.PanPanel" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.GetFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - protocol: null, │ │ │ │ - multipleKey: null, │ │ │ │ - toggleKey: null, │ │ │ │ - modifiers: null, │ │ │ │ - multiple: false, │ │ │ │ - click: true, │ │ │ │ - single: true, │ │ │ │ - clickout: true, │ │ │ │ - toggle: false, │ │ │ │ - clickTolerance: 5, │ │ │ │ - hover: false, │ │ │ │ - box: false, │ │ │ │ - maxFeatures: 10, │ │ │ │ - features: null, │ │ │ │ - hoverFeature: null, │ │ │ │ - handlers: null, │ │ │ │ - hoverResponse: null, │ │ │ │ - filterType: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ - initialize: function(options) { │ │ │ │ - options.handlerOptions = options.handlerOptions || {}; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.features = {}; │ │ │ │ - this.handlers = {}; │ │ │ │ - if (this.click) { │ │ │ │ - this.handlers.click = new OpenLayers.Handler.Click(this, { │ │ │ │ - click: this.selectClick │ │ │ │ - }, this.handlerOptions.click || {}) │ │ │ │ - } │ │ │ │ - if (this.box) { │ │ │ │ - this.handlers.box = new OpenLayers.Handler.Box(this, { │ │ │ │ - done: this.selectBox │ │ │ │ - }, OpenLayers.Util.extend(this.handlerOptions.box, { │ │ │ │ - boxDivClassName: "olHandlerBoxSelectFeature" │ │ │ │ - })) │ │ │ │ - } │ │ │ │ - if (this.hover) { │ │ │ │ - this.handlers.hover = new OpenLayers.Handler.Hover(this, { │ │ │ │ - move: this.cancelHover, │ │ │ │ - pause: this.selectHover │ │ │ │ - }, OpenLayers.Util.extend(this.handlerOptions.hover, { │ │ │ │ - delay: 250, │ │ │ │ - pixelTolerance: 2 │ │ │ │ - })) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (!this.active) { │ │ │ │ - for (var i in this.handlers) { │ │ │ │ - this.handlers[i].activate() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return OpenLayers.Control.prototype.activate.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (this.active) { │ │ │ │ - for (var i in this.handlers) { │ │ │ │ - this.handlers[i].deactivate() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - selectClick: function(evt) { │ │ │ │ - var bounds = this.pixelToBounds(evt.xy); │ │ │ │ - this.setModifiers(evt); │ │ │ │ - this.request(bounds, { │ │ │ │ - single: this.single │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - selectBox: function(position) { │ │ │ │ - var bounds; │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ - bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat, maxXY.lon, maxXY.lat) │ │ │ │ - } else { │ │ │ │ - if (this.click) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - bounds = this.pixelToBounds(position) │ │ │ │ - } │ │ │ │ - this.setModifiers(this.handlers.box.dragHandler.evt); │ │ │ │ - this.request(bounds) │ │ │ │ - }, │ │ │ │ - selectHover: function(evt) { │ │ │ │ - var bounds = this.pixelToBounds(evt.xy); │ │ │ │ - this.request(bounds, { │ │ │ │ - single: true, │ │ │ │ - hover: true │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - cancelHover: function() { │ │ │ │ - if (this.hoverResponse) { │ │ │ │ - this.protocol.abort(this.hoverResponse); │ │ │ │ - this.hoverResponse = null; │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait") │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - request: function(bounds, options) { │ │ │ │ - options = options || {}; │ │ │ │ - var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: this.filterType, │ │ │ │ - value: bounds │ │ │ │ - }); │ │ │ │ - OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - var response = this.protocol.read({ │ │ │ │ - maxFeatures: options.single == true ? this.maxFeatures : undefined, │ │ │ │ - filter: filter, │ │ │ │ - callback: function(result) { │ │ │ │ - if (result.success()) { │ │ │ │ - if (result.features.length) { │ │ │ │ - if (options.single == true) { │ │ │ │ - this.selectBestFeature(result.features, bounds.getCenterLonLat(), options) │ │ │ │ - } else { │ │ │ │ - this.select(result.features) │ │ │ │ - } │ │ │ │ - } else if (options.hover) { │ │ │ │ - this.hoverSelect() │ │ │ │ - } else { │ │ │ │ - this.events.triggerEvent("clickout"); │ │ │ │ - if (this.clickout) { │ │ │ │ - this.unselectAll() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait") │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - if (options.hover == true) { │ │ │ │ - this.hoverResponse = response │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - selectBestFeature: function(features, clickPosition, options) { │ │ │ │ - options = options || {}; │ │ │ │ - if (features.length) { │ │ │ │ - var point = new OpenLayers.Geometry.Point(clickPosition.lon, clickPosition.lat); │ │ │ │ - var feature, resultFeature, dist; │ │ │ │ - var minDist = Number.MAX_VALUE; │ │ │ │ - for (var i = 0; i < features.length; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - if (feature.geometry) { │ │ │ │ - dist = point.distanceTo(feature.geometry, { │ │ │ │ - edge: false │ │ │ │ - }); │ │ │ │ - if (dist < minDist) { │ │ │ │ - minDist = dist; │ │ │ │ - resultFeature = feature; │ │ │ │ - if (minDist == 0) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (options.hover == true) { │ │ │ │ - this.hoverSelect(resultFeature) │ │ │ │ - } else { │ │ │ │ - this.select(resultFeature || features) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setModifiers: function(evt) { │ │ │ │ - this.modifiers = { │ │ │ │ - multiple: this.multiple || this.multipleKey && evt[this.multipleKey], │ │ │ │ - toggle: this.toggle || this.toggleKey && evt[this.toggleKey] │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - select: function(features) { │ │ │ │ - if (!this.modifiers.multiple && !this.modifiers.toggle) { │ │ │ │ - this.unselectAll() │ │ │ │ - } │ │ │ │ - if (!OpenLayers.Util.isArray(features)) { │ │ │ │ - features = [features] │ │ │ │ - } │ │ │ │ - var cont = this.events.triggerEvent("beforefeaturesselected", { │ │ │ │ - features: features │ │ │ │ - }); │ │ │ │ - if (cont !== false) { │ │ │ │ - var selectedFeatures = []; │ │ │ │ - var feature; │ │ │ │ - for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - if (this.features[feature.fid || feature.id]) { │ │ │ │ - if (this.modifiers.toggle) { │ │ │ │ - this.unselect(this.features[feature.fid || feature.id]) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - cont = this.events.triggerEvent("beforefeatureselected", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - if (cont !== false) { │ │ │ │ - this.features[feature.fid || feature.id] = feature; │ │ │ │ - selectedFeatures.push(feature); │ │ │ │ - this.events.triggerEvent("featureselected", { │ │ │ │ - feature: feature │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.events.triggerEvent("featuresselected", { │ │ │ │ - features: selectedFeatures │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - hoverSelect: function(feature) { │ │ │ │ - var fid = feature ? feature.fid || feature.id : null; │ │ │ │ - var hfid = this.hoverFeature ? this.hoverFeature.fid || this.hoverFeature.id : null; │ │ │ │ - if (hfid && hfid != fid) { │ │ │ │ - this.events.triggerEvent("outfeature", { │ │ │ │ - feature: this.hoverFeature │ │ │ │ - }); │ │ │ │ - this.hoverFeature = null │ │ │ │ - } │ │ │ │ - if (fid && fid != hfid) { │ │ │ │ - this.events.triggerEvent("hoverfeature", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - this.hoverFeature = feature │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - unselect: function(feature) { │ │ │ │ - delete this.features[feature.fid || feature.id]; │ │ │ │ - this.events.triggerEvent("featureunselected", { │ │ │ │ - feature: feature │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - unselectAll: function() { │ │ │ │ - for (var fid in this.features) { │ │ │ │ - this.unselect(this.features[fid]) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - for (var i in this.handlers) { │ │ │ │ - this.handlers[i].setMap(map) │ │ │ │ - } │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - pixelToBounds: function(pixel) { │ │ │ │ - var llPx = pixel.add(-this.clickTolerance / 2, this.clickTolerance / 2); │ │ │ │ - var urPx = pixel.add(this.clickTolerance / 2, -this.clickTolerance / 2); │ │ │ │ - var ll = this.map.getLonLatFromPixel(llPx); │ │ │ │ - var ur = this.map.getLonLatFromPixel(urPx); │ │ │ │ - return new OpenLayers.Bounds(ll.lon, ll.lat, ur.lon, ur.lat) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.GetFeature" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.ZoomToMaxExtent = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ - trigger: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.zoomToMaxExtent() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomToMaxExtent" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.CacheRead = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - fetchEvent: "tileloadstart", │ │ │ │ - layers: null, │ │ │ │ - autoActivate: true, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - var i, layers = this.layers || map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.addLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - if (!this.layers) { │ │ │ │ - map.events.on({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - addLayer: function(evt) { │ │ │ │ - evt.layer.events.register(this.fetchEvent, this, this.fetch) │ │ │ │ - }, │ │ │ │ - removeLayer: function(evt) { │ │ │ │ - evt.layer.events.unregister(this.fetchEvent, this, this.fetch) │ │ │ │ - }, │ │ │ │ - fetch: function(evt) { │ │ │ │ - if (this.active && window.localStorage && evt.tile instanceof OpenLayers.Tile.Image) { │ │ │ │ - var tile = evt.tile, │ │ │ │ - url = tile.url; │ │ │ │ - if (!tile.layer.crossOriginKeyword && OpenLayers.ProxyHost && url.indexOf(OpenLayers.ProxyHost) === 0) { │ │ │ │ - url = OpenLayers.Control.CacheWrite.urlMap[url] │ │ │ │ - } │ │ │ │ - var dataURI = window.localStorage.getItem("olCache_" + url); │ │ │ │ - if (dataURI) { │ │ │ │ - tile.url = dataURI; │ │ │ │ - if (evt.type === "tileerror") { │ │ │ │ - tile.setImgSrc(dataURI) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.layers || this.map) { │ │ │ │ - var i, layers = this.layers || this.map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.removeLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.un({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.CacheRead" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.LayerSwitcher = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - layerStates: null, │ │ │ │ - layersDiv: null, │ │ │ │ - baseLayersDiv: null, │ │ │ │ - baseLayers: null, │ │ │ │ - dataLbl: null, │ │ │ │ - dataLayersDiv: null, │ │ │ │ - dataLayers: null, │ │ │ │ - minimizeDiv: null, │ │ │ │ - maximizeDiv: null, │ │ │ │ - ascending: true, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ - this.layerStates = [] │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.clearLayersArray("base"); │ │ │ │ - this.clearLayersArray("data"); │ │ │ │ - this.map.events.un({ │ │ │ │ - buttonclick: this.onButtonClick, │ │ │ │ - addlayer: this.redraw, │ │ │ │ - changelayer: this.redraw, │ │ │ │ - removelayer: this.redraw, │ │ │ │ - changebaselayer: this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - this.map.events.on({ │ │ │ │ - addlayer: this.redraw, │ │ │ │ - changelayer: this.redraw, │ │ │ │ - removelayer: this.redraw, │ │ │ │ - changebaselayer: this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - if (this.outsideViewport) { │ │ │ │ - this.events.attachToElement(this.div); │ │ │ │ - this.events.register("buttonclick", this, this.onButtonClick) │ │ │ │ - } else { │ │ │ │ - this.map.events.register("buttonclick", this, this.onButtonClick) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this); │ │ │ │ - this.loadContents(); │ │ │ │ - if (!this.outsideViewport) { │ │ │ │ - this.minimizeControl() │ │ │ │ - } │ │ │ │ - this.redraw(); │ │ │ │ - return this.div │ │ │ │ - }, │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - var button = evt.buttonElement; │ │ │ │ - if (button === this.minimizeDiv) { │ │ │ │ - this.minimizeControl() │ │ │ │ - } else if (button === this.maximizeDiv) { │ │ │ │ - this.maximizeControl() │ │ │ │ - } else if (button._layerSwitcher === this.id) { │ │ │ │ - if (button["for"]) { │ │ │ │ - button = document.getElementById(button["for"]) │ │ │ │ - } │ │ │ │ - if (!button.disabled) { │ │ │ │ - if (button.type == "radio") { │ │ │ │ - button.checked = true; │ │ │ │ - this.map.setBaseLayer(this.map.getLayer(button._layer)) │ │ │ │ - } else { │ │ │ │ - button.checked = !button.checked; │ │ │ │ - this.updateMap() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clearLayersArray: function(layersType) { │ │ │ │ - this[layersType + "LayersDiv"].innerHTML = ""; │ │ │ │ - this[layersType + "Layers"] = [] │ │ │ │ - }, │ │ │ │ - checkRedraw: function() { │ │ │ │ - if (!this.layerStates.length || this.map.layers.length != this.layerStates.length) { │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - for (var i = 0, len = this.layerStates.length; i < len; i++) { │ │ │ │ - var layerState = this.layerStates[i]; │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - if (layerState.name != layer.name || layerState.inRange != layer.inRange || layerState.id != layer.id || layerState.visibility != layer.visibility) { │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - redraw: function() { │ │ │ │ - if (!this.checkRedraw()) { │ │ │ │ - return this.div │ │ │ │ - } │ │ │ │ - this.clearLayersArray("base"); │ │ │ │ - this.clearLayersArray("data"); │ │ │ │ - var containsOverlays = false; │ │ │ │ - var containsBaseLayers = false; │ │ │ │ - var len = this.map.layers.length; │ │ │ │ - this.layerStates = new Array(len); │ │ │ │ - for (var i = 0; i < len; i++) { │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - this.layerStates[i] = { │ │ │ │ - name: layer.name, │ │ │ │ - visibility: layer.visibility, │ │ │ │ - inRange: layer.inRange, │ │ │ │ - id: layer.id │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var layers = this.map.layers.slice(); │ │ │ │ - if (!this.ascending) { │ │ │ │ - layers.reverse() │ │ │ │ - } │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - var layer = layers[i]; │ │ │ │ - var baseLayer = layer.isBaseLayer; │ │ │ │ - if (layer.displayInLayerSwitcher) { │ │ │ │ - if (baseLayer) { │ │ │ │ - containsBaseLayers = true │ │ │ │ - } else { │ │ │ │ - containsOverlays = true │ │ │ │ - } │ │ │ │ - var checked = baseLayer ? layer == this.map.baseLayer : layer.getVisibility(); │ │ │ │ - var inputElem = document.createElement("input"), │ │ │ │ - inputId = OpenLayers.Util.createUniqueID(this.id + "_input_"); │ │ │ │ - inputElem.id = inputId; │ │ │ │ - inputElem.name = baseLayer ? this.id + "_baseLayers" : layer.name; │ │ │ │ - inputElem.type = baseLayer ? "radio" : "checkbox"; │ │ │ │ - inputElem.value = layer.name; │ │ │ │ - inputElem.checked = checked; │ │ │ │ - inputElem.defaultChecked = checked; │ │ │ │ - inputElem.className = "olButton"; │ │ │ │ - inputElem._layer = layer.id; │ │ │ │ - inputElem._layerSwitcher = this.id; │ │ │ │ - if (!baseLayer && !layer.inRange) { │ │ │ │ - inputElem.disabled = true │ │ │ │ - } │ │ │ │ - var labelSpan = document.createElement("label"); │ │ │ │ - labelSpan["for"] = inputElem.id; │ │ │ │ - OpenLayers.Element.addClass(labelSpan, "labelSpan olButton"); │ │ │ │ - labelSpan._layer = layer.id; │ │ │ │ - labelSpan._layerSwitcher = this.id; │ │ │ │ - if (!baseLayer && !layer.inRange) { │ │ │ │ - labelSpan.style.color = "gray" │ │ │ │ - } │ │ │ │ - labelSpan.innerHTML = layer.name; │ │ │ │ - labelSpan.style.verticalAlign = baseLayer ? "bottom" : "baseline"; │ │ │ │ - var br = document.createElement("br"); │ │ │ │ - var groupArray = baseLayer ? this.baseLayers : this.dataLayers; │ │ │ │ - groupArray.push({ │ │ │ │ - layer: layer, │ │ │ │ - inputElem: inputElem, │ │ │ │ - labelSpan: labelSpan │ │ │ │ - }); │ │ │ │ - var groupDiv = baseLayer ? this.baseLayersDiv : this.dataLayersDiv; │ │ │ │ - groupDiv.appendChild(inputElem); │ │ │ │ - groupDiv.appendChild(labelSpan); │ │ │ │ - groupDiv.appendChild(br) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.dataLbl.style.display = containsOverlays ? "" : "none"; │ │ │ │ - this.baseLbl.style.display = containsBaseLayers ? "" : "none"; │ │ │ │ - return this.div │ │ │ │ - }, │ │ │ │ - updateMap: function() { │ │ │ │ - for (var i = 0, len = this.baseLayers.length; i < len; i++) { │ │ │ │ - var layerEntry = this.baseLayers[i]; │ │ │ │ - if (layerEntry.inputElem.checked) { │ │ │ │ - this.map.setBaseLayer(layerEntry.layer, false) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - for (var i = 0, len = this.dataLayers.length; i < len; i++) { │ │ │ │ - var layerEntry = this.dataLayers[i]; │ │ │ │ - layerEntry.layer.setVisibility(layerEntry.inputElem.checked) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - maximizeControl: function(e) { │ │ │ │ - this.div.style.width = ""; │ │ │ │ - this.div.style.height = ""; │ │ │ │ - this.showControls(false); │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - minimizeControl: function(e) { │ │ │ │ - this.div.style.width = "0px"; │ │ │ │ - this.div.style.height = "0px"; │ │ │ │ - this.showControls(true); │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - showControls: function(minimize) { │ │ │ │ - this.maximizeDiv.style.display = minimize ? "" : "none"; │ │ │ │ - this.minimizeDiv.style.display = minimize ? "none" : ""; │ │ │ │ - this.layersDiv.style.display = minimize ? "none" : "" │ │ │ │ - }, │ │ │ │ - loadContents: function() { │ │ │ │ - this.layersDiv = document.createElement("div"); │ │ │ │ - this.layersDiv.id = this.id + "_layersDiv"; │ │ │ │ - OpenLayers.Element.addClass(this.layersDiv, "layersDiv"); │ │ │ │ - this.baseLbl = document.createElement("div"); │ │ │ │ - this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer"); │ │ │ │ - OpenLayers.Element.addClass(this.baseLbl, "baseLbl"); │ │ │ │ - this.baseLayersDiv = document.createElement("div"); │ │ │ │ - OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv"); │ │ │ │ - this.dataLbl = document.createElement("div"); │ │ │ │ - this.dataLbl.innerHTML = OpenLayers.i18n("Overlays"); │ │ │ │ - OpenLayers.Element.addClass(this.dataLbl, "dataLbl"); │ │ │ │ - this.dataLayersDiv = document.createElement("div"); │ │ │ │ - OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv"); │ │ │ │ - if (this.ascending) { │ │ │ │ - this.layersDiv.appendChild(this.baseLbl); │ │ │ │ - this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ - this.layersDiv.appendChild(this.dataLbl); │ │ │ │ - this.layersDiv.appendChild(this.dataLayersDiv) │ │ │ │ - } else { │ │ │ │ - this.layersDiv.appendChild(this.dataLbl); │ │ │ │ - this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ - this.layersDiv.appendChild(this.baseLbl); │ │ │ │ - this.layersDiv.appendChild(this.baseLayersDiv) │ │ │ │ - } │ │ │ │ - this.div.appendChild(this.layersDiv); │ │ │ │ - var img = OpenLayers.Util.getImageLocation("layer-switcher-maximize.png"); │ │ │ │ - this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MaximizeDiv", null, null, img, "absolute"); │ │ │ │ - OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv olButton"); │ │ │ │ - this.maximizeDiv.style.display = "none"; │ │ │ │ - this.div.appendChild(this.maximizeDiv); │ │ │ │ - var img = OpenLayers.Util.getImageLocation("layer-switcher-minimize.png"); │ │ │ │ - this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MinimizeDiv", null, null, img, "absolute"); │ │ │ │ - OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton"); │ │ │ │ - this.minimizeDiv.style.display = "none"; │ │ │ │ - this.div.appendChild(this.minimizeDiv) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.LayerSwitcher" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.ZoomPanel = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ - this.addControls([new OpenLayers.Control.ZoomIn, new OpenLayers.Control.ZoomToMaxExtent, new OpenLayers.Control.ZoomOut]) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomPanel" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.WMTSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - hover: false, │ │ │ │ - requestEncoding: "KVP", │ │ │ │ - drillDown: false, │ │ │ │ - maxFeatures: 10, │ │ │ │ - clickCallback: "click", │ │ │ │ - layers: null, │ │ │ │ - queryVisible: true, │ │ │ │ - infoFormat: "text/html", │ │ │ │ - vendorParams: {}, │ │ │ │ - format: null, │ │ │ │ - formatOptions: null, │ │ │ │ - handler: null, │ │ │ │ - hoverRequest: null, │ │ │ │ - pending: 0, │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.handlerOptions = options.handlerOptions || {}; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - if (!this.format) { │ │ │ │ - this.format = new OpenLayers.Format.WMSGetFeatureInfo(options.formatOptions) │ │ │ │ - } │ │ │ │ - if (this.drillDown === true) { │ │ │ │ - this.hover = false │ │ │ │ - } │ │ │ │ - if (this.hover) { │ │ │ │ - this.handler = new OpenLayers.Handler.Hover(this, { │ │ │ │ - move: this.cancelHover, │ │ │ │ - pause: this.getInfoForHover │ │ │ │ - }, OpenLayers.Util.extend(this.handlerOptions.hover || {}, { │ │ │ │ - delay: 250 │ │ │ │ - })) │ │ │ │ - } else { │ │ │ │ - var callbacks = {}; │ │ │ │ - callbacks[this.clickCallback] = this.getInfoForClick; │ │ │ │ - this.handler = new OpenLayers.Handler.Click(this, callbacks, this.handlerOptions.click || {}) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getInfoForClick: function(evt) { │ │ │ │ - this.request(evt.xy, {}) │ │ │ │ - }, │ │ │ │ - getInfoForHover: function(evt) { │ │ │ │ - this.request(evt.xy, { │ │ │ │ - hover: true │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - cancelHover: function() { │ │ │ │ - if (this.hoverRequest) { │ │ │ │ - --this.pending; │ │ │ │ - if (this.pending <= 0) { │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - this.pending = 0 │ │ │ │ - } │ │ │ │ - this.hoverRequest.abort(); │ │ │ │ - this.hoverRequest = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - findLayers: function() { │ │ │ │ - var candidates = this.layers || this.map.layers; │ │ │ │ - var layers = []; │ │ │ │ - var layer; │ │ │ │ - for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ - layer = candidates[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.WMTS && layer.requestEncoding === this.requestEncoding && (!this.queryVisible || layer.getVisibility())) { │ │ │ │ - layers.push(layer); │ │ │ │ - if (!this.drillDown || this.hover) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return layers │ │ │ │ - }, │ │ │ │ - buildRequestOptions: function(layer, xy) { │ │ │ │ - var loc = this.map.getLonLatFromPixel(xy); │ │ │ │ - var getTileUrl = layer.getURL(new OpenLayers.Bounds(loc.lon, loc.lat, loc.lon, loc.lat)); │ │ │ │ - var params = OpenLayers.Util.getParameters(getTileUrl); │ │ │ │ - var tileInfo = layer.getTileInfo(loc); │ │ │ │ - OpenLayers.Util.extend(params, { │ │ │ │ - service: "WMTS", │ │ │ │ - version: layer.version, │ │ │ │ - request: "GetFeatureInfo", │ │ │ │ - infoFormat: this.infoFormat, │ │ │ │ - i: tileInfo.i, │ │ │ │ - j: tileInfo.j │ │ │ │ - }); │ │ │ │ - OpenLayers.Util.applyDefaults(params, this.vendorParams); │ │ │ │ - return { │ │ │ │ - url: OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url, │ │ │ │ - params: OpenLayers.Util.upperCaseObject(params), │ │ │ │ - callback: function(request) { │ │ │ │ - this.handleResponse(xy, request, layer) │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - request: function(xy, options) { │ │ │ │ - options = options || {}; │ │ │ │ - var layers = this.findLayers(); │ │ │ │ - if (layers.length > 0) { │ │ │ │ - var issue, layer; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - layer = layers[i]; │ │ │ │ - issue = this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ - xy: xy, │ │ │ │ - layer: layer │ │ │ │ - }); │ │ │ │ - if (issue !== false) { │ │ │ │ - ++this.pending; │ │ │ │ - var requestOptions = this.buildRequestOptions(layer, xy); │ │ │ │ - var request = OpenLayers.Request.GET(requestOptions); │ │ │ │ - if (options.hover === true) { │ │ │ │ - this.hoverRequest = request │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.pending > 0) { │ │ │ │ - OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - handleResponse: function(xy, request, layer) { │ │ │ │ - --this.pending; │ │ │ │ - if (this.pending <= 0) { │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - this.pending = 0 │ │ │ │ - } │ │ │ │ - if (request.status && (request.status < 200 || request.status >= 300)) { │ │ │ │ - this.events.triggerEvent("exception", { │ │ │ │ - xy: xy, │ │ │ │ - request: request, │ │ │ │ - layer: layer │ │ │ │ - }) │ │ │ │ - } else { │ │ │ │ - var doc = request.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = request.responseText │ │ │ │ - } │ │ │ │ - var features, except; │ │ │ │ - try { │ │ │ │ - features = this.format.read(doc) │ │ │ │ - } catch (error) { │ │ │ │ - except = true; │ │ │ │ - this.events.triggerEvent("exception", { │ │ │ │ - xy: xy, │ │ │ │ - request: request, │ │ │ │ - error: error, │ │ │ │ - layer: layer │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - if (!except) { │ │ │ │ - this.events.triggerEvent("getfeatureinfo", { │ │ │ │ - text: request.responseText, │ │ │ │ - features: features, │ │ │ │ - request: request, │ │ │ │ - xy: xy, │ │ │ │ - layer: layer │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.WMTSGetFeatureInfo" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.Attribution = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - separator: ", ", │ │ │ │ - template: "${layers}", │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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()) { │ │ │ │ - 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.Control.Split = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ layer: null, │ │ │ │ source: null, │ │ │ │ sourceOptions: null, │ │ │ │ tolerance: null, │ │ │ │ edge: true, │ │ │ │ deferDelete: false, │ │ │ │ @@ -26882,3337 +30606,354 @@ │ │ │ │ sourceSplit = true │ │ │ │ } │ │ │ │ if (sourceSplit || targetSplit) { │ │ │ │ if (this.deferDelete) { │ │ │ │ var feat, destroys = []; │ │ │ │ for (var i = 0, len = removals.length; i < len; ++i) { │ │ │ │ feat = removals[i]; │ │ │ │ - if (feat.state === OpenLayers.State.INSERT) { │ │ │ │ - destroys.push(feat) │ │ │ │ - } else { │ │ │ │ - feat.state = OpenLayers.State.DELETE; │ │ │ │ - this.layer.drawFeature(feat) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.layer.destroyFeatures(destroys, { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ - for (var i = 0, len = additions.length; i < len; ++i) { │ │ │ │ - additions[i].state = OpenLayers.State.INSERT │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.layer.destroyFeatures(removals, { │ │ │ │ - silent: true │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - this.layer.addFeatures(additions, { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ - this.events.triggerEvent("aftersplit", { │ │ │ │ - source: feature, │ │ │ │ - features: additions │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return sourceSplit │ │ │ │ - }, │ │ │ │ - geomsToFeatures: function(feature, geoms) { │ │ │ │ - var clone = feature.clone(); │ │ │ │ - delete clone.geometry; │ │ │ │ - var newFeature; │ │ │ │ - for (var i = 0, len = geoms.length; i < len; ++i) { │ │ │ │ - newFeature = clone.clone(); │ │ │ │ - newFeature.geometry = geoms[i]; │ │ │ │ - newFeature.state = OpenLayers.State.INSERT; │ │ │ │ - geoms[i] = newFeature │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.active) { │ │ │ │ - this.deactivate() │ │ │ │ - } │ │ │ │ - OpenLayers.Control.prototype.destroy.call(this) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Split" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.KeyboardDefaults = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - autoActivate: true, │ │ │ │ - slideFactor: 75, │ │ │ │ - observeElement: null, │ │ │ │ - draw: function() { │ │ │ │ - var observeElement = this.observeElement || document; │ │ │ │ - this.handler = new OpenLayers.Handler.Keyboard(this, { │ │ │ │ - keydown: this.defaultKeyPress │ │ │ │ - }, { │ │ │ │ - observeElement: observeElement │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - defaultKeyPress: function(evt) { │ │ │ │ - var size, handled = true; │ │ │ │ - var target = OpenLayers.Event.element(evt); │ │ │ │ - if (target && (target.tagName == "INPUT" || target.tagName == "TEXTAREA" || target.tagName == "SELECT")) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - switch (evt.keyCode) { │ │ │ │ - case OpenLayers.Event.KEY_LEFT: │ │ │ │ - this.map.pan(-this.slideFactor, 0); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Event.KEY_RIGHT: │ │ │ │ - this.map.pan(this.slideFactor, 0); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Event.KEY_UP: │ │ │ │ - this.map.pan(0, -this.slideFactor); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Event.KEY_DOWN: │ │ │ │ - this.map.pan(0, this.slideFactor); │ │ │ │ - break; │ │ │ │ - case 33: │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(0, -.75 * size.h); │ │ │ │ - break; │ │ │ │ - case 34: │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(0, .75 * size.h); │ │ │ │ - break; │ │ │ │ - case 35: │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(.75 * size.w, 0); │ │ │ │ - break; │ │ │ │ - case 36: │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(-.75 * size.w, 0); │ │ │ │ - break; │ │ │ │ - case 43: │ │ │ │ - case 61: │ │ │ │ - case 187: │ │ │ │ - case 107: │ │ │ │ - this.map.zoomIn(); │ │ │ │ - break; │ │ │ │ - case 45: │ │ │ │ - case 109: │ │ │ │ - case 189: │ │ │ │ - case 95: │ │ │ │ - this.map.zoomOut(); │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - handled = false │ │ │ │ - } │ │ │ │ - if (handled) { │ │ │ │ - OpenLayers.Event.stop(evt) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.KeyboardDefaults" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - multipleKey: null, │ │ │ │ - toggleKey: null, │ │ │ │ - multiple: false, │ │ │ │ - clickout: true, │ │ │ │ - toggle: false, │ │ │ │ - hover: false, │ │ │ │ - highlightOnly: false, │ │ │ │ - box: false, │ │ │ │ - onBeforeSelect: function() {}, │ │ │ │ - onSelect: function() {}, │ │ │ │ - onUnselect: function() {}, │ │ │ │ - scope: null, │ │ │ │ - geometryTypes: null, │ │ │ │ - layer: null, │ │ │ │ - layers: null, │ │ │ │ - callbacks: null, │ │ │ │ - selectStyle: null, │ │ │ │ - renderIntent: "select", │ │ │ │ - handlers: null, │ │ │ │ - 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" │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - unselectAll: function(options) { │ │ │ │ - var layers = this.layers || [this.layer], │ │ │ │ - layer, feature, l, numExcept; │ │ │ │ - for (l = 0; l < layers.length; ++l) { │ │ │ │ - layer = layers[l]; │ │ │ │ - numExcept = 0; │ │ │ │ - if (layer.selectedFeatures != null) { │ │ │ │ - while (layer.selectedFeatures.length > numExcept) { │ │ │ │ - feature = layer.selectedFeatures[numExcept]; │ │ │ │ - if (!options || options.except != feature) { │ │ │ │ - this.unselect(feature) │ │ │ │ - } else { │ │ │ │ - ++numExcept │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - multipleSelect: function() { │ │ │ │ - return this.multiple || this.handlers.feature.evt && this.handlers.feature.evt[this.multipleKey] │ │ │ │ - }, │ │ │ │ - toggleSelect: function() { │ │ │ │ - return this.toggle || this.handlers.feature.evt && this.handlers.feature.evt[this.toggleKey] │ │ │ │ - }, │ │ │ │ - clickoutFeature: function(feature) { │ │ │ │ - if (!this.hover && this.clickout) { │ │ │ │ - this.unselectAll() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - outFeature: function(feature) { │ │ │ │ - if (this.hover) { │ │ │ │ - if (this.highlightOnly) { │ │ │ │ - if (feature._lastHighlighter == this.id) { │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - unhighlight: function(feature) { │ │ │ │ - var layer = feature.layer; │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - 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 (!this.handlers.feature.lastFeature) { │ │ │ │ - this.handlers.feature.lastFeature = layer.selectedFeatures[0] │ │ │ │ - } │ │ │ │ - layer.events.triggerEvent("featureselected", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - this.onSelect.call(this.scope, feature) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - unselect: function(feature) { │ │ │ │ - var layer = feature.layer; │ │ │ │ - this.unhighlight(feature); │ │ │ │ - OpenLayers.Util.removeItem(layer.selectedFeatures, feature); │ │ │ │ - layer.events.triggerEvent("featureunselected", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - this.onUnselect.call(this.scope, feature) │ │ │ │ - }, │ │ │ │ - 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 (!this.multipleSelect()) { │ │ │ │ - this.unselectAll() │ │ │ │ - } │ │ │ │ - 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]; │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - this.handlers.feature.setMap(map); │ │ │ │ - if (this.box) { │ │ │ │ - this.handlers.box.setMap(map) │ │ │ │ - } │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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.Control.MousePosition = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - autoActivate: true, │ │ │ │ - element: null, │ │ │ │ - prefix: "", │ │ │ │ - separator: ", ", │ │ │ │ - suffix: "", │ │ │ │ - numDigits: 5, │ │ │ │ - granularity: 10, │ │ │ │ - emptyString: null, │ │ │ │ - lastXy: null, │ │ │ │ - displayProjection: null, │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.map.events.register("mousemove", this, this.redraw); │ │ │ │ - this.map.events.register("mouseout", this, this.reset); │ │ │ │ - this.redraw(); │ │ │ │ - return true │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - this.map.events.unregister("mousemove", this, this.redraw); │ │ │ │ - this.map.events.unregister("mouseout", this, this.reset); │ │ │ │ - this.element.innerHTML = ""; │ │ │ │ - return true │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (!this.element) { │ │ │ │ - this.div.left = ""; │ │ │ │ - this.div.top = ""; │ │ │ │ - this.element = this.div │ │ │ │ - } │ │ │ │ - return this.div │ │ │ │ - }, │ │ │ │ - redraw: function(evt) { │ │ │ │ - var lonLat; │ │ │ │ - if (evt == null) { │ │ │ │ - this.reset(); │ │ │ │ - return │ │ │ │ - } else { │ │ │ │ - if (this.lastXy == null || Math.abs(evt.xy.x - this.lastXy.x) > this.granularity || Math.abs(evt.xy.y - this.lastXy.y) > this.granularity) { │ │ │ │ - this.lastXy = evt.xy; │ │ │ │ - return │ │ │ │ - } │ │ │ │ - lonLat = this.map.getLonLatFromPixel(evt.xy); │ │ │ │ - if (!lonLat) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - if (this.displayProjection) { │ │ │ │ - lonLat.transform(this.map.getProjectionObject(), this.displayProjection) │ │ │ │ - } │ │ │ │ - this.lastXy = evt.xy │ │ │ │ - } │ │ │ │ - var newHtml = this.formatOutput(lonLat); │ │ │ │ - if (newHtml != this.element.innerHTML) { │ │ │ │ - this.element.innerHTML = newHtml │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - reset: function(evt) { │ │ │ │ - if (this.emptyString != null) { │ │ │ │ - this.element.innerHTML = this.emptyString │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - formatOutput: function(lonLat) { │ │ │ │ - var digits = parseInt(this.numDigits); │ │ │ │ - var newHtml = this.prefix + lonLat.lon.toFixed(digits) + this.separator + lonLat.lat.toFixed(digits) + this.suffix; │ │ │ │ - return newHtml │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.MousePosition" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.TouchNavigation = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - dragPan: null, │ │ │ │ - dragPanOptions: null, │ │ │ │ - pinchZoom: null, │ │ │ │ - pinchZoomOptions: null, │ │ │ │ - clickHandlerOptions: null, │ │ │ │ - documentDrag: false, │ │ │ │ - autoActivate: true, │ │ │ │ - initialize: function(options) { │ │ │ │ - this.handlers = {}; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.dragPan.activate(); │ │ │ │ - this.handlers.click.activate(); │ │ │ │ - this.pinchZoom.activate(); │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - this.dragPan.deactivate(); │ │ │ │ - this.handlers.click.deactivate(); │ │ │ │ - this.pinchZoom.deactivate(); │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - 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)) │ │ │ │ - }, │ │ │ │ - defaultClick: function(evt) { │ │ │ │ - if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ - this.map.zoomOut() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - defaultDblClick: function(evt) { │ │ │ │ - this.map.zoomTo(this.map.zoom + 1, evt.xy) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.TouchNavigation" │ │ │ │ -}); │ │ │ │ -OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - distance: 20, │ │ │ │ - threshold: null, │ │ │ │ - features: null, │ │ │ │ - clusters: null, │ │ │ │ - clustering: false, │ │ │ │ - resolution: null, │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - beforefeaturesadded: this.cacheFeatures, │ │ │ │ - featuresremoved: this.clearCache, │ │ │ │ - moveend: this.cluster, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.layer.events.un({ │ │ │ │ - beforefeaturesadded: this.cacheFeatures, │ │ │ │ - featuresremoved: this.clearCache, │ │ │ │ - moveend: this.cluster, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - cacheFeatures: function(event) { │ │ │ │ - var propagate = true; │ │ │ │ - if (!this.clustering) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.features = event.features; │ │ │ │ - this.cluster(); │ │ │ │ - propagate = false │ │ │ │ - } │ │ │ │ - return propagate │ │ │ │ - }, │ │ │ │ - clearCache: function() { │ │ │ │ - if (!this.clustering) { │ │ │ │ - this.features = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - cluster: function(event) { │ │ │ │ - if ((!event || event.zoomChanged) && this.features) { │ │ │ │ - var resolution = this.layer.map.getResolution(); │ │ │ │ - if (resolution != this.resolution || !this.clustersExist()) { │ │ │ │ - this.resolution = resolution; │ │ │ │ - var clusters = []; │ │ │ │ - var feature, clustered, cluster; │ │ │ │ - for (var i = 0; i < this.features.length; ++i) { │ │ │ │ - feature = this.features[i]; │ │ │ │ - if (feature.geometry) { │ │ │ │ - clustered = false; │ │ │ │ - for (var j = clusters.length - 1; j >= 0; --j) { │ │ │ │ - cluster = clusters[j]; │ │ │ │ - if (this.shouldCluster(cluster, feature)) { │ │ │ │ - this.addToCluster(cluster, feature); │ │ │ │ - clustered = true; │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (!clustered) { │ │ │ │ - clusters.push(this.createCluster(this.features[i])) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.clustering = true; │ │ │ │ - this.layer.removeAllFeatures(); │ │ │ │ - this.clustering = false; │ │ │ │ - if (clusters.length > 0) { │ │ │ │ - if (this.threshold > 1) { │ │ │ │ - var clone = clusters.slice(); │ │ │ │ - clusters = []; │ │ │ │ - var candidate; │ │ │ │ - for (var i = 0, len = clone.length; i < len; ++i) { │ │ │ │ - candidate = clone[i]; │ │ │ │ - if (candidate.attributes.count < this.threshold) { │ │ │ │ - Array.prototype.push.apply(clusters, candidate.cluster) │ │ │ │ - } else { │ │ │ │ - clusters.push(candidate) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.clustering = true; │ │ │ │ - this.layer.addFeatures(clusters); │ │ │ │ - this.clustering = false │ │ │ │ - } │ │ │ │ - this.clusters = clusters │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clustersExist: function() { │ │ │ │ - var exist = false; │ │ │ │ - if (this.clusters && this.clusters.length > 0 && this.clusters.length == this.layer.features.length) { │ │ │ │ - exist = true; │ │ │ │ - for (var i = 0; i < this.clusters.length; ++i) { │ │ │ │ - if (this.clusters[i] != this.layer.features[i]) { │ │ │ │ - exist = false; │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return exist │ │ │ │ - }, │ │ │ │ - shouldCluster: function(cluster, feature) { │ │ │ │ - var cc = cluster.geometry.getBounds().getCenterLonLat(); │ │ │ │ - var fc = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ - var distance = Math.sqrt(Math.pow(cc.lon - fc.lon, 2) + Math.pow(cc.lat - fc.lat, 2)) / this.resolution; │ │ │ │ - return distance <= this.distance │ │ │ │ - }, │ │ │ │ - addToCluster: function(cluster, feature) { │ │ │ │ - cluster.cluster.push(feature); │ │ │ │ - cluster.attributes.count += 1 │ │ │ │ - }, │ │ │ │ - createCluster: function(feature) { │ │ │ │ - var center = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ - var cluster = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(center.lon, center.lat), { │ │ │ │ - count: 1 │ │ │ │ - }); │ │ │ │ - cluster.cluster = [feature]; │ │ │ │ - return cluster │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Cluster" │ │ │ │ -}); │ │ │ │ -OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - bounds: null, │ │ │ │ - resolution: null, │ │ │ │ - ratio: 2, │ │ │ │ - resFactor: null, │ │ │ │ - response: null, │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - moveend: this.update, │ │ │ │ - refresh: this.update, │ │ │ │ - visibilitychanged: this.update, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.update() │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.layer.events.un({ │ │ │ │ - moveend: this.update, │ │ │ │ - refresh: this.update, │ │ │ │ - visibilitychanged: this.update, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - update: function(options) { │ │ │ │ - var mapBounds = this.getMapBounds(); │ │ │ │ - if (mapBounds !== null && (options && options.force || this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds))) { │ │ │ │ - this.calculateBounds(mapBounds); │ │ │ │ - this.resolution = this.layer.map.getResolution(); │ │ │ │ - this.triggerRead(options) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getMapBounds: function() { │ │ │ │ - if (this.layer.map === null) { │ │ │ │ - return null │ │ │ │ - } │ │ │ │ - var bounds = this.layer.map.getExtent(); │ │ │ │ - if (bounds && !this.layer.projection.equals(this.layer.map.getProjectionObject())) { │ │ │ │ - bounds = bounds.clone().transform(this.layer.map.getProjectionObject(), this.layer.projection) │ │ │ │ - } │ │ │ │ - return bounds │ │ │ │ - }, │ │ │ │ - invalidBounds: function(mapBounds) { │ │ │ │ - if (!mapBounds) { │ │ │ │ - mapBounds = this.getMapBounds() │ │ │ │ - } │ │ │ │ - var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds); │ │ │ │ - if (!invalid && this.resFactor) { │ │ │ │ - var ratio = this.resolution / this.layer.map.getResolution(); │ │ │ │ - invalid = ratio >= this.resFactor || ratio <= 1 / this.resFactor │ │ │ │ - } │ │ │ │ - return invalid │ │ │ │ - }, │ │ │ │ - calculateBounds: function(mapBounds) { │ │ │ │ - if (!mapBounds) { │ │ │ │ - mapBounds = this.getMapBounds() │ │ │ │ - } │ │ │ │ - var center = mapBounds.getCenterLonLat(); │ │ │ │ - var dataWidth = mapBounds.getWidth() * this.ratio; │ │ │ │ - var dataHeight = mapBounds.getHeight() * this.ratio; │ │ │ │ - this.bounds = new OpenLayers.Bounds(center.lon - dataWidth / 2, center.lat - dataHeight / 2, center.lon + dataWidth / 2, center.lat + dataHeight / 2) │ │ │ │ - }, │ │ │ │ - triggerRead: function(options) { │ │ │ │ - if (this.response && !(options && options.noAbort === true)) { │ │ │ │ - this.layer.protocol.abort(this.response); │ │ │ │ - this.layer.events.triggerEvent("loadend") │ │ │ │ - } │ │ │ │ - var evt = { │ │ │ │ - filter: this.createFilter() │ │ │ │ - }; │ │ │ │ - this.layer.events.triggerEvent("loadstart", evt); │ │ │ │ - this.response = this.layer.protocol.read(OpenLayers.Util.applyDefaults({ │ │ │ │ - filter: evt.filter, │ │ │ │ - callback: this.merge, │ │ │ │ - scope: this │ │ │ │ - }, options)) │ │ │ │ - }, │ │ │ │ - createFilter: function() { │ │ │ │ - var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ - value: this.bounds, │ │ │ │ - projection: this.layer.projection │ │ │ │ - }); │ │ │ │ - if (this.layer.filter) { │ │ │ │ - filter = new OpenLayers.Filter.Logical({ │ │ │ │ - type: OpenLayers.Filter.Logical.AND, │ │ │ │ - filters: [this.layer.filter, filter] │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return filter │ │ │ │ - }, │ │ │ │ - merge: function(resp) { │ │ │ │ - this.layer.destroyFeatures(); │ │ │ │ - if (resp.success()) { │ │ │ │ - var features = resp.features; │ │ │ │ - if (features && features.length > 0) { │ │ │ │ - var remote = this.layer.projection; │ │ │ │ - var local = this.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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.layer.addFeatures(features) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.bounds = null │ │ │ │ - } │ │ │ │ - this.response = null; │ │ │ │ - this.layer.events.triggerEvent("loadend", { │ │ │ │ - response: resp │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.BBOX" │ │ │ │ -}); │ │ │ │ -OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - events: null, │ │ │ │ - auto: false, │ │ │ │ - timer: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Strategy.prototype.initialize.apply(this, [options]); │ │ │ │ - this.events = new OpenLayers.Events(this) │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - if (this.auto) { │ │ │ │ - if (typeof this.auto === "number") { │ │ │ │ - this.timer = window.setInterval(OpenLayers.Function.bind(this.save, this), this.auto * 1e3) │ │ │ │ - } else { │ │ │ │ - this.layer.events.on({ │ │ │ │ - featureadded: this.triggerSave, │ │ │ │ - afterfeaturemodified: this.triggerSave, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - if (this.auto) { │ │ │ │ - if (typeof this.auto === "number") { │ │ │ │ - window.clearInterval(this.timer) │ │ │ │ - } else { │ │ │ │ - this.layer.events.un({ │ │ │ │ - featureadded: this.triggerSave, │ │ │ │ - afterfeaturemodified: this.triggerSave, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - triggerSave: function(event) { │ │ │ │ - var feature = event.feature; │ │ │ │ - if (feature.state === OpenLayers.State.INSERT || feature.state === OpenLayers.State.UPDATE || feature.state === OpenLayers.State.DELETE) { │ │ │ │ - this.save([event.feature]) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - save: function(features) { │ │ │ │ - if (!features) { │ │ │ │ - features = this.layer.features │ │ │ │ - } │ │ │ │ - this.events.triggerEvent("start", { │ │ │ │ - features: features │ │ │ │ - }); │ │ │ │ - var remote = this.layer.projection; │ │ │ │ - var local = this.layer.map.getProjectionObject(); │ │ │ │ - if (!local.equals(remote)) { │ │ │ │ - var len = features.length; │ │ │ │ - var clones = new Array(len); │ │ │ │ - var orig, clone; │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ - orig = features[i]; │ │ │ │ - clone = orig.clone(); │ │ │ │ - clone.fid = orig.fid; │ │ │ │ - clone.state = orig.state; │ │ │ │ - if (orig.url) { │ │ │ │ - clone.url = orig.url │ │ │ │ - } │ │ │ │ - clone._original = orig; │ │ │ │ - clone.geometry.transform(local, remote); │ │ │ │ - clones[i] = clone │ │ │ │ - } │ │ │ │ - features = clones │ │ │ │ - } │ │ │ │ - this.layer.protocol.commit(features, { │ │ │ │ - callback: this.onCommit, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - onCommit: function(response) { │ │ │ │ - var evt = { │ │ │ │ - response: response │ │ │ │ - }; │ │ │ │ - if (response.success()) { │ │ │ │ - var features = response.reqFeatures; │ │ │ │ - var state, feature; │ │ │ │ - var destroys = []; │ │ │ │ - var insertIds = response.insertIds || []; │ │ │ │ - var j = 0; │ │ │ │ - for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - feature = feature._original || feature; │ │ │ │ - state = feature.state; │ │ │ │ - if (state) { │ │ │ │ - if (state == OpenLayers.State.DELETE) { │ │ │ │ - destroys.push(feature) │ │ │ │ - } else if (state == OpenLayers.State.INSERT) { │ │ │ │ - feature.fid = insertIds[j]; │ │ │ │ - ++j │ │ │ │ - } │ │ │ │ - feature.state = null │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (destroys.length > 0) { │ │ │ │ - this.layer.destroyFeatures(destroys) │ │ │ │ - } │ │ │ │ - this.events.triggerEvent("success", evt) │ │ │ │ - } else { │ │ │ │ - this.events.triggerEvent("fail", evt) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Save" │ │ │ │ -}); │ │ │ │ -OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - preload: false, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - 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.Strategy.Refresh = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - force: false, │ │ │ │ - interval: 0, │ │ │ │ - timer: null, │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - if (this.layer.visibility === true) { │ │ │ │ - this.start() │ │ │ │ - } │ │ │ │ - this.layer.events.on({ │ │ │ │ - visibilitychanged: this.reset, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.stop(); │ │ │ │ - this.layer.events.un({ │ │ │ │ - visibilitychanged: this.reset, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - reset: function() { │ │ │ │ - if (this.layer.visibility === true) { │ │ │ │ - this.start() │ │ │ │ - } else { │ │ │ │ - this.stop() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - start: function() { │ │ │ │ - if (this.interval && typeof this.interval === "number" && this.interval > 0) { │ │ │ │ - this.timer = window.setInterval(OpenLayers.Function.bind(this.refresh, this), this.interval) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - refresh: function() { │ │ │ │ - if (this.layer && this.layer.refresh && typeof this.layer.refresh == "function") { │ │ │ │ - this.layer.refresh({ │ │ │ │ - force: this.force │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - stop: function() { │ │ │ │ - if (this.timer !== null) { │ │ │ │ - window.clearInterval(this.timer); │ │ │ │ - this.timer = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Refresh" │ │ │ │ -}); │ │ │ │ -OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - features: null, │ │ │ │ - length: 10, │ │ │ │ - num: null, │ │ │ │ - paging: false, │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - beforefeaturesadded: this.cacheFeatures, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.layer.events.un({ │ │ │ │ - beforefeaturesadded: this.cacheFeatures, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - cacheFeatures: function(event) { │ │ │ │ - if (!this.paging) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.features = event.features; │ │ │ │ - this.pageNext(event) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clearCache: function() { │ │ │ │ - if (this.features) { │ │ │ │ - for (var i = 0; i < this.features.length; ++i) { │ │ │ │ - this.features[i].destroy() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.features = null; │ │ │ │ - this.num = null │ │ │ │ - }, │ │ │ │ - pageCount: function() { │ │ │ │ - var numFeatures = this.features ? this.features.length : 0; │ │ │ │ - return Math.ceil(numFeatures / this.length) │ │ │ │ - }, │ │ │ │ - pageNum: function() { │ │ │ │ - return this.num │ │ │ │ - }, │ │ │ │ - pageLength: function(newLength) { │ │ │ │ - if (newLength && newLength > 0) { │ │ │ │ - this.length = newLength │ │ │ │ - } │ │ │ │ - return this.length │ │ │ │ - }, │ │ │ │ - pageNext: function(event) { │ │ │ │ - var changed = false; │ │ │ │ - if (this.features) { │ │ │ │ - if (this.num === null) { │ │ │ │ - this.num = -1 │ │ │ │ - } │ │ │ │ - var start = (this.num + 1) * this.length; │ │ │ │ - changed = this.page(start, event) │ │ │ │ - } │ │ │ │ - return changed │ │ │ │ - }, │ │ │ │ - pagePrevious: function() { │ │ │ │ - var changed = false; │ │ │ │ - if (this.features) { │ │ │ │ - if (this.num === null) { │ │ │ │ - this.num = this.pageCount() │ │ │ │ - } │ │ │ │ - var start = (this.num - 1) * this.length; │ │ │ │ - changed = this.page(start) │ │ │ │ - } │ │ │ │ - return changed │ │ │ │ - }, │ │ │ │ - page: function(start, event) { │ │ │ │ - var changed = false; │ │ │ │ - if (this.features) { │ │ │ │ - if (start >= 0 && start < this.features.length) { │ │ │ │ - var num = Math.floor(start / this.length); │ │ │ │ - if (num != this.num) { │ │ │ │ - this.paging = true; │ │ │ │ - var features = this.features.slice(start, start + this.length); │ │ │ │ - this.layer.removeFeatures(this.layer.features); │ │ │ │ - this.num = num; │ │ │ │ - if (event && event.features) { │ │ │ │ - event.features = features │ │ │ │ - } else { │ │ │ │ - this.layer.addFeatures(features) │ │ │ │ - } │ │ │ │ - this.paging = false; │ │ │ │ - changed = true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return changed │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Paging" │ │ │ │ -}); │ │ │ │ -OpenLayers.Strategy.Filter = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - filter: null, │ │ │ │ - cache: null, │ │ │ │ - caching: false, │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments); │ │ │ │ - if (activated) { │ │ │ │ - this.cache = []; │ │ │ │ - this.layer.events.on({ │ │ │ │ - beforefeaturesadded: this.handleAdd, │ │ │ │ - beforefeaturesremoved: this.handleRemove, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - this.cache = null; │ │ │ │ - if (this.layer && this.layer.events) { │ │ │ │ - this.layer.events.un({ │ │ │ │ - beforefeaturesadded: this.handleAdd, │ │ │ │ - beforefeaturesremoved: this.handleRemove, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return OpenLayers.Strategy.prototype.deactivate.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - handleAdd: function(event) { │ │ │ │ - if (!this.caching && this.filter) { │ │ │ │ - var features = event.features; │ │ │ │ - event.features = []; │ │ │ │ - var feature; │ │ │ │ - for (var i = 0, ii = features.length; i < ii; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - if (this.filter.evaluate(feature)) { │ │ │ │ - event.features.push(feature) │ │ │ │ - } else { │ │ │ │ - this.cache.push(feature) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - handleRemove: function(event) { │ │ │ │ - if (!this.caching) { │ │ │ │ - this.cache = [] │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setFilter: function(filter) { │ │ │ │ - this.filter = filter; │ │ │ │ - var previousCache = this.cache; │ │ │ │ - this.cache = []; │ │ │ │ - this.handleAdd({ │ │ │ │ - features: this.layer.features │ │ │ │ - }); │ │ │ │ - if (this.cache.length > 0) { │ │ │ │ - this.caching = true; │ │ │ │ - this.layer.removeFeatures(this.cache.slice()); │ │ │ │ - this.caching = false │ │ │ │ - } │ │ │ │ - if (previousCache.length > 0) { │ │ │ │ - var event = { │ │ │ │ - features: previousCache │ │ │ │ - }; │ │ │ │ - this.handleAdd(event); │ │ │ │ - if (event.features.length > 0) { │ │ │ │ - this.caching = true; │ │ │ │ - this.layer.addFeatures(event.features); │ │ │ │ - this.caching = false │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Filter" │ │ │ │ -}); │ │ │ │ -OpenLayers.ElementsIndexer = OpenLayers.Class({ │ │ │ │ - maxZIndex: null, │ │ │ │ - order: null, │ │ │ │ - indices: null, │ │ │ │ - compare: null, │ │ │ │ - initialize: function(yOrdering) { │ │ │ │ - this.compare = yOrdering ? OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER : OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER; │ │ │ │ - this.clear() │ │ │ │ - }, │ │ │ │ - insert: function(newNode) { │ │ │ │ - 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); │ │ │ │ - return this.getNextElement(rightIndex) │ │ │ │ - }, │ │ │ │ - remove: function(node) { │ │ │ │ - var nodeId = node.id; │ │ │ │ - var arrayIndex = OpenLayers.Util.indexOf(this.order, nodeId); │ │ │ │ - if (arrayIndex >= 0) { │ │ │ │ - this.order.splice(arrayIndex, 1); │ │ │ │ - delete this.indices[nodeId]; │ │ │ │ - if (this.order.length > 0) { │ │ │ │ - var lastId = this.order[this.order.length - 1]; │ │ │ │ - this.maxZIndex = this.indices[lastId] │ │ │ │ - } else { │ │ │ │ - this.maxZIndex = 0 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clear: function() { │ │ │ │ - this.order = []; │ │ │ │ - this.indices = {}; │ │ │ │ - this.maxZIndex = 0 │ │ │ │ - }, │ │ │ │ - exists: function(node) { │ │ │ │ - return this.indices[node.id] != null │ │ │ │ - }, │ │ │ │ - getZIndex: function(node) { │ │ │ │ - return node._style.graphicZIndex │ │ │ │ - }, │ │ │ │ - determineZIndex: function(node) { │ │ │ │ - var zIndex = node._style.graphicZIndex; │ │ │ │ - if (zIndex == null) { │ │ │ │ - zIndex = this.maxZIndex; │ │ │ │ - node._style.graphicZIndex = zIndex │ │ │ │ - } else if (zIndex > this.maxZIndex) { │ │ │ │ - this.maxZIndex = zIndex │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -OpenLayers.ElementsIndexer.IndexingMethods = { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - Z_ORDER_DRAWING_ORDER: function(indexer, newNode, nextNode) { │ │ │ │ - var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(indexer, newNode, nextNode); │ │ │ │ - if (nextNode && returnVal == 0) { │ │ │ │ - returnVal = 1 │ │ │ │ - } │ │ │ │ - return returnVal │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ - rendererRoot: null, │ │ │ │ - root: null, │ │ │ │ - vectorRoot: null, │ │ │ │ - textRoot: null, │ │ │ │ - xmlns: null, │ │ │ │ - xOffset: 0, │ │ │ │ - indexer: null, │ │ │ │ - BACKGROUND_ID_SUFFIX: "_background", │ │ │ │ - LABEL_ID_SUFFIX: "_label", │ │ │ │ - LABEL_OUTLINE_SUFFIX: "_outline", │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.clear(); │ │ │ │ - this.rendererRoot = null; │ │ │ │ - this.root = null; │ │ │ │ - this.xmlns = null; │ │ │ │ - OpenLayers.Renderer.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - getNodeType: function(geometry, style) {}, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - redrawNode: function(id, geometry, style, featureId) { │ │ │ │ - style = this.applyDefaultSymbolizer(style); │ │ │ │ - var node = this.nodeFactory(id, this.getNodeType(geometry, style)); │ │ │ │ - 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; │ │ │ │ - if (this.indexer) { │ │ │ │ - var insert = this.indexer.insert(node); │ │ │ │ - if (insert) { │ │ │ │ - this.vectorRoot.insertBefore(node, insert) │ │ │ │ - } else { │ │ │ │ - this.vectorRoot.appendChild(node) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (node.parentNode !== this.vectorRoot) { │ │ │ │ - this.vectorRoot.appendChild(node) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.postDraw(node); │ │ │ │ - return drawResult.complete │ │ │ │ - }, │ │ │ │ - redrawBackgroundNode: function(id, geometry, style, featureId) { │ │ │ │ - var backgroundStyle = OpenLayers.Util.extend({}, style); │ │ │ │ - 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; │ │ │ │ - backgroundStyle.backgroundGraphic = null; │ │ │ │ - backgroundStyle.backgroundXOffset = null; │ │ │ │ - backgroundStyle.backgroundYOffset = null; │ │ │ │ - backgroundStyle.backgroundGraphicZIndex = null; │ │ │ │ - return this.redrawNode(id + this.BACKGROUND_ID_SUFFIX, geometry, backgroundStyle, null) │ │ │ │ - }, │ │ │ │ - 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; │ │ │ │ - if (drawn != false) { │ │ │ │ - return { │ │ │ │ - node: this.setStyle(node, style, options, geometry), │ │ │ │ - complete: drawn │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - postDraw: function(node) {}, │ │ │ │ - drawPoint: function(node, geometry) {}, │ │ │ │ - drawLineString: function(node, geometry) {}, │ │ │ │ - drawLinearRing: function(node, geometry) {}, │ │ │ │ - drawPolygon: function(node, geometry) {}, │ │ │ │ - drawRectangle: function(node, geometry) {}, │ │ │ │ - drawCircle: function(node, geometry) {}, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getFeatureIdFromEvent: function(evt) { │ │ │ │ - var target = evt.target; │ │ │ │ - var useElement = target && target.correspondingUseElement; │ │ │ │ - var node = useElement ? useElement : target || evt.srcElement; │ │ │ │ - return node._featureId │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - bElem.parentNode.removeChild(bElem) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - nodeTypeCompare: function(node, type) {}, │ │ │ │ - createNode: function(type, id) {}, │ │ │ │ - moveRoot: function(renderer) { │ │ │ │ - var root = this.root; │ │ │ │ - if (renderer.root.parentNode == this.rendererRoot) { │ │ │ │ - root = renderer.root │ │ │ │ - } │ │ │ │ - root.parentNode.removeChild(root); │ │ │ │ - renderer.rendererRoot.appendChild(root) │ │ │ │ - }, │ │ │ │ - getRenderLayerId: function() { │ │ │ │ - return this.root.parentNode.parentNode.id │ │ │ │ - }, │ │ │ │ - isComplexSymbol: function(graphicName) { │ │ │ │ - return graphicName != "circle" && !!graphicName │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.Elements" │ │ │ │ -}); │ │ │ │ -OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ - xmlns: "http://www.w3.org/2000/svg", │ │ │ │ - xlinkns: "http://www.w3.org/1999/xlink", │ │ │ │ - MAX_PIXEL: 15e3, │ │ │ │ - translationParameters: null, │ │ │ │ - symbolMetrics: null, │ │ │ │ - initialize: function(containerID) { │ │ │ │ - if (!this.supported()) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - OpenLayers.Renderer.Elements.prototype.initialize.apply(this, arguments); │ │ │ │ - this.translationParameters = { │ │ │ │ - x: 0, │ │ │ │ - y: 0 │ │ │ │ - }; │ │ │ │ - this.symbolMetrics = {} │ │ │ │ - }, │ │ │ │ - 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")) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 (resolutionChanged) { │ │ │ │ - this.left = left; │ │ │ │ - this.top = top; │ │ │ │ - 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) { │ │ │ │ - this.setExtent(extent, true) │ │ │ │ - } │ │ │ │ - return coordSysUnchanged && inRange │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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); │ │ │ │ - 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 : -(.5 * width); │ │ │ │ - var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.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)) { │ │ │ │ - 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; │ │ │ │ - var parent = node.parentNode; │ │ │ │ - var nextSibling = node.nextSibling; │ │ │ │ - if (parent) { │ │ │ │ - parent.removeChild(node) │ │ │ │ - } │ │ │ │ - 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); │ │ │ │ - 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"); │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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, ",") │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - createNode: function(type, id) { │ │ │ │ - var node = document.createElementNS(this.xmlns, type); │ │ │ │ - if (id) { │ │ │ │ - node.setAttributeNS(null, "id", id) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - nodeTypeCompare: function(node, type) { │ │ │ │ - return type == node.nodeName │ │ │ │ - }, │ │ │ │ - createRenderRoot: function() { │ │ │ │ - var svg = this.nodeFactory(this.container.id + "_svgRoot", "svg"); │ │ │ │ - svg.style.display = "block"; │ │ │ │ - return svg │ │ │ │ - }, │ │ │ │ - createRoot: function(suffix) { │ │ │ │ - return this.nodeFactory(this.container.id + suffix, "g") │ │ │ │ - }, │ │ │ │ - createDefs: function() { │ │ │ │ - var defs = this.nodeFactory(this.container.id + "_defs", "defs"); │ │ │ │ - this.rendererRoot.appendChild(defs); │ │ │ │ - return defs │ │ │ │ - }, │ │ │ │ - drawPoint: function(node, geometry) { │ │ │ │ - return this.drawCircle(node, geometry, 1) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawText: function(featureId, style, location) { │ │ │ │ - var drawOutline = !!style.labelOutlineWidth; │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 { │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getPosition: function(node) { │ │ │ │ - return { │ │ │ │ - x: parseFloat(node.getAttributeNS(null, "cx")), │ │ │ │ - y: parseFloat(node.getAttributeNS(null, "cy")) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - importSymbol: function(graphicName) { │ │ │ │ - if (!this.defs) { │ │ │ │ - this.defs = this.createDefs() │ │ │ │ - } │ │ │ │ - var id = this.container.id + "-" + graphicName; │ │ │ │ - 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(); │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -OpenLayers.Renderer.SVG.LABEL_ALIGN = { │ │ │ │ - l: "start", │ │ │ │ - r: "end", │ │ │ │ - b: "bottom", │ │ │ │ - t: "hanging" │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.SVG.LABEL_VSHIFT = { │ │ │ │ - t: "-70%", │ │ │ │ - b: "0" │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.SVG.LABEL_VFACTOR = { │ │ │ │ - t: 0, │ │ │ │ - b: -1 │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.SVG.preventDefault = function(e) { │ │ │ │ - OpenLayers.Event.preventDefault(e) │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ - hitDetection: true, │ │ │ │ - hitOverflow: 0, │ │ │ │ - canvas: null, │ │ │ │ - features: null, │ │ │ │ - pendingRedraw: false, │ │ │ │ - cachedSymbolBounds: {}, │ │ │ │ - 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") │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setExtent: function() { │ │ │ │ - OpenLayers.Renderer.prototype.setExtent.apply(this, arguments); │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - eraseGeometry: function(geometry, featureId) { │ │ │ │ - this.eraseFeatures(this.features[featureId][0]) │ │ │ │ - }, │ │ │ │ - supported: function() { │ │ │ │ - return OpenLayers.CANVAS_SUPPORTED │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawFeature: function(feature, style) { │ │ │ │ - var rendered; │ │ │ │ - if (feature.geometry) { │ │ │ │ - style = this.applyDefaultSymbolizer(style || feature.style); │ │ │ │ - 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) { │ │ │ │ - this.features[feature.id] = [feature, style] │ │ │ │ - } else { │ │ │ │ - delete this.features[feature.id] │ │ │ │ - } │ │ │ │ - this.pendingRedraw = true │ │ │ │ - } │ │ │ │ - if (this.pendingRedraw && !this.locked) { │ │ │ │ - this.redraw(); │ │ │ │ - this.pendingRedraw = false │ │ │ │ - } │ │ │ │ - return rendered │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 : -(.5 * width); │ │ │ │ - var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.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 / 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 │ │ │ │ - }, │ │ │ │ - drawNamedSymbol: function(geometry, style, featureId) { │ │ │ │ - var x, y, cx, cy, i, symbolBounds, scaling, angle; │ │ │ │ - var unscaledStrokeWidth; │ │ │ │ - var deg2rad = Math.PI / 180; │ │ │ │ - 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; │ │ │ │ - this.canvas.lineCap = "round"; │ │ │ │ - this.canvas.lineJoin = "round"; │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.lineCap = "round"; │ │ │ │ - this.hitContext.lineJoin = "round" │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - this.canvas.save(); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.save() │ │ │ │ - } │ │ │ │ - this.canvas.translate(p0, p1); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.translate(p0, p1) │ │ │ │ - } │ │ │ │ - angle = deg2rad * style.rotation; │ │ │ │ - if (!isNaN(angle)) { │ │ │ │ - this.canvas.rotate(angle); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.rotate(angle) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - scaling = 2 * style.pointRadius / Math.max(symbolBounds.getWidth(), symbolBounds.getHeight()); │ │ │ │ - this.canvas.scale(scaling, scaling); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.scale(scaling, scaling) │ │ │ │ - } │ │ │ │ - cx = symbolBounds.getCenterLonLat().lon; │ │ │ │ - cy = symbolBounds.getCenterLonLat().lat; │ │ │ │ - this.canvas.translate(-cx, -cy); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.translate(-cx, -cy) │ │ │ │ - } │ │ │ │ - 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") │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - featureIdToHex: function(featureId) { │ │ │ │ - var id = Number(featureId.split("_").pop()) + 1; │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - setHitContextStyle: function(type, featureId, symbolizer, strokeScaling) { │ │ │ │ - var hex = this.featureIdToHex(featureId); │ │ │ │ - if (type == "fill") { │ │ │ │ - this.hitContext.globalAlpha = 1; │ │ │ │ - this.hitContext.fillStyle = hex │ │ │ │ - } else if (type == "stroke") { │ │ │ │ - this.hitContext.globalAlpha = 1; │ │ │ │ - this.hitContext.strokeStyle = hex; │ │ │ │ - if (typeof strokeScaling === "undefined") { │ │ │ │ - this.hitContext.lineWidth = symbolizer.strokeWidth + 2 │ │ │ │ - } else { │ │ │ │ - if (!isNaN(strokeScaling)) { │ │ │ │ - this.hitContext.lineWidth = symbolizer.strokeWidth + 2 / strokeScaling │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.hitContext.globalAlpha = 0; │ │ │ │ - this.hitContext.lineWidth = 1 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawLineString: function(geometry, style, featureId) { │ │ │ │ - style = OpenLayers.Util.applyDefaults({ │ │ │ │ - fill: false │ │ │ │ - }, style); │ │ │ │ - this.drawLinearRing(geometry, style, featureId) │ │ │ │ - }, │ │ │ │ - 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") │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawPolygon: function(geometry, style, featureId) { │ │ │ │ - var components = geometry.components; │ │ │ │ - var len = components.length; │ │ │ │ - this.drawLinearRing(components[0], style, featureId); │ │ │ │ - for (var i = 1; i < len; ++i) { │ │ │ │ - this.canvas.globalCompositeOperation = "destination-out"; │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.globalCompositeOperation = "destination-out" │ │ │ │ - } │ │ │ │ - this.drawLinearRing(components[i], OpenLayers.Util.applyDefaults({ │ │ │ │ - stroke: false, │ │ │ │ - fillOpacity: 1 │ │ │ │ - }, 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawText: function(location, style) { │ │ │ │ - var pt = this.getLocalXY(location); │ │ │ │ - this.setCanvasStyle("reset"); │ │ │ │ - this.canvas.fillStyle = style.fontColor; │ │ │ │ - this.canvas.globalAlpha = style.fontOpacity || 1; │ │ │ │ - var fontStyle = [style.fontStyle ? style.fontStyle : "normal", "normal", 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) { │ │ │ │ - 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; │ │ │ │ - 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) { │ │ │ │ - this.canvas.mozTextStyle = fontStyle; │ │ │ │ - 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") │ │ │ │ - }, │ │ │ │ - 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] │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getFeatureIdFromEvent: function(evt) { │ │ │ │ - var featureId, feature; │ │ │ │ - if (this.hitDetection && this.root.style.display !== "none") { │ │ │ │ - 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) { │ │ │ │ - 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) {} │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return feature │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -OpenLayers.Renderer.Canvas.LABEL_ALIGN = { │ │ │ │ - l: "left", │ │ │ │ - r: "right", │ │ │ │ - t: "top", │ │ │ │ - b: "bottom" │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.Canvas.LABEL_FACTOR = { │ │ │ │ - l: 0, │ │ │ │ - r: -1, │ │ │ │ - t: 0, │ │ │ │ - b: -1 │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.Canvas.drawImageScaleFactor = null; │ │ │ │ -OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ - xmlns: "urn:schemas-microsoft-com:vml", │ │ │ │ - symbolCache: {}, │ │ │ │ - offset: null, │ │ │ │ - initialize: function(containerID) { │ │ │ │ - if (!this.supported()) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - if (!document.namespaces.olv) { │ │ │ │ - document.namespaces.add("olv", this.xmlns); │ │ │ │ - var style = document.createStyleSheet(); │ │ │ │ - var shapes = ["shape", "rect", "oval", "fill", "stroke", "imagedata", "group", "textbox"]; │ │ │ │ - for (var i = 0, len = shapes.length; i < len; i++) { │ │ │ │ - style.addRule("olv\\:" + shapes[i], "behavior: url(#default#VML); " + "position: absolute; display: inline-block;") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - OpenLayers.Renderer.Elements.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - supported: function() { │ │ │ │ - return !!document.namespaces │ │ │ │ - }, │ │ │ │ - setExtent: function(extent, resolutionChanged) { │ │ │ │ - var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments); │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var left = extent.left / resolution | 0; │ │ │ │ - var top = extent.top / resolution - this.size.h | 0; │ │ │ │ - if (resolutionChanged || !this.offset) { │ │ │ │ - this.offset = { │ │ │ │ - x: left, │ │ │ │ - y: top │ │ │ │ - }; │ │ │ │ - left = 0; │ │ │ │ - top = 0 │ │ │ │ - } else { │ │ │ │ - left = left - this.offset.x; │ │ │ │ - top = top - this.offset.y │ │ │ │ - } │ │ │ │ - var org = left - this.xOffset + " " + top; │ │ │ │ - this.root.coordorigin = org; │ │ │ │ - var roots = [this.root, this.vectorRoot, this.textRoot]; │ │ │ │ - var root; │ │ │ │ - for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ - root = roots[i]; │ │ │ │ - var size = this.size.w + " " + this.size.h; │ │ │ │ - root.coordsize = size │ │ │ │ - } │ │ │ │ - this.root.style.flip = "y"; │ │ │ │ - return coordSysUnchanged │ │ │ │ - }, │ │ │ │ - setSize: function(size) { │ │ │ │ - OpenLayers.Renderer.prototype.setSize.apply(this, arguments); │ │ │ │ - var roots = [this.rendererRoot, this.root, this.vectorRoot, this.textRoot]; │ │ │ │ - var w = this.size.w + "px"; │ │ │ │ - var h = this.size.h + "px"; │ │ │ │ - var root; │ │ │ │ - for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ - root = roots[i]; │ │ │ │ - root.style.width = w; │ │ │ │ - root.style.height = h │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getNodeType: function(geometry, style) { │ │ │ │ - var nodeType = null; │ │ │ │ - switch (geometry.CLASS_NAME) { │ │ │ │ - case "OpenLayers.Geometry.Point": │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - nodeType = "olv:rect" │ │ │ │ - } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ - nodeType = "olv:shape" │ │ │ │ - } else { │ │ │ │ - nodeType = "olv:oval" │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "OpenLayers.Geometry.Rectangle": │ │ │ │ - nodeType = "olv:rect"; │ │ │ │ - break; │ │ │ │ - case "OpenLayers.Geometry.LineString": │ │ │ │ - case "OpenLayers.Geometry.LinearRing": │ │ │ │ - case "OpenLayers.Geometry.Polygon": │ │ │ │ - case "OpenLayers.Geometry.Curve": │ │ │ │ - nodeType = "olv:shape"; │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - break │ │ │ │ - } │ │ │ │ - return nodeType │ │ │ │ - }, │ │ │ │ - setStyle: function(node, style, options, geometry) { │ │ │ │ - style = style || node._style; │ │ │ │ - options = options || node._options; │ │ │ │ - var fillColor = style.fillColor; │ │ │ │ - var title = style.title || style.graphicTitle; │ │ │ │ - if (title) { │ │ │ │ - node.title = title │ │ │ │ - } │ │ │ │ - if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - options.isFilled = true; │ │ │ │ - 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 resolution = this.getResolution(); │ │ │ │ - var xOffset = style.graphicXOffset != undefined ? style.graphicXOffset : -(.5 * width); │ │ │ │ - var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.5 * height); │ │ │ │ - node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x + xOffset | 0) + "px"; │ │ │ │ - node.style.top = (geometry.y / resolution - this.offset.y - (yOffset + height) | 0) + "px"; │ │ │ │ - node.style.width = width + "px"; │ │ │ │ - node.style.height = height + "px"; │ │ │ │ - node.style.flip = "y"; │ │ │ │ - fillColor = "none"; │ │ │ │ - options.isStroked = false │ │ │ │ - } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ - var cache = this.importSymbol(style.graphicName); │ │ │ │ - node.path = cache.path; │ │ │ │ - node.coordorigin = cache.left + "," + cache.bottom; │ │ │ │ - var size = cache.size; │ │ │ │ - node.coordsize = size + "," + size; │ │ │ │ - this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ - node.style.flip = "y" │ │ │ │ - } else { │ │ │ │ - this.drawCircle(node, geometry, style.pointRadius) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (options.isFilled) { │ │ │ │ - node.fillcolor = fillColor │ │ │ │ - } else { │ │ │ │ - node.filled = "false" │ │ │ │ - } │ │ │ │ - var fills = node.getElementsByTagName("fill"); │ │ │ │ - var fill = fills.length == 0 ? null : fills[0]; │ │ │ │ - if (!options.isFilled) { │ │ │ │ - if (fill) { │ │ │ │ - node.removeChild(fill) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (!fill) { │ │ │ │ - fill = this.createNode("olv:fill", node.id + "_fill") │ │ │ │ - } │ │ │ │ - fill.opacity = style.fillOpacity; │ │ │ │ - if (node._geometryClass === "OpenLayers.Geometry.Point" && style.externalGraphic) { │ │ │ │ - if (style.graphicOpacity) { │ │ │ │ - fill.opacity = style.graphicOpacity │ │ │ │ - } │ │ │ │ - fill.src = style.externalGraphic; │ │ │ │ - fill.type = "frame"; │ │ │ │ - if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ - fill.aspect = "atmost" │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (fill.parentNode != node) { │ │ │ │ - node.appendChild(fill) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var rotation = style.rotation; │ │ │ │ - if (rotation !== undefined || node._rotation !== undefined) { │ │ │ │ - node._rotation = rotation; │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ - fill.opacity = 0 │ │ │ │ - } else if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ - node.style.rotation = rotation || 0 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var strokes = node.getElementsByTagName("stroke"); │ │ │ │ - var stroke = strokes.length == 0 ? null : strokes[0]; │ │ │ │ - if (!options.isStroked) { │ │ │ │ - node.stroked = false; │ │ │ │ - if (stroke) { │ │ │ │ - stroke.on = false │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (!stroke) { │ │ │ │ - stroke = this.createNode("olv:stroke", node.id + "_stroke"); │ │ │ │ - node.appendChild(stroke) │ │ │ │ - } │ │ │ │ - stroke.on = true; │ │ │ │ - stroke.color = style.strokeColor; │ │ │ │ - stroke.weight = style.strokeWidth + "px"; │ │ │ │ - stroke.opacity = style.strokeOpacity; │ │ │ │ - stroke.endcap = style.strokeLinecap == "butt" ? "flat" : style.strokeLinecap || "round"; │ │ │ │ - if (style.strokeDashstyle) { │ │ │ │ - stroke.dashstyle = this.dashStyle(style) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ - node.style.cursor = style.cursor │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - graphicRotate: function(node, xOffset, yOffset, style) { │ │ │ │ - var style = style || node._style; │ │ │ │ - var rotation = style.rotation || 0; │ │ │ │ - var aspectRatio, size; │ │ │ │ - if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ - var img = new Image; │ │ │ │ - img.onreadystatechange = OpenLayers.Function.bind(function() { │ │ │ │ - if (img.readyState == "complete" || img.readyState == "interactive") { │ │ │ │ - aspectRatio = img.width / img.height; │ │ │ │ - size = Math.max(style.pointRadius * 2, style.graphicWidth || 0, style.graphicHeight || 0); │ │ │ │ - xOffset = xOffset * aspectRatio; │ │ │ │ - style.graphicWidth = size * aspectRatio; │ │ │ │ - style.graphicHeight = size; │ │ │ │ - this.graphicRotate(node, xOffset, yOffset, style) │ │ │ │ - } │ │ │ │ - }, this); │ │ │ │ - img.src = style.externalGraphic; │ │ │ │ - return │ │ │ │ - } else { │ │ │ │ - size = Math.max(style.graphicWidth, style.graphicHeight); │ │ │ │ - aspectRatio = style.graphicWidth / style.graphicHeight │ │ │ │ - } │ │ │ │ - var width = Math.round(style.graphicWidth || size * aspectRatio); │ │ │ │ - var height = Math.round(style.graphicHeight || size); │ │ │ │ - node.style.width = width + "px"; │ │ │ │ - node.style.height = height + "px"; │ │ │ │ - var image = document.getElementById(node.id + "_image"); │ │ │ │ - if (!image) { │ │ │ │ - image = this.createNode("olv:imagedata", node.id + "_image"); │ │ │ │ - node.appendChild(image) │ │ │ │ - } │ │ │ │ - image.style.width = width + "px"; │ │ │ │ - image.style.height = height + "px"; │ │ │ │ - image.src = style.externalGraphic; │ │ │ │ - image.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + "src='', sizingMethod='scale')"; │ │ │ │ - var rot = rotation * Math.PI / 180; │ │ │ │ - var sintheta = Math.sin(rot); │ │ │ │ - var costheta = Math.cos(rot); │ │ │ │ - var filter = "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta + ",M12=" + -sintheta + ",M21=" + sintheta + ",M22=" + costheta + ",SizingMethod='auto expand')\n"; │ │ │ │ - var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ - if (opacity && opacity != 1) { │ │ │ │ - filter += "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + opacity + ")\n" │ │ │ │ - } │ │ │ │ - node.style.filter = filter; │ │ │ │ - var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset); │ │ │ │ - var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry(); │ │ │ │ - imgBox.rotate(style.rotation, centerPoint); │ │ │ │ - var imgBounds = imgBox.getBounds(); │ │ │ │ - node.style.left = Math.round(parseInt(node.style.left) + imgBounds.left) + "px"; │ │ │ │ - node.style.top = Math.round(parseInt(node.style.top) - imgBounds.bottom) + "px" │ │ │ │ - }, │ │ │ │ - postDraw: function(node) { │ │ │ │ - node.style.visibility = "visible"; │ │ │ │ - var fillColor = node._style.fillColor; │ │ │ │ - var strokeColor = node._style.strokeColor; │ │ │ │ - if (fillColor == "none" && node.fillcolor != fillColor) { │ │ │ │ - node.fillcolor = fillColor │ │ │ │ - } │ │ │ │ - if (strokeColor == "none" && node.strokecolor != strokeColor) { │ │ │ │ - node.strokecolor = strokeColor │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setNodeDimension: function(node, geometry) { │ │ │ │ - var bbox = geometry.getBounds(); │ │ │ │ - if (bbox) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var scaledBox = new OpenLayers.Bounds((bbox.left - this.featureDx) / resolution - this.offset.x | 0, bbox.bottom / resolution - this.offset.y | 0, (bbox.right - this.featureDx) / resolution - this.offset.x | 0, bbox.top / resolution - this.offset.y | 0); │ │ │ │ - node.style.left = scaledBox.left + "px"; │ │ │ │ - node.style.top = scaledBox.top + "px"; │ │ │ │ - node.style.width = scaledBox.getWidth() + "px"; │ │ │ │ - node.style.height = scaledBox.getHeight() + "px"; │ │ │ │ - node.coordorigin = scaledBox.left + " " + scaledBox.top; │ │ │ │ - node.coordsize = scaledBox.getWidth() + " " + scaledBox.getHeight() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - dashStyle: function(style) { │ │ │ │ - var dash = style.strokeDashstyle; │ │ │ │ - switch (dash) { │ │ │ │ - case "solid": │ │ │ │ - case "dot": │ │ │ │ - case "dash": │ │ │ │ - case "dashdot": │ │ │ │ - case "longdash": │ │ │ │ - case "longdashdot": │ │ │ │ - return dash; │ │ │ │ - default: │ │ │ │ - var parts = dash.split(/[ ,]/); │ │ │ │ - if (parts.length == 2) { │ │ │ │ - if (1 * parts[0] >= 2 * parts[1]) { │ │ │ │ - return "longdash" │ │ │ │ + if (feat.state === OpenLayers.State.INSERT) { │ │ │ │ + destroys.push(feat) │ │ │ │ + } else { │ │ │ │ + feat.state = OpenLayers.State.DELETE; │ │ │ │ + this.layer.drawFeature(feat) │ │ │ │ + } │ │ │ │ } │ │ │ │ - return parts[0] == 1 || parts[1] == 1 ? "dot" : "dash" │ │ │ │ - } else if (parts.length == 4) { │ │ │ │ - return 1 * parts[0] >= 2 * parts[1] ? "longdashdot" : "dashdot" │ │ │ │ + this.layer.destroyFeatures(destroys, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + for (var i = 0, len = additions.length; i < len; ++i) { │ │ │ │ + additions[i].state = OpenLayers.State.INSERT │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.layer.destroyFeatures(removals, { │ │ │ │ + silent: true │ │ │ │ + }) │ │ │ │ } │ │ │ │ - return "solid" │ │ │ │ + this.layer.addFeatures(additions, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + this.events.triggerEvent("aftersplit", { │ │ │ │ + source: feature, │ │ │ │ + features: additions │ │ │ │ + }) │ │ │ │ + } │ │ │ │ } │ │ │ │ + return sourceSplit │ │ │ │ }, │ │ │ │ - createNode: function(type, id) { │ │ │ │ - var node = document.createElement(type); │ │ │ │ - if (id) { │ │ │ │ - node.id = id │ │ │ │ + geomsToFeatures: function(feature, geoms) { │ │ │ │ + var clone = feature.clone(); │ │ │ │ + delete clone.geometry; │ │ │ │ + var newFeature; │ │ │ │ + for (var i = 0, len = geoms.length; i < len; ++i) { │ │ │ │ + newFeature = clone.clone(); │ │ │ │ + newFeature.geometry = geoms[i]; │ │ │ │ + newFeature.state = OpenLayers.State.INSERT; │ │ │ │ + geoms[i] = newFeature │ │ │ │ } │ │ │ │ - node.unselectable = "on"; │ │ │ │ - node.onselectstart = OpenLayers.Function.False; │ │ │ │ - return node │ │ │ │ }, │ │ │ │ - nodeTypeCompare: function(node, type) { │ │ │ │ - var subType = type; │ │ │ │ - var splitIndex = subType.indexOf(":"); │ │ │ │ - if (splitIndex != -1) { │ │ │ │ - subType = subType.substr(splitIndex + 1) │ │ │ │ - } │ │ │ │ - var nodeName = node.nodeName; │ │ │ │ - splitIndex = nodeName.indexOf(":"); │ │ │ │ - if (splitIndex != -1) { │ │ │ │ - nodeName = nodeName.substr(splitIndex + 1) │ │ │ │ + destroy: function() { │ │ │ │ + if (this.active) { │ │ │ │ + this.deactivate() │ │ │ │ } │ │ │ │ - return subType == nodeName │ │ │ │ + OpenLayers.Control.prototype.destroy.call(this) │ │ │ │ }, │ │ │ │ - createRenderRoot: function() { │ │ │ │ - return this.nodeFactory(this.container.id + "_vmlRoot", "div") │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Split" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.NavigationHistory = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + type: OpenLayers.Control.TYPE_TOGGLE, │ │ │ │ + previous: null, │ │ │ │ + previousOptions: null, │ │ │ │ + next: null, │ │ │ │ + nextOptions: null, │ │ │ │ + limit: 50, │ │ │ │ + autoActivate: true, │ │ │ │ + clearOnDeactivate: false, │ │ │ │ + registry: null, │ │ │ │ + nextStack: null, │ │ │ │ + previousStack: null, │ │ │ │ + listeners: null, │ │ │ │ + restoring: false, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.registry = OpenLayers.Util.extend({ │ │ │ │ + moveend: this.getState │ │ │ │ + }, this.registry); │ │ │ │ + var previousOptions = { │ │ │ │ + trigger: OpenLayers.Function.bind(this.previousTrigger, this), │ │ │ │ + displayClass: this.displayClass + " " + this.displayClass + "Previous" │ │ │ │ + }; │ │ │ │ + OpenLayers.Util.extend(previousOptions, this.previousOptions); │ │ │ │ + this.previous = new OpenLayers.Control.Button(previousOptions); │ │ │ │ + var nextOptions = { │ │ │ │ + trigger: OpenLayers.Function.bind(this.nextTrigger, this), │ │ │ │ + displayClass: this.displayClass + " " + this.displayClass + "Next" │ │ │ │ + }; │ │ │ │ + OpenLayers.Util.extend(nextOptions, this.nextOptions); │ │ │ │ + this.next = new OpenLayers.Control.Button(nextOptions); │ │ │ │ + this.clear() │ │ │ │ }, │ │ │ │ - createRoot: function(suffix) { │ │ │ │ - return this.nodeFactory(this.container.id + suffix, "olv:group") │ │ │ │ + onPreviousChange: function(state, length) { │ │ │ │ + if (state && !this.previous.active) { │ │ │ │ + this.previous.activate() │ │ │ │ + } else if (!state && this.previous.active) { │ │ │ │ + this.previous.deactivate() │ │ │ │ + } │ │ │ │ }, │ │ │ │ - drawPoint: function(node, geometry) { │ │ │ │ - return this.drawCircle(node, geometry, 1) │ │ │ │ + onNextChange: function(state, length) { │ │ │ │ + if (state && !this.next.active) { │ │ │ │ + this.next.activate() │ │ │ │ + } else if (!state && this.next.active) { │ │ │ │ + this.next.deactivate() │ │ │ │ + } │ │ │ │ }, │ │ │ │ - drawCircle: function(node, geometry, radius) { │ │ │ │ - if (!isNaN(geometry.x) && !isNaN(geometry.y)) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x | 0) - radius + "px"; │ │ │ │ - node.style.top = (geometry.y / resolution - this.offset.y | 0) - radius + "px"; │ │ │ │ - var diameter = radius * 2; │ │ │ │ - node.style.width = diameter + "px"; │ │ │ │ - node.style.height = diameter + "px"; │ │ │ │ - return node │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this); │ │ │ │ + this.previous.destroy(); │ │ │ │ + this.next.destroy(); │ │ │ │ + this.deactivate(); │ │ │ │ + for (var prop in this) { │ │ │ │ + this[prop] = null │ │ │ │ } │ │ │ │ - return false │ │ │ │ }, │ │ │ │ - drawLineString: function(node, geometry) { │ │ │ │ - return this.drawLine(node, geometry, false) │ │ │ │ + setMap: function(map) { │ │ │ │ + this.map = map; │ │ │ │ + this.next.setMap(map); │ │ │ │ + this.previous.setMap(map) │ │ │ │ }, │ │ │ │ - drawLinearRing: function(node, geometry) { │ │ │ │ - return this.drawLine(node, geometry, true) │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + this.next.draw(); │ │ │ │ + this.previous.draw() │ │ │ │ }, │ │ │ │ - drawLine: function(node, geometry, closeLine) { │ │ │ │ - this.setNodeDimension(node, geometry); │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var numComponents = geometry.components.length; │ │ │ │ - var parts = new Array(numComponents); │ │ │ │ - var comp, x, y; │ │ │ │ - for (var i = 0; i < numComponents; i++) { │ │ │ │ - comp = geometry.components[i]; │ │ │ │ - x = (comp.x - this.featureDx) / resolution - this.offset.x | 0; │ │ │ │ - y = comp.y / resolution - this.offset.y | 0; │ │ │ │ - parts[i] = " " + x + "," + y + " l " │ │ │ │ + previousTrigger: function() { │ │ │ │ + var current = this.previousStack.shift(); │ │ │ │ + var state = this.previousStack.shift(); │ │ │ │ + if (state != undefined) { │ │ │ │ + this.nextStack.unshift(current); │ │ │ │ + this.previousStack.unshift(state); │ │ │ │ + this.restoring = true; │ │ │ │ + this.restore(state); │ │ │ │ + this.restoring = false; │ │ │ │ + this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ + this.onPreviousChange(this.previousStack[1], this.previousStack.length - 1) │ │ │ │ + } else { │ │ │ │ + this.previousStack.unshift(current) │ │ │ │ } │ │ │ │ - var end = closeLine ? " x e" : " e"; │ │ │ │ - node.path = "m" + parts.join("") + end; │ │ │ │ - return node │ │ │ │ + return state │ │ │ │ }, │ │ │ │ - drawPolygon: function(node, geometry) { │ │ │ │ - this.setNodeDimension(node, geometry); │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var path = []; │ │ │ │ - var j, jj, points, area, first, second, i, ii, comp, pathComp, x, y; │ │ │ │ - for (j = 0, jj = geometry.components.length; j < jj; j++) { │ │ │ │ - path.push("m"); │ │ │ │ - points = geometry.components[j].components; │ │ │ │ - area = j === 0; │ │ │ │ - first = null; │ │ │ │ - second = null; │ │ │ │ - for (i = 0, ii = points.length; i < ii; i++) { │ │ │ │ - comp = points[i]; │ │ │ │ - x = (comp.x - this.featureDx) / resolution - this.offset.x | 0; │ │ │ │ - y = comp.y / resolution - this.offset.y | 0; │ │ │ │ - pathComp = " " + x + "," + y; │ │ │ │ - path.push(pathComp); │ │ │ │ - if (i == 0) { │ │ │ │ - path.push(" l") │ │ │ │ - } │ │ │ │ - if (!area) { │ │ │ │ - if (!first) { │ │ │ │ - first = pathComp │ │ │ │ - } else if (first != pathComp) { │ │ │ │ - if (!second) { │ │ │ │ - second = pathComp │ │ │ │ - } else if (second != pathComp) { │ │ │ │ - area = true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - path.push(area ? " x " : " ") │ │ │ │ + nextTrigger: function() { │ │ │ │ + var state = this.nextStack.shift(); │ │ │ │ + if (state != undefined) { │ │ │ │ + this.previousStack.unshift(state); │ │ │ │ + this.restoring = true; │ │ │ │ + this.restore(state); │ │ │ │ + this.restoring = false; │ │ │ │ + this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ + this.onPreviousChange(this.previousStack[1], this.previousStack.length - 1) │ │ │ │ } │ │ │ │ - path.push("e"); │ │ │ │ - node.path = path.join(""); │ │ │ │ - return node │ │ │ │ + return state │ │ │ │ }, │ │ │ │ - drawRectangle: function(node, geometry) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x | 0) + "px"; │ │ │ │ - node.style.top = (geometry.y / resolution - this.offset.y | 0) + "px"; │ │ │ │ - node.style.width = (geometry.width / resolution | 0) + "px"; │ │ │ │ - node.style.height = (geometry.height / resolution | 0) + "px"; │ │ │ │ - return node │ │ │ │ + clear: function() { │ │ │ │ + this.previousStack = []; │ │ │ │ + this.previous.deactivate(); │ │ │ │ + this.nextStack = []; │ │ │ │ + this.next.deactivate() │ │ │ │ }, │ │ │ │ - drawText: function(featureId, style, location) { │ │ │ │ - var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect"); │ │ │ │ - var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox"); │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - label.style.left = ((location.x - this.featureDx) / resolution - this.offset.x | 0) + "px"; │ │ │ │ - label.style.top = (location.y / resolution - this.offset.y | 0) + "px"; │ │ │ │ - label.style.flip = "y"; │ │ │ │ - textbox.innerText = style.label; │ │ │ │ - if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ - textbox.style.cursor = style.cursor │ │ │ │ - } │ │ │ │ - if (style.fontColor) { │ │ │ │ - textbox.style.color = style.fontColor │ │ │ │ - } │ │ │ │ - if (style.fontOpacity) { │ │ │ │ - textbox.style.filter = "alpha(opacity=" + style.fontOpacity * 100 + ")" │ │ │ │ - } │ │ │ │ - if (style.fontFamily) { │ │ │ │ - textbox.style.fontFamily = style.fontFamily │ │ │ │ - } │ │ │ │ - if (style.fontSize) { │ │ │ │ - textbox.style.fontSize = style.fontSize │ │ │ │ - } │ │ │ │ - if (style.fontWeight) { │ │ │ │ - textbox.style.fontWeight = style.fontWeight │ │ │ │ - } │ │ │ │ - if (style.fontStyle) { │ │ │ │ - textbox.style.fontStyle = style.fontStyle │ │ │ │ - } │ │ │ │ - if (style.labelSelect === true) { │ │ │ │ - label._featureId = featureId; │ │ │ │ - textbox._featureId = featureId; │ │ │ │ - textbox._geometry = location; │ │ │ │ - textbox._geometryClass = location.CLASS_NAME │ │ │ │ - } │ │ │ │ - textbox.style.whiteSpace = "nowrap"; │ │ │ │ - textbox.inset = "1px,0px,0px,0px"; │ │ │ │ - if (!label.parentNode) { │ │ │ │ - label.appendChild(textbox); │ │ │ │ - this.textRoot.appendChild(label) │ │ │ │ + getState: function() { │ │ │ │ + return { │ │ │ │ + center: this.map.getCenter(), │ │ │ │ + resolution: this.map.getResolution(), │ │ │ │ + projection: this.map.getProjectionObject(), │ │ │ │ + units: this.map.getProjectionObject().getUnits() || this.map.units || this.map.baseLayer.units │ │ │ │ } │ │ │ │ - var align = style.labelAlign || "cm"; │ │ │ │ - if (align.length == 1) { │ │ │ │ - align += "m" │ │ │ │ + }, │ │ │ │ + restore: function(state) { │ │ │ │ + var center, zoom; │ │ │ │ + if (this.map.getProjectionObject() == state.projection) { │ │ │ │ + zoom = this.map.getZoomForResolution(state.resolution); │ │ │ │ + center = state.center │ │ │ │ + } else { │ │ │ │ + center = state.center.clone(); │ │ │ │ + center.transform(state.projection, this.map.getProjectionObject()); │ │ │ │ + var sourceUnits = state.units; │ │ │ │ + var targetUnits = this.map.getProjectionObject().getUnits() || this.map.units || this.map.baseLayer.units; │ │ │ │ + var resolutionFactor = sourceUnits && targetUnits ? OpenLayers.INCHES_PER_UNIT[sourceUnits] / OpenLayers.INCHES_PER_UNIT[targetUnits] : 1; │ │ │ │ + zoom = this.map.getZoomForResolution(resolutionFactor * state.resolution) │ │ │ │ } │ │ │ │ - var xshift = textbox.clientWidth * OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0, 1)]; │ │ │ │ - var yshift = textbox.clientHeight * OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1, 1)]; │ │ │ │ - label.style.left = parseInt(label.style.left) - xshift - 1 + "px"; │ │ │ │ - label.style.top = parseInt(label.style.top) + yshift + "px" │ │ │ │ + this.map.setCenter(center, zoom) │ │ │ │ }, │ │ │ │ - moveRoot: function(renderer) { │ │ │ │ - var layer = this.map.getLayer(renderer.container.id); │ │ │ │ - if (layer instanceof OpenLayers.Layer.Vector.RootContainer) { │ │ │ │ - layer = this.map.getLayer(this.container.id) │ │ │ │ + setListeners: function() { │ │ │ │ + this.listeners = {}; │ │ │ │ + for (var type in this.registry) { │ │ │ │ + this.listeners[type] = OpenLayers.Function.bind(function() { │ │ │ │ + if (!this.restoring) { │ │ │ │ + var state = this.registry[type].apply(this, arguments); │ │ │ │ + this.previousStack.unshift(state); │ │ │ │ + if (this.previousStack.length > 1) { │ │ │ │ + this.onPreviousChange(this.previousStack[1], this.previousStack.length - 1) │ │ │ │ + } │ │ │ │ + if (this.previousStack.length > this.limit + 1) { │ │ │ │ + this.previousStack.pop() │ │ │ │ + } │ │ │ │ + if (this.nextStack.length > 0) { │ │ │ │ + this.nextStack = []; │ │ │ │ + this.onNextChange(null, 0) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return true │ │ │ │ + }, this) │ │ │ │ } │ │ │ │ - layer && layer.renderer.clear(); │ │ │ │ - OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments); │ │ │ │ - layer && layer.redraw() │ │ │ │ }, │ │ │ │ - importSymbol: function(graphicName) { │ │ │ │ - var id = this.container.id + "-" + graphicName; │ │ │ │ - var cache = this.symbolCache[id]; │ │ │ │ - if (cache) { │ │ │ │ - return cache │ │ │ │ + activate: function() { │ │ │ │ + var activated = false; │ │ │ │ + if (this.map) { │ │ │ │ + if (OpenLayers.Control.prototype.activate.apply(this)) { │ │ │ │ + if (this.listeners == null) { │ │ │ │ + this.setListeners() │ │ │ │ + } │ │ │ │ + for (var type in this.listeners) { │ │ │ │ + this.map.events.register(type, this, this.listeners[type]) │ │ │ │ + } │ │ │ │ + activated = true; │ │ │ │ + if (this.previousStack.length == 0) { │ │ │ │ + this.initStack() │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - var symbol = OpenLayers.Renderer.symbol[graphicName]; │ │ │ │ - if (!symbol) { │ │ │ │ - throw new Error(graphicName + " is not a valid symbol name") │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + initStack: function() { │ │ │ │ + if (this.map.getCenter()) { │ │ │ │ + this.listeners.moveend() │ │ │ │ } │ │ │ │ - var symbolExtent = new OpenLayers.Bounds(Number.MAX_VALUE, Number.MAX_VALUE, 0, 0); │ │ │ │ - var pathitems = ["m"]; │ │ │ │ - for (var i = 0; i < symbol.length; i = i + 2) { │ │ │ │ - var x = symbol[i]; │ │ │ │ - var 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); │ │ │ │ - pathitems.push(x); │ │ │ │ - pathitems.push(y); │ │ │ │ - if (i == 0) { │ │ │ │ - pathitems.push("l") │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = false; │ │ │ │ + if (this.map) { │ │ │ │ + if (OpenLayers.Control.prototype.deactivate.apply(this)) { │ │ │ │ + for (var type in this.listeners) { │ │ │ │ + this.map.events.unregister(type, this, this.listeners[type]) │ │ │ │ + } │ │ │ │ + if (this.clearOnDeactivate) { │ │ │ │ + this.clear() │ │ │ │ + } │ │ │ │ + deactivated = true │ │ │ │ } │ │ │ │ } │ │ │ │ - pathitems.push("x e"); │ │ │ │ - var path = pathitems.join(" "); │ │ │ │ - var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2; │ │ │ │ - if (diff > 0) { │ │ │ │ - symbolExtent.bottom = symbolExtent.bottom - diff; │ │ │ │ - symbolExtent.top = symbolExtent.top + diff │ │ │ │ - } else { │ │ │ │ - symbolExtent.left = symbolExtent.left + diff; │ │ │ │ - symbolExtent.right = symbolExtent.right - diff │ │ │ │ - } │ │ │ │ - cache = { │ │ │ │ - path: path, │ │ │ │ - size: symbolExtent.getWidth(), │ │ │ │ - left: symbolExtent.left, │ │ │ │ - bottom: symbolExtent.bottom │ │ │ │ - }; │ │ │ │ - this.symbolCache[id] = cache; │ │ │ │ - return cache │ │ │ │ + return deactivated │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.VML" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.NavigationHistory" │ │ │ │ }); │ │ │ │ -OpenLayers.Renderer.VML.LABEL_SHIFT = { │ │ │ │ - l: 0, │ │ │ │ - c: .5, │ │ │ │ - r: 1, │ │ │ │ - t: 0, │ │ │ │ - m: .5, │ │ │ │ - b: 1 │ │ │ │ -}; │ │ │ │ -OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, { │ │ │ │ - bounds: null, │ │ │ │ - div: null, │ │ │ │ - initialize: function(bounds, borderColor, borderWidth) { │ │ │ │ - this.bounds = bounds; │ │ │ │ - this.div = OpenLayers.Util.createDiv(); │ │ │ │ - this.div.style.overflow = "hidden"; │ │ │ │ - this.events = new OpenLayers.Events(this, this.div); │ │ │ │ - this.setBorder(borderColor, borderWidth) │ │ │ │ +OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + layers: null, │ │ │ │ + imageFormat: "image/png", │ │ │ │ + quotaRegEx: /quota/i, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + var i, layers = this.layers || map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.addLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + if (!this.layers) { │ │ │ │ + map.events.on({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - this.bounds = null; │ │ │ │ - this.div = null; │ │ │ │ - OpenLayers.Marker.prototype.destroy.apply(this, arguments) │ │ │ │ + addLayer: function(evt) { │ │ │ │ + evt.layer.events.on({ │ │ │ │ + tileloadstart: this.makeSameOrigin, │ │ │ │ + tileloaded: this.onTileLoaded, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - setBorder: function(color, width) { │ │ │ │ - if (!color) { │ │ │ │ - color = "red" │ │ │ │ + removeLayer: function(evt) { │ │ │ │ + evt.layer.events.un({ │ │ │ │ + tileloadstart: this.makeSameOrigin, │ │ │ │ + tileloaded: this.onTileLoaded, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + makeSameOrigin: function(evt) { │ │ │ │ + if (this.active) { │ │ │ │ + var tile = evt.tile; │ │ │ │ + if (tile instanceof OpenLayers.Tile.Image && !tile.crossOriginKeyword && tile.url.substr(0, 5) !== "data:") { │ │ │ │ + var sameOriginUrl = OpenLayers.Request.makeSameOrigin(tile.url, OpenLayers.ProxyHost); │ │ │ │ + OpenLayers.Control.CacheWrite.urlMap[sameOriginUrl] = tile.url; │ │ │ │ + tile.url = sameOriginUrl │ │ │ │ + } │ │ │ │ } │ │ │ │ - if (!width) { │ │ │ │ - width = 2 │ │ │ │ + }, │ │ │ │ + onTileLoaded: function(evt) { │ │ │ │ + if (this.active && !evt.aborted && evt.tile instanceof OpenLayers.Tile.Image && evt.tile.url.substr(0, 5) !== "data:") { │ │ │ │ + this.cache({ │ │ │ │ + tile: evt.tile │ │ │ │ + }); │ │ │ │ + delete OpenLayers.Control.CacheWrite.urlMap[evt.tile.url] │ │ │ │ } │ │ │ │ - this.div.style.border = width + "px solid " + color │ │ │ │ }, │ │ │ │ - draw: function(px, sz) { │ │ │ │ - OpenLayers.Util.modifyDOMElement(this.div, null, px, sz); │ │ │ │ - return this.div │ │ │ │ + cache: function(obj) { │ │ │ │ + if (window.localStorage) { │ │ │ │ + var tile = obj.tile; │ │ │ │ + try { │ │ │ │ + var canvasContext = tile.getCanvasContext(); │ │ │ │ + if (canvasContext) { │ │ │ │ + var urlMap = OpenLayers.Control.CacheWrite.urlMap; │ │ │ │ + var url = urlMap[tile.url] || tile.url; │ │ │ │ + window.localStorage.setItem("olCache_" + url, canvasContext.canvas.toDataURL(this.imageFormat)) │ │ │ │ + } │ │ │ │ + } catch (e) { │ │ │ │ + var reason = e.name || e.message; │ │ │ │ + if (reason && this.quotaRegEx.test(reason)) { │ │ │ │ + this.events.triggerEvent("cachefull", { │ │ │ │ + tile: tile │ │ │ │ + }) │ │ │ │ + } else { │ │ │ │ + OpenLayers.Console.error(e.toString()) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ - onScreen: function() { │ │ │ │ - var onScreen = false; │ │ │ │ + destroy: function() { │ │ │ │ + if (this.layers || this.map) { │ │ │ │ + var i, layers = this.layers || this.map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.removeLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ if (this.map) { │ │ │ │ - var screenBounds = this.map.getExtent(); │ │ │ │ - onScreen = screenBounds.containsBounds(this.bounds, true, true) │ │ │ │ + this.map.events.un({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ } │ │ │ │ - return onScreen │ │ │ │ - }, │ │ │ │ - display: function(display) { │ │ │ │ - this.div.style.display = display ? "" : "none" │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Marker.Box" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.CacheWrite" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.QueryStringFilter = function() { │ │ │ │ - var cmpToStr = {}; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.EQUAL_TO] = "eq"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.NOT_EQUAL_TO] = "ne"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN] = "lt"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO] = "lte"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN] = "gt"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO] = "gte"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.LIKE] = "ilike"; │ │ │ │ - │ │ │ │ - function regex2value(value) { │ │ │ │ - value = value.replace(/%/g, "\\%"); │ │ │ │ - value = value.replace(/\\\\\.(\*)?/g, function($0, $1) { │ │ │ │ - return $1 ? $0 : "\\\\_" │ │ │ │ - }); │ │ │ │ - value = value.replace(/\\\\\.\*/g, "\\\\%"); │ │ │ │ - value = value.replace(/(\\)?\.(\*)?/g, function($0, $1, $2) { │ │ │ │ - return $1 || $2 ? $0 : "_" │ │ │ │ - }); │ │ │ │ - value = value.replace(/(\\)?\.\*/g, function($0, $1) { │ │ │ │ - return $1 ? $0 : "%" │ │ │ │ - }); │ │ │ │ - value = value.replace(/\\\./g, "."); │ │ │ │ - value = value.replace(/(\\)?\\\*/g, function($0, $1) { │ │ │ │ - return $1 ? $0 : "*" │ │ │ │ - }); │ │ │ │ - return value │ │ │ │ +OpenLayers.Control.CacheWrite.clearCache = function() { │ │ │ │ + if (!window.localStorage) { │ │ │ │ + return │ │ │ │ } │ │ │ │ - return OpenLayers.Class(OpenLayers.Format, { │ │ │ │ - wildcarded: false, │ │ │ │ - srsInBBOX: false, │ │ │ │ - write: function(filter, params) { │ │ │ │ - params = params || {}; │ │ │ │ - var className = filter.CLASS_NAME; │ │ │ │ - var filterType = className.substring(className.lastIndexOf(".") + 1); │ │ │ │ - switch (filterType) { │ │ │ │ - case "Spatial": │ │ │ │ - switch (filter.type) { │ │ │ │ - case OpenLayers.Filter.Spatial.BBOX: │ │ │ │ - params.bbox = filter.value.toArray(); │ │ │ │ - if (this.srsInBBOX && filter.projection) { │ │ │ │ - params.bbox.push(filter.projection.getCode()) │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case OpenLayers.Filter.Spatial.DWITHIN: │ │ │ │ - params.tolerance = filter.distance; │ │ │ │ - case OpenLayers.Filter.Spatial.WITHIN: │ │ │ │ - params.lon = filter.value.x; │ │ │ │ - params.lat = filter.value.y; │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - OpenLayers.Console.warn("Unknown spatial filter type " + filter.type) │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "Comparison": │ │ │ │ - var op = cmpToStr[filter.type]; │ │ │ │ - if (op !== undefined) { │ │ │ │ - var value = filter.value; │ │ │ │ - if (filter.type == OpenLayers.Filter.Comparison.LIKE) { │ │ │ │ - value = regex2value(value); │ │ │ │ - if (this.wildcarded) { │ │ │ │ - value = "%" + value + "%" │ │ │ │ - } │ │ │ │ - } │ │ │ │ - params[filter.property + "__" + op] = value; │ │ │ │ - params.queryable = params.queryable || []; │ │ │ │ - params.queryable.push(filter.property) │ │ │ │ - } else { │ │ │ │ - OpenLayers.Console.warn("Unknown comparison filter type " + filter.type) │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "Logical": │ │ │ │ - if (filter.type === OpenLayers.Filter.Logical.AND) { │ │ │ │ - for (var i = 0, len = filter.filters.length; i < len; i++) { │ │ │ │ - params = this.write(filter.filters[i], params) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Console.warn("Unsupported logical filter type " + filter.type) │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - OpenLayers.Console.warn("Unknown filter type " + filterType) │ │ │ │ - } │ │ │ │ - return params │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.QueryStringFilter" │ │ │ │ - }) │ │ │ │ -}(); │ │ │ │ + var i, key; │ │ │ │ + for (i = window.localStorage.length - 1; i >= 0; --i) { │ │ │ │ + key = window.localStorage.key(i); │ │ │ │ + if (key.substr(0, 8) === "olCache_") { │ │ │ │ + window.localStorage.removeItem(key) │ │ │ │ + } │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.Control.CacheWrite.urlMap = {}; │ │ │ │ OpenLayers.Format.WFSDescribeFeatureType = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ regExes: { │ │ │ │ trimSpace: /^\s*|\s*$/g │ │ │ │ }, │ │ │ │ namespaces: { │ │ │ │ xsd: "http://www.w3.org/2001/XMLSchema" │ │ │ │ }, │ │ │ │ @@ -30362,256 +31103,14 @@ │ │ │ │ } else { │ │ │ │ this.readNode(data, schema) │ │ │ │ } │ │ │ │ return schema │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.WFSDescribeFeatureType" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.WFS = OpenLayers.Class(OpenLayers.Format.GML, { │ │ │ │ - layer: null, │ │ │ │ - wfsns: "http://www.opengis.net/wfs", │ │ │ │ - ogcns: "http://www.opengis.net/ogc", │ │ │ │ - initialize: function(options, layer) { │ │ │ │ - OpenLayers.Format.GML.prototype.initialize.apply(this, [options]); │ │ │ │ - this.layer = layer; │ │ │ │ - if (this.layer.featureNS) { │ │ │ │ - this.featureNS = this.layer.featureNS │ │ │ │ - } │ │ │ │ - if (this.layer.options.geometry_column) { │ │ │ │ - this.geometryName = this.layer.options.geometry_column │ │ │ │ - } │ │ │ │ - if (this.layer.options.typename) { │ │ │ │ - this.featureName = this.layer.options.typename │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - write: function(features) { │ │ │ │ - var transaction = this.createElementNS(this.wfsns, "wfs:Transaction"); │ │ │ │ - transaction.setAttribute("version", "1.0.0"); │ │ │ │ - transaction.setAttribute("service", "WFS"); │ │ │ │ - for (var i = 0; i < features.length; i++) { │ │ │ │ - switch (features[i].state) { │ │ │ │ - case OpenLayers.State.INSERT: │ │ │ │ - transaction.appendChild(this.insert(features[i])); │ │ │ │ - break; │ │ │ │ - case OpenLayers.State.UPDATE: │ │ │ │ - transaction.appendChild(this.update(features[i])); │ │ │ │ - break; │ │ │ │ - case OpenLayers.State.DELETE: │ │ │ │ - transaction.appendChild(this.remove(features[i])); │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [transaction]) │ │ │ │ - }, │ │ │ │ - createFeatureXML: function(feature) { │ │ │ │ - var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ - var geomContainer = this.createElementNS(this.featureNS, "feature:" + this.geometryName); │ │ │ │ - geomContainer.appendChild(geometryNode); │ │ │ │ - var featureContainer = this.createElementNS(this.featureNS, "feature:" + this.featureName); │ │ │ │ - featureContainer.appendChild(geomContainer); │ │ │ │ - for (var attr in feature.attributes) { │ │ │ │ - var attrText = this.createTextNode(feature.attributes[attr]); │ │ │ │ - var nodename = attr; │ │ │ │ - if (attr.search(":") != -1) { │ │ │ │ - nodename = attr.split(":")[1] │ │ │ │ - } │ │ │ │ - var attrContainer = this.createElementNS(this.featureNS, "feature:" + nodename); │ │ │ │ - attrContainer.appendChild(attrText); │ │ │ │ - featureContainer.appendChild(attrContainer) │ │ │ │ - } │ │ │ │ - return featureContainer │ │ │ │ - }, │ │ │ │ - insert: function(feature) { │ │ │ │ - var insertNode = this.createElementNS(this.wfsns, "wfs:Insert"); │ │ │ │ - insertNode.appendChild(this.createFeatureXML(feature)); │ │ │ │ - return insertNode │ │ │ │ - }, │ │ │ │ - update: function(feature) { │ │ │ │ - if (!feature.fid) { │ │ │ │ - OpenLayers.Console.userError(OpenLayers.i18n("noFID")) │ │ │ │ - } │ │ │ │ - var updateNode = this.createElementNS(this.wfsns, "wfs:Update"); │ │ │ │ - updateNode.setAttribute("typeName", this.featurePrefix + ":" + this.featureName); │ │ │ │ - updateNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ - var propertyNode = this.createElementNS(this.wfsns, "wfs:Property"); │ │ │ │ - var nameNode = this.createElementNS(this.wfsns, "wfs:Name"); │ │ │ │ - var txtNode = this.createTextNode(this.geometryName); │ │ │ │ - nameNode.appendChild(txtNode); │ │ │ │ - propertyNode.appendChild(nameNode); │ │ │ │ - var valueNode = this.createElementNS(this.wfsns, "wfs:Value"); │ │ │ │ - var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ - if (feature.layer) { │ │ │ │ - geometryNode.setAttribute("srsName", feature.layer.projection.getCode()) │ │ │ │ - } │ │ │ │ - valueNode.appendChild(geometryNode); │ │ │ │ - propertyNode.appendChild(valueNode); │ │ │ │ - updateNode.appendChild(propertyNode); │ │ │ │ - for (var propName in feature.attributes) { │ │ │ │ - propertyNode = this.createElementNS(this.wfsns, "wfs:Property"); │ │ │ │ - nameNode = this.createElementNS(this.wfsns, "wfs:Name"); │ │ │ │ - nameNode.appendChild(this.createTextNode(propName)); │ │ │ │ - propertyNode.appendChild(nameNode); │ │ │ │ - valueNode = this.createElementNS(this.wfsns, "wfs:Value"); │ │ │ │ - valueNode.appendChild(this.createTextNode(feature.attributes[propName])); │ │ │ │ - propertyNode.appendChild(valueNode); │ │ │ │ - updateNode.appendChild(propertyNode) │ │ │ │ - } │ │ │ │ - var filterNode = this.createElementNS(this.ogcns, "ogc:Filter"); │ │ │ │ - var filterIdNode = this.createElementNS(this.ogcns, "ogc:FeatureId"); │ │ │ │ - filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ - filterNode.appendChild(filterIdNode); │ │ │ │ - updateNode.appendChild(filterNode); │ │ │ │ - return updateNode │ │ │ │ - }, │ │ │ │ - remove: function(feature) { │ │ │ │ - if (!feature.fid) { │ │ │ │ - OpenLayers.Console.userError(OpenLayers.i18n("noFID")); │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - var deleteNode = this.createElementNS(this.wfsns, "wfs:Delete"); │ │ │ │ - deleteNode.setAttribute("typeName", this.featurePrefix + ":" + this.featureName); │ │ │ │ - deleteNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ - var filterNode = this.createElementNS(this.ogcns, "ogc:Filter"); │ │ │ │ - var filterIdNode = this.createElementNS(this.ogcns, "ogc:FeatureId"); │ │ │ │ - filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ - filterNode.appendChild(filterIdNode); │ │ │ │ - deleteNode.appendChild(filterNode); │ │ │ │ - return deleteNode │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.layer = null │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFS" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMTSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.0.0", │ │ │ │ - yx: { │ │ │ │ - "urn:ogc:def:crs:EPSG::4326": true │ │ │ │ - }, │ │ │ │ - createLayer: function(capabilities, config) { │ │ │ │ - var layer; │ │ │ │ - if (!("layer" in config)) { │ │ │ │ - throw new Error("Missing property 'layer' in configuration.") │ │ │ │ - } │ │ │ │ - var contents = capabilities.contents; │ │ │ │ - var layers = contents.layers; │ │ │ │ - var layerDef; │ │ │ │ - for (var i = 0, ii = contents.layers.length; i < ii; ++i) { │ │ │ │ - if (contents.layers[i].identifier === config.layer) { │ │ │ │ - layerDef = contents.layers[i]; │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (!layerDef) { │ │ │ │ - throw new Error("Layer not found") │ │ │ │ - } │ │ │ │ - var format = config.format; │ │ │ │ - if (!format && layerDef.formats && layerDef.formats.length) { │ │ │ │ - format = layerDef.formats[0] │ │ │ │ - } │ │ │ │ - var matrixSet; │ │ │ │ - if (config.matrixSet) { │ │ │ │ - matrixSet = contents.tileMatrixSets[config.matrixSet] │ │ │ │ - } else if (layerDef.tileMatrixSetLinks.length >= 1) { │ │ │ │ - matrixSet = contents.tileMatrixSets[layerDef.tileMatrixSetLinks[0].tileMatrixSet] │ │ │ │ - } │ │ │ │ - if (!matrixSet) { │ │ │ │ - throw new Error("matrixSet not found") │ │ │ │ - } │ │ │ │ - var style; │ │ │ │ - for (var i = 0, ii = layerDef.styles.length; i < ii; ++i) { │ │ │ │ - style = layerDef.styles[i]; │ │ │ │ - if (style.isDefault) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var requestEncoding = config.requestEncoding; │ │ │ │ - if (!requestEncoding) { │ │ │ │ - requestEncoding = "KVP"; │ │ │ │ - if (capabilities.operationsMetadata.GetTile.dcp.http) { │ │ │ │ - var http = capabilities.operationsMetadata.GetTile.dcp.http; │ │ │ │ - if (http.get[0].constraints) { │ │ │ │ - var constraints = http.get[0].constraints; │ │ │ │ - var allowedValues = constraints.GetEncoding.allowedValues; │ │ │ │ - if (!allowedValues.KVP && (allowedValues.REST || allowedValues.RESTful)) { │ │ │ │ - requestEncoding = "REST" │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var dimensions = []; │ │ │ │ - var params = config.params || {}; │ │ │ │ - delete config.params; │ │ │ │ - for (var id = 0, ld = layerDef.dimensions.length; id < ld; id++) { │ │ │ │ - var dimension = layerDef.dimensions[id]; │ │ │ │ - dimensions.push(dimension.identifier); │ │ │ │ - if (!params.hasOwnProperty(dimension.identifier)) { │ │ │ │ - params[dimension.identifier] = dimension["default"] │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var projection = config.projection || matrixSet.supportedCRS.replace(/urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, "$1:$3"); │ │ │ │ - var units = config.units || (projection === "EPSG:4326" ? "degrees" : "m"); │ │ │ │ - var resolutions = []; │ │ │ │ - for (var mid in matrixSet.matrixIds) { │ │ │ │ - if (matrixSet.matrixIds.hasOwnProperty(mid)) { │ │ │ │ - resolutions.push(matrixSet.matrixIds[mid].scaleDenominator * 28e-5 / OpenLayers.METERS_PER_INCH / OpenLayers.INCHES_PER_UNIT[units]) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var url; │ │ │ │ - if (requestEncoding === "REST" && layerDef.resourceUrls) { │ │ │ │ - url = []; │ │ │ │ - var resourceUrls = layerDef.resourceUrls, │ │ │ │ - resourceUrl; │ │ │ │ - for (var t = 0, tt = layerDef.resourceUrls.length; t < tt; ++t) { │ │ │ │ - resourceUrl = layerDef.resourceUrls[t]; │ │ │ │ - if (resourceUrl.format === format && resourceUrl.resourceType === "tile") { │ │ │ │ - url.push(resourceUrl.template) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - var httpGet = capabilities.operationsMetadata.GetTile.dcp.http.get; │ │ │ │ - url = []; │ │ │ │ - var constraint; │ │ │ │ - for (var i = 0, ii = httpGet.length; i < ii; i++) { │ │ │ │ - constraint = httpGet[i].constraints; │ │ │ │ - if (!constraint || constraint && constraint.GetEncoding.allowedValues[requestEncoding]) { │ │ │ │ - url.push(httpGet[i].url) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return new OpenLayers.Layer.WMTS(OpenLayers.Util.applyDefaults(config, { │ │ │ │ - url: url, │ │ │ │ - requestEncoding: requestEncoding, │ │ │ │ - name: layerDef.title, │ │ │ │ - style: style.identifier, │ │ │ │ - format: format, │ │ │ │ - matrixIds: matrixSet.matrixIds, │ │ │ │ - matrixSet: matrixSet.identifier, │ │ │ │ - projection: projection, │ │ │ │ - units: units, │ │ │ │ - resolutions: config.isBaseLayer === false ? undefined : resolutions, │ │ │ │ - serverResolutions: resolutions, │ │ │ │ - tileFullExtent: matrixSet.bounds, │ │ │ │ - dimensions: dimensions, │ │ │ │ - params: params │ │ │ │ - })) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMTSCapabilities" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.CSWGetRecords = function(options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, OpenLayers.Format.CSWGetRecords.DEFAULTS); │ │ │ │ - var cls = OpenLayers.Format.CSWGetRecords["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (!cls) { │ │ │ │ - throw "Unsupported CSWGetRecords version: " + options.version │ │ │ │ - } │ │ │ │ - return new cls(options) │ │ │ │ -}; │ │ │ │ -OpenLayers.Format.CSWGetRecords.DEFAULTS = { │ │ │ │ - version: "2.0.2" │ │ │ │ -}; │ │ │ │ OpenLayers.Format.Context = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ layerOptions: null, │ │ │ │ layerParams: null, │ │ │ │ read: function(data, options) { │ │ │ │ var context = OpenLayers.Format.XML.VersionedOGC.prototype.read.apply(this, arguments); │ │ │ │ var map; │ │ │ │ if (options && options.map) { │ │ │ │ @@ -30772,702 +31271,14 @@ │ │ │ │ WFS: "urn:ogc:serviceType:WFS", │ │ │ │ WCS: "urn:ogc:serviceType:WCS", │ │ │ │ GML: "urn:ogc:serviceType:GML", │ │ │ │ SLD: "urn:ogc:serviceType:SLD", │ │ │ │ FES: "urn:ogc:serviceType:FES", │ │ │ │ KML: "urn:ogc:serviceType:KML" │ │ │ │ }; │ │ │ │ -OpenLayers.Format.SOSGetFeatureOfInterest = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - VERSION: "1.0.0", │ │ │ │ - namespaces: { │ │ │ │ - sos: "http://www.opengis.net/sos/1.0", │ │ │ │ - gml: "http://www.opengis.net/gml", │ │ │ │ - sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ - schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosAll.xsd", │ │ │ │ - defaultPrefix: "sos", │ │ │ │ - regExes: { │ │ │ │ - trimSpace: /^\s*|\s*$/g, │ │ │ │ - removeSpace: /\s*/g, │ │ │ │ - splitSpace: /\s+/, │ │ │ │ - trimComma: /\s*,\s*/g │ │ │ │ - }, │ │ │ │ - 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 info = { │ │ │ │ - features: [] │ │ │ │ - }; │ │ │ │ - this.readNode(data, info); │ │ │ │ - var features = []; │ │ │ │ - for (var i = 0, len = info.features.length; i < len; i++) { │ │ │ │ - var container = info.features[i]; │ │ │ │ - if (this.internalProjection && this.externalProjection && container.components[0]) { │ │ │ │ - container.components[0].transform(this.externalProjection, this.internalProjection) │ │ │ │ - } │ │ │ │ - var feature = new OpenLayers.Feature.Vector(container.components[0], container.attributes); │ │ │ │ - features.push(feature) │ │ │ │ - } │ │ │ │ - return features │ │ │ │ - }, │ │ │ │ - readers: { │ │ │ │ - sa: { │ │ │ │ - SamplingPoint: function(node, obj) { │ │ │ │ - if (!obj.attributes) { │ │ │ │ - var feature = { │ │ │ │ - attributes: {} │ │ │ │ - }; │ │ │ │ - obj.features.push(feature); │ │ │ │ - obj = feature │ │ │ │ - } │ │ │ │ - obj.attributes.id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - position: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - gml: OpenLayers.Util.applyDefaults({ │ │ │ │ - FeatureCollection: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - featureMember: function(node, obj) { │ │ │ │ - var feature = { │ │ │ │ - attributes: {} │ │ │ │ - }; │ │ │ │ - obj.features.push(feature); │ │ │ │ - this.readChildNodes(node, feature) │ │ │ │ - }, │ │ │ │ - name: function(node, obj) { │ │ │ │ - obj.attributes.name = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - pos: function(node, obj) { │ │ │ │ - if (!this.externalProjection) { │ │ │ │ - this.externalProjection = new OpenLayers.Projection(node.getAttribute("srsName")) │ │ │ │ - } │ │ │ │ - OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply(this, [node, obj]) │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.GML.v3.prototype.readers.gml) │ │ │ │ - }, │ │ │ │ - writers: { │ │ │ │ - sos: { │ │ │ │ - GetFeatureOfInterest: function(options) { │ │ │ │ - var node = this.createElementNSPlus("GetFeatureOfInterest", { │ │ │ │ - attributes: { │ │ │ │ - version: this.VERSION, │ │ │ │ - service: "SOS", │ │ │ │ - "xsi:schemaLocation": this.schemaLocation │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - for (var i = 0, len = options.fois.length; i < len; i++) { │ │ │ │ - this.writeNode("FeatureOfInterestId", { │ │ │ │ - foi: options.fois[i] │ │ │ │ - }, node) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - FeatureOfInterestId: function(options) { │ │ │ │ - var node = this.createElementNSPlus("FeatureOfInterestId", { │ │ │ │ - value: options.foi │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SOSGetFeatureOfInterest" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.SOSGetObservation = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - namespaces: { │ │ │ │ - ows: "http://www.opengis.net/ows", │ │ │ │ - gml: "http://www.opengis.net/gml", │ │ │ │ - sos: "http://www.opengis.net/sos/1.0", │ │ │ │ - ogc: "http://www.opengis.net/ogc", │ │ │ │ - om: "http://www.opengis.net/om/1.0", │ │ │ │ - sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ - regExes: { │ │ │ │ - trimSpace: /^\s*|\s*$/g, │ │ │ │ - removeSpace: /\s*/g, │ │ │ │ - splitSpace: /\s+/, │ │ │ │ - trimComma: /\s*,\s*/g │ │ │ │ - }, │ │ │ │ - VERSION: "1.0.0", │ │ │ │ - schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosGetObservation.xsd", │ │ │ │ - defaultPrefix: "sos", │ │ │ │ - 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 info = { │ │ │ │ - measurements: [], │ │ │ │ - observations: [] │ │ │ │ - }; │ │ │ │ - this.readNode(data, info); │ │ │ │ - return info │ │ │ │ - }, │ │ │ │ - write: function(options) { │ │ │ │ - var node = this.writeNode("sos:GetObservation", options); │ │ │ │ - node.setAttribute("xmlns:om", this.namespaces.om); │ │ │ │ - node.setAttribute("xmlns:ogc", this.namespaces.ogc); │ │ │ │ - this.setAttributeNS(node, this.namespaces.xsi, "xsi:schemaLocation", this.schemaLocation); │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [node]) │ │ │ │ - }, │ │ │ │ - readers: { │ │ │ │ - om: { │ │ │ │ - ObservationCollection: function(node, obj) { │ │ │ │ - obj.id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - member: function(node, observationCollection) { │ │ │ │ - this.readChildNodes(node, observationCollection) │ │ │ │ - }, │ │ │ │ - Measurement: function(node, observationCollection) { │ │ │ │ - var measurement = {}; │ │ │ │ - observationCollection.measurements.push(measurement); │ │ │ │ - this.readChildNodes(node, measurement) │ │ │ │ - }, │ │ │ │ - Observation: function(node, observationCollection) { │ │ │ │ - var observation = {}; │ │ │ │ - observationCollection.observations.push(observation); │ │ │ │ - this.readChildNodes(node, observation) │ │ │ │ - }, │ │ │ │ - samplingTime: function(node, measurement) { │ │ │ │ - var samplingTime = {}; │ │ │ │ - measurement.samplingTime = samplingTime; │ │ │ │ - this.readChildNodes(node, samplingTime) │ │ │ │ - }, │ │ │ │ - observedProperty: function(node, measurement) { │ │ │ │ - measurement.observedProperty = this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ - this.readChildNodes(node, measurement) │ │ │ │ - }, │ │ │ │ - procedure: function(node, measurement) { │ │ │ │ - measurement.procedure = this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ - this.readChildNodes(node, measurement) │ │ │ │ - }, │ │ │ │ - featureOfInterest: function(node, observation) { │ │ │ │ - var foi = { │ │ │ │ - features: [] │ │ │ │ - }; │ │ │ │ - observation.fois = []; │ │ │ │ - observation.fois.push(foi); │ │ │ │ - this.readChildNodes(node, foi); │ │ │ │ - var features = []; │ │ │ │ - for (var i = 0, len = foi.features.length; i < len; i++) { │ │ │ │ - var feature = foi.features[i]; │ │ │ │ - features.push(new OpenLayers.Feature.Vector(feature.components[0], feature.attributes)) │ │ │ │ - } │ │ │ │ - foi.features = features │ │ │ │ - }, │ │ │ │ - result: function(node, measurement) { │ │ │ │ - var result = {}; │ │ │ │ - measurement.result = result; │ │ │ │ - if (this.getChildValue(node) !== "") { │ │ │ │ - result.value = this.getChildValue(node); │ │ │ │ - result.uom = node.getAttribute("uom") │ │ │ │ - } else { │ │ │ │ - this.readChildNodes(node, result) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - sa: OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.sa, │ │ │ │ - gml: OpenLayers.Util.applyDefaults({ │ │ │ │ - TimeInstant: function(node, samplingTime) { │ │ │ │ - var timeInstant = {}; │ │ │ │ - samplingTime.timeInstant = timeInstant; │ │ │ │ - this.readChildNodes(node, timeInstant) │ │ │ │ - }, │ │ │ │ - timePosition: function(node, timeInstant) { │ │ │ │ - timeInstant.timePosition = this.getChildValue(node) │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.gml) │ │ │ │ - }, │ │ │ │ - writers: { │ │ │ │ - sos: { │ │ │ │ - GetObservation: function(options) { │ │ │ │ - var node = this.createElementNSPlus("GetObservation", { │ │ │ │ - attributes: { │ │ │ │ - version: this.VERSION, │ │ │ │ - service: "SOS" │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.writeNode("offering", options, node); │ │ │ │ - if (options.eventTime) { │ │ │ │ - this.writeNode("eventTime", options, node) │ │ │ │ - } │ │ │ │ - for (var procedure in options.procedures) { │ │ │ │ - this.writeNode("procedure", options.procedures[procedure], node) │ │ │ │ - } │ │ │ │ - for (var observedProperty in options.observedProperties) { │ │ │ │ - this.writeNode("observedProperty", options.observedProperties[observedProperty], node) │ │ │ │ - } │ │ │ │ - if (options.foi) { │ │ │ │ - this.writeNode("featureOfInterest", options.foi, node) │ │ │ │ - } │ │ │ │ - this.writeNode("responseFormat", options, node); │ │ │ │ - if (options.resultModel) { │ │ │ │ - this.writeNode("resultModel", options, node) │ │ │ │ - } │ │ │ │ - if (options.responseMode) { │ │ │ │ - this.writeNode("responseMode", options, node) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - featureOfInterest: function(foi) { │ │ │ │ - var node = this.createElementNSPlus("featureOfInterest"); │ │ │ │ - this.writeNode("ObjectID", foi.objectId, node); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - ObjectID: function(options) { │ │ │ │ - return this.createElementNSPlus("ObjectID", { │ │ │ │ - value: options │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - responseFormat: function(options) { │ │ │ │ - return this.createElementNSPlus("responseFormat", { │ │ │ │ - value: options.responseFormat │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - procedure: function(procedure) { │ │ │ │ - return this.createElementNSPlus("procedure", { │ │ │ │ - value: procedure │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - offering: function(options) { │ │ │ │ - return this.createElementNSPlus("offering", { │ │ │ │ - value: options.offering │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - observedProperty: function(observedProperty) { │ │ │ │ - return this.createElementNSPlus("observedProperty", { │ │ │ │ - value: observedProperty │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - eventTime: function(options) { │ │ │ │ - var node = this.createElementNSPlus("eventTime"); │ │ │ │ - if (options.eventTime === "latest") { │ │ │ │ - this.writeNode("ogc:TM_Equals", options, node) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - resultModel: function(options) { │ │ │ │ - return this.createElementNSPlus("resultModel", { │ │ │ │ - value: options.resultModel │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - responseMode: function(options) { │ │ │ │ - return this.createElementNSPlus("responseMode", { │ │ │ │ - value: options.responseMode │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - ogc: { │ │ │ │ - TM_Equals: function(options) { │ │ │ │ - var node = this.createElementNSPlus("ogc:TM_Equals"); │ │ │ │ - this.writeNode("ogc:PropertyName", { │ │ │ │ - property: "urn:ogc:data:time:iso8601" │ │ │ │ - }, node); │ │ │ │ - if (options.eventTime === "latest") { │ │ │ │ - this.writeNode("gml:TimeInstant", { │ │ │ │ - value: "latest" │ │ │ │ - }, node) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - PropertyName: function(options) { │ │ │ │ - return this.createElementNSPlus("ogc:PropertyName", { │ │ │ │ - value: options.property │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - gml: { │ │ │ │ - TimeInstant: function(options) { │ │ │ │ - var node = this.createElementNSPlus("gml:TimeInstant"); │ │ │ │ - this.writeNode("gml:timePosition", options, node); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - timePosition: function(options) { │ │ │ │ - var node = this.createElementNSPlus("gml:timePosition", { │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SOSGetObservation" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.1.1", │ │ │ │ - profile: null, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.CQL = function() { │ │ │ │ - var tokens = ["PROPERTY", "COMPARISON", "VALUE", "LOGICAL"], │ │ │ │ - patterns = { │ │ │ │ - PROPERTY: /^[_a-zA-Z]\w*/, │ │ │ │ - COMPARISON: /^(=|<>|<=|<|>=|>|LIKE)/i, │ │ │ │ - IS_NULL: /^IS NULL/i, │ │ │ │ - COMMA: /^,/, │ │ │ │ - LOGICAL: /^(AND|OR)/i, │ │ │ │ - VALUE: /^('([^']|'')*'|\d+(\.\d*)?|\.\d+)/, │ │ │ │ - LPAREN: /^\(/, │ │ │ │ - RPAREN: /^\)/, │ │ │ │ - SPATIAL: /^(BBOX|INTERSECTS|DWITHIN|WITHIN|CONTAINS)/i, │ │ │ │ - NOT: /^NOT/i, │ │ │ │ - BETWEEN: /^BETWEEN/i, │ │ │ │ - GEOMETRY: function(text) { │ │ │ │ - var type = /^(POINT|LINESTRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)/.exec(text); │ │ │ │ - if (type) { │ │ │ │ - var len = text.length; │ │ │ │ - var idx = text.indexOf("(", type[0].length); │ │ │ │ - if (idx > -1) { │ │ │ │ - var depth = 1; │ │ │ │ - while (idx < len && depth > 0) { │ │ │ │ - idx++; │ │ │ │ - switch (text.charAt(idx)) { │ │ │ │ - case "(": │ │ │ │ - depth++; │ │ │ │ - break; │ │ │ │ - case ")": │ │ │ │ - depth--; │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return [text.substr(0, idx + 1)] │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - END: /^$/ │ │ │ │ - }, │ │ │ │ - follows = { │ │ │ │ - LPAREN: ["GEOMETRY", "SPATIAL", "PROPERTY", "VALUE", "LPAREN"], │ │ │ │ - RPAREN: ["NOT", "LOGICAL", "END", "RPAREN"], │ │ │ │ - PROPERTY: ["COMPARISON", "BETWEEN", "COMMA", "IS_NULL"], │ │ │ │ - BETWEEN: ["VALUE"], │ │ │ │ - IS_NULL: ["END"], │ │ │ │ - COMPARISON: ["VALUE"], │ │ │ │ - COMMA: ["GEOMETRY", "VALUE", "PROPERTY"], │ │ │ │ - VALUE: ["LOGICAL", "COMMA", "RPAREN", "END"], │ │ │ │ - SPATIAL: ["LPAREN"], │ │ │ │ - LOGICAL: ["NOT", "VALUE", "SPATIAL", "PROPERTY", "LPAREN"], │ │ │ │ - NOT: ["PROPERTY", "LPAREN"], │ │ │ │ - GEOMETRY: ["COMMA", "RPAREN"] │ │ │ │ - }, │ │ │ │ - operators = { │ │ │ │ - "=": OpenLayers.Filter.Comparison.EQUAL_TO, │ │ │ │ - "<>": OpenLayers.Filter.Comparison.NOT_EQUAL_TO, │ │ │ │ - "<": OpenLayers.Filter.Comparison.LESS_THAN, │ │ │ │ - "<=": OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO, │ │ │ │ - ">": OpenLayers.Filter.Comparison.GREATER_THAN, │ │ │ │ - ">=": OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO, │ │ │ │ - LIKE: OpenLayers.Filter.Comparison.LIKE, │ │ │ │ - BETWEEN: OpenLayers.Filter.Comparison.BETWEEN, │ │ │ │ - "IS NULL": OpenLayers.Filter.Comparison.IS_NULL │ │ │ │ - }, │ │ │ │ - operatorReverse = {}, │ │ │ │ - logicals = { │ │ │ │ - AND: OpenLayers.Filter.Logical.AND, │ │ │ │ - OR: OpenLayers.Filter.Logical.OR │ │ │ │ - }, │ │ │ │ - logicalReverse = {}, │ │ │ │ - precedence = { │ │ │ │ - RPAREN: 3, │ │ │ │ - LOGICAL: 2, │ │ │ │ - COMPARISON: 1 │ │ │ │ - }; │ │ │ │ - var i; │ │ │ │ - for (i in operators) { │ │ │ │ - if (operators.hasOwnProperty(i)) { │ │ │ │ - operatorReverse[operators[i]] = i │ │ │ │ - } │ │ │ │ - } │ │ │ │ - for (i in logicals) { │ │ │ │ - if (logicals.hasOwnProperty(i)) { │ │ │ │ - logicalReverse[logicals[i]] = i │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - function tryToken(text, pattern) { │ │ │ │ - if (pattern instanceof RegExp) { │ │ │ │ - return pattern.exec(text) │ │ │ │ - } else { │ │ │ │ - return pattern(text) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - function nextToken(text, tokens) { │ │ │ │ - var i, token, len = tokens.length; │ │ │ │ - for (i = 0; i < len; i++) { │ │ │ │ - token = tokens[i]; │ │ │ │ - var pat = patterns[token]; │ │ │ │ - var matches = tryToken(text, pat); │ │ │ │ - if (matches) { │ │ │ │ - var match = matches[0]; │ │ │ │ - var remainder = text.substr(match.length).replace(/^\s*/, ""); │ │ │ │ - return { │ │ │ │ - type: token, │ │ │ │ - text: match, │ │ │ │ - remainder: remainder │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var msg = "ERROR: In parsing: [" + text + "], expected one of: "; │ │ │ │ - for (i = 0; i < len; i++) { │ │ │ │ - token = tokens[i]; │ │ │ │ - msg += "\n " + token + ": " + patterns[token] │ │ │ │ - } │ │ │ │ - throw new Error(msg) │ │ │ │ - } │ │ │ │ - │ │ │ │ - function tokenize(text) { │ │ │ │ - var results = []; │ │ │ │ - var token, expect = ["NOT", "GEOMETRY", "SPATIAL", "PROPERTY", "LPAREN"]; │ │ │ │ - do { │ │ │ │ - token = nextToken(text, expect); │ │ │ │ - text = token.remainder; │ │ │ │ - expect = follows[token.type]; │ │ │ │ - if (token.type != "END" && !expect) { │ │ │ │ - throw new Error("No follows list for " + token.type) │ │ │ │ - } │ │ │ │ - results.push(token) │ │ │ │ - } while (token.type != "END"); │ │ │ │ - return results │ │ │ │ - } │ │ │ │ - │ │ │ │ - function buildAst(tokens) { │ │ │ │ - var operatorStack = [], │ │ │ │ - postfix = []; │ │ │ │ - while (tokens.length) { │ │ │ │ - var tok = tokens.shift(); │ │ │ │ - switch (tok.type) { │ │ │ │ - case "PROPERTY": │ │ │ │ - case "GEOMETRY": │ │ │ │ - case "VALUE": │ │ │ │ - postfix.push(tok); │ │ │ │ - break; │ │ │ │ - case "COMPARISON": │ │ │ │ - case "BETWEEN": │ │ │ │ - case "IS_NULL": │ │ │ │ - case "LOGICAL": │ │ │ │ - var p = precedence[tok.type]; │ │ │ │ - while (operatorStack.length > 0 && precedence[operatorStack[operatorStack.length - 1].type] <= p) { │ │ │ │ - postfix.push(operatorStack.pop()) │ │ │ │ - } │ │ │ │ - operatorStack.push(tok); │ │ │ │ - break; │ │ │ │ - case "SPATIAL": │ │ │ │ - case "NOT": │ │ │ │ - case "LPAREN": │ │ │ │ - operatorStack.push(tok); │ │ │ │ - break; │ │ │ │ - case "RPAREN": │ │ │ │ - while (operatorStack.length > 0 && operatorStack[operatorStack.length - 1].type != "LPAREN") { │ │ │ │ - postfix.push(operatorStack.pop()) │ │ │ │ - } │ │ │ │ - operatorStack.pop(); │ │ │ │ - if (operatorStack.length > 0 && operatorStack[operatorStack.length - 1].type == "SPATIAL") { │ │ │ │ - postfix.push(operatorStack.pop()) │ │ │ │ - } │ │ │ │ - case "COMMA": │ │ │ │ - case "END": │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - throw new Error("Unknown token type " + tok.type) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - while (operatorStack.length > 0) { │ │ │ │ - postfix.push(operatorStack.pop()) │ │ │ │ - } │ │ │ │ - │ │ │ │ - function buildTree() { │ │ │ │ - var tok = postfix.pop(); │ │ │ │ - switch (tok.type) { │ │ │ │ - case "LOGICAL": │ │ │ │ - var rhs = buildTree(), │ │ │ │ - lhs = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Logical({ │ │ │ │ - filters: [lhs, rhs], │ │ │ │ - type: logicals[tok.text.toUpperCase()] │ │ │ │ - }); │ │ │ │ - case "NOT": │ │ │ │ - var operand = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Logical({ │ │ │ │ - filters: [operand], │ │ │ │ - type: OpenLayers.Filter.Logical.NOT │ │ │ │ - }); │ │ │ │ - case "BETWEEN": │ │ │ │ - var min, max, property; │ │ │ │ - postfix.pop(); │ │ │ │ - max = buildTree(); │ │ │ │ - min = buildTree(); │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Comparison({ │ │ │ │ - property: property, │ │ │ │ - lowerBoundary: min, │ │ │ │ - upperBoundary: max, │ │ │ │ - type: OpenLayers.Filter.Comparison.BETWEEN │ │ │ │ - }); │ │ │ │ - case "COMPARISON": │ │ │ │ - var value = buildTree(), │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Comparison({ │ │ │ │ - property: property, │ │ │ │ - value: value, │ │ │ │ - type: operators[tok.text.toUpperCase()] │ │ │ │ - }); │ │ │ │ - case "IS_NULL": │ │ │ │ - var property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Comparison({ │ │ │ │ - property: property, │ │ │ │ - type: operators[tok.text.toUpperCase()] │ │ │ │ - }); │ │ │ │ - case "VALUE": │ │ │ │ - var match = tok.text.match(/^'(.*)'$/); │ │ │ │ - if (match) { │ │ │ │ - return match[1].replace(/''/g, "'") │ │ │ │ - } else { │ │ │ │ - return Number(tok.text) │ │ │ │ - } │ │ │ │ - case "SPATIAL": │ │ │ │ - switch (tok.text.toUpperCase()) { │ │ │ │ - case "BBOX": │ │ │ │ - var maxy = buildTree(), │ │ │ │ - maxx = buildTree(), │ │ │ │ - miny = buildTree(), │ │ │ │ - minx = buildTree(), │ │ │ │ - prop = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ - property: prop, │ │ │ │ - value: OpenLayers.Bounds.fromArray([minx, miny, maxx, maxy]) │ │ │ │ - }); │ │ │ │ - case "INTERSECTS": │ │ │ │ - var value = buildTree(), │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ - property: property, │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - case "WITHIN": │ │ │ │ - var value = buildTree(), │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.WITHIN, │ │ │ │ - property: property, │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - case "CONTAINS": │ │ │ │ - var value = buildTree(), │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.CONTAINS, │ │ │ │ - property: property, │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - case "DWITHIN": │ │ │ │ - var distance = buildTree(), │ │ │ │ - value = buildTree(), │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.DWITHIN, │ │ │ │ - value: value, │ │ │ │ - property: property, │ │ │ │ - distance: Number(distance) │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - case "GEOMETRY": │ │ │ │ - return OpenLayers.Geometry.fromWKT(tok.text); │ │ │ │ - default: │ │ │ │ - return tok.text │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var result = buildTree(); │ │ │ │ - if (postfix.length > 0) { │ │ │ │ - var msg = "Remaining tokens after building AST: \n"; │ │ │ │ - for (var i = postfix.length - 1; i >= 0; i--) { │ │ │ │ - msg += postfix[i].type + ": " + postfix[i].text + "\n" │ │ │ │ - } │ │ │ │ - throw new Error(msg) │ │ │ │ - } │ │ │ │ - return result │ │ │ │ - } │ │ │ │ - return OpenLayers.Class(OpenLayers.Format, { │ │ │ │ - read: function(text) { │ │ │ │ - var result = buildAst(tokenize(text)); │ │ │ │ - if (this.keepData) { │ │ │ │ - this.data = result │ │ │ │ - } │ │ │ │ - return result │ │ │ │ - }, │ │ │ │ - write: function(filter) { │ │ │ │ - if (filter instanceof OpenLayers.Geometry) { │ │ │ │ - return filter.toString() │ │ │ │ - } │ │ │ │ - switch (filter.CLASS_NAME) { │ │ │ │ - case "OpenLayers.Filter.Spatial": │ │ │ │ - switch (filter.type) { │ │ │ │ - case OpenLayers.Filter.Spatial.BBOX: │ │ │ │ - return "BBOX(" + filter.property + "," + filter.value.toBBOX() + ")"; │ │ │ │ - case OpenLayers.Filter.Spatial.DWITHIN: │ │ │ │ - return "DWITHIN(" + filter.property + ", " + this.write(filter.value) + ", " + filter.distance + ")"; │ │ │ │ - case OpenLayers.Filter.Spatial.WITHIN: │ │ │ │ - return "WITHIN(" + filter.property + ", " + this.write(filter.value) + ")"; │ │ │ │ - case OpenLayers.Filter.Spatial.INTERSECTS: │ │ │ │ - return "INTERSECTS(" + filter.property + ", " + this.write(filter.value) + ")"; │ │ │ │ - case OpenLayers.Filter.Spatial.CONTAINS: │ │ │ │ - return "CONTAINS(" + filter.property + ", " + this.write(filter.value) + ")"; │ │ │ │ - default: │ │ │ │ - throw new Error("Unknown spatial filter type: " + filter.type) │ │ │ │ - } │ │ │ │ - case "OpenLayers.Filter.Logical": │ │ │ │ - if (filter.type == OpenLayers.Filter.Logical.NOT) { │ │ │ │ - return "NOT (" + this.write(filter.filters[0]) + ")" │ │ │ │ - } else { │ │ │ │ - var res = "("; │ │ │ │ - var first = true; │ │ │ │ - for (var i = 0; i < filter.filters.length; i++) { │ │ │ │ - if (first) { │ │ │ │ - first = false │ │ │ │ - } else { │ │ │ │ - res += ") " + logicalReverse[filter.type] + " (" │ │ │ │ - } │ │ │ │ - res += this.write(filter.filters[i]) │ │ │ │ - } │ │ │ │ - return res + ")" │ │ │ │ - } │ │ │ │ - case "OpenLayers.Filter.Comparison": │ │ │ │ - if (filter.type == OpenLayers.Filter.Comparison.BETWEEN) { │ │ │ │ - return filter.property + " BETWEEN " + this.write(filter.lowerBoundary) + " AND " + this.write(filter.upperBoundary) │ │ │ │ - } else { │ │ │ │ - return filter.value !== null ? filter.property + " " + operatorReverse[filter.type] + " " + this.write(filter.value) : filter.property + " " + operatorReverse[filter.type] │ │ │ │ - } │ │ │ │ - case undefined: │ │ │ │ - if (typeof filter === "string") { │ │ │ │ - return "'" + filter.replace(/'/g, "''") + "'" │ │ │ │ - } else if (typeof filter === "number") { │ │ │ │ - return String(filter) │ │ │ │ - } │ │ │ │ - default: │ │ │ │ - throw new Error("Can't encode: " + filter.CLASS_NAME + " " + filter) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.CQL" │ │ │ │ - }) │ │ │ │ -}(); │ │ │ │ OpenLayers.Format.WMC = OpenLayers.Class(OpenLayers.Format.Context, { │ │ │ │ defaultVersion: "1.1.0", │ │ │ │ layerToContext: function(layer) { │ │ │ │ var parser = this.getParser(); │ │ │ │ var layerContext = { │ │ │ │ queryable: layer.queryable, │ │ │ │ visibility: layer.visibility, │ │ │ │ @@ -31569,230 +31380,106 @@ │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ return context │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.WMC" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.WPSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.0.0", │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WPSCapabilities" │ │ │ │ +OpenLayers.Format.WCSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.1.0", │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ - geometryType: "linestring", │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - read: function(encoded) { │ │ │ │ - var geomType; │ │ │ │ - if (this.geometryType == "linestring") geomType = OpenLayers.Geometry.LineString; │ │ │ │ - else if (this.geometryType == "linearring") geomType = OpenLayers.Geometry.LinearRing; │ │ │ │ - else if (this.geometryType == "multipoint") geomType = OpenLayers.Geometry.MultiPoint; │ │ │ │ - else if (this.geometryType != "point" && this.geometryType != "polygon") return null; │ │ │ │ - var flatPoints = this.decodeDeltas(encoded, 2); │ │ │ │ - var flatPointsLength = flatPoints.length; │ │ │ │ - var pointGeometries = []; │ │ │ │ - for (var i = 0; i + 1 < flatPointsLength;) { │ │ │ │ - var y = flatPoints[i++], │ │ │ │ - x = flatPoints[i++]; │ │ │ │ - pointGeometries.push(new OpenLayers.Geometry.Point(x, y)) │ │ │ │ - } │ │ │ │ - if (this.geometryType == "point") return new OpenLayers.Feature.Vector(pointGeometries[0]); │ │ │ │ - if (this.geometryType == "polygon") return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(pointGeometries)])); │ │ │ │ - return new OpenLayers.Feature.Vector(new geomType(pointGeometries)) │ │ │ │ - }, │ │ │ │ - decode: function(encoded, dims, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var flatPoints = this.decodeDeltas(encoded, dims, factor); │ │ │ │ - var flatPointsLength = flatPoints.length; │ │ │ │ - var points = []; │ │ │ │ - for (var i = 0; i + (dims - 1) < flatPointsLength;) { │ │ │ │ - var point = []; │ │ │ │ - for (var dim = 0; dim < dims; ++dim) { │ │ │ │ - point.push(flatPoints[i++]) │ │ │ │ - } │ │ │ │ - points.push(point) │ │ │ │ - } │ │ │ │ - return points │ │ │ │ - }, │ │ │ │ - write: function(features) { │ │ │ │ - var feature; │ │ │ │ - if (features.constructor == Array) feature = features[0]; │ │ │ │ - else feature = features; │ │ │ │ - var geometry = feature.geometry; │ │ │ │ - var type = geometry.CLASS_NAME.split(".")[2].toLowerCase(); │ │ │ │ - var pointGeometries; │ │ │ │ - if (type == "point") pointGeometries = new Array(geometry); │ │ │ │ - else if (type == "linestring" || type == "linearring" || type == "multipoint") pointGeometries = geometry.components; │ │ │ │ - else if (type == "polygon") pointGeometries = geometry.components[0].components; │ │ │ │ - else return null; │ │ │ │ - var flatPoints = []; │ │ │ │ - var pointGeometriesLength = pointGeometries.length; │ │ │ │ - for (var i = 0; i < pointGeometriesLength; ++i) { │ │ │ │ - var pointGeometry = pointGeometries[i]; │ │ │ │ - flatPoints.push(pointGeometry.y); │ │ │ │ - flatPoints.push(pointGeometry.x) │ │ │ │ - } │ │ │ │ - return this.encodeDeltas(flatPoints, 2) │ │ │ │ - }, │ │ │ │ - encode: function(points, dims, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var flatPoints = []; │ │ │ │ - var pointsLength = points.length; │ │ │ │ - for (var i = 0; i < pointsLength; ++i) { │ │ │ │ - var point = points[i]; │ │ │ │ - for (var dim = 0; dim < dims; ++dim) { │ │ │ │ - flatPoints.push(point[dim]) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return this.encodeDeltas(flatPoints, dims, factor) │ │ │ │ - }, │ │ │ │ - encodeDeltas: function(numbers, dimension, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var d; │ │ │ │ - var lastNumbers = new Array(dimension); │ │ │ │ - for (d = 0; d < dimension; ++d) { │ │ │ │ - lastNumbers[d] = 0 │ │ │ │ - } │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength;) { │ │ │ │ - for (d = 0; d < dimension; ++d, ++i) { │ │ │ │ - var num = numbers[i]; │ │ │ │ - var delta = num - lastNumbers[d]; │ │ │ │ - lastNumbers[d] = num; │ │ │ │ - numbers[i] = delta │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return this.encodeFloats(numbers, factor) │ │ │ │ - }, │ │ │ │ - decodeDeltas: function(encoded, dimension, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var d; │ │ │ │ - var lastNumbers = new Array(dimension); │ │ │ │ - for (d = 0; d < dimension; ++d) { │ │ │ │ - lastNumbers[d] = 0 │ │ │ │ - } │ │ │ │ - var numbers = this.decodeFloats(encoded, factor); │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength;) { │ │ │ │ - for (d = 0; d < dimension; ++d, ++i) { │ │ │ │ - lastNumbers[d] += numbers[i]; │ │ │ │ - numbers[i] = lastNumbers[d] │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return numbers │ │ │ │ - }, │ │ │ │ - encodeFloats: function(numbers, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength; ++i) { │ │ │ │ - numbers[i] = Math.round(numbers[i] * factor) │ │ │ │ - } │ │ │ │ - return this.encodeSignedIntegers(numbers) │ │ │ │ - }, │ │ │ │ - decodeFloats: function(encoded, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var numbers = this.decodeSignedIntegers(encoded); │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength; ++i) { │ │ │ │ - numbers[i] /= factor │ │ │ │ - } │ │ │ │ - return numbers │ │ │ │ - }, │ │ │ │ - encodeSignedIntegers: function(numbers) { │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength; ++i) { │ │ │ │ - var num = numbers[i]; │ │ │ │ - var signedNum = num << 1; │ │ │ │ - if (num < 0) { │ │ │ │ - signedNum = ~signedNum │ │ │ │ - } │ │ │ │ - numbers[i] = signedNum │ │ │ │ - } │ │ │ │ - return this.encodeUnsignedIntegers(numbers) │ │ │ │ - }, │ │ │ │ - decodeSignedIntegers: function(encoded) { │ │ │ │ - var numbers = this.decodeUnsignedIntegers(encoded); │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength; ++i) { │ │ │ │ - var num = numbers[i]; │ │ │ │ - numbers[i] = num & 1 ? ~(num >> 1) : num >> 1 │ │ │ │ - } │ │ │ │ - return numbers │ │ │ │ - }, │ │ │ │ - encodeUnsignedIntegers: function(numbers) { │ │ │ │ - var encoded = ""; │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength; ++i) { │ │ │ │ - encoded += this.encodeUnsignedInteger(numbers[i]) │ │ │ │ - } │ │ │ │ - return encoded │ │ │ │ - }, │ │ │ │ - decodeUnsignedIntegers: function(encoded) { │ │ │ │ - var numbers = []; │ │ │ │ - var current = 0; │ │ │ │ - var shift = 0; │ │ │ │ - var encodedLength = encoded.length; │ │ │ │ - for (var i = 0; i < encodedLength; ++i) { │ │ │ │ - var b = encoded.charCodeAt(i) - 63; │ │ │ │ - current |= (b & 31) << shift; │ │ │ │ - if (b < 32) { │ │ │ │ - numbers.push(current); │ │ │ │ - current = 0; │ │ │ │ - shift = 0 │ │ │ │ - } else { │ │ │ │ - shift += 5 │ │ │ │ +OpenLayers.Format.QueryStringFilter = function() { │ │ │ │ + var cmpToStr = {}; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.EQUAL_TO] = "eq"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.NOT_EQUAL_TO] = "ne"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN] = "lt"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO] = "lte"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN] = "gt"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO] = "gte"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.LIKE] = "ilike"; │ │ │ │ + │ │ │ │ + function regex2value(value) { │ │ │ │ + value = value.replace(/%/g, "\\%"); │ │ │ │ + value = value.replace(/\\\\\.(\*)?/g, function($0, $1) { │ │ │ │ + return $1 ? $0 : "\\\\_" │ │ │ │ + }); │ │ │ │ + value = value.replace(/\\\\\.\*/g, "\\\\%"); │ │ │ │ + value = value.replace(/(\\)?\.(\*)?/g, function($0, $1, $2) { │ │ │ │ + return $1 || $2 ? $0 : "_" │ │ │ │ + }); │ │ │ │ + value = value.replace(/(\\)?\.\*/g, function($0, $1) { │ │ │ │ + return $1 ? $0 : "%" │ │ │ │ + }); │ │ │ │ + value = value.replace(/\\\./g, "."); │ │ │ │ + value = value.replace(/(\\)?\\\*/g, function($0, $1) { │ │ │ │ + return $1 ? $0 : "*" │ │ │ │ + }); │ │ │ │ + return value │ │ │ │ + } │ │ │ │ + return OpenLayers.Class(OpenLayers.Format, { │ │ │ │ + wildcarded: false, │ │ │ │ + srsInBBOX: false, │ │ │ │ + write: function(filter, params) { │ │ │ │ + params = params || {}; │ │ │ │ + var className = filter.CLASS_NAME; │ │ │ │ + var filterType = className.substring(className.lastIndexOf(".") + 1); │ │ │ │ + switch (filterType) { │ │ │ │ + case "Spatial": │ │ │ │ + switch (filter.type) { │ │ │ │ + case OpenLayers.Filter.Spatial.BBOX: │ │ │ │ + params.bbox = filter.value.toArray(); │ │ │ │ + if (this.srsInBBOX && filter.projection) { │ │ │ │ + params.bbox.push(filter.projection.getCode()) │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case OpenLayers.Filter.Spatial.DWITHIN: │ │ │ │ + params.tolerance = filter.distance; │ │ │ │ + case OpenLayers.Filter.Spatial.WITHIN: │ │ │ │ + params.lon = filter.value.x; │ │ │ │ + params.lat = filter.value.y; │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + OpenLayers.Console.warn("Unknown spatial filter type " + filter.type) │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case "Comparison": │ │ │ │ + var op = cmpToStr[filter.type]; │ │ │ │ + if (op !== undefined) { │ │ │ │ + var value = filter.value; │ │ │ │ + if (filter.type == OpenLayers.Filter.Comparison.LIKE) { │ │ │ │ + value = regex2value(value); │ │ │ │ + if (this.wildcarded) { │ │ │ │ + value = "%" + value + "%" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + params[filter.property + "__" + op] = value; │ │ │ │ + params.queryable = params.queryable || []; │ │ │ │ + params.queryable.push(filter.property) │ │ │ │ + } else { │ │ │ │ + OpenLayers.Console.warn("Unknown comparison filter type " + filter.type) │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case "Logical": │ │ │ │ + if (filter.type === OpenLayers.Filter.Logical.AND) { │ │ │ │ + for (var i = 0, len = filter.filters.length; i < len; i++) { │ │ │ │ + params = this.write(filter.filters[i], params) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Console.warn("Unsupported logical filter type " + filter.type) │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + OpenLayers.Console.warn("Unknown filter type " + filterType) │ │ │ │ } │ │ │ │ - } │ │ │ │ - return numbers │ │ │ │ - }, │ │ │ │ - encodeFloat: function(num, opt_factor) { │ │ │ │ - num = Math.round(num * (opt_factor || 1e5)); │ │ │ │ - return this.encodeSignedInteger(num) │ │ │ │ - }, │ │ │ │ - decodeFloat: function(encoded, opt_factor) { │ │ │ │ - var result = this.decodeSignedInteger(encoded); │ │ │ │ - return result / (opt_factor || 1e5) │ │ │ │ - }, │ │ │ │ - encodeSignedInteger: function(num) { │ │ │ │ - var signedNum = num << 1; │ │ │ │ - if (num < 0) { │ │ │ │ - signedNum = ~signedNum │ │ │ │ - } │ │ │ │ - return this.encodeUnsignedInteger(signedNum) │ │ │ │ - }, │ │ │ │ - decodeSignedInteger: function(encoded) { │ │ │ │ - var result = this.decodeUnsignedInteger(encoded); │ │ │ │ - return result & 1 ? ~(result >> 1) : result >> 1 │ │ │ │ - }, │ │ │ │ - encodeUnsignedInteger: function(num) { │ │ │ │ - var value, encoded = ""; │ │ │ │ - while (num >= 32) { │ │ │ │ - value = (32 | num & 31) + 63; │ │ │ │ - encoded += String.fromCharCode(value); │ │ │ │ - num >>= 5 │ │ │ │ - } │ │ │ │ - value = num + 63; │ │ │ │ - encoded += String.fromCharCode(value); │ │ │ │ - return encoded │ │ │ │ - }, │ │ │ │ - decodeUnsignedInteger: function(encoded) { │ │ │ │ - var result = 0; │ │ │ │ - var shift = 0; │ │ │ │ - var encodedLength = encoded.length; │ │ │ │ - for (var i = 0; i < encodedLength; ++i) { │ │ │ │ - var b = encoded.charCodeAt(i) - 63; │ │ │ │ - result |= (b & 31) << shift; │ │ │ │ - if (b < 32) break; │ │ │ │ - shift += 5 │ │ │ │ - } │ │ │ │ - return result │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.EncodedPolyline" │ │ │ │ -}); │ │ │ │ + return params │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.QueryStringFilter" │ │ │ │ + }) │ │ │ │ +}(); │ │ │ │ OpenLayers.Format.Atom = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ namespaces: { │ │ │ │ atom: "http://www.w3.org/2005/Atom", │ │ │ │ georss: "http://www.georss.org/georss" │ │ │ │ }, │ │ │ │ feedTitle: "untitled", │ │ │ │ defaultEntryTitle: "untitled", │ │ │ │ @@ -32150,232 +31837,239 @@ │ │ │ │ } │ │ │ │ if (persons.length > 0) { │ │ │ │ data[name + "s"] = persons │ │ │ │ } │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.Atom" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.GeoRSS = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - rssns: "http://backend.userland.com/rss2", │ │ │ │ - featureNS: "http://mapserver.gis.umn.edu/mapserver", │ │ │ │ - georssns: "http://www.georss.org/georss", │ │ │ │ - geons: "http://www.w3.org/2003/01/geo/wgs84_pos#", │ │ │ │ - featureTitle: "Untitled", │ │ │ │ - featureDescription: "No Description", │ │ │ │ - gmlParser: null, │ │ │ │ - xy: false, │ │ │ │ - createGeometryFromItem: function(item) { │ │ │ │ - var point = this.getElementsByTagNameNS(item, this.georssns, "point"); │ │ │ │ - var lat = this.getElementsByTagNameNS(item, this.geons, "lat"); │ │ │ │ - var lon = this.getElementsByTagNameNS(item, this.geons, "long"); │ │ │ │ - var line = this.getElementsByTagNameNS(item, this.georssns, "line"); │ │ │ │ - var polygon = this.getElementsByTagNameNS(item, this.georssns, "polygon"); │ │ │ │ - var where = this.getElementsByTagNameNS(item, this.georssns, "where"); │ │ │ │ - var box = this.getElementsByTagNameNS(item, this.georssns, "box"); │ │ │ │ - if (point.length > 0 || lat.length > 0 && lon.length > 0) { │ │ │ │ - var location; │ │ │ │ - if (point.length > 0) { │ │ │ │ - location = OpenLayers.String.trim(point[0].firstChild.nodeValue).split(/\s+/); │ │ │ │ - if (location.length != 2) { │ │ │ │ - location = OpenLayers.String.trim(point[0].firstChild.nodeValue).split(/\s*,\s*/) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - location = [parseFloat(lat[0].firstChild.nodeValue), parseFloat(lon[0].firstChild.nodeValue)] │ │ │ │ - } │ │ │ │ - var geometry = new OpenLayers.Geometry.Point(location[1], location[0]) │ │ │ │ - } else if (line.length > 0) { │ │ │ │ - var coords = OpenLayers.String.trim(this.getChildValue(line[0])).split(/\s+/); │ │ │ │ - var components = []; │ │ │ │ - var point; │ │ │ │ - for (var i = 0, len = coords.length; i < len; i += 2) { │ │ │ │ - point = new OpenLayers.Geometry.Point(coords[i + 1], coords[i]); │ │ │ │ - components.push(point) │ │ │ │ - } │ │ │ │ - geometry = new OpenLayers.Geometry.LineString(components) │ │ │ │ - } else if (polygon.length > 0) { │ │ │ │ - var coords = OpenLayers.String.trim(this.getChildValue(polygon[0])).split(/\s+/); │ │ │ │ - var components = []; │ │ │ │ - var point; │ │ │ │ - for (var i = 0, len = coords.length; i < len; i += 2) { │ │ │ │ - point = new OpenLayers.Geometry.Point(coords[i + 1], coords[i]); │ │ │ │ - components.push(point) │ │ │ │ - } │ │ │ │ - geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]) │ │ │ │ - } else if (where.length > 0) { │ │ │ │ - if (!this.gmlParser) { │ │ │ │ - this.gmlParser = new OpenLayers.Format.GML({ │ │ │ │ - xy: this.xy │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - var feature = this.gmlParser.parseFeature(where[0]); │ │ │ │ - geometry = feature.geometry │ │ │ │ - } else if (box.length > 0) { │ │ │ │ - var coords = OpenLayers.String.trim(box[0].firstChild.nodeValue).split(/\s+/); │ │ │ │ - var components = []; │ │ │ │ - var point; │ │ │ │ - if (coords.length > 3) { │ │ │ │ - point = new OpenLayers.Geometry.Point(coords[1], coords[0]); │ │ │ │ - components.push(point); │ │ │ │ - point = new OpenLayers.Geometry.Point(coords[1], coords[2]); │ │ │ │ - components.push(point); │ │ │ │ - point = new OpenLayers.Geometry.Point(coords[3], coords[2]); │ │ │ │ - components.push(point); │ │ │ │ - point = new OpenLayers.Geometry.Point(coords[3], coords[0]); │ │ │ │ - components.push(point); │ │ │ │ - point = new OpenLayers.Geometry.Point(coords[1], coords[0]); │ │ │ │ - components.push(point) │ │ │ │ +OpenLayers.Format.WMSDescribeLayer = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.1.1", │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.SOSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.0.0", │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SOSCapabilities" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WMSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.1.1", │ │ │ │ + profile: null, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ + geometryType: "linestring", │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + read: function(encoded) { │ │ │ │ + var geomType; │ │ │ │ + if (this.geometryType == "linestring") geomType = OpenLayers.Geometry.LineString; │ │ │ │ + else if (this.geometryType == "linearring") geomType = OpenLayers.Geometry.LinearRing; │ │ │ │ + else if (this.geometryType == "multipoint") geomType = OpenLayers.Geometry.MultiPoint; │ │ │ │ + else if (this.geometryType != "point" && this.geometryType != "polygon") return null; │ │ │ │ + var flatPoints = this.decodeDeltas(encoded, 2); │ │ │ │ + var flatPointsLength = flatPoints.length; │ │ │ │ + var pointGeometries = []; │ │ │ │ + for (var i = 0; i + 1 < flatPointsLength;) { │ │ │ │ + var y = flatPoints[i++], │ │ │ │ + x = flatPoints[i++]; │ │ │ │ + pointGeometries.push(new OpenLayers.Geometry.Point(x, y)) │ │ │ │ + } │ │ │ │ + if (this.geometryType == "point") return new OpenLayers.Feature.Vector(pointGeometries[0]); │ │ │ │ + if (this.geometryType == "polygon") return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(pointGeometries)])); │ │ │ │ + return new OpenLayers.Feature.Vector(new geomType(pointGeometries)) │ │ │ │ + }, │ │ │ │ + decode: function(encoded, dims, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var flatPoints = this.decodeDeltas(encoded, dims, factor); │ │ │ │ + var flatPointsLength = flatPoints.length; │ │ │ │ + var points = []; │ │ │ │ + for (var i = 0; i + (dims - 1) < flatPointsLength;) { │ │ │ │ + var point = []; │ │ │ │ + for (var dim = 0; dim < dims; ++dim) { │ │ │ │ + point.push(flatPoints[i++]) │ │ │ │ } │ │ │ │ - geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]) │ │ │ │ + points.push(point) │ │ │ │ } │ │ │ │ - if (geometry && this.internalProjection && this.externalProjection) { │ │ │ │ - geometry.transform(this.externalProjection, this.internalProjection) │ │ │ │ + return points │ │ │ │ + }, │ │ │ │ + write: function(features) { │ │ │ │ + var feature; │ │ │ │ + if (features.constructor == Array) feature = features[0]; │ │ │ │ + else feature = features; │ │ │ │ + var geometry = feature.geometry; │ │ │ │ + var type = geometry.CLASS_NAME.split(".")[2].toLowerCase(); │ │ │ │ + var pointGeometries; │ │ │ │ + if (type == "point") pointGeometries = new Array(geometry); │ │ │ │ + else if (type == "linestring" || type == "linearring" || type == "multipoint") pointGeometries = geometry.components; │ │ │ │ + else if (type == "polygon") pointGeometries = geometry.components[0].components; │ │ │ │ + else return null; │ │ │ │ + var flatPoints = []; │ │ │ │ + var pointGeometriesLength = pointGeometries.length; │ │ │ │ + for (var i = 0; i < pointGeometriesLength; ++i) { │ │ │ │ + var pointGeometry = pointGeometries[i]; │ │ │ │ + flatPoints.push(pointGeometry.y); │ │ │ │ + flatPoints.push(pointGeometry.x) │ │ │ │ } │ │ │ │ - return geometry │ │ │ │ + return this.encodeDeltas(flatPoints, 2) │ │ │ │ }, │ │ │ │ - createFeatureFromItem: function(item) { │ │ │ │ - var geometry = this.createGeometryFromItem(item); │ │ │ │ - var title = this._getChildValue(item, "*", "title", this.featureTitle); │ │ │ │ - var description = this._getChildValue(item, "*", "description", this._getChildValue(item, "*", "content", this._getChildValue(item, "*", "summary", this.featureDescription))); │ │ │ │ - var link = this._getChildValue(item, "*", "link"); │ │ │ │ - if (!link) { │ │ │ │ - try { │ │ │ │ - link = this.getElementsByTagNameNS(item, "*", "link")[0].getAttribute("href") │ │ │ │ - } catch (e) { │ │ │ │ - link = null │ │ │ │ + encode: function(points, dims, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var flatPoints = []; │ │ │ │ + var pointsLength = points.length; │ │ │ │ + for (var i = 0; i < pointsLength; ++i) { │ │ │ │ + var point = points[i]; │ │ │ │ + for (var dim = 0; dim < dims; ++dim) { │ │ │ │ + flatPoints.push(point[dim]) │ │ │ │ } │ │ │ │ } │ │ │ │ - var id = this._getChildValue(item, "*", "id", null); │ │ │ │ - var data = { │ │ │ │ - title: title, │ │ │ │ - description: description, │ │ │ │ - link: link │ │ │ │ - }; │ │ │ │ - var feature = new OpenLayers.Feature.Vector(geometry, data); │ │ │ │ - feature.fid = id; │ │ │ │ - return feature │ │ │ │ + return this.encodeDeltas(flatPoints, dims, factor) │ │ │ │ }, │ │ │ │ - _getChildValue: function(node, nsuri, name, def) { │ │ │ │ - var value; │ │ │ │ - var eles = this.getElementsByTagNameNS(node, nsuri, name); │ │ │ │ - if (eles && eles[0] && eles[0].firstChild && eles[0].firstChild.nodeValue) { │ │ │ │ - value = this.getChildValue(eles[0]) │ │ │ │ - } else { │ │ │ │ - value = def == undefined ? "" : def │ │ │ │ + encodeDeltas: function(numbers, dimension, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var d; │ │ │ │ + var lastNumbers = new Array(dimension); │ │ │ │ + for (d = 0; d < dimension; ++d) { │ │ │ │ + lastNumbers[d] = 0 │ │ │ │ } │ │ │ │ - return value │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength;) { │ │ │ │ + for (d = 0; d < dimension; ++d, ++i) { │ │ │ │ + var num = numbers[i]; │ │ │ │ + var delta = num - lastNumbers[d]; │ │ │ │ + lastNumbers[d] = num; │ │ │ │ + numbers[i] = delta │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return this.encodeFloats(numbers, factor) │ │ │ │ }, │ │ │ │ - read: function(doc) { │ │ │ │ - if (typeof doc == "string") { │ │ │ │ - doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]) │ │ │ │ + decodeDeltas: function(encoded, dimension, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var d; │ │ │ │ + var lastNumbers = new Array(dimension); │ │ │ │ + for (d = 0; d < dimension; ++d) { │ │ │ │ + lastNumbers[d] = 0 │ │ │ │ } │ │ │ │ - var itemlist = null; │ │ │ │ - itemlist = this.getElementsByTagNameNS(doc, "*", "item"); │ │ │ │ - if (itemlist.length == 0) { │ │ │ │ - itemlist = this.getElementsByTagNameNS(doc, "*", "entry") │ │ │ │ + var numbers = this.decodeFloats(encoded, factor); │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength;) { │ │ │ │ + for (d = 0; d < dimension; ++d, ++i) { │ │ │ │ + lastNumbers[d] += numbers[i]; │ │ │ │ + numbers[i] = lastNumbers[d] │ │ │ │ + } │ │ │ │ } │ │ │ │ - var numItems = itemlist.length; │ │ │ │ - var features = new Array(numItems); │ │ │ │ - for (var i = 0; i < numItems; i++) { │ │ │ │ - features[i] = this.createFeatureFromItem(itemlist[i]) │ │ │ │ + return numbers │ │ │ │ + }, │ │ │ │ + encodeFloats: function(numbers, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength; ++i) { │ │ │ │ + numbers[i] = Math.round(numbers[i] * factor) │ │ │ │ } │ │ │ │ - return features │ │ │ │ + return this.encodeSignedIntegers(numbers) │ │ │ │ }, │ │ │ │ - write: function(features) { │ │ │ │ - var georss; │ │ │ │ - if (OpenLayers.Util.isArray(features)) { │ │ │ │ - georss = this.createElementNS(this.rssns, "rss"); │ │ │ │ - for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ - georss.appendChild(this.createFeatureXML(features[i])) │ │ │ │ + decodeFloats: function(encoded, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var numbers = this.decodeSignedIntegers(encoded); │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength; ++i) { │ │ │ │ + numbers[i] /= factor │ │ │ │ + } │ │ │ │ + return numbers │ │ │ │ + }, │ │ │ │ + encodeSignedIntegers: function(numbers) { │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength; ++i) { │ │ │ │ + var num = numbers[i]; │ │ │ │ + var signedNum = num << 1; │ │ │ │ + if (num < 0) { │ │ │ │ + signedNum = ~signedNum │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - georss = this.createFeatureXML(features) │ │ │ │ + numbers[i] = signedNum │ │ │ │ } │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [georss]) │ │ │ │ + return this.encodeUnsignedIntegers(numbers) │ │ │ │ }, │ │ │ │ - createFeatureXML: function(feature) { │ │ │ │ - var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ - var featureNode = this.createElementNS(this.rssns, "item"); │ │ │ │ - var titleNode = this.createElementNS(this.rssns, "title"); │ │ │ │ - titleNode.appendChild(this.createTextNode(feature.attributes.title ? feature.attributes.title : "")); │ │ │ │ - var descNode = this.createElementNS(this.rssns, "description"); │ │ │ │ - descNode.appendChild(this.createTextNode(feature.attributes.description ? feature.attributes.description : "")); │ │ │ │ - featureNode.appendChild(titleNode); │ │ │ │ - featureNode.appendChild(descNode); │ │ │ │ - if (feature.attributes.link) { │ │ │ │ - var linkNode = this.createElementNS(this.rssns, "link"); │ │ │ │ - linkNode.appendChild(this.createTextNode(feature.attributes.link)); │ │ │ │ - featureNode.appendChild(linkNode) │ │ │ │ + decodeSignedIntegers: function(encoded) { │ │ │ │ + var numbers = this.decodeUnsignedIntegers(encoded); │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength; ++i) { │ │ │ │ + var num = numbers[i]; │ │ │ │ + numbers[i] = num & 1 ? ~(num >> 1) : num >> 1 │ │ │ │ } │ │ │ │ - for (var attr in feature.attributes) { │ │ │ │ - if (attr == "link" || attr == "title" || attr == "description") { │ │ │ │ - continue │ │ │ │ - } │ │ │ │ - var attrText = this.createTextNode(feature.attributes[attr]); │ │ │ │ - var nodename = attr; │ │ │ │ - if (attr.search(":") != -1) { │ │ │ │ - nodename = attr.split(":")[1] │ │ │ │ - } │ │ │ │ - var attrContainer = this.createElementNS(this.featureNS, "feature:" + nodename); │ │ │ │ - attrContainer.appendChild(attrText); │ │ │ │ - featureNode.appendChild(attrContainer) │ │ │ │ + return numbers │ │ │ │ + }, │ │ │ │ + encodeUnsignedIntegers: function(numbers) { │ │ │ │ + var encoded = ""; │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength; ++i) { │ │ │ │ + encoded += this.encodeUnsignedInteger(numbers[i]) │ │ │ │ } │ │ │ │ - featureNode.appendChild(geometryNode); │ │ │ │ - return featureNode │ │ │ │ + return encoded │ │ │ │ }, │ │ │ │ - buildGeometryNode: function(geometry) { │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - geometry = geometry.clone(); │ │ │ │ - geometry.transform(this.internalProjection, this.externalProjection) │ │ │ │ + decodeUnsignedIntegers: function(encoded) { │ │ │ │ + var numbers = []; │ │ │ │ + var current = 0; │ │ │ │ + var shift = 0; │ │ │ │ + var encodedLength = encoded.length; │ │ │ │ + for (var i = 0; i < encodedLength; ++i) { │ │ │ │ + var b = encoded.charCodeAt(i) - 63; │ │ │ │ + current |= (b & 31) << shift; │ │ │ │ + if (b < 32) { │ │ │ │ + numbers.push(current); │ │ │ │ + current = 0; │ │ │ │ + shift = 0 │ │ │ │ + } else { │ │ │ │ + shift += 5 │ │ │ │ + } │ │ │ │ } │ │ │ │ - var node; │ │ │ │ - if (geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") { │ │ │ │ - node = this.createElementNS(this.georssns, "georss:polygon"); │ │ │ │ - node.appendChild(this.buildCoordinatesNode(geometry.components[0])) │ │ │ │ - } else if (geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") { │ │ │ │ - node = this.createElementNS(this.georssns, "georss:line"); │ │ │ │ - node.appendChild(this.buildCoordinatesNode(geometry)) │ │ │ │ - } else if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { │ │ │ │ - node = this.createElementNS(this.georssns, "georss:point"); │ │ │ │ - node.appendChild(this.buildCoordinatesNode(geometry)) │ │ │ │ - } else { │ │ │ │ - throw "Couldn't parse " + geometry.CLASS_NAME │ │ │ │ + return numbers │ │ │ │ + }, │ │ │ │ + encodeFloat: function(num, opt_factor) { │ │ │ │ + num = Math.round(num * (opt_factor || 1e5)); │ │ │ │ + return this.encodeSignedInteger(num) │ │ │ │ + }, │ │ │ │ + decodeFloat: function(encoded, opt_factor) { │ │ │ │ + var result = this.decodeSignedInteger(encoded); │ │ │ │ + return result / (opt_factor || 1e5) │ │ │ │ + }, │ │ │ │ + encodeSignedInteger: function(num) { │ │ │ │ + var signedNum = num << 1; │ │ │ │ + if (num < 0) { │ │ │ │ + signedNum = ~signedNum │ │ │ │ } │ │ │ │ - return node │ │ │ │ + return this.encodeUnsignedInteger(signedNum) │ │ │ │ }, │ │ │ │ - buildCoordinatesNode: function(geometry) { │ │ │ │ - var points = null; │ │ │ │ - if (geometry.components) { │ │ │ │ - points = geometry.components │ │ │ │ + decodeSignedInteger: function(encoded) { │ │ │ │ + var result = this.decodeUnsignedInteger(encoded); │ │ │ │ + return result & 1 ? ~(result >> 1) : result >> 1 │ │ │ │ + }, │ │ │ │ + encodeUnsignedInteger: function(num) { │ │ │ │ + var value, encoded = ""; │ │ │ │ + while (num >= 32) { │ │ │ │ + value = (32 | num & 31) + 63; │ │ │ │ + encoded += String.fromCharCode(value); │ │ │ │ + num >>= 5 │ │ │ │ } │ │ │ │ - var path; │ │ │ │ - if (points) { │ │ │ │ - var numPoints = points.length; │ │ │ │ - var parts = new Array(numPoints); │ │ │ │ - for (var i = 0; i < numPoints; i++) { │ │ │ │ - parts[i] = points[i].y + " " + points[i].x │ │ │ │ - } │ │ │ │ - path = parts.join(" ") │ │ │ │ - } else { │ │ │ │ - path = geometry.y + " " + geometry.x │ │ │ │ + value = num + 63; │ │ │ │ + encoded += String.fromCharCode(value); │ │ │ │ + return encoded │ │ │ │ + }, │ │ │ │ + decodeUnsignedInteger: function(encoded) { │ │ │ │ + var result = 0; │ │ │ │ + var shift = 0; │ │ │ │ + var encodedLength = encoded.length; │ │ │ │ + for (var i = 0; i < encodedLength; ++i) { │ │ │ │ + var b = encoded.charCodeAt(i) - 63; │ │ │ │ + result |= (b & 31) << shift; │ │ │ │ + if (b < 32) break; │ │ │ │ + shift += 5 │ │ │ │ } │ │ │ │ - return this.createTextNode(path) │ │ │ │ + return result │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.GeoRSS" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.EncodedPolyline" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.CSWGetDomain = function(options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, OpenLayers.Format.CSWGetDomain.DEFAULTS); │ │ │ │ - var cls = OpenLayers.Format.CSWGetDomain["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (!cls) { │ │ │ │ - throw "Unsupported CSWGetDomain version: " + options.version │ │ │ │ - } │ │ │ │ - return new cls(options) │ │ │ │ -}; │ │ │ │ -OpenLayers.Format.CSWGetDomain.DEFAULTS = { │ │ │ │ - version: "2.0.2" │ │ │ │ -}; │ │ │ │ OpenLayers.Format.OSM = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ checkTags: false, │ │ │ │ interestingTagsExclude: null, │ │ │ │ areaTags: null, │ │ │ │ initialize: function(options) { │ │ │ │ var layer_defaults = { │ │ │ │ interestingTagsExclude: ["source", "source_ref", "source:ref", "history", "attribution", "created_by"], │ │ │ │ @@ -32635,14 +32329,957 @@ │ │ │ │ if (state) { │ │ │ │ node.setAttribute("action", state) │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.OSM" │ │ │ │ }); │ │ │ │ +OpenLayers.Format.CQL = function() { │ │ │ │ + var tokens = ["PROPERTY", "COMPARISON", "VALUE", "LOGICAL"], │ │ │ │ + patterns = { │ │ │ │ + PROPERTY: /^[_a-zA-Z]\w*/, │ │ │ │ + COMPARISON: /^(=|<>|<=|<|>=|>|LIKE)/i, │ │ │ │ + IS_NULL: /^IS NULL/i, │ │ │ │ + COMMA: /^,/, │ │ │ │ + LOGICAL: /^(AND|OR)/i, │ │ │ │ + VALUE: /^('([^']|'')*'|\d+(\.\d*)?|\.\d+)/, │ │ │ │ + LPAREN: /^\(/, │ │ │ │ + RPAREN: /^\)/, │ │ │ │ + SPATIAL: /^(BBOX|INTERSECTS|DWITHIN|WITHIN|CONTAINS)/i, │ │ │ │ + NOT: /^NOT/i, │ │ │ │ + BETWEEN: /^BETWEEN/i, │ │ │ │ + GEOMETRY: function(text) { │ │ │ │ + var type = /^(POINT|LINESTRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)/.exec(text); │ │ │ │ + if (type) { │ │ │ │ + var len = text.length; │ │ │ │ + var idx = text.indexOf("(", type[0].length); │ │ │ │ + if (idx > -1) { │ │ │ │ + var depth = 1; │ │ │ │ + while (idx < len && depth > 0) { │ │ │ │ + idx++; │ │ │ │ + switch (text.charAt(idx)) { │ │ │ │ + case "(": │ │ │ │ + depth++; │ │ │ │ + break; │ │ │ │ + case ")": │ │ │ │ + depth--; │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return [text.substr(0, idx + 1)] │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + END: /^$/ │ │ │ │ + }, │ │ │ │ + follows = { │ │ │ │ + LPAREN: ["GEOMETRY", "SPATIAL", "PROPERTY", "VALUE", "LPAREN"], │ │ │ │ + RPAREN: ["NOT", "LOGICAL", "END", "RPAREN"], │ │ │ │ + PROPERTY: ["COMPARISON", "BETWEEN", "COMMA", "IS_NULL"], │ │ │ │ + BETWEEN: ["VALUE"], │ │ │ │ + IS_NULL: ["END"], │ │ │ │ + COMPARISON: ["VALUE"], │ │ │ │ + COMMA: ["GEOMETRY", "VALUE", "PROPERTY"], │ │ │ │ + VALUE: ["LOGICAL", "COMMA", "RPAREN", "END"], │ │ │ │ + SPATIAL: ["LPAREN"], │ │ │ │ + LOGICAL: ["NOT", "VALUE", "SPATIAL", "PROPERTY", "LPAREN"], │ │ │ │ + NOT: ["PROPERTY", "LPAREN"], │ │ │ │ + GEOMETRY: ["COMMA", "RPAREN"] │ │ │ │ + }, │ │ │ │ + operators = { │ │ │ │ + "=": OpenLayers.Filter.Comparison.EQUAL_TO, │ │ │ │ + "<>": OpenLayers.Filter.Comparison.NOT_EQUAL_TO, │ │ │ │ + "<": OpenLayers.Filter.Comparison.LESS_THAN, │ │ │ │ + "<=": OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO, │ │ │ │ + ">": OpenLayers.Filter.Comparison.GREATER_THAN, │ │ │ │ + ">=": OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO, │ │ │ │ + LIKE: OpenLayers.Filter.Comparison.LIKE, │ │ │ │ + BETWEEN: OpenLayers.Filter.Comparison.BETWEEN, │ │ │ │ + "IS NULL": OpenLayers.Filter.Comparison.IS_NULL │ │ │ │ + }, │ │ │ │ + operatorReverse = {}, │ │ │ │ + logicals = { │ │ │ │ + AND: OpenLayers.Filter.Logical.AND, │ │ │ │ + OR: OpenLayers.Filter.Logical.OR │ │ │ │ + }, │ │ │ │ + logicalReverse = {}, │ │ │ │ + precedence = { │ │ │ │ + RPAREN: 3, │ │ │ │ + LOGICAL: 2, │ │ │ │ + COMPARISON: 1 │ │ │ │ + }; │ │ │ │ + var i; │ │ │ │ + for (i in operators) { │ │ │ │ + if (operators.hasOwnProperty(i)) { │ │ │ │ + operatorReverse[operators[i]] = i │ │ │ │ + } │ │ │ │ + } │ │ │ │ + for (i in logicals) { │ │ │ │ + if (logicals.hasOwnProperty(i)) { │ │ │ │ + logicalReverse[logicals[i]] = i │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + function tryToken(text, pattern) { │ │ │ │ + if (pattern instanceof RegExp) { │ │ │ │ + return pattern.exec(text) │ │ │ │ + } else { │ │ │ │ + return pattern(text) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + function nextToken(text, tokens) { │ │ │ │ + var i, token, len = tokens.length; │ │ │ │ + for (i = 0; i < len; i++) { │ │ │ │ + token = tokens[i]; │ │ │ │ + var pat = patterns[token]; │ │ │ │ + var matches = tryToken(text, pat); │ │ │ │ + if (matches) { │ │ │ │ + var match = matches[0]; │ │ │ │ + var remainder = text.substr(match.length).replace(/^\s*/, ""); │ │ │ │ + return { │ │ │ │ + type: token, │ │ │ │ + text: match, │ │ │ │ + remainder: remainder │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var msg = "ERROR: In parsing: [" + text + "], expected one of: "; │ │ │ │ + for (i = 0; i < len; i++) { │ │ │ │ + token = tokens[i]; │ │ │ │ + msg += "\n " + token + ": " + patterns[token] │ │ │ │ + } │ │ │ │ + throw new Error(msg) │ │ │ │ + } │ │ │ │ + │ │ │ │ + function tokenize(text) { │ │ │ │ + var results = []; │ │ │ │ + var token, expect = ["NOT", "GEOMETRY", "SPATIAL", "PROPERTY", "LPAREN"]; │ │ │ │ + do { │ │ │ │ + token = nextToken(text, expect); │ │ │ │ + text = token.remainder; │ │ │ │ + expect = follows[token.type]; │ │ │ │ + if (token.type != "END" && !expect) { │ │ │ │ + throw new Error("No follows list for " + token.type) │ │ │ │ + } │ │ │ │ + results.push(token) │ │ │ │ + } while (token.type != "END"); │ │ │ │ + return results │ │ │ │ + } │ │ │ │ + │ │ │ │ + function buildAst(tokens) { │ │ │ │ + var operatorStack = [], │ │ │ │ + postfix = []; │ │ │ │ + while (tokens.length) { │ │ │ │ + var tok = tokens.shift(); │ │ │ │ + switch (tok.type) { │ │ │ │ + case "PROPERTY": │ │ │ │ + case "GEOMETRY": │ │ │ │ + case "VALUE": │ │ │ │ + postfix.push(tok); │ │ │ │ + break; │ │ │ │ + case "COMPARISON": │ │ │ │ + case "BETWEEN": │ │ │ │ + case "IS_NULL": │ │ │ │ + case "LOGICAL": │ │ │ │ + var p = precedence[tok.type]; │ │ │ │ + while (operatorStack.length > 0 && precedence[operatorStack[operatorStack.length - 1].type] <= p) { │ │ │ │ + postfix.push(operatorStack.pop()) │ │ │ │ + } │ │ │ │ + operatorStack.push(tok); │ │ │ │ + break; │ │ │ │ + case "SPATIAL": │ │ │ │ + case "NOT": │ │ │ │ + case "LPAREN": │ │ │ │ + operatorStack.push(tok); │ │ │ │ + break; │ │ │ │ + case "RPAREN": │ │ │ │ + while (operatorStack.length > 0 && operatorStack[operatorStack.length - 1].type != "LPAREN") { │ │ │ │ + postfix.push(operatorStack.pop()) │ │ │ │ + } │ │ │ │ + operatorStack.pop(); │ │ │ │ + if (operatorStack.length > 0 && operatorStack[operatorStack.length - 1].type == "SPATIAL") { │ │ │ │ + postfix.push(operatorStack.pop()) │ │ │ │ + } │ │ │ │ + case "COMMA": │ │ │ │ + case "END": │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + throw new Error("Unknown token type " + tok.type) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + while (operatorStack.length > 0) { │ │ │ │ + postfix.push(operatorStack.pop()) │ │ │ │ + } │ │ │ │ + │ │ │ │ + function buildTree() { │ │ │ │ + var tok = postfix.pop(); │ │ │ │ + switch (tok.type) { │ │ │ │ + case "LOGICAL": │ │ │ │ + var rhs = buildTree(), │ │ │ │ + lhs = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Logical({ │ │ │ │ + filters: [lhs, rhs], │ │ │ │ + type: logicals[tok.text.toUpperCase()] │ │ │ │ + }); │ │ │ │ + case "NOT": │ │ │ │ + var operand = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Logical({ │ │ │ │ + filters: [operand], │ │ │ │ + type: OpenLayers.Filter.Logical.NOT │ │ │ │ + }); │ │ │ │ + case "BETWEEN": │ │ │ │ + var min, max, property; │ │ │ │ + postfix.pop(); │ │ │ │ + max = buildTree(); │ │ │ │ + min = buildTree(); │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Comparison({ │ │ │ │ + property: property, │ │ │ │ + lowerBoundary: min, │ │ │ │ + upperBoundary: max, │ │ │ │ + type: OpenLayers.Filter.Comparison.BETWEEN │ │ │ │ + }); │ │ │ │ + case "COMPARISON": │ │ │ │ + var value = buildTree(), │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Comparison({ │ │ │ │ + property: property, │ │ │ │ + value: value, │ │ │ │ + type: operators[tok.text.toUpperCase()] │ │ │ │ + }); │ │ │ │ + case "IS_NULL": │ │ │ │ + var property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Comparison({ │ │ │ │ + property: property, │ │ │ │ + type: operators[tok.text.toUpperCase()] │ │ │ │ + }); │ │ │ │ + case "VALUE": │ │ │ │ + var match = tok.text.match(/^'(.*)'$/); │ │ │ │ + if (match) { │ │ │ │ + return match[1].replace(/''/g, "'") │ │ │ │ + } else { │ │ │ │ + return Number(tok.text) │ │ │ │ + } │ │ │ │ + case "SPATIAL": │ │ │ │ + switch (tok.text.toUpperCase()) { │ │ │ │ + case "BBOX": │ │ │ │ + var maxy = buildTree(), │ │ │ │ + maxx = buildTree(), │ │ │ │ + miny = buildTree(), │ │ │ │ + minx = buildTree(), │ │ │ │ + prop = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ + property: prop, │ │ │ │ + value: OpenLayers.Bounds.fromArray([minx, miny, maxx, maxy]) │ │ │ │ + }); │ │ │ │ + case "INTERSECTS": │ │ │ │ + var value = buildTree(), │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ + property: property, │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + case "WITHIN": │ │ │ │ + var value = buildTree(), │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.WITHIN, │ │ │ │ + property: property, │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + case "CONTAINS": │ │ │ │ + var value = buildTree(), │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.CONTAINS, │ │ │ │ + property: property, │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + case "DWITHIN": │ │ │ │ + var distance = buildTree(), │ │ │ │ + value = buildTree(), │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.DWITHIN, │ │ │ │ + value: value, │ │ │ │ + property: property, │ │ │ │ + distance: Number(distance) │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + case "GEOMETRY": │ │ │ │ + return OpenLayers.Geometry.fromWKT(tok.text); │ │ │ │ + default: │ │ │ │ + return tok.text │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var result = buildTree(); │ │ │ │ + if (postfix.length > 0) { │ │ │ │ + var msg = "Remaining tokens after building AST: \n"; │ │ │ │ + for (var i = postfix.length - 1; i >= 0; i--) { │ │ │ │ + msg += postfix[i].type + ": " + postfix[i].text + "\n" │ │ │ │ + } │ │ │ │ + throw new Error(msg) │ │ │ │ + } │ │ │ │ + return result │ │ │ │ + } │ │ │ │ + return OpenLayers.Class(OpenLayers.Format, { │ │ │ │ + read: function(text) { │ │ │ │ + var result = buildAst(tokenize(text)); │ │ │ │ + if (this.keepData) { │ │ │ │ + this.data = result │ │ │ │ + } │ │ │ │ + return result │ │ │ │ + }, │ │ │ │ + write: function(filter) { │ │ │ │ + if (filter instanceof OpenLayers.Geometry) { │ │ │ │ + return filter.toString() │ │ │ │ + } │ │ │ │ + switch (filter.CLASS_NAME) { │ │ │ │ + case "OpenLayers.Filter.Spatial": │ │ │ │ + switch (filter.type) { │ │ │ │ + case OpenLayers.Filter.Spatial.BBOX: │ │ │ │ + return "BBOX(" + filter.property + "," + filter.value.toBBOX() + ")"; │ │ │ │ + case OpenLayers.Filter.Spatial.DWITHIN: │ │ │ │ + return "DWITHIN(" + filter.property + ", " + this.write(filter.value) + ", " + filter.distance + ")"; │ │ │ │ + case OpenLayers.Filter.Spatial.WITHIN: │ │ │ │ + return "WITHIN(" + filter.property + ", " + this.write(filter.value) + ")"; │ │ │ │ + case OpenLayers.Filter.Spatial.INTERSECTS: │ │ │ │ + return "INTERSECTS(" + filter.property + ", " + this.write(filter.value) + ")"; │ │ │ │ + case OpenLayers.Filter.Spatial.CONTAINS: │ │ │ │ + return "CONTAINS(" + filter.property + ", " + this.write(filter.value) + ")"; │ │ │ │ + default: │ │ │ │ + throw new Error("Unknown spatial filter type: " + filter.type) │ │ │ │ + } │ │ │ │ + case "OpenLayers.Filter.Logical": │ │ │ │ + if (filter.type == OpenLayers.Filter.Logical.NOT) { │ │ │ │ + return "NOT (" + this.write(filter.filters[0]) + ")" │ │ │ │ + } else { │ │ │ │ + var res = "("; │ │ │ │ + var first = true; │ │ │ │ + for (var i = 0; i < filter.filters.length; i++) { │ │ │ │ + if (first) { │ │ │ │ + first = false │ │ │ │ + } else { │ │ │ │ + res += ") " + logicalReverse[filter.type] + " (" │ │ │ │ + } │ │ │ │ + res += this.write(filter.filters[i]) │ │ │ │ + } │ │ │ │ + return res + ")" │ │ │ │ + } │ │ │ │ + case "OpenLayers.Filter.Comparison": │ │ │ │ + if (filter.type == OpenLayers.Filter.Comparison.BETWEEN) { │ │ │ │ + return filter.property + " BETWEEN " + this.write(filter.lowerBoundary) + " AND " + this.write(filter.upperBoundary) │ │ │ │ + } else { │ │ │ │ + return filter.value !== null ? filter.property + " " + operatorReverse[filter.type] + " " + this.write(filter.value) : filter.property + " " + operatorReverse[filter.type] │ │ │ │ + } │ │ │ │ + case undefined: │ │ │ │ + if (typeof filter === "string") { │ │ │ │ + return "'" + filter.replace(/'/g, "''") + "'" │ │ │ │ + } else if (typeof filter === "number") { │ │ │ │ + return String(filter) │ │ │ │ + } │ │ │ │ + default: │ │ │ │ + throw new Error("Can't encode: " + filter.CLASS_NAME + " " + filter) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.CQL" │ │ │ │ + }) │ │ │ │ +}(); │ │ │ │ +OpenLayers.Format.XLS = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.1.0", │ │ │ │ + stringifyOutput: true, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.XLS" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.OWSContext = OpenLayers.Class(OpenLayers.Format.Context, { │ │ │ │ + defaultVersion: "0.3.1", │ │ │ │ + getVersion: function(root, options) { │ │ │ │ + var version = OpenLayers.Format.XML.VersionedOGC.prototype.getVersion.apply(this, arguments); │ │ │ │ + if (version === "0.3.0") { │ │ │ │ + version = this.defaultVersion │ │ │ │ + } │ │ │ │ + return version │ │ │ │ + }, │ │ │ │ + toContext: function(obj) { │ │ │ │ + var context = {}; │ │ │ │ + if (obj.CLASS_NAME == "OpenLayers.Map") { │ │ │ │ + context.bounds = obj.getExtent(); │ │ │ │ + context.maxExtent = obj.maxExtent; │ │ │ │ + context.projection = obj.projection; │ │ │ │ + context.size = obj.getSize(); │ │ │ │ + context.layers = obj.layers │ │ │ │ + } │ │ │ │ + return context │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.OWSContext" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.SOSGetObservation = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + namespaces: { │ │ │ │ + ows: "http://www.opengis.net/ows", │ │ │ │ + gml: "http://www.opengis.net/gml", │ │ │ │ + sos: "http://www.opengis.net/sos/1.0", │ │ │ │ + ogc: "http://www.opengis.net/ogc", │ │ │ │ + om: "http://www.opengis.net/om/1.0", │ │ │ │ + sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + }, │ │ │ │ + regExes: { │ │ │ │ + trimSpace: /^\s*|\s*$/g, │ │ │ │ + removeSpace: /\s*/g, │ │ │ │ + splitSpace: /\s+/, │ │ │ │ + trimComma: /\s*,\s*/g │ │ │ │ + }, │ │ │ │ + VERSION: "1.0.0", │ │ │ │ + schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosGetObservation.xsd", │ │ │ │ + defaultPrefix: "sos", │ │ │ │ + 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 info = { │ │ │ │ + measurements: [], │ │ │ │ + observations: [] │ │ │ │ + }; │ │ │ │ + this.readNode(data, info); │ │ │ │ + return info │ │ │ │ + }, │ │ │ │ + write: function(options) { │ │ │ │ + var node = this.writeNode("sos:GetObservation", options); │ │ │ │ + node.setAttribute("xmlns:om", this.namespaces.om); │ │ │ │ + node.setAttribute("xmlns:ogc", this.namespaces.ogc); │ │ │ │ + this.setAttributeNS(node, this.namespaces.xsi, "xsi:schemaLocation", this.schemaLocation); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [node]) │ │ │ │ + }, │ │ │ │ + readers: { │ │ │ │ + om: { │ │ │ │ + ObservationCollection: function(node, obj) { │ │ │ │ + obj.id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + member: function(node, observationCollection) { │ │ │ │ + this.readChildNodes(node, observationCollection) │ │ │ │ + }, │ │ │ │ + Measurement: function(node, observationCollection) { │ │ │ │ + var measurement = {}; │ │ │ │ + observationCollection.measurements.push(measurement); │ │ │ │ + this.readChildNodes(node, measurement) │ │ │ │ + }, │ │ │ │ + Observation: function(node, observationCollection) { │ │ │ │ + var observation = {}; │ │ │ │ + observationCollection.observations.push(observation); │ │ │ │ + this.readChildNodes(node, observation) │ │ │ │ + }, │ │ │ │ + samplingTime: function(node, measurement) { │ │ │ │ + var samplingTime = {}; │ │ │ │ + measurement.samplingTime = samplingTime; │ │ │ │ + this.readChildNodes(node, samplingTime) │ │ │ │ + }, │ │ │ │ + observedProperty: function(node, measurement) { │ │ │ │ + measurement.observedProperty = this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ + this.readChildNodes(node, measurement) │ │ │ │ + }, │ │ │ │ + procedure: function(node, measurement) { │ │ │ │ + measurement.procedure = this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ + this.readChildNodes(node, measurement) │ │ │ │ + }, │ │ │ │ + featureOfInterest: function(node, observation) { │ │ │ │ + var foi = { │ │ │ │ + features: [] │ │ │ │ + }; │ │ │ │ + observation.fois = []; │ │ │ │ + observation.fois.push(foi); │ │ │ │ + this.readChildNodes(node, foi); │ │ │ │ + var features = []; │ │ │ │ + for (var i = 0, len = foi.features.length; i < len; i++) { │ │ │ │ + var feature = foi.features[i]; │ │ │ │ + features.push(new OpenLayers.Feature.Vector(feature.components[0], feature.attributes)) │ │ │ │ + } │ │ │ │ + foi.features = features │ │ │ │ + }, │ │ │ │ + result: function(node, measurement) { │ │ │ │ + var result = {}; │ │ │ │ + measurement.result = result; │ │ │ │ + if (this.getChildValue(node) !== "") { │ │ │ │ + result.value = this.getChildValue(node); │ │ │ │ + result.uom = node.getAttribute("uom") │ │ │ │ + } else { │ │ │ │ + this.readChildNodes(node, result) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + sa: OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.sa, │ │ │ │ + gml: OpenLayers.Util.applyDefaults({ │ │ │ │ + TimeInstant: function(node, samplingTime) { │ │ │ │ + var timeInstant = {}; │ │ │ │ + samplingTime.timeInstant = timeInstant; │ │ │ │ + this.readChildNodes(node, timeInstant) │ │ │ │ + }, │ │ │ │ + timePosition: function(node, timeInstant) { │ │ │ │ + timeInstant.timePosition = this.getChildValue(node) │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.gml) │ │ │ │ + }, │ │ │ │ + writers: { │ │ │ │ + sos: { │ │ │ │ + GetObservation: function(options) { │ │ │ │ + var node = this.createElementNSPlus("GetObservation", { │ │ │ │ + attributes: { │ │ │ │ + version: this.VERSION, │ │ │ │ + service: "SOS" │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.writeNode("offering", options, node); │ │ │ │ + if (options.eventTime) { │ │ │ │ + this.writeNode("eventTime", options, node) │ │ │ │ + } │ │ │ │ + for (var procedure in options.procedures) { │ │ │ │ + this.writeNode("procedure", options.procedures[procedure], node) │ │ │ │ + } │ │ │ │ + for (var observedProperty in options.observedProperties) { │ │ │ │ + this.writeNode("observedProperty", options.observedProperties[observedProperty], node) │ │ │ │ + } │ │ │ │ + if (options.foi) { │ │ │ │ + this.writeNode("featureOfInterest", options.foi, node) │ │ │ │ + } │ │ │ │ + this.writeNode("responseFormat", options, node); │ │ │ │ + if (options.resultModel) { │ │ │ │ + this.writeNode("resultModel", options, node) │ │ │ │ + } │ │ │ │ + if (options.responseMode) { │ │ │ │ + this.writeNode("responseMode", options, node) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + featureOfInterest: function(foi) { │ │ │ │ + var node = this.createElementNSPlus("featureOfInterest"); │ │ │ │ + this.writeNode("ObjectID", foi.objectId, node); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + ObjectID: function(options) { │ │ │ │ + return this.createElementNSPlus("ObjectID", { │ │ │ │ + value: options │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + responseFormat: function(options) { │ │ │ │ + return this.createElementNSPlus("responseFormat", { │ │ │ │ + value: options.responseFormat │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + procedure: function(procedure) { │ │ │ │ + return this.createElementNSPlus("procedure", { │ │ │ │ + value: procedure │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + offering: function(options) { │ │ │ │ + return this.createElementNSPlus("offering", { │ │ │ │ + value: options.offering │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + observedProperty: function(observedProperty) { │ │ │ │ + return this.createElementNSPlus("observedProperty", { │ │ │ │ + value: observedProperty │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + eventTime: function(options) { │ │ │ │ + var node = this.createElementNSPlus("eventTime"); │ │ │ │ + if (options.eventTime === "latest") { │ │ │ │ + this.writeNode("ogc:TM_Equals", options, node) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + resultModel: function(options) { │ │ │ │ + return this.createElementNSPlus("resultModel", { │ │ │ │ + value: options.resultModel │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + responseMode: function(options) { │ │ │ │ + return this.createElementNSPlus("responseMode", { │ │ │ │ + value: options.responseMode │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + ogc: { │ │ │ │ + TM_Equals: function(options) { │ │ │ │ + var node = this.createElementNSPlus("ogc:TM_Equals"); │ │ │ │ + this.writeNode("ogc:PropertyName", { │ │ │ │ + property: "urn:ogc:data:time:iso8601" │ │ │ │ + }, node); │ │ │ │ + if (options.eventTime === "latest") { │ │ │ │ + this.writeNode("gml:TimeInstant", { │ │ │ │ + value: "latest" │ │ │ │ + }, node) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + PropertyName: function(options) { │ │ │ │ + return this.createElementNSPlus("ogc:PropertyName", { │ │ │ │ + value: options.property │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + gml: { │ │ │ │ + TimeInstant: function(options) { │ │ │ │ + var node = this.createElementNSPlus("gml:TimeInstant"); │ │ │ │ + this.writeNode("gml:timePosition", options, node); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + timePosition: function(options) { │ │ │ │ + var node = this.createElementNSPlus("gml:timePosition", { │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SOSGetObservation" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WMTSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.0.0", │ │ │ │ + yx: { │ │ │ │ + "urn:ogc:def:crs:EPSG::4326": true │ │ │ │ + }, │ │ │ │ + createLayer: function(capabilities, config) { │ │ │ │ + var layer; │ │ │ │ + if (!("layer" in config)) { │ │ │ │ + throw new Error("Missing property 'layer' in configuration.") │ │ │ │ + } │ │ │ │ + var contents = capabilities.contents; │ │ │ │ + var layers = contents.layers; │ │ │ │ + var layerDef; │ │ │ │ + for (var i = 0, ii = contents.layers.length; i < ii; ++i) { │ │ │ │ + if (contents.layers[i].identifier === config.layer) { │ │ │ │ + layerDef = contents.layers[i]; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (!layerDef) { │ │ │ │ + throw new Error("Layer not found") │ │ │ │ + } │ │ │ │ + var format = config.format; │ │ │ │ + if (!format && layerDef.formats && layerDef.formats.length) { │ │ │ │ + format = layerDef.formats[0] │ │ │ │ + } │ │ │ │ + var matrixSet; │ │ │ │ + if (config.matrixSet) { │ │ │ │ + matrixSet = contents.tileMatrixSets[config.matrixSet] │ │ │ │ + } else if (layerDef.tileMatrixSetLinks.length >= 1) { │ │ │ │ + matrixSet = contents.tileMatrixSets[layerDef.tileMatrixSetLinks[0].tileMatrixSet] │ │ │ │ + } │ │ │ │ + if (!matrixSet) { │ │ │ │ + throw new Error("matrixSet not found") │ │ │ │ + } │ │ │ │ + var style; │ │ │ │ + for (var i = 0, ii = layerDef.styles.length; i < ii; ++i) { │ │ │ │ + style = layerDef.styles[i]; │ │ │ │ + if (style.isDefault) { │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var requestEncoding = config.requestEncoding; │ │ │ │ + if (!requestEncoding) { │ │ │ │ + requestEncoding = "KVP"; │ │ │ │ + if (capabilities.operationsMetadata.GetTile.dcp.http) { │ │ │ │ + var http = capabilities.operationsMetadata.GetTile.dcp.http; │ │ │ │ + if (http.get[0].constraints) { │ │ │ │ + var constraints = http.get[0].constraints; │ │ │ │ + var allowedValues = constraints.GetEncoding.allowedValues; │ │ │ │ + if (!allowedValues.KVP && (allowedValues.REST || allowedValues.RESTful)) { │ │ │ │ + requestEncoding = "REST" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var dimensions = []; │ │ │ │ + var params = config.params || {}; │ │ │ │ + delete config.params; │ │ │ │ + for (var id = 0, ld = layerDef.dimensions.length; id < ld; id++) { │ │ │ │ + var dimension = layerDef.dimensions[id]; │ │ │ │ + dimensions.push(dimension.identifier); │ │ │ │ + if (!params.hasOwnProperty(dimension.identifier)) { │ │ │ │ + params[dimension.identifier] = dimension["default"] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var projection = config.projection || matrixSet.supportedCRS.replace(/urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, "$1:$3"); │ │ │ │ + var units = config.units || (projection === "EPSG:4326" ? "degrees" : "m"); │ │ │ │ + var resolutions = []; │ │ │ │ + for (var mid in matrixSet.matrixIds) { │ │ │ │ + if (matrixSet.matrixIds.hasOwnProperty(mid)) { │ │ │ │ + resolutions.push(matrixSet.matrixIds[mid].scaleDenominator * 28e-5 / OpenLayers.METERS_PER_INCH / OpenLayers.INCHES_PER_UNIT[units]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var url; │ │ │ │ + if (requestEncoding === "REST" && layerDef.resourceUrls) { │ │ │ │ + url = []; │ │ │ │ + var resourceUrls = layerDef.resourceUrls, │ │ │ │ + resourceUrl; │ │ │ │ + for (var t = 0, tt = layerDef.resourceUrls.length; t < tt; ++t) { │ │ │ │ + resourceUrl = layerDef.resourceUrls[t]; │ │ │ │ + if (resourceUrl.format === format && resourceUrl.resourceType === "tile") { │ │ │ │ + url.push(resourceUrl.template) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + var httpGet = capabilities.operationsMetadata.GetTile.dcp.http.get; │ │ │ │ + url = []; │ │ │ │ + var constraint; │ │ │ │ + for (var i = 0, ii = httpGet.length; i < ii; i++) { │ │ │ │ + constraint = httpGet[i].constraints; │ │ │ │ + if (!constraint || constraint && constraint.GetEncoding.allowedValues[requestEncoding]) { │ │ │ │ + url.push(httpGet[i].url) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return new OpenLayers.Layer.WMTS(OpenLayers.Util.applyDefaults(config, { │ │ │ │ + url: url, │ │ │ │ + requestEncoding: requestEncoding, │ │ │ │ + name: layerDef.title, │ │ │ │ + style: style.identifier, │ │ │ │ + format: format, │ │ │ │ + matrixIds: matrixSet.matrixIds, │ │ │ │ + matrixSet: matrixSet.identifier, │ │ │ │ + projection: projection, │ │ │ │ + units: units, │ │ │ │ + resolutions: config.isBaseLayer === false ? undefined : resolutions, │ │ │ │ + serverResolutions: resolutions, │ │ │ │ + tileFullExtent: matrixSet.bounds, │ │ │ │ + dimensions: dimensions, │ │ │ │ + params: params │ │ │ │ + })) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMTSCapabilities" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.GeoRSS = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + rssns: "http://backend.userland.com/rss2", │ │ │ │ + featureNS: "http://mapserver.gis.umn.edu/mapserver", │ │ │ │ + georssns: "http://www.georss.org/georss", │ │ │ │ + geons: "http://www.w3.org/2003/01/geo/wgs84_pos#", │ │ │ │ + featureTitle: "Untitled", │ │ │ │ + featureDescription: "No Description", │ │ │ │ + gmlParser: null, │ │ │ │ + xy: false, │ │ │ │ + createGeometryFromItem: function(item) { │ │ │ │ + var point = this.getElementsByTagNameNS(item, this.georssns, "point"); │ │ │ │ + var lat = this.getElementsByTagNameNS(item, this.geons, "lat"); │ │ │ │ + var lon = this.getElementsByTagNameNS(item, this.geons, "long"); │ │ │ │ + var line = this.getElementsByTagNameNS(item, this.georssns, "line"); │ │ │ │ + var polygon = this.getElementsByTagNameNS(item, this.georssns, "polygon"); │ │ │ │ + var where = this.getElementsByTagNameNS(item, this.georssns, "where"); │ │ │ │ + var box = this.getElementsByTagNameNS(item, this.georssns, "box"); │ │ │ │ + if (point.length > 0 || lat.length > 0 && lon.length > 0) { │ │ │ │ + var location; │ │ │ │ + if (point.length > 0) { │ │ │ │ + location = OpenLayers.String.trim(point[0].firstChild.nodeValue).split(/\s+/); │ │ │ │ + if (location.length != 2) { │ │ │ │ + location = OpenLayers.String.trim(point[0].firstChild.nodeValue).split(/\s*,\s*/) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + location = [parseFloat(lat[0].firstChild.nodeValue), parseFloat(lon[0].firstChild.nodeValue)] │ │ │ │ + } │ │ │ │ + var geometry = new OpenLayers.Geometry.Point(location[1], location[0]) │ │ │ │ + } else if (line.length > 0) { │ │ │ │ + var coords = OpenLayers.String.trim(this.getChildValue(line[0])).split(/\s+/); │ │ │ │ + var components = []; │ │ │ │ + var point; │ │ │ │ + for (var i = 0, len = coords.length; i < len; i += 2) { │ │ │ │ + point = new OpenLayers.Geometry.Point(coords[i + 1], coords[i]); │ │ │ │ + components.push(point) │ │ │ │ + } │ │ │ │ + geometry = new OpenLayers.Geometry.LineString(components) │ │ │ │ + } else if (polygon.length > 0) { │ │ │ │ + var coords = OpenLayers.String.trim(this.getChildValue(polygon[0])).split(/\s+/); │ │ │ │ + var components = []; │ │ │ │ + var point; │ │ │ │ + for (var i = 0, len = coords.length; i < len; i += 2) { │ │ │ │ + point = new OpenLayers.Geometry.Point(coords[i + 1], coords[i]); │ │ │ │ + components.push(point) │ │ │ │ + } │ │ │ │ + geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]) │ │ │ │ + } else if (where.length > 0) { │ │ │ │ + if (!this.gmlParser) { │ │ │ │ + this.gmlParser = new OpenLayers.Format.GML({ │ │ │ │ + xy: this.xy │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + var feature = this.gmlParser.parseFeature(where[0]); │ │ │ │ + geometry = feature.geometry │ │ │ │ + } else if (box.length > 0) { │ │ │ │ + var coords = OpenLayers.String.trim(box[0].firstChild.nodeValue).split(/\s+/); │ │ │ │ + var components = []; │ │ │ │ + var point; │ │ │ │ + if (coords.length > 3) { │ │ │ │ + point = new OpenLayers.Geometry.Point(coords[1], coords[0]); │ │ │ │ + components.push(point); │ │ │ │ + point = new OpenLayers.Geometry.Point(coords[1], coords[2]); │ │ │ │ + components.push(point); │ │ │ │ + point = new OpenLayers.Geometry.Point(coords[3], coords[2]); │ │ │ │ + components.push(point); │ │ │ │ + point = new OpenLayers.Geometry.Point(coords[3], coords[0]); │ │ │ │ + components.push(point); │ │ │ │ + point = new OpenLayers.Geometry.Point(coords[1], coords[0]); │ │ │ │ + components.push(point) │ │ │ │ + } │ │ │ │ + geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]) │ │ │ │ + } │ │ │ │ + if (geometry && this.internalProjection && this.externalProjection) { │ │ │ │ + geometry.transform(this.externalProjection, this.internalProjection) │ │ │ │ + } │ │ │ │ + return geometry │ │ │ │ + }, │ │ │ │ + createFeatureFromItem: function(item) { │ │ │ │ + var geometry = this.createGeometryFromItem(item); │ │ │ │ + var title = this._getChildValue(item, "*", "title", this.featureTitle); │ │ │ │ + var description = this._getChildValue(item, "*", "description", this._getChildValue(item, "*", "content", this._getChildValue(item, "*", "summary", this.featureDescription))); │ │ │ │ + var link = this._getChildValue(item, "*", "link"); │ │ │ │ + if (!link) { │ │ │ │ + try { │ │ │ │ + link = this.getElementsByTagNameNS(item, "*", "link")[0].getAttribute("href") │ │ │ │ + } catch (e) { │ │ │ │ + link = null │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var id = this._getChildValue(item, "*", "id", null); │ │ │ │ + var data = { │ │ │ │ + title: title, │ │ │ │ + description: description, │ │ │ │ + link: link │ │ │ │ + }; │ │ │ │ + var feature = new OpenLayers.Feature.Vector(geometry, data); │ │ │ │ + feature.fid = id; │ │ │ │ + return feature │ │ │ │ + }, │ │ │ │ + _getChildValue: function(node, nsuri, name, def) { │ │ │ │ + var value; │ │ │ │ + var eles = this.getElementsByTagNameNS(node, nsuri, name); │ │ │ │ + if (eles && eles[0] && eles[0].firstChild && eles[0].firstChild.nodeValue) { │ │ │ │ + value = this.getChildValue(eles[0]) │ │ │ │ + } else { │ │ │ │ + value = def == undefined ? "" : def │ │ │ │ + } │ │ │ │ + return value │ │ │ │ + }, │ │ │ │ + read: function(doc) { │ │ │ │ + if (typeof doc == "string") { │ │ │ │ + doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]) │ │ │ │ + } │ │ │ │ + var itemlist = null; │ │ │ │ + itemlist = this.getElementsByTagNameNS(doc, "*", "item"); │ │ │ │ + if (itemlist.length == 0) { │ │ │ │ + itemlist = this.getElementsByTagNameNS(doc, "*", "entry") │ │ │ │ + } │ │ │ │ + var numItems = itemlist.length; │ │ │ │ + var features = new Array(numItems); │ │ │ │ + for (var i = 0; i < numItems; i++) { │ │ │ │ + features[i] = this.createFeatureFromItem(itemlist[i]) │ │ │ │ + } │ │ │ │ + return features │ │ │ │ + }, │ │ │ │ + write: function(features) { │ │ │ │ + var georss; │ │ │ │ + if (OpenLayers.Util.isArray(features)) { │ │ │ │ + georss = this.createElementNS(this.rssns, "rss"); │ │ │ │ + for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ + georss.appendChild(this.createFeatureXML(features[i])) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + georss = this.createFeatureXML(features) │ │ │ │ + } │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [georss]) │ │ │ │ + }, │ │ │ │ + createFeatureXML: function(feature) { │ │ │ │ + var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ + var featureNode = this.createElementNS(this.rssns, "item"); │ │ │ │ + var titleNode = this.createElementNS(this.rssns, "title"); │ │ │ │ + titleNode.appendChild(this.createTextNode(feature.attributes.title ? feature.attributes.title : "")); │ │ │ │ + var descNode = this.createElementNS(this.rssns, "description"); │ │ │ │ + descNode.appendChild(this.createTextNode(feature.attributes.description ? feature.attributes.description : "")); │ │ │ │ + featureNode.appendChild(titleNode); │ │ │ │ + featureNode.appendChild(descNode); │ │ │ │ + if (feature.attributes.link) { │ │ │ │ + var linkNode = this.createElementNS(this.rssns, "link"); │ │ │ │ + linkNode.appendChild(this.createTextNode(feature.attributes.link)); │ │ │ │ + featureNode.appendChild(linkNode) │ │ │ │ + } │ │ │ │ + for (var attr in feature.attributes) { │ │ │ │ + if (attr == "link" || attr == "title" || attr == "description") { │ │ │ │ + continue │ │ │ │ + } │ │ │ │ + var attrText = this.createTextNode(feature.attributes[attr]); │ │ │ │ + var nodename = attr; │ │ │ │ + if (attr.search(":") != -1) { │ │ │ │ + nodename = attr.split(":")[1] │ │ │ │ + } │ │ │ │ + var attrContainer = this.createElementNS(this.featureNS, "feature:" + nodename); │ │ │ │ + attrContainer.appendChild(attrText); │ │ │ │ + featureNode.appendChild(attrContainer) │ │ │ │ + } │ │ │ │ + featureNode.appendChild(geometryNode); │ │ │ │ + return featureNode │ │ │ │ + }, │ │ │ │ + buildGeometryNode: function(geometry) { │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + geometry = geometry.clone(); │ │ │ │ + geometry.transform(this.internalProjection, this.externalProjection) │ │ │ │ + } │ │ │ │ + var node; │ │ │ │ + if (geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") { │ │ │ │ + node = this.createElementNS(this.georssns, "georss:polygon"); │ │ │ │ + node.appendChild(this.buildCoordinatesNode(geometry.components[0])) │ │ │ │ + } else if (geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") { │ │ │ │ + node = this.createElementNS(this.georssns, "georss:line"); │ │ │ │ + node.appendChild(this.buildCoordinatesNode(geometry)) │ │ │ │ + } else if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { │ │ │ │ + node = this.createElementNS(this.georssns, "georss:point"); │ │ │ │ + node.appendChild(this.buildCoordinatesNode(geometry)) │ │ │ │ + } else { │ │ │ │ + throw "Couldn't parse " + geometry.CLASS_NAME │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + buildCoordinatesNode: function(geometry) { │ │ │ │ + var points = null; │ │ │ │ + if (geometry.components) { │ │ │ │ + points = geometry.components │ │ │ │ + } │ │ │ │ + var path; │ │ │ │ + if (points) { │ │ │ │ + var numPoints = points.length; │ │ │ │ + var parts = new Array(numPoints); │ │ │ │ + for (var i = 0; i < numPoints; i++) { │ │ │ │ + parts[i] = points[i].y + " " + points[i].x │ │ │ │ + } │ │ │ │ + path = parts.join(" ") │ │ │ │ + } else { │ │ │ │ + path = geometry.y + " " + geometry.x │ │ │ │ + } │ │ │ │ + return this.createTextNode(path) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.GeoRSS" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WFSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.1.0", │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.CSWGetDomain = function(options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, OpenLayers.Format.CSWGetDomain.DEFAULTS); │ │ │ │ + var cls = OpenLayers.Format.CSWGetDomain["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (!cls) { │ │ │ │ + throw "Unsupported CSWGetDomain version: " + options.version │ │ │ │ + } │ │ │ │ + return new cls(options) │ │ │ │ +}; │ │ │ │ +OpenLayers.Format.CSWGetDomain.DEFAULTS = { │ │ │ │ + version: "2.0.2" │ │ │ │ +}; │ │ │ │ OpenLayers.Format.GPX = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ defaultDesc: "No description available", │ │ │ │ extractWaypoints: true, │ │ │ │ extractTracks: true, │ │ │ │ extractRoutes: true, │ │ │ │ extractAttributes: true, │ │ │ │ namespaces: { │ │ │ │ @@ -32814,43 +33451,129 @@ │ │ │ │ node.appendChild(name); │ │ │ │ var desc = this.createElementNS(this.namespaces.gpx, "desc"); │ │ │ │ desc.appendChild(this.createTextNode(feature.attributes.description || this.defaultDesc)); │ │ │ │ node.appendChild(desc) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.GPX" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.WCSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.1.0", │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.OWSContext = OpenLayers.Class(OpenLayers.Format.Context, { │ │ │ │ - defaultVersion: "0.3.1", │ │ │ │ - getVersion: function(root, options) { │ │ │ │ - var version = OpenLayers.Format.XML.VersionedOGC.prototype.getVersion.apply(this, arguments); │ │ │ │ - if (version === "0.3.0") { │ │ │ │ - version = this.defaultVersion │ │ │ │ +OpenLayers.Format.WFS = OpenLayers.Class(OpenLayers.Format.GML, { │ │ │ │ + layer: null, │ │ │ │ + wfsns: "http://www.opengis.net/wfs", │ │ │ │ + ogcns: "http://www.opengis.net/ogc", │ │ │ │ + initialize: function(options, layer) { │ │ │ │ + OpenLayers.Format.GML.prototype.initialize.apply(this, [options]); │ │ │ │ + this.layer = layer; │ │ │ │ + if (this.layer.featureNS) { │ │ │ │ + this.featureNS = this.layer.featureNS │ │ │ │ + } │ │ │ │ + if (this.layer.options.geometry_column) { │ │ │ │ + this.geometryName = this.layer.options.geometry_column │ │ │ │ + } │ │ │ │ + if (this.layer.options.typename) { │ │ │ │ + this.featureName = this.layer.options.typename │ │ │ │ } │ │ │ │ - return version │ │ │ │ }, │ │ │ │ - toContext: function(obj) { │ │ │ │ - var context = {}; │ │ │ │ - if (obj.CLASS_NAME == "OpenLayers.Map") { │ │ │ │ - context.bounds = obj.getExtent(); │ │ │ │ - context.maxExtent = obj.maxExtent; │ │ │ │ - context.projection = obj.projection; │ │ │ │ - context.size = obj.getSize(); │ │ │ │ - context.layers = obj.layers │ │ │ │ + write: function(features) { │ │ │ │ + var transaction = this.createElementNS(this.wfsns, "wfs:Transaction"); │ │ │ │ + transaction.setAttribute("version", "1.0.0"); │ │ │ │ + transaction.setAttribute("service", "WFS"); │ │ │ │ + for (var i = 0; i < features.length; i++) { │ │ │ │ + switch (features[i].state) { │ │ │ │ + case OpenLayers.State.INSERT: │ │ │ │ + transaction.appendChild(this.insert(features[i])); │ │ │ │ + break; │ │ │ │ + case OpenLayers.State.UPDATE: │ │ │ │ + transaction.appendChild(this.update(features[i])); │ │ │ │ + break; │ │ │ │ + case OpenLayers.State.DELETE: │ │ │ │ + transaction.appendChild(this.remove(features[i])); │ │ │ │ + break │ │ │ │ + } │ │ │ │ } │ │ │ │ - return context │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [transaction]) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.OWSContext" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WFSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.1.0", │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities" │ │ │ │ + createFeatureXML: function(feature) { │ │ │ │ + var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ + var geomContainer = this.createElementNS(this.featureNS, "feature:" + this.geometryName); │ │ │ │ + geomContainer.appendChild(geometryNode); │ │ │ │ + var featureContainer = this.createElementNS(this.featureNS, "feature:" + this.featureName); │ │ │ │ + featureContainer.appendChild(geomContainer); │ │ │ │ + for (var attr in feature.attributes) { │ │ │ │ + var attrText = this.createTextNode(feature.attributes[attr]); │ │ │ │ + var nodename = attr; │ │ │ │ + if (attr.search(":") != -1) { │ │ │ │ + nodename = attr.split(":")[1] │ │ │ │ + } │ │ │ │ + var attrContainer = this.createElementNS(this.featureNS, "feature:" + nodename); │ │ │ │ + attrContainer.appendChild(attrText); │ │ │ │ + featureContainer.appendChild(attrContainer) │ │ │ │ + } │ │ │ │ + return featureContainer │ │ │ │ + }, │ │ │ │ + insert: function(feature) { │ │ │ │ + var insertNode = this.createElementNS(this.wfsns, "wfs:Insert"); │ │ │ │ + insertNode.appendChild(this.createFeatureXML(feature)); │ │ │ │ + return insertNode │ │ │ │ + }, │ │ │ │ + update: function(feature) { │ │ │ │ + if (!feature.fid) { │ │ │ │ + OpenLayers.Console.userError(OpenLayers.i18n("noFID")) │ │ │ │ + } │ │ │ │ + var updateNode = this.createElementNS(this.wfsns, "wfs:Update"); │ │ │ │ + updateNode.setAttribute("typeName", this.featurePrefix + ":" + this.featureName); │ │ │ │ + updateNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ + var propertyNode = this.createElementNS(this.wfsns, "wfs:Property"); │ │ │ │ + var nameNode = this.createElementNS(this.wfsns, "wfs:Name"); │ │ │ │ + var txtNode = this.createTextNode(this.geometryName); │ │ │ │ + nameNode.appendChild(txtNode); │ │ │ │ + propertyNode.appendChild(nameNode); │ │ │ │ + var valueNode = this.createElementNS(this.wfsns, "wfs:Value"); │ │ │ │ + var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ + if (feature.layer) { │ │ │ │ + geometryNode.setAttribute("srsName", feature.layer.projection.getCode()) │ │ │ │ + } │ │ │ │ + valueNode.appendChild(geometryNode); │ │ │ │ + propertyNode.appendChild(valueNode); │ │ │ │ + updateNode.appendChild(propertyNode); │ │ │ │ + for (var propName in feature.attributes) { │ │ │ │ + propertyNode = this.createElementNS(this.wfsns, "wfs:Property"); │ │ │ │ + nameNode = this.createElementNS(this.wfsns, "wfs:Name"); │ │ │ │ + nameNode.appendChild(this.createTextNode(propName)); │ │ │ │ + propertyNode.appendChild(nameNode); │ │ │ │ + valueNode = this.createElementNS(this.wfsns, "wfs:Value"); │ │ │ │ + valueNode.appendChild(this.createTextNode(feature.attributes[propName])); │ │ │ │ + propertyNode.appendChild(valueNode); │ │ │ │ + updateNode.appendChild(propertyNode) │ │ │ │ + } │ │ │ │ + var filterNode = this.createElementNS(this.ogcns, "ogc:Filter"); │ │ │ │ + var filterIdNode = this.createElementNS(this.ogcns, "ogc:FeatureId"); │ │ │ │ + filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ + filterNode.appendChild(filterIdNode); │ │ │ │ + updateNode.appendChild(filterNode); │ │ │ │ + return updateNode │ │ │ │ + }, │ │ │ │ + remove: function(feature) { │ │ │ │ + if (!feature.fid) { │ │ │ │ + OpenLayers.Console.userError(OpenLayers.i18n("noFID")); │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + var deleteNode = this.createElementNS(this.wfsns, "wfs:Delete"); │ │ │ │ + deleteNode.setAttribute("typeName", this.featurePrefix + ":" + this.featureName); │ │ │ │ + deleteNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ + var filterNode = this.createElementNS(this.ogcns, "ogc:Filter"); │ │ │ │ + var filterIdNode = this.createElementNS(this.ogcns, "ogc:FeatureId"); │ │ │ │ + filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ + filterNode.appendChild(filterIdNode); │ │ │ │ + deleteNode.appendChild(filterNode); │ │ │ │ + return deleteNode │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.layer = null │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFS" │ │ │ │ }); │ │ │ │ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ namespaces: { │ │ │ │ kml: "http://www.opengis.net/kml/2.2", │ │ │ │ gx: "http://www.google.com/kml/ext/2.2" │ │ │ │ }, │ │ │ │ kmlns: "http://earth.google.com/kml/2.0", │ │ │ │ @@ -33477,1574 +34200,352 @@ │ │ │ │ var folderNameText = this.createTextNode(this.foldersName); │ │ │ │ folderName.appendChild(folderNameText); │ │ │ │ folder.appendChild(folderName) │ │ │ │ } │ │ │ │ if (this.foldersDesc) { │ │ │ │ var folderDesc = this.createElementNS(this.kmlns, "description"); │ │ │ │ var folderDescText = this.createTextNode(this.foldersDesc); │ │ │ │ - folderDesc.appendChild(folderDescText); │ │ │ │ - folder.appendChild(folderDesc) │ │ │ │ - } │ │ │ │ - return folder │ │ │ │ - }, │ │ │ │ - createPlacemarkXML: function(feature) { │ │ │ │ - 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)); │ │ │ │ - var placemarkDesc = this.createElementNS(this.kmlns, "description"); │ │ │ │ - var desc = feature.attributes.description || this.placemarksDesc; │ │ │ │ - placemarkDesc.appendChild(this.createTextNode(desc)); │ │ │ │ - var placemarkNode = this.createElementNS(this.kmlns, "Placemark"); │ │ │ │ - if (feature.fid != null) { │ │ │ │ - placemarkNode.setAttribute("id", feature.fid) │ │ │ │ - } │ │ │ │ - placemarkNode.appendChild(placemarkName); │ │ │ │ - placemarkNode.appendChild(placemarkDesc); │ │ │ │ - var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ - placemarkNode.appendChild(geometryNode); │ │ │ │ - if (feature.attributes) { │ │ │ │ - var edNode = this.buildExtendedData(feature.attributes); │ │ │ │ - if (edNode) { │ │ │ │ - placemarkNode.appendChild(edNode) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return placemarkNode │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - buildGeometry: { │ │ │ │ - point: function(geometry) { │ │ │ │ - var kml = this.createElementNS(this.kmlns, "Point"); │ │ │ │ - kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ - return kml │ │ │ │ - }, │ │ │ │ - multipoint: function(geometry) { │ │ │ │ - return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ - }, │ │ │ │ - linestring: function(geometry) { │ │ │ │ - var kml = this.createElementNS(this.kmlns, "LineString"); │ │ │ │ - kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ - return kml │ │ │ │ - }, │ │ │ │ - multilinestring: function(geometry) { │ │ │ │ - return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ - }, │ │ │ │ - linearring: function(geometry) { │ │ │ │ - var kml = this.createElementNS(this.kmlns, "LinearRing"); │ │ │ │ - kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ - return kml │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - multipolygon: function(geometry) { │ │ │ │ - return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - buildCoordinatesNode: function(geometry) { │ │ │ │ - var coordinatesNode = this.createElementNS(this.kmlns, "coordinates"); │ │ │ │ - var path; │ │ │ │ - var points = geometry.components; │ │ │ │ - if (points) { │ │ │ │ - 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 { │ │ │ │ - path = this.buildCoordinates(geometry) │ │ │ │ - } │ │ │ │ - var txtNode = this.createTextNode(path); │ │ │ │ - coordinatesNode.appendChild(txtNode); │ │ │ │ - return coordinatesNode │ │ │ │ - }, │ │ │ │ - buildCoordinates: function(point) { │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - point = point.clone(); │ │ │ │ - point.transform(this.internalProjection, this.externalProjection) │ │ │ │ - } │ │ │ │ - return point.x + "," + point.y │ │ │ │ - }, │ │ │ │ - buildExtendedData: function(attributes) { │ │ │ │ - var extendedData = this.createElementNS(this.kmlns, "ExtendedData"); │ │ │ │ - for (var attributeName in attributes) { │ │ │ │ - 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") { │ │ │ │ - if (attributes[attributeName].value) { │ │ │ │ - value.appendChild(this.createTextNode(attributes[attributeName].value)) │ │ │ │ - } │ │ │ │ - if (attributes[attributeName].displayName) { │ │ │ │ - var displayName = this.createElementNS(this.kmlns, "displayName"); │ │ │ │ - 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.Format.WMSDescribeLayer = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.1.1", │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.XLS = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.1.0", │ │ │ │ - stringifyOutput: true, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.XLS" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.SOSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.0.0", │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SOSCapabilities" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WFST.v1_0_0 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, OpenLayers.Format.WFST.v1, { │ │ │ │ - version: "1.0.0", │ │ │ │ - srsNameInQuery: false, │ │ │ │ - schemaLocations: { │ │ │ │ - wfs: "http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd" │ │ │ │ - }, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this, [options]); │ │ │ │ - OpenLayers.Format.WFST.v1.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - readNode: function(node, obj, first) { │ │ │ │ - return OpenLayers.Format.GML.v2.prototype.readNode.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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"] │ │ │ │ - }, │ │ │ │ - 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.Format.ArcXML.Features = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - read: function(data) { │ │ │ │ - var axl = new OpenLayers.Format.ArcXML; │ │ │ │ - var parsed = axl.read(data); │ │ │ │ - return parsed.features.feature │ │ │ │ - } │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSDescribeLayer.v1_1_1 = OpenLayers.Class(OpenLayers.Format.WMSDescribeLayer, { │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.WMSDescribeLayer.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ - } │ │ │ │ - var root = data.documentElement; │ │ │ │ - var children = root.childNodes; │ │ │ │ - var describelayer = { │ │ │ │ - layerDescriptions: [] │ │ │ │ - }; │ │ │ │ - var childNode, nodeName; │ │ │ │ - for (var i = 0; i < children.length; ++i) { │ │ │ │ - childNode = children[i]; │ │ │ │ - nodeName = childNode.nodeName; │ │ │ │ - if (nodeName == "LayerDescription") { │ │ │ │ - var layerName = childNode.getAttribute("name"); │ │ │ │ - var owsType = ""; │ │ │ │ - var owsURL = ""; │ │ │ │ - var typeName = ""; │ │ │ │ - if (childNode.getAttribute("owsType")) { │ │ │ │ - owsType = childNode.getAttribute("owsType"); │ │ │ │ - owsURL = childNode.getAttribute("owsURL") │ │ │ │ - } else { │ │ │ │ - if (childNode.getAttribute("wfs") != "") { │ │ │ │ - owsType = "WFS"; │ │ │ │ - owsURL = childNode.getAttribute("wfs") │ │ │ │ - } else if (childNode.getAttribute("wcs") != "") { │ │ │ │ - owsType = "WCS"; │ │ │ │ - owsURL = childNode.getAttribute("wcs") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var query = childNode.getElementsByTagName("Query"); │ │ │ │ - if (query.length > 0) { │ │ │ │ - typeName = query[0].getAttribute("typeName"); │ │ │ │ - if (!typeName) { │ │ │ │ - typeName = query[0].getAttribute("typename") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var layerDescription = { │ │ │ │ - layerName: layerName, │ │ │ │ - owsType: owsType, │ │ │ │ - owsURL: owsURL, │ │ │ │ - typeName: typeName │ │ │ │ - }; │ │ │ │ - describelayer.layerDescriptions.push(layerDescription); │ │ │ │ - describelayer.length = describelayer.layerDescriptions.length; │ │ │ │ - describelayer[describelayer.length - 1] = layerDescription │ │ │ │ - } else if (nodeName == "ServiceException") { │ │ │ │ - var parser = new OpenLayers.Format.OGCExceptionReport; │ │ │ │ - return { │ │ │ │ - error: parser.read(data) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return describelayer │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer.v1_1_1" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSDescribeLayer.v1_1_0 = OpenLayers.Format.WMSDescribeLayer.v1_1_1; │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - namespaces: { │ │ │ │ - wms: "http://www.opengis.net/wms", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ - defaultPrefix: "wms", │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ - } │ │ │ │ - var raw = data; │ │ │ │ - if (data && data.nodeType == 9) { │ │ │ │ - data = data.documentElement │ │ │ │ - } │ │ │ │ - var capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - if (capabilities.service === undefined) { │ │ │ │ - var parser = new OpenLayers.Format.OGCExceptionReport; │ │ │ │ - capabilities.error = parser.read(raw) │ │ │ │ - } │ │ │ │ - return capabilities │ │ │ │ - }, │ │ │ │ - readers: { │ │ │ │ - wms: { │ │ │ │ - Service: function(node, obj) { │ │ │ │ - obj.service = {}; │ │ │ │ - this.readChildNodes(node, obj.service) │ │ │ │ - }, │ │ │ │ - Name: function(node, obj) { │ │ │ │ - obj.name = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - Title: function(node, obj) { │ │ │ │ - obj.title = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - Abstract: function(node, obj) { │ │ │ │ - obj["abstract"] = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - BoundingBox: function(node, obj) { │ │ │ │ - var bbox = {}; │ │ │ │ - bbox.bbox = [parseFloat(node.getAttribute("minx")), parseFloat(node.getAttribute("miny")), parseFloat(node.getAttribute("maxx")), parseFloat(node.getAttribute("maxy"))]; │ │ │ │ - var res = { │ │ │ │ - x: parseFloat(node.getAttribute("resx")), │ │ │ │ - y: parseFloat(node.getAttribute("resy")) │ │ │ │ - }; │ │ │ │ - if (!(isNaN(res.x) && isNaN(res.y))) { │ │ │ │ - bbox.res = res │ │ │ │ - } │ │ │ │ - return bbox │ │ │ │ - }, │ │ │ │ - OnlineResource: function(node, obj) { │ │ │ │ - obj.href = this.getAttributeNS(node, this.namespaces.xlink, "href") │ │ │ │ - }, │ │ │ │ - ContactInformation: function(node, obj) { │ │ │ │ - obj.contactInformation = {}; │ │ │ │ - this.readChildNodes(node, obj.contactInformation) │ │ │ │ - }, │ │ │ │ - ContactPersonPrimary: function(node, obj) { │ │ │ │ - obj.personPrimary = {}; │ │ │ │ - this.readChildNodes(node, obj.personPrimary) │ │ │ │ - }, │ │ │ │ - ContactPerson: function(node, obj) { │ │ │ │ - obj.person = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - ContactOrganization: function(node, obj) { │ │ │ │ - obj.organization = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - ContactPosition: function(node, obj) { │ │ │ │ - obj.position = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - ContactAddress: function(node, obj) { │ │ │ │ - obj.contactAddress = {}; │ │ │ │ - this.readChildNodes(node, obj.contactAddress) │ │ │ │ - }, │ │ │ │ - AddressType: function(node, obj) { │ │ │ │ - obj.type = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - Address: function(node, obj) { │ │ │ │ - obj.address = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - City: function(node, obj) { │ │ │ │ - obj.city = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - StateOrProvince: function(node, obj) { │ │ │ │ - obj.stateOrProvince = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - PostCode: function(node, obj) { │ │ │ │ - obj.postcode = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - Country: function(node, obj) { │ │ │ │ - obj.country = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - ContactVoiceTelephone: function(node, obj) { │ │ │ │ - obj.phone = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - ContactFacsimileTelephone: function(node, obj) { │ │ │ │ - obj.fax = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - ContactElectronicMailAddress: function(node, obj) { │ │ │ │ - obj.email = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - Fees: function(node, obj) { │ │ │ │ - var fees = this.getChildValue(node); │ │ │ │ - if (fees && fees.toLowerCase() != "none") { │ │ │ │ - obj.fees = fees │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - AccessConstraints: function(node, obj) { │ │ │ │ - var constraints = this.getChildValue(node); │ │ │ │ - if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ - obj.accessConstraints = constraints │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - Capability: function(node, obj) { │ │ │ │ - obj.capability = { │ │ │ │ - nestedLayers: [], │ │ │ │ - layers: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.capability) │ │ │ │ - }, │ │ │ │ - Request: function(node, obj) { │ │ │ │ - obj.request = {}; │ │ │ │ - this.readChildNodes(node, obj.request) │ │ │ │ - }, │ │ │ │ - GetCapabilities: function(node, obj) { │ │ │ │ - obj.getcapabilities = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getcapabilities) │ │ │ │ - }, │ │ │ │ - Format: function(node, obj) { │ │ │ │ - if (OpenLayers.Util.isArray(obj.formats)) { │ │ │ │ - obj.formats.push(this.getChildValue(node)) │ │ │ │ - } else { │ │ │ │ - obj.format = this.getChildValue(node) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - DCPType: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - HTTP: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - Get: function(node, obj) { │ │ │ │ - obj.get = {}; │ │ │ │ - this.readChildNodes(node, obj.get); │ │ │ │ - if (!obj.href) { │ │ │ │ - obj.href = obj.get.href │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - Post: function(node, obj) { │ │ │ │ - obj.post = {}; │ │ │ │ - this.readChildNodes(node, obj.post); │ │ │ │ - if (!obj.href) { │ │ │ │ - obj.href = obj.get.href │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - GetMap: function(node, obj) { │ │ │ │ - obj.getmap = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getmap) │ │ │ │ - }, │ │ │ │ - GetFeatureInfo: function(node, obj) { │ │ │ │ - obj.getfeatureinfo = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getfeatureinfo) │ │ │ │ - }, │ │ │ │ - Exception: function(node, obj) { │ │ │ │ - obj.exception = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.exception) │ │ │ │ - }, │ │ │ │ - Layer: function(node, obj) { │ │ │ │ - var parentLayer, capability; │ │ │ │ - if (obj.capability) { │ │ │ │ - capability = obj.capability; │ │ │ │ - parentLayer = obj │ │ │ │ - } else { │ │ │ │ - capability = obj │ │ │ │ - } │ │ │ │ - var attrNode = node.getAttributeNode("queryable"); │ │ │ │ - var queryable = attrNode && attrNode.specified ? node.getAttribute("queryable") : null; │ │ │ │ - attrNode = node.getAttributeNode("cascaded"); │ │ │ │ - var cascaded = attrNode && attrNode.specified ? node.getAttribute("cascaded") : null; │ │ │ │ - attrNode = node.getAttributeNode("opaque"); │ │ │ │ - var opaque = attrNode && attrNode.specified ? node.getAttribute("opaque") : null; │ │ │ │ - var noSubsets = node.getAttribute("noSubsets"); │ │ │ │ - var fixedWidth = node.getAttribute("fixedWidth"); │ │ │ │ - var fixedHeight = node.getAttribute("fixedHeight"); │ │ │ │ - var parent = parentLayer || {}, │ │ │ │ - extend = OpenLayers.Util.extend; │ │ │ │ - var layer = { │ │ │ │ - nestedLayers: [], │ │ │ │ - styles: parentLayer ? [].concat(parentLayer.styles) : [], │ │ │ │ - srs: parentLayer ? extend({}, parent.srs) : {}, │ │ │ │ - metadataURLs: [], │ │ │ │ - bbox: parentLayer ? extend({}, parent.bbox) : {}, │ │ │ │ - llbbox: parent.llbbox, │ │ │ │ - dimensions: parentLayer ? extend({}, parent.dimensions) : {}, │ │ │ │ - authorityURLs: parentLayer ? extend({}, parent.authorityURLs) : {}, │ │ │ │ - identifiers: {}, │ │ │ │ - keywords: [], │ │ │ │ - queryable: queryable && queryable !== "" ? queryable === "1" || queryable === "true" : parent.queryable || false, │ │ │ │ - cascaded: cascaded !== null ? parseInt(cascaded) : parent.cascaded || 0, │ │ │ │ - opaque: opaque ? opaque === "1" || opaque === "true" : parent.opaque || false, │ │ │ │ - noSubsets: noSubsets !== null ? noSubsets === "1" || noSubsets === "true" : parent.noSubsets || false, │ │ │ │ - fixedWidth: fixedWidth != null ? parseInt(fixedWidth) : parent.fixedWidth || 0, │ │ │ │ - fixedHeight: fixedHeight != null ? parseInt(fixedHeight) : parent.fixedHeight || 0, │ │ │ │ - minScale: parent.minScale, │ │ │ │ - maxScale: parent.maxScale, │ │ │ │ - attribution: parent.attribution │ │ │ │ - }; │ │ │ │ - obj.nestedLayers.push(layer); │ │ │ │ - layer.capability = capability; │ │ │ │ - this.readChildNodes(node, layer); │ │ │ │ - delete layer.capability; │ │ │ │ - if (layer.name) { │ │ │ │ - var parts = layer.name.split(":"), │ │ │ │ - request = capability.request, │ │ │ │ - gfi = request.getfeatureinfo; │ │ │ │ - if (parts.length > 0) { │ │ │ │ - layer.prefix = parts[0] │ │ │ │ - } │ │ │ │ - capability.layers.push(layer); │ │ │ │ - if (layer.formats === undefined) { │ │ │ │ - layer.formats = request.getmap.formats │ │ │ │ - } │ │ │ │ - if (layer.infoFormats === undefined && gfi) { │ │ │ │ - layer.infoFormats = gfi.formats │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - Attribution: function(node, obj) { │ │ │ │ - obj.attribution = {}; │ │ │ │ - this.readChildNodes(node, obj.attribution) │ │ │ │ - }, │ │ │ │ - LogoURL: function(node, obj) { │ │ │ │ - obj.logo = { │ │ │ │ - width: node.getAttribute("width"), │ │ │ │ - height: node.getAttribute("height") │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.logo) │ │ │ │ - }, │ │ │ │ - Style: function(node, obj) { │ │ │ │ - var style = {}; │ │ │ │ - obj.styles.push(style); │ │ │ │ - this.readChildNodes(node, style) │ │ │ │ - }, │ │ │ │ - LegendURL: function(node, obj) { │ │ │ │ - var legend = { │ │ │ │ - width: node.getAttribute("width"), │ │ │ │ - height: node.getAttribute("height") │ │ │ │ - }; │ │ │ │ - obj.legend = legend; │ │ │ │ - this.readChildNodes(node, legend) │ │ │ │ - }, │ │ │ │ - MetadataURL: function(node, obj) { │ │ │ │ - var metadataURL = { │ │ │ │ - type: node.getAttribute("type") │ │ │ │ - }; │ │ │ │ - obj.metadataURLs.push(metadataURL); │ │ │ │ - this.readChildNodes(node, metadataURL) │ │ │ │ - }, │ │ │ │ - DataURL: function(node, obj) { │ │ │ │ - obj.dataURL = {}; │ │ │ │ - this.readChildNodes(node, obj.dataURL) │ │ │ │ - }, │ │ │ │ - FeatureListURL: function(node, obj) { │ │ │ │ - obj.featureListURL = {}; │ │ │ │ - this.readChildNodes(node, obj.featureListURL) │ │ │ │ - }, │ │ │ │ - AuthorityURL: function(node, obj) { │ │ │ │ - var name = node.getAttribute("name"); │ │ │ │ - var authority = {}; │ │ │ │ - this.readChildNodes(node, authority); │ │ │ │ - obj.authorityURLs[name] = authority.href │ │ │ │ - }, │ │ │ │ - Identifier: function(node, obj) { │ │ │ │ - var authority = node.getAttribute("authority"); │ │ │ │ - obj.identifiers[authority] = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - KeywordList: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - SRS: function(node, obj) { │ │ │ │ - obj.srs[this.getChildValue(node)] = true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ - readers: { │ │ │ │ - wms: OpenLayers.Util.applyDefaults({ │ │ │ │ - WMT_MS_Capabilities: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - Keyword: function(node, obj) { │ │ │ │ - if (obj.keywords) { │ │ │ │ - obj.keywords.push(this.getChildValue(node)) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - DescribeLayer: function(node, obj) { │ │ │ │ - obj.describelayer = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.describelayer) │ │ │ │ - }, │ │ │ │ - GetLegendGraphic: function(node, obj) { │ │ │ │ - obj.getlegendgraphic = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getlegendgraphic) │ │ │ │ - }, │ │ │ │ - GetStyles: function(node, obj) { │ │ │ │ - obj.getstyles = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getstyles) │ │ │ │ - }, │ │ │ │ - PutStyles: function(node, obj) { │ │ │ │ - obj.putstyles = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.putstyles) │ │ │ │ - }, │ │ │ │ - UserDefinedSymbolization: function(node, obj) { │ │ │ │ - var userSymbols = { │ │ │ │ - supportSLD: parseInt(node.getAttribute("SupportSLD")) == 1, │ │ │ │ - userLayer: parseInt(node.getAttribute("UserLayer")) == 1, │ │ │ │ - userStyle: parseInt(node.getAttribute("UserStyle")) == 1, │ │ │ │ - remoteWFS: parseInt(node.getAttribute("RemoteWFS")) == 1 │ │ │ │ - }; │ │ │ │ - obj.userSymbols = userSymbols │ │ │ │ - }, │ │ │ │ - LatLonBoundingBox: function(node, obj) { │ │ │ │ - obj.llbbox = [parseFloat(node.getAttribute("minx")), parseFloat(node.getAttribute("miny")), parseFloat(node.getAttribute("maxx")), parseFloat(node.getAttribute("maxy"))] │ │ │ │ - }, │ │ │ │ - BoundingBox: function(node, obj) { │ │ │ │ - var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ - bbox.srs = node.getAttribute("SRS"); │ │ │ │ - obj.bbox[bbox.srs] = bbox │ │ │ │ - }, │ │ │ │ - ScaleHint: function(node, obj) { │ │ │ │ - var min = node.getAttribute("min"); │ │ │ │ - var max = node.getAttribute("max"); │ │ │ │ - var rad2 = Math.pow(2, .5); │ │ │ │ - var ipm = OpenLayers.INCHES_PER_UNIT["m"]; │ │ │ │ - if (min != 0) { │ │ │ │ - obj.maxScale = parseFloat((min / rad2 * ipm * OpenLayers.DOTS_PER_INCH).toPrecision(13)) │ │ │ │ - } │ │ │ │ - if (max != Number.POSITIVE_INFINITY) { │ │ │ │ - obj.minScale = parseFloat((max / rad2 * ipm * OpenLayers.DOTS_PER_INCH).toPrecision(13)) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - Dimension: function(node, obj) { │ │ │ │ - var name = node.getAttribute("name").toLowerCase(); │ │ │ │ - var dim = { │ │ │ │ - name: name, │ │ │ │ - units: node.getAttribute("units"), │ │ │ │ - unitsymbol: node.getAttribute("unitSymbol") │ │ │ │ - }; │ │ │ │ - obj.dimensions[dim.name] = dim │ │ │ │ - }, │ │ │ │ - Extent: function(node, obj) { │ │ │ │ - var name = node.getAttribute("name").toLowerCase(); │ │ │ │ - if (name in obj["dimensions"]) { │ │ │ │ - var extent = obj.dimensions[name]; │ │ │ │ - extent.nearestVal = node.getAttribute("nearestValue") === "1"; │ │ │ │ - extent.multipleVal = node.getAttribute("multipleValues") === "1"; │ │ │ │ - extent.current = node.getAttribute("current") === "1"; │ │ │ │ - extent["default"] = node.getAttribute("default") || ""; │ │ │ │ - var values = this.getChildValue(node); │ │ │ │ - extent.values = values.split(",") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_3 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ - readers: { │ │ │ │ - wms: OpenLayers.Util.applyDefaults({ │ │ │ │ - WMS_Capabilities: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - LayerLimit: function(node, obj) { │ │ │ │ - obj.layerLimit = parseInt(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - MaxWidth: function(node, obj) { │ │ │ │ - obj.maxWidth = parseInt(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - MaxHeight: function(node, obj) { │ │ │ │ - obj.maxHeight = parseInt(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - BoundingBox: function(node, obj) { │ │ │ │ - var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ - bbox.srs = node.getAttribute("CRS"); │ │ │ │ - obj.bbox[bbox.srs] = bbox │ │ │ │ - }, │ │ │ │ - CRS: function(node, obj) { │ │ │ │ - this.readers.wms.SRS.apply(this, [node, obj]) │ │ │ │ - }, │ │ │ │ - EX_GeographicBoundingBox: function(node, obj) { │ │ │ │ - obj.llbbox = []; │ │ │ │ - this.readChildNodes(node, obj.llbbox) │ │ │ │ - }, │ │ │ │ - westBoundLongitude: function(node, obj) { │ │ │ │ - obj[0] = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - eastBoundLongitude: function(node, obj) { │ │ │ │ - obj[2] = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - southBoundLatitude: function(node, obj) { │ │ │ │ - obj[1] = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - northBoundLatitude: function(node, obj) { │ │ │ │ - obj[3] = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - MinScaleDenominator: function(node, obj) { │ │ │ │ - obj.maxScale = parseFloat(this.getChildValue(node)).toPrecision(16) │ │ │ │ - }, │ │ │ │ - MaxScaleDenominator: function(node, obj) { │ │ │ │ - obj.minScale = parseFloat(this.getChildValue(node)).toPrecision(16) │ │ │ │ - }, │ │ │ │ - Dimension: function(node, obj) { │ │ │ │ - var name = node.getAttribute("name").toLowerCase(); │ │ │ │ - var dim = { │ │ │ │ - name: name, │ │ │ │ - units: node.getAttribute("units"), │ │ │ │ - unitsymbol: node.getAttribute("unitSymbol"), │ │ │ │ - nearestVal: node.getAttribute("nearestValue") === "1", │ │ │ │ - multipleVal: node.getAttribute("multipleValues") === "1", │ │ │ │ - default: node.getAttribute("default") || "", │ │ │ │ - current: node.getAttribute("current") === "1", │ │ │ │ - values: this.getChildValue(node).split(",") │ │ │ │ - }; │ │ │ │ - obj.dimensions[dim.name] = dim │ │ │ │ - }, │ │ │ │ - Keyword: function(node, obj) { │ │ │ │ - var keyword = { │ │ │ │ - value: this.getChildValue(node), │ │ │ │ - vocabulary: node.getAttribute("vocabulary") │ │ │ │ - }; │ │ │ │ - if (obj.keywords) { │ │ │ │ - obj.keywords.push(keyword) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]), │ │ │ │ - sld: { │ │ │ │ - UserDefinedSymbolization: function(node, obj) { │ │ │ │ - this.readers.wms.UserDefinedSymbolization.apply(this, [node, obj]); │ │ │ │ - obj.userSymbols.inlineFeature = parseInt(node.getAttribute("InlineFeature")) == 1; │ │ │ │ - obj.userSymbols.remoteWCS = parseInt(node.getAttribute("RemoteWCS")) == 1 │ │ │ │ - }, │ │ │ │ - DescribeLayer: function(node, obj) { │ │ │ │ - this.readers.wms.DescribeLayer.apply(this, [node, obj]) │ │ │ │ - }, │ │ │ │ - GetLegendGraphic: function(node, obj) { │ │ │ │ - this.readers.wms.GetLegendGraphic.apply(this, [node, obj]) │ │ │ │ + folderDesc.appendChild(folderDescText); │ │ │ │ + folder.appendChild(folderDesc) │ │ │ │ + } │ │ │ │ + return folder │ │ │ │ + }, │ │ │ │ + createPlacemarkXML: function(feature) { │ │ │ │ + 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)); │ │ │ │ + var placemarkDesc = this.createElementNS(this.kmlns, "description"); │ │ │ │ + var desc = feature.attributes.description || this.placemarksDesc; │ │ │ │ + placemarkDesc.appendChild(this.createTextNode(desc)); │ │ │ │ + var placemarkNode = this.createElementNS(this.kmlns, "Placemark"); │ │ │ │ + if (feature.fid != null) { │ │ │ │ + placemarkNode.setAttribute("id", feature.fid) │ │ │ │ + } │ │ │ │ + placemarkNode.appendChild(placemarkName); │ │ │ │ + placemarkNode.appendChild(placemarkDesc); │ │ │ │ + var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ + placemarkNode.appendChild(geometryNode); │ │ │ │ + if (feature.attributes) { │ │ │ │ + var edNode = this.buildExtendedData(feature.attributes); │ │ │ │ + if (edNode) { │ │ │ │ + placemarkNode.appendChild(edNode) │ │ │ │ } │ │ │ │ } │ │ │ │ + return placemarkNode │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_3_0 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_3, { │ │ │ │ - version: "1.3.0", │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3_0" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1_0 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ - version: "1.1.0", │ │ │ │ - readers: { │ │ │ │ - wms: OpenLayers.Util.applyDefaults({ │ │ │ │ - SRS: function(node, obj) { │ │ │ │ - var srs = this.getChildValue(node); │ │ │ │ - var values = srs.split(/ +/); │ │ │ │ - for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ - obj.srs[values[i]] = true │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + buildGeometry: { │ │ │ │ + point: function(geometry) { │ │ │ │ + var kml = this.createElementNS(this.kmlns, "Point"); │ │ │ │ + kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ + return kml │ │ │ │ + }, │ │ │ │ + multipoint: function(geometry) { │ │ │ │ + return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ + }, │ │ │ │ + linestring: function(geometry) { │ │ │ │ + var kml = this.createElementNS(this.kmlns, "LineString"); │ │ │ │ + kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ + return kml │ │ │ │ + }, │ │ │ │ + multilinestring: function(geometry) { │ │ │ │ + return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ + }, │ │ │ │ + linearring: function(geometry) { │ │ │ │ + var kml = this.createElementNS(this.kmlns, "LinearRing"); │ │ │ │ + kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ + return kml │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + multipolygon: function(geometry) { │ │ │ │ + return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ } │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ + return kml │ │ │ │ + } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_0" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1_1 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ - version: "1.1.1", │ │ │ │ - readers: { │ │ │ │ - wms: OpenLayers.Util.applyDefaults({ │ │ │ │ - SRS: function(node, obj) { │ │ │ │ - obj.srs[this.getChildValue(node)] = true │ │ │ │ + buildCoordinatesNode: function(geometry) { │ │ │ │ + var coordinatesNode = this.createElementNS(this.kmlns, "coordinates"); │ │ │ │ + var path; │ │ │ │ + var points = geometry.components; │ │ │ │ + if (points) { │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ + path = parts.join(" ") │ │ │ │ + } else { │ │ │ │ + path = this.buildCoordinates(geometry) │ │ │ │ + } │ │ │ │ + var txtNode = this.createTextNode(path); │ │ │ │ + coordinatesNode.appendChild(txtNode); │ │ │ │ + return coordinatesNode │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1_1, { │ │ │ │ - version: "1.1.1", │ │ │ │ - profile: "WMSC", │ │ │ │ - readers: { │ │ │ │ - wms: OpenLayers.Util.applyDefaults({ │ │ │ │ - VendorSpecificCapabilities: function(node, obj) { │ │ │ │ - obj.vendorSpecific = { │ │ │ │ - tileSets: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.vendorSpecific) │ │ │ │ - }, │ │ │ │ - TileSet: function(node, vendorSpecific) { │ │ │ │ - var tileset = { │ │ │ │ - srs: {}, │ │ │ │ - bbox: {}, │ │ │ │ - resolutions: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, tileset); │ │ │ │ - vendorSpecific.tileSets.push(tileset) │ │ │ │ - }, │ │ │ │ - Resolutions: function(node, tileset) { │ │ │ │ - var res = this.getChildValue(node).split(" "); │ │ │ │ - for (var i = 0, len = res.length; i < len; i++) { │ │ │ │ - if (res[i] != "") { │ │ │ │ - tileset.resolutions.push(parseFloat(res[i])) │ │ │ │ + buildCoordinates: function(point) { │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + point = point.clone(); │ │ │ │ + point.transform(this.internalProjection, this.externalProjection) │ │ │ │ + } │ │ │ │ + return point.x + "," + point.y │ │ │ │ + }, │ │ │ │ + buildExtendedData: function(attributes) { │ │ │ │ + var extendedData = this.createElementNS(this.kmlns, "ExtendedData"); │ │ │ │ + for (var attributeName in attributes) { │ │ │ │ + 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") { │ │ │ │ + if (attributes[attributeName].value) { │ │ │ │ + value.appendChild(this.createTextNode(attributes[attributeName].value)) │ │ │ │ + } │ │ │ │ + if (attributes[attributeName].displayName) { │ │ │ │ + var displayName = this.createElementNS(this.kmlns, "displayName"); │ │ │ │ + displayName.appendChild(this.getXMLDoc().createCDATASection(attributes[attributeName].displayName)); │ │ │ │ + data.appendChild(displayName) │ │ │ │ } │ │ │ │ + } else { │ │ │ │ + value.appendChild(this.createTextNode(attributes[attributeName])) │ │ │ │ } │ │ │ │ - }, │ │ │ │ - Width: function(node, tileset) { │ │ │ │ - tileset.width = parseInt(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - Height: function(node, tileset) { │ │ │ │ - tileset.height = parseInt(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - Layers: function(node, tileset) { │ │ │ │ - tileset.layers = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - Styles: function(node, tileset) { │ │ │ │ - tileset.styles = this.getChildValue(node) │ │ │ │ + data.appendChild(value); │ │ │ │ + extendedData.appendChild(data) │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1_1_1.prototype.readers["wms"]) │ │ │ │ + } │ │ │ │ + if (this.isSimpleContent(extendedData)) { │ │ │ │ + return null │ │ │ │ + } else { │ │ │ │ + return extendedData │ │ │ │ + } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.KML" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.WPSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - namespaces: { │ │ │ │ - ows: "http://www.opengis.net/ows/1.1", │ │ │ │ - wps: "http://www.opengis.net/wps/1.0.0", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink" │ │ │ │ - }, │ │ │ │ +OpenLayers.Format.WPSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.0.0", │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WPSCapabilities" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WCSCapabilities.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ regExes: { │ │ │ │ trimSpace: /^\s*|\s*$/g, │ │ │ │ - removeSpace: /\s*/g, │ │ │ │ - splitSpace: /\s+/, │ │ │ │ - trimComma: /\s*,\s*/g │ │ │ │ - }, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]) │ │ │ │ + splitSpace: /\s+/ │ │ │ │ }, │ │ │ │ + defaultPrefix: "wcs", │ │ │ │ read: function(data) { │ │ │ │ if (typeof data == "string") { │ │ │ │ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ } │ │ │ │ + var raw = data; │ │ │ │ if (data && data.nodeType == 9) { │ │ │ │ data = data.documentElement │ │ │ │ } │ │ │ │ var capabilities = {}; │ │ │ │ this.readNode(data, capabilities); │ │ │ │ return capabilities │ │ │ │ }, │ │ │ │ - readers: { │ │ │ │ - wps: { │ │ │ │ - Capabilities: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - ProcessOfferings: function(node, obj) { │ │ │ │ - obj.processOfferings = {}; │ │ │ │ - this.readChildNodes(node, obj.processOfferings) │ │ │ │ - }, │ │ │ │ - Process: function(node, processOfferings) { │ │ │ │ - var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); │ │ │ │ - var process = { │ │ │ │ - processVersion: processVersion │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, process); │ │ │ │ - processOfferings[process.identifier] = process │ │ │ │ - }, │ │ │ │ - Languages: function(node, obj) { │ │ │ │ - obj.languages = []; │ │ │ │ - this.readChildNodes(node, obj.languages) │ │ │ │ - }, │ │ │ │ - Default: function(node, languages) { │ │ │ │ - var language = { │ │ │ │ - isDefault: true │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, language); │ │ │ │ - languages.push(language) │ │ │ │ - }, │ │ │ │ - Supported: function(node, languages) { │ │ │ │ - var language = {}; │ │ │ │ - this.readChildNodes(node, language); │ │ │ │ - languages.push(language) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - ows: OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WPSCapabilities.v1_0_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.CSWGetRecords.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ +OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ namespaces: { │ │ │ │ - csw: "http://www.opengis.net/cat/csw/2.0.2", │ │ │ │ - dc: "http://purl.org/dc/elements/1.1/", │ │ │ │ - dct: "http://purl.org/dc/terms/", │ │ │ │ - gmd: "http://www.isotc211.org/2005/gmd", │ │ │ │ - geonet: "http://www.fao.org/geonetwork", │ │ │ │ - ogc: "http://www.opengis.net/ogc", │ │ │ │ - ows: "http://www.opengis.net/ows", │ │ │ │ + wcs: "http://www.opengis.net/wcs", │ │ │ │ xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ - defaultPrefix: "csw", │ │ │ │ - version: "2.0.2", │ │ │ │ - schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ - requestId: null, │ │ │ │ - resultType: null, │ │ │ │ - outputFormat: null, │ │ │ │ - outputSchema: null, │ │ │ │ - startPosition: null, │ │ │ │ - maxRecords: null, │ │ │ │ - DistributedSearch: null, │ │ │ │ - ResponseHandler: null, │ │ │ │ - Query: null, │ │ │ │ - regExes: { │ │ │ │ - trimSpace: /^\s*|\s*$/g, │ │ │ │ - removeSpace: /\s*/g, │ │ │ │ - splitSpace: /\s+/, │ │ │ │ - trimComma: /\s*,\s*/g │ │ │ │ - }, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - 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 obj = {}; │ │ │ │ - this.readNode(data, obj); │ │ │ │ - return obj │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ + ows: "http://www.opengis.net/ows" │ │ │ │ }, │ │ │ │ + errorProperty: "service", │ │ │ │ readers: { │ │ │ │ - csw: { │ │ │ │ - GetRecordsResponse: function(node, obj) { │ │ │ │ - obj.records = []; │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - var version = this.getAttributeNS(node, "", "version"); │ │ │ │ - if (version != "") { │ │ │ │ - obj.version = version │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - RequestId: function(node, obj) { │ │ │ │ - obj.RequestId = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - SearchStatus: function(node, obj) { │ │ │ │ - obj.SearchStatus = {}; │ │ │ │ - var timestamp = this.getAttributeNS(node, "", "timestamp"); │ │ │ │ - if (timestamp != "") { │ │ │ │ - obj.SearchStatus.timestamp = timestamp │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - SearchResults: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var SearchResults = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - if (attrs[i].name == "numberOfRecordsMatched" || attrs[i].name == "numberOfRecordsReturned" || attrs[i].name == "nextRecord") { │ │ │ │ - SearchResults[attrs[i].name] = parseInt(attrs[i].nodeValue) │ │ │ │ - } else { │ │ │ │ - SearchResults[attrs[i].name] = attrs[i].nodeValue │ │ │ │ - } │ │ │ │ - } │ │ │ │ - obj.SearchResults = SearchResults │ │ │ │ - }, │ │ │ │ - SummaryRecord: function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "SummaryRecord" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record) │ │ │ │ - }, │ │ │ │ - BriefRecord: function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "BriefRecord" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record) │ │ │ │ - }, │ │ │ │ - DCMIRecord: function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "DCMIRecord" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record) │ │ │ │ - }, │ │ │ │ - Record: function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "Record" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record) │ │ │ │ + wcs: { │ │ │ │ + WCS_Capabilities: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ }, │ │ │ │ - "*": function(node, obj) { │ │ │ │ - var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ - obj[name] = this.getChildValue(node) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - geonet: { │ │ │ │ - info: function(node, obj) { │ │ │ │ - var gninfo = {}; │ │ │ │ - this.readChildNodes(node, gninfo); │ │ │ │ - obj.gninfo = gninfo │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - dc: { │ │ │ │ - "*": function(node, obj) { │ │ │ │ - var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ - if (!OpenLayers.Util.isArray(obj[name])) { │ │ │ │ - obj[name] = [] │ │ │ │ - } │ │ │ │ - var dc_element = {}; │ │ │ │ - var attrs = node.attributes; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - dc_element[attrs[i].name] = attrs[i].nodeValue │ │ │ │ - } │ │ │ │ - dc_element.value = this.getChildValue(node); │ │ │ │ - if (dc_element.value != "") { │ │ │ │ - obj[name].push(dc_element) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - dct: { │ │ │ │ - "*": function(node, obj) { │ │ │ │ - var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ - if (!OpenLayers.Util.isArray(obj[name])) { │ │ │ │ - obj[name] = [] │ │ │ │ - } │ │ │ │ - obj[name].push(this.getChildValue(node)) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - ows: OpenLayers.Util.applyDefaults({ │ │ │ │ - BoundingBox: function(node, obj) { │ │ │ │ - if (obj.bounds) { │ │ │ │ - obj.BoundingBox = [{ │ │ │ │ - crs: obj.projection, │ │ │ │ - value: [obj.bounds.left, obj.bounds.bottom, obj.bounds.right, obj.bounds.top] │ │ │ │ - }]; │ │ │ │ - delete obj.projection; │ │ │ │ - delete obj.bounds │ │ │ │ - } │ │ │ │ - OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]["BoundingBox"].apply(this, arguments) │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]) │ │ │ │ - }, │ │ │ │ - write: function(options) { │ │ │ │ - var node = this.writeNode("csw:GetRecords", options); │ │ │ │ - node.setAttribute("xmlns:gmd", this.namespaces.gmd); │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [node]) │ │ │ │ - }, │ │ │ │ - writers: { │ │ │ │ - csw: { │ │ │ │ - GetRecords: function(options) { │ │ │ │ - if (!options) { │ │ │ │ - options = {} │ │ │ │ - } │ │ │ │ - var node = this.createElementNSPlus("csw:GetRecords", { │ │ │ │ - attributes: { │ │ │ │ - service: "CSW", │ │ │ │ - version: this.version, │ │ │ │ - requestId: options.requestId || this.requestId, │ │ │ │ - resultType: options.resultType || this.resultType, │ │ │ │ - outputFormat: options.outputFormat || this.outputFormat, │ │ │ │ - outputSchema: options.outputSchema || this.outputSchema, │ │ │ │ - startPosition: options.startPosition || this.startPosition, │ │ │ │ - maxRecords: options.maxRecords || this.maxRecords │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (options.DistributedSearch || this.DistributedSearch) { │ │ │ │ - this.writeNode("csw:DistributedSearch", options.DistributedSearch || this.DistributedSearch, node) │ │ │ │ - } │ │ │ │ - var ResponseHandler = options.ResponseHandler || this.ResponseHandler; │ │ │ │ - if (OpenLayers.Util.isArray(ResponseHandler) && ResponseHandler.length > 0) { │ │ │ │ - for (var i = 0, len = ResponseHandler.length; i < len; i++) { │ │ │ │ - this.writeNode("csw:ResponseHandler", ResponseHandler[i], node) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.writeNode("Query", options.Query || this.Query, node); │ │ │ │ - return node │ │ │ │ + Service: function(node, obj) { │ │ │ │ + obj.service = {}; │ │ │ │ + this.readChildNodes(node, obj.service) │ │ │ │ }, │ │ │ │ - DistributedSearch: function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:DistributedSearch", { │ │ │ │ - attributes: { │ │ │ │ - hopCount: options.hopCount │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ + name: function(node, service) { │ │ │ │ + service.name = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - ResponseHandler: function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:ResponseHandler", { │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ + label: function(node, service) { │ │ │ │ + service.label = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - Query: function(options) { │ │ │ │ - if (!options) { │ │ │ │ - options = {} │ │ │ │ - } │ │ │ │ - var node = this.createElementNSPlus("csw:Query", { │ │ │ │ - attributes: { │ │ │ │ - typeNames: options.typeNames || "csw:Record" │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - var ElementName = options.ElementName; │ │ │ │ - if (OpenLayers.Util.isArray(ElementName) && ElementName.length > 0) { │ │ │ │ - for (var i = 0, len = ElementName.length; i < len; i++) { │ │ │ │ - this.writeNode("csw:ElementName", ElementName[i], node) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.writeNode("csw:ElementSetName", options.ElementSetName || { │ │ │ │ - value: "summary" │ │ │ │ - }, node) │ │ │ │ - } │ │ │ │ - if (options.Constraint) { │ │ │ │ - this.writeNode("csw:Constraint", options.Constraint, node) │ │ │ │ - } │ │ │ │ - if (options.SortBy) { │ │ │ │ - this.writeNode("ogc:SortBy", options.SortBy, node) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ + keywords: function(node, service) { │ │ │ │ + service.keywords = []; │ │ │ │ + this.readChildNodes(node, service.keywords) │ │ │ │ }, │ │ │ │ - ElementName: function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:ElementName", { │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ + keyword: function(node, keywords) { │ │ │ │ + keywords.push(this.getChildValue(node)) │ │ │ │ }, │ │ │ │ - ElementSetName: function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:ElementSetName", { │ │ │ │ - attributes: { │ │ │ │ - typeNames: options.typeNames │ │ │ │ - }, │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ + responsibleParty: function(node, service) { │ │ │ │ + service.responsibleParty = {}; │ │ │ │ + this.readChildNodes(node, service.responsibleParty) │ │ │ │ }, │ │ │ │ - Constraint: function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:Constraint", { │ │ │ │ - attributes: { │ │ │ │ - version: options.version │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (options.Filter) { │ │ │ │ - var format = new OpenLayers.Format.Filter({ │ │ │ │ - version: options.version │ │ │ │ - }); │ │ │ │ - node.appendChild(format.write(options.Filter)) │ │ │ │ - } else if (options.CqlText) { │ │ │ │ - var child = this.createElementNSPlus("CqlText", { │ │ │ │ - value: options.CqlText.value │ │ │ │ - }); │ │ │ │ - node.appendChild(child) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - ogc: OpenLayers.Format.Filter.v1_1_0.prototype.writers["ogc"] │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.CSWGetRecords.v2_0_2" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class(OpenLayers.Format.SLD.v1_0_0, { │ │ │ │ - version: "1.0.0", │ │ │ │ - profile: "GeoServer", │ │ │ │ - readers: OpenLayers.Util.applyDefaults({ │ │ │ │ - sld: OpenLayers.Util.applyDefaults({ │ │ │ │ - Priority: function(node, obj) { │ │ │ │ - var value = this.readers.ogc._expression.call(this, node); │ │ │ │ - if (value) { │ │ │ │ - obj.priority = value │ │ │ │ - } │ │ │ │ + individualName: function(node, responsibleParty) { │ │ │ │ + responsibleParty.individualName = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - VendorOption: function(node, obj) { │ │ │ │ - if (!obj.vendorOptions) { │ │ │ │ - obj.vendorOptions = {} │ │ │ │ - } │ │ │ │ - obj.vendorOptions[node.getAttribute("name")] = this.getChildValue(node) │ │ │ │ + organisationName: function(node, responsibleParty) { │ │ │ │ + responsibleParty.organisationName = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - TextSymbolizer: function(node, rule) { │ │ │ │ - OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld.TextSymbolizer.apply(this, arguments); │ │ │ │ - var symbolizer = this.multipleSymbolizers ? rule.symbolizers[rule.symbolizers.length - 1] : rule.symbolizer["Text"]; │ │ │ │ - if (symbolizer.graphic === undefined) { │ │ │ │ - symbolizer.graphic = false │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.readers["sld"]) │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.readers), │ │ │ │ - writers: OpenLayers.Util.applyDefaults({ │ │ │ │ - sld: OpenLayers.Util.applyDefaults({ │ │ │ │ - Priority: function(priority) { │ │ │ │ - return this.writers.sld._OGCExpression.call(this, "sld:Priority", priority) │ │ │ │ + positionName: function(node, responsibleParty) { │ │ │ │ + responsibleParty.positionName = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - VendorOption: function(option) { │ │ │ │ - return this.createElementNSPlus("sld:VendorOption", { │ │ │ │ - attributes: { │ │ │ │ - name: option.name │ │ │ │ - }, │ │ │ │ - value: option.value │ │ │ │ - }) │ │ │ │ + contactInfo: function(node, responsibleParty) { │ │ │ │ + responsibleParty.contactInfo = {}; │ │ │ │ + this.readChildNodes(node, responsibleParty.contactInfo) │ │ │ │ }, │ │ │ │ - TextSymbolizer: function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["TextSymbolizer"].apply(this, arguments); │ │ │ │ - if (symbolizer.graphic !== false && (symbolizer.externalGraphic || symbolizer.graphicName)) { │ │ │ │ - this.writeNode("Graphic", symbolizer, node) │ │ │ │ - } │ │ │ │ - if ("priority" in symbolizer) { │ │ │ │ - this.writeNode("Priority", symbolizer.priority, node) │ │ │ │ - } │ │ │ │ - return this.addVendorOptions(node, symbolizer) │ │ │ │ + phone: function(node, contactInfo) { │ │ │ │ + contactInfo.phone = {}; │ │ │ │ + this.readChildNodes(node, contactInfo.phone) │ │ │ │ }, │ │ │ │ - PointSymbolizer: function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["PointSymbolizer"].apply(this, arguments); │ │ │ │ - return this.addVendorOptions(node, symbolizer) │ │ │ │ + voice: function(node, phone) { │ │ │ │ + phone.voice = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - LineSymbolizer: function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["LineSymbolizer"].apply(this, arguments); │ │ │ │ - return this.addVendorOptions(node, symbolizer) │ │ │ │ + facsimile: function(node, phone) { │ │ │ │ + phone.facsimile = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - PolygonSymbolizer: function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["PolygonSymbolizer"].apply(this, arguments); │ │ │ │ - return this.addVendorOptions(node, symbolizer) │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.writers["sld"]) │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.writers), │ │ │ │ - addVendorOptions: function(node, symbolizer) { │ │ │ │ - var options = symbolizer.vendorOptions; │ │ │ │ - if (options) { │ │ │ │ - for (var key in symbolizer.vendorOptions) { │ │ │ │ - this.writeNode("VendorOption", { │ │ │ │ - name: key, │ │ │ │ - value: symbolizer.vendorOptions[key] │ │ │ │ - }, node) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0_GeoServer" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.CSWGetDomain.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - namespaces: { │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ - csw: "http://www.opengis.net/cat/csw/2.0.2" │ │ │ │ - }, │ │ │ │ - defaultPrefix: "csw", │ │ │ │ - version: "2.0.2", │ │ │ │ - schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ - PropertyName: null, │ │ │ │ - ParameterName: null, │ │ │ │ - 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 obj = {}; │ │ │ │ - this.readNode(data, obj); │ │ │ │ - return obj │ │ │ │ - }, │ │ │ │ - readers: { │ │ │ │ - csw: { │ │ │ │ - GetDomainResponse: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ + address: function(node, contactInfo) { │ │ │ │ + contactInfo.address = {}; │ │ │ │ + this.readChildNodes(node, contactInfo.address) │ │ │ │ }, │ │ │ │ - DomainValues: function(node, obj) { │ │ │ │ - if (!OpenLayers.Util.isArray(obj.DomainValues)) { │ │ │ │ - obj.DomainValues = [] │ │ │ │ - } │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var domainValue = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - domainValue[attrs[i].name] = attrs[i].nodeValue │ │ │ │ - } │ │ │ │ - this.readChildNodes(node, domainValue); │ │ │ │ - obj.DomainValues.push(domainValue) │ │ │ │ + deliveryPoint: function(node, address) { │ │ │ │ + address.deliveryPoint = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - PropertyName: function(node, obj) { │ │ │ │ - obj.PropertyName = this.getChildValue(node) │ │ │ │ + city: function(node, address) { │ │ │ │ + address.city = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - ParameterName: function(node, obj) { │ │ │ │ - obj.ParameterName = this.getChildValue(node) │ │ │ │ + postalCode: function(node, address) { │ │ │ │ + address.postalCode = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - ListOfValues: function(node, obj) { │ │ │ │ - if (!OpenLayers.Util.isArray(obj.ListOfValues)) { │ │ │ │ - obj.ListOfValues = [] │ │ │ │ - } │ │ │ │ - this.readChildNodes(node, obj.ListOfValues) │ │ │ │ + country: function(node, address) { │ │ │ │ + address.country = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - Value: function(node, obj) { │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var value = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - value[attrs[i].name] = attrs[i].nodeValue │ │ │ │ - } │ │ │ │ - value.value = this.getChildValue(node); │ │ │ │ - obj.push({ │ │ │ │ - Value: value │ │ │ │ - }) │ │ │ │ + electronicMailAddress: function(node, address) { │ │ │ │ + address.electronicMailAddress = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - ConceptualScheme: function(node, obj) { │ │ │ │ - obj.ConceptualScheme = {}; │ │ │ │ - this.readChildNodes(node, obj.ConceptualScheme) │ │ │ │ + fees: function(node, service) { │ │ │ │ + service.fees = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - Name: function(node, obj) { │ │ │ │ - obj.Name = this.getChildValue(node) │ │ │ │ + accessConstraints: function(node, service) { │ │ │ │ + service.accessConstraints = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - Document: function(node, obj) { │ │ │ │ - obj.Document = this.getChildValue(node) │ │ │ │ + ContentMetadata: function(node, obj) { │ │ │ │ + obj.contentMetadata = []; │ │ │ │ + this.readChildNodes(node, obj.contentMetadata) │ │ │ │ }, │ │ │ │ - Authority: function(node, obj) { │ │ │ │ - obj.Authority = this.getChildValue(node) │ │ │ │ + CoverageOfferingBrief: function(node, contentMetadata) { │ │ │ │ + var coverageOfferingBrief = {}; │ │ │ │ + this.readChildNodes(node, coverageOfferingBrief); │ │ │ │ + contentMetadata.push(coverageOfferingBrief) │ │ │ │ }, │ │ │ │ - RangeOfValues: function(node, obj) { │ │ │ │ - obj.RangeOfValues = {}; │ │ │ │ - this.readChildNodes(node, obj.RangeOfValues) │ │ │ │ + name: function(node, coverageOfferingBrief) { │ │ │ │ + coverageOfferingBrief.name = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - MinValue: function(node, obj) { │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var value = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - value[attrs[i].name] = attrs[i].nodeValue │ │ │ │ - } │ │ │ │ - value.value = this.getChildValue(node); │ │ │ │ - obj.MinValue = value │ │ │ │ + label: function(node, coverageOfferingBrief) { │ │ │ │ + coverageOfferingBrief.label = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - MaxValue: function(node, obj) { │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var value = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - value[attrs[i].name] = attrs[i].nodeValue │ │ │ │ - } │ │ │ │ - value.value = this.getChildValue(node); │ │ │ │ - obj.MaxValue = value │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - write: function(options) { │ │ │ │ - var node = this.writeNode("csw:GetDomain", options); │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [node]) │ │ │ │ - }, │ │ │ │ - writers: { │ │ │ │ - csw: { │ │ │ │ - GetDomain: function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:GetDomain", { │ │ │ │ - attributes: { │ │ │ │ - service: "CSW", │ │ │ │ - version: this.version │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (options.PropertyName || this.PropertyName) { │ │ │ │ - this.writeNode("csw:PropertyName", options.PropertyName || this.PropertyName, node) │ │ │ │ - } else if (options.ParameterName || this.ParameterName) { │ │ │ │ - this.writeNode("csw:ParameterName", options.ParameterName || this.ParameterName, node) │ │ │ │ + lonLatEnvelope: function(node, coverageOfferingBrief) { │ │ │ │ + var nodeList = this.getElementsByTagNameNS(node, "http://www.opengis.net/gml", "pos"); │ │ │ │ + if (nodeList.length == 2) { │ │ │ │ + var min = {}; │ │ │ │ + var max = {}; │ │ │ │ + OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[0], min]); │ │ │ │ + OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[1], max]); │ │ │ │ + coverageOfferingBrief.lonLatEnvelope = {}; │ │ │ │ + coverageOfferingBrief.lonLatEnvelope.srsName = node.getAttribute("srsName"); │ │ │ │ + coverageOfferingBrief.lonLatEnvelope.min = min.points[0]; │ │ │ │ + coverageOfferingBrief.lonLatEnvelope.max = max.points[0] │ │ │ │ } │ │ │ │ - this.readChildNodes(node, options); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - PropertyName: function(value) { │ │ │ │ - var node = this.createElementNSPlus("csw:PropertyName", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - ParameterName: function(value) { │ │ │ │ - var node = this.createElementNSPlus("csw:ParameterName", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.CSWGetDomain.v2_0_2" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_0_0" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.WMTSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.OWSCommon.v1_1_0, { │ │ │ │ - version: "1.0.0", │ │ │ │ +OpenLayers.Format.WCSCapabilities.v1_1_0 = OpenLayers.Class(OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ namespaces: { │ │ │ │ - ows: "http://www.opengis.net/ows/1.1", │ │ │ │ - wmts: "http://www.opengis.net/wmts/1.0", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink" │ │ │ │ - }, │ │ │ │ - yx: null, │ │ │ │ - defaultPrefix: "wmts", │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ - this.options = options; │ │ │ │ - var yx = OpenLayers.Util.extend({}, OpenLayers.Format.WMTSCapabilities.prototype.yx); │ │ │ │ - this.yx = OpenLayers.Util.extend(yx, this.yx) │ │ │ │ - }, │ │ │ │ - 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 capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - capabilities.version = this.version; │ │ │ │ - return capabilities │ │ │ │ + wcs: "http://www.opengis.net/wcs/1.1", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ + ows: "http://www.opengis.net/ows/1.1" │ │ │ │ }, │ │ │ │ + errorProperty: "operationsMetadata", │ │ │ │ readers: { │ │ │ │ - wmts: { │ │ │ │ + wcs: OpenLayers.Util.applyDefaults({ │ │ │ │ Capabilities: function(node, obj) { │ │ │ │ this.readChildNodes(node, obj) │ │ │ │ }, │ │ │ │ - Contents: function(node, obj) { │ │ │ │ - obj.contents = {}; │ │ │ │ - obj.contents.layers = []; │ │ │ │ - obj.contents.tileMatrixSets = {}; │ │ │ │ - this.readChildNodes(node, obj.contents) │ │ │ │ - }, │ │ │ │ - Layer: function(node, obj) { │ │ │ │ - var layer = { │ │ │ │ - styles: [], │ │ │ │ - formats: [], │ │ │ │ - dimensions: [], │ │ │ │ - tileMatrixSetLinks: [] │ │ │ │ - }; │ │ │ │ - layer.layers = []; │ │ │ │ - this.readChildNodes(node, layer); │ │ │ │ - obj.layers.push(layer) │ │ │ │ - }, │ │ │ │ - Style: function(node, obj) { │ │ │ │ - var style = {}; │ │ │ │ - style.isDefault = node.getAttribute("isDefault") === "true"; │ │ │ │ - this.readChildNodes(node, style); │ │ │ │ - obj.styles.push(style) │ │ │ │ - }, │ │ │ │ - Format: function(node, obj) { │ │ │ │ - obj.formats.push(this.getChildValue(node)) │ │ │ │ + Contents: function(node, request) { │ │ │ │ + request.contentMetadata = []; │ │ │ │ + this.readChildNodes(node, request.contentMetadata) │ │ │ │ }, │ │ │ │ - TileMatrixSetLink: function(node, obj) { │ │ │ │ - var tileMatrixSetLink = {}; │ │ │ │ - this.readChildNodes(node, tileMatrixSetLink); │ │ │ │ - obj.tileMatrixSetLinks.push(tileMatrixSetLink) │ │ │ │ + CoverageSummary: function(node, contentMetadata) { │ │ │ │ + var coverageSummary = {}; │ │ │ │ + this.readChildNodes(node, coverageSummary); │ │ │ │ + contentMetadata.push(coverageSummary) │ │ │ │ }, │ │ │ │ - TileMatrixSet: function(node, obj) { │ │ │ │ - if (obj.layers) { │ │ │ │ - var tileMatrixSet = { │ │ │ │ - matrixIds: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, tileMatrixSet); │ │ │ │ - obj.tileMatrixSets[tileMatrixSet.identifier] = tileMatrixSet │ │ │ │ - } else { │ │ │ │ - obj.tileMatrixSet = this.getChildValue(node) │ │ │ │ - } │ │ │ │ + Identifier: function(node, coverageSummary) { │ │ │ │ + coverageSummary.identifier = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - TileMatrix: function(node, obj) { │ │ │ │ - var tileMatrix = { │ │ │ │ - supportedCRS: obj.supportedCRS │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, tileMatrix); │ │ │ │ - obj.matrixIds.push(tileMatrix) │ │ │ │ + Title: function(node, coverageSummary) { │ │ │ │ + coverageSummary.title = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - ScaleDenominator: function(node, obj) { │ │ │ │ - obj.scaleDenominator = parseFloat(this.getChildValue(node)) │ │ │ │ + Abstract: function(node, coverageSummary) { │ │ │ │ + coverageSummary["abstract"] = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - TopLeftCorner: function(node, obj) { │ │ │ │ - var topLeftCorner = this.getChildValue(node); │ │ │ │ - var coords = topLeftCorner.split(" "); │ │ │ │ - var yx; │ │ │ │ - if (obj.supportedCRS) { │ │ │ │ - var crs = obj.supportedCRS.replace(/urn:ogc:def:crs:(\w+):.+:(\w+)$/, "urn:ogc:def:crs:$1::$2"); │ │ │ │ - yx = !!this.yx[crs] │ │ │ │ - } │ │ │ │ - if (yx) { │ │ │ │ - obj.topLeftCorner = new OpenLayers.LonLat(coords[1], coords[0]) │ │ │ │ - } else { │ │ │ │ - obj.topLeftCorner = new OpenLayers.LonLat(coords[0], coords[1]) │ │ │ │ + SupportedCRS: function(node, coverageSummary) { │ │ │ │ + var crs = this.getChildValue(node); │ │ │ │ + if (crs) { │ │ │ │ + if (!coverageSummary.supportedCRS) { │ │ │ │ + coverageSummary.supportedCRS = [] │ │ │ │ + } │ │ │ │ + coverageSummary.supportedCRS.push(crs) │ │ │ │ } │ │ │ │ }, │ │ │ │ - TileWidth: function(node, obj) { │ │ │ │ - obj.tileWidth = parseInt(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - TileHeight: function(node, obj) { │ │ │ │ - obj.tileHeight = parseInt(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - MatrixWidth: function(node, obj) { │ │ │ │ - obj.matrixWidth = parseInt(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - MatrixHeight: function(node, obj) { │ │ │ │ - obj.matrixHeight = parseInt(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - ResourceURL: function(node, obj) { │ │ │ │ - obj.resourceUrl = obj.resourceUrl || {}; │ │ │ │ - var resourceType = node.getAttribute("resourceType"); │ │ │ │ - if (!obj.resourceUrls) { │ │ │ │ - obj.resourceUrls = [] │ │ │ │ + SupportedFormat: function(node, coverageSummary) { │ │ │ │ + var format = this.getChildValue(node); │ │ │ │ + if (format) { │ │ │ │ + if (!coverageSummary.supportedFormat) { │ │ │ │ + coverageSummary.supportedFormat = [] │ │ │ │ + } │ │ │ │ + coverageSummary.supportedFormat.push(format) │ │ │ │ } │ │ │ │ - var resourceUrl = obj.resourceUrl[resourceType] = { │ │ │ │ - format: node.getAttribute("format"), │ │ │ │ - template: node.getAttribute("template"), │ │ │ │ - resourceType: resourceType │ │ │ │ - }; │ │ │ │ - obj.resourceUrls.push(resourceUrl) │ │ │ │ - }, │ │ │ │ - WSDL: function(node, obj) { │ │ │ │ - obj.wsdl = {}; │ │ │ │ - obj.wsdl.href = node.getAttribute("xlink:href") │ │ │ │ - }, │ │ │ │ - ServiceMetadataURL: function(node, obj) { │ │ │ │ - obj.serviceMetadataUrl = {}; │ │ │ │ - obj.serviceMetadataUrl.href = node.getAttribute("xlink:href") │ │ │ │ - }, │ │ │ │ - LegendURL: function(node, obj) { │ │ │ │ - obj.legend = {}; │ │ │ │ - obj.legend.href = node.getAttribute("xlink:href"); │ │ │ │ - obj.legend.format = node.getAttribute("format") │ │ │ │ - }, │ │ │ │ - Dimension: function(node, obj) { │ │ │ │ - var dimension = { │ │ │ │ - values: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, dimension); │ │ │ │ - obj.dimensions.push(dimension) │ │ │ │ - }, │ │ │ │ - Default: function(node, obj) { │ │ │ │ - obj["default"] = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - Value: function(node, obj) { │ │ │ │ - obj.values.push(this.getChildValue(node)) │ │ │ │ } │ │ │ │ - }, │ │ │ │ + }, OpenLayers.Format.WCSCapabilities.v1.prototype.readers["wcs"]), │ │ │ │ ows: OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMTSCapabilities.v1_0_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_1_0" │ │ │ │ }); │ │ │ │ OpenLayers.Format.WMC.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ namespaces: { │ │ │ │ ol: "http://openlayers.org/context", │ │ │ │ wmc: "http://www.opengis.net/context", │ │ │ │ sld: "http://www.opengis.net/sld", │ │ │ │ xlink: "http://www.w3.org/1999/xlink", │ │ │ │ @@ -35691,14 +35192,48 @@ │ │ │ │ if (links.length > 0) { │ │ │ │ this.read_wmc_OnlineResource(object, links[0]) │ │ │ │ } │ │ │ │ return object.href │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.WMC.v1" │ │ │ │ }); │ │ │ │ +OpenLayers.Format.WMC.v1_0_0 = OpenLayers.Class(OpenLayers.Format.WMC.v1, { │ │ │ │ + VERSION: "1.0.0", │ │ │ │ + schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.0.0/context.xsd", │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.WMC.v1.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + read_wmc_SRS: function(layerContext, node) { │ │ │ │ + var srs = this.getChildValue(node); │ │ │ │ + if (typeof layerContext.projections != "object") { │ │ │ │ + layerContext.projections = {} │ │ │ │ + } │ │ │ │ + var values = srs.split(/ +/); │ │ │ │ + for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ + layerContext.projections[values[i]] = true │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + write_wmc_Layer: function(context) { │ │ │ │ + var node = OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply(this, [context]); │ │ │ │ + if (context.srs) { │ │ │ │ + var projections = []; │ │ │ │ + for (var name in context.srs) { │ │ │ │ + projections.push(name) │ │ │ │ + } │ │ │ │ + node.appendChild(this.createElementDefaultNS("SRS", projections.join(" "))) │ │ │ │ + } │ │ │ │ + node.appendChild(this.write_wmc_FormatList(context)); │ │ │ │ + node.appendChild(this.write_wmc_StyleList(context)); │ │ │ │ + if (context.dimensions) { │ │ │ │ + node.appendChild(this.write_wmc_DimensionList(context)) │ │ │ │ + } │ │ │ │ + node.appendChild(this.write_wmc_LayerExtension(context)) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMC.v1_0_0" │ │ │ │ +}); │ │ │ │ OpenLayers.Format.WMC.v1_1_0 = OpenLayers.Class(OpenLayers.Format.WMC.v1, { │ │ │ │ VERSION: "1.1.0", │ │ │ │ schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.1.0/context.xsd", │ │ │ │ initialize: function(options) { │ │ │ │ OpenLayers.Format.WMC.v1.prototype.initialize.apply(this, [options]) │ │ │ │ }, │ │ │ │ read_sld_MinScaleDenominator: function(layerContext, node) { │ │ │ │ @@ -35739,491 +35274,458 @@ │ │ │ │ node.appendChild(this.write_wmc_DimensionList(context)) │ │ │ │ } │ │ │ │ node.appendChild(this.write_wmc_LayerExtension(context)); │ │ │ │ return node │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.WMC.v1_1_0" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.WMC.v1_0_0 = OpenLayers.Class(OpenLayers.Format.WMC.v1, { │ │ │ │ - VERSION: "1.0.0", │ │ │ │ - schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.0.0/context.xsd", │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.WMC.v1.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - read_wmc_SRS: function(layerContext, node) { │ │ │ │ - var srs = this.getChildValue(node); │ │ │ │ - if (typeof layerContext.projections != "object") { │ │ │ │ - layerContext.projections = {} │ │ │ │ - } │ │ │ │ - var values = srs.split(/ +/); │ │ │ │ - for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ - layerContext.projections[values[i]] = true │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - write_wmc_Layer: function(context) { │ │ │ │ - var node = OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply(this, [context]); │ │ │ │ - if (context.srs) { │ │ │ │ - var projections = []; │ │ │ │ - for (var name in context.srs) { │ │ │ │ - projections.push(name) │ │ │ │ - } │ │ │ │ - node.appendChild(this.createElementDefaultNS("SRS", projections.join(" "))) │ │ │ │ - } │ │ │ │ - node.appendChild(this.write_wmc_FormatList(context)); │ │ │ │ - node.appendChild(this.write_wmc_StyleList(context)); │ │ │ │ - if (context.dimensions) { │ │ │ │ - node.appendChild(this.write_wmc_DimensionList(context)) │ │ │ │ - } │ │ │ │ - node.appendChild(this.write_wmc_LayerExtension(context)) │ │ │ │ +OpenLayers.Format.SOSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.SOSCapabilities, { │ │ │ │ + namespaces: { │ │ │ │ + ows: "http://www.opengis.net/ows/1.1", │ │ │ │ + sos: "http://www.opengis.net/sos/1.0", │ │ │ │ + gml: "http://www.opengis.net/gml", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink" │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMC.v1_0_0" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WCSCapabilities.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ regExes: { │ │ │ │ trimSpace: /^\s*|\s*$/g, │ │ │ │ - splitSpace: /\s+/ │ │ │ │ + removeSpace: /\s*/g, │ │ │ │ + splitSpace: /\s+/, │ │ │ │ + trimComma: /\s*,\s*/g │ │ │ │ + }, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ + this.options = options │ │ │ │ }, │ │ │ │ - defaultPrefix: "wcs", │ │ │ │ read: function(data) { │ │ │ │ if (typeof data == "string") { │ │ │ │ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ } │ │ │ │ - var raw = data; │ │ │ │ if (data && data.nodeType == 9) { │ │ │ │ data = data.documentElement │ │ │ │ } │ │ │ │ var capabilities = {}; │ │ │ │ this.readNode(data, capabilities); │ │ │ │ return capabilities │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WCSCapabilities.v1_1_0 = OpenLayers.Class(OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ - namespaces: { │ │ │ │ - wcs: "http://www.opengis.net/wcs/1.1", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ - ows: "http://www.opengis.net/ows/1.1" │ │ │ │ - }, │ │ │ │ - errorProperty: "operationsMetadata", │ │ │ │ readers: { │ │ │ │ - wcs: OpenLayers.Util.applyDefaults({ │ │ │ │ + gml: OpenLayers.Util.applyDefaults({ │ │ │ │ + name: function(node, obj) { │ │ │ │ + obj.name = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + TimePeriod: function(node, obj) { │ │ │ │ + obj.timePeriod = {}; │ │ │ │ + this.readChildNodes(node, obj.timePeriod) │ │ │ │ + }, │ │ │ │ + beginPosition: function(node, timePeriod) { │ │ │ │ + timePeriod.beginPosition = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + endPosition: function(node, timePeriod) { │ │ │ │ + timePeriod.endPosition = this.getChildValue(node) │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.GML.v3.prototype.readers["gml"]), │ │ │ │ + sos: { │ │ │ │ Capabilities: function(node, obj) { │ │ │ │ this.readChildNodes(node, obj) │ │ │ │ }, │ │ │ │ - Contents: function(node, request) { │ │ │ │ - request.contentMetadata = []; │ │ │ │ - this.readChildNodes(node, request.contentMetadata) │ │ │ │ + Contents: function(node, obj) { │ │ │ │ + obj.contents = {}; │ │ │ │ + this.readChildNodes(node, obj.contents) │ │ │ │ }, │ │ │ │ - CoverageSummary: function(node, contentMetadata) { │ │ │ │ - var coverageSummary = {}; │ │ │ │ - this.readChildNodes(node, coverageSummary); │ │ │ │ - contentMetadata.push(coverageSummary) │ │ │ │ + ObservationOfferingList: function(node, contents) { │ │ │ │ + contents.offeringList = {}; │ │ │ │ + this.readChildNodes(node, contents.offeringList) │ │ │ │ }, │ │ │ │ - Identifier: function(node, coverageSummary) { │ │ │ │ - coverageSummary.identifier = this.getChildValue(node) │ │ │ │ + ObservationOffering: function(node, offeringList) { │ │ │ │ + var id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ + offeringList[id] = { │ │ │ │ + procedures: [], │ │ │ │ + observedProperties: [], │ │ │ │ + featureOfInterestIds: [], │ │ │ │ + responseFormats: [], │ │ │ │ + resultModels: [], │ │ │ │ + responseModes: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, offeringList[id]) │ │ │ │ }, │ │ │ │ - Title: function(node, coverageSummary) { │ │ │ │ - coverageSummary.title = this.getChildValue(node) │ │ │ │ + time: function(node, offering) { │ │ │ │ + offering.time = {}; │ │ │ │ + this.readChildNodes(node, offering.time) │ │ │ │ }, │ │ │ │ - Abstract: function(node, coverageSummary) { │ │ │ │ - coverageSummary["abstract"] = this.getChildValue(node) │ │ │ │ + procedure: function(node, offering) { │ │ │ │ + offering.procedures.push(this.getAttributeNS(node, this.namespaces.xlink, "href")) │ │ │ │ }, │ │ │ │ - SupportedCRS: function(node, coverageSummary) { │ │ │ │ - var crs = this.getChildValue(node); │ │ │ │ - if (crs) { │ │ │ │ - if (!coverageSummary.supportedCRS) { │ │ │ │ - coverageSummary.supportedCRS = [] │ │ │ │ - } │ │ │ │ - coverageSummary.supportedCRS.push(crs) │ │ │ │ - } │ │ │ │ + observedProperty: function(node, offering) { │ │ │ │ + offering.observedProperties.push(this.getAttributeNS(node, this.namespaces.xlink, "href")) │ │ │ │ }, │ │ │ │ - SupportedFormat: function(node, coverageSummary) { │ │ │ │ - var format = this.getChildValue(node); │ │ │ │ - if (format) { │ │ │ │ - if (!coverageSummary.supportedFormat) { │ │ │ │ - coverageSummary.supportedFormat = [] │ │ │ │ - } │ │ │ │ - coverageSummary.supportedFormat.push(format) │ │ │ │ - } │ │ │ │ + featureOfInterest: function(node, offering) { │ │ │ │ + offering.featureOfInterestIds.push(this.getAttributeNS(node, this.namespaces.xlink, "href")) │ │ │ │ + }, │ │ │ │ + responseFormat: function(node, offering) { │ │ │ │ + offering.responseFormats.push(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + resultModel: function(node, offering) { │ │ │ │ + offering.resultModels.push(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + responseMode: function(node, offering) { │ │ │ │ + offering.responseModes.push(this.getChildValue(node)) │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.WCSCapabilities.v1.prototype.readers["wcs"]), │ │ │ │ + }, │ │ │ │ ows: OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_1_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SOSCapabilities.v1_0_0" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ +OpenLayers.Format.XLS.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ namespaces: { │ │ │ │ - wcs: "http://www.opengis.net/wcs", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ - ows: "http://www.opengis.net/ows" │ │ │ │ + xls: "http://www.opengis.net/xls", │ │ │ │ + gml: "http://www.opengis.net/gml", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + }, │ │ │ │ + regExes: { │ │ │ │ + trimSpace: /^\s*|\s*$/g, │ │ │ │ + removeSpace: /\s*/g, │ │ │ │ + splitSpace: /\s+/, │ │ │ │ + trimComma: /\s*,\s*/g │ │ │ │ + }, │ │ │ │ + xy: true, │ │ │ │ + defaultPrefix: "xls", │ │ │ │ + schemaLocation: null, │ │ │ │ + read: function(data, options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ + var xls = {}; │ │ │ │ + this.readChildNodes(data, xls); │ │ │ │ + return xls │ │ │ │ }, │ │ │ │ - errorProperty: "service", │ │ │ │ readers: { │ │ │ │ - wcs: { │ │ │ │ - WCS_Capabilities: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - Service: function(node, obj) { │ │ │ │ - obj.service = {}; │ │ │ │ - this.readChildNodes(node, obj.service) │ │ │ │ - }, │ │ │ │ - name: function(node, service) { │ │ │ │ - service.name = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - label: function(node, service) { │ │ │ │ - service.label = this.getChildValue(node) │ │ │ │ + xls: { │ │ │ │ + XLS: function(node, xls) { │ │ │ │ + xls.version = node.getAttribute("version"); │ │ │ │ + this.readChildNodes(node, xls) │ │ │ │ }, │ │ │ │ - keywords: function(node, service) { │ │ │ │ - service.keywords = []; │ │ │ │ - this.readChildNodes(node, service.keywords) │ │ │ │ + Response: function(node, xls) { │ │ │ │ + this.readChildNodes(node, xls) │ │ │ │ }, │ │ │ │ - keyword: function(node, keywords) { │ │ │ │ - keywords.push(this.getChildValue(node)) │ │ │ │ + GeocodeResponse: function(node, xls) { │ │ │ │ + xls.responseLists = []; │ │ │ │ + this.readChildNodes(node, xls) │ │ │ │ }, │ │ │ │ - responsibleParty: function(node, service) { │ │ │ │ - service.responsibleParty = {}; │ │ │ │ - this.readChildNodes(node, service.responsibleParty) │ │ │ │ + GeocodeResponseList: function(node, xls) { │ │ │ │ + var responseList = { │ │ │ │ + features: [], │ │ │ │ + numberOfGeocodedAddresses: parseInt(node.getAttribute("numberOfGeocodedAddresses")) │ │ │ │ + }; │ │ │ │ + xls.responseLists.push(responseList); │ │ │ │ + this.readChildNodes(node, responseList) │ │ │ │ }, │ │ │ │ - individualName: function(node, responsibleParty) { │ │ │ │ - responsibleParty.individualName = this.getChildValue(node) │ │ │ │ + GeocodedAddress: function(node, responseList) { │ │ │ │ + var feature = new OpenLayers.Feature.Vector; │ │ │ │ + responseList.features.push(feature); │ │ │ │ + this.readChildNodes(node, feature); │ │ │ │ + feature.geometry = feature.components[0] │ │ │ │ }, │ │ │ │ - organisationName: function(node, responsibleParty) { │ │ │ │ - responsibleParty.organisationName = this.getChildValue(node) │ │ │ │ + GeocodeMatchCode: function(node, feature) { │ │ │ │ + feature.attributes.matchCode = { │ │ │ │ + accuracy: parseFloat(node.getAttribute("accuracy")), │ │ │ │ + matchType: node.getAttribute("matchType") │ │ │ │ + } │ │ │ │ }, │ │ │ │ - positionName: function(node, responsibleParty) { │ │ │ │ - responsibleParty.positionName = this.getChildValue(node) │ │ │ │ + Address: function(node, feature) { │ │ │ │ + var address = { │ │ │ │ + countryCode: node.getAttribute("countryCode"), │ │ │ │ + addressee: node.getAttribute("addressee"), │ │ │ │ + street: [], │ │ │ │ + place: [] │ │ │ │ + }; │ │ │ │ + feature.attributes.address = address; │ │ │ │ + this.readChildNodes(node, address) │ │ │ │ }, │ │ │ │ - contactInfo: function(node, responsibleParty) { │ │ │ │ - responsibleParty.contactInfo = {}; │ │ │ │ - this.readChildNodes(node, responsibleParty.contactInfo) │ │ │ │ + freeFormAddress: function(node, address) { │ │ │ │ + address.freeFormAddress = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - phone: function(node, contactInfo) { │ │ │ │ - contactInfo.phone = {}; │ │ │ │ - this.readChildNodes(node, contactInfo.phone) │ │ │ │ + StreetAddress: function(node, address) { │ │ │ │ + this.readChildNodes(node, address) │ │ │ │ }, │ │ │ │ - voice: function(node, phone) { │ │ │ │ - phone.voice = this.getChildValue(node) │ │ │ │ + Building: function(node, address) { │ │ │ │ + address.building = { │ │ │ │ + number: node.getAttribute("number"), │ │ │ │ + subdivision: node.getAttribute("subdivision"), │ │ │ │ + buildingName: node.getAttribute("buildingName") │ │ │ │ + } │ │ │ │ }, │ │ │ │ - facsimile: function(node, phone) { │ │ │ │ - phone.facsimile = this.getChildValue(node) │ │ │ │ + Street: function(node, address) { │ │ │ │ + address.street.push(this.getChildValue(node)) │ │ │ │ }, │ │ │ │ - address: function(node, contactInfo) { │ │ │ │ - contactInfo.address = {}; │ │ │ │ - this.readChildNodes(node, contactInfo.address) │ │ │ │ + Place: function(node, address) { │ │ │ │ + address.place[node.getAttribute("type")] = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - deliveryPoint: function(node, address) { │ │ │ │ - address.deliveryPoint = this.getChildValue(node) │ │ │ │ + PostalCode: function(node, address) { │ │ │ │ + address.postalCode = this.getChildValue(node) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + gml: OpenLayers.Format.GML.v3.prototype.readers.gml │ │ │ │ + }, │ │ │ │ + write: function(request) { │ │ │ │ + return this.writers.xls.XLS.apply(this, [request]) │ │ │ │ + }, │ │ │ │ + writers: { │ │ │ │ + xls: { │ │ │ │ + XLS: function(request) { │ │ │ │ + var root = this.createElementNSPlus("xls:XLS", { │ │ │ │ + attributes: { │ │ │ │ + version: this.VERSION, │ │ │ │ + "xsi:schemaLocation": this.schemaLocation │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.writeNode("RequestHeader", request.header, root); │ │ │ │ + this.writeNode("Request", request, root); │ │ │ │ + return root │ │ │ │ }, │ │ │ │ - city: function(node, address) { │ │ │ │ - address.city = this.getChildValue(node) │ │ │ │ + RequestHeader: function(header) { │ │ │ │ + return this.createElementNSPlus("xls:RequestHeader") │ │ │ │ }, │ │ │ │ - postalCode: function(node, address) { │ │ │ │ - address.postalCode = this.getChildValue(node) │ │ │ │ + Request: function(request) { │ │ │ │ + var node = this.createElementNSPlus("xls:Request", { │ │ │ │ + attributes: { │ │ │ │ + methodName: "GeocodeRequest", │ │ │ │ + requestID: request.requestID || "", │ │ │ │ + version: this.VERSION │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.writeNode("GeocodeRequest", request.addresses, node); │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - country: function(node, address) { │ │ │ │ - address.country = this.getChildValue(node) │ │ │ │ + GeocodeRequest: function(addresses) { │ │ │ │ + var node = this.createElementNSPlus("xls:GeocodeRequest"); │ │ │ │ + for (var i = 0, len = addresses.length; i < len; i++) { │ │ │ │ + this.writeNode("Address", addresses[i], node) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - electronicMailAddress: function(node, address) { │ │ │ │ - address.electronicMailAddress = this.getChildValue(node) │ │ │ │ + Address: function(address) { │ │ │ │ + var node = this.createElementNSPlus("xls:Address", { │ │ │ │ + attributes: { │ │ │ │ + countryCode: address.countryCode │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (address.freeFormAddress) { │ │ │ │ + this.writeNode("freeFormAddress", address.freeFormAddress, node) │ │ │ │ + } else { │ │ │ │ + if (address.street) { │ │ │ │ + this.writeNode("StreetAddress", address, node) │ │ │ │ + } │ │ │ │ + if (address.municipality) { │ │ │ │ + this.writeNode("Municipality", address.municipality, node) │ │ │ │ + } │ │ │ │ + if (address.countrySubdivision) { │ │ │ │ + this.writeNode("CountrySubdivision", address.countrySubdivision, node) │ │ │ │ + } │ │ │ │ + if (address.postalCode) { │ │ │ │ + this.writeNode("PostalCode", address.postalCode, node) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - fees: function(node, service) { │ │ │ │ - service.fees = this.getChildValue(node) │ │ │ │ + freeFormAddress: function(freeFormAddress) { │ │ │ │ + return this.createElementNSPlus("freeFormAddress", { │ │ │ │ + value: freeFormAddress │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - accessConstraints: function(node, service) { │ │ │ │ - service.accessConstraints = this.getChildValue(node) │ │ │ │ + StreetAddress: function(address) { │ │ │ │ + var node = this.createElementNSPlus("xls:StreetAddress"); │ │ │ │ + if (address.building) { │ │ │ │ + this.writeNode(node, "Building", address.building) │ │ │ │ + } │ │ │ │ + var street = address.street; │ │ │ │ + if (!OpenLayers.Util.isArray(street)) { │ │ │ │ + street = [street] │ │ │ │ + } │ │ │ │ + for (var i = 0, len = street.length; i < len; i++) { │ │ │ │ + this.writeNode("Street", street[i], node) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - ContentMetadata: function(node, obj) { │ │ │ │ - obj.contentMetadata = []; │ │ │ │ - this.readChildNodes(node, obj.contentMetadata) │ │ │ │ + Building: function(building) { │ │ │ │ + return this.createElementNSPlus("xls:Building", { │ │ │ │ + attributes: { │ │ │ │ + number: building["number"], │ │ │ │ + subdivision: building.subdivision, │ │ │ │ + buildingName: building.buildingName │ │ │ │ + } │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - CoverageOfferingBrief: function(node, contentMetadata) { │ │ │ │ - var coverageOfferingBrief = {}; │ │ │ │ - this.readChildNodes(node, coverageOfferingBrief); │ │ │ │ - contentMetadata.push(coverageOfferingBrief) │ │ │ │ + Street: function(street) { │ │ │ │ + return this.createElementNSPlus("xls:Street", { │ │ │ │ + value: street │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - name: function(node, coverageOfferingBrief) { │ │ │ │ - coverageOfferingBrief.name = this.getChildValue(node) │ │ │ │ + Municipality: function(municipality) { │ │ │ │ + return this.createElementNSPlus("xls:Place", { │ │ │ │ + attributes: { │ │ │ │ + type: "Municipality" │ │ │ │ + }, │ │ │ │ + value: municipality │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - label: function(node, coverageOfferingBrief) { │ │ │ │ - coverageOfferingBrief.label = this.getChildValue(node) │ │ │ │ + CountrySubdivision: function(countrySubdivision) { │ │ │ │ + return this.createElementNSPlus("xls:Place", { │ │ │ │ + attributes: { │ │ │ │ + type: "CountrySubdivision" │ │ │ │ + }, │ │ │ │ + value: countrySubdivision │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - lonLatEnvelope: function(node, coverageOfferingBrief) { │ │ │ │ - var nodeList = this.getElementsByTagNameNS(node, "http://www.opengis.net/gml", "pos"); │ │ │ │ - if (nodeList.length == 2) { │ │ │ │ - var min = {}; │ │ │ │ - var max = {}; │ │ │ │ - OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[0], min]); │ │ │ │ - OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[1], max]); │ │ │ │ - coverageOfferingBrief.lonLatEnvelope = {}; │ │ │ │ - coverageOfferingBrief.lonLatEnvelope.srsName = node.getAttribute("srsName"); │ │ │ │ - coverageOfferingBrief.lonLatEnvelope.min = min.points[0]; │ │ │ │ - coverageOfferingBrief.lonLatEnvelope.max = max.points[0] │ │ │ │ - } │ │ │ │ + PostalCode: function(postalCode) { │ │ │ │ + return this.createElementNSPlus("xls:PostalCode", { │ │ │ │ + value: postalCode │ │ │ │ + }) │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_0_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.XLS.v1" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.WFSCapabilities.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ +OpenLayers.Format.XLS.v1_1_0 = OpenLayers.Class(OpenLayers.Format.XLS.v1, { │ │ │ │ + VERSION: "1.1", │ │ │ │ + schemaLocation: "http://www.opengis.net/xls http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd", │ │ │ │ + CLASS_NAME: "OpenLayers.Format.XLS.v1_1_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.XLS.v1_1 = OpenLayers.Format.XLS.v1_1_0; │ │ │ │ +OpenLayers.Format.CSWGetDomain.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ namespaces: { │ │ │ │ - wfs: "http://www.opengis.net/wfs", │ │ │ │ xlink: "http://www.w3.org/1999/xlink", │ │ │ │ xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ - ows: "http://www.opengis.net/ows" │ │ │ │ + csw: "http://www.opengis.net/cat/csw/2.0.2" │ │ │ │ }, │ │ │ │ - errorProperty: "featureTypeList", │ │ │ │ - defaultPrefix: "wfs", │ │ │ │ + defaultPrefix: "csw", │ │ │ │ + version: "2.0.2", │ │ │ │ + schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ + PropertyName: null, │ │ │ │ + ParameterName: null, │ │ │ │ read: function(data) { │ │ │ │ if (typeof data == "string") { │ │ │ │ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ } │ │ │ │ - var raw = data; │ │ │ │ if (data && data.nodeType == 9) { │ │ │ │ data = data.documentElement │ │ │ │ } │ │ │ │ - var capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - return capabilities │ │ │ │ + var obj = {}; │ │ │ │ + this.readNode(data, obj); │ │ │ │ + return obj │ │ │ │ }, │ │ │ │ readers: { │ │ │ │ - wfs: { │ │ │ │ - WFS_Capabilities: function(node, obj) { │ │ │ │ + csw: { │ │ │ │ + GetDomainResponse: function(node, obj) { │ │ │ │ this.readChildNodes(node, obj) │ │ │ │ }, │ │ │ │ - FeatureTypeList: function(node, request) { │ │ │ │ - request.featureTypeList = { │ │ │ │ - featureTypes: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, request.featureTypeList) │ │ │ │ - }, │ │ │ │ - FeatureType: function(node, featureTypeList) { │ │ │ │ - var featureType = {}; │ │ │ │ - this.readChildNodes(node, featureType); │ │ │ │ - featureTypeList.featureTypes.push(featureType) │ │ │ │ - }, │ │ │ │ - Name: function(node, obj) { │ │ │ │ - var name = this.getChildValue(node); │ │ │ │ - if (name) { │ │ │ │ - var parts = name.split(":"); │ │ │ │ - obj.name = parts.pop(); │ │ │ │ - if (parts.length > 0) { │ │ │ │ - obj.featureNS = this.lookupNamespaceURI(node, parts[0]) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - Title: function(node, obj) { │ │ │ │ - var title = this.getChildValue(node); │ │ │ │ - if (title) { │ │ │ │ - obj.title = title │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - Abstract: function(node, obj) { │ │ │ │ - var abst = this.getChildValue(node); │ │ │ │ - if (abst) { │ │ │ │ - obj["abstract"] = abst │ │ │ │ + DomainValues: function(node, obj) { │ │ │ │ + if (!OpenLayers.Util.isArray(obj.DomainValues)) { │ │ │ │ + obj.DomainValues = [] │ │ │ │ } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WFSCapabilities.v1_1_0 = OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ - regExes: { │ │ │ │ - trimSpace: /^\s*|\s*$/g, │ │ │ │ - removeSpace: /\s*/g, │ │ │ │ - splitSpace: /\s+/, │ │ │ │ - trimComma: /\s*,\s*/g │ │ │ │ - }, │ │ │ │ - readers: { │ │ │ │ - wfs: OpenLayers.Util.applyDefaults({ │ │ │ │ - DefaultSRS: function(node, obj) { │ │ │ │ - var defaultSRS = this.getChildValue(node); │ │ │ │ - if (defaultSRS) { │ │ │ │ - obj.srs = defaultSRS │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var domainValue = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + domainValue[attrs[i].name] = attrs[i].nodeValue │ │ │ │ } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]), │ │ │ │ - ows: OpenLayers.Format.OWSCommon.v1.prototype.readers.ows │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_1_0" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WFSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ - readers: { │ │ │ │ - wfs: OpenLayers.Util.applyDefaults({ │ │ │ │ - Service: function(node, capabilities) { │ │ │ │ - capabilities.service = {}; │ │ │ │ - this.readChildNodes(node, capabilities.service) │ │ │ │ + this.readChildNodes(node, domainValue); │ │ │ │ + obj.DomainValues.push(domainValue) │ │ │ │ }, │ │ │ │ - Fees: function(node, service) { │ │ │ │ - var fees = this.getChildValue(node); │ │ │ │ - if (fees && fees.toLowerCase() != "none") { │ │ │ │ - service.fees = fees │ │ │ │ - } │ │ │ │ + PropertyName: function(node, obj) { │ │ │ │ + obj.PropertyName = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - AccessConstraints: function(node, service) { │ │ │ │ - var constraints = this.getChildValue(node); │ │ │ │ - if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ - service.accessConstraints = constraints │ │ │ │ - } │ │ │ │ + ParameterName: function(node, obj) { │ │ │ │ + obj.ParameterName = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - OnlineResource: function(node, service) { │ │ │ │ - var onlineResource = this.getChildValue(node); │ │ │ │ - if (onlineResource && onlineResource.toLowerCase() != "none") { │ │ │ │ - service.onlineResource = onlineResource │ │ │ │ + ListOfValues: function(node, obj) { │ │ │ │ + if (!OpenLayers.Util.isArray(obj.ListOfValues)) { │ │ │ │ + obj.ListOfValues = [] │ │ │ │ } │ │ │ │ + this.readChildNodes(node, obj.ListOfValues) │ │ │ │ }, │ │ │ │ - Keywords: function(node, service) { │ │ │ │ - var keywords = this.getChildValue(node); │ │ │ │ - if (keywords && keywords.toLowerCase() != "none") { │ │ │ │ - service.keywords = keywords.split(", ") │ │ │ │ + Value: function(node, obj) { │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var value = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + value[attrs[i].name] = attrs[i].nodeValue │ │ │ │ } │ │ │ │ + value.value = this.getChildValue(node); │ │ │ │ + obj.push({ │ │ │ │ + Value: value │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - Capability: function(node, capabilities) { │ │ │ │ - capabilities.capability = {}; │ │ │ │ - this.readChildNodes(node, capabilities.capability) │ │ │ │ - }, │ │ │ │ - Request: function(node, obj) { │ │ │ │ - obj.request = {}; │ │ │ │ - this.readChildNodes(node, obj.request) │ │ │ │ - }, │ │ │ │ - GetFeature: function(node, request) { │ │ │ │ - request.getfeature = { │ │ │ │ - href: {}, │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, request.getfeature) │ │ │ │ + ConceptualScheme: function(node, obj) { │ │ │ │ + obj.ConceptualScheme = {}; │ │ │ │ + this.readChildNodes(node, obj.ConceptualScheme) │ │ │ │ }, │ │ │ │ - ResultFormat: function(node, obj) { │ │ │ │ - var children = node.childNodes; │ │ │ │ - var childNode; │ │ │ │ - for (var i = 0; i < children.length; i++) { │ │ │ │ - childNode = children[i]; │ │ │ │ - if (childNode.nodeType == 1) { │ │ │ │ - obj.formats.push(childNode.nodeName) │ │ │ │ - } │ │ │ │ - } │ │ │ │ + Name: function(node, obj) { │ │ │ │ + obj.Name = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - DCPType: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ + Document: function(node, obj) { │ │ │ │ + obj.Document = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - HTTP: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj.href) │ │ │ │ + Authority: function(node, obj) { │ │ │ │ + obj.Authority = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - Get: function(node, obj) { │ │ │ │ - obj.get = node.getAttribute("onlineResource") │ │ │ │ + RangeOfValues: function(node, obj) { │ │ │ │ + obj.RangeOfValues = {}; │ │ │ │ + this.readChildNodes(node, obj.RangeOfValues) │ │ │ │ }, │ │ │ │ - Post: function(node, obj) { │ │ │ │ - obj.post = node.getAttribute("onlineResource") │ │ │ │ + MinValue: function(node, obj) { │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var value = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + value[attrs[i].name] = attrs[i].nodeValue │ │ │ │ + } │ │ │ │ + value.value = this.getChildValue(node); │ │ │ │ + obj.MinValue = value │ │ │ │ }, │ │ │ │ - SRS: function(node, obj) { │ │ │ │ - var srs = this.getChildValue(node); │ │ │ │ - if (srs) { │ │ │ │ - obj.srs = srs │ │ │ │ + MaxValue: function(node, obj) { │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var value = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + value[attrs[i].name] = attrs[i].nodeValue │ │ │ │ } │ │ │ │ + value.value = this.getChildValue(node); │ │ │ │ + obj.MaxValue = value │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_0_0" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.SOSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.SOSCapabilities, { │ │ │ │ - namespaces: { │ │ │ │ - ows: "http://www.opengis.net/ows/1.1", │ │ │ │ - sos: "http://www.opengis.net/sos/1.0", │ │ │ │ - gml: "http://www.opengis.net/gml", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink" │ │ │ │ - }, │ │ │ │ - regExes: { │ │ │ │ - trimSpace: /^\s*|\s*$/g, │ │ │ │ - removeSpace: /\s*/g, │ │ │ │ - splitSpace: /\s+/, │ │ │ │ - trimComma: /\s*,\s*/g │ │ │ │ - }, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ - this.options = options │ │ │ │ - }, │ │ │ │ - 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 capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - return capabilities │ │ │ │ }, │ │ │ │ - readers: { │ │ │ │ - gml: OpenLayers.Util.applyDefaults({ │ │ │ │ - name: function(node, obj) { │ │ │ │ - obj.name = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - TimePeriod: function(node, obj) { │ │ │ │ - obj.timePeriod = {}; │ │ │ │ - this.readChildNodes(node, obj.timePeriod) │ │ │ │ - }, │ │ │ │ - beginPosition: function(node, timePeriod) { │ │ │ │ - timePeriod.beginPosition = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - endPosition: function(node, timePeriod) { │ │ │ │ - timePeriod.endPosition = this.getChildValue(node) │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.GML.v3.prototype.readers["gml"]), │ │ │ │ - sos: { │ │ │ │ - Capabilities: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - Contents: function(node, obj) { │ │ │ │ - obj.contents = {}; │ │ │ │ - this.readChildNodes(node, obj.contents) │ │ │ │ - }, │ │ │ │ - ObservationOfferingList: function(node, contents) { │ │ │ │ - contents.offeringList = {}; │ │ │ │ - this.readChildNodes(node, contents.offeringList) │ │ │ │ - }, │ │ │ │ - ObservationOffering: function(node, offeringList) { │ │ │ │ - var id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ - offeringList[id] = { │ │ │ │ - procedures: [], │ │ │ │ - observedProperties: [], │ │ │ │ - featureOfInterestIds: [], │ │ │ │ - responseFormats: [], │ │ │ │ - resultModels: [], │ │ │ │ - responseModes: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, offeringList[id]) │ │ │ │ - }, │ │ │ │ - time: function(node, offering) { │ │ │ │ - offering.time = {}; │ │ │ │ - this.readChildNodes(node, offering.time) │ │ │ │ - }, │ │ │ │ - procedure: function(node, offering) { │ │ │ │ - offering.procedures.push(this.getAttributeNS(node, this.namespaces.xlink, "href")) │ │ │ │ - }, │ │ │ │ - observedProperty: function(node, offering) { │ │ │ │ - offering.observedProperties.push(this.getAttributeNS(node, this.namespaces.xlink, "href")) │ │ │ │ - }, │ │ │ │ - featureOfInterest: function(node, offering) { │ │ │ │ - offering.featureOfInterestIds.push(this.getAttributeNS(node, this.namespaces.xlink, "href")) │ │ │ │ - }, │ │ │ │ - responseFormat: function(node, offering) { │ │ │ │ - offering.responseFormats.push(this.getChildValue(node)) │ │ │ │ + write: function(options) { │ │ │ │ + var node = this.writeNode("csw:GetDomain", options); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [node]) │ │ │ │ + }, │ │ │ │ + writers: { │ │ │ │ + csw: { │ │ │ │ + GetDomain: function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:GetDomain", { │ │ │ │ + attributes: { │ │ │ │ + service: "CSW", │ │ │ │ + version: this.version │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (options.PropertyName || this.PropertyName) { │ │ │ │ + this.writeNode("csw:PropertyName", options.PropertyName || this.PropertyName, node) │ │ │ │ + } else if (options.ParameterName || this.ParameterName) { │ │ │ │ + this.writeNode("csw:ParameterName", options.ParameterName || this.ParameterName, node) │ │ │ │ + } │ │ │ │ + this.readChildNodes(node, options); │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - resultModel: function(node, offering) { │ │ │ │ - offering.resultModels.push(this.getChildValue(node)) │ │ │ │ + PropertyName: function(value) { │ │ │ │ + var node = this.createElementNSPlus("csw:PropertyName", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - responseMode: function(node, offering) { │ │ │ │ - offering.responseModes.push(this.getChildValue(node)) │ │ │ │ + ParameterName: function(value) { │ │ │ │ + var node = this.createElementNSPlus("csw:ParameterName", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ } │ │ │ │ - }, │ │ │ │ - ows: OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ + } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SOSCapabilities.v1_0_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.CSWGetDomain.v2_0_2" │ │ │ │ }); │ │ │ │ OpenLayers.Format.OWSContext.v0_3_1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ namespaces: { │ │ │ │ owc: "http://www.opengis.net/ows-context", │ │ │ │ gml: "http://www.opengis.net/gml", │ │ │ │ kml: "http://www.opengis.net/kml/2.2", │ │ │ │ ogc: "http://www.opengis.net/ogc", │ │ │ │ @@ -36627,1044 +36129,1084 @@ │ │ │ │ }, OpenLayers.Format.GML.v2.prototype.writers.gml), │ │ │ │ ows: OpenLayers.Format.OWSCommon.v1_0_0.prototype.writers.ows, │ │ │ │ sld: OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld, │ │ │ │ feature: OpenLayers.Format.GML.v2.prototype.writers.feature │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.OWSContext.v0_3_1" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.XLS.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ +OpenLayers.Format.WPSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ namespaces: { │ │ │ │ - xls: "http://www.opengis.net/xls", │ │ │ │ - gml: "http://www.opengis.net/gml", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + ows: "http://www.opengis.net/ows/1.1", │ │ │ │ + wps: "http://www.opengis.net/wps/1.0.0", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink" │ │ │ │ }, │ │ │ │ regExes: { │ │ │ │ trimSpace: /^\s*|\s*$/g, │ │ │ │ removeSpace: /\s*/g, │ │ │ │ splitSpace: /\s+/, │ │ │ │ trimComma: /\s*,\s*/g │ │ │ │ }, │ │ │ │ - xy: true, │ │ │ │ - defaultPrefix: "xls", │ │ │ │ - schemaLocation: null, │ │ │ │ - read: function(data, options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ - var xls = {}; │ │ │ │ - this.readChildNodes(data, xls); │ │ │ │ - return xls │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + 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 capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + return capabilities │ │ │ │ }, │ │ │ │ readers: { │ │ │ │ - xls: { │ │ │ │ - XLS: function(node, xls) { │ │ │ │ - xls.version = node.getAttribute("version"); │ │ │ │ - this.readChildNodes(node, xls) │ │ │ │ - }, │ │ │ │ - Response: function(node, xls) { │ │ │ │ - this.readChildNodes(node, xls) │ │ │ │ + wps: { │ │ │ │ + Capabilities: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ }, │ │ │ │ - GeocodeResponse: function(node, xls) { │ │ │ │ - xls.responseLists = []; │ │ │ │ - this.readChildNodes(node, xls) │ │ │ │ + ProcessOfferings: function(node, obj) { │ │ │ │ + obj.processOfferings = {}; │ │ │ │ + this.readChildNodes(node, obj.processOfferings) │ │ │ │ }, │ │ │ │ - GeocodeResponseList: function(node, xls) { │ │ │ │ - var responseList = { │ │ │ │ - features: [], │ │ │ │ - numberOfGeocodedAddresses: parseInt(node.getAttribute("numberOfGeocodedAddresses")) │ │ │ │ + Process: function(node, processOfferings) { │ │ │ │ + var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); │ │ │ │ + var process = { │ │ │ │ + processVersion: processVersion │ │ │ │ }; │ │ │ │ - xls.responseLists.push(responseList); │ │ │ │ - this.readChildNodes(node, responseList) │ │ │ │ - }, │ │ │ │ - GeocodedAddress: function(node, responseList) { │ │ │ │ - var feature = new OpenLayers.Feature.Vector; │ │ │ │ - responseList.features.push(feature); │ │ │ │ - this.readChildNodes(node, feature); │ │ │ │ - feature.geometry = feature.components[0] │ │ │ │ + this.readChildNodes(node, process); │ │ │ │ + processOfferings[process.identifier] = process │ │ │ │ }, │ │ │ │ - GeocodeMatchCode: function(node, feature) { │ │ │ │ - feature.attributes.matchCode = { │ │ │ │ - accuracy: parseFloat(node.getAttribute("accuracy")), │ │ │ │ - matchType: node.getAttribute("matchType") │ │ │ │ - } │ │ │ │ + Languages: function(node, obj) { │ │ │ │ + obj.languages = []; │ │ │ │ + this.readChildNodes(node, obj.languages) │ │ │ │ }, │ │ │ │ - Address: function(node, feature) { │ │ │ │ - var address = { │ │ │ │ - countryCode: node.getAttribute("countryCode"), │ │ │ │ - addressee: node.getAttribute("addressee"), │ │ │ │ - street: [], │ │ │ │ - place: [] │ │ │ │ + Default: function(node, languages) { │ │ │ │ + var language = { │ │ │ │ + isDefault: true │ │ │ │ }; │ │ │ │ - feature.attributes.address = address; │ │ │ │ - this.readChildNodes(node, address) │ │ │ │ - }, │ │ │ │ - freeFormAddress: function(node, address) { │ │ │ │ - address.freeFormAddress = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - StreetAddress: function(node, address) { │ │ │ │ - this.readChildNodes(node, address) │ │ │ │ - }, │ │ │ │ - Building: function(node, address) { │ │ │ │ - address.building = { │ │ │ │ - number: node.getAttribute("number"), │ │ │ │ - subdivision: node.getAttribute("subdivision"), │ │ │ │ - buildingName: node.getAttribute("buildingName") │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - Street: function(node, address) { │ │ │ │ - address.street.push(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - Place: function(node, address) { │ │ │ │ - address.place[node.getAttribute("type")] = this.getChildValue(node) │ │ │ │ + this.readChildNodes(node, language); │ │ │ │ + languages.push(language) │ │ │ │ }, │ │ │ │ - PostalCode: function(node, address) { │ │ │ │ - address.postalCode = this.getChildValue(node) │ │ │ │ + Supported: function(node, languages) { │ │ │ │ + var language = {}; │ │ │ │ + this.readChildNodes(node, language); │ │ │ │ + languages.push(language) │ │ │ │ } │ │ │ │ }, │ │ │ │ - gml: OpenLayers.Format.GML.v3.prototype.readers.gml │ │ │ │ + ows: OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ }, │ │ │ │ - write: function(request) { │ │ │ │ - return this.writers.xls.XLS.apply(this, [request]) │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WPSCapabilities.v1_0_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WFSCapabilities.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + namespaces: { │ │ │ │ + wfs: "http://www.opengis.net/wfs", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ + ows: "http://www.opengis.net/ows" │ │ │ │ }, │ │ │ │ - writers: { │ │ │ │ - xls: { │ │ │ │ - XLS: function(request) { │ │ │ │ - var root = this.createElementNSPlus("xls:XLS", { │ │ │ │ - attributes: { │ │ │ │ - version: this.VERSION, │ │ │ │ - "xsi:schemaLocation": this.schemaLocation │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.writeNode("RequestHeader", request.header, root); │ │ │ │ - this.writeNode("Request", request, root); │ │ │ │ - return root │ │ │ │ + errorProperty: "featureTypeList", │ │ │ │ + defaultPrefix: "wfs", │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ + } │ │ │ │ + var raw = data; │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement │ │ │ │ + } │ │ │ │ + var capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + return capabilities │ │ │ │ + }, │ │ │ │ + readers: { │ │ │ │ + wfs: { │ │ │ │ + WFS_Capabilities: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ }, │ │ │ │ - RequestHeader: function(header) { │ │ │ │ - return this.createElementNSPlus("xls:RequestHeader") │ │ │ │ + FeatureTypeList: function(node, request) { │ │ │ │ + request.featureTypeList = { │ │ │ │ + featureTypes: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, request.featureTypeList) │ │ │ │ }, │ │ │ │ - Request: function(request) { │ │ │ │ - var node = this.createElementNSPlus("xls:Request", { │ │ │ │ - attributes: { │ │ │ │ - methodName: "GeocodeRequest", │ │ │ │ - requestID: request.requestID || "", │ │ │ │ - version: this.VERSION │ │ │ │ + FeatureType: function(node, featureTypeList) { │ │ │ │ + var featureType = {}; │ │ │ │ + this.readChildNodes(node, featureType); │ │ │ │ + featureTypeList.featureTypes.push(featureType) │ │ │ │ + }, │ │ │ │ + Name: function(node, obj) { │ │ │ │ + var name = this.getChildValue(node); │ │ │ │ + if (name) { │ │ │ │ + var parts = name.split(":"); │ │ │ │ + obj.name = parts.pop(); │ │ │ │ + if (parts.length > 0) { │ │ │ │ + obj.featureNS = this.lookupNamespaceURI(node, parts[0]) │ │ │ │ } │ │ │ │ - }); │ │ │ │ - this.writeNode("GeocodeRequest", request.addresses, node); │ │ │ │ - return node │ │ │ │ + } │ │ │ │ }, │ │ │ │ - GeocodeRequest: function(addresses) { │ │ │ │ - var node = this.createElementNSPlus("xls:GeocodeRequest"); │ │ │ │ - for (var i = 0, len = addresses.length; i < len; i++) { │ │ │ │ - this.writeNode("Address", addresses[i], node) │ │ │ │ + Title: function(node, obj) { │ │ │ │ + var title = this.getChildValue(node); │ │ │ │ + if (title) { │ │ │ │ + obj.title = title │ │ │ │ } │ │ │ │ - return node │ │ │ │ }, │ │ │ │ - Address: function(address) { │ │ │ │ - var node = this.createElementNSPlus("xls:Address", { │ │ │ │ - attributes: { │ │ │ │ - countryCode: address.countryCode │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (address.freeFormAddress) { │ │ │ │ - this.writeNode("freeFormAddress", address.freeFormAddress, node) │ │ │ │ - } else { │ │ │ │ - if (address.street) { │ │ │ │ - this.writeNode("StreetAddress", address, node) │ │ │ │ - } │ │ │ │ - if (address.municipality) { │ │ │ │ - this.writeNode("Municipality", address.municipality, node) │ │ │ │ - } │ │ │ │ - if (address.countrySubdivision) { │ │ │ │ - this.writeNode("CountrySubdivision", address.countrySubdivision, node) │ │ │ │ - } │ │ │ │ - if (address.postalCode) { │ │ │ │ - this.writeNode("PostalCode", address.postalCode, node) │ │ │ │ - } │ │ │ │ + Abstract: function(node, obj) { │ │ │ │ + var abst = this.getChildValue(node); │ │ │ │ + if (abst) { │ │ │ │ + obj["abstract"] = abst │ │ │ │ } │ │ │ │ - return node │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WFSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ + readers: { │ │ │ │ + wfs: OpenLayers.Util.applyDefaults({ │ │ │ │ + Service: function(node, capabilities) { │ │ │ │ + capabilities.service = {}; │ │ │ │ + this.readChildNodes(node, capabilities.service) │ │ │ │ }, │ │ │ │ - freeFormAddress: function(freeFormAddress) { │ │ │ │ - return this.createElementNSPlus("freeFormAddress", { │ │ │ │ - value: freeFormAddress │ │ │ │ - }) │ │ │ │ + Fees: function(node, service) { │ │ │ │ + var fees = this.getChildValue(node); │ │ │ │ + if (fees && fees.toLowerCase() != "none") { │ │ │ │ + service.fees = fees │ │ │ │ + } │ │ │ │ }, │ │ │ │ - StreetAddress: function(address) { │ │ │ │ - var node = this.createElementNSPlus("xls:StreetAddress"); │ │ │ │ - if (address.building) { │ │ │ │ - this.writeNode(node, "Building", address.building) │ │ │ │ + AccessConstraints: function(node, service) { │ │ │ │ + var constraints = this.getChildValue(node); │ │ │ │ + if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ + service.accessConstraints = constraints │ │ │ │ } │ │ │ │ - var street = address.street; │ │ │ │ - if (!OpenLayers.Util.isArray(street)) { │ │ │ │ - street = [street] │ │ │ │ + }, │ │ │ │ + OnlineResource: function(node, service) { │ │ │ │ + var onlineResource = this.getChildValue(node); │ │ │ │ + if (onlineResource && onlineResource.toLowerCase() != "none") { │ │ │ │ + service.onlineResource = onlineResource │ │ │ │ } │ │ │ │ - for (var i = 0, len = street.length; i < len; i++) { │ │ │ │ - this.writeNode("Street", street[i], node) │ │ │ │ + }, │ │ │ │ + Keywords: function(node, service) { │ │ │ │ + var keywords = this.getChildValue(node); │ │ │ │ + if (keywords && keywords.toLowerCase() != "none") { │ │ │ │ + service.keywords = keywords.split(", ") │ │ │ │ } │ │ │ │ - return node │ │ │ │ }, │ │ │ │ - Building: function(building) { │ │ │ │ - return this.createElementNSPlus("xls:Building", { │ │ │ │ - attributes: { │ │ │ │ - number: building["number"], │ │ │ │ - subdivision: building.subdivision, │ │ │ │ - buildingName: building.buildingName │ │ │ │ + Capability: function(node, capabilities) { │ │ │ │ + capabilities.capability = {}; │ │ │ │ + this.readChildNodes(node, capabilities.capability) │ │ │ │ + }, │ │ │ │ + Request: function(node, obj) { │ │ │ │ + obj.request = {}; │ │ │ │ + this.readChildNodes(node, obj.request) │ │ │ │ + }, │ │ │ │ + GetFeature: function(node, request) { │ │ │ │ + request.getfeature = { │ │ │ │ + href: {}, │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, request.getfeature) │ │ │ │ + }, │ │ │ │ + ResultFormat: function(node, obj) { │ │ │ │ + var children = node.childNodes; │ │ │ │ + var childNode; │ │ │ │ + for (var i = 0; i < children.length; i++) { │ │ │ │ + childNode = children[i]; │ │ │ │ + if (childNode.nodeType == 1) { │ │ │ │ + obj.formats.push(childNode.nodeName) │ │ │ │ } │ │ │ │ - }) │ │ │ │ + } │ │ │ │ }, │ │ │ │ - Street: function(street) { │ │ │ │ - return this.createElementNSPlus("xls:Street", { │ │ │ │ - value: street │ │ │ │ - }) │ │ │ │ + DCPType: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ }, │ │ │ │ - Municipality: function(municipality) { │ │ │ │ - return this.createElementNSPlus("xls:Place", { │ │ │ │ - attributes: { │ │ │ │ - type: "Municipality" │ │ │ │ - }, │ │ │ │ - value: municipality │ │ │ │ - }) │ │ │ │ + HTTP: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj.href) │ │ │ │ }, │ │ │ │ - CountrySubdivision: function(countrySubdivision) { │ │ │ │ - return this.createElementNSPlus("xls:Place", { │ │ │ │ - attributes: { │ │ │ │ - type: "CountrySubdivision" │ │ │ │ - }, │ │ │ │ - value: countrySubdivision │ │ │ │ - }) │ │ │ │ + Get: function(node, obj) { │ │ │ │ + obj.get = node.getAttribute("onlineResource") │ │ │ │ }, │ │ │ │ - PostalCode: function(postalCode) { │ │ │ │ - return this.createElementNSPlus("xls:PostalCode", { │ │ │ │ - value: postalCode │ │ │ │ - }) │ │ │ │ + Post: function(node, obj) { │ │ │ │ + obj.post = node.getAttribute("onlineResource") │ │ │ │ + }, │ │ │ │ + SRS: function(node, obj) { │ │ │ │ + var srs = this.getChildValue(node); │ │ │ │ + if (srs) { │ │ │ │ + obj.srs = srs │ │ │ │ + } │ │ │ │ } │ │ │ │ - } │ │ │ │ + }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.XLS.v1" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.XLS.v1_1_0 = OpenLayers.Class(OpenLayers.Format.XLS.v1, { │ │ │ │ - VERSION: "1.1", │ │ │ │ - schemaLocation: "http://www.opengis.net/xls http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd", │ │ │ │ - CLASS_NAME: "OpenLayers.Format.XLS.v1_1_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_0_0" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.XLS.v1_1 = OpenLayers.Format.XLS.v1_1_0; │ │ │ │ -OpenLayers.Tile.Image.IFrame = { │ │ │ │ - useIFrame: null, │ │ │ │ - blankImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7", │ │ │ │ - draw: function() { │ │ │ │ - var draw = OpenLayers.Tile.Image.prototype.shouldDraw.call(this); │ │ │ │ - if (draw) { │ │ │ │ - var url = this.layer.getURL(this.bounds); │ │ │ │ - var usedIFrame = this.useIFrame; │ │ │ │ - this.useIFrame = this.maxGetUrlLength !== null && !this.layer.async && url.length > this.maxGetUrlLength; │ │ │ │ - var fromIFrame = usedIFrame && !this.useIFrame; │ │ │ │ - var toIFrame = !usedIFrame && this.useIFrame; │ │ │ │ - if (fromIFrame || toIFrame) { │ │ │ │ - if (this.imgDiv && this.imgDiv.parentNode === this.frame) { │ │ │ │ - this.frame.removeChild(this.imgDiv) │ │ │ │ - } │ │ │ │ - this.imgDiv = null; │ │ │ │ - if (fromIFrame) { │ │ │ │ - this.frame.removeChild(this.frame.firstChild) │ │ │ │ +OpenLayers.Format.WFSCapabilities.v1_1_0 = OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ + regExes: { │ │ │ │ + trimSpace: /^\s*|\s*$/g, │ │ │ │ + removeSpace: /\s*/g, │ │ │ │ + splitSpace: /\s+/, │ │ │ │ + trimComma: /\s*,\s*/g │ │ │ │ + }, │ │ │ │ + readers: { │ │ │ │ + wfs: OpenLayers.Util.applyDefaults({ │ │ │ │ + DefaultSRS: function(node, obj) { │ │ │ │ + var defaultSRS = this.getChildValue(node); │ │ │ │ + if (defaultSRS) { │ │ │ │ + obj.srs = defaultSRS │ │ │ │ } │ │ │ │ } │ │ │ │ - } │ │ │ │ - return OpenLayers.Tile.Image.prototype.draw.apply(this, arguments) │ │ │ │ + }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]), │ │ │ │ + ows: OpenLayers.Format.OWSCommon.v1.prototype.readers.ows │ │ │ │ }, │ │ │ │ - getImage: function() { │ │ │ │ - if (this.useIFrame === true) { │ │ │ │ - if (!this.frame.childNodes.length) { │ │ │ │ - var eventPane = document.createElement("div"), │ │ │ │ - style = eventPane.style; │ │ │ │ - style.position = "absolute"; │ │ │ │ - style.width = "100%"; │ │ │ │ - style.height = "100%"; │ │ │ │ - style.zIndex = 1; │ │ │ │ - style.backgroundImage = "url(" + this.blankImageUrl + ")"; │ │ │ │ - this.frame.appendChild(eventPane) │ │ │ │ - } │ │ │ │ - var id = this.id + "_iFrame", │ │ │ │ - iframe; │ │ │ │ - if (parseFloat(navigator.appVersion.split("MSIE")[1]) < 9) { │ │ │ │ - iframe = document.createElement('<iframe name="' + id + '">'); │ │ │ │ - iframe.style.backgroundColor = "#FFFFFF"; │ │ │ │ - iframe.style.filter = "chroma(color=#FFFFFF)" │ │ │ │ - } else { │ │ │ │ - iframe = document.createElement("iframe"); │ │ │ │ - iframe.style.backgroundColor = "transparent"; │ │ │ │ - iframe.name = id │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_1_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class(OpenLayers.Format.SLD.v1_0_0, { │ │ │ │ + version: "1.0.0", │ │ │ │ + profile: "GeoServer", │ │ │ │ + readers: OpenLayers.Util.applyDefaults({ │ │ │ │ + sld: OpenLayers.Util.applyDefaults({ │ │ │ │ + Priority: function(node, obj) { │ │ │ │ + var value = this.readers.ogc._expression.call(this, node); │ │ │ │ + if (value) { │ │ │ │ + obj.priority = value │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + VendorOption: function(node, obj) { │ │ │ │ + if (!obj.vendorOptions) { │ │ │ │ + obj.vendorOptions = {} │ │ │ │ + } │ │ │ │ + obj.vendorOptions[node.getAttribute("name")] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + TextSymbolizer: function(node, rule) { │ │ │ │ + OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld.TextSymbolizer.apply(this, arguments); │ │ │ │ + var symbolizer = this.multipleSymbolizers ? rule.symbolizers[rule.symbolizers.length - 1] : rule.symbolizer["Text"]; │ │ │ │ + if (symbolizer.graphic === undefined) { │ │ │ │ + symbolizer.graphic = false │ │ │ │ + } │ │ │ │ } │ │ │ │ - iframe.scrolling = "no"; │ │ │ │ - iframe.marginWidth = "0px"; │ │ │ │ - iframe.marginHeight = "0px"; │ │ │ │ - iframe.frameBorder = "0"; │ │ │ │ - iframe.style.position = "absolute"; │ │ │ │ - iframe.style.width = "100%"; │ │ │ │ - iframe.style.height = "100%"; │ │ │ │ - if (this.layer.opacity < 1) { │ │ │ │ - OpenLayers.Util.modifyDOMElement(iframe, null, null, null, null, null, null, this.layer.opacity) │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.readers["sld"]) │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.readers), │ │ │ │ + writers: OpenLayers.Util.applyDefaults({ │ │ │ │ + sld: OpenLayers.Util.applyDefaults({ │ │ │ │ + Priority: function(priority) { │ │ │ │ + return this.writers.sld._OGCExpression.call(this, "sld:Priority", priority) │ │ │ │ + }, │ │ │ │ + VendorOption: function(option) { │ │ │ │ + return this.createElementNSPlus("sld:VendorOption", { │ │ │ │ + attributes: { │ │ │ │ + name: option.name │ │ │ │ + }, │ │ │ │ + value: option.value │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + TextSymbolizer: function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["TextSymbolizer"].apply(this, arguments); │ │ │ │ + if (symbolizer.graphic !== false && (symbolizer.externalGraphic || symbolizer.graphicName)) { │ │ │ │ + this.writeNode("Graphic", symbolizer, node) │ │ │ │ + } │ │ │ │ + if ("priority" in symbolizer) { │ │ │ │ + this.writeNode("Priority", symbolizer.priority, node) │ │ │ │ + } │ │ │ │ + return this.addVendorOptions(node, symbolizer) │ │ │ │ + }, │ │ │ │ + PointSymbolizer: function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["PointSymbolizer"].apply(this, arguments); │ │ │ │ + return this.addVendorOptions(node, symbolizer) │ │ │ │ + }, │ │ │ │ + LineSymbolizer: function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["LineSymbolizer"].apply(this, arguments); │ │ │ │ + return this.addVendorOptions(node, symbolizer) │ │ │ │ + }, │ │ │ │ + PolygonSymbolizer: function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["PolygonSymbolizer"].apply(this, arguments); │ │ │ │ + return this.addVendorOptions(node, symbolizer) │ │ │ │ } │ │ │ │ - this.frame.appendChild(iframe); │ │ │ │ - this.imgDiv = iframe; │ │ │ │ - return iframe │ │ │ │ - } else { │ │ │ │ - return OpenLayers.Tile.Image.prototype.getImage.apply(this, arguments) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - createRequestForm: function() { │ │ │ │ - var form = document.createElement("form"); │ │ │ │ - form.method = "POST"; │ │ │ │ - var cacheId = this.layer.params["_OLSALT"]; │ │ │ │ - cacheId = (cacheId ? cacheId + "_" : "") + this.bounds.toBBOX(); │ │ │ │ - form.action = OpenLayers.Util.urlAppend(this.layer.url, cacheId); │ │ │ │ - form.target = this.id + "_iFrame"; │ │ │ │ - var imageSize = this.layer.getImageSize(), │ │ │ │ - params = OpenLayers.Util.getParameters(this.url), │ │ │ │ - field; │ │ │ │ - for (var par in params) { │ │ │ │ - field = document.createElement("input"); │ │ │ │ - field.type = "hidden"; │ │ │ │ - field.name = par; │ │ │ │ - field.value = params[par]; │ │ │ │ - form.appendChild(field) │ │ │ │ - } │ │ │ │ - return form │ │ │ │ - }, │ │ │ │ - setImgSrc: function(url) { │ │ │ │ - if (this.useIFrame === true) { │ │ │ │ - if (url) { │ │ │ │ - var form = this.createRequestForm(); │ │ │ │ - this.frame.appendChild(form); │ │ │ │ - form.submit(); │ │ │ │ - this.frame.removeChild(form) │ │ │ │ - } else if (this.imgDiv.parentNode === this.frame) { │ │ │ │ - this.frame.removeChild(this.imgDiv); │ │ │ │ - this.imgDiv = null │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.writers["sld"]) │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.writers), │ │ │ │ + addVendorOptions: function(node, symbolizer) { │ │ │ │ + var options = symbolizer.vendorOptions; │ │ │ │ + if (options) { │ │ │ │ + for (var key in symbolizer.vendorOptions) { │ │ │ │ + this.writeNode("VendorOption", { │ │ │ │ + name: key, │ │ │ │ + value: symbolizer.vendorOptions[key] │ │ │ │ + }, node) │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Tile.Image.prototype.setImgSrc.apply(this, arguments) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - onImageLoad: function() { │ │ │ │ - OpenLayers.Tile.Image.prototype.onImageLoad.apply(this, arguments); │ │ │ │ - if (this.useIFrame === true) { │ │ │ │ - this.imgDiv.style.opacity = 1; │ │ │ │ - this.frame.style.opacity = this.layer.opacity │ │ │ │ } │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - createBackBuffer: function() { │ │ │ │ - var backBuffer; │ │ │ │ - if (this.useIFrame === false) { │ │ │ │ - backBuffer = OpenLayers.Tile.Image.prototype.createBackBuffer.call(this) │ │ │ │ - } │ │ │ │ - return backBuffer │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -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) │ │ │ │ -}; │ │ │ │ -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)) │ │ │ │ -}; │ │ │ │ -OpenLayers.Protocol.WFS.DEFAULTS = { │ │ │ │ - version: "1.0.0" │ │ │ │ -}; │ │ │ │ -OpenLayers.Protocol.Script = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - url: null, │ │ │ │ - params: null, │ │ │ │ - callback: null, │ │ │ │ - callbackTemplate: "OpenLayers.Protocol.Script.registry.${id}", │ │ │ │ - callbackKey: "callback", │ │ │ │ - callbackPrefix: "", │ │ │ │ - scope: null, │ │ │ │ - format: null, │ │ │ │ - pendingRequests: null, │ │ │ │ - srsInBBOX: false, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0_GeoServer" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WMSDescribeLayer.v1_1_1 = OpenLayers.Class(OpenLayers.Format.WMSDescribeLayer, { │ │ │ │ initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - this.params = {}; │ │ │ │ - this.pendingRequests = {}; │ │ │ │ - OpenLayers.Protocol.prototype.initialize.apply(this, arguments); │ │ │ │ - if (!this.format) { │ │ │ │ - this.format = new OpenLayers.Format.GeoJSON │ │ │ │ + OpenLayers.Format.WMSDescribeLayer.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ } │ │ │ │ - if (!this.filterToParams && OpenLayers.Format.QueryStringFilter) { │ │ │ │ - var format = new OpenLayers.Format.QueryStringFilter({ │ │ │ │ - srsInBBOX: this.srsInBBOX │ │ │ │ - }); │ │ │ │ - this.filterToParams = function(filter, params) { │ │ │ │ - return format.write(filter, params) │ │ │ │ + var root = data.documentElement; │ │ │ │ + var children = root.childNodes; │ │ │ │ + var describelayer = { │ │ │ │ + layerDescriptions: [] │ │ │ │ + }; │ │ │ │ + var childNode, nodeName; │ │ │ │ + for (var i = 0; i < children.length; ++i) { │ │ │ │ + childNode = children[i]; │ │ │ │ + nodeName = childNode.nodeName; │ │ │ │ + if (nodeName == "LayerDescription") { │ │ │ │ + var layerName = childNode.getAttribute("name"); │ │ │ │ + var owsType = ""; │ │ │ │ + var owsURL = ""; │ │ │ │ + var typeName = ""; │ │ │ │ + if (childNode.getAttribute("owsType")) { │ │ │ │ + owsType = childNode.getAttribute("owsType"); │ │ │ │ + owsURL = childNode.getAttribute("owsURL") │ │ │ │ + } else { │ │ │ │ + if (childNode.getAttribute("wfs") != "") { │ │ │ │ + owsType = "WFS"; │ │ │ │ + owsURL = childNode.getAttribute("wfs") │ │ │ │ + } else if (childNode.getAttribute("wcs") != "") { │ │ │ │ + owsType = "WCS"; │ │ │ │ + owsURL = childNode.getAttribute("wcs") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var query = childNode.getElementsByTagName("Query"); │ │ │ │ + if (query.length > 0) { │ │ │ │ + typeName = query[0].getAttribute("typeName"); │ │ │ │ + if (!typeName) { │ │ │ │ + typeName = query[0].getAttribute("typename") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var layerDescription = { │ │ │ │ + layerName: layerName, │ │ │ │ + owsType: owsType, │ │ │ │ + owsURL: owsURL, │ │ │ │ + typeName: typeName │ │ │ │ + }; │ │ │ │ + describelayer.layerDescriptions.push(layerDescription); │ │ │ │ + describelayer.length = describelayer.layerDescriptions.length; │ │ │ │ + describelayer[describelayer.length - 1] = layerDescription │ │ │ │ + } else if (nodeName == "ServiceException") { │ │ │ │ + var parser = new OpenLayers.Format.OGCExceptionReport; │ │ │ │ + return { │ │ │ │ + error: parser.read(data) │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ + return describelayer │ │ │ │ }, │ │ │ │ - read: function(options) { │ │ │ │ - OpenLayers.Protocol.prototype.read.apply(this, arguments); │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ - options.params = OpenLayers.Util.applyDefaults(options.params, this.options.params); │ │ │ │ - if (options.filter && this.filterToParams) { │ │ │ │ - options.params = this.filterToParams(options.filter, options.params) │ │ │ │ - } │ │ │ │ - var response = new OpenLayers.Protocol.Response({ │ │ │ │ - requestType: "read" │ │ │ │ - }); │ │ │ │ - var request = this.createRequest(options.url, options.params, OpenLayers.Function.bind(function(data) { │ │ │ │ - response.data = data; │ │ │ │ - this.handleRead(response, options) │ │ │ │ - }, this)); │ │ │ │ - response.priv = request; │ │ │ │ - return response │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer.v1_1_1" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WMSDescribeLayer.v1_1_0 = OpenLayers.Format.WMSDescribeLayer.v1_1_1; │ │ │ │ +OpenLayers.Format.WMTSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.OWSCommon.v1_1_0, { │ │ │ │ + version: "1.0.0", │ │ │ │ + namespaces: { │ │ │ │ + ows: "http://www.opengis.net/ows/1.1", │ │ │ │ + wmts: "http://www.opengis.net/wmts/1.0", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink" │ │ │ │ }, │ │ │ │ - createRequest: function(url, params, callback) { │ │ │ │ - var id = OpenLayers.Protocol.Script.register(callback); │ │ │ │ - var name = OpenLayers.String.format(this.callbackTemplate, { │ │ │ │ - id: id │ │ │ │ - }); │ │ │ │ - params = OpenLayers.Util.extend({}, params); │ │ │ │ - params[this.callbackKey] = this.callbackPrefix + name; │ │ │ │ - url = OpenLayers.Util.urlAppend(url, OpenLayers.Util.getParameterString(params)); │ │ │ │ - var script = document.createElement("script"); │ │ │ │ - script.type = "text/javascript"; │ │ │ │ - script.src = url; │ │ │ │ - script.id = "OpenLayers_Protocol_Script_" + id; │ │ │ │ - this.pendingRequests[script.id] = script; │ │ │ │ - var head = document.getElementsByTagName("head")[0]; │ │ │ │ - head.appendChild(script); │ │ │ │ - return script │ │ │ │ + yx: null, │ │ │ │ + defaultPrefix: "wmts", │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ + this.options = options; │ │ │ │ + var yx = OpenLayers.Util.extend({}, OpenLayers.Format.WMTSCapabilities.prototype.yx); │ │ │ │ + this.yx = OpenLayers.Util.extend(yx, this.yx) │ │ │ │ }, │ │ │ │ - destroyRequest: function(script) { │ │ │ │ - OpenLayers.Protocol.Script.unregister(script.id.split("_").pop()); │ │ │ │ - delete this.pendingRequests[script.id]; │ │ │ │ - if (script.parentNode) { │ │ │ │ - script.parentNode.removeChild(script) │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ } │ │ │ │ - }, │ │ │ │ - handleRead: function(response, options) { │ │ │ │ - this.handleResponse(response, options) │ │ │ │ - }, │ │ │ │ - handleResponse: function(response, options) { │ │ │ │ - if (options.callback) { │ │ │ │ - if (response.data) { │ │ │ │ - response.features = this.parseFeatures(response.data); │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ - } else { │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ - } │ │ │ │ - this.destroyRequest(response.priv); │ │ │ │ - options.callback.call(options.scope, response) │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement │ │ │ │ } │ │ │ │ + var capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + capabilities.version = this.version; │ │ │ │ + return capabilities │ │ │ │ }, │ │ │ │ - parseFeatures: function(data) { │ │ │ │ - return this.format.read(data) │ │ │ │ - }, │ │ │ │ - abort: function(response) { │ │ │ │ - if (response) { │ │ │ │ - this.destroyRequest(response.priv) │ │ │ │ - } else { │ │ │ │ - for (var key in this.pendingRequests) { │ │ │ │ - this.destroyRequest(this.pendingRequests[key]) │ │ │ │ + readers: { │ │ │ │ + wmts: { │ │ │ │ + Capabilities: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + Contents: function(node, obj) { │ │ │ │ + obj.contents = {}; │ │ │ │ + obj.contents.layers = []; │ │ │ │ + obj.contents.tileMatrixSets = {}; │ │ │ │ + this.readChildNodes(node, obj.contents) │ │ │ │ + }, │ │ │ │ + Layer: function(node, obj) { │ │ │ │ + var layer = { │ │ │ │ + styles: [], │ │ │ │ + formats: [], │ │ │ │ + dimensions: [], │ │ │ │ + tileMatrixSetLinks: [] │ │ │ │ + }; │ │ │ │ + layer.layers = []; │ │ │ │ + this.readChildNodes(node, layer); │ │ │ │ + obj.layers.push(layer) │ │ │ │ + }, │ │ │ │ + Style: function(node, obj) { │ │ │ │ + var style = {}; │ │ │ │ + style.isDefault = node.getAttribute("isDefault") === "true"; │ │ │ │ + this.readChildNodes(node, style); │ │ │ │ + obj.styles.push(style) │ │ │ │ + }, │ │ │ │ + Format: function(node, obj) { │ │ │ │ + obj.formats.push(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + TileMatrixSetLink: function(node, obj) { │ │ │ │ + var tileMatrixSetLink = {}; │ │ │ │ + this.readChildNodes(node, tileMatrixSetLink); │ │ │ │ + obj.tileMatrixSetLinks.push(tileMatrixSetLink) │ │ │ │ + }, │ │ │ │ + TileMatrixSet: function(node, obj) { │ │ │ │ + if (obj.layers) { │ │ │ │ + var tileMatrixSet = { │ │ │ │ + matrixIds: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, tileMatrixSet); │ │ │ │ + obj.tileMatrixSets[tileMatrixSet.identifier] = tileMatrixSet │ │ │ │ + } else { │ │ │ │ + obj.tileMatrixSet = this.getChildValue(node) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + TileMatrix: function(node, obj) { │ │ │ │ + var tileMatrix = { │ │ │ │ + supportedCRS: obj.supportedCRS │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, tileMatrix); │ │ │ │ + obj.matrixIds.push(tileMatrix) │ │ │ │ + }, │ │ │ │ + ScaleDenominator: function(node, obj) { │ │ │ │ + obj.scaleDenominator = parseFloat(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + TopLeftCorner: function(node, obj) { │ │ │ │ + var topLeftCorner = this.getChildValue(node); │ │ │ │ + var coords = topLeftCorner.split(" "); │ │ │ │ + var yx; │ │ │ │ + if (obj.supportedCRS) { │ │ │ │ + var crs = obj.supportedCRS.replace(/urn:ogc:def:crs:(\w+):.+:(\w+)$/, "urn:ogc:def:crs:$1::$2"); │ │ │ │ + yx = !!this.yx[crs] │ │ │ │ + } │ │ │ │ + if (yx) { │ │ │ │ + obj.topLeftCorner = new OpenLayers.LonLat(coords[1], coords[0]) │ │ │ │ + } else { │ │ │ │ + obj.topLeftCorner = new OpenLayers.LonLat(coords[0], coords[1]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + TileWidth: function(node, obj) { │ │ │ │ + obj.tileWidth = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + TileHeight: function(node, obj) { │ │ │ │ + obj.tileHeight = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + MatrixWidth: function(node, obj) { │ │ │ │ + obj.matrixWidth = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + MatrixHeight: function(node, obj) { │ │ │ │ + obj.matrixHeight = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + ResourceURL: function(node, obj) { │ │ │ │ + obj.resourceUrl = obj.resourceUrl || {}; │ │ │ │ + var resourceType = node.getAttribute("resourceType"); │ │ │ │ + if (!obj.resourceUrls) { │ │ │ │ + obj.resourceUrls = [] │ │ │ │ + } │ │ │ │ + var resourceUrl = obj.resourceUrl[resourceType] = { │ │ │ │ + format: node.getAttribute("format"), │ │ │ │ + template: node.getAttribute("template"), │ │ │ │ + resourceType: resourceType │ │ │ │ + }; │ │ │ │ + obj.resourceUrls.push(resourceUrl) │ │ │ │ + }, │ │ │ │ + WSDL: function(node, obj) { │ │ │ │ + obj.wsdl = {}; │ │ │ │ + obj.wsdl.href = node.getAttribute("xlink:href") │ │ │ │ + }, │ │ │ │ + ServiceMetadataURL: function(node, obj) { │ │ │ │ + obj.serviceMetadataUrl = {}; │ │ │ │ + obj.serviceMetadataUrl.href = node.getAttribute("xlink:href") │ │ │ │ + }, │ │ │ │ + LegendURL: function(node, obj) { │ │ │ │ + obj.legend = {}; │ │ │ │ + obj.legend.href = node.getAttribute("xlink:href"); │ │ │ │ + obj.legend.format = node.getAttribute("format") │ │ │ │ + }, │ │ │ │ + Dimension: function(node, obj) { │ │ │ │ + var dimension = { │ │ │ │ + values: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, dimension); │ │ │ │ + obj.dimensions.push(dimension) │ │ │ │ + }, │ │ │ │ + Default: function(node, obj) { │ │ │ │ + obj["default"] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + Value: function(node, obj) { │ │ │ │ + obj.values.push(this.getChildValue(node)) │ │ │ │ } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.abort(); │ │ │ │ - delete this.params; │ │ │ │ - delete this.format; │ │ │ │ - OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ + }, │ │ │ │ + ows: OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.Script" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMTSCapabilities.v1_0_0" │ │ │ │ }); │ │ │ │ -(function() { │ │ │ │ - var o = OpenLayers.Protocol.Script; │ │ │ │ - var counter = 0; │ │ │ │ - o.registry = {}; │ │ │ │ - o.register = function(callback) { │ │ │ │ - var id = "c" + ++counter; │ │ │ │ - o.registry[id] = function() { │ │ │ │ - callback.apply(this, arguments) │ │ │ │ - }; │ │ │ │ - return id │ │ │ │ - }; │ │ │ │ - o.unregister = function(id) { │ │ │ │ - delete o.registry[id] │ │ │ │ - } │ │ │ │ -})(); │ │ │ │ -OpenLayers.Protocol.CSW = function(options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, OpenLayers.Protocol.CSW.DEFAULTS); │ │ │ │ - var cls = OpenLayers.Protocol.CSW["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (!cls) { │ │ │ │ - throw "Unsupported CSW version: " + options.version │ │ │ │ - } │ │ │ │ - return new cls(options) │ │ │ │ -}; │ │ │ │ -OpenLayers.Protocol.CSW.DEFAULTS = { │ │ │ │ - version: "2.0.2" │ │ │ │ -}; │ │ │ │ -OpenLayers.Protocol.SOS = function(options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, OpenLayers.Protocol.SOS.DEFAULTS); │ │ │ │ - var cls = OpenLayers.Protocol.SOS["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (!cls) { │ │ │ │ - throw "Unsupported SOS version: " + options.version │ │ │ │ - } │ │ │ │ - return new cls(options) │ │ │ │ -}; │ │ │ │ -OpenLayers.Protocol.SOS.DEFAULTS = { │ │ │ │ - version: "1.0.0" │ │ │ │ -}; │ │ │ │ -OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - url: null, │ │ │ │ - headers: null, │ │ │ │ - params: null, │ │ │ │ - callback: null, │ │ │ │ - scope: null, │ │ │ │ - readWithPOST: false, │ │ │ │ - updateWithPOST: false, │ │ │ │ - deleteWithPOST: false, │ │ │ │ - wildcarded: false, │ │ │ │ - srsInBBOX: false, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.params = null; │ │ │ │ - this.headers = null; │ │ │ │ - OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + namespaces: { │ │ │ │ + wms: "http://www.opengis.net/wms", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ }, │ │ │ │ - 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) │ │ │ │ + defaultPrefix: "wms", │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ } │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ + var raw = data; │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement │ │ │ │ } │ │ │ │ - return resp │ │ │ │ - }, │ │ │ │ - handleRead: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - handleCreate: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - handleUpdate: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ + var capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + if (capabilities.service === undefined) { │ │ │ │ + var parser = new OpenLayers.Format.OGCExceptionReport; │ │ │ │ + capabilities.error = parser.read(raw) │ │ │ │ } │ │ │ │ - resp.priv = OpenLayers.Request[method](requestOptions); │ │ │ │ - return resp │ │ │ │ - }, │ │ │ │ - handleDelete: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options) │ │ │ │ + return capabilities │ │ │ │ }, │ │ │ │ - handleResponse: function(resp, options) { │ │ │ │ - var request = resp.priv; │ │ │ │ - if (options.callback) { │ │ │ │ - if (request.status >= 200 && request.status < 300) { │ │ │ │ - if (resp.requestType != "delete") { │ │ │ │ - resp.features = this.parseFeatures(request) │ │ │ │ + readers: { │ │ │ │ + wms: { │ │ │ │ + Service: function(node, obj) { │ │ │ │ + obj.service = {}; │ │ │ │ + this.readChildNodes(node, obj.service) │ │ │ │ + }, │ │ │ │ + Name: function(node, obj) { │ │ │ │ + obj.name = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + Title: function(node, obj) { │ │ │ │ + obj.title = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + Abstract: function(node, obj) { │ │ │ │ + obj["abstract"] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + BoundingBox: function(node, obj) { │ │ │ │ + var bbox = {}; │ │ │ │ + bbox.bbox = [parseFloat(node.getAttribute("minx")), parseFloat(node.getAttribute("miny")), parseFloat(node.getAttribute("maxx")), parseFloat(node.getAttribute("maxy"))]; │ │ │ │ + var res = { │ │ │ │ + x: parseFloat(node.getAttribute("resx")), │ │ │ │ + y: parseFloat(node.getAttribute("resy")) │ │ │ │ + }; │ │ │ │ + if (!(isNaN(res.x) && isNaN(res.y))) { │ │ │ │ + bbox.res = res │ │ │ │ } │ │ │ │ - resp.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ - } else { │ │ │ │ - resp.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ - } │ │ │ │ - options.callback.call(options.scope, resp) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - commit: function(features, options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ - var resp = [], │ │ │ │ - nResponses = 0; │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var nRequests = (types[OpenLayers.State.INSERT].length > 0 ? 1 : 0) + types[OpenLayers.State.UPDATE].length + types[OpenLayers.State.DELETE].length; │ │ │ │ - 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]) │ │ │ │ + return bbox │ │ │ │ + }, │ │ │ │ + OnlineResource: function(node, obj) { │ │ │ │ + obj.href = this.getAttributeNS(node, this.namespaces.xlink, "href") │ │ │ │ + }, │ │ │ │ + ContactInformation: function(node, obj) { │ │ │ │ + obj.contactInformation = {}; │ │ │ │ + this.readChildNodes(node, obj.contactInformation) │ │ │ │ + }, │ │ │ │ + ContactPersonPrimary: function(node, obj) { │ │ │ │ + obj.personPrimary = {}; │ │ │ │ + this.readChildNodes(node, obj.personPrimary) │ │ │ │ + }, │ │ │ │ + ContactPerson: function(node, obj) { │ │ │ │ + obj.person = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + ContactOrganization: function(node, obj) { │ │ │ │ + obj.organization = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + ContactPosition: function(node, obj) { │ │ │ │ + obj.position = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + ContactAddress: function(node, obj) { │ │ │ │ + obj.contactAddress = {}; │ │ │ │ + this.readChildNodes(node, obj.contactAddress) │ │ │ │ + }, │ │ │ │ + AddressType: function(node, obj) { │ │ │ │ + obj.type = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + Address: function(node, obj) { │ │ │ │ + obj.address = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + City: function(node, obj) { │ │ │ │ + obj.city = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + StateOrProvince: function(node, obj) { │ │ │ │ + obj.stateOrProvince = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + PostCode: function(node, obj) { │ │ │ │ + obj.postcode = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + Country: function(node, obj) { │ │ │ │ + obj.country = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + ContactVoiceTelephone: function(node, obj) { │ │ │ │ + obj.phone = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + ContactFacsimileTelephone: function(node, obj) { │ │ │ │ + obj.fax = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + ContactElectronicMailAddress: function(node, obj) { │ │ │ │ + obj.email = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + Fees: function(node, obj) { │ │ │ │ + var fees = this.getChildValue(node); │ │ │ │ + if (fees && fees.toLowerCase() != "none") { │ │ │ │ + obj.fees = fees │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + AccessConstraints: function(node, obj) { │ │ │ │ + var constraints = this.getChildValue(node); │ │ │ │ + if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ + obj.accessConstraints = constraints │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + Capability: function(node, obj) { │ │ │ │ + obj.capability = { │ │ │ │ + nestedLayers: [], │ │ │ │ + layers: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.capability) │ │ │ │ + }, │ │ │ │ + Request: function(node, obj) { │ │ │ │ + obj.request = {}; │ │ │ │ + this.readChildNodes(node, obj.request) │ │ │ │ + }, │ │ │ │ + GetCapabilities: function(node, obj) { │ │ │ │ + obj.getcapabilities = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getcapabilities) │ │ │ │ + }, │ │ │ │ + Format: function(node, obj) { │ │ │ │ + if (OpenLayers.Util.isArray(obj.formats)) { │ │ │ │ + obj.formats.push(this.getChildValue(node)) │ │ │ │ + } else { │ │ │ │ + obj.format = this.getChildValue(node) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + DCPType: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + HTTP: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + Get: function(node, obj) { │ │ │ │ + obj.get = {}; │ │ │ │ + this.readChildNodes(node, obj.get); │ │ │ │ + if (!obj.href) { │ │ │ │ + obj.href = obj.get.href │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + Post: function(node, obj) { │ │ │ │ + obj.post = {}; │ │ │ │ + this.readChildNodes(node, obj.post); │ │ │ │ + if (!obj.href) { │ │ │ │ + obj.href = obj.get.href │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + GetMap: function(node, obj) { │ │ │ │ + obj.getmap = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getmap) │ │ │ │ + }, │ │ │ │ + GetFeatureInfo: function(node, obj) { │ │ │ │ + obj.getfeatureinfo = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getfeatureinfo) │ │ │ │ + }, │ │ │ │ + Exception: function(node, obj) { │ │ │ │ + obj.exception = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.exception) │ │ │ │ + }, │ │ │ │ + Layer: function(node, obj) { │ │ │ │ + var parentLayer, capability; │ │ │ │ + if (obj.capability) { │ │ │ │ + capability = obj.capability; │ │ │ │ + parentLayer = obj │ │ │ │ + } else { │ │ │ │ + capability = obj │ │ │ │ + } │ │ │ │ + var attrNode = node.getAttributeNode("queryable"); │ │ │ │ + var queryable = attrNode && attrNode.specified ? node.getAttribute("queryable") : null; │ │ │ │ + attrNode = node.getAttributeNode("cascaded"); │ │ │ │ + var cascaded = attrNode && attrNode.specified ? node.getAttribute("cascaded") : null; │ │ │ │ + attrNode = node.getAttributeNode("opaque"); │ │ │ │ + var opaque = attrNode && attrNode.specified ? node.getAttribute("opaque") : null; │ │ │ │ + var noSubsets = node.getAttribute("noSubsets"); │ │ │ │ + var fixedWidth = node.getAttribute("fixedWidth"); │ │ │ │ + var fixedHeight = node.getAttribute("fixedHeight"); │ │ │ │ + var parent = parentLayer || {}, │ │ │ │ + extend = OpenLayers.Util.extend; │ │ │ │ + var layer = { │ │ │ │ + nestedLayers: [], │ │ │ │ + styles: parentLayer ? [].concat(parentLayer.styles) : [], │ │ │ │ + srs: parentLayer ? extend({}, parent.srs) : {}, │ │ │ │ + metadataURLs: [], │ │ │ │ + bbox: parentLayer ? extend({}, parent.bbox) : {}, │ │ │ │ + llbbox: parent.llbbox, │ │ │ │ + dimensions: parentLayer ? extend({}, parent.dimensions) : {}, │ │ │ │ + authorityURLs: parentLayer ? extend({}, parent.authorityURLs) : {}, │ │ │ │ + identifiers: {}, │ │ │ │ + keywords: [], │ │ │ │ + queryable: queryable && queryable !== "" ? queryable === "1" || queryable === "true" : parent.queryable || false, │ │ │ │ + cascaded: cascaded !== null ? parseInt(cascaded) : parent.cascaded || 0, │ │ │ │ + opaque: opaque ? opaque === "1" || opaque === "true" : parent.opaque || false, │ │ │ │ + noSubsets: noSubsets !== null ? noSubsets === "1" || noSubsets === "true" : parent.noSubsets || false, │ │ │ │ + fixedWidth: fixedWidth != null ? parseInt(fixedWidth) : parent.fixedWidth || 0, │ │ │ │ + fixedHeight: fixedHeight != null ? parseInt(fixedHeight) : parent.fixedHeight || 0, │ │ │ │ + minScale: parent.minScale, │ │ │ │ + maxScale: parent.maxScale, │ │ │ │ + attribution: parent.attribution │ │ │ │ + }; │ │ │ │ + obj.nestedLayers.push(layer); │ │ │ │ + layer.capability = capability; │ │ │ │ + this.readChildNodes(node, layer); │ │ │ │ + delete layer.capability; │ │ │ │ + if (layer.name) { │ │ │ │ + var parts = layer.name.split(":"), │ │ │ │ + request = capability.request, │ │ │ │ + gfi = request.getfeatureinfo; │ │ │ │ + if (parts.length > 0) { │ │ │ │ + layer.prefix = parts[0] │ │ │ │ + } │ │ │ │ + capability.layers.push(layer); │ │ │ │ + if (layer.formats === undefined) { │ │ │ │ + layer.formats = request.getmap.formats │ │ │ │ + } │ │ │ │ + if (layer.infoFormats === undefined && gfi) { │ │ │ │ + layer.infoFormats = gfi.formats │ │ │ │ + } │ │ │ │ } │ │ │ │ + }, │ │ │ │ + Attribution: function(node, obj) { │ │ │ │ + obj.attribution = {}; │ │ │ │ + this.readChildNodes(node, obj.attribution) │ │ │ │ + }, │ │ │ │ + LogoURL: function(node, obj) { │ │ │ │ + obj.logo = { │ │ │ │ + width: node.getAttribute("width"), │ │ │ │ + height: node.getAttribute("height") │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.logo) │ │ │ │ + }, │ │ │ │ + Style: function(node, obj) { │ │ │ │ + var style = {}; │ │ │ │ + obj.styles.push(style); │ │ │ │ + this.readChildNodes(node, style) │ │ │ │ + }, │ │ │ │ + LegendURL: function(node, obj) { │ │ │ │ + var legend = { │ │ │ │ + width: node.getAttribute("width"), │ │ │ │ + height: node.getAttribute("height") │ │ │ │ + }; │ │ │ │ + obj.legend = legend; │ │ │ │ + this.readChildNodes(node, legend) │ │ │ │ + }, │ │ │ │ + MetadataURL: function(node, obj) { │ │ │ │ + var metadataURL = { │ │ │ │ + type: node.getAttribute("type") │ │ │ │ + }; │ │ │ │ + obj.metadataURLs.push(metadataURL); │ │ │ │ + this.readChildNodes(node, metadataURL) │ │ │ │ + }, │ │ │ │ + DataURL: function(node, obj) { │ │ │ │ + obj.dataURL = {}; │ │ │ │ + this.readChildNodes(node, obj.dataURL) │ │ │ │ + }, │ │ │ │ + FeatureListURL: function(node, obj) { │ │ │ │ + obj.featureListURL = {}; │ │ │ │ + this.readChildNodes(node, obj.featureListURL) │ │ │ │ + }, │ │ │ │ + AuthorityURL: function(node, obj) { │ │ │ │ + var name = node.getAttribute("name"); │ │ │ │ + var authority = {}; │ │ │ │ + this.readChildNodes(node, authority); │ │ │ │ + obj.authorityURLs[name] = authority.href │ │ │ │ + }, │ │ │ │ + Identifier: function(node, obj) { │ │ │ │ + var authority = node.getAttribute("authority"); │ │ │ │ + obj.identifiers[authority] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + KeywordList: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + SRS: function(node, obj) { │ │ │ │ + obj.srs[this.getChildValue(node)] = true │ │ │ │ } │ │ │ │ } │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - abort: function(response) { │ │ │ │ - if (response) { │ │ │ │ - response.priv.abort() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - callUserCallback: function(resp, options) { │ │ │ │ - var opt = options[resp.requestType]; │ │ │ │ - if (opt && opt.callback) { │ │ │ │ - opt.callback.call(opt.scope, resp) │ │ │ │ - } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.HTTP" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1" │ │ │ │ }); │ │ │ │ -OpenLayers.Protocol.CSW.v2_0_2 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - formatOptions: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ - if (!options.format) { │ │ │ │ - this.format = new OpenLayers.Format.CSWGetRecords.v2_0_2(OpenLayers.Util.extend({}, this.formatOptions)) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.options && !this.options.format) { │ │ │ │ - this.format.destroy() │ │ │ │ - } │ │ │ │ - this.format = null; │ │ │ │ - OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ - }, │ │ │ │ - read: function(options) { │ │ │ │ - options = OpenLayers.Util.extend({}, options); │ │ │ │ - OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ - var response = new OpenLayers.Protocol.Response({ │ │ │ │ - requestType: "read" │ │ │ │ - }); │ │ │ │ - var data = this.format.write(options.params || 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 │ │ │ │ - }, │ │ │ │ - handleRead: function(response, options) { │ │ │ │ - if (options.callback) { │ │ │ │ - var request = response.priv; │ │ │ │ - if (request.status >= 200 && request.status < 300) { │ │ │ │ - response.data = this.parseData(request); │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ - } else { │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ + readers: { │ │ │ │ + wms: OpenLayers.Util.applyDefaults({ │ │ │ │ + WMT_MS_Capabilities: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + Keyword: function(node, obj) { │ │ │ │ + if (obj.keywords) { │ │ │ │ + obj.keywords.push(this.getChildValue(node)) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + DescribeLayer: function(node, obj) { │ │ │ │ + obj.describelayer = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.describelayer) │ │ │ │ + }, │ │ │ │ + GetLegendGraphic: function(node, obj) { │ │ │ │ + obj.getlegendgraphic = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getlegendgraphic) │ │ │ │ + }, │ │ │ │ + GetStyles: function(node, obj) { │ │ │ │ + obj.getstyles = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getstyles) │ │ │ │ + }, │ │ │ │ + PutStyles: function(node, obj) { │ │ │ │ + obj.putstyles = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.putstyles) │ │ │ │ + }, │ │ │ │ + UserDefinedSymbolization: function(node, obj) { │ │ │ │ + var userSymbols = { │ │ │ │ + supportSLD: parseInt(node.getAttribute("SupportSLD")) == 1, │ │ │ │ + userLayer: parseInt(node.getAttribute("UserLayer")) == 1, │ │ │ │ + userStyle: parseInt(node.getAttribute("UserStyle")) == 1, │ │ │ │ + remoteWFS: parseInt(node.getAttribute("RemoteWFS")) == 1 │ │ │ │ + }; │ │ │ │ + obj.userSymbols = userSymbols │ │ │ │ + }, │ │ │ │ + LatLonBoundingBox: function(node, obj) { │ │ │ │ + obj.llbbox = [parseFloat(node.getAttribute("minx")), parseFloat(node.getAttribute("miny")), parseFloat(node.getAttribute("maxx")), parseFloat(node.getAttribute("maxy"))] │ │ │ │ + }, │ │ │ │ + BoundingBox: function(node, obj) { │ │ │ │ + var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ + bbox.srs = node.getAttribute("SRS"); │ │ │ │ + obj.bbox[bbox.srs] = bbox │ │ │ │ + }, │ │ │ │ + ScaleHint: function(node, obj) { │ │ │ │ + var min = node.getAttribute("min"); │ │ │ │ + var max = node.getAttribute("max"); │ │ │ │ + var rad2 = Math.pow(2, .5); │ │ │ │ + var ipm = OpenLayers.INCHES_PER_UNIT["m"]; │ │ │ │ + if (min != 0) { │ │ │ │ + obj.maxScale = parseFloat((min / rad2 * ipm * OpenLayers.DOTS_PER_INCH).toPrecision(13)) │ │ │ │ + } │ │ │ │ + if (max != Number.POSITIVE_INFINITY) { │ │ │ │ + obj.minScale = parseFloat((max / rad2 * ipm * OpenLayers.DOTS_PER_INCH).toPrecision(13)) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + Dimension: function(node, obj) { │ │ │ │ + var name = node.getAttribute("name").toLowerCase(); │ │ │ │ + var dim = { │ │ │ │ + name: name, │ │ │ │ + units: node.getAttribute("units"), │ │ │ │ + unitsymbol: node.getAttribute("unitSymbol") │ │ │ │ + }; │ │ │ │ + obj.dimensions[dim.name] = dim │ │ │ │ + }, │ │ │ │ + Extent: function(node, obj) { │ │ │ │ + var name = node.getAttribute("name").toLowerCase(); │ │ │ │ + if (name in obj["dimensions"]) { │ │ │ │ + var extent = obj.dimensions[name]; │ │ │ │ + extent.nearestVal = node.getAttribute("nearestValue") === "1"; │ │ │ │ + extent.multipleVal = node.getAttribute("multipleValues") === "1"; │ │ │ │ + extent.current = node.getAttribute("current") === "1"; │ │ │ │ + extent["default"] = node.getAttribute("default") || ""; │ │ │ │ + var values = this.getChildValue(node); │ │ │ │ + extent.values = values.split(",") │ │ │ │ + } │ │ │ │ } │ │ │ │ - options.callback.call(options.scope, response) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - parseData: 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) │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.CSW.v2_0_2" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1" │ │ │ │ }); │ │ │ │ -OpenLayers.Protocol.SOS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - fois: null, │ │ │ │ - formatOptions: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ - if (!options.format) { │ │ │ │ - this.format = new OpenLayers.Format.SOSGetFeatureOfInterest(this.formatOptions) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.options && !this.options.format) { │ │ │ │ - this.format.destroy() │ │ │ │ - } │ │ │ │ - this.format = null; │ │ │ │ - OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ - }, │ │ │ │ - read: function(options) { │ │ │ │ - options = OpenLayers.Util.extend({}, options); │ │ │ │ - OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ - var response = new OpenLayers.Protocol.Response({ │ │ │ │ - requestType: "read" │ │ │ │ - }); │ │ │ │ - var format = this.format; │ │ │ │ - var data = OpenLayers.Format.XML.prototype.write.apply(format, [format.writeNode("sos:GetFeatureOfInterest", { │ │ │ │ - fois: this.fois │ │ │ │ - })]); │ │ │ │ - response.priv = OpenLayers.Request.POST({ │ │ │ │ - url: options.url, │ │ │ │ - callback: this.createCallback(this.handleRead, response, options), │ │ │ │ - data: data │ │ │ │ - }); │ │ │ │ - return response │ │ │ │ - }, │ │ │ │ - handleRead: function(response, options) { │ │ │ │ - if (options.callback) { │ │ │ │ - var request = response.priv; │ │ │ │ - if (request.status >= 200 && request.status < 300) { │ │ │ │ - response.features = this.parseFeatures(request); │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ - } else { │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1_1 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ + version: "1.1.1", │ │ │ │ + readers: { │ │ │ │ + wms: OpenLayers.Util.applyDefaults({ │ │ │ │ + SRS: function(node, obj) { │ │ │ │ + obj.srs[this.getChildValue(node)] = true │ │ │ │ } │ │ │ │ - options.callback.call(options.scope, response) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.SOS.v1_0_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1" │ │ │ │ }); │ │ │ │ -OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - version: null, │ │ │ │ - srsName: "EPSG:4326", │ │ │ │ - featureType: null, │ │ │ │ - featureNS: null, │ │ │ │ - geometryName: "the_geom", │ │ │ │ - schema: null, │ │ │ │ - featurePrefix: "feature", │ │ │ │ - formatOptions: null, │ │ │ │ - readFormat: null, │ │ │ │ - readOptions: null, │ │ │ │ - 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) { │ │ │ │ - this.setGeometryName(null) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.options && !this.options.format) { │ │ │ │ - this.format.destroy() │ │ │ │ - } │ │ │ │ - this.format = null; │ │ │ │ - OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - setFeatureType: function(featureType) { │ │ │ │ - this.featureType = featureType; │ │ │ │ - this.format.featureType = featureType │ │ │ │ - }, │ │ │ │ - setGeometryName: function(geometryName) { │ │ │ │ - this.geometryName = geometryName; │ │ │ │ - this.format.geometryName = geometryName │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - 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 │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1_1, { │ │ │ │ + version: "1.1.1", │ │ │ │ + profile: "WMSC", │ │ │ │ + readers: { │ │ │ │ + wms: OpenLayers.Util.applyDefaults({ │ │ │ │ + VendorSpecificCapabilities: function(node, obj) { │ │ │ │ + obj.vendorSpecific = { │ │ │ │ + tileSets: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.vendorSpecific) │ │ │ │ + }, │ │ │ │ + TileSet: function(node, vendorSpecific) { │ │ │ │ + var tileset = { │ │ │ │ + srs: {}, │ │ │ │ + bbox: {}, │ │ │ │ + resolutions: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, tileset); │ │ │ │ + vendorSpecific.tileSets.push(tileset) │ │ │ │ + }, │ │ │ │ + Resolutions: function(node, tileset) { │ │ │ │ + var res = this.getChildValue(node).split(" "); │ │ │ │ + for (var i = 0, len = res.length; i < len; i++) { │ │ │ │ + if (res[i] != "") { │ │ │ │ + tileset.resolutions.push(parseFloat(res[i])) │ │ │ │ } │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ - } else { │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ - response.error = result │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ - } │ │ │ │ - options.callback.call(options.scope, response) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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; │ │ │ │ - format.autoConfig = false; │ │ │ │ - if (!this.geometryName) { │ │ │ │ - this.setGeometryName(format.geometryName) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return result │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - handleCommit: function(response, options) { │ │ │ │ - if (options.callback) { │ │ │ │ - var request = response.priv; │ │ │ │ - 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 │ │ │ │ + }, │ │ │ │ + Width: function(node, tileset) { │ │ │ │ + tileset.width = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + Height: function(node, tileset) { │ │ │ │ + tileset.height = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + Layers: function(node, tileset) { │ │ │ │ + tileset.layers = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + Styles: function(node, tileset) { │ │ │ │ + tileset.styles = this.getChildValue(node) │ │ │ │ } │ │ │ │ - options.callback.call(options.scope, response) │ │ │ │ - } │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1_1_1.prototype.readers["wms"]) │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_3 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ + readers: { │ │ │ │ + wms: OpenLayers.Util.applyDefaults({ │ │ │ │ + WMS_Capabilities: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + LayerLimit: function(node, obj) { │ │ │ │ + obj.layerLimit = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + MaxWidth: function(node, obj) { │ │ │ │ + obj.maxWidth = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + MaxHeight: function(node, obj) { │ │ │ │ + obj.maxHeight = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + BoundingBox: function(node, obj) { │ │ │ │ + var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ + bbox.srs = node.getAttribute("CRS"); │ │ │ │ + obj.bbox[bbox.srs] = bbox │ │ │ │ + }, │ │ │ │ + CRS: function(node, obj) { │ │ │ │ + this.readers.wms.SRS.apply(this, [node, obj]) │ │ │ │ + }, │ │ │ │ + EX_GeographicBoundingBox: function(node, obj) { │ │ │ │ + obj.llbbox = []; │ │ │ │ + this.readChildNodes(node, obj.llbbox) │ │ │ │ + }, │ │ │ │ + westBoundLongitude: function(node, obj) { │ │ │ │ + obj[0] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + eastBoundLongitude: function(node, obj) { │ │ │ │ + obj[2] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + southBoundLatitude: function(node, obj) { │ │ │ │ + obj[1] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + northBoundLatitude: function(node, obj) { │ │ │ │ + obj[3] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + MinScaleDenominator: function(node, obj) { │ │ │ │ + obj.maxScale = parseFloat(this.getChildValue(node)).toPrecision(16) │ │ │ │ + }, │ │ │ │ + MaxScaleDenominator: function(node, obj) { │ │ │ │ + obj.minScale = parseFloat(this.getChildValue(node)).toPrecision(16) │ │ │ │ + }, │ │ │ │ + Dimension: function(node, obj) { │ │ │ │ + var name = node.getAttribute("name").toLowerCase(); │ │ │ │ + var dim = { │ │ │ │ + name: name, │ │ │ │ + units: node.getAttribute("units"), │ │ │ │ + unitsymbol: node.getAttribute("unitSymbol"), │ │ │ │ + nearestVal: node.getAttribute("nearestValue") === "1", │ │ │ │ + multipleVal: node.getAttribute("multipleValues") === "1", │ │ │ │ + default: node.getAttribute("default") || "", │ │ │ │ + current: node.getAttribute("current") === "1", │ │ │ │ + values: this.getChildValue(node).split(",") │ │ │ │ + }; │ │ │ │ + obj.dimensions[dim.name] = dim │ │ │ │ + }, │ │ │ │ + Keyword: function(node, obj) { │ │ │ │ + var keyword = { │ │ │ │ + value: this.getChildValue(node), │ │ │ │ + vocabulary: node.getAttribute("vocabulary") │ │ │ │ + }; │ │ │ │ + if (obj.keywords) { │ │ │ │ + obj.keywords.push(keyword) │ │ │ │ + } │ │ │ │ } │ │ │ │ - }); │ │ │ │ - var deleteNode = this.format.createElementNSPlus("wfs:Delete", { │ │ │ │ - attributes: { │ │ │ │ - typeName: (options.featureNS ? this.featurePrefix + ":" : "") + options.featureType │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]), │ │ │ │ + sld: { │ │ │ │ + UserDefinedSymbolization: function(node, obj) { │ │ │ │ + this.readers.wms.UserDefinedSymbolization.apply(this, [node, obj]); │ │ │ │ + obj.userSymbols.inlineFeature = parseInt(node.getAttribute("InlineFeature")) == 1; │ │ │ │ + obj.userSymbols.remoteWCS = parseInt(node.getAttribute("RemoteWCS")) == 1 │ │ │ │ + }, │ │ │ │ + DescribeLayer: function(node, obj) { │ │ │ │ + this.readers.wms.DescribeLayer.apply(this, [node, obj]) │ │ │ │ + }, │ │ │ │ + GetLegendGraphic: function(node, obj) { │ │ │ │ + this.readers.wms.GetLegendGraphic.apply(this, [node, obj]) │ │ │ │ } │ │ │ │ - }); │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - abort: function(response) { │ │ │ │ - if (response) { │ │ │ │ - response.priv.abort() │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.WFS.v1" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3" │ │ │ │ }); │ │ │ │ -OpenLayers.Protocol.WFS.v1_1_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_3_0 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_3, { │ │ │ │ + version: "1.3.0", │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1_0 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ version: "1.1.0", │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Protocol.WFS.v1.prototype.initialize.apply(this, arguments); │ │ │ │ - if (this.outputFormat && !this.readFormat) { │ │ │ │ - if (this.outputFormat.toLowerCase() == "gml2") { │ │ │ │ - this.readFormat = new OpenLayers.Format.GML.v2({ │ │ │ │ - featureType: this.featureType, │ │ │ │ - featureNS: this.featureNS, │ │ │ │ - geometryName: this.geometryName │ │ │ │ - }) │ │ │ │ - } else if (this.outputFormat.toLowerCase() == "json") { │ │ │ │ - this.readFormat = new OpenLayers.Format.GeoJSON │ │ │ │ + readers: { │ │ │ │ + wms: OpenLayers.Util.applyDefaults({ │ │ │ │ + SRS: function(node, obj) { │ │ │ │ + var srs = this.getChildValue(node); │ │ │ │ + var values = srs.split(/ +/); │ │ │ │ + for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ + obj.srs[values[i]] = true │ │ │ │ + } │ │ │ │ } │ │ │ │ - } │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.WFS.v1_1_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_0" │ │ │ │ }); │ │ │ │ -OpenLayers.Protocol.WFS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ - version: "1.0.0", │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.WFS.v1_0_0" │ │ │ │ +OpenLayers.Format.ArcXML.Features = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + read: function(data) { │ │ │ │ + var axl = new OpenLayers.Format.ArcXML; │ │ │ │ + var parsed = axl.read(data); │ │ │ │ + return parsed.features.feature │ │ │ │ + } │ │ │ │ }); │ │ │ │ OpenLayers.Events.featureclick = OpenLayers.Class({ │ │ │ │ cache: null, │ │ │ │ map: null, │ │ │ │ provides: ["featureclick", "nofeatureclick", "featureover", "featureout"], │ │ │ │ initialize: function(target) { │ │ │ │ this.target = target; │ │ │ │ @@ -38142,8 +37684,466 @@ │ │ │ │ maxSize: new OpenLayers.Size(1200, 660), │ │ │ │ initialize: function(id, lonlat, contentSize, contentHTML, anchor, closeBox, closeBoxCallback) { │ │ │ │ this.imageSrc = OpenLayers.Util.getImageLocation("cloud-popup-relative.png"); │ │ │ │ OpenLayers.Popup.Framed.prototype.initialize.apply(this, arguments); │ │ │ │ this.contentDiv.className = this.contentDisplayClass │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Popup.FramedCloud" │ │ │ │ -}); │ │ │ │ +}); │ │ │ │ +OpenLayers.Console.warn("OpenLayers.Rico is deprecated"); │ │ │ │ +OpenLayers.Rico = OpenLayers.Rico || {}; │ │ │ │ +OpenLayers.Rico.Color = OpenLayers.Class({ │ │ │ │ + initialize: function(red, green, blue) { │ │ │ │ + this.rgb = { │ │ │ │ + r: red, │ │ │ │ + g: green, │ │ │ │ + b: blue │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setRed: function(r) { │ │ │ │ + this.rgb.r = r │ │ │ │ + }, │ │ │ │ + setGreen: function(g) { │ │ │ │ + this.rgb.g = g │ │ │ │ + }, │ │ │ │ + setBlue: function(b) { │ │ │ │ + this.rgb.b = b │ │ │ │ + }, │ │ │ │ + setHue: function(h) { │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ + hsb.h = h; │ │ │ │ + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b) │ │ │ │ + }, │ │ │ │ + setSaturation: function(s) { │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ + hsb.s = s; │ │ │ │ + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b) │ │ │ │ + }, │ │ │ │ + setBrightness: function(b) { │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ + hsb.b = b; │ │ │ │ + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b) │ │ │ │ + }, │ │ │ │ + darken: function(percent) { │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent, 0)) │ │ │ │ + }, │ │ │ │ + brighten: function(percent) { │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent, 1)) │ │ │ │ + }, │ │ │ │ + blend: function(other) { │ │ │ │ + this.rgb.r = Math.floor((this.rgb.r + other.rgb.r) / 2); │ │ │ │ + this.rgb.g = Math.floor((this.rgb.g + other.rgb.g) / 2); │ │ │ │ + this.rgb.b = Math.floor((this.rgb.b + other.rgb.b) / 2) │ │ │ │ + }, │ │ │ │ + isBright: function() { │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ + return this.asHSB().b > .5 │ │ │ │ + }, │ │ │ │ + isDark: function() { │ │ │ │ + return !this.isBright() │ │ │ │ + }, │ │ │ │ + asRGB: function() { │ │ │ │ + return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")" │ │ │ │ + }, │ │ │ │ + asHex: function() { │ │ │ │ + return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart() │ │ │ │ + }, │ │ │ │ + asHSB: function() { │ │ │ │ + return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b) │ │ │ │ + }, │ │ │ │ + toString: function() { │ │ │ │ + return this.asHex() │ │ │ │ + } │ │ │ │ +}); │ │ │ │ +OpenLayers.Rico.Color.createFromHex = function(hexCode) { │ │ │ │ + if (hexCode.length == 4) { │ │ │ │ + var shortHexCode = hexCode; │ │ │ │ + var hexCode = "#"; │ │ │ │ + for (var i = 1; i < 4; i++) { │ │ │ │ + hexCode += shortHexCode.charAt(i) + shortHexCode.charAt(i) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (hexCode.indexOf("#") == 0) { │ │ │ │ + hexCode = hexCode.substring(1) │ │ │ │ + } │ │ │ │ + var red = hexCode.substring(0, 2); │ │ │ │ + var green = hexCode.substring(2, 4); │ │ │ │ + var blue = hexCode.substring(4, 6); │ │ │ │ + return new OpenLayers.Rico.Color(parseInt(red, 16), parseInt(green, 16), parseInt(blue, 16)) │ │ │ │ +}; │ │ │ │ +OpenLayers.Rico.Color.createColorFromBackground = function(elem) { │ │ │ │ + var actualColor = OpenLayers.Element.getStyle(OpenLayers.Util.getElement(elem), "backgroundColor"); │ │ │ │ + if (actualColor == "transparent" && elem.parentNode) { │ │ │ │ + return OpenLayers.Rico.Color.createColorFromBackground(elem.parentNode) │ │ │ │ + } │ │ │ │ + if (actualColor == null) { │ │ │ │ + return new OpenLayers.Rico.Color(255, 255, 255) │ │ │ │ + } │ │ │ │ + if (actualColor.indexOf("rgb(") == 0) { │ │ │ │ + var colors = actualColor.substring(4, actualColor.length - 1); │ │ │ │ + var colorArray = colors.split(","); │ │ │ │ + return new OpenLayers.Rico.Color(parseInt(colorArray[0]), parseInt(colorArray[1]), parseInt(colorArray[2])) │ │ │ │ + } else if (actualColor.indexOf("#") == 0) { │ │ │ │ + return OpenLayers.Rico.Color.createFromHex(actualColor) │ │ │ │ + } else { │ │ │ │ + return new OpenLayers.Rico.Color(255, 255, 255) │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.Rico.Color.HSBtoRGB = function(hue, saturation, brightness) { │ │ │ │ + var red = 0; │ │ │ │ + var green = 0; │ │ │ │ + var blue = 0; │ │ │ │ + if (saturation == 0) { │ │ │ │ + red = parseInt(brightness * 255 + .5); │ │ │ │ + green = red; │ │ │ │ + blue = red │ │ │ │ + } else { │ │ │ │ + var h = (hue - Math.floor(hue)) * 6; │ │ │ │ + var f = h - Math.floor(h); │ │ │ │ + var p = brightness * (1 - saturation); │ │ │ │ + var q = brightness * (1 - saturation * f); │ │ │ │ + var t = brightness * (1 - saturation * (1 - f)); │ │ │ │ + switch (parseInt(h)) { │ │ │ │ + case 0: │ │ │ │ + red = brightness * 255 + .5; │ │ │ │ + green = t * 255 + .5; │ │ │ │ + blue = p * 255 + .5; │ │ │ │ + break; │ │ │ │ + case 1: │ │ │ │ + red = q * 255 + .5; │ │ │ │ + green = brightness * 255 + .5; │ │ │ │ + blue = p * 255 + .5; │ │ │ │ + break; │ │ │ │ + case 2: │ │ │ │ + red = p * 255 + .5; │ │ │ │ + green = brightness * 255 + .5; │ │ │ │ + blue = t * 255 + .5; │ │ │ │ + break; │ │ │ │ + case 3: │ │ │ │ + red = p * 255 + .5; │ │ │ │ + green = q * 255 + .5; │ │ │ │ + blue = brightness * 255 + .5; │ │ │ │ + break; │ │ │ │ + case 4: │ │ │ │ + red = t * 255 + .5; │ │ │ │ + green = p * 255 + .5; │ │ │ │ + blue = brightness * 255 + .5; │ │ │ │ + break; │ │ │ │ + case 5: │ │ │ │ + red = brightness * 255 + .5; │ │ │ │ + green = p * 255 + .5; │ │ │ │ + blue = q * 255 + .5; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return { │ │ │ │ + r: parseInt(red), │ │ │ │ + g: parseInt(green), │ │ │ │ + b: parseInt(blue) │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.Rico.Color.RGBtoHSB = function(r, g, b) { │ │ │ │ + var hue; │ │ │ │ + var saturation; │ │ │ │ + var brightness; │ │ │ │ + var cmax = r > g ? r : g; │ │ │ │ + if (b > cmax) { │ │ │ │ + cmax = b │ │ │ │ + } │ │ │ │ + var cmin = r < g ? r : g; │ │ │ │ + if (b < cmin) { │ │ │ │ + cmin = b │ │ │ │ + } │ │ │ │ + brightness = cmax / 255; │ │ │ │ + if (cmax != 0) { │ │ │ │ + saturation = (cmax - cmin) / cmax │ │ │ │ + } else { │ │ │ │ + saturation = 0 │ │ │ │ + } │ │ │ │ + if (saturation == 0) { │ │ │ │ + hue = 0 │ │ │ │ + } else { │ │ │ │ + var redc = (cmax - r) / (cmax - cmin); │ │ │ │ + var greenc = (cmax - g) / (cmax - cmin); │ │ │ │ + var bluec = (cmax - b) / (cmax - cmin); │ │ │ │ + if (r == cmax) { │ │ │ │ + hue = bluec - greenc │ │ │ │ + } else if (g == cmax) { │ │ │ │ + hue = 2 + redc - bluec │ │ │ │ + } else { │ │ │ │ + hue = 4 + greenc - redc │ │ │ │ + } │ │ │ │ + hue = hue / 6; │ │ │ │ + if (hue < 0) { │ │ │ │ + hue = hue + 1 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return { │ │ │ │ + h: hue, │ │ │ │ + s: saturation, │ │ │ │ + b: brightness │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.Console.warn("OpenLayers.Rico is deprecated"); │ │ │ │ +OpenLayers.Rico = OpenLayers.Rico || {}; │ │ │ │ +OpenLayers.Rico.Corner = { │ │ │ │ + round: function(e, options) { │ │ │ │ + e = OpenLayers.Util.getElement(e); │ │ │ │ + this._setOptions(options); │ │ │ │ + var color = this.options.color; │ │ │ │ + if (this.options.color == "fromElement") { │ │ │ │ + color = this._background(e) │ │ │ │ + } │ │ │ │ + var bgColor = this.options.bgColor; │ │ │ │ + if (this.options.bgColor == "fromParent") { │ │ │ │ + bgColor = this._background(e.offsetParent) │ │ │ │ + } │ │ │ │ + this._roundCornersImpl(e, color, bgColor) │ │ │ │ + }, │ │ │ │ + changeColor: function(theDiv, newColor) { │ │ │ │ + theDiv.style.backgroundColor = newColor; │ │ │ │ + var spanElements = theDiv.parentNode.getElementsByTagName("span"); │ │ │ │ + for (var currIdx = 0; currIdx < spanElements.length; currIdx++) { │ │ │ │ + spanElements[currIdx].style.backgroundColor = newColor │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + changeOpacity: function(theDiv, newOpacity) { │ │ │ │ + var mozillaOpacity = newOpacity; │ │ │ │ + var ieOpacity = "alpha(opacity=" + newOpacity * 100 + ")"; │ │ │ │ + theDiv.style.opacity = mozillaOpacity; │ │ │ │ + theDiv.style.filter = ieOpacity; │ │ │ │ + var spanElements = theDiv.parentNode.getElementsByTagName("span"); │ │ │ │ + for (var currIdx = 0; currIdx < spanElements.length; currIdx++) { │ │ │ │ + spanElements[currIdx].style.opacity = mozillaOpacity; │ │ │ │ + spanElements[currIdx].style.filter = ieOpacity │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + reRound: function(theDiv, options) { │ │ │ │ + var topRico = theDiv.parentNode.childNodes[0]; │ │ │ │ + var bottomRico = theDiv.parentNode.childNodes[2]; │ │ │ │ + theDiv.parentNode.removeChild(topRico); │ │ │ │ + theDiv.parentNode.removeChild(bottomRico); │ │ │ │ + this.round(theDiv.parentNode, options) │ │ │ │ + }, │ │ │ │ + _roundCornersImpl: function(e, color, bgColor) { │ │ │ │ + if (this.options.border) { │ │ │ │ + this._renderBorder(e, bgColor) │ │ │ │ + } │ │ │ │ + if (this._isTopRounded()) { │ │ │ │ + this._roundTopCorners(e, color, bgColor) │ │ │ │ + } │ │ │ │ + if (this._isBottomRounded()) { │ │ │ │ + this._roundBottomCorners(e, color, bgColor) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + _renderBorder: function(el, bgColor) { │ │ │ │ + var borderValue = "1px solid " + this._borderColor(bgColor); │ │ │ │ + var borderL = "border-left: " + borderValue; │ │ │ │ + var borderR = "border-right: " + borderValue; │ │ │ │ + var style = "style='" + borderL + ";" + borderR + "'"; │ │ │ │ + el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>" │ │ │ │ + }, │ │ │ │ + _roundTopCorners: function(el, color, bgColor) { │ │ │ │ + var corner = this._createCorner(bgColor); │ │ │ │ + for (var i = 0; i < this.options.numSlices; i++) { │ │ │ │ + corner.appendChild(this._createCornerSlice(color, bgColor, i, "top")) │ │ │ │ + } │ │ │ │ + el.style.paddingTop = 0; │ │ │ │ + el.insertBefore(corner, el.firstChild) │ │ │ │ + }, │ │ │ │ + _roundBottomCorners: function(el, color, bgColor) { │ │ │ │ + var corner = this._createCorner(bgColor); │ │ │ │ + for (var i = this.options.numSlices - 1; i >= 0; i--) { │ │ │ │ + corner.appendChild(this._createCornerSlice(color, bgColor, i, "bottom")) │ │ │ │ + } │ │ │ │ + el.style.paddingBottom = 0; │ │ │ │ + el.appendChild(corner) │ │ │ │ + }, │ │ │ │ + _createCorner: function(bgColor) { │ │ │ │ + var corner = document.createElement("div"); │ │ │ │ + corner.style.backgroundColor = this._isTransparent() ? "transparent" : bgColor; │ │ │ │ + return corner │ │ │ │ + }, │ │ │ │ + _createCornerSlice: function(color, bgColor, n, position) { │ │ │ │ + var slice = document.createElement("span"); │ │ │ │ + var inStyle = slice.style; │ │ │ │ + inStyle.backgroundColor = color; │ │ │ │ + inStyle.display = "block"; │ │ │ │ + inStyle.height = "1px"; │ │ │ │ + inStyle.overflow = "hidden"; │ │ │ │ + inStyle.fontSize = "1px"; │ │ │ │ + var borderColor = this._borderColor(color, bgColor); │ │ │ │ + if (this.options.border && n == 0) { │ │ │ │ + inStyle.borderTopStyle = "solid"; │ │ │ │ + inStyle.borderTopWidth = "1px"; │ │ │ │ + inStyle.borderLeftWidth = "0px"; │ │ │ │ + inStyle.borderRightWidth = "0px"; │ │ │ │ + inStyle.borderBottomWidth = "0px"; │ │ │ │ + inStyle.height = "0px"; │ │ │ │ + inStyle.borderColor = borderColor │ │ │ │ + } else if (borderColor) { │ │ │ │ + inStyle.borderColor = borderColor; │ │ │ │ + inStyle.borderStyle = "solid"; │ │ │ │ + inStyle.borderWidth = "0px 1px" │ │ │ │ + } │ │ │ │ + if (!this.options.compact && n == this.options.numSlices - 1) { │ │ │ │ + inStyle.height = "2px" │ │ │ │ + } │ │ │ │ + this._setMargin(slice, n, position); │ │ │ │ + this._setBorder(slice, n, position); │ │ │ │ + return slice │ │ │ │ + }, │ │ │ │ + _setOptions: function(options) { │ │ │ │ + this.options = { │ │ │ │ + corners: "all", │ │ │ │ + color: "fromElement", │ │ │ │ + bgColor: "fromParent", │ │ │ │ + blend: true, │ │ │ │ + border: false, │ │ │ │ + compact: false │ │ │ │ + }; │ │ │ │ + OpenLayers.Util.extend(this.options, options || {}); │ │ │ │ + this.options.numSlices = this.options.compact ? 2 : 4; │ │ │ │ + if (this._isTransparent()) { │ │ │ │ + this.options.blend = false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + _whichSideTop: function() { │ │ │ │ + if (this._hasString(this.options.corners, "all", "top")) { │ │ │ │ + return "" │ │ │ │ + } │ │ │ │ + if (this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0) { │ │ │ │ + return "" │ │ │ │ + } │ │ │ │ + if (this.options.corners.indexOf("tl") >= 0) { │ │ │ │ + return "left" │ │ │ │ + } else if (this.options.corners.indexOf("tr") >= 0) { │ │ │ │ + return "right" │ │ │ │ + } │ │ │ │ + return "" │ │ │ │ + }, │ │ │ │ + _whichSideBottom: function() { │ │ │ │ + if (this._hasString(this.options.corners, "all", "bottom")) { │ │ │ │ + return "" │ │ │ │ + } │ │ │ │ + if (this.options.corners.indexOf("bl") >= 0 && this.options.corners.indexOf("br") >= 0) { │ │ │ │ + return "" │ │ │ │ + } │ │ │ │ + if (this.options.corners.indexOf("bl") >= 0) { │ │ │ │ + return "left" │ │ │ │ + } else if (this.options.corners.indexOf("br") >= 0) { │ │ │ │ + return "right" │ │ │ │ + } │ │ │ │ + return "" │ │ │ │ + }, │ │ │ │ + _borderColor: function(color, bgColor) { │ │ │ │ + if (color == "transparent") { │ │ │ │ + return bgColor │ │ │ │ + } else if (this.options.border) { │ │ │ │ + return this.options.border │ │ │ │ + } else if (this.options.blend) { │ │ │ │ + return this._blend(bgColor, color) │ │ │ │ + } else { │ │ │ │ + return "" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + _setMargin: function(el, n, corners) { │ │ │ │ + var marginSize = this._marginSize(n); │ │ │ │ + var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); │ │ │ │ + if (whichSide == "left") { │ │ │ │ + el.style.marginLeft = marginSize + "px"; │ │ │ │ + el.style.marginRight = "0px" │ │ │ │ + } else if (whichSide == "right") { │ │ │ │ + el.style.marginRight = marginSize + "px"; │ │ │ │ + el.style.marginLeft = "0px" │ │ │ │ + } else { │ │ │ │ + el.style.marginLeft = marginSize + "px"; │ │ │ │ + el.style.marginRight = marginSize + "px" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + _setBorder: function(el, n, corners) { │ │ │ │ + var borderSize = this._borderSize(n); │ │ │ │ + var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); │ │ │ │ + if (whichSide == "left") { │ │ │ │ + el.style.borderLeftWidth = borderSize + "px"; │ │ │ │ + el.style.borderRightWidth = "0px" │ │ │ │ + } else if (whichSide == "right") { │ │ │ │ + el.style.borderRightWidth = borderSize + "px"; │ │ │ │ + el.style.borderLeftWidth = "0px" │ │ │ │ + } else { │ │ │ │ + el.style.borderLeftWidth = borderSize + "px"; │ │ │ │ + el.style.borderRightWidth = borderSize + "px" │ │ │ │ + } │ │ │ │ + if (this.options.border != false) { │ │ │ │ + el.style.borderLeftWidth = borderSize + "px"; │ │ │ │ + el.style.borderRightWidth = borderSize + "px" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + _marginSize: function(n) { │ │ │ │ + if (this._isTransparent()) { │ │ │ │ + return 0 │ │ │ │ + } │ │ │ │ + var marginSizes = [5, 3, 2, 1]; │ │ │ │ + var blendedMarginSizes = [3, 2, 1, 0]; │ │ │ │ + var compactMarginSizes = [2, 1]; │ │ │ │ + var smBlendedMarginSizes = [1, 0]; │ │ │ │ + if (this.options.compact && this.options.blend) { │ │ │ │ + return smBlendedMarginSizes[n] │ │ │ │ + } else if (this.options.compact) { │ │ │ │ + return compactMarginSizes[n] │ │ │ │ + } else if (this.options.blend) { │ │ │ │ + return blendedMarginSizes[n] │ │ │ │ + } else { │ │ │ │ + return marginSizes[n] │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + _borderSize: function(n) { │ │ │ │ + var transparentBorderSizes = [5, 3, 2, 1]; │ │ │ │ + var blendedBorderSizes = [2, 1, 1, 1]; │ │ │ │ + var compactBorderSizes = [1, 0]; │ │ │ │ + var actualBorderSizes = [0, 2, 0, 0]; │ │ │ │ + if (this.options.compact && (this.options.blend || this._isTransparent())) { │ │ │ │ + return 1 │ │ │ │ + } else if (this.options.compact) { │ │ │ │ + return compactBorderSizes[n] │ │ │ │ + } else if (this.options.blend) { │ │ │ │ + return blendedBorderSizes[n] │ │ │ │ + } else if (this.options.border) { │ │ │ │ + return actualBorderSizes[n] │ │ │ │ + } else if (this._isTransparent()) { │ │ │ │ + return transparentBorderSizes[n] │ │ │ │ + } │ │ │ │ + return 0 │ │ │ │ + }, │ │ │ │ + _hasString: function(str) { │ │ │ │ + for (var i = 1; i < arguments.length; i++) │ │ │ │ + if (str.indexOf(arguments[i]) >= 0) { │ │ │ │ + return true │ │ │ │ + } return false │ │ │ │ + }, │ │ │ │ + _blend: function(c1, c2) { │ │ │ │ + var cc1 = OpenLayers.Rico.Color.createFromHex(c1); │ │ │ │ + cc1.blend(OpenLayers.Rico.Color.createFromHex(c2)); │ │ │ │ + return cc1 │ │ │ │ + }, │ │ │ │ + _background: function(el) { │ │ │ │ + try { │ │ │ │ + return OpenLayers.Rico.Color.createColorFromBackground(el).asHex() │ │ │ │ + } catch (err) { │ │ │ │ + return "#ffffff" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + _isTransparent: function() { │ │ │ │ + return this.options.color == "transparent" │ │ │ │ + }, │ │ │ │ + _isTopRounded: function() { │ │ │ │ + return this._hasString(this.options.corners, "all", "top", "tl", "tr") │ │ │ │ + }, │ │ │ │ + _isBottomRounded: function() { │ │ │ │ + return this._hasString(this.options.corners, "all", "bottom", "bl", "br") │ │ │ │ + }, │ │ │ │ + _hasSingleTextChild: function(el) { │ │ │ │ + return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3 │ │ │ │ + } │ │ │ │ +}; │ │ ├── ./usr/share/javascript/openlayers/OpenLayers.mobile.js │ │ │ ├── js-beautify {} │ │ │ │ @@ -136,14 +136,141 @@ │ │ │ │ * (code) │ │ │ │ * <link rel="stylesheet" href="/path/to/default/style.css" type="text/css"> │ │ │ │ * (end code) │ │ │ │ */ │ │ │ │ ImgPath: '' │ │ │ │ }; │ │ │ │ /* ====================================================================== │ │ │ │ + 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.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. */ │ │ │ │ @@ -603,141 +730,14 @@ │ │ │ │ } │ │ │ │ } │ │ │ │ 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. */ │ │ │ │ @@ -13915,538 +13915,14 @@ │ │ │ │ OpenLayers.Function.bind(timerCallback, this) │ │ │ │ ); │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Kinetic" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - 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/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/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. */ │ │ │ │ @@ -14881,3818 +14357,3623 @@ │ │ │ │ 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/Feature.js │ │ │ │ + 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/BaseTypes/Class.js │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ + * @requires OpenLayers/Renderer.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Feature │ │ │ │ - * Features are combinations of geography and attributes. The OpenLayers.Feature │ │ │ │ - * class specifically combines a marker and a lonlat. │ │ │ │ + * Class: OpenLayers.Renderer.Canvas │ │ │ │ + * A renderer based on the 2D 'canvas' drawing element. │ │ │ │ + * │ │ │ │ + * Inherits: │ │ │ │ + * - <OpenLayers.Renderer> │ │ │ │ */ │ │ │ │ -OpenLayers.Feature = OpenLayers.Class({ │ │ │ │ +OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: layer │ │ │ │ - * {<OpenLayers.Layer>} │ │ │ │ + /** │ │ │ │ + * APIProperty: hitDetection │ │ │ │ + * {Boolean} Allow for hit detection of features. Default is true. │ │ │ │ */ │ │ │ │ - layer: null, │ │ │ │ + hitDetection: true, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: id │ │ │ │ - * {String} │ │ │ │ + /** │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - id: null, │ │ │ │ + hitOverflow: 0, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: lonlat │ │ │ │ - * {<OpenLayers.LonLat>} │ │ │ │ + /** │ │ │ │ + * Property: canvas │ │ │ │ + * {Canvas} The canvas context object. │ │ │ │ */ │ │ │ │ - lonlat: null, │ │ │ │ + canvas: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: data │ │ │ │ - * {Object} │ │ │ │ + /** │ │ │ │ + * Property: features │ │ │ │ + * {Object} Internal object of feature/style pairs for use in redrawing the layer. │ │ │ │ */ │ │ │ │ - data: null, │ │ │ │ + features: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: marker │ │ │ │ - * {<OpenLayers.Marker>} │ │ │ │ + /** │ │ │ │ + * Property: pendingRedraw │ │ │ │ + * {Boolean} The renderer needs a redraw call to render features added while │ │ │ │ + * the renderer was locked. │ │ │ │ */ │ │ │ │ - marker: null, │ │ │ │ + pendingRedraw: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: popupClass │ │ │ │ - * {<OpenLayers.Class>} The class which will be used to instantiate │ │ │ │ - * a new Popup. Default is <OpenLayers.Popup.Anchored>. │ │ │ │ + * Property: cachedSymbolBounds │ │ │ │ + * {Object} Internal cache of calculated symbol extents. │ │ │ │ */ │ │ │ │ - popupClass: null, │ │ │ │ + cachedSymbolBounds: {}, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: popup │ │ │ │ - * {<OpenLayers.Popup>} │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Renderer.Canvas │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * containerID - {<String>} │ │ │ │ + * options - {Object} Optional properties to be set on the renderer. │ │ │ │ */ │ │ │ │ - popup: null, │ │ │ │ + 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"); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Feature │ │ │ │ - * Constructor for features. │ │ │ │ + /** │ │ │ │ + * Method: setExtent │ │ │ │ + * Set the visible part of the layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer>} │ │ │ │ - * lonlat - {<OpenLayers.LonLat>} │ │ │ │ - * data - {Object} │ │ │ │ - * │ │ │ │ + * extent - {<OpenLayers.Bounds>} │ │ │ │ + * resolutionChanged - {Boolean} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Feature>} │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - initialize: function(layer, lonlat, data) { │ │ │ │ - this.layer = layer; │ │ │ │ - this.lonlat = lonlat; │ │ │ │ - this.data = (data != null) ? data : {}; │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ + setExtent: function() { │ │ │ │ + OpenLayers.Renderer.prototype.setExtent.apply(this, arguments); │ │ │ │ + // always redraw features │ │ │ │ + return false; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroy │ │ │ │ - * nullify references to prevent circular references and memory leaks │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + eraseGeometry: function(geometry, featureId) { │ │ │ │ + this.eraseFeatures(this.features[featureId][0]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onScreen │ │ │ │ + * APIMethod: supported │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Whether or not the feature is currently visible on screen │ │ │ │ - * (based on its 'lonlat' property) │ │ │ │ + * {Boolean} Whether or not the browser supports the renderer class │ │ │ │ */ │ │ │ │ - onScreen: function() { │ │ │ │ + supported: function() { │ │ │ │ + return OpenLayers.CANVAS_SUPPORTED; │ │ │ │ + }, │ │ │ │ │ │ │ │ - var onScreen = false; │ │ │ │ - if ((this.layer != null) && (this.layer.map != null)) { │ │ │ │ - var screenBounds = this.layer.map.getExtent(); │ │ │ │ - onScreen = screenBounds.containsLonLat(this.lonlat); │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ } │ │ │ │ - return onScreen; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: createMarker │ │ │ │ - * Based on the data associated with the Feature, create and return a marker object. │ │ │ │ + * Method: drawFeature │ │ │ │ + * Draw the feature. Stores the feature in the features list, │ │ │ │ + * then redraws the layer. │ │ │ │ * │ │ │ │ - * 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 │ │ │ │ - * │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - createMarker: function() { │ │ │ │ + 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(); │ │ │ │ │ │ │ │ - if (this.lonlat != null) { │ │ │ │ - this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - return this.marker; │ │ │ │ + if (this.pendingRedraw && !this.locked) { │ │ │ │ + this.redraw(); │ │ │ │ + this.pendingRedraw = false; │ │ │ │ + } │ │ │ │ + return rendered; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroyMarker │ │ │ │ - * Destroys marker. │ │ │ │ - * If user overrides the createMarker() function, s/he should be able │ │ │ │ - * to also specify an alternative function for destroying it │ │ │ │ + /** │ │ │ │ + * Method: drawGeometry │ │ │ │ + * Used when looping (in redraw) over the features; draws │ │ │ │ + * the canvas. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ */ │ │ │ │ - destroyMarker: function() { │ │ │ │ - this.marker.destroy(); │ │ │ │ + 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: 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 │ │ │ │ + * Method: drawExternalGraphic │ │ │ │ + * Called to draw External graphics. │ │ │ │ * │ │ │ │ * 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>. │ │ │ │ - * │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - createPopup: function(closeBox) { │ │ │ │ + drawExternalGraphic: function(geometry, style, featureId) { │ │ │ │ + var img = new Image(); │ │ │ │ │ │ │ │ - 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); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - if (this.data.overflow != null) { │ │ │ │ - this.popup.contentDiv.style.overflow = this.data.overflow; │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ } │ │ │ │ + }; │ │ │ │ │ │ │ │ - this.popup.feature = this; │ │ │ │ - } │ │ │ │ - return this.popup; │ │ │ │ + img.onload = OpenLayers.Function.bind(onLoad, this); │ │ │ │ + img.src = style.externalGraphic; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - destroyPopup: function() { │ │ │ │ - if (this.popup) { │ │ │ │ - this.popup.feature = null; │ │ │ │ - this.popup.destroy(); │ │ │ │ - this.popup = null; │ │ │ │ + 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'); │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Feature" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Feature/Vector.js │ │ │ │ - ====================================================================== */ │ │ │ │ + if (!symbol.length || symbol.length < 2) return; │ │ │ │ │ │ │ │ -/* 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 pt = this.getLocalXY(geometry); │ │ │ │ + var p0 = pt[0]; │ │ │ │ + var p1 = pt[1]; │ │ │ │ │ │ │ │ -// TRASH THIS │ │ │ │ -OpenLayers.State = { │ │ │ │ - /** states */ │ │ │ │ - UNKNOWN: 'Unknown', │ │ │ │ - INSERT: 'Insert', │ │ │ │ - UPDATE: 'Update', │ │ │ │ - DELETE: 'Delete' │ │ │ │ -}; │ │ │ │ + if (isNaN(p0) || isNaN(p1)) return; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Feature.js │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ - */ │ │ │ │ + // Use rounded line caps │ │ │ │ + this.canvas.lineCap = "round"; │ │ │ │ + this.canvas.lineJoin = "round"; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * 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, { │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.lineCap = "round"; │ │ │ │ + this.hitContext.lineJoin = "round"; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: fid │ │ │ │ - * {String} │ │ │ │ - */ │ │ │ │ - fid: null, │ │ │ │ + // 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; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: geometry │ │ │ │ - * {<OpenLayers.Geometry>} │ │ │ │ - */ │ │ │ │ - geometry: null, │ │ │ │ + // 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(); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: attributes │ │ │ │ - * {Object} This object holds arbitrary, serializable properties that │ │ │ │ - * describe the feature. │ │ │ │ - */ │ │ │ │ - attributes: null, │ │ │ │ + // Step 3: place symbol at the desired location │ │ │ │ + this.canvas.translate(p0, p1); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.translate(p0, p1); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + // 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: state │ │ │ │ - * {String} │ │ │ │ - */ │ │ │ │ - state: null, │ │ │ │ + // // 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); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: style │ │ │ │ - * {Object} │ │ │ │ - */ │ │ │ │ - style: null, │ │ │ │ + // 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); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + // 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; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: renderIntent │ │ │ │ - * {String} rendering intent currently being used │ │ │ │ - */ │ │ │ │ - renderIntent: "default", │ │ │ │ + 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(); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + 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(); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ + │ │ │ │ + style.strokeWidth = unscaledStrokeWidth; │ │ │ │ + this.canvas.restore(); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.restore(); │ │ │ │ + } │ │ │ │ + this.setCanvasStyle("reset"); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - * nullify references to prevent circular references and memory leaks │ │ │ │ + /** │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.layer) { │ │ │ │ - this.layer.removeFeatures(this); │ │ │ │ - this.layer = null; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - │ │ │ │ - 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. │ │ │ │ + * Method: featureIdToHex │ │ │ │ + * Convert a feature ID string into an RGB hex string. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * featureId - {String} Feature id │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} An exact clone of this vector feature. │ │ │ │ + * {String} RGB hex string. │ │ │ │ */ │ │ │ │ - clone: function() { │ │ │ │ - return new OpenLayers.Feature.Vector( │ │ │ │ - this.geometry ? this.geometry.clone() : null, │ │ │ │ - this.attributes, │ │ │ │ - this.style); │ │ │ │ + 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: 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. │ │ │ │ + * Method: setHitContextStyle │ │ │ │ + * Prepare the hit canvas for drawing by setting various global settings. │ │ │ │ * │ │ │ │ * 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). │ │ │ │ + * type - {String} one of 'stroke', 'fill', or 'reset' │ │ │ │ + * featureId - {String} The feature id. │ │ │ │ + * symbolizer - {<OpenLayers.Symbolizer>} The symbolizer. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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 { │ │ │ │ - var screenPoly = screenBounds.toGeometry(); │ │ │ │ - onScreen = screenPoly.intersects(this.geometry); │ │ │ │ + if (!isNaN(strokeScaling)) { │ │ │ │ + this.hitContext.lineWidth = symbolizer.strokeWidth + 2.0 / strokeScaling; │ │ │ │ + } │ │ │ │ } │ │ │ │ + } else { │ │ │ │ + this.hitContext.globalAlpha = 0; │ │ │ │ + this.hitContext.lineWidth = 1; │ │ │ │ } │ │ │ │ - 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. │ │ │ │ + * Method: drawPoint │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The feature is currently displayed. │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - 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()); │ │ │ │ + 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: createMarker │ │ │ │ - * HACK - we need to decide if all vector features should be able to │ │ │ │ - * create markers │ │ │ │ + * Method: drawLineString │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Marker>} For now just returns null │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - createMarker: function() { │ │ │ │ - return null; │ │ │ │ + drawLineString: function(geometry, style, featureId) { │ │ │ │ + style = OpenLayers.Util.applyDefaults({ │ │ │ │ + fill: false │ │ │ │ + }, style); │ │ │ │ + this.drawLinearRing(geometry, style, featureId); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroyMarker │ │ │ │ - * HACK - we need to decide if all vector features should be able to │ │ │ │ - * delete markers │ │ │ │ + * Method: drawLinearRing │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ - * If user overrides the createMarker() function, s/he should be able │ │ │ │ - * to also specify an alternative function for destroying it │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - destroyMarker: function() { │ │ │ │ - // pass │ │ │ │ + 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: createPopup │ │ │ │ - * HACK - we need to decide if all vector features should be able to │ │ │ │ - * create popups │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Popup>} For now just returns null │ │ │ │ + * Method: renderPath │ │ │ │ + * Render a path with stroke and optional fill. │ │ │ │ */ │ │ │ │ - createPopup: function() { │ │ │ │ - return null; │ │ │ │ + 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: atPoint │ │ │ │ - * Determins whether the feature intersects with the specified location. │ │ │ │ + * Method: drawPolygon │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ * 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 │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - atPoint: function(lonlat, toleranceLon, toleranceLat) { │ │ │ │ - var atPoint = false; │ │ │ │ - if (this.geometry) { │ │ │ │ - atPoint = this.geometry.atPoint(lonlat, toleranceLon, │ │ │ │ - toleranceLat); │ │ │ │ + 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 │ │ │ │ + ); │ │ │ │ } │ │ │ │ - return atPoint; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroyPopup │ │ │ │ - * HACK - we need to decide if all vector features should be able to │ │ │ │ - * delete popups │ │ │ │ + * Method: drawText │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * location - {<OpenLayers.Point>} │ │ │ │ + * style - {Object} │ │ │ │ */ │ │ │ │ - destroyPopup: function() { │ │ │ │ - // pass │ │ │ │ + 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: move │ │ │ │ - * Moves the feature and redraws it at its new location │ │ │ │ + * Method: getLocalXY │ │ │ │ + * transform geographic xy into pixel xy │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * location - {<OpenLayers.LonLat> or <OpenLayers.Pixel>} the │ │ │ │ - * location to which to move the feature. │ │ │ │ + * Parameters: │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} │ │ │ │ */ │ │ │ │ - move: function(location) { │ │ │ │ + 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]; │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (!this.layer || !this.geometry.move) { │ │ │ │ - //do nothing if no layer or immoveable geometry │ │ │ │ - return undefined; │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - var pixel; │ │ │ │ - if (location.CLASS_NAME == "OpenLayers.LonLat") { │ │ │ │ - pixel = this.layer.getViewPortPxFromLonLat(location); │ │ │ │ - } else { │ │ │ │ - pixel = location; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ │ │ │ │ - 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; │ │ │ │ + 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: toState │ │ │ │ - * Sets the new state │ │ │ │ - * │ │ │ │ + * Method: eraseFeatures │ │ │ │ + * This is called by the layer to erase features; removes the feature from │ │ │ │ + * the list, then redraws the layer. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * state - {String} │ │ │ │ + * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - } else if (state == OpenLayers.State.INSERT) { │ │ │ │ - switch (this.state) { │ │ │ │ - case OpenLayers.State.UNKNOWN: │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - this.state = state; │ │ │ │ - break; │ │ │ │ + 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]); │ │ │ │ + } │ │ │ │ } │ │ │ │ - } 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; │ │ │ │ + var item; │ │ │ │ + for (var i = 0, len = labelMap.length; i < len; ++i) { │ │ │ │ + item = labelMap[i]; │ │ │ │ + this.drawText(item[0].geometry.getCentroid(), item[1]); │ │ │ │ } │ │ │ │ - } else if (state == OpenLayers.State.UNKNOWN) { │ │ │ │ - this.state = state; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Feature.Vector" │ │ │ │ + CLASS_NAME: "OpenLayers.Renderer.Canvas" │ │ │ │ }); │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Constant: OpenLayers.Renderer.Canvas.LABEL_ALIGN │ │ │ │ + * {Object} │ │ │ │ */ │ │ │ │ -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 │ │ │ │ +OpenLayers.Renderer.Canvas.LABEL_ALIGN = { │ │ │ │ + "l": "left", │ │ │ │ + "r": "right", │ │ │ │ + "t": "top", │ │ │ │ + "b": "bottom" │ │ │ │ +}; │ │ │ │ │ │ │ │ - }, │ │ │ │ - 'delete': { │ │ │ │ - display: "none" │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * 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/Style.js │ │ │ │ + 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/BaseTypes/Class.js │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ - * @requires OpenLayers/Feature/Vector.js │ │ │ │ + * @requires OpenLayers/Renderer.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Style │ │ │ │ - * This class represents a UserStyle obtained │ │ │ │ - * from a SLD, containing styling rules. │ │ │ │ + * 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.Style = OpenLayers.Class({ │ │ │ │ +OpenLayers.ElementsIndexer = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: id │ │ │ │ - * {String} A unique id for this session. │ │ │ │ + * Property: maxZIndex │ │ │ │ + * {Integer} This is the largest-most z-index value for a node │ │ │ │ + * contained within the indexer. │ │ │ │ */ │ │ │ │ - id: null, │ │ │ │ + maxZIndex: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: name │ │ │ │ - * {String} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - name: null, │ │ │ │ + order: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: title │ │ │ │ - * {String} Title of this style (set if included in SLD) │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - title: null, │ │ │ │ + indices: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: description │ │ │ │ - * {String} Description of this style (set if abstract is included in SLD) │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - description: null, │ │ │ │ + compare: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layerName │ │ │ │ - * {<String>} name of the layer that this style belongs to, usually │ │ │ │ - * according to the NamedLayer attribute of an SLD document. │ │ │ │ + * APIMethod: initialize │ │ │ │ + * Create a new indexer with │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * yOrdering - {Boolean} Whether to use y-ordering. │ │ │ │ */ │ │ │ │ - layerName: null, │ │ │ │ + initialize: function(yOrdering) { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: isDefault │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - isDefault: false, │ │ │ │ + this.compare = yOrdering ? │ │ │ │ + OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER : │ │ │ │ + OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: rules │ │ │ │ - * {Array(<OpenLayers.Rule>)} │ │ │ │ - */ │ │ │ │ - rules: null, │ │ │ │ + this.clear(); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - context: null, │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + var nodeId = newNode.id; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + this.determineZIndex(newNode); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + var leftIndex = -1; │ │ │ │ + var rightIndex = this.order.length; │ │ │ │ + var middle; │ │ │ │ │ │ │ │ + while (rightIndex - leftIndex > 1) { │ │ │ │ + middle = parseInt((leftIndex + rightIndex) / 2); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) { │ │ │ │ + var placement = this.compare(this, newNode, │ │ │ │ + OpenLayers.Util.getElement(this.order[middle])); │ │ │ │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - this.rules = []; │ │ │ │ - if (options && options.rules) { │ │ │ │ - this.addRules(options.rules); │ │ │ │ + if (placement > 0) { │ │ │ │ + leftIndex = middle; │ │ │ │ + } else { │ │ │ │ + rightIndex = middle; │ │ │ │ + } │ │ │ │ } │ │ │ │ │ │ │ │ - // 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 + "_"); │ │ │ │ - }, │ │ │ │ + this.order.splice(rightIndex, 0, nodeId); │ │ │ │ + this.indices[nodeId] = this.getZIndex(newNode); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ + // 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); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createSymbolizer │ │ │ │ - * creates a style by applying all feature-dependent rules to the base │ │ │ │ - * style. │ │ │ │ + * APIMethod: remove │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature>} feature to evaluate rules for │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} symbolizer hash │ │ │ │ + * node - {DOMElement} The node to be removed. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 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]; │ │ │ │ │ │ │ │ - // 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); │ │ │ │ + // 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; │ │ │ │ } │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - // 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; │ │ │ │ + /** │ │ │ │ + * APIMethod: clear │ │ │ │ + */ │ │ │ │ + clear: function() { │ │ │ │ + this.order = []; │ │ │ │ + this.indices = {}; │ │ │ │ + this.maxZIndex = 0; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: applySymbolizer │ │ │ │ + * APIMethod: exists │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * rule - {<OpenLayers.Rule>} │ │ │ │ - * style - {Object} │ │ │ │ - * feature - {<OpenLayer.Feature.Vector>} │ │ │ │ + * node - {DOMElement} The node to test for existence. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} A style with new symbolizer applied. │ │ │ │ + * {Boolean} Whether or not the node exists in the indexer? │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + exists: function(node) { │ │ │ │ + return (this.indices[node.id] != null); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createLiterals │ │ │ │ - * creates literals for all style properties that have an entry in │ │ │ │ - * <this.propertyStyles>. │ │ │ │ + * APIMethod: getZIndex │ │ │ │ + * Get the z-index value for the current node from the node data itself. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * style - {Object} style to create literals for. Will be modified │ │ │ │ - * inline. │ │ │ │ - * feature - {Object} │ │ │ │ + * node - {DOMElement} The node whose z-index to get. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} the modified style │ │ │ │ + * {Integer} The z-index value for the specified node (from the node │ │ │ │ + * data itself). │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + getZIndex: function(node) { │ │ │ │ + return node._style.graphicZIndex; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Object} hash of property names that need createLiteral parsing. The │ │ │ │ - * name of the property is the key, and the value is true; │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ */ │ │ │ │ - findPropertyStyles: function() { │ │ │ │ - var propertyStyles = {}; │ │ │ │ - │ │ │ │ - // check the default style │ │ │ │ - var style = this.defaultStyle; │ │ │ │ - this.addPropertyStyles(propertyStyles, style); │ │ │ │ + determineZIndex: function(node) { │ │ │ │ + var zIndex = node._style.graphicZIndex; │ │ │ │ │ │ │ │ - // 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + // 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; │ │ │ │ } │ │ │ │ - return propertyStyles; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: addPropertyStyles │ │ │ │ + * APIMethod: getNextElement │ │ │ │ + * Get the next element in the order stack. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * propertyStyles - {Object} hash to add new property styles to. Will be │ │ │ │ - * modified inline │ │ │ │ - * symbolizer - {Object} search this symbolizer for property styles │ │ │ │ + * index - {Integer} The index of the current node in this.order. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} propertyStyles hash │ │ │ │ + * {DOMElement} the node following the index passed in, or │ │ │ │ + * null. │ │ │ │ */ │ │ │ │ - addPropertyStyles: function(propertyStyles, symbolizer) { │ │ │ │ - var property; │ │ │ │ - for (var key in symbolizer) { │ │ │ │ - property = symbolizer[key]; │ │ │ │ - if (typeof property == "string" && │ │ │ │ - property.match(/\$\{\w+\}/)) { │ │ │ │ - propertyStyles[key] = true; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - 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(); │ │ │ │ - }, │ │ │ │ + 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 = { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setDefaultStyle │ │ │ │ - * Sets the default style for this style object. │ │ │ │ + * 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: │ │ │ │ - * style - {Object} Hash of style properties │ │ │ │ + * indexer - {<OpenLayers.ElementsIndexer>} │ │ │ │ + * newNode - {DOMElement} │ │ │ │ + * nextNode - {DOMElement} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} │ │ │ │ */ │ │ │ │ - setDefaultStyle: function(style) { │ │ │ │ - this.defaultStyle = style; │ │ │ │ - this.propertyStyles = this.findPropertyStyles(); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getSymbolizerPrefix │ │ │ │ - * Returns the correct symbolizer prefix according to the │ │ │ │ - * geometry type of the passed geometry │ │ │ │ + * 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: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * indexer - {<OpenLayers.ElementsIndexer>} │ │ │ │ + * newNode - {DOMElement} │ │ │ │ + * nextNode - {DOMElement} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} key of the according symbolizer │ │ │ │ + * {Integer} │ │ │ │ */ │ │ │ │ - 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]; │ │ │ │ - } │ │ │ │ + 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: clone │ │ │ │ - * Clones this style. │ │ │ │ + * 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: │ │ │ │ - * {<OpenLayers.Style>} Clone of this style. │ │ │ │ + * {Integer} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - }, │ │ │ │ + Z_ORDER_Y_ORDER: function(indexer, newNode, nextNode) { │ │ │ │ + var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER( │ │ │ │ + indexer, │ │ │ │ + newNode, │ │ │ │ + nextNode │ │ │ │ + ); │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Style" │ │ │ │ -}); │ │ │ │ + if (nextNode && returnVal === 0) { │ │ │ │ + var result = nextNode._boundsBottom - newNode._boundsBottom; │ │ │ │ + returnVal = (result === 0) ? 1 : result; │ │ │ │ + } │ │ │ │ │ │ │ │ + return returnVal; │ │ │ │ + } │ │ │ │ +}; │ │ │ │ │ │ │ │ /** │ │ │ │ - * Function: createLiteral │ │ │ │ - * converts a style value holding a combination of PropertyName and Literal │ │ │ │ - * into a Literal, taking the property values from the passed features. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * 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". │ │ │ │ + * Inherits: │ │ │ │ + * - <OpenLayers.Renderer> │ │ │ │ */ │ │ │ │ -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; │ │ │ │ -}; │ │ │ │ +OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ │ │ │ │ -/** │ │ │ │ - * 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/StyleMap.js │ │ │ │ - ====================================================================== */ │ │ │ │ + /** │ │ │ │ + * Property: rendererRoot │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + rendererRoot: null, │ │ │ │ │ │ │ │ -/* 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. */ │ │ │ │ + /** │ │ │ │ + * Property: root │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + root: null, │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ - * @requires OpenLayers/Style.js │ │ │ │ - * @requires OpenLayers/Feature/Vector.js │ │ │ │ - */ │ │ │ │ + /** │ │ │ │ + * Property: vectorRoot │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + vectorRoot: null, │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.StyleMap │ │ │ │ - */ │ │ │ │ -OpenLayers.StyleMap = OpenLayers.Class({ │ │ │ │ + /** │ │ │ │ + * Property: textRoot │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + textRoot: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: styles │ │ │ │ - * {Object} Hash of {<OpenLayers.Style>}, keyed by names of well known │ │ │ │ - * rendering intents (e.g. "default", "temporary", "select", "delete"). │ │ │ │ + * Property: xmlns │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - styles: null, │ │ │ │ + xmlns: 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - extendDefault: true, │ │ │ │ + xOffset: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.StyleMap │ │ │ │ + * 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: │ │ │ │ - * 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 │ │ │ │ + * 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(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"]) │ │ │ │ - }; │ │ │ │ + initialize: function(containerID, options) { │ │ │ │ + OpenLayers.Renderer.prototype.initialize.apply(this, arguments); │ │ │ │ │ │ │ │ - // 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * Method: destroy │ │ │ │ */ │ │ │ │ destroy: function() { │ │ │ │ - for (var key in this.styles) { │ │ │ │ - this.styles[key].destroy(); │ │ │ │ + │ │ │ │ + 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(); │ │ │ │ } │ │ │ │ - this.styles = null; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createSymbolizer │ │ │ │ - * Creates the symbolizer for a feature for a render intent. │ │ │ │ + * 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: │ │ │ │ - * 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). │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} symbolizer hash │ │ │ │ + * {Boolean} true if the geometry has been drawn completely; null if │ │ │ │ + * incomplete; false otherwise │ │ │ │ */ │ │ │ │ - createSymbolizer: function(feature, intent) { │ │ │ │ - if (!feature) { │ │ │ │ - feature = new OpenLayers.Feature.Vector(); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - if (!this.styles[intent]) { │ │ │ │ - intent = "default"; │ │ │ │ + │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - feature.renderIntent = intent; │ │ │ │ - var defaultSymbolizer = {}; │ │ │ │ - if (this.extendDefault && intent != "default") { │ │ │ │ - defaultSymbolizer = this.styles["default"].createSymbolizer(feature); │ │ │ │ + if (rendered == false) { │ │ │ │ + var node = document.getElementById(geometry.id); │ │ │ │ + if (node) { │ │ │ │ + if (node._style.backgroundGraphic) { │ │ │ │ + removeBackground = true; │ │ │ │ + } │ │ │ │ + node.parentNode.removeChild(node); │ │ │ │ + } │ │ │ │ } │ │ │ │ - return OpenLayers.Util.extend(defaultSymbolizer, │ │ │ │ - this.styles[intent].createSymbolizer(feature)); │ │ │ │ + if (removeBackground) { │ │ │ │ + var node = document.getElementById( │ │ │ │ + geometry.id + this.BACKGROUND_ID_SUFFIX); │ │ │ │ + if (node) { │ │ │ │ + node.parentNode.removeChild(node); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return rendered; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Method: redrawNode │ │ │ │ * │ │ │ │ * 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 │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - })); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - this.styles[renderIntent].addRules(rules); │ │ │ │ - }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.StyleMap" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Layer/Vector.js │ │ │ │ - ====================================================================== */ │ │ │ │ + node = drawResult.node; │ │ │ │ │ │ │ │ -/* 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. */ │ │ │ │ + // 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @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 │ │ │ │ - */ │ │ │ │ + this.postDraw(node); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * 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, { │ │ │ │ + return drawResult.complete; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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 │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} The layer is a base layer. Default is false. Set this property │ │ │ │ - * in the layer options. │ │ │ │ + * 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) │ │ │ │ */ │ │ │ │ - isBaseLayer: false, │ │ │ │ + drawGeometryNode: function(node, geometry, style) { │ │ │ │ + style = style || node._style; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: features │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ - */ │ │ │ │ - features: null, │ │ │ │ + node._options = options; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: filter │ │ │ │ - * {<OpenLayers.Filter>} The filter set in this layer, │ │ │ │ - * a strategy launching read requests can combined │ │ │ │ - * this filter with its own filter. │ │ │ │ + //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} │ │ │ │ */ │ │ │ │ - filter: null, │ │ │ │ + postDraw: function(node) {}, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: selectedFeatures │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ + /** │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - selectedFeatures: null, │ │ │ │ + drawPoint: function(node, geometry) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: unrenderedFeatures │ │ │ │ - * {Object} hash of features, keyed by feature.id, that the renderer │ │ │ │ - * failed to draw │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - unrenderedFeatures: null, │ │ │ │ + drawLineString: function(node, geometry) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: reportError │ │ │ │ - * {Boolean} report friendly error message when loading of renderer │ │ │ │ - * fails. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - reportError: true, │ │ │ │ + drawLinearRing: function(node, geometry) {}, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: style │ │ │ │ - * {Object} Default style for the layer │ │ │ │ + /** │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - style: null, │ │ │ │ + drawPolygon: function(node, geometry) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: styleMap │ │ │ │ - * {<OpenLayers.StyleMap>} │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - styleMap: null, │ │ │ │ + drawRectangle: function(node, geometry) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: strategies │ │ │ │ - * {Array(<OpenLayers.Strategy>})} Optional list of strategies for the layer. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - strategies: null, │ │ │ │ + drawCircle: function(node, geometry) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: protocol │ │ │ │ - * {<OpenLayers.Protocol>} Optional protocol for the layer. │ │ │ │ + * Method: removeText │ │ │ │ + * Removes a label │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - protocol: null, │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: getFeatureIdFromEvent │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Object} An <OpenLayers.Event> object │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A feature id or undefined. │ │ │ │ */ │ │ │ │ - renderers: ['SVG', 'VML', 'Canvas'], │ │ │ │ + getFeatureIdFromEvent: function(evt) { │ │ │ │ + var target = evt.target; │ │ │ │ + var useElement = target && target.correspondingUseElement; │ │ │ │ + var node = useElement ? useElement : (target || evt.srcElement); │ │ │ │ + return node._featureId; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: renderer │ │ │ │ - * {<OpenLayers.Renderer>} │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - renderer: null, │ │ │ │ + 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); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: rendererOptions │ │ │ │ - * {Object} Options for the renderer. See {<OpenLayers.Renderer>} for │ │ │ │ - * supported options. │ │ │ │ - */ │ │ │ │ - rendererOptions: null, │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - geometryType: null, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: drawn │ │ │ │ - * {Boolean} Whether the Vector Layer features have been drawn yet. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - drawn: false, │ │ │ │ + nodeTypeCompare: function(node, type) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: ratio │ │ │ │ - * {Float} This specifies the ratio of the size of the visiblity of the Vector Layer features to the size of the map. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - ratio: 1, │ │ │ │ + createNode: function(type, id) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.Vector │ │ │ │ - * Create a new vector layer │ │ │ │ - * │ │ │ │ + * Method: moveRoot │ │ │ │ + * moves this renderer's root to a different renderer. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} A name for the layer │ │ │ │ - * options - {Object} Optional object with non-default properties to set on │ │ │ │ - * the layer. │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * {<OpenLayers.Layer.Vector>} A new vector layer │ │ │ │ + * {String} the id of the output layer. │ │ │ │ */ │ │ │ │ - initialize: function(name, options) { │ │ │ │ - OpenLayers.Layer.prototype.initialize.apply(this, arguments); │ │ │ │ + getRenderLayerId: function() { │ │ │ │ + return this.root.parentNode.parentNode.id; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // allow user-set renderer, otherwise assign one │ │ │ │ - if (!this.renderer || !this.renderer.supported()) { │ │ │ │ - this.assignRenderer(); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // if no valid renderer found, display error │ │ │ │ - if (!this.renderer || !this.renderer.supported()) { │ │ │ │ - this.renderer = null; │ │ │ │ - this.displayError(); │ │ │ │ - } │ │ │ │ + CLASS_NAME: "OpenLayers.Renderer.Elements" │ │ │ │ +}); │ │ │ │ │ │ │ │ - if (!this.styleMap) { │ │ │ │ - this.styleMap = new OpenLayers.StyleMap(); │ │ │ │ - } │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Renderer/SVG.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - this.features = []; │ │ │ │ - this.selectedFeatures = []; │ │ │ │ - this.unrenderedFeatures = {}; │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - // Allow for custom layer behavior │ │ │ │ - if (this.strategies) { │ │ │ │ - for (var i = 0, len = this.strategies.length; i < len; i++) { │ │ │ │ - this.strategies[i].setLayer(this); │ │ │ │ - } │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Renderer/Elements.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Renderer.SVG │ │ │ │ + * │ │ │ │ + * Inherits: │ │ │ │ + * - <OpenLayers.Renderer.Elements> │ │ │ │ + */ │ │ │ │ +OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Destroy this layer │ │ │ │ + /** │ │ │ │ + * Property: xmlns │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - }, │ │ │ │ + xmlns: "http://www.w3.org/2000/svg", │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Property: xlinkns │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.Vector(this.name, this.getOptions()); │ │ │ │ - } │ │ │ │ + xlinkns: "http://www.w3.org/1999/xlink", │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]); │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - // 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; │ │ │ │ + /** │ │ │ │ + * Property: translationParameters │ │ │ │ + * {Object} Hash with "x" and "y" properties │ │ │ │ + */ │ │ │ │ + translationParameters: null, │ │ │ │ │ │ │ │ - return obj; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: refresh │ │ │ │ - * Ask the layer to request features again and redraw them. Triggers │ │ │ │ - * the refresh event if the layer is in range and visible. │ │ │ │ - * │ │ │ │ + * Constructor: OpenLayers.Renderer.SVG │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * obj - {Object} Optional object with properties for any listener of │ │ │ │ - * the refresh event. │ │ │ │ + * containerID - {String} │ │ │ │ */ │ │ │ │ - refresh: function(obj) { │ │ │ │ - if (this.calculateInRange() && this.visibility) { │ │ │ │ - this.events.triggerEvent("refresh", obj); │ │ │ │ + initialize: function(containerID) { │ │ │ │ + if (!this.supported()) { │ │ │ │ + return; │ │ │ │ } │ │ │ │ + OpenLayers.Renderer.Elements.prototype.initialize.apply(this, │ │ │ │ + arguments); │ │ │ │ + this.translationParameters = { │ │ │ │ + x: 0, │ │ │ │ + y: 0 │ │ │ │ + }; │ │ │ │ + │ │ │ │ + this.symbolMetrics = {}; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: assignRenderer │ │ │ │ - * Iterates through the available renderer implementations and selects │ │ │ │ - * and assigns the first one whose "supported()" function returns true. │ │ │ │ + /** │ │ │ │ + * APIMethod: supported │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the browser supports the SVG renderer │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 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: displayError │ │ │ │ - * Let the user know their browser isn't supported. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - displayError: function() { │ │ │ │ - if (this.reportError) { │ │ │ │ - OpenLayers.Console.userError(OpenLayers.i18n("browserNotSupported", { │ │ │ │ - renderers: this.renderers.join('\n') │ │ │ │ - })); │ │ │ │ - } │ │ │ │ + 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: 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. │ │ │ │ + /** │ │ │ │ + * Method: setExtent │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.prototype.setMap.apply(this, arguments); │ │ │ │ + setExtent: function(extent, resolutionChanged) { │ │ │ │ + var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments); │ │ │ │ │ │ │ │ - if (!this.renderer) { │ │ │ │ - this.map.removeLayer(this); │ │ │ │ - } else { │ │ │ │ - this.renderer.map = this.map; │ │ │ │ + var resolution = this.getResolution(), │ │ │ │ + left = -extent.left / resolution, │ │ │ │ + top = extent.top / resolution; │ │ │ │ │ │ │ │ - var newSize = this.map.getSize(); │ │ │ │ - newSize.w = newSize.w * this.ratio; │ │ │ │ - newSize.h = newSize.h * this.ratio; │ │ │ │ - this.renderer.setSize(newSize); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + // 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; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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(); │ │ │ │ - } │ │ │ │ + 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: removeMap │ │ │ │ - * The layer has been removed from the map. │ │ │ │ - * │ │ │ │ + * Method: translate │ │ │ │ + * Transforms the SVG coordinate system │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * x - {Float} │ │ │ │ + * y - {Float} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} true if the translation parameters are in the valid coordinates │ │ │ │ + * range, false otherwise. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ + 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: onMapResize │ │ │ │ - * Notify the renderer of the change in size. │ │ │ │ + * Method: setSize │ │ │ │ + * Sets the size of the drawing surface. │ │ │ │ * │ │ │ │ + * Parameters: │ │ │ │ + * size - {<OpenLayers.Size>} The size of the drawing surface │ │ │ │ */ │ │ │ │ - onMapResize: function() { │ │ │ │ - OpenLayers.Layer.prototype.onMapResize.apply(this, arguments); │ │ │ │ + setSize: function(size) { │ │ │ │ + OpenLayers.Renderer.prototype.setSize.apply(this, arguments); │ │ │ │ │ │ │ │ - var newSize = this.map.getSize(); │ │ │ │ - newSize.w = newSize.w * this.ratio; │ │ │ │ - newSize.h = newSize.h * this.ratio; │ │ │ │ - this.renderer.setSize(newSize); │ │ │ │ + this.rendererRoot.setAttributeNS(null, "width", this.size.w); │ │ │ │ + this.rendererRoot.setAttributeNS(null, "height", this.size.h); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * Method: getNodeType │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - * zoomChanged - {Boolean} │ │ │ │ - * dragging - {Boolean} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} The corresponding node type for the specified geometry │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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"; │ │ │ │ } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: display │ │ │ │ - * Hide or show the Layer │ │ │ │ + * Method: setStyle │ │ │ │ + * Use to set all the style attributes to a SVG node. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Takes care to adjust stroke width and point radius to be │ │ │ │ + * resolution-relative │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ - * options - {Object} │ │ │ │ + * node - {SVGDomElement} An SVG element to decorate │ │ │ │ + * style - {Object} │ │ │ │ + * options - {Object} Currently supported options include │ │ │ │ + * 'isFilled' {Boolean} and │ │ │ │ + * 'isStroked' {Boolean} │ │ │ │ */ │ │ │ │ - addFeatures: function(features, options) { │ │ │ │ - if (!(OpenLayers.Util.isArray(features))) { │ │ │ │ - features = [features]; │ │ │ │ - } │ │ │ │ + setStyle: function(node, style, options) { │ │ │ │ + style = style || node._style; │ │ │ │ + options = options || node._options; │ │ │ │ │ │ │ │ - var notify = !options || !options.silent; │ │ │ │ - if (notify) { │ │ │ │ - var event = { │ │ │ │ - features: features │ │ │ │ - }; │ │ │ │ - var ret = this.events.triggerEvent("beforefeaturesadded", event); │ │ │ │ - if (ret === false) { │ │ │ │ - return; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + 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"); │ │ │ │ } │ │ │ │ - this.preFeatureInsert(feature); │ │ │ │ - } │ │ │ │ - │ │ │ │ - featuresAdded.push(feature); │ │ │ │ - this.features.push(feature); │ │ │ │ - this.drawFeature(feature); │ │ │ │ + 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); │ │ │ │ │ │ │ │ - if (notify) { │ │ │ │ - this.events.triggerEvent("featureadded", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - this.onFeatureInsert(feature); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ │ │ │ │ - if (notify) { │ │ │ │ - this.events.triggerEvent("featuresadded", { │ │ │ │ - features: featuresAdded │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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(); │ │ │ │ - } │ │ │ │ + // 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")); │ │ │ │ │ │ │ │ - var notify = !options || !options.silent; │ │ │ │ + node.setAttributeNS(null, "width", size); │ │ │ │ + node.setAttributeNS(null, "height", size); │ │ │ │ + node.setAttributeNS(null, "x", pos.x - offset); │ │ │ │ + node.setAttributeNS(null, "y", pos.y - offset); │ │ │ │ │ │ │ │ - if (notify) { │ │ │ │ - this.events.triggerEvent( │ │ │ │ - "beforefeaturesremoved", { │ │ │ │ - features: features │ │ │ │ + // 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); │ │ │ │ } │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - │ │ │ │ - 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; │ │ │ │ + node.setAttributeNS(null, "r", style.pointRadius); │ │ │ │ } │ │ │ │ │ │ │ │ - var feature = features[i]; │ │ │ │ - delete this.unrenderedFeatures[feature.id]; │ │ │ │ + var rotation = style.rotation; │ │ │ │ │ │ │ │ - if (notify) { │ │ │ │ - this.events.triggerEvent("beforefeatureremoved", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ + 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] + ")"); │ │ │ │ + } │ │ │ │ } │ │ │ │ + } │ │ │ │ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + if (options.isFilled) { │ │ │ │ + node.setAttributeNS(null, "fill", style.fillColor); │ │ │ │ + node.setAttributeNS(null, "fill-opacity", style.fillOpacity); │ │ │ │ + } else { │ │ │ │ + node.setAttributeNS(null, "fill", "none"); │ │ │ │ + } │ │ │ │ │ │ │ │ - //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 (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 (notify) { │ │ │ │ - this.events.triggerEvent("featureremoved", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - } │ │ │ │ + if (style.pointerEvents) { │ │ │ │ + node.setAttributeNS(null, "pointer-events", style.pointerEvents); │ │ │ │ } │ │ │ │ │ │ │ │ - if (notify) { │ │ │ │ - this.events.triggerEvent("featuresremoved", { │ │ │ │ - features: features │ │ │ │ - }); │ │ │ │ + if (style.cursor != null) { │ │ │ │ + node.setAttributeNS(null, "cursor", style.cursor); │ │ │ │ } │ │ │ │ + │ │ │ │ + return node; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: removeAllFeatures │ │ │ │ - * Remove all features from the layer. │ │ │ │ - * │ │ │ │ + * Method: dashStyle │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional properties for changing behavior of the │ │ │ │ - * removal. │ │ │ │ - * │ │ │ │ - * Valid options: │ │ │ │ - * silent - {Boolean} Supress event triggering. Default is false. │ │ │ │ + * style - {Object} │ │ │ │ + * widthFactor - {Number} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A SVG compliant 'stroke-dasharray' value │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + 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, ","); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: destroyFeatures │ │ │ │ - * Erase and destroy features on the layer. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: createNode │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * type - {String} Kind of node to draw │ │ │ │ + * id - {String} Id for node │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A new node of the given type and id │ │ │ │ */ │ │ │ │ - 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]; │ │ │ │ + createNode: function(type, id) { │ │ │ │ + var node = document.createElementNS(this.xmlns, type); │ │ │ │ + if (id) { │ │ │ │ + node.setAttributeNS(null, "id", id); │ │ │ │ } │ │ │ │ + return node; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: eraseFeatures │ │ │ │ - * Erase features from the layer. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: nodeTypeCompare │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ + * node - {SVGDomElement} An SVG element │ │ │ │ + * type - {String} Kind of node │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the specified node is of the specified type │ │ │ │ */ │ │ │ │ - eraseFeatures: function(features) { │ │ │ │ - this.renderer.eraseFeatures(features); │ │ │ │ + nodeTypeCompare: function(node, type) { │ │ │ │ + return (type == node.nodeName); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getFeatureFromEvent │ │ │ │ - * Given an event, return a feature if the event occurred over one. │ │ │ │ - * Otherwise, return null. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ + * Method: createRenderRoot │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} A feature if one was under the event. │ │ │ │ + * {DOMElement} The specific render engine's root element │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + createRenderRoot: function() { │ │ │ │ + var svg = this.nodeFactory(this.container.id + "_svgRoot", "svg"); │ │ │ │ + svg.style.display = "block"; │ │ │ │ + return svg; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getFeatureBy │ │ │ │ - * Given a property value, return the feature if it exists in the features array │ │ │ │ - * │ │ │ │ + * Method: createRoot │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * property - {String} │ │ │ │ - * value - {String} │ │ │ │ - * │ │ │ │ + * suffix - {String} suffix to append to the id │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} A feature corresponding to the given │ │ │ │ - * property value or null if there is no such feature. │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + createRoot: function(suffix) { │ │ │ │ + return this.nodeFactory(this.container.id + suffix, "g"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getFeatureById │ │ │ │ - * Given a feature id, return the feature if it exists in the features array │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * featureId - {String} │ │ │ │ + * Method: createDefs │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} A feature corresponding to the given │ │ │ │ - * featureId or null if there is no such feature. │ │ │ │ + * {DOMElement} The element to which we'll add the symbol definitions │ │ │ │ */ │ │ │ │ - getFeatureById: function(featureId) { │ │ │ │ - return this.getFeatureBy('id', featureId); │ │ │ │ + createDefs: function() { │ │ │ │ + var defs = this.nodeFactory(this.container.id + "_defs", "defs"); │ │ │ │ + this.rendererRoot.appendChild(defs); │ │ │ │ + return defs; │ │ │ │ }, │ │ │ │ │ │ │ │ + /************************************** │ │ │ │ + * * │ │ │ │ + * GEOMETRY DRAWING FUNCTIONS * │ │ │ │ + * * │ │ │ │ + **************************************/ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * APIMethod: getFeatureByFid │ │ │ │ - * Given a feature fid, return the feature if it exists in the features array │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * featureFid - {String} │ │ │ │ - * │ │ │ │ + * Method: drawPoint │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} A feature corresponding to the given │ │ │ │ - * featureFid or null if there is no such feature. │ │ │ │ + * {DOMElement} or false if the renderer could not draw the point │ │ │ │ */ │ │ │ │ - getFeatureByFid: function(featureFid) { │ │ │ │ - return this.getFeatureBy('fid', featureFid); │ │ │ │ + drawPoint: function(node, geometry) { │ │ │ │ + return this.drawCircle(node, geometry, 1); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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} │ │ │ │ - * │ │ │ │ + * Method: drawCircle │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * radius - {Float} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * Array({<OpenLayers.Feature.Vector>}) An array of features that have the │ │ │ │ - * passed named attribute set to the given value. │ │ │ │ + * {DOMElement} or false if the renderer could not draw the circle │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - 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); │ │ │ │ + * 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; │ │ │ │ } │ │ │ │ - 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. │ │ │ │ - * │ │ │ │ + * Method: drawLinearRing │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - onFeatureInsert: function(feature) {}, │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: drawPolygon │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} or null if the layer has no features with │ │ │ │ - * geometries. │ │ │ │ + * {DOMElement} or null if the renderer could not draw all components │ │ │ │ + * of the polygon, or false if nothing could be drawn │ │ │ │ */ │ │ │ │ - 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()); │ │ │ │ - } │ │ │ │ + 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; │ │ │ │ } │ │ │ │ } │ │ │ │ - return maxExtent; │ │ │ │ + d += " z"; │ │ │ │ + if (draw) { │ │ │ │ + node.setAttributeNS(null, "d", d); │ │ │ │ + node.setAttributeNS(null, "fill-rule", "evenodd"); │ │ │ │ + return complete ? node : null; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Vector" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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 │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - DEFAULT_PARAMS: { │ │ │ │ - service: "WMS", │ │ │ │ - version: "1.1.1", │ │ │ │ - request: "GetMap", │ │ │ │ - styles: "", │ │ │ │ - format: "image/jpeg" │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} Default is true for WMS layer │ │ │ │ + * Method: drawText │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * featureId - {String} │ │ │ │ + * style - │ │ │ │ + * location - {<OpenLayers.Geometry.Point>} │ │ │ │ */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + var x = ((location.x - this.featureDx) / resolution + this.left); │ │ │ │ + var y = (location.y / resolution - this.top); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: {}, │ │ │ │ + var suffix = (drawOutline) ? this.LABEL_OUTLINE_SUFFIX : this.LABEL_ID_SUFFIX; │ │ │ │ + var label = this.nodeFactory(featureId + suffix, "text"); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) │ │ │ │ - ); │ │ │ │ + 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"); │ │ │ │ │ │ │ │ - //layer is transparent │ │ │ │ - if (!this.noMagic && this.params.TRANSPARENT && │ │ │ │ - this.params.TRANSPARENT.toString().toLowerCase() == "true") { │ │ │ │ + if (OpenLayers.IS_GECKO === true) { │ │ │ │ + label.setAttributeNS(null, "dominant-baseline", │ │ │ │ + OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]] || "central"); │ │ │ │ + } │ │ │ │ │ │ │ │ - // unless explicitly set in options, make layer an overlay │ │ │ │ - if ((options == null) || (!options.isBaseLayer)) { │ │ │ │ - this.isBaseLayer = false; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - │ │ │ │ - // 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"; │ │ │ │ + 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: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: getComponentString │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * components - {Array(<OpenLayers.Geometry.Point>)} Array of points │ │ │ │ + * separator - {String} character between coordinate pairs. Defaults to "," │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Layer.WMS>} An exact clone of this layer │ │ │ │ + * {Object} hash with properties "path" (the string created from the │ │ │ │ + * components and "complete" (false if the renderer was unable to │ │ │ │ + * draw all components) │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.WMS(this.name, │ │ │ │ - this.url, │ │ │ │ - this.params, │ │ │ │ - this.getOptions()); │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ } │ │ │ │ │ │ │ │ - //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; │ │ │ │ + return { │ │ │ │ + path: strings.join(separator || ","), │ │ │ │ + complete: complete │ │ │ │ + }; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: reverseAxisOrder │ │ │ │ - * Returns true if the axis order is reversed for the WMS version and │ │ │ │ - * projection of the layer. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} true if the axis order is reversed, false otherwise. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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)); │ │ │ │ + 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: getURL │ │ │ │ - * Return a GetMap query string for this layer │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: getShortString │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the │ │ │ │ - * request. │ │ │ │ - * │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {String} A string with the layer's url and parameters and also the │ │ │ │ - * passed-in bounds and appropriate tile size specified as │ │ │ │ - * parameters. │ │ │ │ + * {String} or false if point is outside the valid range │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ + getShortString: function(point) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var x = ((point.x - this.featureDx) / resolution + this.left); │ │ │ │ + var y = (this.top - point.y / resolution); │ │ │ │ │ │ │ │ - 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; │ │ │ │ + if (this.inValidRange(x, y)) { │ │ │ │ + return x + "," + y; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: getPosition │ │ │ │ + * Finds the position of an svg node. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * newParams - {Object} Hashtable of new params to use │ │ │ │ + * node - {DOMElement} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} hash with x and y properties, representing the coordinates │ │ │ │ + * within the svg coordinate system │ │ │ │ */ │ │ │ │ - mergeNewParams: function(newParams) { │ │ │ │ - var upperParams = OpenLayers.Util.upperCaseObject(newParams); │ │ │ │ - var newArguments = [upperParams]; │ │ │ │ - return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, │ │ │ │ - newArguments); │ │ │ │ + getPosition: function(node) { │ │ │ │ + return ({ │ │ │ │ + x: parseFloat(node.getAttributeNS(null, "cx")), │ │ │ │ + y: parseFloat(node.getAttributeNS(null, "cy")) │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: importSymbol │ │ │ │ + * add a new symbol definition from the rendererer's symbol hash │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * newParams - {Object} │ │ │ │ - * altUrl - {String} Use this as the url instead of the layer's url │ │ │ │ + * graphicName - {String} name of the symbol to import │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} │ │ │ │ + * {DOMElement} - the imported symbol │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + importSymbol: function(graphicName) { │ │ │ │ + if (!this.defs) { │ │ │ │ + // create svg defs tag │ │ │ │ + this.defs = this.createDefs(); │ │ │ │ } │ │ │ │ + var id = this.container.id + "-" + graphicName; │ │ │ │ │ │ │ │ - if (typeof this.params.TRANSPARENT == "boolean") { │ │ │ │ - newParams.TRANSPARENT = this.params.TRANSPARENT ? "TRUE" : "FALSE"; │ │ │ │ + // check if symbol already exists in the defs │ │ │ │ + var existing = document.getElementById(id); │ │ │ │ + if (existing != null) { │ │ │ │ + return existing; │ │ │ │ } │ │ │ │ │ │ │ │ - return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply( │ │ │ │ - this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.WMS" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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' │ │ │ │ - ], │ │ │ │ + var symbol = OpenLayers.Renderer.symbol[graphicName]; │ │ │ │ + if (!symbol) { │ │ │ │ + throw new Error(graphicName + ' is not a valid symbol name'); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: attribution │ │ │ │ - * {String} The layer attribution. │ │ │ │ - */ │ │ │ │ - attribution: "© <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors", │ │ │ │ + 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); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: sphericalMercator │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - sphericalMercator: true, │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: wrapDateLine │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - wrapDateLine: true, │ │ │ │ + node.setAttributeNS(null, "points", points.join(" ")); │ │ │ │ │ │ │ │ - /** 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, │ │ │ │ + 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 │ │ │ │ + ]; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + this.defs.appendChild(symbolNode); │ │ │ │ + return symbolNode; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clone │ │ │ │ + * Method: getFeatureIdFromEvent │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Object} An <OpenLayers.Event> object │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A feature id or undefined. │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.OSM( │ │ │ │ - this.name, this.url, this.getOptions()); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj; │ │ │ │ + return featureId; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.OSM" │ │ │ │ + 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/Control.js │ │ │ │ + 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.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); │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Strategy │ │ │ │ + * Abstract vector layer strategy class. Not to be instantiated directly. Use │ │ │ │ + * one of the strategy subclasses instead. │ │ │ │ */ │ │ │ │ -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: "", │ │ │ │ +OpenLayers.Strategy = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: title │ │ │ │ - * {string} This property is used for showing a tooltip over the │ │ │ │ - * Control. │ │ │ │ + * Property: layer │ │ │ │ + * {<OpenLayers.Layer.Vector>} The layer this strategy belongs to. │ │ │ │ */ │ │ │ │ - title: "", │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * false. │ │ │ │ + * Property: options │ │ │ │ + * {Object} Any options sent to the constructor. │ │ │ │ */ │ │ │ │ - autoActivate: false, │ │ │ │ + options: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: active │ │ │ │ - * {Boolean} The control is active (read-only). Use <activate> and │ │ │ │ - * <deactivate> to change control state. │ │ │ │ + * Property: active │ │ │ │ + * {Boolean} The control is active. │ │ │ │ */ │ │ │ │ active: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: handlerOptions │ │ │ │ - * {Object} Used to set non-default properties on the control's handler │ │ │ │ - */ │ │ │ │ - handlerOptions: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: handler │ │ │ │ - * {<OpenLayers.Handler>} 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. │ │ │ │ */ │ │ │ │ - handler: null, │ │ │ │ + autoActivate: 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, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + * Property: autoDestroy │ │ │ │ + * {Boolean} The creator of the strategy can set autoDestroy to false │ │ │ │ + * to fully control when the strategy is destroyed. Defaults to │ │ │ │ + * true. │ │ │ │ */ │ │ │ │ - events: null, │ │ │ │ + autoDestroy: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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}); │ │ │ │ + * Constructor: OpenLayers.Strategy │ │ │ │ + * Abstract class for vector strategies. Create instances of a subclass. │ │ │ │ * │ │ │ │ - * Overrides the default div attribute value of null. │ │ │ │ - * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ 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 + "_"); │ │ │ │ - } │ │ │ │ + this.options = options; │ │ │ │ + // set the active property here, so that user cannot override it │ │ │ │ + this.active = false; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Clean up the strategy. │ │ │ │ */ │ │ │ │ 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); │ │ │ │ - } │ │ │ │ + this.deactivate(); │ │ │ │ + this.layer = null; │ │ │ │ + this.options = null; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: setLayer │ │ │ │ + * Called to set the <layer> property. │ │ │ │ * │ │ │ │ * 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 │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + setLayer: function(layer) { │ │ │ │ + this.layer = layer; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: moveTo │ │ │ │ - * Sets the left and top style attributes to the passed in pixel │ │ │ │ - * coordinates. │ │ │ │ + * Method: activate │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ + * the strategy 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" │ │ │ │ - ); │ │ │ │ + if (!this.active) { │ │ │ │ + this.active = true; │ │ │ │ + return true; │ │ │ │ } │ │ │ │ - this.events.triggerEvent("activate"); │ │ │ │ - return true; │ │ │ │ + return false; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivates a control and it's associated handler if any. The exact │ │ │ │ - * effect of this depends on the control itself. │ │ │ │ - * │ │ │ │ + * Method: deactivate │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ + * tear-down. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} True if the control was effectively deactivated or false │ │ │ │ - * if the control was already inactive. │ │ │ │ + * {Boolean} True if the strategy was successfully deactivated or false if │ │ │ │ + * the strategy 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" │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ }); │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Control.TYPE_BUTTON │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.TYPE_BUTTON = 1; │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Control.TYPE_TOGGLE │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.TYPE_TOGGLE = 2; │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Control.TYPE_TOOL │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.TYPE_TOOL = 3; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Events/buttonclick.js │ │ │ │ + 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/Events.js │ │ │ │ + * @requires OpenLayers/Strategy.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>. │ │ │ │ + * Class: OpenLayers.Strategy.Fixed │ │ │ │ + * A simple strategy that requests features once and never requests new data. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Strategy> │ │ │ │ */ │ │ │ │ -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$/, │ │ │ │ +OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: startEvt │ │ │ │ - * {Event} The event that started the click sequence │ │ │ │ + * 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.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. │ │ │ │ + * Constructor: OpenLayers.Strategy.Fixed │ │ │ │ + * Create a new Fixed strategy. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * target - {<OpenLayers.Events>} The events instance that the buttonclick │ │ │ │ - * event will be triggered on. │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - for (var i = this.events.length - 1; i >= 0; --i) { │ │ │ │ - this.target.unregister(this.events[i], this, this.buttonClick); │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ + } │ │ │ │ } │ │ │ │ - delete this.target; │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getPressedButton │ │ │ │ - * Get the pressed button, if any. Returns undefined if no button │ │ │ │ - * was pressed. │ │ │ │ - * │ │ │ │ - * Arguments: │ │ │ │ - * element - {DOMElement} The event target. │ │ │ │ - * │ │ │ │ + * Method: deactivate │ │ │ │ + * Deactivate the strategy. Undo what is done in <activate>. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} The button element, or undefined. │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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: ignore │ │ │ │ - * Check for event target elements that should be ignored by OpenLayers. │ │ │ │ + * Method: load │ │ │ │ + * Tells protocol to load data and unhooks the visibilitychanged event │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * element - {DOMElement} The event target. │ │ │ │ + * options - {Object} options to pass to protocol read. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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: buttonClick │ │ │ │ - * Check if a button was clicked, and fire the buttonclick event │ │ │ │ + * 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: │ │ │ │ - * evt - {Event} │ │ │ │ + * resp - {<OpenLayers.Protocol.Response>} The response object passed │ │ │ │ + * by the protocol. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - 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; │ │ │ │ } │ │ │ │ + layer.addFeatures(features); │ │ │ │ } │ │ │ │ - return propagate; │ │ │ │ - } │ │ │ │ + layer.events.triggerEvent("loadend", { │ │ │ │ + response: resp │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Fixed" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Panel.js │ │ │ │ + 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/Control.js │ │ │ │ - * @requires OpenLayers/Events/buttonclick.js │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Panel │ │ │ │ - * The Panel control is a container for other controls. With it toolbars │ │ │ │ - * may be composed. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * 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.Control.Panel = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - /** │ │ │ │ - * Property: controls │ │ │ │ - * {Array(<OpenLayers.Control>)} │ │ │ │ - */ │ │ │ │ - controls: null, │ │ │ │ +OpenLayers.Handler = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ + * Property: id │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - autoActivate: true, │ │ │ │ + id: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - defaultControl: null, │ │ │ │ + control: 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. │ │ │ │ + * Property: map │ │ │ │ + * {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - saveState: false, │ │ │ │ + map: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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) │ │ │ │ */ │ │ │ │ - allowDepress: false, │ │ │ │ + keyMask: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: activeState │ │ │ │ - * {Object} stores the active state of this panel's controls. │ │ │ │ + * Property: active │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - activeState: null, │ │ │ │ + active: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.controls = []; │ │ │ │ - this.activeState = {}; │ │ │ │ - }, │ │ │ │ + evt: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - }, │ │ │ │ + touch: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: activate │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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 + "_"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ + * Method: setMap │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + setMap: function(map) { │ │ │ │ + this.map = map; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: draw │ │ │ │ + * 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: │ │ │ │ - * {DOMElement} │ │ │ │ + * {Boolean} The keyMask matches the keys down on an event. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + checkModifiers: function(evt) { │ │ │ │ + if (this.keyMask == null) { │ │ │ │ + return true; │ │ │ │ } │ │ │ │ - this.addControlsToMap(this.controls); │ │ │ │ - return this.div; │ │ │ │ + /* 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); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: redraw │ │ │ │ + * APIMethod: activate │ │ │ │ + * Turn on the handler. Returns false if the handler was already active. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The handler was activated. │ │ │ │ */ │ │ │ │ - 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 = ""; │ │ │ │ + activate: function() { │ │ │ │ if (this.active) { │ │ │ │ - for (var i = 0, len = this.controls.length; i < len; i++) { │ │ │ │ - this.div.appendChild(this.controls[i].panel_div); │ │ │ │ + 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: activateControl │ │ │ │ - * This method is called when the user click on the icon representing a │ │ │ │ - * control in the panel. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * control - {<OpenLayers.Control>} │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Turn off the handler. Returns false if the handler was already inactive. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The handler was deactivated. │ │ │ │ */ │ │ │ │ - activateControl: function(control) { │ │ │ │ + deactivate: function() { │ │ │ │ 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(); │ │ │ │ - } │ │ │ │ + // 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]]); │ │ │ │ } │ │ │ │ - control.activate(); │ │ │ │ } │ │ │ │ + this.touch = false; │ │ │ │ + this.active = false; │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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]]); │ │ │ │ + } │ │ │ │ } │ │ │ │ - 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. │ │ │ │ + * Method: callback │ │ │ │ + * Trigger the control's named callback with the given arguments │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * controls - {Array(<OpenLayers.Control>)} Controls to add into map. │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + callback: function(name, args) { │ │ │ │ + if (name && this.callbacks[name]) { │ │ │ │ + this.callbacks[name].apply(this.control, args); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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". │ │ │ │ + * Method: register │ │ │ │ + * register an event on the map │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ + 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: onButtonClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * Method: unregister │ │ │ │ + * unregister an event from the map │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + unregister: function(name, method) { │ │ │ │ + this.map.events.unregister(name, this, method); │ │ │ │ + this.map.events.unregister(name, this, this.setEvent); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * 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: │ │ │ │ - * 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. │ │ │ │ + * evt - {Event} The browser event. │ │ │ │ */ │ │ │ │ - getControlsByName: function(match) { │ │ │ │ - return this.getControlsBy("name", match); │ │ │ │ + setEvent: function(evt) { │ │ │ │ + this.evt = evt; │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: destroy │ │ │ │ + * Deconstruct the handler. │ │ │ │ */ │ │ │ │ - getControlsByClass: function(match) { │ │ │ │ - return this.getControlsBy("CLASS_NAME", match); │ │ │ │ + destroy: function() { │ │ │ │ + // unregister event listeners │ │ │ │ + this.deactivate(); │ │ │ │ + // eliminate circular references │ │ │ │ + this.control = this.map = null; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Panel" │ │ │ │ + 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/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 │ │ │ │ @@ -19487,8422 +18768,9211 @@ │ │ │ │ getVertices: function(nodes) { │ │ │ │ return [this]; │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Geometry.Point" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Geolocate.js │ │ │ │ + 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/Control.js │ │ │ │ + * @requires OpenLayers/Handler.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. │ │ │ │ - * │ │ │ │ + * 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.Control> │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.Geolocate = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: point │ │ │ │ + * {<OpenLayers.Feature.Vector>} The currently drawn point │ │ │ │ */ │ │ │ │ + point: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: geolocation │ │ │ │ - * {Object} The geolocation engine, as a property to be possibly mocked. │ │ │ │ - * This is set lazily to avoid a memory leak in IE9. │ │ │ │ + * Property: layer │ │ │ │ + * {<OpenLayers.Layer.Vector>} The temporary drawing layer │ │ │ │ */ │ │ │ │ - geolocation: null, │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: available │ │ │ │ - * {Boolean} The navigator.geolocation object is available. │ │ │ │ + * APIProperty: multi │ │ │ │ + * {Boolean} Cast features to multi-part geometries before passing to the │ │ │ │ + * layer. Default is false. │ │ │ │ */ │ │ │ │ - available: ('geolocation' in navigator), │ │ │ │ + multi: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: bind │ │ │ │ - * {Boolean} If true, map center will be set on location update. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - bind: true, │ │ │ │ + citeCompliant: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: watch │ │ │ │ - * {Boolean} If true, position will be update regularly. │ │ │ │ + * Property: mouseDown │ │ │ │ + * {Boolean} The mouse is down │ │ │ │ */ │ │ │ │ - watch: false, │ │ │ │ + mouseDown: 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. │ │ │ │ + * Property: stoppedDown │ │ │ │ + * {Boolean} Indicate whether the last mousedown stopped the event │ │ │ │ + * propagation. │ │ │ │ */ │ │ │ │ - geolocationOptions: null, │ │ │ │ + stoppedDown: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.Geolocate │ │ │ │ - * Create a new control to deal with browser geolocation API │ │ │ │ - * │ │ │ │ + * Property: lastDown │ │ │ │ + * {<OpenLayers.Pixel>} Location of the last mouse down │ │ │ │ */ │ │ │ │ + lastDown: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroy │ │ │ │ + * Property: lastUp │ │ │ │ + * {<OpenLayers.Pixel>} │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + lastUp: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ - * Activates the control. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The control was effectively activated. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + if (!(options && options.layerOptions && options.layerOptions.styleMap)) { │ │ │ │ + this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {}); │ │ │ │ } │ │ │ │ - return false; │ │ │ │ + │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Deactivates the control. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The control was effectively deactivated. │ │ │ │ + * APIMethod: activate │ │ │ │ + * turn on the handler │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - if (this.active && this.watchId !== null) { │ │ │ │ - this.geolocation.clearWatch(this.watchId); │ │ │ │ + activate: function() { │ │ │ │ + if (!OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + return false; │ │ │ │ } │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply( │ │ │ │ - this, arguments │ │ │ │ - ); │ │ │ │ + // 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: geolocate │ │ │ │ - * Activates the control. │ │ │ │ + * Method: createFeature │ │ │ │ + * Add temporary features │ │ │ │ * │ │ │ │ + * Parameters: │ │ │ │ + * pixel - {<OpenLayers.Pixel>} A pixel location on the map. │ │ │ │ */ │ │ │ │ - geolocate: function(position) { │ │ │ │ - var center = new OpenLayers.LonLat( │ │ │ │ - position.coords.longitude, │ │ │ │ - position.coords.latitude │ │ │ │ - ).transform( │ │ │ │ - new OpenLayers.Projection("EPSG:4326"), │ │ │ │ - this.map.getProjectionObject() │ │ │ │ + createFeature: function(pixel) { │ │ │ │ + var lonlat = this.layer.getLonLatFromViewPortPx(pixel); │ │ │ │ + var geometry = new OpenLayers.Geometry.Point( │ │ │ │ + lonlat.lon, lonlat.lat │ │ │ │ ); │ │ │ │ - if (this.bind) { │ │ │ │ - this.map.setCenter(center); │ │ │ │ - } │ │ │ │ - this.events.triggerEvent("locationupdated", { │ │ │ │ - position: position, │ │ │ │ - point: new OpenLayers.Geometry.Point( │ │ │ │ - center.lon, center.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: getCurrentLocation │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Returns true if a event will be fired (successfull │ │ │ │ - * registration) │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * turn off the handler │ │ │ │ */ │ │ │ │ - getCurrentLocation: function() { │ │ │ │ - if (!this.active || this.watch) { │ │ │ │ + deactivate: function() { │ │ │ │ + if (!OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ return false; │ │ │ │ } │ │ │ │ - this.geolocation.getCurrentPosition( │ │ │ │ - OpenLayers.Function.bind(this.geolocate, this), │ │ │ │ - OpenLayers.Function.bind(this.failure, this), │ │ │ │ - this.geolocationOptions │ │ │ │ - ); │ │ │ │ + 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: failure │ │ │ │ - * method called on browser's geolocation failure │ │ │ │ + * Method: destroyFeature │ │ │ │ + * Destroy the temporary geometries │ │ │ │ * │ │ │ │ + * Parameters: │ │ │ │ + * force - {Boolean} Destroy even if persist is true. │ │ │ │ */ │ │ │ │ - failure: function(error) { │ │ │ │ - this.events.triggerEvent("locationfailed", { │ │ │ │ - error: error │ │ │ │ - }); │ │ │ │ + destroyFeature: function(force) { │ │ │ │ + if (this.layer && (force || !this.persist)) { │ │ │ │ + this.layer.destroyFeatures(); │ │ │ │ + } │ │ │ │ + this.point = null; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Geolocate" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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>} │ │ │ │ + * Method: destroyPersistedFeature │ │ │ │ + * Destroy the persisted feature. │ │ │ │ */ │ │ │ │ - layer: null, │ │ │ │ + destroyPersistedFeature: function() { │ │ │ │ + var layer = this.layer; │ │ │ │ + if (layer && layer.features.length > 1) { │ │ │ │ + this.layer.features[0].destroy(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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) │ │ │ │ + * Method: finalize │ │ │ │ + * Finish the geometry and call the "done" callback. │ │ │ │ * │ │ │ │ - * Supported event types (in addition to those from <OpenLayers.Control.events>): │ │ │ │ - * featureadded - Triggered when a feature is added │ │ │ │ + * 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); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: multi │ │ │ │ - * {Boolean} Cast features to multi-part geometries before passing to the │ │ │ │ - * layer. Default is false. │ │ │ │ + * APIMethod: cancel │ │ │ │ + * Finish the geometry and call the "cancel" callback. │ │ │ │ */ │ │ │ │ - multi: false, │ │ │ │ + cancel: function() { │ │ │ │ + this.finalize(true); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: featureAdded │ │ │ │ - * {Function} Called after each feature is added │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - featureAdded: function() {}, │ │ │ │ + click: function(evt) { │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ + return false; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: handlerOptions │ │ │ │ - * {Object} Used to set non-default properties on the control's handler │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.DrawFeature │ │ │ │ - * │ │ │ │ + * Method: modifyFeature │ │ │ │ + * Modify the existing geometry given a pixel location. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} │ │ │ │ - * handler - {<OpenLayers.Handler>} │ │ │ │ - * options - {Object} │ │ │ │ + * pixel - {<OpenLayers.Pixel>} A pixel location on the map. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - ); │ │ │ │ + modifyFeature: function(pixel) { │ │ │ │ + if (!this.point) { │ │ │ │ + this.createFeature(pixel); │ │ │ │ } │ │ │ │ - this.handler = new handler(this, this.callbacks, this.handlerOptions); │ │ │ │ + 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(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 │ │ │ │ - }); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: insertXY │ │ │ │ - * Insert a point in the current sketch given x & y coordinates. │ │ │ │ + * 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: │ │ │ │ - * x - {Number} The x-coordinate of the point. │ │ │ │ - * y - {Number} The y-coordinate of the point. │ │ │ │ + * evt - {Event} The browser event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ */ │ │ │ │ - insertXY: function(x, y) { │ │ │ │ - if (this.handler && this.handler.line) { │ │ │ │ - this.handler.insertXY(x, y); │ │ │ │ - } │ │ │ │ + mousedown: function(evt) { │ │ │ │ + return this.down(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: insertDeltaXY │ │ │ │ - * Insert a point given offsets from the previously inserted point. │ │ │ │ + * 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: │ │ │ │ - * dx - {Number} The x-coordinate offset of the point. │ │ │ │ - * dy - {Number} The y-coordinate offset of the point. │ │ │ │ + * evt - {Event} The browser event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ */ │ │ │ │ - insertDeltaXY: function(dx, dy) { │ │ │ │ - if (this.handler && this.handler.line) { │ │ │ │ - this.handler.insertDeltaXY(dx, dy); │ │ │ │ - } │ │ │ │ + mousemove: function(evt) { │ │ │ │ + return this.move(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: insertDirectionLength │ │ │ │ - * Insert a point in the current sketch given a direction and a length. │ │ │ │ + * 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: │ │ │ │ - * direction - {Number} Degrees clockwise from the positive x-axis. │ │ │ │ - * length - {Number} Distance from the previously drawn point. │ │ │ │ + * evt - {Event} The browser event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ */ │ │ │ │ - insertDirectionLength: function(direction, length) { │ │ │ │ - if (this.handler && this.handler.line) { │ │ │ │ - this.handler.insertDirectionLength(direction, length); │ │ │ │ - } │ │ │ │ + mouseup: function(evt) { │ │ │ │ + return this.up(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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: │ │ │ │ - * deflection - {Number} Degrees clockwise from the previous segment. │ │ │ │ - * length - {Number} Distance from the previously drawn point. │ │ │ │ + * evt - {Event} The browser event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ */ │ │ │ │ - insertDeflectionLength: function(deflection, length) { │ │ │ │ - if (this.handler && this.handler.line) { │ │ │ │ - this.handler.insertDeflectionLength(deflection, length); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: undo │ │ │ │ - * Remove the most recently added point in the current sketch geometry. │ │ │ │ + * 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} An edit was undone. │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ */ │ │ │ │ - undo: function() { │ │ │ │ - return this.handler.undo && this.handler.undo(); │ │ │ │ + move: function(evt) { │ │ │ │ + if (!this.touch // no point displayed until up on touch devices │ │ │ │ + && │ │ │ │ + (!this.mouseDown || this.stoppedDown)) { │ │ │ │ + this.modifyFeature(evt.xy); │ │ │ │ + } │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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} An edit was redone. │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ */ │ │ │ │ - redo: function() { │ │ │ │ - return this.handler.redo && this.handler.redo(); │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - finishSketch: function() { │ │ │ │ - this.handler.finishGeometry(); │ │ │ │ + mouseout: function(evt) { │ │ │ │ + if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ + this.stoppedDown = this.stopDown; │ │ │ │ + this.mouseDown = false; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: cancel │ │ │ │ - * Cancel the current sketch. This removes the current sketch and keeps │ │ │ │ - * the drawing control active. │ │ │ │ + * Method: passesTolerance │ │ │ │ + * Determine whether the event is within the optional pixel tolerance. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The event is within the pixel tolerance (if specified). │ │ │ │ */ │ │ │ │ - cancel: function() { │ │ │ │ - this.handler.cancel(); │ │ │ │ + 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.Control.DrawFeature" │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Point" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Zoom.js │ │ │ │ + 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/Control.js │ │ │ │ - * @requires OpenLayers/Events/buttonclick.js │ │ │ │ + * @requires OpenLayers/Geometry.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Zoom │ │ │ │ - * The Zoom control is a pair of +/- links for zooming in and out. │ │ │ │ + * 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.Control> │ │ │ │ + * - <OpenLayers.Geometry> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.Zoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Geometry.Collection = OpenLayers.Class(OpenLayers.Geometry, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: zoomInText │ │ │ │ - * {String} │ │ │ │ - * Text for zoom-in link. Default is "+". │ │ │ │ + * APIProperty: components │ │ │ │ + * {Array(<OpenLayers.Geometry>)} The component parts of this geometry │ │ │ │ */ │ │ │ │ - zoomInText: "+", │ │ │ │ + components: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - zoomInId: "olZoomInLink", │ │ │ │ + componentTypes: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: zoomOutText │ │ │ │ - * {String} │ │ │ │ - * Text for zoom-out link. Default is "\u2212". │ │ │ │ + * Constructor: OpenLayers.Geometry.Collection │ │ │ │ + * Creates a Geometry Collection -- a list of geoms. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * components - {Array(<OpenLayers.Geometry>)} Optional array of geometries │ │ │ │ + * │ │ │ │ */ │ │ │ │ - zoomOutText: "\u2212", │ │ │ │ + initialize: function(components) { │ │ │ │ + OpenLayers.Geometry.prototype.initialize.apply(this, arguments); │ │ │ │ + this.components = []; │ │ │ │ + if (components != null) { │ │ │ │ + this.addComponents(components); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Destroy this geometry. │ │ │ │ */ │ │ │ │ - zoomOutId: "olZoomOutLink", │ │ │ │ + destroy: function() { │ │ │ │ + this.components.length = 0; │ │ │ │ + this.components = null; │ │ │ │ + OpenLayers.Geometry.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: draw │ │ │ │ + * APIMethod: clone │ │ │ │ + * Clone this geometry. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} A reference to the DOMElement containing the zoom links. │ │ │ │ + * {<OpenLayers.Geometry.Collection>} An exact clone of this collection │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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()); │ │ │ │ } │ │ │ │ - eventsInstance.register("buttonclick", this, this.onZoomClick); │ │ │ │ │ │ │ │ - this.zoomInLink = zoomIn; │ │ │ │ - this.zoomOutLink = zoomOut; │ │ │ │ - return div; │ │ │ │ + // catch any randomly tagged-on properties │ │ │ │ + OpenLayers.Util.applyDefaults(geometry, this); │ │ │ │ + │ │ │ │ + return geometry; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getOrCreateLinks │ │ │ │ + * Method: getComponentsString │ │ │ │ + * Get a string representing the components for this collection │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * el - {DOMElement} │ │ │ │ - * │ │ │ │ - * Return: │ │ │ │ - * {Object} Object with zoomIn and zoomOut properties referencing links. │ │ │ │ + * Returns: │ │ │ │ + * {String} A string representation of the components of this geometry │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + getComponentsString: function() { │ │ │ │ + var strings = []; │ │ │ │ + for (var i = 0, len = this.components.length; i < len; i++) { │ │ │ │ + strings.push(this.components[i].toShortString()); │ │ │ │ } │ │ │ │ - OpenLayers.Element.addClass(zoomOut, "olButton"); │ │ │ │ - return { │ │ │ │ - zoomIn: zoomIn, │ │ │ │ - zoomOut: zoomOut │ │ │ │ - }; │ │ │ │ + return strings.join(","); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onZoomClick │ │ │ │ - * Called when zoomin/out link is clicked. │ │ │ │ + * APIMethod: calculateBounds │ │ │ │ + * Recalculate the bounds by iterating through the components and │ │ │ │ + * calling calling extendBounds() on each item. │ │ │ │ */ │ │ │ │ - onZoomClick: function(evt) { │ │ │ │ - var button = evt.buttonElement; │ │ │ │ - if (button === this.zoomInLink) { │ │ │ │ - this.map.zoomIn(); │ │ │ │ - } else if (button === this.zoomOutLink) { │ │ │ │ - this.map.zoomOut(); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - * Clean up. │ │ │ │ + /** │ │ │ │ + * APIMethod: addComponents │ │ │ │ + * Add components to this geometry. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * components - {Array(<OpenLayers.Geometry>)} An array of geometries to add │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.unregister("buttonclick", this, this.onZoomClick); │ │ │ │ + addComponents: function(components) { │ │ │ │ + if (!(OpenLayers.Util.isArray(components))) { │ │ │ │ + components = [components]; │ │ │ │ + } │ │ │ │ + for (var i = 0, len = components.length; i < len; i++) { │ │ │ │ + this.addComponent(components[i]); │ │ │ │ } │ │ │ │ - delete this.zoomInLink; │ │ │ │ - delete this.zoomOutLink; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Zoom" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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} │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - id: null, │ │ │ │ + addComponent: function(component, index) { │ │ │ │ + var added = false; │ │ │ │ + if (component) { │ │ │ │ + if (this.componentTypes == null || │ │ │ │ + (OpenLayers.Util.indexOf(this.componentTypes, │ │ │ │ + component.CLASS_NAME) > -1)) { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: map │ │ │ │ - * {<OpenLayers.Map>} │ │ │ │ + * APIMethod: removeComponents │ │ │ │ + * Remove components from this geometry. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * components - {Array(<OpenLayers.Geometry>)} The components to be removed │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} A component was removed. │ │ │ │ */ │ │ │ │ - map: null, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: removeComponent │ │ │ │ + * Remove a component from this geometry. │ │ │ │ * │ │ │ │ - * Example: │ │ │ │ - * (code) │ │ │ │ - * // handler only responds if the Shift key is down │ │ │ │ - * handler.keyMask = OpenLayers.Handler.MOD_SHIFT; │ │ │ │ + * Parameters: │ │ │ │ + * component - {<OpenLayers.Geometry>} │ │ │ │ * │ │ │ │ - * // handler only responds if Ctrl-Shift is down │ │ │ │ - * handler.keyMask = OpenLayers.Handler.MOD_SHIFT | │ │ │ │ - * OpenLayers.Handler.MOD_CTRL; │ │ │ │ - * (end) │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The component was removed. │ │ │ │ */ │ │ │ │ - keyMask: null, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: active │ │ │ │ - * {Boolean} │ │ │ │ + * APIMethod: getLength │ │ │ │ + * Calculate the length of this geometry │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Float} The length of the geometry │ │ │ │ */ │ │ │ │ - active: false, │ │ │ │ + getLength: function() { │ │ │ │ + var length = 0.0; │ │ │ │ + for (var i = 0, len = this.components.length; i < len; i++) { │ │ │ │ + length += this.components[i].getLength(); │ │ │ │ + } │ │ │ │ + return length; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - evt: null, │ │ │ │ + getArea: function() { │ │ │ │ + var area = 0.0; │ │ │ │ + for (var i = 0, len = this.components.length; i < len; i++) { │ │ │ │ + area += this.components[i].getArea(); │ │ │ │ + } │ │ │ │ + return area; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - touch: false, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Handler │ │ │ │ - * Construct a handler. │ │ │ │ + * APIMethod: getCentroid │ │ │ │ + * │ │ │ │ + * Compute the centroid for this geometry collection. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - this.control = control; │ │ │ │ - this.callbacks = callbacks; │ │ │ │ + getCentroid: function(weighted) { │ │ │ │ + if (!weighted) { │ │ │ │ + return this.components.length && this.components[0].getCentroid(); │ │ │ │ + } │ │ │ │ + var len = this.components.length; │ │ │ │ + if (!len) { │ │ │ │ + return false; │ │ │ │ + } │ │ │ │ │ │ │ │ - var map = this.map || control.map; │ │ │ │ - if (map) { │ │ │ │ - this.setMap(map); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ + 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); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setMap │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - this.map = map; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The keyMask matches the keys down on an event. │ │ │ │ + * Parameters: │ │ │ │ + * x - {Float} Distance to move geometry in positive x direction. │ │ │ │ + * y - {Float} Distance to move geometry in positive y direction. │ │ │ │ */ │ │ │ │ - checkModifiers: function(evt) { │ │ │ │ - if (this.keyMask == null) { │ │ │ │ - return true; │ │ │ │ + move: function(x, y) { │ │ │ │ + for (var i = 0, len = this.components.length; i < len; i++) { │ │ │ │ + this.components[i].move(x, y); │ │ │ │ } │ │ │ │ - /* 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. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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]]); │ │ │ │ - } │ │ │ │ + rotate: function(angle, origin) { │ │ │ │ + for (var i = 0, len = this.components.length; i < len; ++i) { │ │ │ │ + this.components[i].rotate(angle, origin); │ │ │ │ } │ │ │ │ - this.active = true; │ │ │ │ - return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Turn off the handler. Returns false if the handler was already inactive. │ │ │ │ + * 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: │ │ │ │ - * {Boolean} The handler was deactivated. │ │ │ │ + * {<OpenLayers.Geometry>} - The current geometry. │ │ │ │ */ │ │ │ │ - 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]]); │ │ │ │ - } │ │ │ │ + resize: function(scale, origin, ratio) { │ │ │ │ + for (var i = 0; i < this.components.length; ++i) { │ │ │ │ + this.components[i].resize(scale, origin, ratio); │ │ │ │ } │ │ │ │ - this.touch = false; │ │ │ │ - this.active = false; │ │ │ │ - return true; │ │ │ │ + return this; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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]]); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: callback │ │ │ │ - * Trigger the control's named callback with the given arguments │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * APIMethod: equals │ │ │ │ + * Determine whether another geometry is equivalent to this one. Geometries │ │ │ │ + * are considered equivalent if all components have the same coordinates. │ │ │ │ + * │ │ │ │ * 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). │ │ │ │ + * geometry - {<OpenLayers.Geometry>} The geometry to test. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The supplied geometry is equivalent to this geometry. │ │ │ │ */ │ │ │ │ - callback: function(name, args) { │ │ │ │ - if (name && this.callbacks[name]) { │ │ │ │ - this.callbacks[name].apply(this.control, args); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: register │ │ │ │ - * register an event on the map │ │ │ │ + * APIMethod: transform │ │ │ │ + * Reproject the components geometry from source to dest. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * source - {<OpenLayers.Projection>} │ │ │ │ + * dest - {<OpenLayers.Projection>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Geometry>} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: unregister │ │ │ │ - * unregister an event from the map │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - unregister: function(name, method) { │ │ │ │ - this.map.events.unregister(name, this, method); │ │ │ │ - this.map.events.unregister(name, this, this.setEvent); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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). │ │ │ │ + * APIMethod: getVertices │ │ │ │ + * Return a list of all points in this geometry. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} The browser event. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - setEvent: function(evt) { │ │ │ │ - this.evt = evt; │ │ │ │ - return true; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - * Deconstruct the handler. │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - // unregister event listeners │ │ │ │ - this.deactivate(); │ │ │ │ - // eliminate circular references │ │ │ │ - this.control = this.map = null; │ │ │ │ - }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler" │ │ │ │ + CLASS_NAME: "OpenLayers.Geometry.Collection" │ │ │ │ }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Geometry/MultiPoint.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Handler.MOD_NONE │ │ │ │ - * If set as the <keyMask>, <checkModifiers> returns false if any key is down. │ │ │ │ - */ │ │ │ │ -OpenLayers.Handler.MOD_NONE = 0; │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Handler.MOD_SHIFT │ │ │ │ - * If set as the <keyMask>, <checkModifiers> returns false if Shift is down. │ │ │ │ + * @requires OpenLayers/Geometry/Collection.js │ │ │ │ + * @requires OpenLayers/Geometry/Point.js │ │ │ │ */ │ │ │ │ -OpenLayers.Handler.MOD_SHIFT = 1; │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Handler.MOD_CTRL │ │ │ │ - * If set as the <keyMask>, <checkModifiers> returns false if Ctrl is down. │ │ │ │ + * 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.Handler.MOD_CTRL = 2; │ │ │ │ +OpenLayers.Geometry.MultiPoint = OpenLayers.Class( │ │ │ │ + OpenLayers.Geometry.Collection, { │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Handler.MOD_ALT │ │ │ │ - * If set as the <keyMask>, <checkModifiers> returns false if Alt is down. │ │ │ │ - */ │ │ │ │ -OpenLayers.Handler.MOD_ALT = 4; │ │ │ │ + /** │ │ │ │ + * 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"], │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Handler.MOD_META │ │ │ │ - * If set as the <keyMask>, <checkModifiers> returns false if Cmd is down. │ │ │ │ - */ │ │ │ │ -OpenLayers.Handler.MOD_META = 8; │ │ │ │ + /** │ │ │ │ + * 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/Handler/Drag.js │ │ │ │ + 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/Handler.js │ │ │ │ + * @requires OpenLayers/Geometry/MultiPoint.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> │ │ │ │ + * 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.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ +OpenLayers.Geometry.Curve = OpenLayers.Class(OpenLayers.Geometry.MultiPoint, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - started: false, │ │ │ │ + componentTypes: ["OpenLayers.Geometry.Point"], │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: stopDown │ │ │ │ - * {Boolean} Stop propagation of mousedown events from getting to listeners │ │ │ │ - * on the same element. Default is true. │ │ │ │ + * Constructor: OpenLayers.Geometry.Curve │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * point - {Array(<OpenLayers.Geometry.Point>)} │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + * APIMethod: getLength │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * {Float} The length of the curve │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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]); │ │ │ │ } │ │ │ │ - document.onselectstart = OpenLayers.Function.False; │ │ │ │ - │ │ │ │ - propagate = !this.stopDown; │ │ │ │ - } else { │ │ │ │ - this.started = false; │ │ │ │ - this.start = null; │ │ │ │ - this.last = null; │ │ │ │ } │ │ │ │ - return propagate; │ │ │ │ + return length; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: dragmove │ │ │ │ - * This private method is factorized from mousemove and touchmove methods │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} The event │ │ │ │ + * 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: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * {Float} The appoximate geodesic length of the geometry in meters. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - 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]); │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ } │ │ │ │ - document.onselectstart = this.oldOnselectstart; │ │ │ │ } │ │ │ │ - return true; │ │ │ │ + // convert to m │ │ │ │ + return length * 1000; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * The four methods below (down, move, up, and out) are used by subclasses │ │ │ │ - * to do their own processing related to these mouse events. │ │ │ │ - */ │ │ │ │ + CLASS_NAME: "OpenLayers.Geometry.Curve" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Geometry/LineString.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ +/* 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, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: move │ │ │ │ - * This method is called during the handling of the mouse move event. │ │ │ │ - * Subclasses can do their own processing here. │ │ │ │ + * Constructor: OpenLayers.Geometry.LineString │ │ │ │ + * Create a new LineString geometry │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} The mouse move event │ │ │ │ + * points - {Array(<OpenLayers.Geometry.Point>)} An array of points used to │ │ │ │ + * generate the linestring │ │ │ │ * │ │ │ │ */ │ │ │ │ - move: function(evt) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: up │ │ │ │ - * This method is called during the handling of the mouse up event. │ │ │ │ - * Subclasses can do their own processing here. │ │ │ │ + * 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: │ │ │ │ - * 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: │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} The point to be removed │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: mousedown │ │ │ │ - * Handle mousedown events │ │ │ │ + * 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: │ │ │ │ - * evt - {Event} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * {Boolean} The input geometry intersects this geometry. │ │ │ │ */ │ │ │ │ - mousedown: function(evt) { │ │ │ │ - return this.dragstart(evt); │ │ │ │ + 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: touchstart │ │ │ │ - * Handle touchstart events │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * Method: getSortedSegments │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - return this.dragstart(evt); │ │ │ │ + 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: mousemove │ │ │ │ - * Handle mousemove events │ │ │ │ + * Method: splitWithSegment │ │ │ │ + * Split this geometry with the given segment. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * 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: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * {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). │ │ │ │ */ │ │ │ │ - mousemove: function(evt) { │ │ │ │ - return this.dragmove(evt); │ │ │ │ + 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: touchmove │ │ │ │ - * Handle touchmove events │ │ │ │ - * │ │ │ │ + * Method: split │ │ │ │ + * Use this geometry (the source) to attempt to split a target geometry. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * 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: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ - */ │ │ │ │ - touchmove: function(evt) { │ │ │ │ - return this.dragmove(evt); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: removeTimeout │ │ │ │ - * Private. Called by mousemove() to remove the drag timeout. │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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: mouseup │ │ │ │ - * Handle mouseup events │ │ │ │ + * Method: splitWith │ │ │ │ + * Split this geometry (the target) with the given geometry (the source). │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * 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: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - mouseup: function(evt) { │ │ │ │ - return this.dragend(evt); │ │ │ │ + splitWith: function(geometry, options) { │ │ │ │ + return geometry.split(this, options); │ │ │ │ + │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: touchend │ │ │ │ - * Handle touchend events │ │ │ │ + * APIMethod: getVertices │ │ │ │ + * Return a list of all points in this geometry. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * 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: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * {Array} A list of all vertices in the geometry. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: mouseout │ │ │ │ - * Handle mouseout events │ │ │ │ + * APIMethod: distanceTo │ │ │ │ + * Calculate the closest distance between two geometries (on the x-y plane). │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * 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: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - mouseout: function(evt) { │ │ │ │ - if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ - if (this.documentDrag === true) { │ │ │ │ - this.addDocumentEvents(); │ │ │ │ + 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 { │ │ │ │ - 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]); │ │ │ │ + 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 (document.onselectstart) { │ │ │ │ - document.onselectstart = this.oldOnselectstart; │ │ │ │ + } │ │ │ │ + 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 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; │ │ │ │ + return best; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + * APIMethod: simplify │ │ │ │ + * This function will return a simplified LineString. │ │ │ │ + * Simplification is based on the Douglas-Peucker algorithm. │ │ │ │ + * │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * tolerance - {number} threshhold for simplification in map units │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {OpenLayers.Geometry.LineString} the simplified LineString │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - ====================================================================== */ │ │ │ │ + simplify: function(tolerance) { │ │ │ │ + if (this && this !== null) { │ │ │ │ + var points = this.getVertices(); │ │ │ │ + if (points.length < 3) { │ │ │ │ + return this; │ │ │ │ + } │ │ │ │ │ │ │ │ -/* 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 compareNumbers = function(a, b) { │ │ │ │ + return (a - b); │ │ │ │ + }; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Handler.js │ │ │ │ - * @requires OpenLayers/Events.js │ │ │ │ - */ │ │ │ │ + /** │ │ │ │ + * Private function doing the Douglas-Peucker reduction │ │ │ │ + */ │ │ │ │ + var douglasPeuckerReduction = function(points, firstPoint, lastPoint, tolerance) { │ │ │ │ + var maxDistance = 0; │ │ │ │ + var indexFarthest = 0; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * 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, { │ │ │ │ + for (var index = firstPoint, distance; index < lastPoint; index++) { │ │ │ │ + distance = perpendicularDistance(points[firstPoint], points[lastPoint], points[index]); │ │ │ │ + if (distance > maxDistance) { │ │ │ │ + maxDistance = distance; │ │ │ │ + indexFarthest = index; │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - /* http://www.quirksmode.org/js/keys.html explains key x-browser │ │ │ │ - key handling quirks in pretty nice detail */ │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + }; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: KEY_EVENTS │ │ │ │ - * keydown, keypress, keyup │ │ │ │ - */ │ │ │ │ - KEY_EVENTS: ["keydown", "keyup"], │ │ │ │ + /** │ │ │ │ + * 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 │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: eventListener │ │ │ │ - * {Function} │ │ │ │ - */ │ │ │ │ - eventListener: null, │ │ │ │ + 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; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: observeElement │ │ │ │ - * {DOMElement|String} The DOM element on which we listen for │ │ │ │ - * key events. Default to the document. │ │ │ │ - */ │ │ │ │ - observeElement: null, │ │ │ │ + return height; │ │ │ │ + }; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ + var firstPoint = 0; │ │ │ │ + var lastPoint = points.length - 1; │ │ │ │ + var pointIndexsToKeep = []; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - this.eventListener = null; │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + //Add the first and last index to the keepers │ │ │ │ + pointIndexsToKeep.push(firstPoint); │ │ │ │ + pointIndexsToKeep.push(lastPoint); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + //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); │ │ │ │ } │ │ │ │ - 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); │ │ │ │ + douglasPeuckerReduction(points, firstPoint, lastPoint, tolerance); │ │ │ │ + var returnPoints = []; │ │ │ │ + pointIndexsToKeep.sort(compareNumbers); │ │ │ │ + for (var index = 0; index < pointIndexsToKeep.length; index++) { │ │ │ │ + returnPoints.push(points[pointIndexsToKeep[index]]); │ │ │ │ } │ │ │ │ - deactivated = true; │ │ │ │ - } │ │ │ │ - return deactivated; │ │ │ │ - }, │ │ │ │ + return new OpenLayers.Geometry.LineString(returnPoints); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: handleKeyEvent │ │ │ │ - */ │ │ │ │ - handleKeyEvent: function(evt) { │ │ │ │ - if (this.checkModifiers(evt)) { │ │ │ │ - this.callback(evt.type, [evt]); │ │ │ │ + } else { │ │ │ │ + return this; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Keyboard" │ │ │ │ + CLASS_NAME: "OpenLayers.Geometry.LineString" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/ModifyFeature.js │ │ │ │ + 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/Control.js │ │ │ │ - * @requires OpenLayers/Handler/Drag.js │ │ │ │ - * @requires OpenLayers/Handler/Keyboard.js │ │ │ │ + * @requires OpenLayers/Handler/Point.js │ │ │ │ + * @requires OpenLayers/Geometry/Point.js │ │ │ │ + * @requires OpenLayers/Geometry/LineString.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. │ │ │ │ + * 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.Control> │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Handler.Point> │ │ │ │ */ │ │ │ │ -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, │ │ │ │ +OpenLayers.Handler.Path = OpenLayers.Class(OpenLayers.Handler.Point, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: vertex │ │ │ │ - * {<OpenLayers.Feature.Vector>} Vertex currently being modified. │ │ │ │ + * Property: line │ │ │ │ + * {<OpenLayers.Feature.Vector>} │ │ │ │ */ │ │ │ │ - vertex: null, │ │ │ │ + line: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: vertices │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} Verticies currently available │ │ │ │ - * for dragging. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - vertices: null, │ │ │ │ + maxVertices: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: virtualVertices │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} Virtual vertices in the middle │ │ │ │ - * of each edge. │ │ │ │ + * Property: doubleTouchTolerance │ │ │ │ + * {Number} Maximum number of pixels between two touches for │ │ │ │ + * the gesture to be considered a "finalize feature" action. │ │ │ │ + * Default is 20. │ │ │ │ */ │ │ │ │ - virtualVertices: null, │ │ │ │ + doubleTouchTolerance: 20, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: handlers │ │ │ │ - * {Object} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - handlers: null, │ │ │ │ + freehand: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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'. │ │ │ │ */ │ │ │ │ - deleteCodes: null, │ │ │ │ + freehandToggle: 'shiftKey', │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: virtualStyle │ │ │ │ - * {Object} A symbolizer to be used for virtual vertices. │ │ │ │ + * Property: timerId │ │ │ │ + * {Integer} The timer used to test the double touch. │ │ │ │ */ │ │ │ │ - virtualStyle: null, │ │ │ │ + timerId: 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. │ │ │ │ + * Property: redoStack │ │ │ │ + * {Array} Stack containing points removed with <undo>. │ │ │ │ */ │ │ │ │ - vertexRenderIntent: null, │ │ │ │ + redoStack: 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) │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - mode: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: createVertices │ │ │ │ - * {Boolean} Create new vertices by dragging the virtual vertices │ │ │ │ - * in the middle of each edge. Default is true. │ │ │ │ + * Method: createFeature │ │ │ │ + * Add temporary geometries │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new │ │ │ │ + * feature. │ │ │ │ */ │ │ │ │ - createVertices: true, │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: modified │ │ │ │ - * {Boolean} The currently selected feature has been modified. │ │ │ │ + * Method: destroyFeature │ │ │ │ + * Destroy temporary geometries │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * force - {Boolean} Destroy even if persist is true. │ │ │ │ */ │ │ │ │ - modified: false, │ │ │ │ + destroyFeature: function(force) { │ │ │ │ + OpenLayers.Handler.Point.prototype.destroyFeature.call( │ │ │ │ + this, force); │ │ │ │ + this.line = null; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: radiusHandle │ │ │ │ - * {<OpenLayers.Feature.Vector>} A handle for rotating/resizing a feature. │ │ │ │ + * Method: destroyPersistedFeature │ │ │ │ + * Destroy the persisted feature. │ │ │ │ */ │ │ │ │ - radiusHandle: null, │ │ │ │ + destroyPersistedFeature: function() { │ │ │ │ + var layer = this.layer; │ │ │ │ + if (layer && layer.features.length > 2) { │ │ │ │ + this.layer.features[0].destroy(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: dragHandle │ │ │ │ - * {<OpenLayers.Feature.Vector>} A handle for dragging a feature. │ │ │ │ + * Method: removePoint │ │ │ │ + * Destroy the temporary point. │ │ │ │ */ │ │ │ │ - dragHandle: null, │ │ │ │ + removePoint: function() { │ │ │ │ + if (this.point) { │ │ │ │ + this.layer.removeFeatures([this.point]); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: onModificationStart │ │ │ │ - * {Function} *Deprecated*. Register for "beforefeaturemodified" instead. │ │ │ │ - * The "beforefeaturemodified" event is triggered on the layer before │ │ │ │ - * any modification begins. │ │ │ │ + * Method: addPoint │ │ │ │ + * Add point to geometry. Send the point index to override │ │ │ │ + * the behavior of LinearRing that disregards adding duplicate points. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Parameters: │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The pixel location for the new point. │ │ │ │ */ │ │ │ │ - onModificationStart: function() {}, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: onModification │ │ │ │ - * {Function} *Deprecated*. Register for "featuremodified" instead. │ │ │ │ - * The "featuremodified" event is triggered on the layer with each │ │ │ │ - * feature modification. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Optional function to be called when a feature has been │ │ │ │ - * modified. The function should expect to be called with a feature. │ │ │ │ + * Parameters: │ │ │ │ + * x - {Number} The x-coordinate of the point. │ │ │ │ + * y - {Number} The y-coordinate of the point. │ │ │ │ */ │ │ │ │ - onModification: function() {}, │ │ │ │ + insertXY: function(x, y) { │ │ │ │ + this.line.geometry.addComponent( │ │ │ │ + new OpenLayers.Geometry.Point(x, y), │ │ │ │ + this.getCurrentPointIndex() │ │ │ │ + ); │ │ │ │ + this.drawFeature(); │ │ │ │ + delete this.redoStack; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: onModificationEnd │ │ │ │ - * {Function} *Deprecated*. Register for "afterfeaturemodified" instead. │ │ │ │ - * The "afterfeaturemodified" event is triggered on the layer after │ │ │ │ - * a feature has been modified. │ │ │ │ + * Method: insertDeltaXY │ │ │ │ + * Insert a point given offsets from the previously inserted point. │ │ │ │ * │ │ │ │ - * Optional function to be called when a feature is finished │ │ │ │ - * being modified. The function should expect to be called with a │ │ │ │ - * feature. │ │ │ │ + * Parameters: │ │ │ │ + * dx - {Number} The x-coordinate offset of the point. │ │ │ │ + * dy - {Number} The y-coordinate offset of the point. │ │ │ │ */ │ │ │ │ - onModificationEnd: function() {}, │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.ModifyFeature │ │ │ │ - * Create a new modify feature control. │ │ │ │ + * Method: insertDirectionLength │ │ │ │ + * Insert a point in the current sketch given a direction and a length. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * direction - {Number} Degrees clockwise from the positive x-axis. │ │ │ │ + * length - {Number} Distance from the previously drawn point. │ │ │ │ */ │ │ │ │ - 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) │ │ │ │ - }; │ │ │ │ + insertDirectionLength: function(direction, length) { │ │ │ │ + direction *= Math.PI / 180; │ │ │ │ + var dx = length * Math.cos(direction); │ │ │ │ + var dy = length * Math.sin(direction); │ │ │ │ + this.insertDeltaXY(dx, dy); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Take care of things that are not handled in superclass. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.un({ │ │ │ │ - "removelayer": this.handleMapEvents, │ │ │ │ - "changelayer": this.handleMapEvents, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ + 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 │ │ │ │ + ); │ │ │ │ } │ │ │ │ - this.layer = null; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, []); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the control. │ │ │ │ + * Method: getCurrentPointIndex │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Successfully activated the control. │ │ │ │ + * {Number} The index of the most recently drawn point. │ │ │ │ */ │ │ │ │ - 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)); │ │ │ │ + getCurrentPointIndex: function() { │ │ │ │ + return this.line.geometry.components.length - 1; │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the control. │ │ │ │ + * Method: undo │ │ │ │ + * Remove the most recently added point in the sketch geometry. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Successfully deactivated the control. │ │ │ │ + * {Boolean} A point was removed. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - deactivated = true; │ │ │ │ + if (!this.redoStack) { │ │ │ │ + this.redoStack = []; │ │ │ │ + } │ │ │ │ + this.redoStack.push(target); │ │ │ │ + this.drawFeature(); │ │ │ │ } │ │ │ │ - return deactivated; │ │ │ │ + return undone; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: beforeSelectFeature │ │ │ │ - * Called before a feature is selected. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature about to be selected. │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} A point was added. │ │ │ │ */ │ │ │ │ - beforeSelectFeature: function(feature) { │ │ │ │ - return this.layer.events.triggerEvent( │ │ │ │ - "beforefeaturemodified", { │ │ │ │ - feature: feature │ │ │ │ - } │ │ │ │ - ); │ │ │ │ + redo: function() { │ │ │ │ + var target = this.redoStack && this.redoStack.pop(); │ │ │ │ + if (target) { │ │ │ │ + this.line.geometry.addComponent(target, this.getCurrentPointIndex()); │ │ │ │ + this.drawFeature(); │ │ │ │ + } │ │ │ │ + return !!target; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: freehandMode │ │ │ │ + * Determine whether to behave in freehand mode or not. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} the selected feature. │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ + freehandMode: function(evt) { │ │ │ │ + return (this.freehandToggle && evt[this.freehandToggle]) ? │ │ │ │ + !this.freehand : this.freehand; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: unselectFeature │ │ │ │ - * Called when the select feature control unselects a feature. │ │ │ │ + * Method: modifyFeature │ │ │ │ + * Modify the existing geometry given the new point │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The unselected feature. │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The updated pixel location for the latest │ │ │ │ + * point. │ │ │ │ + * drawing - {Boolean} Indicate if we're currently drawing. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + modifyFeature: function(pixel, drawing) { │ │ │ │ + if (!this.line) { │ │ │ │ + this.createFeature(pixel); │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + 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: 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. │ │ │ │ + * Method: drawFeature │ │ │ │ + * Render geometries on the temporary layer. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + drawFeature: function() { │ │ │ │ + this.layer.drawFeature(this.line, this.style); │ │ │ │ + this.layer.drawFeature(this.point, this.style); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: dragVertex │ │ │ │ - * Called by the drag handler with each drag move of a vertex. │ │ │ │ + * Method: getSketch │ │ │ │ + * Return the sketch feature. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged. │ │ │ │ - * pixel - {<OpenLayers.Pixel>} Pixel location of the mouse event. │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Feature.Vector>} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + getSketch: function() { │ │ │ │ + return this.line; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: dragComplete │ │ │ │ - * Called by the drag handler when the feature dragging is complete. │ │ │ │ + * Method: getGeometry │ │ │ │ + * Return the sketch geometry. If <multi> is true, this will return │ │ │ │ + * a multi-part geometry. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged. │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Geometry.LineString>} │ │ │ │ */ │ │ │ │ - dragComplete: function(vertex) { │ │ │ │ - this.resetVertices(); │ │ │ │ - this.setFeatureState(); │ │ │ │ - this.onModification(this.feature); │ │ │ │ - this.layer.events.triggerEvent("featuremodified", { │ │ │ │ - feature: this.feature │ │ │ │ - }); │ │ │ │ + getGeometry: function() { │ │ │ │ + var geometry = this.line && this.line.geometry; │ │ │ │ + if (geometry && this.multi) { │ │ │ │ + geometry = new OpenLayers.Geometry.MultiLineString([geometry]); │ │ │ │ + } │ │ │ │ + return geometry; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setFeatureState │ │ │ │ - * Called when the feature is modified. If the current state is not │ │ │ │ - * INSERT or DELETE, the state is set to UPDATE. │ │ │ │ + * method: touchstart │ │ │ │ + * handle touchstart. │ │ │ │ + * │ │ │ │ + * parameters: │ │ │ │ + * evt - {event} the browser event │ │ │ │ + * │ │ │ │ + * returns: │ │ │ │ + * {boolean} allow event propagation │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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: resetVertices │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ + 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: 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. │ │ │ │ - * │ │ │ │ + * Method: move │ │ │ │ + * Handle mousemove and touchmove. Adjust the geometry and redraw. │ │ │ │ + * Return determines whether to propagate the event on the map. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} Keypress event. │ │ │ │ + * evt - {Event} The browser event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + 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: collectVertices │ │ │ │ - * Collect the vertices from the modifiable feature's geometry and push │ │ │ │ - * them on to the control's vertices array. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + up: function(evt) { │ │ │ │ + if (this.mouseDown && (!this.lastUp || !this.lastUp.equals(evt.xy))) { │ │ │ │ + if (this.stoppedDown && this.freehandMode(evt)) { │ │ │ │ + if (this.persist) { │ │ │ │ + this.destroyPersistedFeature(); │ │ │ │ } │ │ │ │ - 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); │ │ │ │ + this.removePoint(); │ │ │ │ + this.finalize(); │ │ │ │ + } else { │ │ │ │ + if (this.passesTolerance(this.lastDown, evt.xy, │ │ │ │ + this.pixelTolerance)) { │ │ │ │ + if (this.touch) { │ │ │ │ + this.modifyFeature(evt.xy); │ │ │ │ } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // 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); │ │ │ │ - } │ │ │ │ + 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(); │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + this.stoppedDown = this.stopDown; │ │ │ │ + this.mouseDown = false; │ │ │ │ + return !this.stopUp; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setMap │ │ │ │ - * Set the map property for the control and all handlers. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} The control's map. │ │ │ │ + * APIMethod: finishGeometry │ │ │ │ + * Finish the geometry and send it back to the control. │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - this.handlers.drag.setMap(map); │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + finishGeometry: function() { │ │ │ │ + var index = this.line.geometry.components.length - 1; │ │ │ │ + this.line.geometry.removeComponent(this.line.geometry.components[index]); │ │ │ │ + this.removePoint(); │ │ │ │ + this.finalize(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handleMapEvents │ │ │ │ + * Method: dblclick │ │ │ │ + * Handle double-clicks. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * evt - {Event} The browser event │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Allow event propagation │ │ │ │ */ │ │ │ │ - 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)); │ │ │ │ + dblclick: function(evt) { │ │ │ │ + if (!this.freehandMode(evt)) { │ │ │ │ + this.finishGeometry(); │ │ │ │ } │ │ │ │ + return false; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ModifyFeature" │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Path" │ │ │ │ }); │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * 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/Control/Attribution.js │ │ │ │ + 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/Control.js │ │ │ │ + * @requires OpenLayers/Geometry/LineString.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> │ │ │ │ + * 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.Control.Attribution = │ │ │ │ - OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Geometry.LinearRing = OpenLayers.Class( │ │ │ │ + OpenLayers.Geometry.LineString, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: separator │ │ │ │ - * {String} String used to separate layers. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - separator: ", ", │ │ │ │ + componentTypes: ["OpenLayers.Geometry.Point"], │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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}". │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - template: "${layers}", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.Attribution │ │ │ │ + * 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: │ │ │ │ - * options - {Object} Options for control. │ │ │ │ + * 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(); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - * Destroy control. │ │ │ │ + //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. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - this.map.events.un({ │ │ │ │ - "removelayer": this.updateAttribution, │ │ │ │ - "addlayer": this.updateAttribution, │ │ │ │ - "changelayer": this.updateAttribution, │ │ │ │ - "changebaselayer": this.updateAttribution, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ + move: function(x, y) { │ │ │ │ + for (var i = 0, len = this.components.length; i < len - 1; i++) { │ │ │ │ + this.components[i].move(x, y); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: draw │ │ │ │ - * Initialize control. │ │ │ │ + * 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: │ │ │ │ - * {DOMElement} A reference to the DIV DOMElement containing the control │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Geometry>} - The current geometry. │ │ │ │ */ │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - this.map.events.on({ │ │ │ │ - 'changebaselayer': this.updateAttribution, │ │ │ │ - 'changelayer': this.updateAttribution, │ │ │ │ - 'addlayer': this.updateAttribution, │ │ │ │ - 'removelayer': this.updateAttribution, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.updateAttribution(); │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - return this.div; │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: updateAttribution │ │ │ │ - * Update attribution string. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - this.div.innerHTML = OpenLayers.String.format(this.template, { │ │ │ │ - layers: attributions.join(this.separator) │ │ │ │ - }); │ │ │ │ } │ │ │ │ + var contained = (crosses == -1) ? │ │ │ │ + // on edge │ │ │ │ + 1 : │ │ │ │ + // even (out) or odd (in) │ │ │ │ + !!(crosses & 1); │ │ │ │ + │ │ │ │ + return contained; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Attribution" │ │ │ │ + /** │ │ │ │ + * 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/Handler/Feature.js │ │ │ │ + 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/Handler.js │ │ │ │ + * @requires OpenLayers/Geometry/Collection.js │ │ │ │ + * @requires OpenLayers/Geometry/LinearRing.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. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Geometry.Polygon │ │ │ │ + * Polygon is a collection of Geometry.LinearRings. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Handler> │ │ │ │ + * - <OpenLayers.Geometry.Collection> │ │ │ │ + * - <OpenLayers.Geometry> │ │ │ │ */ │ │ │ │ -OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ +OpenLayers.Geometry.Polygon = OpenLayers.Class( │ │ │ │ + OpenLayers.Geometry.Collection, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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' │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ }, │ │ │ │ - 'dblclick': { │ │ │ │ - 'in': 'dblclick', │ │ │ │ - 'out': null │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ }, │ │ │ │ - 'mousedown': { │ │ │ │ - 'in': null, │ │ │ │ - 'out': null │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ }, │ │ │ │ - 'mouseup': { │ │ │ │ - 'in': null, │ │ │ │ - 'out': null │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ }, │ │ │ │ - 'touchstart': { │ │ │ │ - 'in': 'click', │ │ │ │ - 'out': 'clickout' │ │ │ │ - } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: feature │ │ │ │ - * {<OpenLayers.Feature.Vector>} The last feature that was hovered. │ │ │ │ - */ │ │ │ │ - feature: null, │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: lastFeature │ │ │ │ - * {<OpenLayers.Feature.Vector>} The last feature that was handled. │ │ │ │ - */ │ │ │ │ - lastFeature: null, │ │ │ │ + CLASS_NAME: "OpenLayers.Geometry.Polygon" │ │ │ │ + }); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: down │ │ │ │ - * {<OpenLayers.Pixel>} The location of the last mousedown. │ │ │ │ - */ │ │ │ │ - down: null, │ │ │ │ +/** │ │ │ │ + * 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/Handler/Polygon.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: up │ │ │ │ - * {<OpenLayers.Pixel>} The location of the last mouseup. │ │ │ │ - */ │ │ │ │ - up: null, │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Handler/Path.js │ │ │ │ + * @requires OpenLayers/Geometry/Polygon.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ +/** │ │ │ │ + * 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, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - stopDown: true, │ │ │ │ + holeModifier: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: drawingHole │ │ │ │ + * {Boolean} Currently drawing an interior ring. │ │ │ │ */ │ │ │ │ - stopUp: false, │ │ │ │ + drawingHole: 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} │ │ │ │ + * Property: polygon │ │ │ │ + * {<OpenLayers.Feature.Vector>} │ │ │ │ */ │ │ │ │ - initialize: function(control, layer, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ - this.layer = layer; │ │ │ │ - }, │ │ │ │ + polygon: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: touchstart │ │ │ │ - * Handle touchstart events │ │ │ │ + * Constructor: OpenLayers.Handler.Polygon │ │ │ │ + * Create a Polygon Handler. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * 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 │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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. │ │ │ │ + * Method: createFeature │ │ │ │ + * Add temporary geometries │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new │ │ │ │ + * feature. │ │ │ │ */ │ │ │ │ - touchmove: function(evt) { │ │ │ │ - OpenLayers.Event.preventDefault(evt); │ │ │ │ + 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: mousedown │ │ │ │ - * Handle mouse down. Stop propagation if a feature is targeted by this │ │ │ │ - * event (stops map dragging during feature selection). │ │ │ │ - * │ │ │ │ + * Method: addPoint │ │ │ │ + * Add point to geometry. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The pixel location for the new point. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + OpenLayers.Handler.Path.prototype.addPoint.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: click │ │ │ │ - * Handle click. Call the "click" callback if click on a feature, │ │ │ │ - * or the "clickout" callback if click outside any feature. │ │ │ │ + * Method: getCurrentPointIndex │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} │ │ │ │ + * {Number} The index of the most recently drawn point. │ │ │ │ */ │ │ │ │ - click: function(evt) { │ │ │ │ - return this.handle(evt) ? !this.stopClick : true; │ │ │ │ + getCurrentPointIndex: function() { │ │ │ │ + return this.line.geometry.components.length - 2; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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} │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - mousemove: function(evt) { │ │ │ │ - if (!this.callbacks['over'] && !this.callbacks['out']) { │ │ │ │ - return true; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - 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} │ │ │ │ + * Method: finishGeometry │ │ │ │ + * Finish the geometry and send it back to the control. │ │ │ │ */ │ │ │ │ - geometryTypeMatches: function(feature) { │ │ │ │ - return this.geometryTypes == null || │ │ │ │ - OpenLayers.Util.indexOf(this.geometryTypes, │ │ │ │ - feature.geometry.CLASS_NAME) > -1; │ │ │ │ + finishGeometry: function() { │ │ │ │ + var index = this.line.geometry.components.length - 2; │ │ │ │ + this.line.geometry.removeComponent(this.line.geometry.components[index]); │ │ │ │ + this.removePoint(); │ │ │ │ + this.finalize(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handle │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The event occurred over a relevant feature. │ │ │ │ + * Method: finalizeInteriorRing │ │ │ │ + * Enforces that new ring has some area and doesn't contain vertices of any │ │ │ │ + * other rings. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ } │ │ │ │ - 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]); │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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} │ │ │ │ + * APIMethod: cancel │ │ │ │ + * Finish the geometry and call the "cancel" callback. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + 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: activate │ │ │ │ - * Turn on the handler. Returns false if the handler was already active. │ │ │ │ + * Method: restoreFeature │ │ │ │ + * Move the feature from the sketch layer to the target layer. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} │ │ │ │ + * Properties: │ │ │ │ + * cancel - {Boolean} Cancel drawing. If falsey, the "sketchcomplete" event │ │ │ │ + * will be fired. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + ); │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Turn off the handler. Returns false if the handler was already active. │ │ │ │ + * Method: destroyFeature │ │ │ │ + * Destroy temporary geometries │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} │ │ │ │ + * Parameters: │ │ │ │ + * force - {Boolean} Destroy even if persist is true. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + destroyFeature: function(force) { │ │ │ │ + OpenLayers.Handler.Path.prototype.destroyFeature.call( │ │ │ │ + this, force); │ │ │ │ + this.polygon = null; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handleMapEvents │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} │ │ │ │ + * Method: drawFeature │ │ │ │ + * Render geometries on the temporary layer. │ │ │ │ */ │ │ │ │ - handleMapEvents: function(evt) { │ │ │ │ - if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ - this.moveLayerToTop(); │ │ │ │ - } │ │ │ │ + drawFeature: function() { │ │ │ │ + this.layer.drawFeature(this.polygon, this.style); │ │ │ │ + this.layer.drawFeature(this.point, this.style); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: moveLayerToTop │ │ │ │ - * Moves the layer for this handler to the top, so mouse events can reach │ │ │ │ - * it. │ │ │ │ + * Method: getSketch │ │ │ │ + * Return the sketch feature. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Feature.Vector>} │ │ │ │ */ │ │ │ │ - moveLayerToTop: function() { │ │ │ │ - var index = Math.max(this.map.Z_INDEX_BASE['Feature'] - 1, │ │ │ │ - this.layer.getZIndex()) + 1; │ │ │ │ - this.layer.setZIndex(index); │ │ │ │ - │ │ │ │ + getSketch: function() { │ │ │ │ + return this.polygon; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: moveLayerBack │ │ │ │ - * Moves the layer back to the position determined by the map's layers │ │ │ │ - * array. │ │ │ │ + * Method: getGeometry │ │ │ │ + * Return the sketch geometry. If <multi> is true, this will return │ │ │ │ + * a multi-part geometry. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Geometry.Polygon>} │ │ │ │ */ │ │ │ │ - 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)); │ │ │ │ + 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.Feature" │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Polygon" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/Vector/RootContainer.js │ │ │ │ + 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/Vector.js │ │ │ │ + * @requires OpenLayers/Layer/Grid.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. │ │ │ │ - * │ │ │ │ +/** │ │ │ │ + * 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.Vector> │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ +OpenLayers.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: displayInLayerSwitcher │ │ │ │ - * Set to false for this layer type │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * Default is true, as this is designed to be a base tile source. │ │ │ │ */ │ │ │ │ - displayInLayerSwitcher: false, │ │ │ │ + isBaseLayer: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layers │ │ │ │ - * Layers that are attached to this container. Required config option. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - layers: null, │ │ │ │ + sphericalMercator: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: display │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - display: function() {}, │ │ │ │ + serverResolutions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getFeatureFromEvent │ │ │ │ - * walk through the layers to find the feature returned by the event │ │ │ │ - * │ │ │ │ + * Constructor: OpenLayers.Layer.XYZ │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Object} event object with a feature property │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} │ │ │ │ + * name - {String} │ │ │ │ + * url - {String} │ │ │ │ + * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + 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 │ │ │ │ + ]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setMap │ │ │ │ - * │ │ │ │ + * APIMethod: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ * 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 │ │ │ │ + * obj - {Object} Is this ever used? │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.XYZ>} An exact clone of this OpenLayers.Layer.XYZ │ │ │ │ */ │ │ │ │ - removeMap: function(map) { │ │ │ │ - map.events.unregister("changelayer", this, this.handleChangeLayer); │ │ │ │ - this.resetRoots(); │ │ │ │ - OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments); │ │ │ │ + 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: collectRoots │ │ │ │ - * Collects the root nodes of all layers this control is configured with │ │ │ │ - * and moveswien the nodes to this control's layer │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + 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: resetRoots │ │ │ │ - * Resets the root nodes back into the layers they belong to. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + 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 │ │ │ │ + }; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /* APIMethod: setMap │ │ │ │ + * When the layer is added to a map, then we can fetch our origin │ │ │ │ + * (if we don't have one.) │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Object} │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - handleChangeLayer: function(evt) { │ │ │ │ - var layer = evt.layer; │ │ │ │ - if (evt.property == "order" && │ │ │ │ - OpenLayers.Util.indexOf(this.layers, layer) != -1) { │ │ │ │ - this.resetRoots(); │ │ │ │ - this.collectRoots(); │ │ │ │ + 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.Vector.RootContainer" │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.XYZ" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/SelectFeature.js │ │ │ │ + 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/Control.js │ │ │ │ - * @requires OpenLayers/Feature/Vector.js │ │ │ │ - * @requires OpenLayers/Handler/Feature.js │ │ │ │ - * @requires OpenLayers/Layer/Vector/RootContainer.js │ │ │ │ + * @requires OpenLayers/Layer/XYZ.js │ │ │ │ */ │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.SelectFeature │ │ │ │ - * The SelectFeature control selects vector features from a given layer on │ │ │ │ - * click or hover. │ │ │ │ - * │ │ │ │ +/** │ │ │ │ + * 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.Control> │ │ │ │ + * - <OpenLayers.Layer.XYZ> │ │ │ │ */ │ │ │ │ -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 │ │ │ │ - */ │ │ │ │ +OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: multipleKey │ │ │ │ - * {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets │ │ │ │ - * the <multiple> property to true. Default is null. │ │ │ │ + * Property: key │ │ │ │ + * {String} API key for Bing maps, get your own key │ │ │ │ + * at http://bingmapsportal.com/ . │ │ │ │ */ │ │ │ │ - multipleKey: null, │ │ │ │ + key: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: toggleKey │ │ │ │ - * {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets │ │ │ │ - * the <toggle> property to true. Default is null. │ │ │ │ + * Property: serverResolutions │ │ │ │ + * {Array} the resolutions provided by the Bing servers. │ │ │ │ */ │ │ │ │ - toggleKey: null, │ │ │ │ + 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 │ │ │ │ + ], │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: multiple │ │ │ │ - * {Boolean} Allow selection of multiple geometries. Default is false. │ │ │ │ + * Property: attributionTemplate │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - multiple: false, │ │ │ │ + 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>', │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: clickout │ │ │ │ - * {Boolean} Unselect features when clicking outside any feature. │ │ │ │ - * Default is true. │ │ │ │ + * Property: metadata │ │ │ │ + * {Object} Metadata for this layer, as returned by the callback script │ │ │ │ */ │ │ │ │ - clickout: true, │ │ │ │ + metadata: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: toggle │ │ │ │ - * {Boolean} Unselect a selected feature on click. Default is false. Only │ │ │ │ - * has meaning if hover is false. │ │ │ │ + * Property: protocolRegex │ │ │ │ + * {RegExp} Regular expression to match and replace http: in bing urls │ │ │ │ */ │ │ │ │ - toggle: false, │ │ │ │ + protocolRegex: /^http:/i, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: hover │ │ │ │ - * {Boolean} Select on mouse over and deselect on mouse out. If true, this │ │ │ │ - * ignores clicks and only listens to mouse moves. │ │ │ │ + * 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". │ │ │ │ */ │ │ │ │ - hover: false, │ │ │ │ + type: "Road", │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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". │ │ │ │ */ │ │ │ │ - highlightOnly: false, │ │ │ │ + culture: "en-US", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: box │ │ │ │ - * {Boolean} Allow feature selection by drawing a box. │ │ │ │ + * APIProperty: metadataParams │ │ │ │ + * {Object} Optional url parameters for the Get Imagery Metadata request │ │ │ │ + * as described here: http://msdn.microsoft.com/en-us/library/ff701716.aspx │ │ │ │ */ │ │ │ │ - box: false, │ │ │ │ + metadataParams: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: onBeforeSelect │ │ │ │ - * {Function} Optional function to be called before a feature is selected. │ │ │ │ - * The function should expect to be called with a feature. │ │ │ │ + /** APIProperty: tileOptions │ │ │ │ + * {Object} optional configuration options for <OpenLayers.Tile> instances │ │ │ │ + * created by this Layer. Default is │ │ │ │ + * │ │ │ │ + * (code) │ │ │ │ + * {crossOriginKeyword: 'anonymous'} │ │ │ │ + * (end) │ │ │ │ */ │ │ │ │ - onBeforeSelect: function() {}, │ │ │ │ + tileOptions: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: onSelect │ │ │ │ - * {Function} Optional function to be called when a feature is selected. │ │ │ │ - * The function should expect to be called with a feature. │ │ │ │ + /** 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:'. │ │ │ │ */ │ │ │ │ - onSelect: function() {}, │ │ │ │ + protocol: ~window.location.href.indexOf('http') ? '' : 'http:', │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: onUnselect │ │ │ │ - * {Function} Optional function to be called when a feature is unselected. │ │ │ │ - * The function should expect to be called with a feature. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - onUnselect: function() {}, │ │ │ │ + initialize: function(options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults({ │ │ │ │ + sphericalMercator: true │ │ │ │ + }, options); │ │ │ │ + var name = options.name || "Bing " + (options.type || this.type); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: scope │ │ │ │ - * {Object} The scope to use with the onBeforeSelect, onSelect, onUnselect │ │ │ │ - * callbacks. If null the scope will be this control. │ │ │ │ - */ │ │ │ │ - scope: null, │ │ │ │ + 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(); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: loadMetadata │ │ │ │ */ │ │ │ │ - geometryTypes: null, │ │ │ │ + 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); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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). │ │ │ │ + * Method: initLayer │ │ │ │ + * │ │ │ │ + * Sets layer properties according to the metadata provided by the API │ │ │ │ */ │ │ │ │ - layer: null, │ │ │ │ + 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(); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: layers │ │ │ │ - * {Array(<OpenLayers.Layer.Vector>)} The layers this control will work on, │ │ │ │ - * or null if the control was configured with a single layer │ │ │ │ + * Method: getURL │ │ │ │ + * │ │ │ │ + * Paramters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ */ │ │ │ │ - layers: null, │ │ │ │ + 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); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: callbacks │ │ │ │ - * {Object} The functions that are sent to the handlers.feature for callback │ │ │ │ - */ │ │ │ │ - callbacks: null, │ │ │ │ + return OpenLayers.String.format(url, { │ │ │ │ + 'quadkey': quadKey │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: selectStyle │ │ │ │ - * {Object} Hash of styles │ │ │ │ + * Method: updateAttribution │ │ │ │ + * Updates the attribution according to the requirements outlined in │ │ │ │ + * http://gis.638310.n2.nabble.com/Bing-imagery-td5789168.html │ │ │ │ */ │ │ │ │ - selectStyle: null, │ │ │ │ + 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" │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: renderIntent │ │ │ │ - * {String} key used to retrieve the select style from the layer's │ │ │ │ - * style map. │ │ │ │ + * Method: setMap │ │ │ │ */ │ │ │ │ - renderIntent: "select", │ │ │ │ + setMap: function() { │ │ │ │ + OpenLayers.Layer.XYZ.prototype.setMap.apply(this, arguments); │ │ │ │ + this.map.events.register("moveend", this, this.updateAttribution); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: handlers │ │ │ │ - * {Object} Object with references to multiple <OpenLayers.Handler> │ │ │ │ - * instances. │ │ │ │ + * APIMethod: clone │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.Bing>} An exact clone of this <OpenLayers.Layer.Bing> │ │ │ │ */ │ │ │ │ - handlers: null, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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} │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - initialize: function(layers, options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + destroy: function() { │ │ │ │ + this.map && │ │ │ │ + this.map.events.unregister("moveend", this, this.updateAttribution); │ │ │ │ + OpenLayers.Layer.XYZ.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Bing" │ │ │ │ +}); │ │ │ │ │ │ │ │ - this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks); │ │ │ │ - this.handlers = { │ │ │ │ - feature: new OpenLayers.Handler.Feature( │ │ │ │ - this, this.layer, this.callbacks, { │ │ │ │ - geometryTypes: this.geometryTypes │ │ │ │ - } │ │ │ │ - ) │ │ │ │ - }; │ │ │ │ +/** │ │ │ │ + * 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/Layer/OSM.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - if (this.box) { │ │ │ │ - this.handlers.box = new OpenLayers.Handler.Box( │ │ │ │ - this, { │ │ │ │ - done: this.selectBox │ │ │ │ - }, { │ │ │ │ - boxDivClassName: "olHandlerBoxSelectFeature" │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ +/* 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, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: name │ │ │ │ + * {String} The layer name. Defaults to "OpenStreetMap" if the first │ │ │ │ + * argument to the constructor is null or undefined. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + name: "OpenStreetMap", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroy │ │ │ │ + * 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) │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 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' │ │ │ │ + ], │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ - * Activates the control. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The control was effectively activated. │ │ │ │ + * Property: attribution │ │ │ │ + * {String} The layer attribution. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ + attribution: "© <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Deactivates the control. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The control was effectively deactivated. │ │ │ │ + * Property: sphericalMercator │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ + sphericalMercator: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: unselectAll │ │ │ │ - * Unselect all selected features. To unselect all except for a single │ │ │ │ - * feature, set the options.except property to the feature. │ │ │ │ + * Property: wrapDateLine │ │ │ │ + * {Boolean} │ │ │ │ + */ │ │ │ │ + wrapDateLine: true, │ │ │ │ + │ │ │ │ + /** APIProperty: tileOptions │ │ │ │ + * {Object} optional configuration options for <OpenLayers.Tile> instances │ │ │ │ + * created by this Layer. Default is │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional configuration object. │ │ │ │ + * (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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + tileOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clickFeature │ │ │ │ - * Called on click in a feature │ │ │ │ - * Only responds if this.hover is false. │ │ │ │ + * Constructor: OpenLayers.Layer.OSM │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * 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>). │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 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: multipleSelect │ │ │ │ - * Allow for multiple selected features based on <multiple> property and │ │ │ │ - * <multipleKey> event modifier. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow for multiple selected features. │ │ │ │ + * Method: clone │ │ │ │ */ │ │ │ │ - multipleSelect: function() { │ │ │ │ - return this.multiple || (this.handlers.feature.evt && │ │ │ │ - this.handlers.feature.evt[this.multipleKey]); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.OSM" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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>} │ │ │ │ */ │ │ │ │ - toggleSelect: function() { │ │ │ │ - return this.toggle || (this.handlers.feature.evt && │ │ │ │ - this.handlers.feature.evt[this.toggleKey]); │ │ │ │ - }, │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: clickoutFeature │ │ │ │ - * Called on click outside a previously clicked (selected) feature. │ │ │ │ - * Only responds if this.hover is false. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Vector.Feature>} │ │ │ │ + /** │ │ │ │ + * Property: id │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - clickoutFeature: function(feature) { │ │ │ │ - if (!this.hover && this.clickout) { │ │ │ │ - this.unselectAll(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + id: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: lonlat │ │ │ │ + * {<OpenLayers.LonLat>} │ │ │ │ + */ │ │ │ │ + lonlat: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: data │ │ │ │ + * {Object} │ │ │ │ + */ │ │ │ │ + data: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: marker │ │ │ │ + * {<OpenLayers.Marker>} │ │ │ │ + */ │ │ │ │ + marker: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: overFeature │ │ │ │ - * Called on over a feature. │ │ │ │ - * Only responds if this.hover is true. │ │ │ │ + * 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: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * layer - {<OpenLayers.Layer>} │ │ │ │ + * lonlat - {<OpenLayers.LonLat>} │ │ │ │ + * data - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Feature>} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 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: outFeature │ │ │ │ - * Called on out of a selected feature. │ │ │ │ - * Only responds if this.hover is true. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 │ │ │ │ - }); │ │ │ │ + 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: unhighlight │ │ │ │ - * Redraw feature with the "default" style │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * Method: onScreen │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the feature is currently visible on screen │ │ │ │ + * (based on its 'lonlat' property) │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + onScreen: function() { │ │ │ │ + │ │ │ │ + var onScreen = false; │ │ │ │ + if ((this.layer != null) && (this.layer.map != null)) { │ │ │ │ + var screenBounds = this.layer.map.getExtent(); │ │ │ │ + onScreen = screenBounds.containsLonLat(this.lonlat); │ │ │ │ } │ │ │ │ - layer.drawFeature(feature, feature.style || feature.layer.style || │ │ │ │ - "default"); │ │ │ │ - this.events.triggerEvent("featureunhighlighted", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ + return onScreen; │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: select │ │ │ │ - * Add feature to the layer's selectedFeature array, render the feature as │ │ │ │ - * selected, and call the onSelect function. │ │ │ │ + * 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 │ │ │ │ * │ │ │ │ - * 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); │ │ │ │ - } │ │ │ │ + createMarker: function() { │ │ │ │ + │ │ │ │ + if (this.lonlat != null) { │ │ │ │ + this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon); │ │ │ │ } │ │ │ │ + return this.marker; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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>} │ │ │ │ + * Method: destroyMarker │ │ │ │ + * Destroys marker. │ │ │ │ + * If user overrides the createMarker() function, s/he should be able │ │ │ │ + * to also specify an alternative function for destroying it │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + destroyMarker: function() { │ │ │ │ + this.marker.destroy(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: selectBox │ │ │ │ - * Callback from the handlers.box set up when <box> selection is true │ │ │ │ - * on. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * position - {<OpenLayers.Bounds> || <OpenLayers.Pixel> } │ │ │ │ + * 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>. │ │ │ │ + * │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - ); │ │ │ │ + createPopup: function(closeBox) { │ │ │ │ │ │ │ │ - // if multiple is false, first deselect currently selected features │ │ │ │ - if (!this.multipleSelect()) { │ │ │ │ - this.unselectAll(); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - │ │ │ │ - // 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + if (this.data.overflow != null) { │ │ │ │ + this.popup.contentDiv.style.overflow = this.data.overflow; │ │ │ │ } │ │ │ │ - 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); │ │ │ │ + this.popup.feature = this; │ │ │ │ } │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + return this.popup; │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * APIMethod: setLayer │ │ │ │ - * Attach a new layer to the control, overriding any existing layers. │ │ │ │ + * Method: destroyPopup │ │ │ │ + * Destroys the popup created via createPopup. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * layers - Array of {<OpenLayers.Layer.Vector>} or a single │ │ │ │ - * {<OpenLayers.Layer.Vector>} │ │ │ │ + * As with the marker, if user overrides the createPopup() function, s/he │ │ │ │ + * should also be able to override the destruction │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ + destroyPopup: function() { │ │ │ │ + if (this.popup) { │ │ │ │ + this.popup.feature = null; │ │ │ │ + this.popup.destroy(); │ │ │ │ + this.popup = null; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.SelectFeature" │ │ │ │ + CLASS_NAME: "OpenLayers.Feature" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/DragPan.js │ │ │ │ + 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/Control.js │ │ │ │ - * @requires OpenLayers/Handler/Drag.js │ │ │ │ + * @requires OpenLayers/Feature.js │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.DragPan │ │ │ │ - * The DragPan control pans the map with a drag of the mouse. │ │ │ │ - * │ │ │ │ + * 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.Control> │ │ │ │ + * - <OpenLayers.Feature> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: type │ │ │ │ - * {OpenLayers.Control.TYPES} │ │ │ │ + * Property: fid │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ + fid: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: panned │ │ │ │ - * {Boolean} The map moved. │ │ │ │ + /** │ │ │ │ + * APIProperty: geometry │ │ │ │ + * {<OpenLayers.Geometry>} │ │ │ │ */ │ │ │ │ - panned: false, │ │ │ │ + geometry: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * APIProperty: attributes │ │ │ │ + * {Object} This object holds arbitrary, serializable properties that │ │ │ │ + * describe the feature. │ │ │ │ */ │ │ │ │ - interval: 0, │ │ │ │ + attributes: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: documentDrag │ │ │ │ - * {Boolean} If set to true, mouse dragging will continue even if the │ │ │ │ - * mouse cursor leaves the map viewport. Default is false. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - documentDrag: false, │ │ │ │ + bounds: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: state │ │ │ │ + * {String} │ │ │ │ + */ │ │ │ │ + state: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: style │ │ │ │ + * {Object} │ │ │ │ + */ │ │ │ │ + style: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: kinetic │ │ │ │ - * {<OpenLayers.Kinetic>} The OpenLayers.Kinetic object. │ │ │ │ + * APIProperty: url │ │ │ │ + * {String} If this property is set it will be taken into account by │ │ │ │ + * {<OpenLayers.HTTP>} when upadting or deleting the feature. │ │ │ │ */ │ │ │ │ - kinetic: null, │ │ │ │ + url: 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. │ │ │ │ + * Property: renderIntent │ │ │ │ + * {String} rendering intent currently being used │ │ │ │ */ │ │ │ │ - enableKinetic: true, │ │ │ │ + renderIntent: "default", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: kineticInterval │ │ │ │ - * {Integer} Interval in milliseconds between 2 steps in the "kinetic │ │ │ │ - * scrolling". Applies only if enableKinetic is set. Defaults │ │ │ │ - * to 10 milliseconds. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - kineticInterval: 10, │ │ │ │ + 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: draw │ │ │ │ - * Creates a Drag handler, using <panMap> and │ │ │ │ - * <panMapDone> as callbacks. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - draw: function() { │ │ │ │ - if (this.enableKinetic && OpenLayers.Kinetic) { │ │ │ │ - var config = { │ │ │ │ - interval: this.kineticInterval │ │ │ │ - }; │ │ │ │ - if (typeof this.enableKinetic === "object") { │ │ │ │ - config = OpenLayers.Util.extend(config, this.enableKinetic); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + return onScreen; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: panMapStart │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - panMapStart: function() { │ │ │ │ - if (this.kinetic) { │ │ │ │ - this.kinetic.begin(); │ │ │ │ + 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: panMap │ │ │ │ + * 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: │ │ │ │ - * xy - {<OpenLayers.Pixel>} Pixel of the mouse position │ │ │ │ + * location - {<OpenLayers.LonLat> or <OpenLayers.Pixel>} the │ │ │ │ + * location to which to move the feature. │ │ │ │ */ │ │ │ │ - panMap: function(xy) { │ │ │ │ - if (this.kinetic) { │ │ │ │ - this.kinetic.update(xy); │ │ │ │ + move: function(location) { │ │ │ │ + │ │ │ │ + if (!this.layer || !this.geometry.move) { │ │ │ │ + //do nothing if no layer or immoveable geometry │ │ │ │ + return undefined; │ │ │ │ } │ │ │ │ - this.panned = true; │ │ │ │ - this.map.pan( │ │ │ │ - this.handler.last.x - xy.x, │ │ │ │ - this.handler.last.y - xy.y, { │ │ │ │ - dragging: true, │ │ │ │ - animate: false │ │ │ │ - } │ │ │ │ - ); │ │ │ │ + │ │ │ │ + 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: panMapDone │ │ │ │ - * Finish the panning operation. Only call setCenter (through <panMap>) │ │ │ │ - * if the map has actually been moved. │ │ │ │ + * Method: toState │ │ │ │ + * Sets the new state │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * xy - {<OpenLayers.Pixel>} Pixel of the mouse position │ │ │ │ + * state - {String} │ │ │ │ */ │ │ │ │ - panMapDone: function(xy) { │ │ │ │ - if (this.panned) { │ │ │ │ - var res = null; │ │ │ │ - if (this.kinetic) { │ │ │ │ - res = this.kinetic.end(xy); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ - }); │ │ │ │ + } else if (state == OpenLayers.State.INSERT) { │ │ │ │ + switch (this.state) { │ │ │ │ + case OpenLayers.State.UNKNOWN: │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + this.state = state; │ │ │ │ + break; │ │ │ │ } │ │ │ │ - this.panned = false; │ │ │ │ + } 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.Control.DragPan" │ │ │ │ + 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/Handler/Pinch.js │ │ │ │ + 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/Handler.js │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ + * @requires OpenLayers/Feature/Vector.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> │ │ │ │ + * Class: OpenLayers.Style │ │ │ │ + * This class represents a UserStyle obtained │ │ │ │ + * from a SLD, containing styling rules. │ │ │ │ */ │ │ │ │ -OpenLayers.Handler.Pinch = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ +OpenLayers.Style = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: id │ │ │ │ + * {String} A unique id for this session. │ │ │ │ */ │ │ │ │ - started: false, │ │ │ │ + id: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: stopDown │ │ │ │ - * {Boolean} Stop propagation of touchstart events from getting to │ │ │ │ - * listeners on the same element. Default is false. │ │ │ │ + * APIProperty: name │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - stopDown: false, │ │ │ │ + name: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: pinching │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - pinching: false, │ │ │ │ + isDefault: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: rules │ │ │ │ + * {Array(<OpenLayers.Rule>)} │ │ │ │ + */ │ │ │ │ + rules: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: last │ │ │ │ - * {Object} Object that store informations related to pinch last touch. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - last: null, │ │ │ │ + context: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: start │ │ │ │ - * {Object} Object that store informations related to pinch touchstart. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - start: null, │ │ │ │ + defaultStyle: 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} │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: touchstart │ │ │ │ - * Handle touchstart events │ │ │ │ + * 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: │ │ │ │ - * evt - {Event} │ │ │ │ + * 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: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * {<OpenLayers.Style>} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + initialize: function(style, options) { │ │ │ │ + │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + this.rules = []; │ │ │ │ + if (options && options.rules) { │ │ │ │ + this.addRules(options.rules); │ │ │ │ } │ │ │ │ - // prevent document dragging │ │ │ │ - OpenLayers.Event.preventDefault(evt); │ │ │ │ - return propagate; │ │ │ │ + │ │ │ │ + // 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: touchmove │ │ │ │ - * Handle touchmove events │ │ │ │ - * │ │ │ │ + * Method: createSymbolizer │ │ │ │ + * creates a style by applying all feature-dependent rules to the base │ │ │ │ + * style. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ + * feature - {<OpenLayers.Feature>} feature to evaluate rules for │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * {Object} symbolizer hash │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - return true; │ │ │ │ + │ │ │ │ + // 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: touchend │ │ │ │ - * Handle touchend events │ │ │ │ + * Method: applySymbolizer │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * rule - {<OpenLayers.Rule>} │ │ │ │ + * style - {Object} │ │ │ │ + * feature - {<OpenLayer.Feature.Vector>} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * {Object} A style with new symbolizer applied. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ + } │ │ │ │ } │ │ │ │ - return true; │ │ │ │ + │ │ │ │ + // merge the style with the current style │ │ │ │ + return this.createLiterals( │ │ │ │ + OpenLayers.Util.extend(style, symbolizer), feature); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ - * Activate the handler. │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * {Boolean} The handler was successfully activated. │ │ │ │ + * {Object} the modified style │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.pinching = false; │ │ │ │ - activated = true; │ │ │ │ + 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 activated; │ │ │ │ + return style; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Deactivate the handler. │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * {Boolean} The handler was successfully deactivated. │ │ │ │ + * {Object} hash of property names that need createLiteral parsing. The │ │ │ │ + * name of the property is the key, and the value is true; │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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 deactivated; │ │ │ │ + return propertyStyles; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getDistance │ │ │ │ - * Get the distance in pixels between two touches. │ │ │ │ - * │ │ │ │ + * Method: addPropertyStyles │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * touches - {Array(Object)} │ │ │ │ - * │ │ │ │ + * propertyStyles - {Object} hash to add new property styles to. Will be │ │ │ │ + * modified inline │ │ │ │ + * symbolizer - {Object} search this symbolizer for property styles │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Number} The distance in pixels. │ │ │ │ + * {Object} propertyStyles hash │ │ │ │ */ │ │ │ │ - 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) │ │ │ │ - ); │ │ │ │ + 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(); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getPinchData │ │ │ │ - * Get informations about the pinch event. │ │ │ │ - * │ │ │ │ + * APIMethod: setDefaultStyle │ │ │ │ + * Sets the default style for this style object. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * {Object} Object that contains data about the current pinch. │ │ │ │ + * {String} key of the according symbolizer │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }; │ │ │ │ + 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]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Pinch" │ │ │ │ + /** │ │ │ │ + * 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/Control/PinchZoom.js │ │ │ │ + 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/Handler/Pinch.js │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ + * @requires OpenLayers/Style.js │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.PinchZoom │ │ │ │ - * │ │ │ │ - * Inherits: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * Class: OpenLayers.StyleMap │ │ │ │ */ │ │ │ │ -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, │ │ │ │ +OpenLayers.StyleMap = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: styles │ │ │ │ + * {Object} Hash of {<OpenLayers.Style>}, keyed by names of well known │ │ │ │ + * rendering intents (e.g. "default", "temporary", "select", "delete"). │ │ │ │ */ │ │ │ │ - preserveCenter: false, │ │ │ │ + styles: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: handlerOptions │ │ │ │ - * {Object} Used to set non-default properties on the pinch handler │ │ │ │ + * 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.Control.PinchZoom │ │ │ │ - * Create a control for zooming with pinch gestures. This works on devices │ │ │ │ - * with multi-touch support. │ │ │ │ - * │ │ │ │ + * Constructor: OpenLayers.StyleMap │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * the control │ │ │ │ + * 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(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); │ │ │ │ + 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: 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. │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - pinchStart: function(evt, pinchData) { │ │ │ │ - var xy = (this.preserveCenter) ? │ │ │ │ - this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; │ │ │ │ - this.pinchOrigin = xy; │ │ │ │ - this.currentCenter = xy; │ │ │ │ + destroy: function() { │ │ │ │ + for (var key in this.styles) { │ │ │ │ + this.styles[key].destroy(); │ │ │ │ + } │ │ │ │ + this.styles = null; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: pinchMove │ │ │ │ - * │ │ │ │ + * Method: createSymbolizer │ │ │ │ + * Creates the symbolizer for a feature for a render intent. │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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: pinchDone │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * 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. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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.Control.PinchZoom" │ │ │ │ - │ │ │ │ + CLASS_NAME: "OpenLayers.StyleMap" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Handler/Click.js │ │ │ │ + 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/Handler.js │ │ │ │ + * @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.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. │ │ │ │ - * │ │ │ │ + * 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.Handler> │ │ │ │ + * - <OpenLayers.Layer> │ │ │ │ */ │ │ │ │ -OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ +OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * APIProperty: delay │ │ │ │ - * {Number} Number of milliseconds between clicks before the event is │ │ │ │ - * considered a double-click. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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. │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} The layer is a base layer. Default is false. Set this property │ │ │ │ + * in the layer options. │ │ │ │ */ │ │ │ │ - single: true, │ │ │ │ + isBaseLayer: false, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: double │ │ │ │ - * {Boolean} Handle double-clicks. Default is 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. │ │ │ │ */ │ │ │ │ - 'double': false, │ │ │ │ + isFixed: 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. │ │ │ │ + /** │ │ │ │ + * APIProperty: features │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ */ │ │ │ │ - pixelTolerance: 0, │ │ │ │ + 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: unrenderedFeatures │ │ │ │ + * {Object} hash of features, keyed by feature.id, that the renderer │ │ │ │ + * failed to draw │ │ │ │ */ │ │ │ │ - dblclickTolerance: 13, │ │ │ │ + unrenderedFeatures: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: reportError │ │ │ │ + * {Boolean} report friendly error message when loading of renderer │ │ │ │ + * fails. │ │ │ │ */ │ │ │ │ - stopSingle: false, │ │ │ │ + reportError: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: style │ │ │ │ + * {Object} Default style for the layer │ │ │ │ + */ │ │ │ │ + style: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: styleMap │ │ │ │ + * {<OpenLayers.StyleMap>} │ │ │ │ */ │ │ │ │ - stopDouble: false, │ │ │ │ + styleMap: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: timerId │ │ │ │ - * {Number} The id of the timeout waiting to clear the <delayedCall>. │ │ │ │ + * Property: strategies │ │ │ │ + * {Array(<OpenLayers.Strategy>})} Optional list of strategies for the layer. │ │ │ │ */ │ │ │ │ - timerId: null, │ │ │ │ + strategies: 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. │ │ │ │ + * Property: protocol │ │ │ │ + * {<OpenLayers.Protocol>} Optional protocol for the layer. │ │ │ │ */ │ │ │ │ - down: null, │ │ │ │ + protocol: 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - last: null, │ │ │ │ + renderers: ['SVG', 'VML', 'Canvas'], │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: first │ │ │ │ - * {Object} When waiting for double clicks, this object will store │ │ │ │ - * information about the first click in a two click sequence. │ │ │ │ + * Property: renderer │ │ │ │ + * {<OpenLayers.Renderer>} │ │ │ │ */ │ │ │ │ - first: null, │ │ │ │ + renderer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: rightclickTimerId │ │ │ │ - * {Number} The id of the right mouse timeout waiting to clear the │ │ │ │ - * <delayedEvent>. │ │ │ │ + * APIProperty: rendererOptions │ │ │ │ + * {Object} Options for the renderer. See {<OpenLayers.Renderer>} for │ │ │ │ + * supported options. │ │ │ │ */ │ │ │ │ - rightclickTimerId: null, │ │ │ │ + rendererOptions: 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. │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: touchstart │ │ │ │ - * Handle touchstart. │ │ │ │ + * 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: │ │ │ │ - * {Boolean} Continue propagating this event. │ │ │ │ + * {<OpenLayers.Layer.Vector>} A new vector layer │ │ │ │ */ │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - this.down = this.getEventInfo(evt); │ │ │ │ - this.last = this.getEventInfo(evt); │ │ │ │ - return true; │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: touchmove │ │ │ │ - * Store position of last move, because touchend event can have │ │ │ │ - * an empty "touches" property. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Continue propagating this event. │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Destroy this layer │ │ │ │ */ │ │ │ │ - touchmove: function(evt) { │ │ │ │ - this.last = this.getEventInfo(evt); │ │ │ │ - return true; │ │ │ │ + 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: touchend │ │ │ │ - * Correctly set event xy property, and add lastTouches to have │ │ │ │ - * touches property from last touchstart or touchmove │ │ │ │ + * Method: clone │ │ │ │ + * Create a clone of this layer. │ │ │ │ + * │ │ │ │ + * Note: Features of the layer are also cloned. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Continue propagating this event. │ │ │ │ + * {<OpenLayers.Layer.Vector>} An exact clone of this layer │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.Vector(this.name, this.getOptions()); │ │ │ │ } │ │ │ │ - return true; │ │ │ │ + │ │ │ │ + //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: mousedown │ │ │ │ - * Handle mousedown. │ │ │ │ + * Method: refresh │ │ │ │ + * Ask the layer to request features again and redraw them. Triggers │ │ │ │ + * the refresh event if the layer is in range and visible. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Continue propagating this event. │ │ │ │ + * Parameters: │ │ │ │ + * obj - {Object} Optional object with properties for any listener of │ │ │ │ + * the refresh event. │ │ │ │ */ │ │ │ │ - mousedown: function(evt) { │ │ │ │ - this.down = this.getEventInfo(evt); │ │ │ │ - this.last = this.getEventInfo(evt); │ │ │ │ - return true; │ │ │ │ + refresh: function(obj) { │ │ │ │ + if (this.calculateInRange() && this.visibility) { │ │ │ │ + this.events.triggerEvent("refresh", obj); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: mouseup │ │ │ │ - * Handle mouseup. Installed to support collection of right mouse events. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Continue propagating this event. │ │ │ │ + /** │ │ │ │ + * Method: assignRenderer │ │ │ │ + * Iterates through the available renderer implementations and selects │ │ │ │ + * and assigns the first one whose "supported()" function returns true. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - return propagate; │ │ │ │ + /** │ │ │ │ + * 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: 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. │ │ │ │ + /** │ │ │ │ + * 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>} │ │ │ │ */ │ │ │ │ - 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]); │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Layer.prototype.setMap.apply(this, arguments); │ │ │ │ │ │ │ │ - var delayedRightCall = OpenLayers.Function.bind( │ │ │ │ - this.delayedRightCall, │ │ │ │ - this, │ │ │ │ - clickEvent │ │ │ │ - ); │ │ │ │ - this.rightclickTimerId = window.setTimeout( │ │ │ │ - delayedRightCall, this.delay │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - return !this.stopSingle; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: delayedRightCall │ │ │ │ - * Sets <rightclickTimerId> to null. And optionally triggers the │ │ │ │ - * rightclick callback if evt is set. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - delayedRightCall: function(evt) { │ │ │ │ - this.rightclickTimerId = null; │ │ │ │ - if (evt) { │ │ │ │ - this.callback('rightclick', [evt]); │ │ │ │ + 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: 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. │ │ │ │ + * Method: removeMap │ │ │ │ + * The layer has been removed from the map. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Continue propagating this event. │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - click: function(evt) { │ │ │ │ - if (!this.last) { │ │ │ │ - this.last = this.getEventInfo(evt); │ │ │ │ + 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(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - 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. │ │ │ │ + * Method: onMapResize │ │ │ │ + * Notify the renderer of the change in size. │ │ │ │ + * │ │ │ │ */ │ │ │ │ - dblclick: function(evt) { │ │ │ │ - this.handleDouble(evt); │ │ │ │ - return !this.stopDouble; │ │ │ │ + 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: handleDouble │ │ │ │ - * Handle double-click sequence. │ │ │ │ + /** │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - handleDouble: function(evt) { │ │ │ │ - if (this.passesDblclickTolerance(evt)) { │ │ │ │ - if (this["double"]) { │ │ │ │ - this.callback("dblclick", [evt]); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - // to prevent a dblclick from firing the click callback in IE │ │ │ │ - this.clearTimer(); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handleSingle │ │ │ │ - * Handle single click sequence. │ │ │ │ + * APIMethod: display │ │ │ │ + * Hide or show the Layer │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * display - {Boolean} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - // 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(); │ │ │ │ + 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 { │ │ │ │ - // 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); │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: queuePotentialClick │ │ │ │ - * This method is separated out largely to make testing easier (so we │ │ │ │ - * don't have to override window.setTimeout) │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - queuePotentialClick: function(evt) { │ │ │ │ - this.timerId = window.setTimeout( │ │ │ │ - OpenLayers.Function.bind(this.delayedCall, this, evt), │ │ │ │ - this.delay │ │ │ │ - ); │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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). │ │ │ │ + * APIMethod: destroyFeatures │ │ │ │ + * Erase and destroy features on the layer. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The click is within the pixel tolerance (if specified). │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 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(); │ │ │ │ } │ │ │ │ } │ │ │ │ - return passes; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getTouchDistance │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The pixel displacement between two touches. │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * style - {String | Object} Named render intent or full symbolizer object. │ │ │ │ */ │ │ │ │ - getTouchDistance: function(from, to) { │ │ │ │ - return Math.sqrt( │ │ │ │ - Math.pow(from.clientX - to.clientX, 2) + │ │ │ │ - Math.pow(from.clientY - to.clientY, 2) │ │ │ │ - ); │ │ │ │ + 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: passesDblclickTolerance │ │ │ │ - * Determine whether the event is within the optional double-cick pixel │ │ │ │ - * tolerance. │ │ │ │ + * Method: eraseFeatures │ │ │ │ + * Erase features from the layer. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The click is within the double-click pixel tolerance. │ │ │ │ + * Parameters: │ │ │ │ + * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ */ │ │ │ │ - passesDblclickTolerance: function(evt) { │ │ │ │ - var passes = true; │ │ │ │ - if (this.down && this.first) { │ │ │ │ - passes = this.down.xy.distanceTo(this.first.xy) <= this.dblclickTolerance; │ │ │ │ - } │ │ │ │ - return passes; │ │ │ │ + eraseFeatures: function(features) { │ │ │ │ + this.renderer.eraseFeatures(features); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clearTimer │ │ │ │ - * Clear the timer and set <timerId> to null. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - clearTimer: function() { │ │ │ │ - if (this.timerId != null) { │ │ │ │ - window.clearTimeout(this.timerId); │ │ │ │ - this.timerId = null; │ │ │ │ + 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.'); │ │ │ │ } │ │ │ │ - if (this.rightclickTimerId != null) { │ │ │ │ - window.clearTimeout(this.rightclickTimerId); │ │ │ │ - this.rightclickTimerId = null; │ │ │ │ + var feature = null; │ │ │ │ + var featureId = this.renderer.getFeatureIdFromEvent(evt); │ │ │ │ + if (featureId) { │ │ │ │ + if (typeof featureId === "string") { │ │ │ │ + feature = this.getFeatureById(featureId); │ │ │ │ + } else { │ │ │ │ + feature = featureId; │ │ │ │ + } │ │ │ │ } │ │ │ │ + return feature; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: delayedCall │ │ │ │ - * Sets <timerId> to null. And optionally triggers the click callback if │ │ │ │ - * evt is set. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - delayedCall: function(evt) { │ │ │ │ - this.timerId = null; │ │ │ │ - if (evt) { │ │ │ │ - this.callback("click", [evt]); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: getFeatureById │ │ │ │ + * Given a feature id, return the feature if it exists in the features array │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * featureId - {String} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} An object with event related info. │ │ │ │ + * {<OpenLayers.Feature.Vector>} A feature corresponding to the given │ │ │ │ + * featureId or null if there is no such feature. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }; │ │ │ │ + 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 { │ │ │ │ - xy: evt.xy, │ │ │ │ - touches: touches │ │ │ │ - }; │ │ │ │ + return foundFeatures; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the handler. │ │ │ │ + * 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: │ │ │ │ - * {Boolean} The handler was successfully deactivated. │ │ │ │ + * {<OpenLayers.Bounds>} or null if the layer has no features with │ │ │ │ + * geometries. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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 deactivated; │ │ │ │ + return maxExtent; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Click" │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Vector" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/TouchNavigation.js │ │ │ │ + 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/Control/DragPan.js │ │ │ │ - * @requires OpenLayers/Control/PinchZoom.js │ │ │ │ - * @requires OpenLayers/Handler/Click.js │ │ │ │ + * @requires OpenLayers/Layer/Grid.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> │ │ │ │ + * 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.Control.TouchNavigation = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: dragPan │ │ │ │ - * {<OpenLayers.Control.DragPan>} │ │ │ │ - */ │ │ │ │ - dragPan: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: dragPanOptions │ │ │ │ - * {Object} Options passed to the DragPan control. │ │ │ │ - */ │ │ │ │ - dragPanOptions: null, │ │ │ │ +OpenLayers.Layer.WMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: pinchZoom │ │ │ │ - * {<OpenLayers.Control.PinchZoom>} │ │ │ │ + * Constant: DEFAULT_PARAMS │ │ │ │ + * {Object} Hashtable of default parameter key/value pairs │ │ │ │ */ │ │ │ │ - pinchZoom: null, │ │ │ │ + DEFAULT_PARAMS: { │ │ │ │ + service: "WMS", │ │ │ │ + version: "1.1.1", │ │ │ │ + request: "GetMap", │ │ │ │ + styles: "", │ │ │ │ + format: "image/jpeg" │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: pinchZoomOptions │ │ │ │ - * {Object} Options passed to the PinchZoom control. │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} Default is true for WMS layer │ │ │ │ */ │ │ │ │ - pinchZoomOptions: null, │ │ │ │ + isBaseLayer: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: clickHandlerOptions │ │ │ │ - * {Object} Options passed to the Click handler. │ │ │ │ + * APIProperty: encodeBBOX │ │ │ │ + * {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no', │ │ │ │ + * but some services want it that way. Default false. │ │ │ │ */ │ │ │ │ - clickHandlerOptions: null, │ │ │ │ + encodeBBOX: false, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: documentDrag │ │ │ │ - * {Boolean} Allow panning of the map by dragging outside map viewport. │ │ │ │ - * Default is 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. │ │ │ │ */ │ │ │ │ - documentDrag: false, │ │ │ │ + noMagic: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - autoActivate: true, │ │ │ │ + yx: {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.TouchNavigation │ │ │ │ - * Create a new navigation control │ │ │ │ + * 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: │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - if (this.dragPan) { │ │ │ │ - this.dragPan.destroy(); │ │ │ │ + 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"; │ │ │ │ } │ │ │ │ - this.dragPan = null; │ │ │ │ - if (this.pinchZoom) { │ │ │ │ - this.pinchZoom.destroy(); │ │ │ │ - delete this.pinchZoom; │ │ │ │ + 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"; │ │ │ │ + } │ │ │ │ } │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ + * Method: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.WMS>} An exact clone of this layer │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.dragPan.activate(); │ │ │ │ - this.handlers.click.activate(); │ │ │ │ - this.pinchZoom.activate(); │ │ │ │ - return true; │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.WMS(this.name, │ │ │ │ + this.url, │ │ │ │ + this.params, │ │ │ │ + this.getOptions()); │ │ │ │ } │ │ │ │ - return false; │ │ │ │ + │ │ │ │ + //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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - this.dragPan.deactivate(); │ │ │ │ - this.handlers.click.deactivate(); │ │ │ │ - this.pinchZoom.deactivate(); │ │ │ │ - return true; │ │ │ │ - } │ │ │ │ - return false; │ │ │ │ + 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: draw │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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) │ │ │ │ - ); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: defaultClick │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * evt - {Event} │ │ │ │ + * newParams - {Object} Hashtable of new params to use │ │ │ │ */ │ │ │ │ - defaultClick: function(evt) { │ │ │ │ - if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ - this.map.zoomOut(); │ │ │ │ - } │ │ │ │ + mergeNewParams: function(newParams) { │ │ │ │ + var upperParams = OpenLayers.Util.upperCaseObject(newParams); │ │ │ │ + var newArguments = [upperParams]; │ │ │ │ + return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, │ │ │ │ + newArguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: defaultDblClick │ │ │ │ + /** │ │ │ │ + * 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: │ │ │ │ - * evt - {Event} │ │ │ │ + * newParams - {Object} │ │ │ │ + * altUrl - {String} Use this as the url instead of the layer's url │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - defaultDblClick: function(evt) { │ │ │ │ - this.map.zoomTo(this.map.zoom + 1, evt.xy); │ │ │ │ + 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.Control.TouchNavigation" │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.WMS" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Strategy.js │ │ │ │ + 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.Strategy │ │ │ │ - * Abstract vector layer strategy class. Not to be instantiated directly. Use │ │ │ │ - * one of the strategy subclasses instead. │ │ │ │ + * Class: OpenLayers.Protocol │ │ │ │ + * Abstract vector layer protocol class. Not to be instantiated directly. Use │ │ │ │ + * one of the protocol subclasses instead. │ │ │ │ */ │ │ │ │ -OpenLayers.Strategy = OpenLayers.Class({ │ │ │ │ +OpenLayers.Protocol = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: layer │ │ │ │ - * {<OpenLayers.Layer.Vector>} The layer this strategy belongs to. │ │ │ │ + * Property: format │ │ │ │ + * {<OpenLayers.Format>} The format used by this protocol. │ │ │ │ */ │ │ │ │ - layer: null, │ │ │ │ + format: 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 │ │ │ │ + * {Boolean} The creator of the protocol can set autoDestroy to false │ │ │ │ + * to fully control when the protocol is destroyed. Defaults to │ │ │ │ * true. │ │ │ │ */ │ │ │ │ autoDestroy: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Strategy │ │ │ │ - * Abstract class for vector strategies. Create instances of a subclass. │ │ │ │ + * 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; │ │ │ │ - // set the active property here, so that user cannot override it │ │ │ │ - this.active = false; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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 strategy. │ │ │ │ + * Clean up the protocol. │ │ │ │ */ │ │ │ │ destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - this.layer = null; │ │ │ │ this.options = null; │ │ │ │ + this.format = null; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setLayer │ │ │ │ - * Called to set the <layer> property. │ │ │ │ + * APIMethod: read │ │ │ │ + * Construct a request for reading new features. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.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. │ │ │ │ */ │ │ │ │ - setLayer: function(layer) { │ │ │ │ - this.layer = layer; │ │ │ │ + read: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + options.filter = this.mergeWithDefaultFilter(options.filter); │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ + * 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: │ │ │ │ - * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ - * the strategy was already active. │ │ │ │ + * {<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. │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - if (!this.active) { │ │ │ │ - this.active = true; │ │ │ │ - return true; │ │ │ │ - } │ │ │ │ - return false; │ │ │ │ - }, │ │ │ │ + create: function() {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ - * tear-down. │ │ │ │ + * 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: │ │ │ │ - * {Boolean} True if the strategy was successfully deactivated or false if │ │ │ │ - * the strategy was already inactive. │ │ │ │ + * {<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. │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - if (this.active) { │ │ │ │ - this.active = false; │ │ │ │ - return true; │ │ │ │ - } │ │ │ │ - return false; │ │ │ │ + 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.Strategy" │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol" │ │ │ │ }); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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.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, │ │ │ │ │ │ │ │ -/** │ │ │ │ - * 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, { │ │ │ │ + /** │ │ │ │ + * Property: requestType │ │ │ │ + * {String} The type of request this response corresponds to. Either │ │ │ │ + * "create", "read", "update" or "delete". │ │ │ │ + */ │ │ │ │ + requestType: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: last │ │ │ │ + * {Boolean} - true if this is the last response expected in a commit, │ │ │ │ + * false otherwise, defaults to true. │ │ │ │ */ │ │ │ │ - preload: false, │ │ │ │ + last: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Strategy.Fixed │ │ │ │ - * Create a new Fixed strategy. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - }, │ │ │ │ + data: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Deactivate the strategy. Undo what is done in <activate>. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully deactivated. │ │ │ │ + * Property: reqFeatures │ │ │ │ + * {Array({<OpenLayers.Feature.Vector>})} or {<OpenLayers.Feature.Vector>} │ │ │ │ + * The features provided by the user and placed in the request by the │ │ │ │ + * protocol. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - }, │ │ │ │ + reqFeatures: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: load │ │ │ │ - * Tells protocol to load data and unhooks the visibilitychanged event │ │ │ │ + * 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} options to pass to protocol read. │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: success │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * resp - {<OpenLayers.Protocol.Response>} The response object passed │ │ │ │ - * by the protocol. │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} - true on success, false otherwise │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + success: function() { │ │ │ │ + return this.code > 0; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Fixed" │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.Response" │ │ │ │ }); │ │ │ │ + │ │ │ │ +OpenLayers.Protocol.Response.SUCCESS = 1; │ │ │ │ +OpenLayers.Protocol.Response.FAILURE = 0; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Renderer/Elements.js │ │ │ │ + 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/Renderer.js │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ + * @requires OpenLayers/Request/XMLHttpRequest.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. │ │ │ │ + * TODO: deprecate me │ │ │ │ + * Use OpenLayers.Request.proxy instead. │ │ │ │ */ │ │ │ │ -OpenLayers.ElementsIndexer = OpenLayers.Class({ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: maxZIndex │ │ │ │ - * {Integer} This is the largest-most z-index value for a node │ │ │ │ - * contained within the indexer. │ │ │ │ - */ │ │ │ │ - maxZIndex: null, │ │ │ │ +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) { │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * This allows for OpenLayers/Request/XMLHttpRequest.js to be included │ │ │ │ + * before or after this script. │ │ │ │ */ │ │ │ │ - order: null, │ │ │ │ + OpenLayers.Request = {}; │ │ │ │ +} │ │ │ │ +OpenLayers.Util.extend(OpenLayers.Request, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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). │ │ │ │ + * Constant: DEFAULT_CONFIG │ │ │ │ + * {Object} Default configuration for all requests. │ │ │ │ */ │ │ │ │ - indices: null, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Constant: URL_SPLIT_REGEX │ │ │ │ */ │ │ │ │ - compare: null, │ │ │ │ + URL_SPLIT_REGEX: /([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: initialize │ │ │ │ - * Create a new indexer with │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * yOrdering - {Boolean} Whether to use y-ordering. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - initialize: function(yOrdering) { │ │ │ │ - │ │ │ │ - this.compare = yOrdering ? │ │ │ │ - OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER : │ │ │ │ - OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER; │ │ │ │ - │ │ │ │ - this.clear(); │ │ │ │ - }, │ │ │ │ + events: new OpenLayers.Events(this), │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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)). │ │ │ │ - * │ │ │ │ + * Method: makeSameOrigin │ │ │ │ + * Using the specified proxy, returns a same origin url of the provided url. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * newNode - {DOMElement} The new node to be inserted. │ │ │ │ - * │ │ │ │ + * url - {String} An arbitrary url │ │ │ │ + * proxy {String|Function} The proxy to use to make the provided url a │ │ │ │ + * same origin url. │ │ │ │ + * │ │ │ │ * Returns │ │ │ │ - * {DOMElement} the node before which we should insert our newNode, or │ │ │ │ - * null if newNode can just be appended. │ │ │ │ + * {String} the same origin url. If no proxy is provided, the returned url │ │ │ │ + * will be the same as the provided url. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - this.determineZIndex(newNode); │ │ │ │ + /** │ │ │ │ + * 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'; │ │ │ │ + } │ │ │ │ │ │ │ │ - var leftIndex = -1; │ │ │ │ - var rightIndex = this.order.length; │ │ │ │ - var middle; │ │ │ │ + // 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]); │ │ │ │ + } │ │ │ │ │ │ │ │ - while (rightIndex - leftIndex > 1) { │ │ │ │ - middle = parseInt((leftIndex + rightIndex) / 2); │ │ │ │ + var events = this.events; │ │ │ │ │ │ │ │ - var placement = this.compare(this, newNode, │ │ │ │ - OpenLayers.Util.getElement(this.order[middle])); │ │ │ │ + // we want to execute runCallbacks with "this" as the │ │ │ │ + // execution scope │ │ │ │ + var self = this; │ │ │ │ │ │ │ │ - if (placement > 0) { │ │ │ │ - leftIndex = middle; │ │ │ │ - } else { │ │ │ │ - rightIndex = middle; │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ + } │ │ │ │ } │ │ │ │ - } │ │ │ │ - │ │ │ │ - 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); │ │ │ │ + // 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: remove │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * node - {DOMElement} The node to be removed. │ │ │ │ + * options - {Object} Hash containing request, config and requestUrl keys │ │ │ │ */ │ │ │ │ - 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]; │ │ │ │ + runCallbacks: function(options) { │ │ │ │ + var request = options.request; │ │ │ │ + var config = options.config; │ │ │ │ │ │ │ │ - // 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; │ │ │ │ - } │ │ │ │ + // 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; │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: clear │ │ │ │ - */ │ │ │ │ - clear: function() { │ │ │ │ - this.order = []; │ │ │ │ - this.indices = {}; │ │ │ │ - this.maxZIndex = 0; │ │ │ │ + // 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: exists │ │ │ │ + * APIMethod: GET │ │ │ │ + * Send an HTTP GET request. Additional configuration properties are │ │ │ │ + * documented in the <issue> method, with the method property set │ │ │ │ + * to GET. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} The node to test for existence. │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * {Boolean} Whether or not the node exists in the indexer? │ │ │ │ + * {XMLHttpRequest} Request object. │ │ │ │ */ │ │ │ │ - exists: function(node) { │ │ │ │ - return (this.indices[node.id] != null); │ │ │ │ + GET: function(config) { │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ + method: "GET" │ │ │ │ + }); │ │ │ │ + return OpenLayers.Request.issue(config); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getZIndex │ │ │ │ - * Get the z-index value for the current node from the node data itself. │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * node - {DOMElement} The node whose z-index to get. │ │ │ │ + * 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: │ │ │ │ - * {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} │ │ │ │ + * {XMLHttpRequest} Request object. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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: getNextElement │ │ │ │ - * Get the next element in the order stack. │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * index - {Integer} The index of the current node in this.order. │ │ │ │ + * 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: │ │ │ │ - * {DOMElement} the node following the index passed in, or │ │ │ │ - * null. │ │ │ │ + * {XMLHttpRequest} Request object. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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); │ │ │ │ }, │ │ │ │ │ │ │ │ - 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. │ │ │ │ - * │ │ │ │ + * APIMethod: DELETE │ │ │ │ + * Send an HTTP DELETE request. Additional configuration properties are │ │ │ │ + * documented in the <issue> method, with the method property set │ │ │ │ + * to DELETE. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * indexer - {<OpenLayers.ElementsIndexer>} │ │ │ │ - * newNode - {DOMElement} │ │ │ │ - * nextNode - {DOMElement} │ │ │ │ + * 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: │ │ │ │ - * {Integer} │ │ │ │ + * {XMLHttpRequest} Request object. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + DELETE: function(config) { │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ + method: "DELETE" │ │ │ │ + }); │ │ │ │ + return OpenLayers.Request.issue(config); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + * APIMethod: HEAD │ │ │ │ + * Send an HTTP HEAD request. Additional configuration properties are │ │ │ │ + * documented in the <issue> method, with the method property set │ │ │ │ + * to HEAD. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * indexer - {<OpenLayers.ElementsIndexer>} │ │ │ │ - * newNode - {DOMElement} │ │ │ │ - * nextNode - {DOMElement} │ │ │ │ + * 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: │ │ │ │ - * {Integer} │ │ │ │ + * {XMLHttpRequest} Request object. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + HEAD: function(config) { │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ + method: "HEAD" │ │ │ │ + }); │ │ │ │ + return OpenLayers.Request.issue(config); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + * APIMethod: OPTIONS │ │ │ │ + * Send an HTTP OPTIONS request. Additional configuration properties are │ │ │ │ + * documented in the <issue> method, with the method property set │ │ │ │ + * to OPTIONS. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * indexer - {<OpenLayers.ElementsIndexer>} │ │ │ │ - * newNode - {DOMElement} │ │ │ │ - * nextNode - {DOMElement} │ │ │ │ + * 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: │ │ │ │ - * {Integer} │ │ │ │ + * {XMLHttpRequest} Request object. │ │ │ │ */ │ │ │ │ - Z_ORDER_Y_ORDER: function(indexer, newNode, nextNode) { │ │ │ │ - var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER( │ │ │ │ - indexer, │ │ │ │ - newNode, │ │ │ │ - nextNode │ │ │ │ - ); │ │ │ │ + OPTIONS: function(config) { │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ + method: "OPTIONS" │ │ │ │ + }); │ │ │ │ + return OpenLayers.Request.issue(config); │ │ │ │ + } │ │ │ │ │ │ │ │ - if (nextNode && returnVal === 0) { │ │ │ │ - var result = nextNode._boundsBottom - newNode._boundsBottom; │ │ │ │ - returnVal = (result === 0) ? 1 : result; │ │ │ │ - } │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Request/XMLHttpRequest.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - return returnVal; │ │ │ │ - } │ │ │ │ -}; │ │ │ │ +// 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. │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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> │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: rendererRoot │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - rendererRoot: null, │ │ │ │ +(function() { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: root │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - root: null, │ │ │ │ + // Save reference to earlier defined object implementation (if any) │ │ │ │ + var oXMLHttpRequest = window.XMLHttpRequest; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: vectorRoot │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - vectorRoot: null, │ │ │ │ + // Define on browser type │ │ │ │ + var bGecko = !!window.controllers, │ │ │ │ + bIE = window.document.all && !window.opera, │ │ │ │ + bIE7 = bIE && window.navigator.userAgent.match(/MSIE 7.0/); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: textRoot │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - textRoot: null, │ │ │ │ + // Enables "XMLHttpRequest()" call next to "new XMLHttpReques()" │ │ │ │ + function fXMLHttpRequest() { │ │ │ │ + this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP"); │ │ │ │ + this._listeners = []; │ │ │ │ + }; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: xmlns │ │ │ │ - * {String} │ │ │ │ - */ │ │ │ │ - xmlns: null, │ │ │ │ + // Constructor │ │ │ │ + function cXMLHttpRequest() { │ │ │ │ + return new fXMLHttpRequest; │ │ │ │ + }; │ │ │ │ + cXMLHttpRequest.prototype = fXMLHttpRequest.prototype; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + // BUGFIX: Firefox with Firebug installed would break pages if not executed │ │ │ │ + if (bGecko && oXMLHttpRequest.wrapped) │ │ │ │ + cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ - */ │ │ │ │ + // Constants │ │ │ │ + cXMLHttpRequest.UNSENT = 0; │ │ │ │ + cXMLHttpRequest.OPENED = 1; │ │ │ │ + cXMLHttpRequest.HEADERS_RECEIVED = 2; │ │ │ │ + cXMLHttpRequest.LOADING = 3; │ │ │ │ + cXMLHttpRequest.DONE = 4; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + // Public Properties │ │ │ │ + cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ + cXMLHttpRequest.prototype.responseText = ''; │ │ │ │ + cXMLHttpRequest.prototype.responseXML = null; │ │ │ │ + cXMLHttpRequest.prototype.status = 0; │ │ │ │ + cXMLHttpRequest.prototype.statusText = ''; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: BACKGROUND_ID_SUFFIX │ │ │ │ - * {String} │ │ │ │ - */ │ │ │ │ - BACKGROUND_ID_SUFFIX: "_background", │ │ │ │ + // Priority proposal │ │ │ │ + cXMLHttpRequest.prototype.priority = "NORMAL"; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: LABEL_ID_SUFFIX │ │ │ │ - * {String} │ │ │ │ - */ │ │ │ │ - LABEL_ID_SUFFIX: "_label", │ │ │ │ + // Instance-level Events Handlers │ │ │ │ + cXMLHttpRequest.prototype.onreadystatechange = null; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: LABEL_OUTLINE_SUFFIX │ │ │ │ - * {String} │ │ │ │ - */ │ │ │ │ - LABEL_OUTLINE_SUFFIX: "_outline", │ │ │ │ + // Class-level Events Handlers │ │ │ │ + cXMLHttpRequest.onreadystatechange = null; │ │ │ │ + cXMLHttpRequest.onopen = null; │ │ │ │ + cXMLHttpRequest.onsend = null; │ │ │ │ + cXMLHttpRequest.onabort = null; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + // Public Methods │ │ │ │ + cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) { │ │ │ │ + // Delete headers, required when object is reused │ │ │ │ + delete this._headers; │ │ │ │ │ │ │ │ - this.rendererRoot = this.createRenderRoot(); │ │ │ │ - this.root = this.createRoot("_root"); │ │ │ │ - this.vectorRoot = this.createRoot("_vroot"); │ │ │ │ - this.textRoot = this.createRoot("_troot"); │ │ │ │ + // When bAsync parameter value is omitted, use true as default │ │ │ │ + if (arguments.length < 3) │ │ │ │ + bAsync = true; │ │ │ │ │ │ │ │ - this.root.appendChild(this.vectorRoot); │ │ │ │ - this.root.appendChild(this.textRoot); │ │ │ │ + // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests │ │ │ │ + this._async = bAsync; │ │ │ │ │ │ │ │ - this.rendererRoot.appendChild(this.root); │ │ │ │ - this.container.appendChild(this.rendererRoot); │ │ │ │ + // Set the onreadystatechange handler │ │ │ │ + var oRequest = this, │ │ │ │ + nState = this.readyState, │ │ │ │ + fOnUnload; │ │ │ │ │ │ │ │ - if (options && (options.zIndexing || options.yOrdering)) { │ │ │ │ - this.indexer = new OpenLayers.ElementsIndexer(options.yOrdering); │ │ │ │ + // 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); │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ + // Add method sniffer │ │ │ │ + if (cXMLHttpRequest.onopen) │ │ │ │ + cXMLHttpRequest.onopen.apply(this, arguments); │ │ │ │ │ │ │ │ - this.clear(); │ │ │ │ + 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.rendererRoot = null; │ │ │ │ - this.root = null; │ │ │ │ - this.xmlns = null; │ │ │ │ + this.readyState = cXMLHttpRequest.OPENED; │ │ │ │ + fReadyStateChange(this); │ │ │ │ │ │ │ │ - OpenLayers.Renderer.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + this._object.onreadystatechange = function() { │ │ │ │ + if (bGecko && !bAsync) │ │ │ │ + return; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + // Synchronize state │ │ │ │ + oRequest.readyState = oRequest._object.readyState; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - }, │ │ │ │ + // │ │ │ │ + fSynchronizeValues(oRequest); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ + // BUGFIX: Firefox fires unnecessary DONE when aborting │ │ │ │ + if (oRequest._aborted) { │ │ │ │ + // Reset readyState to UNSENT │ │ │ │ + oRequest.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 now │ │ │ │ + return; │ │ │ │ } │ │ │ │ - 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; │ │ │ │ - }, │ │ │ │ + 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; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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)); │ │ │ │ + // Instantiate a new transport object │ │ │ │ + cXMLHttpRequest.call(oRequest); │ │ │ │ │ │ │ │ - // 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; │ │ │ │ + // 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]); │ │ │ │ │ │ │ │ - var drawResult = this.drawGeometryNode(node, geometry, style); │ │ │ │ - if (drawResult === false) { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ + oRequest._object.onreadystatechange = function() { │ │ │ │ + // Synchronize state │ │ │ │ + oRequest.readyState = oRequest._object.readyState; │ │ │ │ │ │ │ │ - node = drawResult.node; │ │ │ │ + if (oRequest._aborted) { │ │ │ │ + // │ │ │ │ + oRequest.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ │ │ │ │ - // 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + // Return │ │ │ │ + return; │ │ │ │ + } │ │ │ │ │ │ │ │ - this.postDraw(node); │ │ │ │ + if (oRequest.readyState == cXMLHttpRequest.DONE) { │ │ │ │ + // Clean Object │ │ │ │ + fCleanTransport(oRequest); │ │ │ │ │ │ │ │ - return drawResult.complete; │ │ │ │ - }, │ │ │ │ + // get cached request │ │ │ │ + if (oRequest.status == 304) │ │ │ │ + oRequest._object = oRequest._cached; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + // │ │ │ │ + delete oRequest._cached; │ │ │ │ │ │ │ │ - // 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; │ │ │ │ + // │ │ │ │ + fSynchronizeValues(oRequest); │ │ │ │ │ │ │ │ - // Erase background styles. │ │ │ │ - backgroundStyle.backgroundGraphic = null; │ │ │ │ - backgroundStyle.backgroundXOffset = null; │ │ │ │ - backgroundStyle.backgroundYOffset = null; │ │ │ │ - backgroundStyle.backgroundGraphicZIndex = null; │ │ │ │ + // │ │ │ │ + fReadyStateChange(oRequest); │ │ │ │ │ │ │ │ - return this.redrawNode( │ │ │ │ - id + this.BACKGROUND_ID_SUFFIX, │ │ │ │ - geometry, │ │ │ │ - backgroundStyle, │ │ │ │ - null │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ + // BUGFIX: IE - memory leak in interrupted │ │ │ │ + if (bIE && bAsync) │ │ │ │ + window.detachEvent("onunload", fOnUnload); │ │ │ │ + } │ │ │ │ + }; │ │ │ │ + oRequest._object.send(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; │ │ │ │ + // Return now - wait until re-sent request is finished │ │ │ │ + return; │ │ │ │ + }; │ │ │ │ + */ │ │ │ │ + // BUGFIX: IE - memory leak in interrupted │ │ │ │ + if (bIE && bAsync) │ │ │ │ + window.detachEvent("onunload", fOnUnload); │ │ │ │ + } │ │ │ │ │ │ │ │ - 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; │ │ │ │ + // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice │ │ │ │ + if (nState != oRequest.readyState) │ │ │ │ + fReadyStateChange(oRequest); │ │ │ │ + │ │ │ │ + nState = oRequest.readyState; │ │ │ │ } │ │ │ │ + }; │ │ │ │ │ │ │ │ - node._options = options; │ │ │ │ + function fXMLHttpRequest_send(oRequest) { │ │ │ │ + oRequest._object.send(oRequest._data); │ │ │ │ │ │ │ │ - //set style │ │ │ │ - //TBD simplify this │ │ │ │ - if (drawn != false) { │ │ │ │ - return { │ │ │ │ - node: this.setStyle(node, style, options, geometry), │ │ │ │ - complete: drawn │ │ │ │ - }; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ + // 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); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ + if (!arguments.length) │ │ │ │ + vData = null; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ + // 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"); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ + 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); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ + // BUGFIX: Gecko - unnecessary DONE when aborting │ │ │ │ + if (this.readyState > cXMLHttpRequest.UNSENT) │ │ │ │ + this._aborted = true; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ + this._object.abort(); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ + // BUGFIX: IE - memory leak │ │ │ │ + fCleanTransport(this); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ + this.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 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; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - }, │ │ │ │ + return this._object.setRequestHeader(sName, sValue); │ │ │ │ + }; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + // 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]); │ │ │ │ + }; │ │ │ │ │ │ │ │ - if (this.indexer) { │ │ │ │ - this.indexer.remove(element); │ │ │ │ - } │ │ │ │ + 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); │ │ │ │ + }; │ │ │ │ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 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 │ │ │ │ + }; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - }, │ │ │ │ + // Execute onreadystatechange │ │ │ │ + if (oEventPseudo.type == "readystatechange" && this.onreadystatechange) │ │ │ │ + (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ + // 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]); │ │ │ │ + }; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) {}, │ │ │ │ + // │ │ │ │ + cXMLHttpRequest.prototype.toString = function() { │ │ │ │ + return '[' + "object" + ' ' + "XMLHttpRequest" + ']'; │ │ │ │ + }; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - root.parentNode.removeChild(root); │ │ │ │ - renderer.rendererRoot.appendChild(root); │ │ │ │ - }, │ │ │ │ + // 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; │ │ │ │ + }; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - }, │ │ │ │ + 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) {} │ │ │ │ + }; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - }, │ │ │ │ + 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); │ │ │ │ + }; │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.Elements" │ │ │ │ -}); │ │ │ │ + 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/Renderer/SVG.js │ │ │ │ + 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/Renderer/Elements.js │ │ │ │ + * @requires OpenLayers/Protocol.js │ │ │ │ + * @requires OpenLayers/Request/XMLHttpRequest.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Renderer.SVG │ │ │ │ - * │ │ │ │ - * Inherits: │ │ │ │ - * - <OpenLayers.Renderer.Elements> │ │ │ │ + * if application uses the query string, for example, for BBOX parameters, │ │ │ │ + * OpenLayers/Format/QueryStringFilter.js should be included in the build config file │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: xmlns │ │ │ │ - * {String} │ │ │ │ - */ │ │ │ │ - xmlns: "http://www.w3.org/2000/svg", │ │ │ │ +/** │ │ │ │ + * 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: xlinkns │ │ │ │ - * {String} │ │ │ │ + * Property: url │ │ │ │ + * {String} Service URL, read-only, set through the options │ │ │ │ + * passed to constructor. │ │ │ │ */ │ │ │ │ - xlinkns: "http://www.w3.org/1999/xlink", │ │ │ │ + url: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: headers │ │ │ │ + * {Object} HTTP request headers, read-only, set through the options │ │ │ │ + * passed to the constructor, │ │ │ │ + * Example: {'Content-Type': 'plain/text'} │ │ │ │ */ │ │ │ │ - MAX_PIXEL: 15000, │ │ │ │ + headers: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: translationParameters │ │ │ │ - * {Object} Hash with "x" and "y" properties │ │ │ │ + * Property: params │ │ │ │ + * {Object} Parameters of GET requests, read-only, set through the options │ │ │ │ + * passed to the constructor, │ │ │ │ + * Example: {'bbox': '5,5,5,5'} │ │ │ │ */ │ │ │ │ - translationParameters: null, │ │ │ │ + params: 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]. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - symbolMetrics: null, │ │ │ │ + callback: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Renderer.SVG │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * containerID - {String} │ │ │ │ + * Property: scope │ │ │ │ + * {Object} Callback execution scope, read-only, set through the │ │ │ │ + * options passed to the constructor. │ │ │ │ */ │ │ │ │ - initialize: function(containerID) { │ │ │ │ - if (!this.supported()) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - OpenLayers.Renderer.Elements.prototype.initialize.apply(this, │ │ │ │ - arguments); │ │ │ │ - this.translationParameters = { │ │ │ │ - x: 0, │ │ │ │ - y: 0 │ │ │ │ - }; │ │ │ │ - │ │ │ │ - this.symbolMetrics = {}; │ │ │ │ - }, │ │ │ │ + scope: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: supported │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the browser supports the SVG renderer │ │ │ │ + * APIProperty: readWithPOST │ │ │ │ + * {Boolean} true if read operations are done with POST requests │ │ │ │ + * instead of GET, defaults to false. │ │ │ │ */ │ │ │ │ - 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"))); │ │ │ │ - }, │ │ │ │ + readWithPOST: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: updateWithPOST │ │ │ │ + * {Boolean} true if update operations are done with POST requests │ │ │ │ + * defaults to false. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - }, │ │ │ │ + updateWithPOST: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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(). │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + deleteWithPOST: false, │ │ │ │ │ │ │ │ - // 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; │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: translate │ │ │ │ - * Transforms the SVG coordinate system │ │ │ │ - * │ │ │ │ + * Constructor: OpenLayers.Protocol.HTTP │ │ │ │ + * A class for giving layers generic HTTP protocol. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * x - {Float} │ │ │ │ - * y - {Float} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} true if the translation parameters are in the valid coordinates │ │ │ │ - * range, false otherwise. │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + 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); │ │ │ │ }; │ │ │ │ - return true; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setSize │ │ │ │ - * Sets the size of the drawing surface. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * size - {<OpenLayers.Size>} The size of the drawing surface │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Clean up the protocol. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + destroy: function() { │ │ │ │ + this.params = null; │ │ │ │ + this.headers = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getNodeType │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * 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: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ - * │ │ │ │ + * filter - {<OpenLayers.Filter>} filter to convert. │ │ │ │ + * params - {Object} The parameters object. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {String} The corresponding node type for the specified geometry │ │ │ │ + * {Object} The resulting parameters object. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Construct a request for reading new features. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {SVGDomElement} An SVG element to decorate │ │ │ │ - * style - {Object} │ │ │ │ - * options - {Object} Currently supported options include │ │ │ │ - * 'isFilled' {Boolean} and │ │ │ │ - * 'isStroked' {Boolean} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ + 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 │ │ │ │ + ); │ │ │ │ } │ │ │ │ - │ │ │ │ - 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)); │ │ │ │ + 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 { │ │ │ │ - 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); │ │ │ │ + resp.priv = OpenLayers.Request.GET({ │ │ │ │ + url: options.url, │ │ │ │ + callback: this.createCallback(this.handleRead, resp, options), │ │ │ │ + params: options.params, │ │ │ │ + headers: options.headers │ │ │ │ + }); │ │ │ │ } │ │ │ │ - │ │ │ │ - return node; │ │ │ │ + return resp; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: dashStyle │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: handleRead │ │ │ │ + * Individual callbacks are created for read, create and update, should │ │ │ │ + * a subclass need to override each one separately. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * style - {Object} │ │ │ │ - * widthFactor - {Number} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A SVG compliant 'stroke-dasharray' value │ │ │ │ + * resp - {<OpenLayers.Protocol.Response>} The response object to pass to │ │ │ │ + * the user callback. │ │ │ │ + * options - {Object} The user options passed to the read call. │ │ │ │ */ │ │ │ │ - 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, ","); │ │ │ │ - } │ │ │ │ + handleRead: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: createNode │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * APIMethod: create │ │ │ │ + * Construct a request for writing newly created features. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * type - {String} Kind of node to draw │ │ │ │ - * id - {String} Id for node │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * {DOMElement} A new node of the given type and id │ │ │ │ + * {<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. │ │ │ │ */ │ │ │ │ - createNode: function(type, id) { │ │ │ │ - var node = document.createElementNS(this.xmlns, type); │ │ │ │ - if (id) { │ │ │ │ - node.setAttributeNS(null, "id", id); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ + create: function(features, options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - }, │ │ │ │ + var resp = new OpenLayers.Protocol.Response({ │ │ │ │ + reqFeatures: features, │ │ │ │ + requestType: "create" │ │ │ │ + }); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ + 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: createRoot │ │ │ │ - * │ │ │ │ + * Method: handleCreate │ │ │ │ + * Called the the request issued by <create> is complete. May be overridden │ │ │ │ + * by subclasses. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * suffix - {String} suffix to append to the id │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * resp - {<OpenLayers.Protocol.Response>} The response object to pass to │ │ │ │ + * any user callback. │ │ │ │ + * options - {Object} The user options passed to the create call. │ │ │ │ */ │ │ │ │ - createRoot: function(suffix) { │ │ │ │ - return this.nodeFactory(this.container.id + suffix, "g"); │ │ │ │ + handleCreate: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createDefs │ │ │ │ + * 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: │ │ │ │ - * {DOMElement} The element to which we'll add the symbol definitions │ │ │ │ + * {<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. │ │ │ │ */ │ │ │ │ - createDefs: function() { │ │ │ │ - var defs = this.nodeFactory(this.container.id + "_defs", "defs"); │ │ │ │ - this.rendererRoot.appendChild(defs); │ │ │ │ - return defs; │ │ │ │ - }, │ │ │ │ + update: function(feature, options) { │ │ │ │ + options = options || {}; │ │ │ │ + var url = options.url || │ │ │ │ + feature.url || │ │ │ │ + this.options.url + "/" + feature.fid; │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ │ │ │ │ - /************************************** │ │ │ │ - * * │ │ │ │ - * GEOMETRY DRAWING FUNCTIONS * │ │ │ │ - * * │ │ │ │ - **************************************/ │ │ │ │ + var resp = new OpenLayers.Protocol.Response({ │ │ │ │ + reqFeatures: feature, │ │ │ │ + requestType: "update" │ │ │ │ + }); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + 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: 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 │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - │ │ │ │ + handleUpdate: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawLineString │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * {DOMElement} or null if the renderer could not draw all components of │ │ │ │ - * the linestring, or false if nothing could be drawn │ │ │ │ + * {<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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + "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: 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 │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + handleDelete: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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 { │ │ │ │ - draw = false; │ │ │ │ + // failure │ │ │ │ + resp.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ } │ │ │ │ - } │ │ │ │ - d += " z"; │ │ │ │ - if (draw) { │ │ │ │ - node.setAttributeNS(null, "d", d); │ │ │ │ - node.setAttributeNS(null, "fill-rule", "evenodd"); │ │ │ │ - return complete ? node : null; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ + options.callback.call(options.scope, resp); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawRectangle │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ + * Method: parseFeatures │ │ │ │ + * Read HTTP response body and return features. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * request - {XMLHttpRequest} The request object │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} or false if the renderer could not draw the rectangle │ │ │ │ + * {Array({<OpenLayers.Feature.Vector>})} or │ │ │ │ + * {<OpenLayers.Feature.Vector>} Array of features or a single feature. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawText │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ + * APIMethod: commit │ │ │ │ + * Iterate over each feature and take action based on the feature state. │ │ │ │ + * Possible actions are create, update and delete. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * featureId - {String} │ │ │ │ - * style - │ │ │ │ - * location - {<OpenLayers.Geometry.Point>} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + commit: function(features, options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ + var resp = [], │ │ │ │ + nResponses = 0; │ │ │ │ │ │ │ │ - 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"); │ │ │ │ + // 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); │ │ │ │ + } │ │ │ │ } │ │ │ │ - var align = style.labelAlign || OpenLayers.Renderer.defaultSymbolizer.labelAlign; │ │ │ │ - label.setAttributeNS(null, "text-anchor", │ │ │ │ - OpenLayers.Renderer.SVG.LABEL_ALIGN[align[0]] || "middle"); │ │ │ │ + // 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; │ │ │ │ │ │ │ │ - if (OpenLayers.IS_GECKO === true) { │ │ │ │ - label.setAttributeNS(null, "dominant-baseline", │ │ │ │ - OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]] || "central"); │ │ │ │ - } │ │ │ │ + // 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 │ │ │ │ + }); │ │ │ │ │ │ │ │ - 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); │ │ │ │ + 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]); │ │ │ │ } │ │ │ │ │ │ │ │ - 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])); │ │ │ │ - } │ │ │ │ + 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]); │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + // 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) │ │ │ │ + )); │ │ │ │ } │ │ │ │ - if (y2 < -maxY || y2 > maxY) { │ │ │ │ - k = (x2 - x1) / (y2 - y1); │ │ │ │ - y2 = y2 < 0 ? -maxY : maxY; │ │ │ │ - x2 = x1 + (y2 - y1) * k; │ │ │ │ + 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))); │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * graphicName - {String} name of the symbol to import │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} - the imported symbol │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + response.priv.abort(); │ │ │ │ } │ │ │ │ - │ │ │ │ - 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 │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {String} A feature id or undefined. │ │ │ │ + * Parameters: │ │ │ │ + * resp - {<OpenLayers.Protocol.Response>} │ │ │ │ + * options - {Object} The map of options passed to the commit call. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + callUserCallback: function(resp, options) { │ │ │ │ + var opt = options[resp.requestType]; │ │ │ │ + if (opt && opt.callback) { │ │ │ │ + opt.callback.call(opt.scope, resp); │ │ │ │ } │ │ │ │ - return featureId; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.SVG" │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.HTTP" │ │ │ │ }); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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. */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Renderer.SVG.LABEL_ALIGN │ │ │ │ - * {Object} │ │ │ │ + * @requires OpenLayers/Protocol.js │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.SVG.LABEL_ALIGN = { │ │ │ │ - "l": "start", │ │ │ │ - "r": "end", │ │ │ │ - "b": "bottom", │ │ │ │ - "t": "hanging" │ │ │ │ -}; │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Renderer.SVG.LABEL_VSHIFT │ │ │ │ - * {Object} │ │ │ │ + * 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.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" │ │ │ │ +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); │ │ │ │ }; │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Renderer.SVG.LABEL_VFACTOR │ │ │ │ - * {Object} │ │ │ │ + * 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.Renderer.SVG.LABEL_VFACTOR = { │ │ │ │ - "t": 0, │ │ │ │ - "b": -1 │ │ │ │ +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 │ │ │ │ + )); │ │ │ │ }; │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Constant: OpenLayers.Protocol.WFS.DEFAULTS │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.SVG.preventDefault = function(e) { │ │ │ │ - OpenLayers.Event.preventDefault(e); │ │ │ │ +OpenLayers.Protocol.WFS.DEFAULTS = { │ │ │ │ + "version": "1.0.0" │ │ │ │ }; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Renderer/Canvas.js │ │ │ │ + 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/Renderer.js │ │ │ │ + * @requires OpenLayers/Protocol/WFS.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Renderer.Canvas │ │ │ │ - * A renderer based on the 2D 'canvas' drawing element. │ │ │ │ - * │ │ │ │ - * Inherits: │ │ │ │ - * - <OpenLayers.Renderer> │ │ │ │ + * Class: OpenLayers.Protocol.WFS.v1 │ │ │ │ + * Abstract class for for v1.0.0 and v1.1.0 protocol. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Protocol> │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ +OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: hitDetection │ │ │ │ - * {Boolean} Allow for hit detection of features. Default is true. │ │ │ │ + * Property: version │ │ │ │ + * {String} WFS version number. │ │ │ │ */ │ │ │ │ - hitDetection: true, │ │ │ │ + version: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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). │ │ │ │ + * Property: srsName │ │ │ │ + * {String} Name of spatial reference system. Default is "EPSG:4326". │ │ │ │ */ │ │ │ │ - hitOverflow: 0, │ │ │ │ + srsName: "EPSG:4326", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: canvas │ │ │ │ - * {Canvas} The canvas context object. │ │ │ │ + * Property: featureType │ │ │ │ + * {String} Local feature typeName. │ │ │ │ */ │ │ │ │ - canvas: null, │ │ │ │ + featureType: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: features │ │ │ │ - * {Object} Internal object of feature/style pairs for use in redrawing the layer. │ │ │ │ + * Property: featureNS │ │ │ │ + * {String} Feature namespace. │ │ │ │ */ │ │ │ │ - features: null, │ │ │ │ + featureNS: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: pendingRedraw │ │ │ │ - * {Boolean} The renderer needs a redraw call to render features added while │ │ │ │ - * the renderer was locked. │ │ │ │ + * Property: geometryName │ │ │ │ + * {String} Name of the geometry attribute for features. Default is │ │ │ │ + * "the_geom" for WFS <version> 1.0, and null for higher versions. │ │ │ │ */ │ │ │ │ - pendingRedraw: false, │ │ │ │ + geometryName: "the_geom", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: cachedSymbolBounds │ │ │ │ - * {Object} Internal cache of calculated symbol extents. │ │ │ │ + * Property: maxFeatures │ │ │ │ + * {Integer} Optional maximum number of features to retrieve. │ │ │ │ */ │ │ │ │ - cachedSymbolBounds: {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Renderer.Canvas │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * containerID - {<String>} │ │ │ │ - * options - {Object} Optional properties to be set on the renderer. │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + schema: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: featurePrefix │ │ │ │ + * {String} Namespace alias for feature type. Default is "feature". │ │ │ │ */ │ │ │ │ - setExtent: function() { │ │ │ │ - OpenLayers.Renderer.prototype.setExtent.apply(this, arguments); │ │ │ │ - // always redraw features │ │ │ │ - return false; │ │ │ │ - }, │ │ │ │ + featurePrefix: "feature", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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} │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - eraseGeometry: function(geometry, featureId) { │ │ │ │ - this.eraseFeatures(this.features[featureId][0]); │ │ │ │ - }, │ │ │ │ + formatOptions: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: supported │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the browser supports the renderer class │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - supported: function() { │ │ │ │ - return OpenLayers.CANVAS_SUPPORTED; │ │ │ │ - }, │ │ │ │ + readFormat: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setSize │ │ │ │ - * Sets the size of the drawing surface. │ │ │ │ - * │ │ │ │ - * Once the size is updated, redraw the canvas. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * size - {<OpenLayers.Size>} │ │ │ │ + * Property: readOptions │ │ │ │ + * {Object} Optional object to pass to format's read. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + readOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawFeature │ │ │ │ - * Draw the feature. Stores the feature in the features list, │ │ │ │ - * then redraws the layer. │ │ │ │ + * Constructor: OpenLayers.Protocol.WFS │ │ │ │ + * A class for giving layers WFS protocol. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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)); │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + if (!options.geometryName && parseFloat(this.format.version) > 1.0) { │ │ │ │ + this.setGeometryName(null); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawExternalGraphic │ │ │ │ - * Called to draw External graphics. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ - * featureId - {String} │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Clean up the protocol. │ │ │ │ */ │ │ │ │ - drawExternalGraphic: function(geometry, style, featureId) { │ │ │ │ - var img = new Image(); │ │ │ │ - │ │ │ │ - var title = style.title || style.graphicTitle; │ │ │ │ - if (title) { │ │ │ │ - img.title = title; │ │ │ │ + destroy: function() { │ │ │ │ + if (this.options && !this.options.format) { │ │ │ │ + this.format.destroy(); │ │ │ │ } │ │ │ │ - │ │ │ │ - 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; │ │ │ │ + this.format = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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} │ │ │ │ + * 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) │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - │ │ │ │ + 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" │ │ │ │ + }); │ │ │ │ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ │ │ │ │ - style.strokeWidth = unscaledStrokeWidth; │ │ │ │ - this.canvas.restore(); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.restore(); │ │ │ │ - } │ │ │ │ - this.setCanvasStyle("reset"); │ │ │ │ + return response; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setCanvasStyle │ │ │ │ - * Prepare the canvas for drawing by setting various global settings. │ │ │ │ + * APIMethod: setFeatureType │ │ │ │ + * Change the feature type on the fly. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * type - {String} one of 'stroke', 'fill', or 'reset' │ │ │ │ - * style - {Object} Symbolizer hash │ │ │ │ + * featureType - {String} Local (without prefix) feature typeName. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + setFeatureType: function(featureType) { │ │ │ │ + this.featureType = featureType; │ │ │ │ + this.format.featureType = featureType; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: featureIdToHex │ │ │ │ - * Convert a feature ID string into an RGB hex string. │ │ │ │ + * APIMethod: setGeometryName │ │ │ │ + * Sets the geometryName option after instantiation. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * featureId - {String} Feature id │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} RGB hex string. │ │ │ │ + * geometryName - {String} Name of geometry attribute. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + setGeometryName: function(geometryName) { │ │ │ │ + this.geometryName = geometryName; │ │ │ │ + this.format.geometryName = geometryName; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setHitContextStyle │ │ │ │ - * Prepare the hit canvas for drawing by setting various global settings. │ │ │ │ + * Method: handleRead │ │ │ │ + * Deal with response from the read request. │ │ │ │ * │ │ │ │ * 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} │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} The response object to pass │ │ │ │ + * to the user callback. │ │ │ │ + * options - {Object} The user options passed to the read call. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + handleRead: function(response, options) { │ │ │ │ + options = OpenLayers.Util.extend({}, options); │ │ │ │ + OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ │ │ │ │ - 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"); │ │ │ │ + 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: 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} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ - } │ │ │ │ + parseResponse: function(request, options) { │ │ │ │ + var doc = request.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = request.responseText; │ │ │ │ } │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ + if (!doc || doc.length <= 0) { │ │ │ │ + return null; │ │ │ │ } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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"; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - this.drawLinearRing( │ │ │ │ - components[i], │ │ │ │ - OpenLayers.Util.applyDefaults({ │ │ │ │ - fill: false │ │ │ │ - }, style), │ │ │ │ - featureId │ │ │ │ - ); │ │ │ │ } │ │ │ │ + return result; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawText │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ + * 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: │ │ │ │ - * location - {<OpenLayers.Point>} │ │ │ │ - * style - {Object} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - drawText: function(location, style) { │ │ │ │ - var pt = this.getLocalXY(location); │ │ │ │ + commit: function(features, options) { │ │ │ │ │ │ │ │ - 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"); │ │ │ │ - }, │ │ │ │ + options = OpenLayers.Util.extend({}, options); │ │ │ │ + OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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]; │ │ │ │ - }, │ │ │ │ + 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) │ │ │ │ + }); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - } │ │ │ │ + return response; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getFeatureIdFromEvent │ │ │ │ - * Returns a feature id from an event on the renderer. │ │ │ │ + * Method: handleCommit │ │ │ │ + * Called when the commit request returns. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} The response object to pass │ │ │ │ + * to the user callback. │ │ │ │ + * options - {Object} The user options passed to the commit call. │ │ │ │ */ │ │ │ │ - getFeatureIdFromEvent: function(evt) { │ │ │ │ - var featureId, feature; │ │ │ │ + handleCommit: function(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + var request = response.priv; │ │ │ │ │ │ │ │ - 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. │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + // 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); │ │ │ │ } │ │ │ │ - return feature; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: eraseFeatures │ │ │ │ - * This is called by the layer to erase features; removes the feature from │ │ │ │ - * the list, then redraws the layer. │ │ │ │ + * Method: filterDelete │ │ │ │ + * Send a request that deletes all features by their filter. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ + * filter - {<OpenLayers.Filter>} filter │ │ │ │ */ │ │ │ │ - eraseFeatures: function(features) { │ │ │ │ - if (!(OpenLayers.Util.isArray(features))) { │ │ │ │ - features = [features]; │ │ │ │ - } │ │ │ │ - for (var i = 0; i < features.length; ++i) { │ │ │ │ - delete this.features[features[i].id]; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - this.redraw(); │ │ │ │ + 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: 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. │ │ │ │ + * 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>} │ │ │ │ */ │ │ │ │ - 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]); │ │ │ │ - } │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + response.priv.abort(); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.Canvas" │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.WFS.v1" │ │ │ │ }); │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * 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/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 │ │ │ │ @@ -28022,3720 +28092,54 @@ │ │ │ │ write: function(object) { │ │ │ │ throw new Error('Write not implemented.'); │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/JSON.js │ │ │ │ + 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. */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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.JSON = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ +OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: indent │ │ │ │ - * {String} For "pretty" printing, the indent string will be used once for │ │ │ │ - * each indentation level. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - indent: " ", │ │ │ │ + namespaces: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: space │ │ │ │ - * {String} For "pretty" printing, the space string will be used after │ │ │ │ - * the ":" separating a name/value pair. │ │ │ │ + * Property: namespaceAlias │ │ │ │ + * {Object} Mapping of namespace URI to namespace alias. This object │ │ │ │ + * is read-only. Use <setNamespace> to add or set a namespace alias. │ │ │ │ */ │ │ │ │ - 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/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/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/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/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/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/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/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/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, │ │ │ │ + namespaceAlias: null, │ │ │ │ │ │ │ │ /** │ │ │ │ * Property: defaultPrefix │ │ │ │ * {String} The default namespace alias for creating element nodes. │ │ │ │ */ │ │ │ │ defaultPrefix: null, │ │ │ │ │ │ │ │ @@ -32594,9686 +28998,13282 @@ │ │ │ │ /** │ │ │ │ * 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/Request.js │ │ │ │ + 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/Events.js │ │ │ │ - * @requires OpenLayers/Request/XMLHttpRequest.js │ │ │ │ + * @requires OpenLayers/Format.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * TODO: deprecate me │ │ │ │ - * Use OpenLayers.Request.proxy instead. │ │ │ │ + * 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.ProxyHost = ""; │ │ │ │ +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); │ │ │ │ +}; │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Constant: OpenLayers.Format.WFST.DEFAULTS │ │ │ │ + * {Object} Default properties for the WFST format. │ │ │ │ */ │ │ │ │ -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, { │ │ │ │ +OpenLayers.Format.WFST.DEFAULTS = { │ │ │ │ + "version": "1.0.0" │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Filter.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: DEFAULT_CONFIG │ │ │ │ - * {Object} Default configuration for all requests. │ │ │ │ +/* 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>} │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: URL_SPLIT_REGEX │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Remove reference to anything added. │ │ │ │ */ │ │ │ │ - URL_SPLIT_REGEX: /([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/, │ │ │ │ + destroy: function() {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: evaluate │ │ │ │ + * Evaluates this filter in a specific context. Instances or subclasses │ │ │ │ + * are supposed to override this method. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - events: new OpenLayers.Events(this), │ │ │ │ + evaluate: function(context) { │ │ │ │ + return true; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: clone │ │ │ │ + * Clones this filter. Should be implemented by subclasses. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Filter>} Clone of this filter. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + clone: function() { │ │ │ │ + return null; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: toString │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {XMLHttpRequest} Request object. To abort the request before a response │ │ │ │ - * is received, call abort() on the request object. │ │ │ │ + * {String} Include <OpenLayers.Format.CQL> in your build to get a CQL │ │ │ │ + * representation of the filter returned. Otherwise "[Object object]" │ │ │ │ + * will be returned. │ │ │ │ */ │ │ │ │ - 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]); │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - var events = this.events; │ │ │ │ + CLASS_NAME: "OpenLayers.Filter" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Filter/Spatial.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - // we want to execute runCallbacks with "this" as the │ │ │ │ - // execution scope │ │ │ │ - var self = this; │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }; │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Filter.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - // 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; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * 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, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: type │ │ │ │ + * {String} Type of spatial filter. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Hash containing request, config and requestUrl keys │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + type: null, │ │ │ │ │ │ │ │ - // optional failure callback │ │ │ │ - var failure; │ │ │ │ - if (config.failure) { │ │ │ │ - failure = (config.scope) ? │ │ │ │ - OpenLayers.Function.bind(config.failure, config.scope) : │ │ │ │ - config.failure; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: property │ │ │ │ + * {String} Name of the context property to compare. │ │ │ │ + */ │ │ │ │ + property: null, │ │ │ │ │ │ │ │ - if (OpenLayers.Util.createUrlObject(config.url).protocol == "file:" && │ │ │ │ - request.responseText) { │ │ │ │ - request.status = 200; │ │ │ │ - } │ │ │ │ - complete(request); │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * APIProperty: distance │ │ │ │ + * {Number} The distance to use in a DWithin spatial filter. │ │ │ │ + */ │ │ │ │ + distance: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: GET │ │ │ │ - * Send an HTTP GET request. Additional configuration properties are │ │ │ │ - * documented in the <issue> method, with the method property set │ │ │ │ - * to GET. │ │ │ │ + * APIProperty: distanceUnits │ │ │ │ + * {String} The units to use for the distance, e.g. 'm'. │ │ │ │ + */ │ │ │ │ + distanceUnits: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Filter.Spatial │ │ │ │ + * Creates a spatial filter. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * options - {Object} An optional object with properties to set on the │ │ │ │ + * filter. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {XMLHttpRequest} Request object. │ │ │ │ + * {<OpenLayers.Filter.Spatial>} │ │ │ │ */ │ │ │ │ - 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". │ │ │ │ - * │ │ │ │ + * Method: evaluate │ │ │ │ + * Evaluates this filter for a specific feature. │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} feature to apply the filter to. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {XMLHttpRequest} Request object. │ │ │ │ + * {Boolean} The feature meets filter criteria. │ │ │ │ */ │ │ │ │ - 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"; │ │ │ │ + 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 OpenLayers.Request.issue(config); │ │ │ │ + return intersect; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: clone │ │ │ │ + * Clones this filter. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {XMLHttpRequest} Request object. │ │ │ │ + * {<OpenLayers.Filter.Spatial>} Clone of this filter. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: DELETE │ │ │ │ - * Send an HTTP DELETE request. Additional configuration properties are │ │ │ │ - * documented in the <issue> method, with the method property set │ │ │ │ - * to DELETE. │ │ │ │ +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/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: │ │ │ │ - * 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. │ │ │ │ + * options - {Object} An optional object with properties to set on the │ │ │ │ + * rule │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {XMLHttpRequest} Request object. │ │ │ │ + * {<OpenLayers.Filter.FeatureId>} │ │ │ │ */ │ │ │ │ - DELETE: function(config) { │ │ │ │ - config = OpenLayers.Util.extend(config, { │ │ │ │ - method: "DELETE" │ │ │ │ - }); │ │ │ │ - return OpenLayers.Request.issue(config); │ │ │ │ + initialize: function(options) { │ │ │ │ + this.fids = []; │ │ │ │ + OpenLayers.Filter.prototype.initialize.apply(this, [options]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: HEAD │ │ │ │ - * Send an HTTP HEAD request. Additional configuration properties are │ │ │ │ - * documented in the <issue> method, with the method property set │ │ │ │ - * to HEAD. │ │ │ │ - * │ │ │ │ + * APIMethod: evaluate │ │ │ │ + * evaluates this rule for a specific feature │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * 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: │ │ │ │ - * {XMLHttpRequest} Request object. │ │ │ │ + * {Boolean} true if the rule applies, false if it does not │ │ │ │ */ │ │ │ │ - HEAD: function(config) { │ │ │ │ - config = OpenLayers.Util.extend(config, { │ │ │ │ - method: "HEAD" │ │ │ │ - }); │ │ │ │ - return OpenLayers.Request.issue(config); │ │ │ │ + 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: 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. │ │ │ │ + * APIMethod: clone │ │ │ │ + * Clones this filter. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {XMLHttpRequest} Request object. │ │ │ │ + * {<OpenLayers.Filter.FeatureId>} Clone of this filter. │ │ │ │ */ │ │ │ │ - OPTIONS: function(config) { │ │ │ │ - config = OpenLayers.Util.extend(config, { │ │ │ │ - method: "OPTIONS" │ │ │ │ - }); │ │ │ │ - return OpenLayers.Request.issue(config); │ │ │ │ - } │ │ │ │ + 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/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 │ │ │ │ + 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/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 │ │ │ │ + * @requires OpenLayers/Format/WFST.js │ │ │ │ + * @requires OpenLayers/Filter/Spatial.js │ │ │ │ + * @requires OpenLayers/Filter/FeatureId.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.KML │ │ │ │ - * Read/Write KML. Create a new instance with the <OpenLayers.Format.KML> │ │ │ │ - * constructor. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.WFST.v1 │ │ │ │ + * Superclass for WFST parsers. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ +OpenLayers.Format.WFST.v1 = 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" │ │ │ │ + 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" │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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>. │ │ │ │ + * Property: defaultPrefix │ │ │ │ */ │ │ │ │ - trackAttributes: null, │ │ │ │ + defaultPrefix: "wfs", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: internalns │ │ │ │ - * {String} KML Namespace to use -- defaults to the namespace of the │ │ │ │ - * Placemark node being parsed, but falls back to kmlns. │ │ │ │ + * Property: version │ │ │ │ + * {String} WFS version number. │ │ │ │ */ │ │ │ │ - internalns: null, │ │ │ │ + version: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: features │ │ │ │ - * {Array} Array of features │ │ │ │ - * │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} Schema location for a particular minor version. │ │ │ │ */ │ │ │ │ - features: null, │ │ │ │ + schemaLocations: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: styles │ │ │ │ - * {Object} Storage of style objects │ │ │ │ - * │ │ │ │ + * APIProperty: srsName │ │ │ │ + * {String} URI for spatial reference system. │ │ │ │ */ │ │ │ │ - styles: null, │ │ │ │ + srsName: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: styleBaseUrl │ │ │ │ - * {String} │ │ │ │ + * APIProperty: extractAttributes │ │ │ │ + * {Boolean} Extract attributes from GML. Default is true. │ │ │ │ */ │ │ │ │ - styleBaseUrl: "", │ │ │ │ + extractAttributes: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: fetched │ │ │ │ - * {Object} Storage of KML URLs that have been fetched before │ │ │ │ - * in order to prevent reloading them. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - fetched: null, │ │ │ │ + xy: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: maxDepth │ │ │ │ - * {Integer} Maximum depth for recursive loading external KML URLs │ │ │ │ - * Defaults to 0: do no external fetching │ │ │ │ + * Property: stateName │ │ │ │ + * {Object} Maps feature states to node names. │ │ │ │ */ │ │ │ │ - maxDepth: 0, │ │ │ │ + stateName: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.KML │ │ │ │ - * Create a new parser for KML. │ │ │ │ + * 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) { │ │ │ │ - // 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"); │ │ │ │ - │ │ │ │ + // 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]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: getSrsName │ │ │ │ */ │ │ │ │ - read: function(data) { │ │ │ │ - this.features = []; │ │ │ │ - this.styles = {}; │ │ │ │ - this.fetched = {}; │ │ │ │ - │ │ │ │ - // Set default options │ │ │ │ - var options = { │ │ │ │ - depth: 0, │ │ │ │ - styleBaseUrl: this.styleBaseUrl │ │ │ │ - }; │ │ │ │ - │ │ │ │ - return this.parseData(data, options); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * 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(<OpenLayers.Feature.Vector>)} List of features. │ │ │ │ + * {Array | Object} Output depending on the output option. │ │ │ │ */ │ │ │ │ - parseData: function(data, options) { │ │ │ │ + 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]); │ │ │ │ } │ │ │ │ - │ │ │ │ - // 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; │ │ │ │ - } │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement; │ │ │ │ } │ │ │ │ - │ │ │ │ - return this.features; │ │ │ │ + var obj = {}; │ │ │ │ + if (data) { │ │ │ │ + this.readNode(data, obj, true); │ │ │ │ + } │ │ │ │ + if (obj.features && options.output === "features") { │ │ │ │ + obj = obj.features; │ │ │ │ + } │ │ │ │ + return obj; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ - * │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + readers: { │ │ │ │ + "wfs": { │ │ │ │ + "FeatureCollection": function(node, obj) { │ │ │ │ + obj.features = []; │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ } │ │ │ │ } │ │ │ │ - │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: fetchLink │ │ │ │ - * Fetches a URL and returns the result │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * href - {String} url to be fetched │ │ │ │ - * │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - fetchLink: function(href) { │ │ │ │ - var request = OpenLayers.Request.GET({ │ │ │ │ - url: href, │ │ │ │ - async: false │ │ │ │ + write: function(features, options) { │ │ │ │ + var node = this.writeNode("wfs:Transaction", { │ │ │ │ + features: features, │ │ │ │ + options: options │ │ │ │ }); │ │ │ │ - if (request) { │ │ │ │ - return request.responseText; │ │ │ │ + var value = this.schemaLocationAttr(); │ │ │ │ + if (value) { │ │ │ │ + this.setAttributeNS( │ │ │ │ + node, this.namespaces["xsi"], "xsi:schemaLocation", value │ │ │ │ + ); │ │ │ │ } │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [node]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseStyles │ │ │ │ - * Parses <Style> nodes │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * nodes - {Array} of {DOMElement} data to read/parse. │ │ │ │ - * options - {Object} Hash of options │ │ │ │ - * │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ │ │ │ │ - this.styles[styleName] = style; │ │ │ │ + // 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: 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 │ │ │ │ + * Method: schemaLocationAttr │ │ │ │ + * Generate the xsi:schemaLocation attribute value. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} │ │ │ │ + * {String} The xsi:schemaLocation attribute or undefined if none. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }; │ │ │ │ + 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]); │ │ │ │ } │ │ │ │ } │ │ │ │ - return color; │ │ │ │ + var value = parts.join(" ") || undefined; │ │ │ │ + return value; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseStyle │ │ │ │ - * Parses the children of a <Style> node and builds the style hash │ │ │ │ - * accordingly │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} <Style> node │ │ │ │ - * │ │ │ │ + * Method: setFilterProperty │ │ │ │ + * Set the property of each spatial filter. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * filter - {<OpenLayers.Filter>} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - // 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; │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFST.v1" │ │ │ │ │ │ │ │ - case "iconstyle": │ │ │ │ - // set scale │ │ │ │ - var scale = parseFloat(this.parseProperty(styleTypeNode, │ │ │ │ - "*", "scale") || 1); │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Geometry/MultiLineString.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - // set default width and height of icon │ │ │ │ - var width = 32 * scale; │ │ │ │ - var height = 32 * scale; │ │ │ │ +/* 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 iconNode = this.getElementsByTagNameNS(styleTypeNode, │ │ │ │ - "*", │ │ │ │ - "Icon")[0]; │ │ │ │ - if (iconNode) { │ │ │ │ - var href = this.parseProperty(iconNode, "*", "href"); │ │ │ │ - if (href) { │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Geometry/Collection.js │ │ │ │ + * @requires OpenLayers/Geometry/LineString.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - var w = this.parseProperty(iconNode, "*", "w"); │ │ │ │ - var h = this.parseProperty(iconNode, "*", "h"); │ │ │ │ +/** │ │ │ │ + * 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, { │ │ │ │ │ │ │ │ - // 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; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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"], │ │ │ │ │ │ │ │ - // if only dimension is defined, make sure the │ │ │ │ - // other one has the same value │ │ │ │ - w = w || h; │ │ │ │ - h = h || w; │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Geometry.MultiLineString │ │ │ │ + * Constructor for a MultiLineString Geometry. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * components - {Array(<OpenLayers.Geometry.LineString>)} │ │ │ │ + * │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (w) { │ │ │ │ - width = parseInt(w) * scale; │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (h) { │ │ │ │ - height = parseInt(h) * scale; │ │ │ │ + /** │ │ │ │ + * 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()]; │ │ │ │ + } │ │ │ │ } │ │ │ │ - │ │ │ │ - // 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; │ │ │ │ + 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] │ │ │ │ + ]) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ } │ │ │ │ - │ │ │ │ - style["graphicOpacity"] = 1; // fully opaque │ │ │ │ - style["externalGraphic"] = href; │ │ │ │ + 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/Geometry/MultiPolygon.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - // 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")); │ │ │ │ +/* 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 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; │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Geometry/Collection.js │ │ │ │ + * @requires OpenLayers/Geometry/Polygon.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * 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, { │ │ │ │ │ │ │ │ - style["graphicWidth"] = width; │ │ │ │ - style["graphicHeight"] = height; │ │ │ │ - break; │ │ │ │ + /** │ │ │ │ + * 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"], │ │ │ │ │ │ │ │ - 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; │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Geometry.MultiPolygon │ │ │ │ + * Create a new MultiPolygon geometry │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * components - {Array(<OpenLayers.Geometry.Polygon>)} An array of polygons │ │ │ │ + * used to generate the MultiPolygon │ │ │ │ + * │ │ │ │ + */ │ │ │ │ │ │ │ │ - default: │ │ │ │ - } │ │ │ │ - } │ │ │ │ + CLASS_NAME: "OpenLayers.Geometry.MultiPolygon" │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/GML.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - // Some polygons have no line color, so we use the fillColor for that │ │ │ │ - if (!style["strokeColor"] && style["fillColor"]) { │ │ │ │ - style["strokeColor"] = style["fillColor"]; │ │ │ │ - } │ │ │ │ +/* 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 id = node.getAttribute("id"); │ │ │ │ - if (id && style) { │ │ │ │ - style.id = id; │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * @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 │ │ │ │ + */ │ │ │ │ │ │ │ │ - return style; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * 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, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ - * │ │ │ │ + * APIProperty: featureNS │ │ │ │ + * {String} Namespace used for feature attributes. Default is │ │ │ │ + * "http://mapserver.gis.umn.edu/mapserver". │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ + featureNS: "http://mapserver.gis.umn.edu/mapserver", │ │ │ │ │ │ │ │ - if (styleUrl && key == "normal") { │ │ │ │ - this.styles[(options.styleBaseUrl || "") + "#" + id] = │ │ │ │ - this.styles[(options.styleBaseUrl || "") + styleUrl]; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: featurePrefix │ │ │ │ + * {String} Namespace alias (or prefix) for feature nodes. Default is │ │ │ │ + * "feature". │ │ │ │ + */ │ │ │ │ + featurePrefix: "feature", │ │ │ │ │ │ │ │ - // TODO: implement the "select" part │ │ │ │ - //if (styleUrl && key == "highlight") { │ │ │ │ - //} │ │ │ │ + /** │ │ │ │ + * 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", │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ - * │ │ │ │ + * APIProperty: gmlns │ │ │ │ + * {String} GML Namespace. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + gmlns: "http://www.opengis.net/gml", │ │ │ │ │ │ │ │ - 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 │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: extractAttributes │ │ │ │ + * {Boolean} Extract attributes from GML. │ │ │ │ + */ │ │ │ │ + extractAttributes: true, │ │ │ │ │ │ │ │ - // 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - // add new features to existing feature list │ │ │ │ - this.features = this.features.concat(features); │ │ │ │ + /** │ │ │ │ + * 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]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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 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. │ │ │ │ - * │ │ │ │ + * 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} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} A vector feature. │ │ │ │ + * node - {DOMElement} A GML feature node. │ │ │ │ */ │ │ │ │ parseFeature: function(node) { │ │ │ │ // only accept one geometry per feature - look for highest "order" │ │ │ │ - var order = ["MultiGeometry", "Polygon", "LineString", "Point"]; │ │ │ │ + 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, len = order.length; i < len; ++i) { │ │ │ │ + for (var i = 0; i < order.length; ++i) { │ │ │ │ type = order[i]; │ │ │ │ - this.internalns = node.namespaceURI ? │ │ │ │ - node.namespaceURI : this.kmlns; │ │ │ │ - nodeList = this.getElementsByTagNameNS(node, │ │ │ │ - this.internalns, type); │ │ │ │ + nodeList = this.getElementsByTagNameNS(node, this.gmlns, type); │ │ │ │ if (nodeList.length > 0) { │ │ │ │ // only deal with first geometry of this type │ │ │ │ - var parser = this.parseGeometry[type.toLowerCase()]; │ │ │ │ + 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; │ │ │ │ │ │ │ │ - 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]) { │ │ │ │ + feature.gml = { │ │ │ │ + featureType: node.firstChild.nodeName.split(":")[1], │ │ │ │ + featureNS: node.firstChild.namespaceURI, │ │ │ │ + featureNSPrefix: node.firstChild.prefix │ │ │ │ + }; │ │ │ │ │ │ │ │ - var data = this.fetchLink(styleBaseUrl); │ │ │ │ - if (data) { │ │ │ │ - this.parseData(data, newOptions); │ │ │ │ + // 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; │ │ │ │ } │ │ │ │ - │ │ │ │ - // return requested style │ │ │ │ - var style = OpenLayers.Util.extend({}, this.styles[styleUrl]); │ │ │ │ - return style; │ │ │ │ + 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 KML node representing a point geometry, create an OpenLayers │ │ │ │ + * Given a GML node representing a point geometry, create an OpenLayers │ │ │ │ * point geometry. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} A KML Point node. │ │ │ │ + * node - {DOMElement} A GML node. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ * {<OpenLayers.Geometry.Point>} A point geometry. │ │ │ │ */ │ │ │ │ point: function(node) { │ │ │ │ - var nodeList = this.getElementsByTagNameNS(node, this.internalns, │ │ │ │ - "coordinates"); │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ - var coordString = nodeList[0].firstChild.nodeValue; │ │ │ │ - coordString = coordString.replace(this.regExes.removeSpace, ""); │ │ │ │ - coords = coordString.split(","); │ │ │ │ + coordString = nodeList[0].firstChild.nodeValue; │ │ │ │ + coordString = coordString.replace(this.regExes.trimSpace, ""); │ │ │ │ + coords = coordString.split(this.regExes.splitSpace); │ │ │ │ } │ │ │ │ │ │ │ │ - var point = null; │ │ │ │ - if (coords.length > 1) { │ │ │ │ - // preserve third dimension │ │ │ │ - if (coords.length == 2) { │ │ │ │ - coords[2] = null; │ │ │ │ + // 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(","); │ │ │ │ } │ │ │ │ - point = new OpenLayers.Geometry.Point(coords[0], coords[1], │ │ │ │ + } │ │ │ │ + │ │ │ │ + // 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 { │ │ │ │ - throw "Bad coordinate string: " + coordString; │ │ │ │ + return new OpenLayers.Geometry.Point(coords[1], coords[0], │ │ │ │ + coords[2]); │ │ │ │ } │ │ │ │ - return point; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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 KML node representing a linestring geometry, create an │ │ │ │ + * Given a GML node representing a linestring geometry, create an │ │ │ │ * OpenLayers linestring geometry. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} A KML LineString node. │ │ │ │ + * node - {DOMElement} A GML node. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ * {<OpenLayers.Geometry.LineString>} A linestring geometry. │ │ │ │ */ │ │ │ │ linestring: function(node, ring) { │ │ │ │ - var nodeList = this.getElementsByTagNameNS(node, this.internalns, │ │ │ │ - "coordinates"); │ │ │ │ - var line = null; │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ - var coordString = this.getChildValue(nodeList[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)); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - 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) { │ │ │ │ + // 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; │ │ │ │ } │ │ │ │ - points[i] = new OpenLayers.Geometry.Point(coords[0], │ │ │ │ - coords[1], │ │ │ │ - coords[2]); │ │ │ │ - } else { │ │ │ │ - throw "Bad LineString point coordinates: " + │ │ │ │ - pointList[i]; │ │ │ │ + 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])); │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ - if (numPoints) { │ │ │ │ - if (ring) { │ │ │ │ - line = new OpenLayers.Geometry.LinearRing(points); │ │ │ │ - } else { │ │ │ │ - line = new OpenLayers.Geometry.LineString(points); │ │ │ │ - } │ │ │ │ + } │ │ │ │ + │ │ │ │ + var line = null; │ │ │ │ + if (points.length != 0) { │ │ │ │ + if (ring) { │ │ │ │ + line = new OpenLayers.Geometry.LinearRing(points); │ │ │ │ } else { │ │ │ │ - throw "Bad LineString coordinates: " + coordString; │ │ │ │ + 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 KML node representing a polygon geometry, create an │ │ │ │ + * Given a GML node representing a polygon geometry, create an │ │ │ │ * OpenLayers polygon geometry. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} A KML Polygon node. │ │ │ │ + * node - {DOMElement} A GML node. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ * {<OpenLayers.Geometry.Polygon>} A polygon geometry. │ │ │ │ */ │ │ │ │ polygon: function(node) { │ │ │ │ - var nodeList = this.getElementsByTagNameNS(node, this.internalns, │ │ │ │ + var nodeList = this.getElementsByTagNameNS(node, this.gmlns, │ │ │ │ "LinearRing"); │ │ │ │ - var numRings = nodeList.length; │ │ │ │ - var components = new Array(numRings); │ │ │ │ - if (numRings > 0) { │ │ │ │ + var components = []; │ │ │ │ + if (nodeList.length > 0) { │ │ │ │ // this assumes exterior ring first, inner rings after │ │ │ │ var ring; │ │ │ │ - for (var i = 0, len = nodeList.length; i < len; ++i) { │ │ │ │ + for (var i = 0; i < nodeList.length; ++i) { │ │ │ │ ring = this.parseGeometry.linestring.apply(this, │ │ │ │ [nodeList[i], true]); │ │ │ │ if (ring) { │ │ │ │ - components[i] = ring; │ │ │ │ - } else { │ │ │ │ - throw "Bad LinearRing geometry: " + i; │ │ │ │ + components.push(ring); │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ return new OpenLayers.Geometry.Polygon(components); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseGeometry.multigeometry │ │ │ │ - * Given a KML node representing a multigeometry, create an │ │ │ │ - * OpenLayers geometry collection. │ │ │ │ + * Method: parseGeometry.multipolygon │ │ │ │ + * Given a GML node representing a multipolygon geometry, create an │ │ │ │ + * OpenLayers multipolygon geometry. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} A KML MultiGeometry node. │ │ │ │ + * node - {DOMElement} A GML node. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Geometry.Collection>} A geometry collection. │ │ │ │ + * {<OpenLayers.Geometry.MultiPolygon>} A multipolygon geometry. │ │ │ │ */ │ │ │ │ - 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])); │ │ │ │ + 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.Collection(parts); │ │ │ │ - } │ │ │ │ + return new OpenLayers.Geometry.MultiPolygon(components); │ │ │ │ + }, │ │ │ │ │ │ │ │ - }, │ │ │ │ + envelope: function(node) { │ │ │ │ + var components = []; │ │ │ │ + var coordString; │ │ │ │ + var envelope; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: parseAttributes │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An attributes object. │ │ │ │ - */ │ │ │ │ - parseAttributes: function(node) { │ │ │ │ - var attributes = {}; │ │ │ │ + var lpoint = this.getElementsByTagNameNS(node, this.gmlns, "lowerCorner"); │ │ │ │ + if (lpoint.length > 0) { │ │ │ │ + var coords = []; │ │ │ │ │ │ │ │ - // Extended Data is parsed first. │ │ │ │ - var edNodes = node.getElementsByTagName("ExtendedData"); │ │ │ │ - if (edNodes.length) { │ │ │ │ - attributes = this.parseExtendedData(edNodes[0]); │ │ │ │ - } │ │ │ │ + if (lpoint.length > 0) { │ │ │ │ + coordString = lpoint[0].firstChild.nodeValue; │ │ │ │ + coordString = coordString.replace(this.regExes.trimSpace, ""); │ │ │ │ + coords = coordString.split(this.regExes.splitSpace); │ │ │ │ + } │ │ │ │ │ │ │ │ - // assume attribute nodes are type 1 children with a type 3 or 4 child │ │ │ │ - var child, grandchildren, grandchild; │ │ │ │ - var children = node.childNodes; │ │ │ │ + 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]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 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]); │ │ │ │ } │ │ │ │ } │ │ │ │ - } │ │ │ │ - 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 (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]); │ │ │ │ } │ │ │ │ - if (this.kvpAttributes) { │ │ │ │ - attributes[key] = ed['value']; │ │ │ │ - } else { │ │ │ │ - var nameNode = data.getElementsByTagName("displayName"); │ │ │ │ - if (nameNode.length) { │ │ │ │ - ed['displayName'] = this.getChildValue(nameNode[0]); │ │ │ │ + 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(","); │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + if (beginPoint !== null && endPoint !== null) { │ │ │ │ + return new OpenLayers.Bounds(parseFloat(beginPoint[0]), │ │ │ │ + parseFloat(beginPoint[1]), │ │ │ │ + parseFloat(endPoint[0]), │ │ │ │ + parseFloat(endPoint[1])); │ │ │ │ } │ │ │ │ } │ │ │ │ │ │ │ │ - return attributes; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseProperty │ │ │ │ - * Convenience method to find a node and return its value │ │ │ │ + * Method: parseAttributes │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * xmlNode - {<DOMElement>} │ │ │ │ - * namespace - {String} namespace of the node to find │ │ │ │ - * tagName - {String} name of the property to parse │ │ │ │ - * │ │ │ │ + * node - {DOMElement} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {String} The value for the requested property (defaults to null) │ │ │ │ + * {Object} An attributes object. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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 value; │ │ │ │ + return attributes; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: write │ │ │ │ - * Accept Feature Collection, and return a string. │ │ │ │ + * Generate a GML document string given a list of features. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} An array of features. │ │ │ │ + * features - {Array(<OpenLayers.Feature.Vector>)} List of features to │ │ │ │ + * serialize into a string. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} A KML string. │ │ │ │ + * {String} A string representing the GML document. │ │ │ │ */ │ │ │ │ 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); │ │ │ │ + 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 folder; │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [gml]); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: createPlacemarkXML │ │ │ │ - * Creates and returns a KML placemark node representing the given feature. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: createFeatureXML │ │ │ │ + * Accept an OpenLayers.Feature.Vector, and build a GML node for it. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - * │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature to be built as GML. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * {DOMElement} A node reprensting the feature in GML. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - │ │ │ │ - return placemarkNode; │ │ │ │ + featureNode.appendChild(featureContainer); │ │ │ │ + return featureNode; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: buildGeometryNode │ │ │ │ - * Builds and returns a KML geometry node with the given geometry. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * 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()]; │ │ │ │ - var node = null; │ │ │ │ - if (builder) { │ │ │ │ - node = builder.apply(this, [geometry]); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ + return builder.apply(this, [geometry]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * 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)? │ │ │ │ + // 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 KML point. │ │ │ │ + * Given an OpenLayers point geometry, create a GML point. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * geometry - {<OpenLayers.Geometry.Point>} A point geometry. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} A KML point node. │ │ │ │ + * {DOMElement} A GML point node. │ │ │ │ */ │ │ │ │ point: function(geometry) { │ │ │ │ - var kml = this.createElementNS(this.kmlns, "Point"); │ │ │ │ - kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ - return kml; │ │ │ │ + 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 KML │ │ │ │ - * GeometryCollection. │ │ │ │ + * Given an OpenLayers multipoint geometry, create a GML multipoint. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry.Point>} A multipoint geometry. │ │ │ │ + * geometry - {<OpenLayers.Geometry.MultiPoint>} A multipoint geometry. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} A KML GeometryCollection node. │ │ │ │ + * {DOMElement} A GML multipoint node. │ │ │ │ */ │ │ │ │ multipoint: function(geometry) { │ │ │ │ - return this.buildGeometry.collection.apply(this, [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 KML linestring. │ │ │ │ + * Given an OpenLayers linestring geometry, create a GML linestring. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * geometry - {<OpenLayers.Geometry.LineString>} A linestring geometry. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} A KML linestring node. │ │ │ │ + * {DOMElement} A GML linestring node. │ │ │ │ */ │ │ │ │ linestring: function(geometry) { │ │ │ │ - var kml = this.createElementNS(this.kmlns, "LineString"); │ │ │ │ - kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ - return kml; │ │ │ │ + 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 KML │ │ │ │ - * GeometryCollection. │ │ │ │ + * Given an OpenLayers multilinestring geometry, create a GML │ │ │ │ + * multilinestring. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry.Point>} A multilinestring geometry. │ │ │ │ + * geometry - {<OpenLayers.Geometry.MultiLineString>} A multilinestring │ │ │ │ + * geometry. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} A KML GeometryCollection node. │ │ │ │ + * {DOMElement} A GML multilinestring node. │ │ │ │ */ │ │ │ │ multilinestring: function(geometry) { │ │ │ │ - return this.buildGeometry.collection.apply(this, [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 KML linearring. │ │ │ │ + * Given an OpenLayers linearring geometry, create a GML linearring. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * geometry - {<OpenLayers.Geometry.LinearRing>} A linearring geometry. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} A KML linearring node. │ │ │ │ + * {DOMElement} A GML linearring node. │ │ │ │ */ │ │ │ │ linearring: function(geometry) { │ │ │ │ - var kml = this.createElementNS(this.kmlns, "LinearRing"); │ │ │ │ - kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ - return kml; │ │ │ │ + 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 KML polygon. │ │ │ │ + * Given an OpenLayers polygon geometry, create a GML polygon. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * geometry - {<OpenLayers.Geometry.Polygon>} A polygon geometry. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} A KML polygon node. │ │ │ │ + * {DOMElement} A GML polygon node. │ │ │ │ */ │ │ │ │ polygon: function(geometry) { │ │ │ │ - var kml = this.createElementNS(this.kmlns, "Polygon"); │ │ │ │ + var gml = this.createElementNS(this.gmlns, "gml:Polygon"); │ │ │ │ var rings = geometry.components; │ │ │ │ var ringMember, ringGeom, type; │ │ │ │ - for (var i = 0, len = rings.length; i < len; ++i) { │ │ │ │ + for (var i = 0; i < rings.length; ++i) { │ │ │ │ type = (i == 0) ? "outerBoundaryIs" : "innerBoundaryIs"; │ │ │ │ - ringMember = this.createElementNS(this.kmlns, type); │ │ │ │ + ringMember = this.createElementNS(this.gmlns, │ │ │ │ + "gml:" + type); │ │ │ │ ringGeom = this.buildGeometry.linearring.apply(this, │ │ │ │ [rings[i]]); │ │ │ │ ringMember.appendChild(ringGeom); │ │ │ │ - kml.appendChild(ringMember); │ │ │ │ + gml.appendChild(ringMember); │ │ │ │ } │ │ │ │ - return kml; │ │ │ │ + return gml; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * Method: buildGeometry.multipolygon │ │ │ │ - * Given an OpenLayers multipolygon geometry, create a KML │ │ │ │ - * GeometryCollection. │ │ │ │ + * Given an OpenLayers multipolygon geometry, create a GML multipolygon. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry.Point>} A multipolygon geometry. │ │ │ │ + * geometry - {<OpenLayers.Geometry.MultiPolygon>} A multipolygon │ │ │ │ + * geometry. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} A KML GeometryCollection node. │ │ │ │ + * {DOMElement} A GML multipolygon node. │ │ │ │ */ │ │ │ │ multipolygon: function(geometry) { │ │ │ │ - return this.buildGeometry.collection.apply(this, [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.collection │ │ │ │ - * Given an OpenLayers geometry collection, create a KML MultiGeometry. │ │ │ │ + * Method: buildGeometry.bounds │ │ │ │ + * Given an OpenLayers bounds, create a GML box. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry.Collection>} A geometry collection. │ │ │ │ + * bounds - {<OpenLayers.Geometry.Bounds>} A bounds object. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} A KML MultiGeometry node. │ │ │ │ + * {DOMElement} A GML box 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; │ │ │ │ + bounds: function(bounds) { │ │ │ │ + var gml = this.createElementNS(this.gmlns, "gml:Box"); │ │ │ │ + gml.appendChild(this.buildCoordinatesNode(bounds)); │ │ │ │ + return gml; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: buildCoordinatesNode │ │ │ │ - * Builds and returns the KML coordinates node with the given geometry │ │ │ │ - * <coordinates>...</coordinates> │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ + * Method: buildCoordinates │ │ │ │ + * builds the coordinates XmlNode │ │ │ │ + * (code) │ │ │ │ + * <gml:coordinates decimal="." cs="," ts=" ">...</gml:coordinates> │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * {XmlNode} created xmlNode │ │ │ │ */ │ │ │ │ buildCoordinatesNode: function(geometry) { │ │ │ │ - var coordinatesNode = this.createElementNS(this.kmlns, "coordinates"); │ │ │ │ + var coordinatesNode = this.createElementNS(this.gmlns, │ │ │ │ + "gml:coordinates"); │ │ │ │ + coordinatesNode.setAttribute("decimal", "."); │ │ │ │ + coordinatesNode.setAttribute("cs", ","); │ │ │ │ + coordinatesNode.setAttribute("ts", " "); │ │ │ │ │ │ │ │ - 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(" "); │ │ │ │ + var parts = []; │ │ │ │ + │ │ │ │ + if (geometry instanceof OpenLayers.Bounds) { │ │ │ │ + parts.push(geometry.left + "," + geometry.bottom); │ │ │ │ + parts.push(geometry.right + "," + geometry.top); │ │ │ │ } else { │ │ │ │ - // Point │ │ │ │ - path = this.buildCoordinates(geometry); │ │ │ │ + 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(path); │ │ │ │ + var txtNode = this.createTextNode(parts.join(" ")); │ │ │ │ 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" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.GML" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Handler/Point.js │ │ │ │ + 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 │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * @requires OpenLayers/Handler.js │ │ │ │ - * @requires OpenLayers/Geometry/Point.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.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. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.GML.Base │ │ │ │ + * Superclass for GML parsers. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Handler> │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: point │ │ │ │ - * {<OpenLayers.Feature.Vector>} The currently drawn point │ │ │ │ - */ │ │ │ │ - point: null, │ │ │ │ +OpenLayers.Format.GML.Base = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: layer │ │ │ │ - * {<OpenLayers.Layer.Vector>} The temporary drawing layer │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ - layer: null, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: multi │ │ │ │ - * {Boolean} Cast features to multi-part geometries before passing to the │ │ │ │ - * layer. Default is false. │ │ │ │ + * Property: defaultPrefix │ │ │ │ */ │ │ │ │ - multi: false, │ │ │ │ + defaultPrefix: "gml", │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} Schema location for a particular minor version. │ │ │ │ */ │ │ │ │ - citeCompliant: false, │ │ │ │ + schemaLocation: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: mouseDown │ │ │ │ - * {Boolean} The mouse is down │ │ │ │ + * APIProperty: featureType │ │ │ │ + * {Array(String) or String} The local (without prefix) feature typeName(s). │ │ │ │ */ │ │ │ │ - mouseDown: false, │ │ │ │ + featureType: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: stoppedDown │ │ │ │ - * {Boolean} Indicate whether the last mousedown stopped the event │ │ │ │ - * propagation. │ │ │ │ + * APIProperty: featureNS │ │ │ │ + * {String} The feature namespace. Must be set in the options at │ │ │ │ + * construction. │ │ │ │ */ │ │ │ │ - stoppedDown: null, │ │ │ │ + featureNS: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: lastDown │ │ │ │ - * {<OpenLayers.Pixel>} Location of the last mouse down │ │ │ │ + * APIProperty: geometry │ │ │ │ + * {String} Name of geometry element. Defaults to "geometry". If null, it │ │ │ │ + * will be set on <read> when the first geometry is parsed. │ │ │ │ */ │ │ │ │ - lastDown: null, │ │ │ │ + geometryName: "geometry", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: lastUp │ │ │ │ - * {<OpenLayers.Pixel>} │ │ │ │ + * APIProperty: extractAttributes │ │ │ │ + * {Boolean} Extract attributes from GML. Default is true. │ │ │ │ */ │ │ │ │ - lastUp: null, │ │ │ │ + extractAttributes: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - persist: false, │ │ │ │ + srsName: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: stopDown │ │ │ │ - * {Boolean} Stop event propagation on mousedown. Must be false to │ │ │ │ - * allow "pan while drawing". Defaults to false. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - stopDown: false, │ │ │ │ + xy: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIPropery: stopUp │ │ │ │ - * {Boolean} Stop event propagation on mouse. Must be false to │ │ │ │ - * allow "pan while dragging". Defaults to fase. │ │ │ │ + * Property: geometryTypes │ │ │ │ + * {Object} Maps OpenLayers geometry class names to GML element names. │ │ │ │ + * Use <setGeometryTypes> before accessing this property. │ │ │ │ */ │ │ │ │ - stopUp: false, │ │ │ │ + geometryTypes: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: layerOptions │ │ │ │ - * {Object} Any optional properties to be set on the sketch layer. │ │ │ │ + * Property: singleFeatureType │ │ │ │ + * {Boolean} True if there is only 1 featureType, and not an array │ │ │ │ + * of featuretypes. │ │ │ │ */ │ │ │ │ - layerOptions: null, │ │ │ │ + singleFeatureType: 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - pixelTolerance: 5, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: lastTouchPx │ │ │ │ - * {<OpenLayers.Pixel>} The last pixel used to know the distance between │ │ │ │ - * two touches (for double touch). │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ */ │ │ │ │ - lastTouchPx: null, │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g), │ │ │ │ + featureMember: (/^(.*:)?featureMembers?$/) │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Handler.Point │ │ │ │ - * Create a new point handler. │ │ │ │ + * 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: │ │ │ │ - * 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 │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * 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(control, callbacks, options) { │ │ │ │ - if (!(options && options.layerOptions && options.layerOptions.styleMap)) { │ │ │ │ - this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {}); │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ + this.setGeometryTypes(); │ │ │ │ + if (options && options.featureNS) { │ │ │ │ + this.setNamespace("feature", options.featureNS); │ │ │ │ } │ │ │ │ - │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ + this.singleFeatureType = !options || (typeof options.featureType === "string"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * turn on the handler │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - if (!OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - return false; │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ } │ │ │ │ - // 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; │ │ │ │ + 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: createFeature │ │ │ │ - * Add temporary 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: │ │ │ │ - * pixel - {<OpenLayers.Pixel>} A pixel location on the map. │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + 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]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * turn off the handler │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ } │ │ │ │ - this.layer = null; │ │ │ │ - return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroyFeature │ │ │ │ - * Destroy the temporary geometries │ │ │ │ + * Method: write │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * force - {Boolean} Destroy even if persist is true. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - destroyFeature: function(force) { │ │ │ │ - if (this.layer && (force || !this.persist)) { │ │ │ │ - this.layer.destroyFeatures(); │ │ │ │ + write: function(features) { │ │ │ │ + var name; │ │ │ │ + if (OpenLayers.Util.isArray(features)) { │ │ │ │ + name = "featureMembers"; │ │ │ │ + } else { │ │ │ │ + name = "featureMember"; │ │ │ │ } │ │ │ │ - this.point = null; │ │ │ │ + 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]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroyPersistedFeature │ │ │ │ - * Destroy the persisted 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. │ │ │ │ */ │ │ │ │ - destroyPersistedFeature: function() { │ │ │ │ - var layer = this.layer; │ │ │ │ - if (layer && layer.features.length > 1) { │ │ │ │ - this.layer.features[0].destroy(); │ │ │ │ + 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: finalize │ │ │ │ - * Finish the geometry and call the "done" callback. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * cancel - {Boolean} Call cancel instead of done callback. Default │ │ │ │ - * is false. │ │ │ │ + * Method: setGeometryTypes │ │ │ │ + * Sets the <geometryTypes> mapping. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * APIMethod: cancel │ │ │ │ - * Finish the geometry and call the "cancel" callback. │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} Schema location for a particular minor version. │ │ │ │ */ │ │ │ │ - cancel: function() { │ │ │ │ - this.finalize(true); │ │ │ │ - }, │ │ │ │ + schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: click │ │ │ │ - * Handle clicks. Clicks are stopped from propagating to other listeners │ │ │ │ - * on map.events or other dom elements. │ │ │ │ - * │ │ │ │ + * Constructor: OpenLayers.Format.GML.v2 │ │ │ │ + * Create a parser for GML v2. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} The browser event │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow event propagation │ │ │ │ + * Valid options properties: │ │ │ │ + * featureType - {String} Local (without prefix) feature typeName (required). │ │ │ │ + * featureNS - {String} Feature namespace (required). │ │ │ │ + * geometryName - {String} Geometry element name. │ │ │ │ */ │ │ │ │ - click: function(evt) { │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - return false; │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - dblclick: function(evt) { │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - return false; │ │ │ │ + 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: modifyFeature │ │ │ │ - * Modify the existing geometry given a pixel location. │ │ │ │ + * Method: write │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * pixel - {<OpenLayers.Pixel>} A pixel location on the map. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - modifyFeature: function(pixel) { │ │ │ │ - if (!this.point) { │ │ │ │ - this.createFeature(pixel); │ │ │ │ + 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 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(); │ │ │ │ - }, │ │ │ │ + var root = this.writeNode(name, features); │ │ │ │ + this.setAttributeNS( │ │ │ │ + root, this.namespaces["xsi"], │ │ │ │ + "xsi:schemaLocation", this.schemaLocation │ │ │ │ + ); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: drawFeature │ │ │ │ - * Render features on the temporary layer. │ │ │ │ - */ │ │ │ │ - drawFeature: function() { │ │ │ │ - this.layer.drawFeature(this.point, this.style); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [root]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getGeometry │ │ │ │ - * Return the sketch geometry. If <multi> is true, this will return │ │ │ │ - * a multi-part geometry. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Geometry.Point>} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - getGeometry: function() { │ │ │ │ - var geometry = this.point && this.point.geometry; │ │ │ │ - if (geometry && this.multi) { │ │ │ │ - geometry = new OpenLayers.Geometry.MultiPoint([geometry]); │ │ │ │ - } │ │ │ │ - return geometry; │ │ │ │ + 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/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, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: geometryClone │ │ │ │ - * Return a clone of the relevant geometry. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Geometry>} │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ - geometryClone: function() { │ │ │ │ - var geom = this.getGeometry(); │ │ │ │ - return geom && geom.clone(); │ │ │ │ + namespaces: { │ │ │ │ + ogc: "http://www.opengis.net/ogc" │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: mousedown │ │ │ │ - * Handle mousedown. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} The browser event │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow event propagation │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ */ │ │ │ │ - mousedown: function(evt) { │ │ │ │ - return this.down(evt); │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: touchstart │ │ │ │ - * Handle touchstart. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} The browser event │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow event propagation │ │ │ │ + * Property: defaultPrefix │ │ │ │ */ │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - this.lastTouchPx = evt.xy; │ │ │ │ - return this.down(evt); │ │ │ │ - }, │ │ │ │ + defaultPrefix: "ogc", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: mousemove │ │ │ │ - * Handle mousemove. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} The browser event │ │ │ │ + * Constructor: OpenLayers.Format.OGCExceptionReport │ │ │ │ + * Create a new parser for OGC exception reports. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow event propagation │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ */ │ │ │ │ - mousemove: function(evt) { │ │ │ │ - return this.move(evt); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: touchmove │ │ │ │ - * Handle touchmove. │ │ │ │ - * │ │ │ │ + * APIMethod: read │ │ │ │ + * Read OGC exception report data from a string, and return an object with │ │ │ │ + * information about the exceptions. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} The browser event │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ * │ │ │ │ - * 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 │ │ │ │ + * Returns: │ │ │ │ + * {Object} Information about the exceptions that occurred. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + read: function(data) { │ │ │ │ + var result; │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ } │ │ │ │ - if (this.lastDown && this.passesTolerance(this.lastDown, evt.xy, │ │ │ │ - this.pixelTolerance)) { │ │ │ │ - if (this.touch) { │ │ │ │ - this.modifyFeature(evt.xy); │ │ │ │ - } │ │ │ │ - if (this.persist) { │ │ │ │ - this.destroyPersistedFeature(); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - 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; │ │ │ │ } │ │ │ │ + return exceptionInfo; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: passesTolerance │ │ │ │ - * Determine whether the event is within the optional pixel tolerance. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The event is within the pixel tolerance (if specified). │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - passesTolerance: function(pixel1, pixel2, tolerance) { │ │ │ │ - var passes = true; │ │ │ │ - │ │ │ │ - if (tolerance != null && pixel1 && pixel2) { │ │ │ │ - var dist = pixel1.distanceTo(pixel2); │ │ │ │ - if (dist > tolerance) { │ │ │ │ - passes = false; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ } │ │ │ │ - return passes; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Point" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.OGCExceptionReport" │ │ │ │ + │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Handler/Path.js │ │ │ │ + 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/Handler/Point.js │ │ │ │ - * @requires OpenLayers/Geometry/Point.js │ │ │ │ - * @requires OpenLayers/Geometry/LineString.js │ │ │ │ + * @requires OpenLayers/Format/XML.js │ │ │ │ + * @requires OpenLayers/Format/OGCExceptionReport.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. │ │ │ │ + * 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.Handler.Point> │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Handler.Path = OpenLayers.Class(OpenLayers.Handler.Point, { │ │ │ │ +OpenLayers.Format.XML.VersionedOGC = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: line │ │ │ │ - * {<OpenLayers.Feature.Vector>} │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. │ │ │ │ */ │ │ │ │ - line: null, │ │ │ │ + defaultVersion: 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. │ │ │ │ + * APIProperty: version │ │ │ │ + * {String} Specify a version string if one is known. │ │ │ │ */ │ │ │ │ - maxVertices: null, │ │ │ │ + version: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: doubleTouchTolerance │ │ │ │ - * {Number} Maximum number of pixels between two touches for │ │ │ │ - * the gesture to be considered a "finalize feature" action. │ │ │ │ - * Default is 20. │ │ │ │ + * APIProperty: profile │ │ │ │ + * {String} If provided, use a custom profile. │ │ │ │ */ │ │ │ │ - doubleTouchTolerance: 20, │ │ │ │ + profile: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - freehand: false, │ │ │ │ + allowFallback: 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'. │ │ │ │ + * Property: name │ │ │ │ + * {String} The name of this parser, this is the part of the CLASS_NAME │ │ │ │ + * except for "OpenLayers.Format." │ │ │ │ */ │ │ │ │ - freehandToggle: 'shiftKey', │ │ │ │ + name: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: timerId │ │ │ │ - * {Integer} The timer used to test the double touch. │ │ │ │ + * APIProperty: stringifyOutput │ │ │ │ + * {Boolean} If true, write will return a string otherwise a DOMElement. │ │ │ │ + * Default is false. │ │ │ │ */ │ │ │ │ - timerId: null, │ │ │ │ + stringifyOutput: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: redoStack │ │ │ │ - * {Array} Stack containing points removed with <undo>. │ │ │ │ + * Property: parser │ │ │ │ + * {Object} Instance of the versioned parser. Cached for multiple read and │ │ │ │ + * write calls of the same version. │ │ │ │ */ │ │ │ │ - redoStack: null, │ │ │ │ + parser: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Handler.Path │ │ │ │ - * Create a new path hander │ │ │ │ + * Constructor: OpenLayers.Format.XML.VersionedOGC. │ │ │ │ + * Constructor. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * 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: createFeature │ │ │ │ - * Add temporary geometries │ │ │ │ + * Method: getVersion │ │ │ │ + * Returns the version to use. Subclasses can override this function │ │ │ │ + * if a different version detection is needed. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new │ │ │ │ - * feature. │ │ │ │ + * root - {DOMElement} │ │ │ │ + * options - {Object} Optional configuration object. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} The version to use. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + 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: destroyFeature │ │ │ │ - * Destroy temporary geometries │ │ │ │ + * Method: getParser │ │ │ │ + * Get an instance of the cached parser if available, otherwise create one. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * version - {String} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Format>} │ │ │ │ */ │ │ │ │ - destroyPersistedFeature: function() { │ │ │ │ - var layer = this.layer; │ │ │ │ - if (layer && layer.features.length > 2) { │ │ │ │ - this.layer.features[0].destroy(); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: removePoint │ │ │ │ - * Destroy the temporary point. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - removePoint: function() { │ │ │ │ - if (this.point) { │ │ │ │ - this.layer.removeFeatures([this.point]); │ │ │ │ + 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]); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: addPoint │ │ │ │ - * Add point to geometry. Send the point index to override │ │ │ │ - * the behavior of LinearRing that disregards adding duplicate points. │ │ │ │ + * APIMethod: read │ │ │ │ + * Read a doc and return an object representing the document. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * pixel - {<OpenLayers.Pixel>} The pixel location for the new point. │ │ │ │ + * data - {String | DOMElement} Data to read. │ │ │ │ + * options - {Object} Options for the reader. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} An object representing the document. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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/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, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: filters │ │ │ │ + * {Array(<OpenLayers.Filter>)} Child filters for this filter. │ │ │ │ */ │ │ │ │ - insertXY: function(x, y) { │ │ │ │ - this.line.geometry.addComponent( │ │ │ │ - new OpenLayers.Geometry.Point(x, y), │ │ │ │ - this.getCurrentPointIndex() │ │ │ │ - ); │ │ │ │ - this.drawFeature(); │ │ │ │ - delete this.redoStack; │ │ │ │ - }, │ │ │ │ + filters: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: type │ │ │ │ + * {String} type of logical operator. Available types are: │ │ │ │ + * - OpenLayers.Filter.Logical.AND = "&&"; │ │ │ │ + * - OpenLayers.Filter.Logical.OR = "||"; │ │ │ │ + * - OpenLayers.Filter.Logical.NOT = "!"; │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + type: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: insertDirectionLength │ │ │ │ - * Insert a point in the current sketch given a direction and a length. │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Filter.Logical │ │ │ │ + * Creates a logical filter (And, Or, Not). │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * direction - {Number} Degrees clockwise from the positive x-axis. │ │ │ │ - * length - {Number} Distance from the previously drawn point. │ │ │ │ + * options - {Object} An optional object with properties to set on the │ │ │ │ + * filter. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Filter.Logical>} │ │ │ │ */ │ │ │ │ - insertDirectionLength: function(direction, length) { │ │ │ │ - direction *= Math.PI / 180; │ │ │ │ - var dx = length * Math.cos(direction); │ │ │ │ - var dy = length * Math.sin(direction); │ │ │ │ - this.insertDeltaXY(dx, dy); │ │ │ │ + initialize: function(options) { │ │ │ │ + this.filters = []; │ │ │ │ + OpenLayers.Filter.prototype.initialize.apply(this, [options]); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Remove reference to child filters. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + destroy: function() { │ │ │ │ + this.filters = null; │ │ │ │ + OpenLayers.Filter.prototype.destroy.apply(this); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getCurrentPointIndex │ │ │ │ + * 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: │ │ │ │ - * {Number} The index of the most recently drawn point. │ │ │ │ + * {Boolean} The filter applies. │ │ │ │ */ │ │ │ │ - getCurrentPointIndex: function() { │ │ │ │ - return this.line.geometry.components.length - 1; │ │ │ │ - }, │ │ │ │ + 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; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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(); │ │ │ │ + case OpenLayers.Filter.Logical.NOT: │ │ │ │ + return (!this.filters[0].evaluate(context)); │ │ │ │ } │ │ │ │ - return undone; │ │ │ │ + return undefined; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: clone │ │ │ │ + * Clones this filter. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Filter.Logical>} Clone of this filter. │ │ │ │ */ │ │ │ │ - redo: function() { │ │ │ │ - var target = this.redoStack && this.redoStack.pop(); │ │ │ │ - if (target) { │ │ │ │ - this.line.geometry.addComponent(target, this.getCurrentPointIndex()); │ │ │ │ - this.drawFeature(); │ │ │ │ + clone: function() { │ │ │ │ + var filters = []; │ │ │ │ + for (var i = 0, len = this.filters.length; i < len; ++i) { │ │ │ │ + filters.push(this.filters[i].clone()); │ │ │ │ } │ │ │ │ - return !!target; │ │ │ │ + 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, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: freehandMode │ │ │ │ - * Determine whether to behave in freehand mode or not. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} │ │ │ │ + * 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"; │ │ │ │ */ │ │ │ │ - freehandMode: function(evt) { │ │ │ │ - return (this.freehandToggle && evt[this.freehandToggle]) ? │ │ │ │ - !this.freehand : this.freehand; │ │ │ │ - }, │ │ │ │ + type: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: property │ │ │ │ + * {String} │ │ │ │ + * name of the context property to compare │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - }, │ │ │ │ + property: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawFeature │ │ │ │ - * Render geometries on the temporary layer. │ │ │ │ + * 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}" │ │ │ │ */ │ │ │ │ - drawFeature: function() { │ │ │ │ - this.layer.drawFeature(this.line, this.style); │ │ │ │ - this.layer.drawFeature(this.point, this.style); │ │ │ │ - }, │ │ │ │ + value: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getSketch │ │ │ │ - * Return the sketch feature. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - getSketch: function() { │ │ │ │ - return this.line; │ │ │ │ - }, │ │ │ │ + matchCase: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getGeometry │ │ │ │ - * Return the sketch geometry. If <multi> is true, this will return │ │ │ │ - * a multi-part geometry. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Geometry.LineString>} │ │ │ │ + * 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}" │ │ │ │ */ │ │ │ │ - getGeometry: function() { │ │ │ │ - var geometry = this.line && this.line.geometry; │ │ │ │ - if (geometry && this.multi) { │ │ │ │ - geometry = new OpenLayers.Geometry.MultiLineString([geometry]); │ │ │ │ - } │ │ │ │ - return geometry; │ │ │ │ - }, │ │ │ │ + lowerBoundary: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * method: touchstart │ │ │ │ - * handle touchstart. │ │ │ │ - * │ │ │ │ - * parameters: │ │ │ │ - * evt - {event} the browser event │ │ │ │ - * │ │ │ │ - * returns: │ │ │ │ - * {boolean} allow event propagation │ │ │ │ + * 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}" │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + upperBoundary: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Filter.Comparison │ │ │ │ + * Creates a comparison rule. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow event propagation │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object with properties to set on the │ │ │ │ + * rule │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Filter.Comparison>} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - 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. │ │ │ │ + * APIMethod: evaluate │ │ │ │ + * Evaluates this filter in a specific context. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} The browser event │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow event propagation │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + evaluate: function(context) { │ │ │ │ + if (context instanceof OpenLayers.Feature.Vector) { │ │ │ │ + context = context.attributes; │ │ │ │ } │ │ │ │ - if (!this.touch && (!this.mouseDown || this.stoppedDown)) { │ │ │ │ - this.modifyFeature(evt.xy, !!this.lastUp); │ │ │ │ + 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 true; │ │ │ │ + return result; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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: │ │ │ │ - * evt - {Event} The browser event │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow event propagation │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + value2regex: function(wildCard, singleChar, escapeChar) { │ │ │ │ + if (wildCard == ".") { │ │ │ │ + throw new Error("'.' is an unsupported wildCard character for " + │ │ │ │ + "OpenLayers.Filter.Comparison"); │ │ │ │ } │ │ │ │ - this.stoppedDown = this.stopDown; │ │ │ │ - this.mouseDown = false; │ │ │ │ - return !this.stopUp; │ │ │ │ + │ │ │ │ + │ │ │ │ + // 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: finishGeometry │ │ │ │ - * Finish the geometry and send it back to the control. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - finishGeometry: function() { │ │ │ │ - var index = this.line.geometry.components.length - 1; │ │ │ │ - this.line.geometry.removeComponent(this.line.geometry.components[index]); │ │ │ │ - this.removePoint(); │ │ │ │ - this.finalize(); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: dblclick │ │ │ │ - * Handle double-clicks. │ │ │ │ + * APIMethod: clone │ │ │ │ + * Clones this filter. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} The browser event │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Allow event propagation │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Filter.Comparison>} Clone of this filter. │ │ │ │ */ │ │ │ │ - dblclick: function(evt) { │ │ │ │ - if (!this.freehandMode(evt)) { │ │ │ │ - this.finishGeometry(); │ │ │ │ - } │ │ │ │ - return false; │ │ │ │ + clone: function() { │ │ │ │ + return OpenLayers.Util.extend(new OpenLayers.Filter.Comparison(), this); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Path" │ │ │ │ + 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/Handler/Polygon.js │ │ │ │ + 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/Handler/Path.js │ │ │ │ - * @requires OpenLayers/Geometry/Polygon.js │ │ │ │ + * @requires OpenLayers/Format/XML/VersionedOGC.js │ │ │ │ + * @requires OpenLayers/Filter/FeatureId.js │ │ │ │ + * @requires OpenLayers/Filter/Logical.js │ │ │ │ + * @requires OpenLayers/Filter/Comparison.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. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.Filter │ │ │ │ + * Read/Write ogc:Filter. Create a new instance with the <OpenLayers.Format.Filter> │ │ │ │ + * constructor. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Handler.Path> │ │ │ │ - * - <OpenLayers.Handler> │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ */ │ │ │ │ -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, │ │ │ │ +OpenLayers.Format.Filter = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: polygon │ │ │ │ - * {<OpenLayers.Feature.Vector>} │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "1.0.0". │ │ │ │ */ │ │ │ │ - polygon: null, │ │ │ │ + defaultVersion: "1.0.0", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Handler.Polygon │ │ │ │ - * Create a Polygon Handler. │ │ │ │ + * APIMethod: write │ │ │ │ + * Write an ogc:Filter given a filter object. │ │ │ │ * │ │ │ │ * 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 │ │ │ │ + * filter - {<OpenLayers.Filter>} An filter. │ │ │ │ + * options - {Object} Optional configuration object. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Returns: │ │ │ │ + * {Elment} An ogc:Filter element node. │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createFeature │ │ │ │ - * Add temporary geometries │ │ │ │ + * APIMethod: read │ │ │ │ + * Read and Filter doc and return an object representing the Filter. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * data - {String | DOMElement} Data to read. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * {<OpenLayers.Filter>} A filter object. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.Filter" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Filter/Function.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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(); │ │ │ │ - }, │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * @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, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: cancel │ │ │ │ - * Finish the geometry and call the "cancel" callback. │ │ │ │ + * APIProperty: name │ │ │ │ + * {String} Name of the function. │ │ │ │ */ │ │ │ │ - cancel: function() { │ │ │ │ - if (this.drawingHole) { │ │ │ │ - this.polygon.geometry.removeComponent(this.line.geometry); │ │ │ │ - this.restoreFeature(true); │ │ │ │ - } │ │ │ │ - return OpenLayers.Handler.Path.prototype.cancel.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + name: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: params │ │ │ │ + * {Array(<OpenLayers.Filter.Function> || String || Number)} Function parameters │ │ │ │ + * For now support only other Functions, String or Number │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + params: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroyFeature │ │ │ │ - * Destroy temporary geometries │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Filter.Function │ │ │ │ + * Creates a filter function. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * force - {Boolean} Destroy even if persist is true. │ │ │ │ + * options - {Object} An optional object with properties to set on the │ │ │ │ + * function. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Filter.Function>} │ │ │ │ */ │ │ │ │ - destroyFeature: function(force) { │ │ │ │ - OpenLayers.Handler.Path.prototype.destroyFeature.call( │ │ │ │ - this, force); │ │ │ │ - this.polygon = null; │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: drawFeature │ │ │ │ - * Render geometries on the temporary layer. │ │ │ │ + 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)?$/ │ │ │ │ */ │ │ │ │ - drawFeature: function() { │ │ │ │ - this.layer.drawFeature(this.polygon, this.style); │ │ │ │ - this.layer.drawFeature(this.point, this.style); │ │ │ │ - }, │ │ │ │ + dateRegEx: /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:(?:T(\d{1,2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|(?:[+-]\d{1,2}(?::(\d{2}))?)))|Z)?$/, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getSketch │ │ │ │ - * Return the sketch feature. │ │ │ │ + * 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: │ │ │ │ - * {<OpenLayers.Feature.Vector>} │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - getSketch: function() { │ │ │ │ - return this.polygon; │ │ │ │ - }, │ │ │ │ + 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; │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + │ │ │ │ + })(), │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getGeometry │ │ │ │ - * Return the sketch geometry. If <multi> is true, this will return │ │ │ │ - * a multi-part geometry. │ │ │ │ + * 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: │ │ │ │ - * {<OpenLayers.Geometry.Polygon>} │ │ │ │ + * {Date} A date object. If the string could not be parsed, an invalid │ │ │ │ + * date is returned (i.e. isNaN(date.getTime())). │ │ │ │ */ │ │ │ │ - getGeometry: function() { │ │ │ │ - var geometry = this.polygon && this.polygon.geometry; │ │ │ │ - if (geometry && this.multi) { │ │ │ │ - geometry = new OpenLayers.Geometry.MultiPolygon([geometry]); │ │ │ │ + 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 geometry; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Polygon" │ │ │ │ -}); │ │ │ │ + return date; │ │ │ │ + } │ │ │ │ +}; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol.js │ │ │ │ + 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/BaseTypes/Class.js │ │ │ │ + * @requires OpenLayers/Format/Filter.js │ │ │ │ + * @requires OpenLayers/Format/XML.js │ │ │ │ + * @requires OpenLayers/Filter/Function.js │ │ │ │ + * @requires OpenLayers/BaseTypes/Date.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol │ │ │ │ - * Abstract vector layer protocol class. Not to be instantiated directly. Use │ │ │ │ - * one of the protocol subclasses instead. │ │ │ │ + * Class: OpenLayers.Format.Filter.v1 │ │ │ │ + * Superclass for Filter version 1 parsers. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol = OpenLayers.Class({ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: format │ │ │ │ - * {<OpenLayers.Format>} The format used by this protocol. │ │ │ │ - */ │ │ │ │ - format: null, │ │ │ │ +OpenLayers.Format.Filter.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: options │ │ │ │ - * {Object} Any options sent to the constructor. │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ - options: null, │ │ │ │ + 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: autoDestroy │ │ │ │ - * {Boolean} The creator of the protocol can set autoDestroy to false │ │ │ │ - * to fully control when the protocol is destroyed. Defaults to │ │ │ │ - * true. │ │ │ │ + * Property: defaultPrefix │ │ │ │ */ │ │ │ │ - autoDestroy: true, │ │ │ │ + defaultPrefix: "ogc", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: defaultFilter │ │ │ │ - * {<OpenLayers.Filter>} Optional default filter to read requests │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} Schema location for a particular minor version. │ │ │ │ */ │ │ │ │ - defaultFilter: null, │ │ │ │ + schemaLocation: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Protocol │ │ │ │ - * Abstract class for vector protocols. Create instances of a subclass. │ │ │ │ + * Constructor: OpenLayers.Format.Filter.v1 │ │ │ │ + * Instances of this class are not created directly. Use the │ │ │ │ + * <OpenLayers.Format.Filter> constructor instead. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ */ │ │ │ │ initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - this.options = options; │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: mergeWithDefaultFilter │ │ │ │ - * Merge filter passed to the read method with the default one │ │ │ │ + * Method: read │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * filter - {<OpenLayers.Filter>} │ │ │ │ + * data - {DOMElement} A Filter document element. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Filter>} A filter object. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + read: function(data) { │ │ │ │ + var obj = {}; │ │ │ │ + this.readers.ogc["Filter"].apply(this, [data, obj]); │ │ │ │ + return obj.filter; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Clean up the protocol. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - this.options = null; │ │ │ │ - this.format = null; │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Construct a request for reading new features. │ │ │ │ + * Method: readSpatial │ │ │ │ * │ │ │ │ + * Read a {<OpenLayers.Filter.Spatial>} filter. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object for configuring the request. │ │ │ │ + * 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.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. │ │ │ │ + * {<OpenLayers.Filter.Spatial>} The created filter. │ │ │ │ */ │ │ │ │ - read: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.filter = this.mergeWithDefaultFilter(options.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: create │ │ │ │ - * Construct a request for writing newly created features. │ │ │ │ + * 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: │ │ │ │ - * features - {Array({<OpenLayers.Feature.Vector>})} or │ │ │ │ - * {<OpenLayers.Feature.Vector>} │ │ │ │ - * options - {Object} Optional object for configuring the request. │ │ │ │ + * value - {Object} Literal value to encode │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * {String} String representation of the provided value. │ │ │ │ */ │ │ │ │ - create: function() {}, │ │ │ │ + encodeLiteral: function(value) { │ │ │ │ + if (value instanceof Date) { │ │ │ │ + value = OpenLayers.Date.toISOString(value); │ │ │ │ + } │ │ │ │ + return value; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: update │ │ │ │ - * Construct a request updating modified features. │ │ │ │ + * Method: writeOgcExpression │ │ │ │ + * Limited support for writing OGC expressions. Currently it supports │ │ │ │ + * (<OpenLayers.Filter.Function> || String || Number) │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * features - {Array({<OpenLayers.Feature.Vector>})} or │ │ │ │ - * {<OpenLayers.Feature.Vector>} │ │ │ │ - * options - {Object} Optional object for configuring the request. │ │ │ │ + * value - (<OpenLayers.Filter.Function> || String || Number) │ │ │ │ + * node - {DOMElement} A parent DOM element │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * {DOMElement} Updated node element. │ │ │ │ */ │ │ │ │ - update: function() {}, │ │ │ │ + writeOgcExpression: function(value, node) { │ │ │ │ + if (value instanceof OpenLayers.Filter.Function) { │ │ │ │ + this.writeNode("Function", value, node); │ │ │ │ + } else { │ │ │ │ + this.writeNode("Literal", value, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: delete │ │ │ │ - * Construct a request deleting a removed feature. │ │ │ │ + * Method: write │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - * options - {Object} Optional object for configuring the request. │ │ │ │ + * filter - {<OpenLayers.Filter>} A filter object. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * {DOMElement} An ogc:Filter element. │ │ │ │ */ │ │ │ │ - "delete": function() {}, │ │ │ │ + write: function(filter) { │ │ │ │ + return this.writers.ogc["Filter"].apply(this, [filter]); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - commit: function() {}, │ │ │ │ + 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: abort │ │ │ │ - * Abort an ongoing request. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * response - {<OpenLayers.Protocol.Response>} │ │ │ │ + * Method: getFilterType │ │ │ │ */ │ │ │ │ - abort: function(response) {}, │ │ │ │ + getFilterType: function(filter) { │ │ │ │ + var filterType = this.filterMap[filter.type]; │ │ │ │ + if (!filterType) { │ │ │ │ + throw "Filter writing not supported for rule type: " + filter.type; │ │ │ │ + } │ │ │ │ + return filterType; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Property: filterMap │ │ │ │ + * {Object} Contains a member for each filter type. Values are node names │ │ │ │ + * for corresponding OGC Filter child elements. │ │ │ │ */ │ │ │ │ - createCallback: function(method, response, options) { │ │ │ │ - return OpenLayers.Function.bind(function() { │ │ │ │ - method.apply(this, [response, options]); │ │ │ │ - }, this); │ │ │ │ + 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.Protocol" │ │ │ │ + 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. */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.Response │ │ │ │ - * Protocols return Response objects to their users. │ │ │ │ + * @requires OpenLayers/Format/GML/v2.js │ │ │ │ + * @requires OpenLayers/Format/Filter/v1.js │ │ │ │ */ │ │ │ │ -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, │ │ │ │ +/** │ │ │ │ + * 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, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + /** │ │ │ │ + * Constant: VERSION │ │ │ │ + * {String} 1.0.0 │ │ │ │ + */ │ │ │ │ + VERSION: "1.0.0", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: 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", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + /** │ │ │ │ + * 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: priv │ │ │ │ - */ │ │ │ │ - priv: 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: { │ │ │ │ + "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: error │ │ │ │ - * {Object} The error object in case a service exception was encountered. │ │ │ │ - */ │ │ │ │ - error: null, │ │ │ │ + /** │ │ │ │ + * 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"] │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: success │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} - true on success, false otherwise │ │ │ │ - */ │ │ │ │ - success: function() { │ │ │ │ - return this.code > 0; │ │ │ │ - }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.Response" │ │ │ │ -}); │ │ │ │ + CLASS_NAME: "OpenLayers.Format.Filter.v1_0_0" │ │ │ │ │ │ │ │ -OpenLayers.Protocol.Response.SUCCESS = 1; │ │ │ │ -OpenLayers.Protocol.Response.FAILURE = 0; │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/WFS.js │ │ │ │ + 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/Protocol.js │ │ │ │ + * @requires OpenLayers/Format/WFST/v1.js │ │ │ │ + * @requires OpenLayers/Format/Filter/v1_0_0.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) │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * See the protocols for specific WFS versions for more detail. │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.Filter.v1_0_0> │ │ │ │ + * - <OpenLayers.Format.WFST.v1> │ │ │ │ */ │ │ │ │ -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); │ │ │ │ -}; │ │ │ │ +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/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. */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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>} │ │ │ │ + * @requires OpenLayers/Protocol/WFS/v1.js │ │ │ │ + * @requires OpenLayers/Format/WFST/v1_0_0.js │ │ │ │ */ │ │ │ │ -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 │ │ │ │ + * 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.DEFAULTS = { │ │ │ │ - "version": "1.0.0" │ │ │ │ -}; │ │ │ │ +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/Protocol/HTTP.js │ │ │ │ + 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/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 │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.HTTP │ │ │ │ - * A basic HTTP protocol for vector layers. Create a new instance with the │ │ │ │ - * <OpenLayers.Protocol.HTTP> constructor. │ │ │ │ + * 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()); │ │ │ │ * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol> │ │ │ │ + * 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.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ +OpenLayers.Control = OpenLayers.Class({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: url │ │ │ │ - * {String} Service URL, read-only, set through the options │ │ │ │ - * passed to constructor. │ │ │ │ + /** │ │ │ │ + * Property: id │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - url: null, │ │ │ │ + id: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: headers │ │ │ │ - * {Object} HTTP request headers, read-only, set through the options │ │ │ │ - * passed to the constructor, │ │ │ │ - * Example: {'Content-Type': 'plain/text'} │ │ │ │ + /** │ │ │ │ + * Property: map │ │ │ │ + * {<OpenLayers.Map>} this gets set in the addControl() function in │ │ │ │ + * OpenLayers.Map │ │ │ │ */ │ │ │ │ - headers: null, │ │ │ │ + map: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: params │ │ │ │ - * {Object} Parameters of GET requests, read-only, set through the options │ │ │ │ - * passed to the constructor, │ │ │ │ - * Example: {'bbox': '5,5,5,5'} │ │ │ │ + /** │ │ │ │ + * APIProperty: div │ │ │ │ + * {DOMElement} The element that contains the control, if not present the │ │ │ │ + * control is placed inside the map. │ │ │ │ */ │ │ │ │ - params: null, │ │ │ │ + div: 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. │ │ │ │ + /** │ │ │ │ + * 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>. │ │ │ │ */ │ │ │ │ - callback: null, │ │ │ │ + type: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: scope │ │ │ │ - * {Object} Callback execution scope, read-only, set through the │ │ │ │ - * options passed to the constructor. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - scope: null, │ │ │ │ + allowSelection: false, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: readWithPOST │ │ │ │ - * {Boolean} true if read operations are done with POST requests │ │ │ │ - * instead of GET, defaults to false. │ │ │ │ + /** │ │ │ │ + * Property: displayClass │ │ │ │ + * {string} This property is used for CSS related to the drawing of the │ │ │ │ + * Control. │ │ │ │ */ │ │ │ │ - readWithPOST: false, │ │ │ │ + displayClass: "", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: updateWithPOST │ │ │ │ - * {Boolean} true if update operations are done with POST requests │ │ │ │ - * defaults to false. │ │ │ │ + * APIProperty: title │ │ │ │ + * {string} This property is used for showing a tooltip over the │ │ │ │ + * Control. │ │ │ │ */ │ │ │ │ - updateWithPOST: false, │ │ │ │ + title: "", │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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(). │ │ │ │ + * APIProperty: autoActivate │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * false. │ │ │ │ */ │ │ │ │ - deleteWithPOST: false, │ │ │ │ + autoActivate: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: active │ │ │ │ + * {Boolean} The control is active (read-only). Use <activate> and │ │ │ │ + * <deactivate> to change control state. │ │ │ │ + */ │ │ │ │ + active: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: handlerOptions │ │ │ │ + * {Object} Used to set non-default properties on the control's handler │ │ │ │ */ │ │ │ │ - wildcarded: false, │ │ │ │ + handlerOptions: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: handler │ │ │ │ + * {<OpenLayers.Handler>} null │ │ │ │ + */ │ │ │ │ + handler: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - srsInBBOX: false, │ │ │ │ + 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.Protocol.HTTP │ │ │ │ - * A class for giving layers generic HTTP protocol. │ │ │ │ + * 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} 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} │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - this.params = {}; │ │ │ │ - this.headers = {}; │ │ │ │ - OpenLayers.Protocol.prototype.initialize.apply(this, arguments); │ │ │ │ + // We do this before the extend so that instances can override │ │ │ │ + // className in options. │ │ │ │ + this.displayClass = │ │ │ │ + this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, ""); │ │ │ │ │ │ │ │ - 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); │ │ │ │ - }; │ │ │ │ + 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 + "_"); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Clean up the protocol. │ │ │ │ + * 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.params = null; │ │ │ │ - this.headers = null; │ │ │ │ - OpenLayers.Protocol.prototype.destroy.apply(this); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * 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: │ │ │ │ - * filter - {<OpenLayers.Filter>} filter to convert. │ │ │ │ - * params - {Object} The parameters object. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} The resulting parameters object. │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ + setMap: function(map) { │ │ │ │ + this.map = map; │ │ │ │ + if (this.handler) { │ │ │ │ + this.handler.setMap(map); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Construct a request for reading new features. │ │ │ │ + * 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: │ │ │ │ - * 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. │ │ │ │ + * px - {<OpenLayers.Pixel>} The top-left pixel position of the control │ │ │ │ + * or null. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * {DOMElement} A reference to the DIV DOMElement containing the control │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - ); │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ } │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + if (px != null) { │ │ │ │ + this.position = px.clone(); │ │ │ │ } │ │ │ │ - return resp; │ │ │ │ + this.moveTo(this.position); │ │ │ │ + return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handleRead │ │ │ │ - * Individual callbacks are created for read, create and update, should │ │ │ │ - * a subclass need to override each one separately. │ │ │ │ + * Method: moveTo │ │ │ │ + * Sets the left and top style attributes to the passed in pixel │ │ │ │ + * coordinates. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * resp - {<OpenLayers.Protocol.Response>} The response object to pass to │ │ │ │ - * the user callback. │ │ │ │ - * options - {Object} The user options passed to the read call. │ │ │ │ + * px - {<OpenLayers.Pixel>} │ │ │ │ */ │ │ │ │ - handleRead: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options); │ │ │ │ + moveTo: function(px) { │ │ │ │ + if ((px != null) && (this.div != null)) { │ │ │ │ + this.div.style.left = px.x + "px"; │ │ │ │ + this.div.style.top = px.y + "px"; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * {<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. │ │ │ │ + * {Boolean} True if the control was successfully activated or │ │ │ │ + * false if the control was already active. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - handleCreate: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + CLASS_NAME: "OpenLayers.Control" │ │ │ │ +}); │ │ │ │ │ │ │ │ - var resp = new OpenLayers.Protocol.Response({ │ │ │ │ - reqFeatures: feature, │ │ │ │ - requestType: "update" │ │ │ │ - }); │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Control.TYPE_BUTTON │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.TYPE_BUTTON = 1; │ │ │ │ │ │ │ │ - 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) │ │ │ │ - }); │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Control.TYPE_TOGGLE │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.TYPE_TOGGLE = 2; │ │ │ │ │ │ │ │ - return resp; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Control.TYPE_TOOL │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.TYPE_TOOL = 3; │ │ │ │ +/* ====================================================================== │ │ │ │ + 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({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: target │ │ │ │ + * {<OpenLayers.Events>} The events instance that the buttonclick event will │ │ │ │ + * be triggered on. │ │ │ │ */ │ │ │ │ - handleUpdate: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options); │ │ │ │ - }, │ │ │ │ + target: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: events │ │ │ │ + * {Array} Events to observe and conditionally stop from propagating when │ │ │ │ + * an element with the olButton class (or its olAlphaImg child) is │ │ │ │ + * clicked. │ │ │ │ */ │ │ │ │ - "delete": function(feature, options) { │ │ │ │ - options = options || {}; │ │ │ │ - var url = options.url || │ │ │ │ - feature.url || │ │ │ │ - this.options.url + "/" + feature.fid; │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ + events: [ │ │ │ │ + 'mousedown', 'mouseup', 'click', 'dblclick', │ │ │ │ + 'touchstart', 'touchmove', 'touchend', 'keydown' │ │ │ │ + ], │ │ │ │ │ │ │ │ - var resp = new OpenLayers.Protocol.Response({ │ │ │ │ - reqFeatures: feature, │ │ │ │ - requestType: "delete" │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * Property: startRegEx │ │ │ │ + * {RegExp} Regular expression to test Event.type for events that start │ │ │ │ + * a buttonclick sequence. │ │ │ │ + */ │ │ │ │ + startRegEx: /^mousedown|touchstart$/, │ │ │ │ │ │ │ │ - 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); │ │ │ │ + /** │ │ │ │ + * Property: cancelRegEx │ │ │ │ + * {RegExp} Regular expression to test Event.type for events that cancel │ │ │ │ + * a buttonclick sequence. │ │ │ │ + */ │ │ │ │ + cancelRegEx: /^touchmove$/, │ │ │ │ │ │ │ │ - return resp; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: completeRegEx │ │ │ │ + * {RegExp} Regular expression to test Event.type for events that complete │ │ │ │ + * a buttonclick sequence. │ │ │ │ + */ │ │ │ │ + completeRegEx: /^mouseup|touchend$/, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: startEvt │ │ │ │ + * {Event} The event that started the click sequence │ │ │ │ */ │ │ │ │ - handleDelete: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handleResponse │ │ │ │ - * Called by CRUD specific handlers. │ │ │ │ + * 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: │ │ │ │ - * 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. │ │ │ │ + * target - {<OpenLayers.Events>} The events instance that the buttonclick │ │ │ │ + * event will be triggered on. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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: 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. │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - parseFeatures: function(request) { │ │ │ │ - var doc = request.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = request.responseText; │ │ │ │ - } │ │ │ │ - if (!doc || doc.length <= 0) { │ │ │ │ - return null; │ │ │ │ + destroy: function() { │ │ │ │ + for (var i = this.events.length - 1; i >= 0; --i) { │ │ │ │ + this.target.unregister(this.events[i], this, this.buttonClick); │ │ │ │ } │ │ │ │ - return this.format.read(doc); │ │ │ │ + delete this.target; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: getPressedButton │ │ │ │ + * Get the pressed button, if any. Returns undefined if no button │ │ │ │ + * was pressed. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Arguments: │ │ │ │ + * element - {DOMElement} The event target. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * {DOMElement} The button element, or undefined. │ │ │ │ */ │ │ │ │ - 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]); │ │ │ │ - } │ │ │ │ + getPressedButton: function(element) { │ │ │ │ + var depth = 3, // limit the search depth │ │ │ │ + button; │ │ │ │ + do { │ │ │ │ + if (OpenLayers.Element.hasClass(element, "olButton")) { │ │ │ │ + // hit! │ │ │ │ + button = element; │ │ │ │ + break; │ │ │ │ } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // 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; │ │ │ │ + element = element.parentNode; │ │ │ │ + } while (--depth > 0 && element); │ │ │ │ + return button; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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). │ │ │ │ + * Method: ignore │ │ │ │ + * Check for event target elements that should be ignored by OpenLayers. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * response - {<OpenLayers.Protocol.Response>} │ │ │ │ + * element - {DOMElement} The event target. │ │ │ │ */ │ │ │ │ - abort: function(response) { │ │ │ │ - if (response) { │ │ │ │ - response.priv.abort(); │ │ │ │ - } │ │ │ │ + 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: 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. │ │ │ │ + * Method: buttonClick │ │ │ │ + * Check if a button was clicked, and fire the buttonclick event │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * resp - {<OpenLayers.Protocol.Response>} │ │ │ │ - * options - {Object} The map of options passed to the commit call. │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - callUserCallback: function(resp, options) { │ │ │ │ - var opt = options[resp.requestType]; │ │ │ │ - if (opt && opt.callback) { │ │ │ │ - opt.callback.call(opt.scope, resp); │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.HTTP" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/WFS/v1.js │ │ │ │ + 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/Protocol/WFS.js │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Events/buttonclick.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.WFS.v1 │ │ │ │ - * Abstract class for for v1.0.0 and v1.1.0 protocol. │ │ │ │ + * Class: OpenLayers.Control.Panel │ │ │ │ + * The Panel control is a container for other controls. With it toolbars │ │ │ │ + * may be composed. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - │ │ │ │ +OpenLayers.Control.Panel = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ /** │ │ │ │ - * Property: version │ │ │ │ - * {String} WFS version number. │ │ │ │ + * Property: controls │ │ │ │ + * {Array(<OpenLayers.Control>)} │ │ │ │ */ │ │ │ │ - version: null, │ │ │ │ + controls: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: srsName │ │ │ │ - * {String} Name of spatial reference system. Default is "EPSG:4326". │ │ │ │ + * APIProperty: autoActivate │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * true. │ │ │ │ */ │ │ │ │ - srsName: "EPSG:4326", │ │ │ │ + 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: featureType │ │ │ │ - * {String} Local feature typeName. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - featureType: null, │ │ │ │ + saveState: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: featureNS │ │ │ │ - * {String} Feature namespace. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - featureNS: null, │ │ │ │ + allowDepress: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: geometryName │ │ │ │ - * {String} Name of the geometry attribute for features. Default is │ │ │ │ - * "the_geom" for WFS <version> 1.0, and null for higher versions. │ │ │ │ + * Property: activeState │ │ │ │ + * {Object} stores the active state of this panel's controls. │ │ │ │ */ │ │ │ │ - geometryName: "the_geom", │ │ │ │ + activeState: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: maxFeatures │ │ │ │ - * {Integer} Optional maximum number of features to retrieve. │ │ │ │ + * 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 = {}; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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). │ │ │ │ + * APIMethod: destroy │ │ │ │ */ │ │ │ │ - schema: null, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: featurePrefix │ │ │ │ - * {String} Namespace alias for feature type. Default is "feature". │ │ │ │ + * APIMethod: activate │ │ │ │ */ │ │ │ │ - featurePrefix: "feature", │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: deactivate │ │ │ │ */ │ │ │ │ - formatOptions: null, │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * Method: draw │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - readFormat: null, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: readOptions │ │ │ │ - * {Object} Optional object to pass to format's read. │ │ │ │ + * Method: redraw │ │ │ │ */ │ │ │ │ - readOptions: null, │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Protocol.WFS │ │ │ │ - * A class for giving layers WFS protocol. │ │ │ │ + * APIMethod: activateControl │ │ │ │ + * This method is called when the user click on the icon representing a │ │ │ │ + * control in the panel. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * control - {<OpenLayers.Control>} │ │ │ │ */ │ │ │ │ - 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)); │ │ │ │ + activateControl: function(control) { │ │ │ │ + if (!this.active) { │ │ │ │ + return false; │ │ │ │ } │ │ │ │ - if (!options.geometryName && parseFloat(this.format.version) > 1.0) { │ │ │ │ - this.setGeometryName(null); │ │ │ │ + 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: destroy │ │ │ │ - * Clean up the protocol. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.options && !this.options.format) { │ │ │ │ - this.format.destroy(); │ │ │ │ + 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(); │ │ │ │ } │ │ │ │ - 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: │ │ │ │ + * 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) │ │ │ │ - * protocol.read({ │ │ │ │ - * readOptions: {output: "object"}, │ │ │ │ - * resultType: "hits", │ │ │ │ - * maxFeatures: null, │ │ │ │ - * callback: function(resp) { │ │ │ │ - * // process resp.numberOfFeatures here │ │ │ │ + * 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) │ │ │ │ - * │ │ │ │ - * 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: │ │ │ │ + * Parameters: │ │ │ │ + * control - {<OpenLayers.Control>} The control to create the HTML │ │ │ │ + * markup for. │ │ │ │ * │ │ │ │ - * (code) │ │ │ │ - * protocol.read({ │ │ │ │ - * propertyNames: ["DURATION", "INTENSITY"] │ │ │ │ - * }); │ │ │ │ - * (end) │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} The markup. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + createControlMarkup: function(control) { │ │ │ │ + return document.createElement("div"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setFeatureType │ │ │ │ - * Change the feature type on the fly. │ │ │ │ + * Method: addControlsToMap │ │ │ │ + * Only for internal use in draw() and addControls() methods. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * featureType - {String} Local (without prefix) feature typeName. │ │ │ │ + * controls - {Array(<OpenLayers.Control>)} Controls to add into map. │ │ │ │ */ │ │ │ │ - setFeatureType: function(featureType) { │ │ │ │ - this.featureType = featureType; │ │ │ │ - this.format.featureType = featureType; │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setGeometryName │ │ │ │ - * Sets the geometryName option after instantiation. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometryName - {String} Name of geometry attribute. │ │ │ │ + * Method: iconOn │ │ │ │ + * Internal use, for use only with "controls[i].events.on/un". │ │ │ │ */ │ │ │ │ - setGeometryName: function(geometryName) { │ │ │ │ - this.geometryName = geometryName; │ │ │ │ - this.format.geometryName = geometryName; │ │ │ │ + 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: handleRead │ │ │ │ - * Deal with response from the read request. │ │ │ │ + * 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: │ │ │ │ - * response - {<OpenLayers.Protocol.Response>} The response object to pass │ │ │ │ - * to the user callback. │ │ │ │ - * options - {Object} The user options passed to the read call. │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - options.callback.call(options.scope, response); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseResponse │ │ │ │ - * Read HTTP response body and return features │ │ │ │ + * APIMethod: getControlsBy │ │ │ │ + * Get a list of controls with properties matching the given criteria. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * request - {XMLHttpRequest} The request object │ │ │ │ - * options - {Object} Optional object to pass to format's read │ │ │ │ + * 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: │ │ │ │ - * {Object} or {Array({<OpenLayers.Feature.Vector>})} or │ │ │ │ - * {<OpenLayers.Feature.Vector>} │ │ │ │ - * An object with a features property, an array of features or a single │ │ │ │ - * feature. │ │ │ │ + * {Array(<OpenLayers.Control>)} A list of controls matching the given criteria. │ │ │ │ + * An empty array is returned if no matches are found. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: getControlsByName │ │ │ │ + * Get a list of contorls with names matching the given name. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * 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: │ │ │ │ - * {<OpenLayers.Protocol.Response>} A response object with a features │ │ │ │ - * property containing any insertIds and a priv property referencing │ │ │ │ - * the XMLHttpRequest object. │ │ │ │ + * {Array(<OpenLayers.Control>)} A list of controls matching the given name. │ │ │ │ + * An empty array is returned if no matches are found. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + getControlsByName: function(match) { │ │ │ │ + return this.getControlsBy("name", match); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handleCommit │ │ │ │ - * Called when the commit request returns. │ │ │ │ - * │ │ │ │ + * APIMethod: getControlsByClass │ │ │ │ + * Get a list of controls of a given type (CLASS_NAME). │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * response - {<OpenLayers.Protocol.Response>} The response object to pass │ │ │ │ - * to the user callback. │ │ │ │ - * options - {Object} The user options passed to the commit call. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - handleCommit: function(response, options) { │ │ │ │ - if (options.callback) { │ │ │ │ - var request = response.priv; │ │ │ │ + getControlsByClass: function(match) { │ │ │ │ + return this.getControlsBy("CLASS_NAME", match); │ │ │ │ + }, │ │ │ │ │ │ │ │ - // ensure that we have an xml doc │ │ │ │ - var data = request.responseXML; │ │ │ │ - if (!data || !data.documentElement) { │ │ │ │ - data = request.responseText; │ │ │ │ - } │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Panel" │ │ │ │ +}); │ │ │ │ │ │ │ │ - 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/Format/WFST.js │ │ │ │ + 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/Format.js │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Geometry/Point.js │ │ │ │ + * @requires OpenLayers/Projection.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Function: OpenLayers.Format.WFST │ │ │ │ - * Used to create a versioned WFS protocol. Default version is 1.0.0. │ │ │ │ + * 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 │ │ │ │ * │ │ │ │ - * 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.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. │ │ │ │ + * 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.Filter = OpenLayers.Class({ │ │ │ │ +OpenLayers.Control.Geolocate = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Filter │ │ │ │ - * This class represents a generic filter. │ │ │ │ + * APIProperty: events │ │ │ │ + * {<OpenLayers.Events>} Events instance for listeners and triggering │ │ │ │ + * control specific events. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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. │ │ │ │ + * Property: geolocation │ │ │ │ + * {Object} The geolocation engine, as a property to be possibly mocked. │ │ │ │ + * This is set lazily to avoid a memory leak in IE9. │ │ │ │ */ │ │ │ │ - evaluate: function(context) { │ │ │ │ - return true; │ │ │ │ - }, │ │ │ │ + geolocation: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Clones this filter. Should be implemented by subclasses. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Filter>} Clone of this filter. │ │ │ │ + * Property: available │ │ │ │ + * {Boolean} The navigator.geolocation object is available. │ │ │ │ */ │ │ │ │ - clone: function() { │ │ │ │ - return null; │ │ │ │ - }, │ │ │ │ + available: ('geolocation' in navigator), │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: bind │ │ │ │ + * {Boolean} If true, map center will be set on location update. │ │ │ │ */ │ │ │ │ - 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/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, { │ │ │ │ + bind: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * APIProperty: watch │ │ │ │ + * {Boolean} If true, position will be update regularly. │ │ │ │ */ │ │ │ │ - type: null, │ │ │ │ + watch: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: property │ │ │ │ - * {String} Name of the context property to compare. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - property: null, │ │ │ │ + geolocationOptions: 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. │ │ │ │ + * Constructor: OpenLayers.Control.Geolocate │ │ │ │ + * Create a new control to deal with browser geolocation API │ │ │ │ + * │ │ │ │ */ │ │ │ │ - value: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: distance │ │ │ │ - * {Number} The distance to use in a DWithin spatial filter. │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - distance: null, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: distanceUnits │ │ │ │ - * {String} The units to use for the distance, e.g. 'm'. │ │ │ │ - */ │ │ │ │ - distanceUnits: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Filter.Spatial │ │ │ │ - * Creates a spatial filter. │ │ │ │ + * Method: activate │ │ │ │ + * Activates the control. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * {Boolean} The control was effectively activated. │ │ │ │ */ │ │ │ │ - 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.'); │ │ │ │ + activate: function() { │ │ │ │ + if (this.available && !this.geolocation) { │ │ │ │ + // set lazily to avoid IE9 memory leak │ │ │ │ + this.geolocation = navigator.geolocation; │ │ │ │ } │ │ │ │ - return intersect; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Clones this filter. │ │ │ │ - * │ │ │ │ + * Method: deactivate │ │ │ │ + * Deactivates the control. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Filter.Spatial>} Clone of this filter. │ │ │ │ + * {Boolean} The control was effectively deactivated. │ │ │ │ */ │ │ │ │ - clone: function() { │ │ │ │ - var options = OpenLayers.Util.applyDefaults({ │ │ │ │ - value: this.value && this.value.clone && this.value.clone() │ │ │ │ - }, this); │ │ │ │ - return new OpenLayers.Filter.Spatial(options); │ │ │ │ + deactivate: function() { │ │ │ │ + if (this.active && this.watchId !== null) { │ │ │ │ + this.geolocation.clearWatch(this.watchId); │ │ │ │ + } │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply( │ │ │ │ + this, arguments │ │ │ │ + ); │ │ │ │ }, │ │ │ │ - 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/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. │ │ │ │ + /** │ │ │ │ + * Method: geolocate │ │ │ │ + * Activates the control. │ │ │ │ * │ │ │ │ - * 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]); │ │ │ │ + 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: 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. │ │ │ │ - * │ │ │ │ + * APIMethod: getCurrentLocation │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} true if the rule applies, false if it does not │ │ │ │ + * {Boolean} Returns true if a event will be fired (successfull │ │ │ │ + * registration) │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + getCurrentLocation: function() { │ │ │ │ + if (!this.active || this.watch) { │ │ │ │ + return false; │ │ │ │ } │ │ │ │ - return false; │ │ │ │ + this.geolocation.getCurrentPosition( │ │ │ │ + OpenLayers.Function.bind(this.geolocate, this), │ │ │ │ + OpenLayers.Function.bind(this.failure, this), │ │ │ │ + this.geolocationOptions │ │ │ │ + ); │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Clones this filter. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Filter.FeatureId>} Clone of this filter. │ │ │ │ + * Method: failure │ │ │ │ + * method called on browser's geolocation failure │ │ │ │ + * │ │ │ │ */ │ │ │ │ - clone: function() { │ │ │ │ - var filter = new OpenLayers.Filter.FeatureId(); │ │ │ │ - OpenLayers.Util.extend(filter, this); │ │ │ │ - filter.fids = this.fids.slice(); │ │ │ │ - return filter; │ │ │ │ + failure: function(error) { │ │ │ │ + this.events.triggerEvent("locationfailed", { │ │ │ │ + error: error │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Filter.FeatureId" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Geolocate" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WFST/v1.js │ │ │ │ + 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/Format/XML.js │ │ │ │ - * @requires OpenLayers/Format/WFST.js │ │ │ │ - * @requires OpenLayers/Filter/Spatial.js │ │ │ │ - * @requires OpenLayers/Filter/FeatureId.js │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Events/buttonclick.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WFST.v1 │ │ │ │ - * Superclass for WFST parsers. │ │ │ │ + * Class: OpenLayers.Control.Zoom │ │ │ │ + * The Zoom control is a pair of +/- links for zooming in and out. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -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, │ │ │ │ +OpenLayers.Control.Zoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: zoomInText │ │ │ │ + * {String} │ │ │ │ + * Text for zoom-in link. Default is "+". │ │ │ │ */ │ │ │ │ - xy: true, │ │ │ │ + zoomInText: "+", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: stateName │ │ │ │ - * {Object} Maps feature states to node names. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - stateName: null, │ │ │ │ + zoomInId: "olZoomInLink", │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: zoomOutText │ │ │ │ + * {String} │ │ │ │ + * Text for zoom-out link. Default is "\u2212". │ │ │ │ */ │ │ │ │ - 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]); │ │ │ │ - }, │ │ │ │ + zoomOutText: "\u2212", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getSrsName │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - }, │ │ │ │ + zoomOutId: "olZoomOutLink", │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: draw │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Array | Object} Output depending on the output option. │ │ │ │ + * {DOMElement} A reference to the DOMElement containing the zoom links. │ │ │ │ */ │ │ │ │ - read: function(data, options) { │ │ │ │ - options = options || {}; │ │ │ │ - OpenLayers.Util.applyDefaults(options, { │ │ │ │ - output: "features" │ │ │ │ - }); │ │ │ │ + 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 (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; │ │ │ │ + if (zoomOut.parentNode !== div) { │ │ │ │ + eventsInstance = this.events; │ │ │ │ + eventsInstance.attachToElement(zoomOut.parentNode); │ │ │ │ } │ │ │ │ - return obj; │ │ │ │ - }, │ │ │ │ + eventsInstance.register("buttonclick", this, this.onZoomClick); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + this.zoomInLink = zoomIn; │ │ │ │ + this.zoomOutLink = zoomOut; │ │ │ │ + return div; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + * Method: getOrCreateLinks │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * el - {DOMElement} │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {String} A serialized WFS transaction. │ │ │ │ + * Return: │ │ │ │ + * {Object} Object with zoomIn and zoomOut properties referencing links. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - ); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + 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: schemaLocationAttr │ │ │ │ - * Generate the xsi:schemaLocation attribute value. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} The xsi:schemaLocation attribute or undefined if none. │ │ │ │ + * Method: onZoomClick │ │ │ │ + * Called when zoomin/out link is clicked. │ │ │ │ */ │ │ │ │ - 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]); │ │ │ │ - } │ │ │ │ + onZoomClick: function(evt) { │ │ │ │ + var button = evt.buttonElement; │ │ │ │ + if (button === this.zoomInLink) { │ │ │ │ + this.map.zoomIn(); │ │ │ │ + } else if (button === this.zoomOutLink) { │ │ │ │ + this.map.zoomOut(); │ │ │ │ } │ │ │ │ - var value = parts.join(" ") || undefined; │ │ │ │ - return value; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setFilterProperty │ │ │ │ - * Set the property of each spatial filter. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * filter - {<OpenLayers.Filter>} │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + * Clean up. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + 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.Format.WFST.v1" │ │ │ │ - │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Zoom" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/GML.js │ │ │ │ + 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/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 │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.GML │ │ │ │ - * Read/Write GML. Create a new instance with the <OpenLayers.Format.GML> │ │ │ │ - * constructor. Supports the GML simple features profile. │ │ │ │ - * │ │ │ │ + * 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.Format.XML> │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -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", │ │ │ │ +OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: featurePrefix │ │ │ │ - * {String} Namespace alias (or prefix) for feature nodes. Default is │ │ │ │ - * "feature". │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - featurePrefix: "feature", │ │ │ │ + started: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: featureName │ │ │ │ - * {String} Element name for features. Default is "featureMember". │ │ │ │ + * Property: stopDown │ │ │ │ + * {Boolean} Stop propagation of mousedown events from getting to listeners │ │ │ │ + * on the same element. Default is true. │ │ │ │ */ │ │ │ │ - featureName: "featureMember", │ │ │ │ + stopDown: true, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: layerName │ │ │ │ - * {String} Name of data layer. Default is "features". │ │ │ │ + /** │ │ │ │ + * Property: dragging │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - layerName: "features", │ │ │ │ + dragging: false, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: geometryName │ │ │ │ - * {String} Name of geometry element. Defaults to "geometry". │ │ │ │ + /** │ │ │ │ + * Property: last │ │ │ │ + * {<OpenLayers.Pixel>} The last pixel location of the drag. │ │ │ │ */ │ │ │ │ - geometryName: "geometry", │ │ │ │ + last: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: collectionName │ │ │ │ - * {String} Name of featureCollection element. │ │ │ │ + * Property: start │ │ │ │ + * {<OpenLayers.Pixel>} The first pixel location of the drag. │ │ │ │ */ │ │ │ │ - collectionName: "FeatureCollection", │ │ │ │ + start: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: gmlns │ │ │ │ - * {String} GML Namespace. │ │ │ │ + * Property: lastMoveEvt │ │ │ │ + * {Object} The last mousemove event that occurred. Used to │ │ │ │ + * position the map correctly when our "delay drag" │ │ │ │ + * timeout expired. │ │ │ │ */ │ │ │ │ - gmlns: "http://www.opengis.net/gml", │ │ │ │ + lastMoveEvt: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: extractAttributes │ │ │ │ - * {Boolean} Extract attributes from GML. │ │ │ │ + * Property: oldOnselectstart │ │ │ │ + * {Function} │ │ │ │ */ │ │ │ │ - extractAttributes: true, │ │ │ │ + oldOnselectstart: 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - xy: true, │ │ │ │ + interval: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.GML │ │ │ │ - * Create a new parser for GML. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * Property: timeoutId │ │ │ │ + * {String} The id of the timeout used for the mousedown interval. │ │ │ │ + * This is "private", and should be left alone. │ │ │ │ */ │ │ │ │ - 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]); │ │ │ │ - }, │ │ │ │ + timeoutId: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - }, │ │ │ │ + documentDrag: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: documentEvents │ │ │ │ + * {Boolean} Are we currently observing document events? │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - }, │ │ │ │ + documentEvents: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: parseGeometry │ │ │ │ - * Properties of this object are the functions that parse geometries based │ │ │ │ - * on their type. │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - }, │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ + * Method: dragstart │ │ │ │ + * This private method is factorized from mousedown and touchstart methods │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ + * evt - {Event} The event │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} An attributes object. │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - childNode = childNode.nextSibling; │ │ │ │ - } │ │ │ │ - return attributes; │ │ │ │ - }, │ │ │ │ + document.onselectstart = OpenLayers.Function.False; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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])); │ │ │ │ + propagate = !this.stopDown; │ │ │ │ + } else { │ │ │ │ + this.started = false; │ │ │ │ + this.start = null; │ │ │ │ + this.last = null; │ │ │ │ } │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [gml]); │ │ │ │ + return propagate; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: createFeatureXML │ │ │ │ - * Accept an OpenLayers.Feature.Vector, and build a GML node for it. │ │ │ │ + /** │ │ │ │ + * Method: dragmove │ │ │ │ + * This private method is factorized from mousemove and touchmove methods │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature to be built as GML. │ │ │ │ + * evt - {Event} The event │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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(); │ │ │ │ + } │ │ │ │ } │ │ │ │ - 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); │ │ │ │ + if (this.interval > 0) { │ │ │ │ + this.timeoutId = setTimeout( │ │ │ │ + OpenLayers.Function.bind(this.removeTimeout, this), │ │ │ │ + this.interval); │ │ │ │ } │ │ │ │ - return gml; │ │ │ │ - }, │ │ │ │ + this.dragging = true; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + this.move(evt); │ │ │ │ + this.callback("move", [evt.xy]); │ │ │ │ + if (!this.oldOnselectstart) { │ │ │ │ + this.oldOnselectstart = document.onselectstart; │ │ │ │ + document.onselectstart = OpenLayers.Function.False; │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + this.last = evt.xy; │ │ │ │ } │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: buildCoordinates │ │ │ │ - * builds the coordinates XmlNode │ │ │ │ - * (code) │ │ │ │ - * <gml:coordinates decimal="." cs="," ts=" ">...</gml:coordinates> │ │ │ │ - * (end) │ │ │ │ + * Method: dragend │ │ │ │ + * This private method is factorized from mouseup and touchend methods │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} The event │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {XmlNode} created xmlNode │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - │ │ │ │ - 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 │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ + * The four methods below (down, move, up, and out) are used by subclasses │ │ │ │ + * to do their own processing related to these mouse events. │ │ │ │ */ │ │ │ │ - defaultPrefix: "gml", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} Schema location for a particular minor version. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - schemaLocation: null, │ │ │ │ + down: function(evt) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: featureType │ │ │ │ - * {Array(String) or String} The local (without prefix) feature typeName(s). │ │ │ │ + * 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 │ │ │ │ + * │ │ │ │ */ │ │ │ │ - featureType: null, │ │ │ │ + move: function(evt) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: featureNS │ │ │ │ - * {String} The feature namespace. Must be set in the options at │ │ │ │ - * construction. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - featureNS: null, │ │ │ │ + up: function(evt) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: geometry │ │ │ │ - * {String} Name of geometry element. Defaults to "geometry". If null, it │ │ │ │ - * will be set on <read> when the first geometry is parsed. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - geometryName: "geometry", │ │ │ │ + out: function(evt) {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: extractAttributes │ │ │ │ - * {Boolean} Extract attributes from GML. Default is true. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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. │ │ │ │ + * Method: mousedown │ │ │ │ + * Handle mousedown events │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - srsName: null, │ │ │ │ + mousedown: function(evt) { │ │ │ │ + return this.dragstart(evt); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: touchstart │ │ │ │ + * Handle touchstart events │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - xy: true, │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + return this.dragstart(evt); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: geometryTypes │ │ │ │ - * {Object} Maps OpenLayers geometry class names to GML element names. │ │ │ │ - * Use <setGeometryTypes> before accessing this property. │ │ │ │ + * Method: mousemove │ │ │ │ + * Handle mousemove events │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - geometryTypes: null, │ │ │ │ + mousemove: function(evt) { │ │ │ │ + return this.dragmove(evt); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: singleFeatureType │ │ │ │ - * {Boolean} True if there is only 1 featureType, and not an array │ │ │ │ - * of featuretypes. │ │ │ │ + * Method: touchmove │ │ │ │ + * Handle touchmove events │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - singleFeatureType: null, │ │ │ │ + touchmove: function(evt) { │ │ │ │ + return this.dragmove(evt); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ + * Method: mouseup │ │ │ │ + * Handle mouseup events │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g), │ │ │ │ - featureMember: (/^(.*:)?featureMembers?$/) │ │ │ │ + mouseup: function(evt) { │ │ │ │ + return this.dragend(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: touchend │ │ │ │ + * Handle touchend events │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ - * 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). │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ + 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: read │ │ │ │ + * Method: mouseout │ │ │ │ + * Handle mouseout events │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * data - {DOMElement} A gml:featureMember element, a gml:featureMembers │ │ │ │ - * element, or an element containing either of the above at any level. │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} An array of features. │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + mouseout: function(evt) { │ │ │ │ + if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ + if (this.documentDrag === true) { │ │ │ │ + this.addDocumentEvents(); │ │ │ │ } else { │ │ │ │ - // look for gml:featureMembers elements (this is v3, but does no harm here) │ │ │ │ - var elements = this.getElementsByTagNameNS( │ │ │ │ - data, this.namespaces.gml, "featureMembers" │ │ │ │ + var dragged = (this.start != this.last); │ │ │ │ + this.started = false; │ │ │ │ + this.dragging = false; │ │ │ │ + OpenLayers.Element.removeClass( │ │ │ │ + this.map.viewPortDiv, "olDragDown" │ │ │ │ ); │ │ │ │ - if (elements.length) { │ │ │ │ - // there can be only one │ │ │ │ - this.readNode(elements[0], { │ │ │ │ - features: features │ │ │ │ - }, true); │ │ │ │ + this.out(evt); │ │ │ │ + this.callback("out", []); │ │ │ │ + if (dragged) { │ │ │ │ + this.callback("done", [evt.xy]); │ │ │ │ + } │ │ │ │ + if (document.onselectstart) { │ │ │ │ + document.onselectstart = this.oldOnselectstart; │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ - return features; │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * {Object} The input object, modified (or a new one if none was provided). │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - 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]); │ │ │ │ + click: function(evt) { │ │ │ │ + // let the click event propagate only if the mouse moved │ │ │ │ + return (this.start == this.last); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: activate │ │ │ │ + * Activate the handler. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The handler was successfully activated. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + activate: function() { │ │ │ │ + var activated = false; │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.dragging = false; │ │ │ │ + activated = true; │ │ │ │ } │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: write │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector} │ │ │ │ - * An array of features or a single feature. │ │ │ │ - * │ │ │ │ + * Method: deactivate │ │ │ │ + * Deactivate the handler. │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * {Boolean} The handler was successfully deactivated. │ │ │ │ */ │ │ │ │ - write: function(features) { │ │ │ │ - var name; │ │ │ │ - if (OpenLayers.Util.isArray(features)) { │ │ │ │ - name = "featureMembers"; │ │ │ │ - } else { │ │ │ │ - name = "featureMember"; │ │ │ │ + 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" │ │ │ │ + ); │ │ │ │ } │ │ │ │ - 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]); │ │ │ │ + return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + adjustXY: function(evt) { │ │ │ │ + var pos = OpenLayers.Util.pagePosition(this.map.viewPortDiv); │ │ │ │ + evt.xy.x -= pos[0]; │ │ │ │ + evt.xy.y -= pos[1]; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setGeometryTypes │ │ │ │ - * Sets the <geometryTypes> mapping. │ │ │ │ + * Method: addDocumentEvents │ │ │ │ + * Start observing document events when documentDrag is true and the mouse │ │ │ │ + * cursor leaves the map viewport while dragging. │ │ │ │ */ │ │ │ │ - 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" │ │ │ │ - }; │ │ │ │ + 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); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.GML.Base" │ │ │ │ + /** │ │ │ │ + * 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/Format/GML/v2.js │ │ │ │ + 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/Format/GML/Base.js │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Handler/Drag.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.GML.v2 │ │ │ │ - * Parses GML version 2. │ │ │ │ + * Class: OpenLayers.Control.DragPan │ │ │ │ + * The DragPan control pans the map with a drag of the mouse. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.GML.Base> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, { │ │ │ │ +OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} Schema location for a particular minor version. │ │ │ │ + /** │ │ │ │ + * Property: type │ │ │ │ + * {OpenLayers.Control.TYPES} │ │ │ │ */ │ │ │ │ - schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd", │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: panned │ │ │ │ + * {Boolean} The map moved. │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]); │ │ │ │ - }, │ │ │ │ + panned: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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"] │ │ │ │ - }, │ │ │ │ + interval: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: documentDrag │ │ │ │ + * {Boolean} If set to true, mouse dragging will continue even if the │ │ │ │ + * mouse cursor leaves the map viewport. Default is false. │ │ │ │ */ │ │ │ │ - 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]); │ │ │ │ - }, │ │ │ │ + documentDrag: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: kinetic │ │ │ │ + * {<OpenLayers.Kinetic>} The OpenLayers.Kinetic object. │ │ │ │ */ │ │ │ │ - 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/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, { │ │ │ │ + kinetic: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - namespaces: { │ │ │ │ - ogc: "http://www.opengis.net/ogc" │ │ │ │ - }, │ │ │ │ + enableKinetic: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ + * APIProperty: kineticInterval │ │ │ │ + * {Integer} Interval in milliseconds between 2 steps in the "kinetic │ │ │ │ + * scrolling". Applies only if enableKinetic is set. Defaults │ │ │ │ + * to 10 milliseconds. │ │ │ │ */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ - }, │ │ │ │ + kineticInterval: 10, │ │ │ │ + │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ + * Method: draw │ │ │ │ + * Creates a Drag handler, using <panMap> and │ │ │ │ + * <panMapDone> as callbacks. │ │ │ │ */ │ │ │ │ - defaultPrefix: "ogc", │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: panMapStart │ │ │ │ */ │ │ │ │ + panMapStart: function() { │ │ │ │ + if (this.kinetic) { │ │ │ │ + this.kinetic.begin(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read OGC exception report data from a string, and return an object with │ │ │ │ - * information about the exceptions. │ │ │ │ + * Method: panMap │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} Information about the exceptions that occurred. │ │ │ │ + * xy - {<OpenLayers.Pixel>} Pixel of the mouse position │ │ │ │ */ │ │ │ │ - read: function(data) { │ │ │ │ - var result; │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ + panMap: function(xy) { │ │ │ │ + if (this.kinetic) { │ │ │ │ + this.kinetic.update(xy); │ │ │ │ } │ │ │ │ - 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); │ │ │ │ + this.panned = true; │ │ │ │ + this.map.pan( │ │ │ │ + this.handler.last.x - xy.x, │ │ │ │ + this.handler.last.y - xy.y, { │ │ │ │ + dragging: true, │ │ │ │ + animate: false │ │ │ │ } │ │ │ │ - } │ │ │ │ - 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. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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.Format.OGCExceptionReport" │ │ │ │ - │ │ │ │ + CLASS_NAME: "OpenLayers.Control.DragPan" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/XML/VersionedOGC.js │ │ │ │ + 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/Format/XML.js │ │ │ │ - * @requires OpenLayers/Format/OGCExceptionReport.js │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.XML.VersionedOGC │ │ │ │ - * Base class for versioned formats, i.e. a format which supports multiple │ │ │ │ - * versions. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * 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.Format.XML> │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -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, │ │ │ │ +OpenLayers.Handler.Pinch = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: profile │ │ │ │ - * {String} If provided, use a custom profile. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - profile: null, │ │ │ │ + started: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: stopDown │ │ │ │ + * {Boolean} Stop propagation of touchstart events from getting to │ │ │ │ + * listeners on the same element. Default is false. │ │ │ │ */ │ │ │ │ - allowFallback: false, │ │ │ │ + stopDown: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: name │ │ │ │ - * {String} The name of this parser, this is the part of the CLASS_NAME │ │ │ │ - * except for "OpenLayers.Format." │ │ │ │ + * Property: pinching │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - name: null, │ │ │ │ + pinching: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: stringifyOutput │ │ │ │ - * {Boolean} If true, write will return a string otherwise a DOMElement. │ │ │ │ - * Default is false. │ │ │ │ + * Property: last │ │ │ │ + * {Object} Object that store informations related to pinch last touch. │ │ │ │ */ │ │ │ │ - stringifyOutput: false, │ │ │ │ + last: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: parser │ │ │ │ - * {Object} Instance of the versioned parser. Cached for multiple read and │ │ │ │ - * write calls of the same version. │ │ │ │ + * Property: start │ │ │ │ + * {Object} Object that store informations related to pinch touchstart. │ │ │ │ */ │ │ │ │ - parser: null, │ │ │ │ + start: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.XML.VersionedOGC. │ │ │ │ - * Constructor. │ │ │ │ + * Constructor: OpenLayers.Handler.Pinch │ │ │ │ + * Returns OpenLayers.Handler.Pinch │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on │ │ │ │ - * the object. │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - 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. │ │ │ │ + * Method: touchstart │ │ │ │ + * Handle touchstart events │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * root - {DOMElement} │ │ │ │ - * options - {Object} Optional configuration object. │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} The version to use. │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - return version; │ │ │ │ + // prevent document dragging │ │ │ │ + OpenLayers.Event.preventDefault(evt); │ │ │ │ + return propagate; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getParser │ │ │ │ - * Get an instance of the cached parser if available, otherwise create one. │ │ │ │ + * Method: touchmove │ │ │ │ + * Handle touchmove events │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * version - {String} │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Format>} │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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 this.parser; │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Write a document. │ │ │ │ + * Method: touchend │ │ │ │ + * Handle touchend events │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * obj - {Object} An object representing the document. │ │ │ │ - * options - {Object} Optional configuration object. │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} The document as a string │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - 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]); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: activate │ │ │ │ + * Activate the handler. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} An object representing the document. │ │ │ │ + * {Boolean} The handler was successfully activated. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + activate: function() { │ │ │ │ + var activated = false; │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.pinching = false; │ │ │ │ + activated = true; │ │ │ │ } │ │ │ │ - obj.version = version; │ │ │ │ - return obj; │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.XML.VersionedOGC" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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). │ │ │ │ + * Method: deactivate │ │ │ │ + * Deactivate the handler. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * {Boolean} The handler was successfully deactivated. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - this.filters = null; │ │ │ │ - OpenLayers.Filter.prototype.destroy.apply(this); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: evaluate │ │ │ │ - * Evaluates this filter in a specific context. │ │ │ │ - * │ │ │ │ + * Method: getDistance │ │ │ │ + * Get the distance in pixels between two touches. │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ - * │ │ │ │ + * touches - {Array(Object)} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} The filter applies. │ │ │ │ + * {Number} The distance in pixels. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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) │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Clones this filter. │ │ │ │ - * │ │ │ │ + * Method: getPinchData │ │ │ │ + * Get informations about the pinch event. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Filter.Logical>} Clone of this filter. │ │ │ │ + * {Object} Object that contains data about the current pinch. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + 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.Filter.Logical" │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Pinch" │ │ │ │ }); │ │ │ │ │ │ │ │ - │ │ │ │ -OpenLayers.Filter.Logical.AND = "&&"; │ │ │ │ -OpenLayers.Filter.Logical.OR = "||"; │ │ │ │ -OpenLayers.Filter.Logical.NOT = "!"; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Filter/Comparison.js │ │ │ │ + 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/Filter.js │ │ │ │ + * @requires OpenLayers/Handler/Pinch.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Filter.Comparison │ │ │ │ - * This class represents a comparison filter. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Filter> │ │ │ │ + * Class: OpenLayers.Control.PinchZoom │ │ │ │ + * │ │ │ │ + * Inherits: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Filter.Comparison = OpenLayers.Class(OpenLayers.Filter, { │ │ │ │ +OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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"; │ │ │ │ + /** │ │ │ │ + * Property: type │ │ │ │ + * {OpenLayers.Control.TYPES} │ │ │ │ */ │ │ │ │ - type: null, │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: property │ │ │ │ - * {String} │ │ │ │ - * name of the context property to compare │ │ │ │ + * Property: pinchOrigin │ │ │ │ + * {Object} Cached object representing the pinch start (in pixels). │ │ │ │ */ │ │ │ │ - property: null, │ │ │ │ + pinchOrigin: 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}" │ │ │ │ + * Property: currentCenter │ │ │ │ + * {Object} Cached object representing the latest pinch center (in pixels). │ │ │ │ */ │ │ │ │ - value: null, │ │ │ │ + currentCenter: 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. │ │ │ │ + * APIProperty: autoActivate │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * true. │ │ │ │ */ │ │ │ │ - matchCase: true, │ │ │ │ + autoActivate: 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}" │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - lowerBoundary: null, │ │ │ │ + preserveCenter: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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}" │ │ │ │ + * APIProperty: handlerOptions │ │ │ │ + * {Object} Used to set non-default properties on the pinch handler │ │ │ │ */ │ │ │ │ - upperBoundary: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Filter.Comparison │ │ │ │ - * Creates a comparison rule. │ │ │ │ + /** │ │ │ │ + * 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 with properties to set on the │ │ │ │ - * rule │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Filter.Comparison>} │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * the control │ │ │ │ */ │ │ │ │ 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; │ │ │ │ - } │ │ │ │ + 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); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: evaluate │ │ │ │ - * Evaluates this filter in a specific context. │ │ │ │ - * │ │ │ │ + * Method: pinchStart │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + pinchStart: function(evt, pinchData) { │ │ │ │ + var xy = (this.preserveCenter) ? │ │ │ │ + this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; │ │ │ │ + this.pinchOrigin = xy; │ │ │ │ + this.currentCenter = xy; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + * Method: pinchMove │ │ │ │ + * │ │ │ │ * 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 │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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 : "!"; │ │ │ │ + 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; │ │ │ │ │ │ │ │ - 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); │ │ │ │ + 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)); │ │ │ │ │ │ │ │ - return this.value; │ │ │ │ + this.map.applyTransform(dx, dy, scale); │ │ │ │ + this.currentCenter = current; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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 : "!."; │ │ │ │ - }); │ │ │ │ + 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); │ │ │ │ │ │ │ │ - // replace \* with #* (watching out for \\*) │ │ │ │ - value = value.replace(/(\\)?\\\*/g, function($0, $1) { │ │ │ │ - return $1 ? $0 : "!*"; │ │ │ │ - }); │ │ │ │ + var location = this.map.getLonLatFromPixel(this.pinchOrigin); │ │ │ │ + var zoomPixel = this.currentCenter; │ │ │ │ + var size = this.map.getSize(); │ │ │ │ │ │ │ │ - // replace \\ with \ │ │ │ │ - value = value.replace(/\\\\/g, "\\"); │ │ │ │ + location.lon += resolution * ((size.w / 2) - zoomPixel.x); │ │ │ │ + location.lat -= resolution * ((size.h / 2) - zoomPixel.y); │ │ │ │ │ │ │ │ - // convert .* to * (the sequence #.* is not allowed) │ │ │ │ - value = value.replace(/\.\*/g, "*"); │ │ │ │ + // 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; │ │ │ │ │ │ │ │ - return value; │ │ │ │ + this.map.setCenter(location, zoom); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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.Control.PinchZoom" │ │ │ │ │ │ │ │ - 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 │ │ │ │ + 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/Format/XML/VersionedOGC.js │ │ │ │ - * @requires OpenLayers/Filter/FeatureId.js │ │ │ │ - * @requires OpenLayers/Filter/Logical.js │ │ │ │ - * @requires OpenLayers/Filter/Comparison.js │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.Filter │ │ │ │ - * Read/Write ogc:Filter. Create a new instance with the <OpenLayers.Format.Filter> │ │ │ │ - * constructor. │ │ │ │ + * 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.Format.XML.VersionedOGC> │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.Filter = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - │ │ │ │ +OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ /** │ │ │ │ - * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "1.0.0". │ │ │ │ + * APIProperty: delay │ │ │ │ + * {Number} Number of milliseconds between clicks before the event is │ │ │ │ + * considered a double-click. │ │ │ │ */ │ │ │ │ - defaultVersion: "1.0.0", │ │ │ │ + delay: 300, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: double │ │ │ │ + * {Boolean} Handle double-clicks. Default is false. │ │ │ │ */ │ │ │ │ + 'double': false, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.Filter" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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: 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: name │ │ │ │ - * {String} Name of the function. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - name: null, │ │ │ │ + dblclickTolerance: 13, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: params │ │ │ │ - * {Array(<OpenLayers.Filter.Function> || String || Number)} Function parameters │ │ │ │ - * For now support only other Functions, String or Number │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - params: null, │ │ │ │ + stopSingle: false, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Filter.Function │ │ │ │ - * Creates a filter function. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object with properties to set on the │ │ │ │ - * function. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Filter.Function>} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Filter.Function" │ │ │ │ -}); │ │ │ │ - │ │ │ │ -/* ====================================================================== │ │ │ │ - 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, { │ │ │ │ + stopDouble: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + * Property: timerId │ │ │ │ + * {Number} The id of the timeout waiting to clear the <delayedCall>. │ │ │ │ */ │ │ │ │ - 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" │ │ │ │ - }, │ │ │ │ + timerId: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - defaultPrefix: "ogc", │ │ │ │ + down: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} Schema location for a particular minor version. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - schemaLocation: null, │ │ │ │ + last: 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. │ │ │ │ + /** │ │ │ │ + * Property: first │ │ │ │ + * {Object} When waiting for double clicks, this object will store │ │ │ │ + * information about the first click in a two click sequence. │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ - }, │ │ │ │ + first: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: read │ │ │ │ - * │ │ │ │ + * 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: │ │ │ │ - * data - {DOMElement} A Filter document element. │ │ │ │ + * 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: │ │ │ │ - * {<OpenLayers.Filter>} A filter object. │ │ │ │ + * {Boolean} Continue propagating this event. │ │ │ │ */ │ │ │ │ - read: function(data) { │ │ │ │ - var obj = {}; │ │ │ │ - this.readers.ogc["Filter"].apply(this, [data, obj]); │ │ │ │ - return obj.filter; │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + this.down = this.getEventInfo(evt); │ │ │ │ + this.last = this.getEventInfo(evt); │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: touchmove │ │ │ │ + * Store position of last move, because touchend event can have │ │ │ │ + * an empty "touches" property. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Continue propagating this event. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - 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]; │ │ │ │ + // 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(); │ │ │ │ } │ │ │ │ - }, │ │ │ │ - "FeatureId": function(node, obj) { │ │ │ │ - var fid = node.getAttribute("fid"); │ │ │ │ - if (fid) { │ │ │ │ - obj.fids.push(fid); │ │ │ │ + } 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; │ │ │ │ + } │ │ │ │ } │ │ │ │ - }, │ │ │ │ - "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); │ │ │ │ } │ │ │ │ } │ │ │ │ + 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: readSpatial │ │ │ │ + * Method: passesDblclickTolerance │ │ │ │ + * Determine whether the event is within the optional double-cick pixel │ │ │ │ + * tolerance. │ │ │ │ * │ │ │ │ - * Read a {<OpenLayers.Filter.Spatial>} filter. │ │ │ │ + * 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/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: │ │ │ │ - * node - {DOMElement} A DOM element that contains an ogc:expression. │ │ │ │ - * obj - {Object} The target object. │ │ │ │ - * type - {String} One of the OpenLayers.Filter.Spatial.* constants. │ │ │ │ + * 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: │ │ │ │ - * {<OpenLayers.Filter.Spatial>} The created filter. │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + return OpenLayers.Event.isMultiTouch(evt) ? │ │ │ │ + true : this.mousedown(evt); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: encodeLiteral │ │ │ │ - * Generates the string representation of a value for use in <Literal> │ │ │ │ - * elements. The default encoder writes Date values as ISO 8601 │ │ │ │ - * strings. │ │ │ │ + * 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: │ │ │ │ - * value - {Object} Literal value to encode │ │ │ │ + * 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: │ │ │ │ - * {String} String representation of the provided value. │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - encodeLiteral: function(value) { │ │ │ │ - if (value instanceof Date) { │ │ │ │ - value = OpenLayers.Date.toISOString(value); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - return value; │ │ │ │ + this.handle(evt); │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: writeOgcExpression │ │ │ │ - * Limited support for writing OGC expressions. Currently it supports │ │ │ │ - * (<OpenLayers.Filter.Function> || String || Number) │ │ │ │ + * Method: dblclick │ │ │ │ + * Handle dblclick. Call the "dblclick" callback if dblclick on a feature. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * value - (<OpenLayers.Filter.Function> || String || Number) │ │ │ │ - * node - {DOMElement} A parent DOM element │ │ │ │ + * evt - {Event} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} Updated node element. │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - writeOgcExpression: function(value, node) { │ │ │ │ - if (value instanceof OpenLayers.Filter.Function) { │ │ │ │ - this.writeNode("Function", value, node); │ │ │ │ + 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.writeNode("Literal", value, node); │ │ │ │ + this.map.setLayerZIndex(this.layer, │ │ │ │ + this.map.getLayerIndex(this.layer)); │ │ │ │ } │ │ │ │ - return node; │ │ │ │ }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Feature" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: write │ │ │ │ + * 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: │ │ │ │ - * filter - {<OpenLayers.Filter>} A filter object. │ │ │ │ + * 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: │ │ │ │ - * {DOMElement} An ogc:Filter element. │ │ │ │ + * {<OpenLayers.Layer.Vector.RootContainer>} A new vector layer root │ │ │ │ + * container │ │ │ │ */ │ │ │ │ - write: function(filter) { │ │ │ │ - return this.writers.ogc["Filter"].apply(this, [filter]); │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: setMap │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "FeatureId": function(fid) { │ │ │ │ - return this.createElementNSPlus("ogc:FeatureId", { │ │ │ │ - attributes: { │ │ │ │ - fid: fid │ │ │ │ + ) │ │ │ │ + }; │ │ │ │ + │ │ │ │ + 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 │ │ │ │ }); │ │ │ │ - }, │ │ │ │ - "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 │ │ │ │ - ); │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - 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 │ │ │ │ - ); │ │ │ │ + } │ │ │ │ + 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/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/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; │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + move: function(pixel) { │ │ │ │ + delete this._unselect; │ │ │ │ + if (this.vertex) { │ │ │ │ + this.dragVertex(this.vertex, pixel); │ │ │ │ + } │ │ │ │ }, │ │ │ │ - "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; │ │ │ │ + up: function() { │ │ │ │ + this.handlers.drag.stopDown = false; │ │ │ │ + if (this._unselect) { │ │ │ │ + this.unselectFeature(this._unselect); │ │ │ │ + delete this._unselect; │ │ │ │ + } │ │ │ │ }, │ │ │ │ - "PropertyName": function(filter) { │ │ │ │ - // no ogc:expression handling for now │ │ │ │ - return this.createElementNSPlus("ogc:PropertyName", { │ │ │ │ - value: filter.property │ │ │ │ + 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 │ │ │ │ }); │ │ │ │ - }, │ │ │ │ - "Literal": function(value) { │ │ │ │ - var encode = this.encodeLiteral || │ │ │ │ - OpenLayers.Format.Filter.v1.prototype.encodeLiteral; │ │ │ │ - return this.createElementNSPlus("ogc:Literal", { │ │ │ │ - value: encode(value) │ │ │ │ + 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 │ │ │ │ }); │ │ │ │ - }, │ │ │ │ - "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 │ │ │ │ + } │ │ │ │ + // dragging a radius handle - no special treatment │ │ │ │ + if (this.virtualVertices.length > 0) { │ │ │ │ + this.layer.destroyFeatures(this.virtualVertices, { │ │ │ │ + silent: true │ │ │ │ }); │ │ │ │ - }, │ │ │ │ - "Function": function(filter) { │ │ │ │ - var node = this.createElementNSPlus("ogc:Function", { │ │ │ │ - attributes: { │ │ │ │ - name: filter.name │ │ │ │ - } │ │ │ │ + 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 │ │ │ │ }); │ │ │ │ - var params = filter.params; │ │ │ │ - for (var i = 0, len = params.length; i < len; i++) { │ │ │ │ - this.writeOgcExpression(params[i], node); │ │ │ │ + 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/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 │ │ │ │ + } │ │ │ │ + ); │ │ │ │ } │ │ │ │ - return node; │ │ │ │ }, │ │ │ │ - "PropertyIsNull": function(filter) { │ │ │ │ - var node = this.createElementNSPlus("ogc:PropertyIsNull"); │ │ │ │ - this.writeNode("PropertyName", filter, node); │ │ │ │ - return node; │ │ │ │ + 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: getFilterType │ │ │ │ + * Method: drawFeature │ │ │ │ */ │ │ │ │ - getFilterType: function(filter) { │ │ │ │ - var filterType = this.filterMap[filter.type]; │ │ │ │ - if (!filterType) { │ │ │ │ - throw "Filter writing not supported for rule type: " + filter.type; │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ } │ │ │ │ - return filterType; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: filterMap │ │ │ │ - * {Object} Contains a member for each filter type. Values are node names │ │ │ │ - * for corresponding OGC Filter child elements. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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" │ │ │ │ + insertXY: function(x, y) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertXY(x, y); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.Filter.v1" │ │ │ │ + /** │ │ │ │ + * 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/Format/Filter/v1_0_0.js │ │ │ │ + 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. */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * @requires OpenLayers/Format/GML/v2.js │ │ │ │ - * @requires OpenLayers/Format/Filter/v1.js │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.Filter.v1_0_0 │ │ │ │ - * Write ogc:Filter version 1.0.0. │ │ │ │ - * │ │ │ │ + * @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.GML.v2> │ │ │ │ - * - <OpenLayers.Format.Filter.v1> │ │ │ │ + * - <OpenLayers.Format> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.Filter.v1_0_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.GML.v2, OpenLayers.Format.Filter.v1, { │ │ │ │ +OpenLayers.Format.JSON = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: VERSION │ │ │ │ - * {String} 1.0.0 │ │ │ │ - */ │ │ │ │ - VERSION: "1.0.0", │ │ │ │ + /** │ │ │ │ + * APIProperty: indent │ │ │ │ + * {String} For "pretty" printing, the indent string will be used once for │ │ │ │ + * each indentation level. │ │ │ │ + */ │ │ │ │ + indent: " ", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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", │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.Filter.v1_0_0 │ │ │ │ - * Instances of this class are not created directly. Use the │ │ │ │ - * <OpenLayers.Format.Filter> constructor instead. │ │ │ │ + * Method: serialize.object │ │ │ │ + * Transform an object into a JSON string. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * object - {Object} The object to be serialized. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A JSON string representing the object. │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.GML.v2.prototype.initialize.apply( │ │ │ │ - this, [options] │ │ │ │ - ); │ │ │ │ + '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(''); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + '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); │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.Filter.v1.prototype.readers["ogc"]), │ │ │ │ - "gml": OpenLayers.Format.GML.v2.prototype.readers["gml"], │ │ │ │ - "feature": OpenLayers.Format.GML.v2.prototype.readers["feature"] │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.level -= 1; │ │ │ │ + pieces.push(this.writeNewline(), this.writeIndent(), ']'); │ │ │ │ + return pieces.join(''); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + '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; │ │ │ │ } │ │ │ │ - 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"] │ │ │ │ + c = b.charCodeAt(); │ │ │ │ + return '\\u00' + │ │ │ │ + Math.floor(c / 16).toString(16) + │ │ │ │ + (c % 16).toString(16); │ │ │ │ + }) + '"'; │ │ │ │ + } │ │ │ │ + return '"' + string + '"'; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: writeSpatial │ │ │ │ - * │ │ │ │ - * Read a {<OpenLayers.Filter.Spatial>} filter and converts it into XML. │ │ │ │ + * Method: serialize.number │ │ │ │ + * Transform a number into a JSON string. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * filter - {<OpenLayers.Filter.Spatial>} The filter. │ │ │ │ - * name - {String} Name of the generated XML element. │ │ │ │ + * number - {Number} The number to be serialized. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} The created XML element. │ │ │ │ + * {String} A JSON string representing the number. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + '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); │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.Filter.v1_0_0" │ │ │ │ + /** │ │ │ │ + * 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/WFST/v1_0_0.js │ │ │ │ + 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/WFST/v1.js │ │ │ │ - * @requires OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ + * @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.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. │ │ │ │ + * Class: OpenLayers.Format.GeoJSON │ │ │ │ + * Read and write GeoJSON. Create a new parser with the │ │ │ │ + * <OpenLayers.Format.GeoJSON> constructor. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.Filter.v1_0_0> │ │ │ │ - * - <OpenLayers.Format.WFST.v1> │ │ │ │ + * - <OpenLayers.Format.JSON> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WFST.v1_0_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.Filter.v1_0_0, OpenLayers.Format.WFST.v1, { │ │ │ │ +OpenLayers.Format.GeoJSON = OpenLayers.Class(OpenLayers.Format.JSON, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} WFS version number. │ │ │ │ - */ │ │ │ │ - version: "1.0.0", │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - srsNameInQuery: false, │ │ │ │ + "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]); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: schemaLocations │ │ │ │ - * {Object} Properties are namespace aliases, values are schema locations. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - schemaLocations: { │ │ │ │ - "wfs": "http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd" │ │ │ │ + "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); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WFST.v1_0_0 │ │ │ │ - * A class for parsing and generating WFS v1.0.0 transactions. │ │ │ │ + * Method: parseCoords.linestring │ │ │ │ + * Convert a coordinate array from GeoJSON into an │ │ │ │ + * <OpenLayers.Geometry>. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * array - {Object} The coordinates array from the GeoJSON fragment. │ │ │ │ * │ │ │ │ - * 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'. │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Geometry>} A geometry. │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this, [options]); │ │ │ │ - OpenLayers.Format.WFST.v1.prototype.initialize.apply(this, [options]); │ │ │ │ + "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: 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. │ │ │ │ + * Method: parseCoords.multilinestring │ │ │ │ + * Convert a coordinate array from GeoJSON into an │ │ │ │ + * <OpenLayers.Geometry>. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * array - {Object} The coordinates array from the GeoJSON fragment. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} The input object, modified (or a new one if none was provided). │ │ │ │ + * {<OpenLayers.Geometry>} A geometry. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + "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); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: parseCoords.polygon │ │ │ │ + * Convert a coordinate array from GeoJSON into an │ │ │ │ + * <OpenLayers.Geometry>. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Geometry>} A geometry. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + "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; │ │ │ │ } │ │ │ │ - }, 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"] │ │ │ │ + r = new OpenLayers.Geometry.LinearRing(l.components); │ │ │ │ + rings.push(r); │ │ │ │ + } │ │ │ │ + return new OpenLayers.Geometry.Polygon(rings); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + "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" │ │ │ │ } │ │ │ │ - if (options.filter) { │ │ │ │ - this.setFilterProperty(options.filter); │ │ │ │ - this.writeNode("ogc:Filter", options.filter, node); │ │ │ │ + }; │ │ │ │ + } else { │ │ │ │ + crs = { │ │ │ │ + "type": "name", │ │ │ │ + "properties": { │ │ │ │ + "name": "EPSG:" + code │ │ │ │ } │ │ │ │ - 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"] │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFST.v1_0_0" │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * 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/Protocol/WFS/v1_0_0.js │ │ │ │ + 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/Protocol/WFS/v1.js │ │ │ │ - * @requires OpenLayers/Format/WFST/v1_0_0.js │ │ │ │ + * @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.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. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.KML │ │ │ │ + * Read/Write KML. Create a new instance with the <OpenLayers.Format.KML> │ │ │ │ + * constructor. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol.WFS.v1> │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol.WFS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ +OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: version │ │ │ │ - * {String} WFS version number. │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ - version: "1.0.0", │ │ │ │ + namespaces: { │ │ │ │ + kml: "http://www.opengis.net/kml/2.2", │ │ │ │ + gx: "http://www.google.com/kml/ext/2.2" │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Protocol.WFS.v1_0_0 │ │ │ │ - * A class for giving layers WFS v1.0.0 protocol. │ │ │ │ + * 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} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * 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'. │ │ │ │ + * Returns: │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} List of features. │ │ │ │ */ │ │ │ │ + read: function(data) { │ │ │ │ + this.features = []; │ │ │ │ + this.styles = {}; │ │ │ │ + this.fetched = {}; │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.WFS.v1_0_0" │ │ │ │ + // 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" │ │ │ │ }); │ │ ├── ./usr/share/javascript/openlayers/OpenLayers.mobile.min.js │ │ │ ├── js-beautify {} │ │ │ │ @@ -17,14 +17,59 @@ │ │ │ │ } │ │ │ │ return function() { │ │ │ │ return l │ │ │ │ } │ │ │ │ }(), │ │ │ │ ImgPath: "" │ │ │ │ }; │ │ │ │ +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 │ │ │ │ +}; │ │ │ │ +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) │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var sourceIsEvt = typeof window.Event == "function" && source instanceof window.Event; │ │ │ │ + if (!sourceIsEvt && source.hasOwnProperty && source.hasOwnProperty("toString")) { │ │ │ │ + destination.toString = source.toString │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return destination │ │ │ │ +}; │ │ │ │ OpenLayers.String = { │ │ │ │ startsWith: function(str, sub) { │ │ │ │ return str.indexOf(sub) == 0 │ │ │ │ }, │ │ │ │ contains: function(str, sub) { │ │ │ │ return str.indexOf(sub) != -1 │ │ │ │ }, │ │ │ │ @@ -167,59 +212,14 @@ │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ return selected │ │ │ │ } │ │ │ │ }; │ │ │ │ -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 │ │ │ │ -}; │ │ │ │ -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) │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var sourceIsEvt = typeof window.Event == "function" && source instanceof window.Event; │ │ │ │ - if (!sourceIsEvt && source.hasOwnProperty && source.hasOwnProperty("toString")) { │ │ │ │ - destination.toString = source.toString │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return destination │ │ │ │ -}; │ │ │ │ OpenLayers.Bounds = OpenLayers.Class({ │ │ │ │ left: null, │ │ │ │ bottom: null, │ │ │ │ right: null, │ │ │ │ top: null, │ │ │ │ centerLonLat: null, │ │ │ │ initialize: function(left, bottom, right, top) { │ │ │ │ @@ -5452,14 +5452,3664 @@ │ │ │ │ lastY = y; │ │ │ │ callback(args.x, args.y, args.end) │ │ │ │ }; │ │ │ │ this.timerId = OpenLayers.Animation.start(OpenLayers.Function.bind(timerCallback, this)) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Kinetic" │ │ │ │ }); │ │ │ │ +OpenLayers.Renderer = OpenLayers.Class({ │ │ │ │ + container: null, │ │ │ │ + root: null, │ │ │ │ + extent: null, │ │ │ │ + locked: false, │ │ │ │ + size: null, │ │ │ │ + resolution: null, │ │ │ │ + map: null, │ │ │ │ + featureDx: 0, │ │ │ │ + initialize: function(containerID, options) { │ │ │ │ + this.container = OpenLayers.Util.getElement(containerID); │ │ │ │ + OpenLayers.Util.extend(this, options) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.container = null; │ │ │ │ + this.extent = null; │ │ │ │ + this.size = null; │ │ │ │ + this.resolution = null; │ │ │ │ + this.map = null │ │ │ │ + }, │ │ │ │ + supported: function() { │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + setSize: function(size) { │ │ │ │ + this.size = size.clone(); │ │ │ │ + this.resolution = null │ │ │ │ + }, │ │ │ │ + getResolution: function() { │ │ │ │ + this.resolution = this.resolution || this.map.getResolution(); │ │ │ │ + return this.resolution │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawGeometry: function(geometry, style, featureId) {}, │ │ │ │ + drawText: function(featureId, style, location) {}, │ │ │ │ + removeText: function(featureId) {}, │ │ │ │ + clear: function() {}, │ │ │ │ + getFeatureIdFromEvent: function(evt) {}, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + eraseGeometry: function(geometry, featureId) {}, │ │ │ │ + moveRoot: function(renderer) {}, │ │ │ │ + getRenderLayerId: function() { │ │ │ │ + return this.container.id │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +OpenLayers.Renderer.defaultSymbolizer = { │ │ │ │ + fillColor: "#000000", │ │ │ │ + strokeColor: "#000000", │ │ │ │ + strokeWidth: 2, │ │ │ │ + fillOpacity: 1, │ │ │ │ + strokeOpacity: 1, │ │ │ │ + pointRadius: 0, │ │ │ │ + labelAlign: "cm" │ │ │ │ +}; │ │ │ │ +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 = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ + hitDetection: true, │ │ │ │ + hitOverflow: 0, │ │ │ │ + canvas: null, │ │ │ │ + features: null, │ │ │ │ + pendingRedraw: false, │ │ │ │ + cachedSymbolBounds: {}, │ │ │ │ + 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") │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setExtent: function() { │ │ │ │ + OpenLayers.Renderer.prototype.setExtent.apply(this, arguments); │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + eraseGeometry: function(geometry, featureId) { │ │ │ │ + this.eraseFeatures(this.features[featureId][0]) │ │ │ │ + }, │ │ │ │ + supported: function() { │ │ │ │ + return OpenLayers.CANVAS_SUPPORTED │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawFeature: function(feature, style) { │ │ │ │ + var rendered; │ │ │ │ + if (feature.geometry) { │ │ │ │ + style = this.applyDefaultSymbolizer(style || feature.style); │ │ │ │ + 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) { │ │ │ │ + this.features[feature.id] = [feature, style] │ │ │ │ + } else { │ │ │ │ + delete this.features[feature.id] │ │ │ │ + } │ │ │ │ + this.pendingRedraw = true │ │ │ │ + } │ │ │ │ + if (this.pendingRedraw && !this.locked) { │ │ │ │ + this.redraw(); │ │ │ │ + this.pendingRedraw = false │ │ │ │ + } │ │ │ │ + return rendered │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 : -(.5 * width); │ │ │ │ + var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.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 / 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 │ │ │ │ + }, │ │ │ │ + drawNamedSymbol: function(geometry, style, featureId) { │ │ │ │ + var x, y, cx, cy, i, symbolBounds, scaling, angle; │ │ │ │ + var unscaledStrokeWidth; │ │ │ │ + var deg2rad = Math.PI / 180; │ │ │ │ + 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; │ │ │ │ + this.canvas.lineCap = "round"; │ │ │ │ + this.canvas.lineJoin = "round"; │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.lineCap = "round"; │ │ │ │ + this.hitContext.lineJoin = "round" │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + this.canvas.save(); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.save() │ │ │ │ + } │ │ │ │ + this.canvas.translate(p0, p1); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.translate(p0, p1) │ │ │ │ + } │ │ │ │ + angle = deg2rad * style.rotation; │ │ │ │ + if (!isNaN(angle)) { │ │ │ │ + this.canvas.rotate(angle); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.rotate(angle) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + scaling = 2 * style.pointRadius / Math.max(symbolBounds.getWidth(), symbolBounds.getHeight()); │ │ │ │ + this.canvas.scale(scaling, scaling); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.scale(scaling, scaling) │ │ │ │ + } │ │ │ │ + cx = symbolBounds.getCenterLonLat().lon; │ │ │ │ + cy = symbolBounds.getCenterLonLat().lat; │ │ │ │ + this.canvas.translate(-cx, -cy); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.translate(-cx, -cy) │ │ │ │ + } │ │ │ │ + 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") │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + featureIdToHex: function(featureId) { │ │ │ │ + var id = Number(featureId.split("_").pop()) + 1; │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + setHitContextStyle: function(type, featureId, symbolizer, strokeScaling) { │ │ │ │ + var hex = this.featureIdToHex(featureId); │ │ │ │ + if (type == "fill") { │ │ │ │ + this.hitContext.globalAlpha = 1; │ │ │ │ + this.hitContext.fillStyle = hex │ │ │ │ + } else if (type == "stroke") { │ │ │ │ + this.hitContext.globalAlpha = 1; │ │ │ │ + this.hitContext.strokeStyle = hex; │ │ │ │ + if (typeof strokeScaling === "undefined") { │ │ │ │ + this.hitContext.lineWidth = symbolizer.strokeWidth + 2 │ │ │ │ + } else { │ │ │ │ + if (!isNaN(strokeScaling)) { │ │ │ │ + this.hitContext.lineWidth = symbolizer.strokeWidth + 2 / strokeScaling │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.hitContext.globalAlpha = 0; │ │ │ │ + this.hitContext.lineWidth = 1 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawLineString: function(geometry, style, featureId) { │ │ │ │ + style = OpenLayers.Util.applyDefaults({ │ │ │ │ + fill: false │ │ │ │ + }, style); │ │ │ │ + this.drawLinearRing(geometry, style, featureId) │ │ │ │ + }, │ │ │ │ + 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") │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawPolygon: function(geometry, style, featureId) { │ │ │ │ + var components = geometry.components; │ │ │ │ + var len = components.length; │ │ │ │ + this.drawLinearRing(components[0], style, featureId); │ │ │ │ + for (var i = 1; i < len; ++i) { │ │ │ │ + this.canvas.globalCompositeOperation = "destination-out"; │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.globalCompositeOperation = "destination-out" │ │ │ │ + } │ │ │ │ + this.drawLinearRing(components[i], OpenLayers.Util.applyDefaults({ │ │ │ │ + stroke: false, │ │ │ │ + fillOpacity: 1 │ │ │ │ + }, 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawText: function(location, style) { │ │ │ │ + var pt = this.getLocalXY(location); │ │ │ │ + this.setCanvasStyle("reset"); │ │ │ │ + this.canvas.fillStyle = style.fontColor; │ │ │ │ + this.canvas.globalAlpha = style.fontOpacity || 1; │ │ │ │ + var fontStyle = [style.fontStyle ? style.fontStyle : "normal", "normal", 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) { │ │ │ │ + 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; │ │ │ │ + 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) { │ │ │ │ + this.canvas.mozTextStyle = fontStyle; │ │ │ │ + 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") │ │ │ │ + }, │ │ │ │ + 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] │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getFeatureIdFromEvent: function(evt) { │ │ │ │ + var featureId, feature; │ │ │ │ + if (this.hitDetection && this.root.style.display !== "none") { │ │ │ │ + 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) { │ │ │ │ + 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) {} │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return feature │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +OpenLayers.Renderer.Canvas.LABEL_ALIGN = { │ │ │ │ + l: "left", │ │ │ │ + r: "right", │ │ │ │ + t: "top", │ │ │ │ + b: "bottom" │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.Canvas.LABEL_FACTOR = { │ │ │ │ + l: 0, │ │ │ │ + r: -1, │ │ │ │ + t: 0, │ │ │ │ + b: -1 │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.Canvas.drawImageScaleFactor = null; │ │ │ │ +OpenLayers.ElementsIndexer = OpenLayers.Class({ │ │ │ │ + maxZIndex: null, │ │ │ │ + order: null, │ │ │ │ + indices: null, │ │ │ │ + compare: null, │ │ │ │ + initialize: function(yOrdering) { │ │ │ │ + this.compare = yOrdering ? OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER : OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER; │ │ │ │ + this.clear() │ │ │ │ + }, │ │ │ │ + insert: function(newNode) { │ │ │ │ + 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); │ │ │ │ + return this.getNextElement(rightIndex) │ │ │ │ + }, │ │ │ │ + remove: function(node) { │ │ │ │ + var nodeId = node.id; │ │ │ │ + var arrayIndex = OpenLayers.Util.indexOf(this.order, nodeId); │ │ │ │ + if (arrayIndex >= 0) { │ │ │ │ + this.order.splice(arrayIndex, 1); │ │ │ │ + delete this.indices[nodeId]; │ │ │ │ + if (this.order.length > 0) { │ │ │ │ + var lastId = this.order[this.order.length - 1]; │ │ │ │ + this.maxZIndex = this.indices[lastId] │ │ │ │ + } else { │ │ │ │ + this.maxZIndex = 0 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + clear: function() { │ │ │ │ + this.order = []; │ │ │ │ + this.indices = {}; │ │ │ │ + this.maxZIndex = 0 │ │ │ │ + }, │ │ │ │ + exists: function(node) { │ │ │ │ + return this.indices[node.id] != null │ │ │ │ + }, │ │ │ │ + getZIndex: function(node) { │ │ │ │ + return node._style.graphicZIndex │ │ │ │ + }, │ │ │ │ + determineZIndex: function(node) { │ │ │ │ + var zIndex = node._style.graphicZIndex; │ │ │ │ + if (zIndex == null) { │ │ │ │ + zIndex = this.maxZIndex; │ │ │ │ + node._style.graphicZIndex = zIndex │ │ │ │ + } else if (zIndex > this.maxZIndex) { │ │ │ │ + this.maxZIndex = zIndex │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +OpenLayers.ElementsIndexer.IndexingMethods = { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + Z_ORDER_DRAWING_ORDER: function(indexer, newNode, nextNode) { │ │ │ │ + var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(indexer, newNode, nextNode); │ │ │ │ + if (nextNode && returnVal == 0) { │ │ │ │ + returnVal = 1 │ │ │ │ + } │ │ │ │ + return returnVal │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ + rendererRoot: null, │ │ │ │ + root: null, │ │ │ │ + vectorRoot: null, │ │ │ │ + textRoot: null, │ │ │ │ + xmlns: null, │ │ │ │ + xOffset: 0, │ │ │ │ + indexer: null, │ │ │ │ + BACKGROUND_ID_SUFFIX: "_background", │ │ │ │ + LABEL_ID_SUFFIX: "_label", │ │ │ │ + LABEL_OUTLINE_SUFFIX: "_outline", │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.clear(); │ │ │ │ + this.rendererRoot = null; │ │ │ │ + this.root = null; │ │ │ │ + this.xmlns = null; │ │ │ │ + OpenLayers.Renderer.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + getNodeType: function(geometry, style) {}, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + redrawNode: function(id, geometry, style, featureId) { │ │ │ │ + style = this.applyDefaultSymbolizer(style); │ │ │ │ + var node = this.nodeFactory(id, this.getNodeType(geometry, style)); │ │ │ │ + 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; │ │ │ │ + if (this.indexer) { │ │ │ │ + var insert = this.indexer.insert(node); │ │ │ │ + if (insert) { │ │ │ │ + this.vectorRoot.insertBefore(node, insert) │ │ │ │ + } else { │ │ │ │ + this.vectorRoot.appendChild(node) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (node.parentNode !== this.vectorRoot) { │ │ │ │ + this.vectorRoot.appendChild(node) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.postDraw(node); │ │ │ │ + return drawResult.complete │ │ │ │ + }, │ │ │ │ + redrawBackgroundNode: function(id, geometry, style, featureId) { │ │ │ │ + var backgroundStyle = OpenLayers.Util.extend({}, style); │ │ │ │ + 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; │ │ │ │ + backgroundStyle.backgroundGraphic = null; │ │ │ │ + backgroundStyle.backgroundXOffset = null; │ │ │ │ + backgroundStyle.backgroundYOffset = null; │ │ │ │ + backgroundStyle.backgroundGraphicZIndex = null; │ │ │ │ + return this.redrawNode(id + this.BACKGROUND_ID_SUFFIX, geometry, backgroundStyle, null) │ │ │ │ + }, │ │ │ │ + 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; │ │ │ │ + if (drawn != false) { │ │ │ │ + return { │ │ │ │ + node: this.setStyle(node, style, options, geometry), │ │ │ │ + complete: drawn │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + postDraw: function(node) {}, │ │ │ │ + drawPoint: function(node, geometry) {}, │ │ │ │ + drawLineString: function(node, geometry) {}, │ │ │ │ + drawLinearRing: function(node, geometry) {}, │ │ │ │ + drawPolygon: function(node, geometry) {}, │ │ │ │ + drawRectangle: function(node, geometry) {}, │ │ │ │ + drawCircle: function(node, geometry) {}, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getFeatureIdFromEvent: function(evt) { │ │ │ │ + var target = evt.target; │ │ │ │ + var useElement = target && target.correspondingUseElement; │ │ │ │ + var node = useElement ? useElement : target || evt.srcElement; │ │ │ │ + return node._featureId │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + bElem.parentNode.removeChild(bElem) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + nodeTypeCompare: function(node, type) {}, │ │ │ │ + createNode: function(type, id) {}, │ │ │ │ + moveRoot: function(renderer) { │ │ │ │ + var root = this.root; │ │ │ │ + if (renderer.root.parentNode == this.rendererRoot) { │ │ │ │ + root = renderer.root │ │ │ │ + } │ │ │ │ + root.parentNode.removeChild(root); │ │ │ │ + renderer.rendererRoot.appendChild(root) │ │ │ │ + }, │ │ │ │ + getRenderLayerId: function() { │ │ │ │ + return this.root.parentNode.parentNode.id │ │ │ │ + }, │ │ │ │ + isComplexSymbol: function(graphicName) { │ │ │ │ + return graphicName != "circle" && !!graphicName │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Renderer.Elements" │ │ │ │ +}); │ │ │ │ +OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ + xmlns: "http://www.w3.org/2000/svg", │ │ │ │ + xlinkns: "http://www.w3.org/1999/xlink", │ │ │ │ + MAX_PIXEL: 15e3, │ │ │ │ + translationParameters: null, │ │ │ │ + symbolMetrics: null, │ │ │ │ + initialize: function(containerID) { │ │ │ │ + if (!this.supported()) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + OpenLayers.Renderer.Elements.prototype.initialize.apply(this, arguments); │ │ │ │ + this.translationParameters = { │ │ │ │ + x: 0, │ │ │ │ + y: 0 │ │ │ │ + }; │ │ │ │ + this.symbolMetrics = {} │ │ │ │ + }, │ │ │ │ + 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")) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 (resolutionChanged) { │ │ │ │ + this.left = left; │ │ │ │ + this.top = top; │ │ │ │ + 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) { │ │ │ │ + this.setExtent(extent, true) │ │ │ │ + } │ │ │ │ + return coordSysUnchanged && inRange │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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); │ │ │ │ + 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 : -(.5 * width); │ │ │ │ + var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.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)) { │ │ │ │ + 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; │ │ │ │ + var parent = node.parentNode; │ │ │ │ + var nextSibling = node.nextSibling; │ │ │ │ + if (parent) { │ │ │ │ + parent.removeChild(node) │ │ │ │ + } │ │ │ │ + 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); │ │ │ │ + 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"); │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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, ",") │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + createNode: function(type, id) { │ │ │ │ + var node = document.createElementNS(this.xmlns, type); │ │ │ │ + if (id) { │ │ │ │ + node.setAttributeNS(null, "id", id) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + nodeTypeCompare: function(node, type) { │ │ │ │ + return type == node.nodeName │ │ │ │ + }, │ │ │ │ + createRenderRoot: function() { │ │ │ │ + var svg = this.nodeFactory(this.container.id + "_svgRoot", "svg"); │ │ │ │ + svg.style.display = "block"; │ │ │ │ + return svg │ │ │ │ + }, │ │ │ │ + createRoot: function(suffix) { │ │ │ │ + return this.nodeFactory(this.container.id + suffix, "g") │ │ │ │ + }, │ │ │ │ + createDefs: function() { │ │ │ │ + var defs = this.nodeFactory(this.container.id + "_defs", "defs"); │ │ │ │ + this.rendererRoot.appendChild(defs); │ │ │ │ + return defs │ │ │ │ + }, │ │ │ │ + drawPoint: function(node, geometry) { │ │ │ │ + return this.drawCircle(node, geometry, 1) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawText: function(featureId, style, location) { │ │ │ │ + var drawOutline = !!style.labelOutlineWidth; │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 { │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getPosition: function(node) { │ │ │ │ + return { │ │ │ │ + x: parseFloat(node.getAttributeNS(null, "cx")), │ │ │ │ + y: parseFloat(node.getAttributeNS(null, "cy")) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + importSymbol: function(graphicName) { │ │ │ │ + if (!this.defs) { │ │ │ │ + this.defs = this.createDefs() │ │ │ │ + } │ │ │ │ + var id = this.container.id + "-" + graphicName; │ │ │ │ + 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(); │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +OpenLayers.Renderer.SVG.LABEL_ALIGN = { │ │ │ │ + l: "start", │ │ │ │ + r: "end", │ │ │ │ + b: "bottom", │ │ │ │ + t: "hanging" │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.SVG.LABEL_VSHIFT = { │ │ │ │ + t: "-70%", │ │ │ │ + b: "0" │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.SVG.LABEL_VFACTOR = { │ │ │ │ + t: 0, │ │ │ │ + b: -1 │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.SVG.preventDefault = function(e) { │ │ │ │ + OpenLayers.Event.preventDefault(e) │ │ │ │ +}; │ │ │ │ +OpenLayers.Strategy = OpenLayers.Class({ │ │ │ │ + layer: null, │ │ │ │ + options: null, │ │ │ │ + active: null, │ │ │ │ + autoActivate: true, │ │ │ │ + autoDestroy: true, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + this.options = options; │ │ │ │ + this.active = false │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + this.layer = null; │ │ │ │ + this.options = null │ │ │ │ + }, │ │ │ │ + setLayer: function(layer) { │ │ │ │ + this.layer = layer │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (!this.active) { │ │ │ │ + this.active = true; │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (this.active) { │ │ │ │ + this.active = false; │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ +}); │ │ │ │ +OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + preload: false, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + 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.Handler = OpenLayers.Class({ │ │ │ │ + id: null, │ │ │ │ + control: null, │ │ │ │ + map: null, │ │ │ │ + keyMask: null, │ │ │ │ + active: false, │ │ │ │ + evt: null, │ │ │ │ + touch: false, │ │ │ │ + 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 + "_") │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + this.map = map │ │ │ │ + }, │ │ │ │ + checkModifiers: function(evt) { │ │ │ │ + if (this.keyMask == null) { │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + 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); │ │ │ │ + return keyModifiers == this.keyMask │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (this.active) { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (!this.active) { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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]]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + callback: function(name, args) { │ │ │ │ + if (name && this.callbacks[name]) { │ │ │ │ + this.callbacks[name].apply(this.control, args) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + register: function(name, method) { │ │ │ │ + this.map.events.registerPriority(name, this, method); │ │ │ │ + this.map.events.registerPriority(name, this, this.setEvent) │ │ │ │ + }, │ │ │ │ + unregister: function(name, method) { │ │ │ │ + this.map.events.unregister(name, this, method); │ │ │ │ + this.map.events.unregister(name, this, this.setEvent) │ │ │ │ + }, │ │ │ │ + setEvent: function(evt) { │ │ │ │ + this.evt = evt; │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + this.control = this.map = null │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.MOD_NONE = 0; │ │ │ │ +OpenLayers.Handler.MOD_SHIFT = 1; │ │ │ │ +OpenLayers.Handler.MOD_CTRL = 2; │ │ │ │ +OpenLayers.Handler.MOD_ALT = 4; │ │ │ │ +OpenLayers.Handler.MOD_META = 8; │ │ │ │ +OpenLayers.Geometry = OpenLayers.Class({ │ │ │ │ + id: null, │ │ │ │ + parent: null, │ │ │ │ + bounds: null, │ │ │ │ + initialize: function() { │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.id = null; │ │ │ │ + this.bounds = null │ │ │ │ + }, │ │ │ │ + clone: function() { │ │ │ │ + return new OpenLayers.Geometry │ │ │ │ + }, │ │ │ │ + setBounds: function(bounds) { │ │ │ │ + if (bounds) { │ │ │ │ + this.bounds = bounds.clone() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + clearBounds: function() { │ │ │ │ + this.bounds = null; │ │ │ │ + if (this.parent) { │ │ │ │ + this.parent.clearBounds() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + extendBounds: function(newBounds) { │ │ │ │ + var bounds = this.getBounds(); │ │ │ │ + if (!bounds) { │ │ │ │ + this.setBounds(newBounds) │ │ │ │ + } else { │ │ │ │ + this.bounds.extend(newBounds) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getBounds: function() { │ │ │ │ + if (this.bounds == null) { │ │ │ │ + this.calculateBounds() │ │ │ │ + } │ │ │ │ + return this.bounds │ │ │ │ + }, │ │ │ │ + calculateBounds: function() {}, │ │ │ │ + distanceTo: function(geometry, options) {}, │ │ │ │ + getVertices: function(nodes) {}, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + getLength: function() { │ │ │ │ + return 0 │ │ │ │ + }, │ │ │ │ + getArea: function() { │ │ │ │ + return 0 │ │ │ │ + }, │ │ │ │ + getCentroid: function() { │ │ │ │ + return null │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +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 │ │ │ │ +}; │ │ │ │ +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) { │ │ │ │ + if (n1 == 0 && n2 == 0) { │ │ │ │ + intersection = true │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + var along1 = n1 / d; │ │ │ │ + var along2 = n2 / d; │ │ │ │ + if (along1 >= 0 && along1 <= 1 && along2 >= 0 && along2 <= 1) { │ │ │ │ + if (!point) { │ │ │ │ + intersection = true │ │ │ │ + } else { │ │ │ │ + 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; │ │ │ │ + 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 { │ │ │ │ + var segs = [seg1, seg2]; │ │ │ │ + var source, target, x, y, p, result; │ │ │ │ + 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 │ │ │ │ +}; │ │ │ │ +OpenLayers.Geometry.distanceToSegment = function(point, segment) { │ │ │ │ + var result = OpenLayers.Geometry.distanceSquaredToSegment(point, segment); │ │ │ │ + result.distance = Math.sqrt(result.distance); │ │ │ │ + return result │ │ │ │ +}; │ │ │ │ +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) { │ │ │ │ + x = x1; │ │ │ │ + y = y1 │ │ │ │ + } else if (along >= 1) { │ │ │ │ + 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.Point = OpenLayers.Class(OpenLayers.Geometry, { │ │ │ │ + x: null, │ │ │ │ + y: null, │ │ │ │ + initialize: function(x, y) { │ │ │ │ + OpenLayers.Geometry.prototype.initialize.apply(this, arguments); │ │ │ │ + this.x = parseFloat(x); │ │ │ │ + this.y = parseFloat(y) │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Geometry.Point(this.x, this.y) │ │ │ │ + } │ │ │ │ + OpenLayers.Util.applyDefaults(obj, this); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + calculateBounds: function() { │ │ │ │ + this.bounds = new OpenLayers.Bounds(this.x, this.y, this.x, this.y) │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + result = { │ │ │ │ + x0: result.x1, │ │ │ │ + y0: result.y1, │ │ │ │ + x1: result.x0, │ │ │ │ + y1: result.y0, │ │ │ │ + distance: result.distance │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return result │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + toShortString: function() { │ │ │ │ + return this.x + ", " + this.y │ │ │ │ + }, │ │ │ │ + move: function(x, y) { │ │ │ │ + this.x = this.x + x; │ │ │ │ + this.y = this.y + y; │ │ │ │ + this.clearBounds() │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + }, │ │ │ │ + getCentroid: function() { │ │ │ │ + return new OpenLayers.Geometry.Point(this.x, this.y) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + intersects: function(geometry) { │ │ │ │ + var intersect = false; │ │ │ │ + if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { │ │ │ │ + intersect = this.equals(geometry) │ │ │ │ + } else { │ │ │ │ + intersect = geometry.intersects(this) │ │ │ │ + } │ │ │ │ + return intersect │ │ │ │ + }, │ │ │ │ + transform: function(source, dest) { │ │ │ │ + if (source && dest) { │ │ │ │ + OpenLayers.Projection.transform(this, source, dest); │ │ │ │ + this.bounds = null │ │ │ │ + } │ │ │ │ + return this │ │ │ │ + }, │ │ │ │ + getVertices: function(nodes) { │ │ │ │ + return [this] │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Geometry.Point" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + point: null, │ │ │ │ + layer: null, │ │ │ │ + multi: false, │ │ │ │ + citeCompliant: false, │ │ │ │ + mouseDown: false, │ │ │ │ + stoppedDown: null, │ │ │ │ + lastDown: null, │ │ │ │ + lastUp: null, │ │ │ │ + persist: false, │ │ │ │ + stopDown: false, │ │ │ │ + stopUp: false, │ │ │ │ + layerOptions: null, │ │ │ │ + pixelTolerance: 5, │ │ │ │ + lastTouchPx: null, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (!OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + var options = OpenLayers.Util.extend({ │ │ │ │ + displayInLayerSwitcher: false, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (!OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + this.cancel(); │ │ │ │ + if (this.layer.map != null) { │ │ │ │ + this.destroyFeature(true); │ │ │ │ + this.layer.destroy(false) │ │ │ │ + } │ │ │ │ + this.layer = null; │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + destroyFeature: function(force) { │ │ │ │ + if (this.layer && (force || !this.persist)) { │ │ │ │ + this.layer.destroyFeatures() │ │ │ │ + } │ │ │ │ + this.point = null │ │ │ │ + }, │ │ │ │ + destroyPersistedFeature: function() { │ │ │ │ + var layer = this.layer; │ │ │ │ + if (layer && layer.features.length > 1) { │ │ │ │ + this.layer.features[0].destroy() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + cancel: function() { │ │ │ │ + this.finalize(true) │ │ │ │ + }, │ │ │ │ + click: function(evt) { │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + dblclick: function(evt) { │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + }, │ │ │ │ + drawFeature: function() { │ │ │ │ + this.layer.drawFeature(this.point, this.style) │ │ │ │ + }, │ │ │ │ + getGeometry: function() { │ │ │ │ + var geometry = this.point && this.point.geometry; │ │ │ │ + if (geometry && this.multi) { │ │ │ │ + geometry = new OpenLayers.Geometry.MultiPoint([geometry]) │ │ │ │ + } │ │ │ │ + return geometry │ │ │ │ + }, │ │ │ │ + geometryClone: function() { │ │ │ │ + var geom = this.getGeometry(); │ │ │ │ + return geom && geom.clone() │ │ │ │ + }, │ │ │ │ + mousedown: function(evt) { │ │ │ │ + return this.down(evt) │ │ │ │ + }, │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + this.lastTouchPx = evt.xy; │ │ │ │ + return this.down(evt) │ │ │ │ + }, │ │ │ │ + mousemove: function(evt) { │ │ │ │ + return this.move(evt) │ │ │ │ + }, │ │ │ │ + touchmove: function(evt) { │ │ │ │ + this.lastTouchPx = evt.xy; │ │ │ │ + return this.move(evt) │ │ │ │ + }, │ │ │ │ + mouseup: function(evt) { │ │ │ │ + return this.up(evt) │ │ │ │ + }, │ │ │ │ + touchend: function(evt) { │ │ │ │ + evt.xy = this.lastTouchPx; │ │ │ │ + return this.up(evt) │ │ │ │ + }, │ │ │ │ + down: function(evt) { │ │ │ │ + this.mouseDown = true; │ │ │ │ + this.lastDown = evt.xy; │ │ │ │ + if (!this.touch) { │ │ │ │ + this.modifyFeature(evt.xy) │ │ │ │ + } │ │ │ │ + this.stoppedDown = this.stopDown; │ │ │ │ + return !this.stopDown │ │ │ │ + }, │ │ │ │ + move: function(evt) { │ │ │ │ + if (!this.touch && (!this.mouseDown || this.stoppedDown)) { │ │ │ │ + this.modifyFeature(evt.xy) │ │ │ │ + } │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + up: function(evt) { │ │ │ │ + this.mouseDown = false; │ │ │ │ + this.stoppedDown = this.stopDown; │ │ │ │ + if (!this.checkModifiers(evt)) { │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + mouseout: function(evt) { │ │ │ │ + if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ + this.stoppedDown = this.stopDown; │ │ │ │ + this.mouseDown = false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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.Geometry.Collection = OpenLayers.Class(OpenLayers.Geometry, { │ │ │ │ + components: null, │ │ │ │ + componentTypes: null, │ │ │ │ + initialize: function(components) { │ │ │ │ + OpenLayers.Geometry.prototype.initialize.apply(this, arguments); │ │ │ │ + this.components = []; │ │ │ │ + if (components != null) { │ │ │ │ + this.addComponents(components) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.components.length = 0; │ │ │ │ + this.components = null; │ │ │ │ + OpenLayers.Geometry.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + 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()) │ │ │ │ + } │ │ │ │ + OpenLayers.Util.applyDefaults(geometry, this); │ │ │ │ + return 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(",") │ │ │ │ + }, │ │ │ │ + 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()) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (bounds.left != null && bounds.bottom != null && bounds.right != null && bounds.top != null) { │ │ │ │ + this.setBounds(bounds) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + addComponents: function(components) { │ │ │ │ + if (!OpenLayers.Util.isArray(components)) { │ │ │ │ + components = [components] │ │ │ │ + } │ │ │ │ + for (var i = 0, len = components.length; i < len; i++) { │ │ │ │ + this.addComponent(components[i]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + removeComponent: function(component) { │ │ │ │ + OpenLayers.Util.removeItem(this.components, component); │ │ │ │ + this.clearBounds(); │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + getLength: function() { │ │ │ │ + var length = 0; │ │ │ │ + for (var i = 0, len = this.components.length; i < len; i++) { │ │ │ │ + length += this.components[i].getLength() │ │ │ │ + } │ │ │ │ + return length │ │ │ │ + }, │ │ │ │ + getArea: function() { │ │ │ │ + var area = 0; │ │ │ │ + for (var i = 0, len = this.components.length; i < len; i++) { │ │ │ │ + area += this.components[i].getArea() │ │ │ │ + } │ │ │ │ + return area │ │ │ │ + }, │ │ │ │ + getGeodesicArea: function(projection) { │ │ │ │ + var area = 0; │ │ │ │ + for (var i = 0, len = this.components.length; i < len; i++) { │ │ │ │ + area += this.components[i].getGeodesicArea(projection) │ │ │ │ + } │ │ │ │ + return area │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ + areas[i] = 1 │ │ │ │ + } │ │ │ │ + areaSum = areas.length │ │ │ │ + } else { │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + getGeodesicLength: function(projection) { │ │ │ │ + var length = 0; │ │ │ │ + for (var i = 0, len = this.components.length; i < len; i++) { │ │ │ │ + length += this.components[i].getGeodesicLength(projection) │ │ │ │ + } │ │ │ │ + return length │ │ │ │ + }, │ │ │ │ + move: function(x, y) { │ │ │ │ + for (var i = 0, len = this.components.length; i < len; i++) { │ │ │ │ + this.components[i].move(x, y) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + rotate: function(angle, origin) { │ │ │ │ + for (var i = 0, len = this.components.length; i < len; ++i) { │ │ │ │ + this.components[i].rotate(angle, origin) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + resize: function(scale, origin, ratio) { │ │ │ │ + for (var i = 0; i < this.components.length; ++i) { │ │ │ │ + this.components[i].resize(scale, origin, ratio) │ │ │ │ + } │ │ │ │ + return this │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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.MultiPoint = OpenLayers.Class(OpenLayers.Geometry.Collection, { │ │ │ │ + componentTypes: ["OpenLayers.Geometry.Point"], │ │ │ │ + addPoint: function(point, index) { │ │ │ │ + this.addComponent(point, index) │ │ │ │ + }, │ │ │ │ + removePoint: function(point) { │ │ │ │ + this.removeComponent(point) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Geometry.MultiPoint" │ │ │ │ +}); │ │ │ │ +OpenLayers.Geometry.Curve = OpenLayers.Class(OpenLayers.Geometry.MultiPoint, { │ │ │ │ + componentTypes: ["OpenLayers.Geometry.Point"], │ │ │ │ + getLength: function() { │ │ │ │ + var length = 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 │ │ │ │ + }, │ │ │ │ + getGeodesicLength: function(projection) { │ │ │ │ + var geom = this; │ │ │ │ + if (projection) { │ │ │ │ + var gg = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ + if (!gg.equals(projection)) { │ │ │ │ + geom = this.clone().transform(projection, gg) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var length = 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]; │ │ │ │ + length += OpenLayers.Util.distVincenty({ │ │ │ │ + lon: p1.x, │ │ │ │ + lat: p1.y │ │ │ │ + }, { │ │ │ │ + lon: p2.x, │ │ │ │ + lat: p2.y │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return length * 1e3 │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Geometry.Curve" │ │ │ │ +}); │ │ │ │ +OpenLayers.Geometry.LineString = OpenLayers.Class(OpenLayers.Geometry.Curve, { │ │ │ │ + removeComponent: function(point) { │ │ │ │ + var removed = this.components && this.components.length > 2; │ │ │ │ + if (removed) { │ │ │ │ + OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, arguments) │ │ │ │ + } │ │ │ │ + return removed │ │ │ │ + }, │ │ │ │ + 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; │ │ │ │ + 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) { │ │ │ │ + break │ │ │ │ + } │ │ │ │ + if (seg2.x2 < seg1x1) { │ │ │ │ + continue │ │ │ │ + } │ │ │ │ + seg2y1 = seg2.y1; │ │ │ │ + seg2y2 = seg2.y2; │ │ │ │ + if (Math.min(seg2y1, seg2y2) > Math.max(seg1y1, seg1y2)) { │ │ │ │ + continue │ │ │ │ + } │ │ │ │ + if (Math.max(seg2y1, seg2y2) < Math.min(seg1y1, seg1y2)) { │ │ │ │ + continue │ │ │ │ + } │ │ │ │ + if (OpenLayers.Geometry.segmentsIntersect(seg1, seg2)) { │ │ │ │ + intersect = true; │ │ │ │ + break outer │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + intersect = geometry.intersects(this) │ │ │ │ + } │ │ │ │ + return intersect │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + function byX1(seg1, seg2) { │ │ │ │ + return seg1.x1 - seg2.x1 │ │ │ │ + } │ │ │ │ + return segments.sort(byX1) │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + 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) { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + splitWith: function(geometry, options) { │ │ │ │ + return geometry.split(this, options) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 (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) { │ │ │ │ + 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); │ │ │ │ + if (details) { │ │ │ │ + best = { │ │ │ │ + distance: best.distance, │ │ │ │ + x0: best.x1, │ │ │ │ + y0: best.y1, │ │ │ │ + x1: best.x0, │ │ │ │ + y1: best.y0 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return best │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }; │ │ │ │ + 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) { │ │ │ │ + pointIndexsToKeep.push(indexFarthest); │ │ │ │ + douglasPeuckerReduction(points, firstPoint, indexFarthest, tolerance); │ │ │ │ + douglasPeuckerReduction(points, indexFarthest, lastPoint, tolerance) │ │ │ │ + } │ │ │ │ + }; │ │ │ │ + var perpendicularDistance = function(point1, point2, point) { │ │ │ │ + var area = Math.abs(.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 = []; │ │ │ │ + pointIndexsToKeep.push(firstPoint); │ │ │ │ + pointIndexsToKeep.push(lastPoint); │ │ │ │ + while (points[firstPoint].equals(points[lastPoint])) { │ │ │ │ + lastPoint--; │ │ │ │ + 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.Handler.Path = OpenLayers.Class(OpenLayers.Handler.Point, { │ │ │ │ + line: null, │ │ │ │ + maxVertices: null, │ │ │ │ + doubleTouchTolerance: 20, │ │ │ │ + freehand: false, │ │ │ │ + freehandToggle: "shiftKey", │ │ │ │ + timerId: null, │ │ │ │ + redoStack: null, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + destroyFeature: function(force) { │ │ │ │ + OpenLayers.Handler.Point.prototype.destroyFeature.call(this, force); │ │ │ │ + this.line = null │ │ │ │ + }, │ │ │ │ + destroyPersistedFeature: function() { │ │ │ │ + var layer = this.layer; │ │ │ │ + if (layer && layer.features.length > 2) { │ │ │ │ + this.layer.features[0].destroy() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + removePoint: function() { │ │ │ │ + if (this.point) { │ │ │ │ + this.layer.removeFeatures([this.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 │ │ │ │ + }, │ │ │ │ + insertXY: function(x, y) { │ │ │ │ + this.line.geometry.addComponent(new OpenLayers.Geometry.Point(x, y), this.getCurrentPointIndex()); │ │ │ │ + this.drawFeature(); │ │ │ │ + delete this.redoStack │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + insertDirectionLength: function(direction, length) { │ │ │ │ + direction *= Math.PI / 180; │ │ │ │ + var dx = length * Math.cos(direction); │ │ │ │ + var dy = length * Math.sin(direction); │ │ │ │ + this.insertDeltaXY(dx, dy) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getCurrentPointIndex: function() { │ │ │ │ + return this.line.geometry.components.length - 1 │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + if (this.touch && index > 0) { │ │ │ │ + components = geometry.components; │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + redo: function() { │ │ │ │ + var target = this.redoStack && this.redoStack.pop(); │ │ │ │ + if (target) { │ │ │ │ + this.line.geometry.addComponent(target, this.getCurrentPointIndex()); │ │ │ │ + this.drawFeature() │ │ │ │ + } │ │ │ │ + return !!target │ │ │ │ + }, │ │ │ │ + freehandMode: function(evt) { │ │ │ │ + return this.freehandToggle && evt[this.freehandToggle] ? !this.freehand : this.freehand │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + }, │ │ │ │ + drawFeature: function() { │ │ │ │ + this.layer.drawFeature(this.line, this.style); │ │ │ │ + this.layer.drawFeature(this.point, this.style) │ │ │ │ + }, │ │ │ │ + getSketch: function() { │ │ │ │ + return this.line │ │ │ │ + }, │ │ │ │ + getGeometry: function() { │ │ │ │ + var geometry = this.line && this.line.geometry; │ │ │ │ + if (geometry && this.multi) { │ │ │ │ + geometry = new OpenLayers.Geometry.MultiLineString([geometry]) │ │ │ │ + } │ │ │ │ + return geometry │ │ │ │ + }, │ │ │ │ + touchstart: function(evt) { │ │ │ │ + if (this.timerId && this.passesTolerance(this.lastTouchPx, evt.xy, this.doubleTouchTolerance)) { │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + finishGeometry: function() { │ │ │ │ + var index = this.line.geometry.components.length - 1; │ │ │ │ + this.line.geometry.removeComponent(this.line.geometry.components[index]); │ │ │ │ + this.removePoint(); │ │ │ │ + this.finalize() │ │ │ │ + }, │ │ │ │ + dblclick: function(evt) { │ │ │ │ + if (!this.freehandMode(evt)) { │ │ │ │ + this.finishGeometry() │ │ │ │ + } │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Path" │ │ │ │ +}); │ │ │ │ +OpenLayers.Geometry.LinearRing = OpenLayers.Class(OpenLayers.Geometry.LineString, { │ │ │ │ + componentTypes: ["OpenLayers.Geometry.Point"], │ │ │ │ + addComponent: function(point, index) { │ │ │ │ + var added = false; │ │ │ │ + var lastPoint = this.components.pop(); │ │ │ │ + if (index != null || !point.equals(lastPoint)) { │ │ │ │ + added = OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, arguments) │ │ │ │ + } │ │ │ │ + var firstPoint = this.components[0]; │ │ │ │ + OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, [firstPoint]); │ │ │ │ + return added │ │ │ │ + }, │ │ │ │ + removeComponent: function(point) { │ │ │ │ + var removed = this.components && this.components.length > 3; │ │ │ │ + if (removed) { │ │ │ │ + this.components.pop(); │ │ │ │ + OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, arguments); │ │ │ │ + var firstPoint = this.components[0]; │ │ │ │ + OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, [firstPoint]) │ │ │ │ + } │ │ │ │ + return removed │ │ │ │ + }, │ │ │ │ + move: function(x, y) { │ │ │ │ + for (var i = 0, len = this.components.length; i < len - 1; i++) { │ │ │ │ + this.components[i].move(x, y) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + rotate: function(angle, origin) { │ │ │ │ + for (var i = 0, len = this.components.length; i < len - 1; ++i) { │ │ │ │ + this.components[i].rotate(angle, origin) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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; │ │ │ │ + var sumY = 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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getArea: function() { │ │ │ │ + var area = 0; │ │ │ │ + if (this.components && this.components.length > 2) { │ │ │ │ + var sum = 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 │ │ │ │ + } │ │ │ │ + return area │ │ │ │ + }, │ │ │ │ + getGeodesicArea: function(projection) { │ │ │ │ + var ring = this; │ │ │ │ + if (projection) { │ │ │ │ + var gg = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ + if (!gg.equals(projection)) { │ │ │ │ + ring = this.clone().transform(projection, gg) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var area = 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 * 6378137 / 2 │ │ │ │ + } │ │ │ │ + return area │ │ │ │ + }, │ │ │ │ + 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); │ │ │ │ + if (y1 == y2) { │ │ │ │ + if (py == y1) { │ │ │ │ + if (x1 <= x2 && (px >= x1 && px <= x2) || x1 >= x2 && (px <= x1 && px >= x2)) { │ │ │ │ + crosses = -1; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + continue │ │ │ │ + } │ │ │ │ + cx = approx(getX(py, x1, y1, x2, y2), digs); │ │ │ │ + if (cx == px) { │ │ │ │ + if (y1 < y2 && (py >= y1 && py <= y2) || y1 > y2 && (py <= y1 && py >= y2)) { │ │ │ │ + crosses = -1; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (cx <= px) { │ │ │ │ + continue │ │ │ │ + } │ │ │ │ + if (x1 != x2 && (cx < Math.min(x1, x2) || cx > Math.max(x1, x2))) { │ │ │ │ + continue │ │ │ │ + } │ │ │ │ + if (y1 < y2 && (py >= y1 && py < y2) || y1 > y2 && (py < y1 && py >= y2)) { │ │ │ │ + ++crosses │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var contained = crosses == -1 ? 1 : !!(crosses & 1); │ │ │ │ + return contained │ │ │ │ + }, │ │ │ │ + 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 { │ │ │ │ + for (var i = 0, len = geometry.components.length; i < len; ++i) { │ │ │ │ + intersect = geometry.components[i].intersects(this); │ │ │ │ + if (intersect) { │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return intersect │ │ │ │ + }, │ │ │ │ + getVertices: function(nodes) { │ │ │ │ + return nodes === true ? [] : this.components.slice(0, this.components.length - 1) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Geometry.LinearRing" │ │ │ │ +}); │ │ │ │ +OpenLayers.Geometry.Polygon = OpenLayers.Class(OpenLayers.Geometry.Collection, { │ │ │ │ + componentTypes: ["OpenLayers.Geometry.LinearRing"], │ │ │ │ + getArea: function() { │ │ │ │ + var area = 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 │ │ │ │ + }, │ │ │ │ + getGeodesicArea: function(projection) { │ │ │ │ + var area = 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 │ │ │ │ + }, │ │ │ │ + containsPoint: function(point) { │ │ │ │ + var numRings = this.components.length; │ │ │ │ + var contained = false; │ │ │ │ + if (numRings > 0) { │ │ │ │ + contained = this.components[0].containsPoint(point); │ │ │ │ + if (contained !== 1) { │ │ │ │ + if (contained && numRings > 1) { │ │ │ │ + var hole; │ │ │ │ + for (var i = 1; i < numRings; ++i) { │ │ │ │ + hole = this.components[i].containsPoint(point); │ │ │ │ + if (hole) { │ │ │ │ + if (hole === 1) { │ │ │ │ + contained = 1 │ │ │ │ + } else { │ │ │ │ + contained = false │ │ │ │ + } │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return contained │ │ │ │ + }, │ │ │ │ + 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") { │ │ │ │ + for (i = 0, len = this.components.length; i < len; ++i) { │ │ │ │ + intersect = geometry.intersects(this.components[i]); │ │ │ │ + if (intersect) { │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (!intersect) { │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (!intersect && geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + distanceTo: function(geometry, options) { │ │ │ │ + var edge = !(options && options.edge === false); │ │ │ │ + var result; │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +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.Handler.Polygon = OpenLayers.Class(OpenLayers.Handler.Path, { │ │ │ │ + holeModifier: null, │ │ │ │ + drawingHole: false, │ │ │ │ + polygon: null, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + 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; │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + getCurrentPointIndex: function() { │ │ │ │ + return this.line.geometry.components.length - 2 │ │ │ │ + }, │ │ │ │ + enforceTopology: function(event) { │ │ │ │ + var point = event.vertex; │ │ │ │ + var components = this.line.geometry.components; │ │ │ │ + if (!this.polygon.geometry.intersects(point)) { │ │ │ │ + var last = components[components.length - 3]; │ │ │ │ + point.x = last.x; │ │ │ │ + point.y = last.y │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + finishGeometry: function() { │ │ │ │ + var index = this.line.geometry.components.length - 2; │ │ │ │ + this.line.geometry.removeComponent(this.line.geometry.components[index]); │ │ │ │ + this.removePoint(); │ │ │ │ + this.finalize() │ │ │ │ + }, │ │ │ │ + finalizeInteriorRing: function() { │ │ │ │ + var ring = this.line.geometry; │ │ │ │ + var modified = ring.getArea() !== 0; │ │ │ │ + if (modified) { │ │ │ │ + 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) { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + cancel: function() { │ │ │ │ + if (this.drawingHole) { │ │ │ │ + this.polygon.geometry.removeComponent(this.line.geometry); │ │ │ │ + this.restoreFeature(true) │ │ │ │ + } │ │ │ │ + return OpenLayers.Handler.Path.prototype.cancel.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + this.control.layer.events.triggerEvent("sketchcomplete", { │ │ │ │ + feature: this.polygon │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroyFeature: function(force) { │ │ │ │ + OpenLayers.Handler.Path.prototype.destroyFeature.call(this, force); │ │ │ │ + this.polygon = null │ │ │ │ + }, │ │ │ │ + drawFeature: function() { │ │ │ │ + this.layer.drawFeature(this.polygon, this.style); │ │ │ │ + this.layer.drawFeature(this.point, this.style) │ │ │ │ + }, │ │ │ │ + getSketch: function() { │ │ │ │ + return this.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.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ isBaseLayer: true, │ │ │ │ sphericalMercator: false, │ │ │ │ zoomOffset: 0, │ │ │ │ serverResolutions: null, │ │ │ │ initialize: function(name, url, options) { │ │ │ │ if (options && options.sphericalMercator || this.sphericalMercator) { │ │ │ │ @@ -5645,154 +9295,36 @@ │ │ │ │ this.metadata = metadata; │ │ │ │ this.initLayer(); │ │ │ │ var script = document.getElementById(this._callbackId); │ │ │ │ script.parentNode.removeChild(script); │ │ │ │ window[this._callbackId] = undefined; │ │ │ │ delete this._callbackId │ │ │ │ }; │ │ │ │ -OpenLayers.Renderer = OpenLayers.Class({ │ │ │ │ - container: null, │ │ │ │ - root: null, │ │ │ │ - extent: null, │ │ │ │ - locked: false, │ │ │ │ - size: null, │ │ │ │ - resolution: null, │ │ │ │ - map: null, │ │ │ │ - featureDx: 0, │ │ │ │ - initialize: function(containerID, options) { │ │ │ │ - this.container = OpenLayers.Util.getElement(containerID); │ │ │ │ - OpenLayers.Util.extend(this, options) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.container = null; │ │ │ │ - this.extent = null; │ │ │ │ - this.size = null; │ │ │ │ - this.resolution = null; │ │ │ │ - this.map = null │ │ │ │ - }, │ │ │ │ - supported: function() { │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - setSize: function(size) { │ │ │ │ - this.size = size.clone(); │ │ │ │ - this.resolution = null │ │ │ │ - }, │ │ │ │ - getResolution: function() { │ │ │ │ - this.resolution = this.resolution || this.map.getResolution(); │ │ │ │ - return this.resolution │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawGeometry: function(geometry, style, featureId) {}, │ │ │ │ - drawText: function(featureId, style, location) {}, │ │ │ │ - removeText: function(featureId) {}, │ │ │ │ - clear: function() {}, │ │ │ │ - getFeatureIdFromEvent: function(evt) {}, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - eraseGeometry: function(geometry, featureId) {}, │ │ │ │ - moveRoot: function(renderer) {}, │ │ │ │ - getRenderLayerId: function() { │ │ │ │ - return this.container.id │ │ │ │ +OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ + name: "OpenStreetMap", │ │ │ │ + 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"], │ │ │ │ + attribution: "© <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors", │ │ │ │ + sphericalMercator: true, │ │ │ │ + wrapDateLine: true, │ │ │ │ + tileOptions: null, │ │ │ │ + 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) │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.OSM(this.name, this.url, this.getOptions()) │ │ │ │ } │ │ │ │ - OpenLayers.Util.extend(result, symbolizer); │ │ │ │ - return result │ │ │ │ + obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer" │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.OSM" │ │ │ │ }); │ │ │ │ -OpenLayers.Renderer.defaultSymbolizer = { │ │ │ │ - fillColor: "#000000", │ │ │ │ - strokeColor: "#000000", │ │ │ │ - strokeWidth: 2, │ │ │ │ - fillOpacity: 1, │ │ │ │ - strokeOpacity: 1, │ │ │ │ - pointRadius: 0, │ │ │ │ - labelAlign: "cm" │ │ │ │ -}; │ │ │ │ -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.Feature = OpenLayers.Class({ │ │ │ │ layer: null, │ │ │ │ id: null, │ │ │ │ lonlat: null, │ │ │ │ data: null, │ │ │ │ marker: null, │ │ │ │ popupClass: null, │ │ │ │ @@ -6807,6488 +10339,139 @@ │ │ │ │ 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.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ - name: "OpenStreetMap", │ │ │ │ - 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"], │ │ │ │ - attribution: "© <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors", │ │ │ │ - sphericalMercator: true, │ │ │ │ - wrapDateLine: true, │ │ │ │ - tileOptions: null, │ │ │ │ - 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) │ │ │ │ +OpenLayers.Protocol = OpenLayers.Class({ │ │ │ │ + format: null, │ │ │ │ + options: null, │ │ │ │ + autoDestroy: true, │ │ │ │ + defaultFilter: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + this.options = options │ │ │ │ }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.OSM(this.name, this.url, this.getOptions()) │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ + return merged │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.OSM" │ │ │ │ + destroy: function() { │ │ │ │ + this.options = null; │ │ │ │ + this.format = null │ │ │ │ + }, │ │ │ │ + read: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + options.filter = this.mergeWithDefaultFilter(options.filter) │ │ │ │ + }, │ │ │ │ + create: function() {}, │ │ │ │ + update: function() {}, │ │ │ │ + delete: function() {}, │ │ │ │ + commit: function() {}, │ │ │ │ + abort: function(response) {}, │ │ │ │ + createCallback: function(method, response, options) { │ │ │ │ + return OpenLayers.Function.bind(function() { │ │ │ │ + method.apply(this, [response, options]) │ │ │ │ + }, this) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol" │ │ │ │ }); │ │ │ │ -OpenLayers.Control = OpenLayers.Class({ │ │ │ │ - id: null, │ │ │ │ - map: null, │ │ │ │ - div: null, │ │ │ │ - type: null, │ │ │ │ - allowSelection: false, │ │ │ │ - displayClass: "", │ │ │ │ - title: "", │ │ │ │ - autoActivate: false, │ │ │ │ - active: null, │ │ │ │ - handlerOptions: null, │ │ │ │ - handler: null, │ │ │ │ - eventListeners: null, │ │ │ │ - events: null, │ │ │ │ +OpenLayers.Protocol.Response = OpenLayers.Class({ │ │ │ │ + code: null, │ │ │ │ + requestType: null, │ │ │ │ + last: true, │ │ │ │ + features: null, │ │ │ │ + data: null, │ │ │ │ + reqFeatures: null, │ │ │ │ + priv: null, │ │ │ │ + error: null, │ │ │ │ initialize: function(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 + "_") │ │ │ │ - } │ │ │ │ + OpenLayers.Util.extend(this, options) │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.events) { │ │ │ │ - if (this.eventListeners) { │ │ │ │ - this.events.un(this.eventListeners) │ │ │ │ + success: function() { │ │ │ │ + return this.code > 0 │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.Response" │ │ │ │ +}); │ │ │ │ +OpenLayers.Protocol.Response.SUCCESS = 1; │ │ │ │ +OpenLayers.Protocol.Response.FAILURE = 0; │ │ │ │ +OpenLayers.ProxyHost = ""; │ │ │ │ +if (!OpenLayers.Request) { │ │ │ │ + OpenLayers.Request = {} │ │ │ │ +} │ │ │ │ +OpenLayers.Util.extend(OpenLayers.Request, { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + URL_SPLIT_REGEX: /([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/, │ │ │ │ + events: new OpenLayers.Events(this), │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - this.events.destroy(); │ │ │ │ - this.events = null │ │ │ │ - } │ │ │ │ - this.eventListeners = null; │ │ │ │ - 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() │ │ │ │ + if (!sameOrigin) { │ │ │ │ + if (proxy) { │ │ │ │ + if (typeof proxy == "function") { │ │ │ │ + url = proxy(url) │ │ │ │ + } else { │ │ │ │ + url = proxy + encodeURIComponent(url) │ │ │ │ } │ │ │ │ } │ │ │ │ - this.handlers = null │ │ │ │ - } │ │ │ │ - if (this.map) { │ │ │ │ - this.map.removeControl(this); │ │ │ │ - this.map = null │ │ │ │ - } │ │ │ │ - this.div = null │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - this.map = map; │ │ │ │ - if (this.handler) { │ │ │ │ - this.handler.setMap(map) │ │ │ │ } │ │ │ │ + return url │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + issue: function(config) { │ │ │ │ + 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); │ │ │ │ + var customRequestedWithHeader = false, │ │ │ │ + headerKey; │ │ │ │ + for (headerKey in config.headers) { │ │ │ │ + if (config.headers.hasOwnProperty(headerKey)) { │ │ │ │ + if (headerKey.toLowerCase() === "x-requested-with") { │ │ │ │ + customRequestedWithHeader = true │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ - if (px != null) { │ │ │ │ - this.position = px.clone() │ │ │ │ - } │ │ │ │ - this.moveTo(this.position); │ │ │ │ - return this.div │ │ │ │ - }, │ │ │ │ - moveTo: function(px) { │ │ │ │ - if (px != null && this.div != null) { │ │ │ │ - this.div.style.left = px.x + "px"; │ │ │ │ - this.div.style.top = px.y + "px" │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.TYPE_BUTTON = 1; │ │ │ │ -OpenLayers.Control.TYPE_TOGGLE = 2; │ │ │ │ -OpenLayers.Control.TYPE_TOOL = 3; │ │ │ │ -OpenLayers.Events.buttonclick = OpenLayers.Class({ │ │ │ │ - target: null, │ │ │ │ - events: ["mousedown", "mouseup", "click", "dblclick", "touchstart", "touchmove", "touchend", "keydown"], │ │ │ │ - startRegEx: /^mousedown|touchstart$/, │ │ │ │ - cancelRegEx: /^touchmove$/, │ │ │ │ - completeRegEx: /^mouseup|touchend$/, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - for (var i = this.events.length - 1; i >= 0; --i) { │ │ │ │ - this.target.unregister(this.events[i], this, this.buttonClick) │ │ │ │ - } │ │ │ │ - delete this.target │ │ │ │ - }, │ │ │ │ - getPressedButton: function(element) { │ │ │ │ - var depth = 3, │ │ │ │ - button; │ │ │ │ - do { │ │ │ │ - if (OpenLayers.Element.hasClass(element, "olButton")) { │ │ │ │ - button = element; │ │ │ │ - break │ │ │ │ - } │ │ │ │ - element = element.parentNode │ │ │ │ - } while (--depth > 0 && element); │ │ │ │ - return button │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - buttonClick: function(evt) { │ │ │ │ - var propagate = true, │ │ │ │ - element = OpenLayers.Event.element(evt); │ │ │ │ - if (element && (OpenLayers.Event.isLeftClick(evt) || !~evt.type.indexOf("mouse"))) { │ │ │ │ - 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.Panel = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - controls: null, │ │ │ │ - autoActivate: true, │ │ │ │ - defaultControl: null, │ │ │ │ - saveState: false, │ │ │ │ - allowDepress: false, │ │ │ │ - activeState: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.controls = []; │ │ │ │ - this.activeState = {} │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - this.addControlsToMap(controls); │ │ │ │ - this.redraw() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - createControlMarkup: function(control) { │ │ │ │ - return document.createElement("div") │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - iconOn: function() { │ │ │ │ - var d = this.panel_div; │ │ │ │ - var re = new RegExp("\\b(" + this.displayClass + "Item)Inactive\\b"); │ │ │ │ - d.className = d.className.replace(re, "$1Active") │ │ │ │ - }, │ │ │ │ - iconOff: function() { │ │ │ │ - var d = this.panel_div; │ │ │ │ - var re = new RegExp("\\b(" + this.displayClass + "Item)Active\\b"); │ │ │ │ - d.className = d.className.replace(re, "$1Inactive") │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - getControlsByName: function(match) { │ │ │ │ - return this.getControlsBy("name", match) │ │ │ │ - }, │ │ │ │ - getControlsByClass: function(match) { │ │ │ │ - return this.getControlsBy("CLASS_NAME", match) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Panel" │ │ │ │ -}); │ │ │ │ -OpenLayers.Geometry = OpenLayers.Class({ │ │ │ │ - id: null, │ │ │ │ - parent: null, │ │ │ │ - bounds: null, │ │ │ │ - initialize: function() { │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.id = null; │ │ │ │ - this.bounds = null │ │ │ │ - }, │ │ │ │ - clone: function() { │ │ │ │ - return new OpenLayers.Geometry │ │ │ │ - }, │ │ │ │ - setBounds: function(bounds) { │ │ │ │ - if (bounds) { │ │ │ │ - this.bounds = bounds.clone() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clearBounds: function() { │ │ │ │ - this.bounds = null; │ │ │ │ - if (this.parent) { │ │ │ │ - this.parent.clearBounds() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - extendBounds: function(newBounds) { │ │ │ │ - var bounds = this.getBounds(); │ │ │ │ - if (!bounds) { │ │ │ │ - this.setBounds(newBounds) │ │ │ │ - } else { │ │ │ │ - this.bounds.extend(newBounds) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getBounds: function() { │ │ │ │ - if (this.bounds == null) { │ │ │ │ - this.calculateBounds() │ │ │ │ - } │ │ │ │ - return this.bounds │ │ │ │ - }, │ │ │ │ - calculateBounds: function() {}, │ │ │ │ - distanceTo: function(geometry, options) {}, │ │ │ │ - getVertices: function(nodes) {}, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - getLength: function() { │ │ │ │ - return 0 │ │ │ │ - }, │ │ │ │ - getArea: function() { │ │ │ │ - return 0 │ │ │ │ - }, │ │ │ │ - getCentroid: function() { │ │ │ │ - return null │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -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 │ │ │ │ -}; │ │ │ │ -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) { │ │ │ │ - if (n1 == 0 && n2 == 0) { │ │ │ │ - intersection = true │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - var along1 = n1 / d; │ │ │ │ - var along2 = n2 / d; │ │ │ │ - if (along1 >= 0 && along1 <= 1 && along2 >= 0 && along2 <= 1) { │ │ │ │ - if (!point) { │ │ │ │ - intersection = true │ │ │ │ - } else { │ │ │ │ - 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; │ │ │ │ - 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 { │ │ │ │ - var segs = [seg1, seg2]; │ │ │ │ - var source, target, x, y, p, result; │ │ │ │ - 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 │ │ │ │ -}; │ │ │ │ -OpenLayers.Geometry.distanceToSegment = function(point, segment) { │ │ │ │ - var result = OpenLayers.Geometry.distanceSquaredToSegment(point, segment); │ │ │ │ - result.distance = Math.sqrt(result.distance); │ │ │ │ - return result │ │ │ │ -}; │ │ │ │ -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) { │ │ │ │ - x = x1; │ │ │ │ - y = y1 │ │ │ │ - } else if (along >= 1) { │ │ │ │ - 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.Point = OpenLayers.Class(OpenLayers.Geometry, { │ │ │ │ - x: null, │ │ │ │ - y: null, │ │ │ │ - initialize: function(x, y) { │ │ │ │ - OpenLayers.Geometry.prototype.initialize.apply(this, arguments); │ │ │ │ - this.x = parseFloat(x); │ │ │ │ - this.y = parseFloat(y) │ │ │ │ - }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Geometry.Point(this.x, this.y) │ │ │ │ - } │ │ │ │ - OpenLayers.Util.applyDefaults(obj, this); │ │ │ │ - return obj │ │ │ │ - }, │ │ │ │ - calculateBounds: function() { │ │ │ │ - this.bounds = new OpenLayers.Bounds(this.x, this.y, this.x, this.y) │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - result = { │ │ │ │ - x0: result.x1, │ │ │ │ - y0: result.y1, │ │ │ │ - x1: result.x0, │ │ │ │ - y1: result.y0, │ │ │ │ - distance: result.distance │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return result │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - toShortString: function() { │ │ │ │ - return this.x + ", " + this.y │ │ │ │ - }, │ │ │ │ - move: function(x, y) { │ │ │ │ - this.x = this.x + x; │ │ │ │ - this.y = this.y + y; │ │ │ │ - this.clearBounds() │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - }, │ │ │ │ - getCentroid: function() { │ │ │ │ - return new OpenLayers.Geometry.Point(this.x, this.y) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - intersects: function(geometry) { │ │ │ │ - var intersect = false; │ │ │ │ - if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { │ │ │ │ - intersect = this.equals(geometry) │ │ │ │ - } else { │ │ │ │ - intersect = geometry.intersects(this) │ │ │ │ - } │ │ │ │ - return intersect │ │ │ │ - }, │ │ │ │ - transform: function(source, dest) { │ │ │ │ - if (source && dest) { │ │ │ │ - OpenLayers.Projection.transform(this, source, dest); │ │ │ │ - this.bounds = null │ │ │ │ - } │ │ │ │ - return this │ │ │ │ - }, │ │ │ │ - getVertices: function(nodes) { │ │ │ │ - return [this] │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Geometry.Point" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.Geolocate = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - geolocation: null, │ │ │ │ - available: "geolocation" in navigator, │ │ │ │ - bind: true, │ │ │ │ - watch: false, │ │ │ │ - geolocationOptions: null, │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (this.available && !this.geolocation) { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (this.active && this.watchId !== null) { │ │ │ │ - this.geolocation.clearWatch(this.watchId) │ │ │ │ - } │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - failure: function(error) { │ │ │ │ - this.events.triggerEvent("locationfailed", { │ │ │ │ - error: error │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Geolocate" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.DrawFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - layer: null, │ │ │ │ - callbacks: null, │ │ │ │ - multi: false, │ │ │ │ - featureAdded: function() {}, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - insertXY: function(x, y) { │ │ │ │ - if (this.handler && this.handler.line) { │ │ │ │ - this.handler.insertXY(x, y) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - insertDeltaXY: function(dx, dy) { │ │ │ │ - if (this.handler && this.handler.line) { │ │ │ │ - this.handler.insertDeltaXY(dx, dy) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - insertDirectionLength: function(direction, length) { │ │ │ │ - if (this.handler && this.handler.line) { │ │ │ │ - this.handler.insertDirectionLength(direction, length) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - insertDeflectionLength: function(deflection, length) { │ │ │ │ - if (this.handler && this.handler.line) { │ │ │ │ - this.handler.insertDeflectionLength(deflection, length) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - undo: function() { │ │ │ │ - return this.handler.undo && this.handler.undo() │ │ │ │ - }, │ │ │ │ - redo: function() { │ │ │ │ - return this.handler.redo && this.handler.redo() │ │ │ │ - }, │ │ │ │ - finishSketch: function() { │ │ │ │ - this.handler.finishGeometry() │ │ │ │ - }, │ │ │ │ - cancel: function() { │ │ │ │ - this.handler.cancel() │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.DrawFeature" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.Zoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - zoomInText: "+", │ │ │ │ - zoomInId: "olZoomInLink", │ │ │ │ - zoomOutText: "−", │ │ │ │ - zoomOutId: "olZoomOutLink", │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - onZoomClick: function(evt) { │ │ │ │ - var button = evt.buttonElement; │ │ │ │ - if (button === this.zoomInLink) { │ │ │ │ - this.map.zoomIn() │ │ │ │ - } else if (button === this.zoomOutLink) { │ │ │ │ - this.map.zoomOut() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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.Handler = OpenLayers.Class({ │ │ │ │ - id: null, │ │ │ │ - control: null, │ │ │ │ - map: null, │ │ │ │ - keyMask: null, │ │ │ │ - active: false, │ │ │ │ - evt: null, │ │ │ │ - touch: false, │ │ │ │ - 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 + "_") │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - this.map = map │ │ │ │ - }, │ │ │ │ - checkModifiers: function(evt) { │ │ │ │ - if (this.keyMask == null) { │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - 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); │ │ │ │ - return keyModifiers == this.keyMask │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (this.active) { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (!this.active) { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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]]) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - callback: function(name, args) { │ │ │ │ - if (name && this.callbacks[name]) { │ │ │ │ - this.callbacks[name].apply(this.control, args) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - register: function(name, method) { │ │ │ │ - this.map.events.registerPriority(name, this, method); │ │ │ │ - this.map.events.registerPriority(name, this, this.setEvent) │ │ │ │ - }, │ │ │ │ - unregister: function(name, method) { │ │ │ │ - this.map.events.unregister(name, this, method); │ │ │ │ - this.map.events.unregister(name, this, this.setEvent) │ │ │ │ - }, │ │ │ │ - setEvent: function(evt) { │ │ │ │ - this.evt = evt; │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - this.control = this.map = null │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.MOD_NONE = 0; │ │ │ │ -OpenLayers.Handler.MOD_SHIFT = 1; │ │ │ │ -OpenLayers.Handler.MOD_CTRL = 2; │ │ │ │ -OpenLayers.Handler.MOD_ALT = 4; │ │ │ │ -OpenLayers.Handler.MOD_META = 8; │ │ │ │ -OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - started: false, │ │ │ │ - stopDown: true, │ │ │ │ - dragging: false, │ │ │ │ - last: null, │ │ │ │ - start: null, │ │ │ │ - lastMoveEvt: null, │ │ │ │ - oldOnselectstart: null, │ │ │ │ - interval: 0, │ │ │ │ - timeoutId: null, │ │ │ │ - documentDrag: false, │ │ │ │ - documentEvents: null, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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]); │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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); │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - down: function(evt) {}, │ │ │ │ - move: function(evt) {}, │ │ │ │ - up: function(evt) {}, │ │ │ │ - out: function(evt) {}, │ │ │ │ - mousedown: function(evt) { │ │ │ │ - return this.dragstart(evt) │ │ │ │ - }, │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - return this.dragstart(evt) │ │ │ │ - }, │ │ │ │ - mousemove: function(evt) { │ │ │ │ - return this.dragmove(evt) │ │ │ │ - }, │ │ │ │ - touchmove: function(evt) { │ │ │ │ - return this.dragmove(evt) │ │ │ │ - }, │ │ │ │ - removeTimeout: function() { │ │ │ │ - this.timeoutId = null; │ │ │ │ - if (this.dragging) { │ │ │ │ - this.mousemove(this.lastMoveEvt) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - mouseup: function(evt) { │ │ │ │ - return this.dragend(evt) │ │ │ │ - }, │ │ │ │ - touchend: function(evt) { │ │ │ │ - evt.xy = this.last; │ │ │ │ - return this.dragend(evt) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - click: function(evt) { │ │ │ │ - return this.start == this.last │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.dragging = false; │ │ │ │ - activated = true │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - adjustXY: function(evt) { │ │ │ │ - var pos = OpenLayers.Util.pagePosition(this.map.viewPortDiv); │ │ │ │ - evt.xy.x -= pos[0]; │ │ │ │ - evt.xy.y -= pos[1] │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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 = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - KEY_EVENTS: ["keydown", "keyup"], │ │ │ │ - eventListener: null, │ │ │ │ - observeElement: null, │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ - this.eventListener = OpenLayers.Function.bindAsEventListener(this.handleKeyEvent, this) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - this.eventListener = null; │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - handleKeyEvent: function(evt) { │ │ │ │ - if (this.checkModifiers(evt)) { │ │ │ │ - this.callback(evt.type, [evt]) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Keyboard" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - documentDrag: false, │ │ │ │ - geometryTypes: null, │ │ │ │ - clickout: true, │ │ │ │ - toggle: true, │ │ │ │ - standalone: false, │ │ │ │ - layer: null, │ │ │ │ - feature: null, │ │ │ │ - vertex: null, │ │ │ │ - vertices: null, │ │ │ │ - virtualVertices: null, │ │ │ │ - handlers: null, │ │ │ │ - deleteCodes: null, │ │ │ │ - virtualStyle: null, │ │ │ │ - vertexRenderIntent: null, │ │ │ │ - mode: null, │ │ │ │ - createVertices: true, │ │ │ │ - modified: false, │ │ │ │ - radiusHandle: null, │ │ │ │ - dragHandle: null, │ │ │ │ - onModificationStart: function() {}, │ │ │ │ - onModification: function() {}, │ │ │ │ - onModificationEnd: function() {}, │ │ │ │ - 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 = .3; │ │ │ │ - this.virtualStyle.strokeOpacity = .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] │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - }; │ │ │ │ - var keyboardOptions = { │ │ │ │ - keydown: this.handleKeypress │ │ │ │ - }; │ │ │ │ - this.handlers = { │ │ │ │ - keyboard: new OpenLayers.Handler.Keyboard(this, keyboardOptions), │ │ │ │ - drag: new OpenLayers.Handler.Drag(this, dragCallbacks, dragOptions) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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, []) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = false; │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - beforeSelectFeature: function(feature) { │ │ │ │ - return this.layer.events.triggerEvent("beforefeaturemodified", { │ │ │ │ - feature: 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) │ │ │ │ - } │ │ │ │ - var modified = feature.modified; │ │ │ │ - if (feature.geometry && !(modified && modified.geometry)) { │ │ │ │ - this._originalGeometry = feature.geometry.clone() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - this._unselect = feature │ │ │ │ - } │ │ │ │ - this.selectFeature(feature) │ │ │ │ - } │ │ │ │ - if (feature._sketch || isPoint) { │ │ │ │ - this.vertex = feature; │ │ │ │ - this.handlers.drag.stopDown = true │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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; │ │ │ │ - if (this.feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { │ │ │ │ - this.layer.events.triggerEvent("vertexmodified", { │ │ │ │ - vertex: vertex.geometry, │ │ │ │ - feature: this.feature, │ │ │ │ - pixel: pixel │ │ │ │ - }) │ │ │ │ - } else { │ │ │ │ - if (vertex._index) { │ │ │ │ - vertex.geometry.parent.addComponent(vertex.geometry, vertex._index); │ │ │ │ - delete vertex._index; │ │ │ │ - OpenLayers.Util.removeItem(this.virtualVertices, vertex); │ │ │ │ - this.vertices.push(vertex) │ │ │ │ - } else if (vertex == this.dragHandle) { │ │ │ │ - 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) { │ │ │ │ - this.layer.events.triggerEvent("vertexmodified", { │ │ │ │ - vertex: vertex.geometry, │ │ │ │ - feature: this.feature, │ │ │ │ - pixel: pixel │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - if (this.virtualVertices.length > 0) { │ │ │ │ - this.layer.destroyFeatures(this.virtualVertices, { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ - this.virtualVertices = [] │ │ │ │ - } │ │ │ │ - this.layer.drawFeature(this.feature, this.standalone ? undefined : "select") │ │ │ │ - } │ │ │ │ - this.layer.drawFeature(vertex) │ │ │ │ - }, │ │ │ │ - dragComplete: function(vertex) { │ │ │ │ - this.resetVertices(); │ │ │ │ - this.setFeatureState(); │ │ │ │ - this.onModification(this.feature); │ │ │ │ - this.layer.events.triggerEvent("featuremodified", { │ │ │ │ - feature: this.feature │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - if (!(this.mode & OpenLayers.Control.ModifyFeature.RESIZE)) { │ │ │ │ - this.collectVertices() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - handleKeypress: function(evt) { │ │ │ │ - var code = evt.keyCode; │ │ │ │ - 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) { │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - 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); │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - 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; │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - this.handlers.drag.setMap(map); │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - handleMapEvents: function(evt) { │ │ │ │ - if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ - this.moveLayerToTop() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - moveLayerToTop: function() { │ │ │ │ - var index = Math.max(this.map.Z_INDEX_BASE["Feature"] - 1, this.layer.getZIndex()) + 1; │ │ │ │ - this.layer.setZIndex(index) │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.ModifyFeature.RESHAPE = 1; │ │ │ │ -OpenLayers.Control.ModifyFeature.RESIZE = 2; │ │ │ │ -OpenLayers.Control.ModifyFeature.ROTATE = 4; │ │ │ │ -OpenLayers.Control.ModifyFeature.DRAG = 8; │ │ │ │ -OpenLayers.Control.Attribution = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - separator: ", ", │ │ │ │ - template: "${layers}", │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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()) { │ │ │ │ - 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.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - 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" │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - feature: null, │ │ │ │ - lastFeature: null, │ │ │ │ - down: null, │ │ │ │ - up: null, │ │ │ │ - clickTolerance: 4, │ │ │ │ - geometryTypes: null, │ │ │ │ - stopClick: true, │ │ │ │ - stopDown: true, │ │ │ │ - stopUp: false, │ │ │ │ - initialize: function(control, layer, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ - this.layer = layer │ │ │ │ - }, │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - return OpenLayers.Event.isMultiTouch(evt) ? true : this.mousedown(evt) │ │ │ │ - }, │ │ │ │ - touchmove: function(evt) { │ │ │ │ - OpenLayers.Event.preventDefault(evt) │ │ │ │ - }, │ │ │ │ - mousedown: function(evt) { │ │ │ │ - if (OpenLayers.Event.isLeftClick(evt) || OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ - this.down = evt.xy │ │ │ │ - } │ │ │ │ - return this.handle(evt) ? !this.stopDown : true │ │ │ │ - }, │ │ │ │ - mouseup: function(evt) { │ │ │ │ - this.up = evt.xy; │ │ │ │ - return this.handle(evt) ? !this.stopUp : true │ │ │ │ - }, │ │ │ │ - click: function(evt) { │ │ │ │ - return this.handle(evt) ? !this.stopClick : true │ │ │ │ - }, │ │ │ │ - mousemove: function(evt) { │ │ │ │ - if (!this.callbacks["over"] && !this.callbacks["out"]) { │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - this.handle(evt); │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - dblclick: function(evt) { │ │ │ │ - return !this.handle(evt) │ │ │ │ - }, │ │ │ │ - geometryTypeMatches: function(feature) { │ │ │ │ - return this.geometryTypes == null || OpenLayers.Util.indexOf(this.geometryTypes, feature.geometry.CLASS_NAME) > -1 │ │ │ │ - }, │ │ │ │ - handle: function(evt) { │ │ │ │ - if (this.feature && !this.feature.layer) { │ │ │ │ - this.feature = null │ │ │ │ - } │ │ │ │ - var type = evt.type; │ │ │ │ - var handled = false; │ │ │ │ - var previouslyIn = !!this.feature; │ │ │ │ - var click = type == "click" || type == "dblclick" || type == "touchstart"; │ │ │ │ - this.feature = this.layer.getFeatureFromEvent(evt); │ │ │ │ - if (this.feature && !this.feature.layer) { │ │ │ │ - this.feature = null │ │ │ │ - } │ │ │ │ - if (this.lastFeature && !this.lastFeature.layer) { │ │ │ │ - this.lastFeature = null │ │ │ │ - } │ │ │ │ - if (this.feature) { │ │ │ │ - if (type === "touchstart") { │ │ │ │ - OpenLayers.Event.preventDefault(evt) │ │ │ │ - } │ │ │ │ - var inNew = this.feature != this.lastFeature; │ │ │ │ - if (this.geometryTypeMatches(this.feature)) { │ │ │ │ - if (previouslyIn && inNew) { │ │ │ │ - if (this.lastFeature) { │ │ │ │ - this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ - } │ │ │ │ - this.triggerCallback(type, "in", [this.feature]) │ │ │ │ - } else if (!previouslyIn || click) { │ │ │ │ - this.triggerCallback(type, "in", [this.feature]) │ │ │ │ - } │ │ │ │ - this.lastFeature = this.feature; │ │ │ │ - handled = true │ │ │ │ - } else { │ │ │ │ - if (this.lastFeature && (previouslyIn && inNew || click)) { │ │ │ │ - this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ - } │ │ │ │ - this.feature = null │ │ │ │ - } │ │ │ │ - } else if (this.lastFeature && (previouslyIn || click)) { │ │ │ │ - this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ - } │ │ │ │ - return handled │ │ │ │ - }, │ │ │ │ - triggerCallback: function(type, mode, args) { │ │ │ │ - var key = this.EVENTMAP[type][mode]; │ │ │ │ - if (key) { │ │ │ │ - if (type == "click" && this.up && this.down) { │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - this.up = this.down = null │ │ │ │ - } else { │ │ │ │ - this.callback(key, args) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - handleMapEvents: function(evt) { │ │ │ │ - if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ - this.moveLayerToTop() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - moveLayerToTop: function() { │ │ │ │ - var index = Math.max(this.map.Z_INDEX_BASE["Feature"] - 1, this.layer.getZIndex()) + 1; │ │ │ │ - this.layer.setZIndex(index) │ │ │ │ - }, │ │ │ │ - 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.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ - displayInLayerSwitcher: false, │ │ │ │ - layers: null, │ │ │ │ - display: function() {}, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ - this.collectRoots(); │ │ │ │ - map.events.register("changelayer", this, this.handleChangeLayer) │ │ │ │ - }, │ │ │ │ - removeMap: function(map) { │ │ │ │ - map.events.unregister("changelayer", this, this.handleChangeLayer); │ │ │ │ - this.resetRoots(); │ │ │ │ - OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - collectRoots: function() { │ │ │ │ - var layer; │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - multipleKey: null, │ │ │ │ - toggleKey: null, │ │ │ │ - multiple: false, │ │ │ │ - clickout: true, │ │ │ │ - toggle: false, │ │ │ │ - hover: false, │ │ │ │ - highlightOnly: false, │ │ │ │ - box: false, │ │ │ │ - onBeforeSelect: function() {}, │ │ │ │ - onSelect: function() {}, │ │ │ │ - onUnselect: function() {}, │ │ │ │ - scope: null, │ │ │ │ - geometryTypes: null, │ │ │ │ - layer: null, │ │ │ │ - layers: null, │ │ │ │ - callbacks: null, │ │ │ │ - selectStyle: null, │ │ │ │ - renderIntent: "select", │ │ │ │ - handlers: null, │ │ │ │ - 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" │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - unselectAll: function(options) { │ │ │ │ - var layers = this.layers || [this.layer], │ │ │ │ - layer, feature, l, numExcept; │ │ │ │ - for (l = 0; l < layers.length; ++l) { │ │ │ │ - layer = layers[l]; │ │ │ │ - numExcept = 0; │ │ │ │ - if (layer.selectedFeatures != null) { │ │ │ │ - while (layer.selectedFeatures.length > numExcept) { │ │ │ │ - feature = layer.selectedFeatures[numExcept]; │ │ │ │ - if (!options || options.except != feature) { │ │ │ │ - this.unselect(feature) │ │ │ │ - } else { │ │ │ │ - ++numExcept │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - multipleSelect: function() { │ │ │ │ - return this.multiple || this.handlers.feature.evt && this.handlers.feature.evt[this.multipleKey] │ │ │ │ - }, │ │ │ │ - toggleSelect: function() { │ │ │ │ - return this.toggle || this.handlers.feature.evt && this.handlers.feature.evt[this.toggleKey] │ │ │ │ - }, │ │ │ │ - clickoutFeature: function(feature) { │ │ │ │ - if (!this.hover && this.clickout) { │ │ │ │ - this.unselectAll() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - outFeature: function(feature) { │ │ │ │ - if (this.hover) { │ │ │ │ - if (this.highlightOnly) { │ │ │ │ - if (feature._lastHighlighter == this.id) { │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - unhighlight: function(feature) { │ │ │ │ - var layer = feature.layer; │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - 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 (!this.handlers.feature.lastFeature) { │ │ │ │ - this.handlers.feature.lastFeature = layer.selectedFeatures[0] │ │ │ │ - } │ │ │ │ - layer.events.triggerEvent("featureselected", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - this.onSelect.call(this.scope, feature) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - unselect: function(feature) { │ │ │ │ - var layer = feature.layer; │ │ │ │ - this.unhighlight(feature); │ │ │ │ - OpenLayers.Util.removeItem(layer.selectedFeatures, feature); │ │ │ │ - layer.events.triggerEvent("featureunselected", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - this.onUnselect.call(this.scope, feature) │ │ │ │ - }, │ │ │ │ - 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 (!this.multipleSelect()) { │ │ │ │ - this.unselectAll() │ │ │ │ - } │ │ │ │ - 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]; │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - this.handlers.feature.setMap(map); │ │ │ │ - if (this.box) { │ │ │ │ - this.handlers.box.setMap(map) │ │ │ │ - } │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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.Control.DragPan = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ - panned: false, │ │ │ │ - interval: 0, │ │ │ │ - documentDrag: false, │ │ │ │ - kinetic: null, │ │ │ │ - enableKinetic: true, │ │ │ │ - kineticInterval: 10, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - panMapStart: function() { │ │ │ │ - if (this.kinetic) { │ │ │ │ - this.kinetic.begin() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - 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.Handler.Pinch = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - started: false, │ │ │ │ - stopDown: false, │ │ │ │ - pinching: false, │ │ │ │ - last: null, │ │ │ │ - start: null, │ │ │ │ - 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) { │ │ │ │ - return false │ │ │ │ - } else { │ │ │ │ - this.started = false; │ │ │ │ - this.start = null; │ │ │ │ - this.last = null │ │ │ │ - } │ │ │ │ - OpenLayers.Event.preventDefault(evt); │ │ │ │ - return 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; │ │ │ │ - OpenLayers.Event.stop(evt) │ │ │ │ - } else if (this.started) { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.pinching = false; │ │ │ │ - activated = true │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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)) │ │ │ │ - }, │ │ │ │ - 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.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ - pinchOrigin: null, │ │ │ │ - currentCenter: null, │ │ │ │ - autoActivate: true, │ │ │ │ - preserveCenter: false, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - pinchStart: function(evt, pinchData) { │ │ │ │ - var xy = this.preserveCenter ? this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; │ │ │ │ - this.pinchOrigin = xy; │ │ │ │ - this.currentCenter = xy │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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); │ │ │ │ - this.map.div.clientWidth = this.map.div.clientWidth; │ │ │ │ - this.map.setCenter(location, zoom) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.PinchZoom" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - delay: 300, │ │ │ │ - single: true, │ │ │ │ - double: false, │ │ │ │ - pixelTolerance: 0, │ │ │ │ - dblclickTolerance: 13, │ │ │ │ - stopSingle: false, │ │ │ │ - stopDouble: false, │ │ │ │ - timerId: null, │ │ │ │ - down: null, │ │ │ │ - last: null, │ │ │ │ - first: null, │ │ │ │ - rightclickTimerId: null, │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - this.down = this.getEventInfo(evt); │ │ │ │ - this.last = this.getEventInfo(evt); │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - touchmove: function(evt) { │ │ │ │ - this.last = this.getEventInfo(evt); │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - touchend: function(evt) { │ │ │ │ - if (this.down) { │ │ │ │ - evt.xy = this.last.xy; │ │ │ │ - evt.lastTouches = this.last.touches; │ │ │ │ - this.handleSingle(evt); │ │ │ │ - this.down = null │ │ │ │ - } │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - mousedown: function(evt) { │ │ │ │ - this.down = this.getEventInfo(evt); │ │ │ │ - this.last = this.getEventInfo(evt); │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - mouseup: function(evt) { │ │ │ │ - var propagate = true; │ │ │ │ - if (this.checkModifiers(evt) && this.control.handleRightClicks && OpenLayers.Event.isRightClick(evt)) { │ │ │ │ - propagate = this.rightclick(evt) │ │ │ │ - } │ │ │ │ - return propagate │ │ │ │ - }, │ │ │ │ - rightclick: function(evt) { │ │ │ │ - if (this.passesTolerance(evt)) { │ │ │ │ - if (this.rightclickTimerId != null) { │ │ │ │ - this.clearTimer(); │ │ │ │ - this.callback("dblrightclick", [evt]); │ │ │ │ - return !this.stopDouble │ │ │ │ - } else { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - delayedRightCall: function(evt) { │ │ │ │ - this.rightclickTimerId = null; │ │ │ │ - if (evt) { │ │ │ │ - this.callback("rightclick", [evt]) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - click: function(evt) { │ │ │ │ - if (!this.last) { │ │ │ │ - this.last = this.getEventInfo(evt) │ │ │ │ - } │ │ │ │ - this.handleSingle(evt); │ │ │ │ - return !this.stopSingle │ │ │ │ - }, │ │ │ │ - dblclick: function(evt) { │ │ │ │ - this.handleDouble(evt); │ │ │ │ - return !this.stopDouble │ │ │ │ - }, │ │ │ │ - handleDouble: function(evt) { │ │ │ │ - if (this.passesDblclickTolerance(evt)) { │ │ │ │ - if (this["double"]) { │ │ │ │ - this.callback("dblclick", [evt]) │ │ │ │ - } │ │ │ │ - this.clearTimer() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - handleSingle: function(evt) { │ │ │ │ - if (this.passesTolerance(evt)) { │ │ │ │ - if (this.timerId != null) { │ │ │ │ - if (this.last.touches && this.last.touches.length === 1) { │ │ │ │ - if (this["double"]) { │ │ │ │ - OpenLayers.Event.preventDefault(evt) │ │ │ │ - } │ │ │ │ - this.handleDouble(evt) │ │ │ │ - } │ │ │ │ - if (!this.last.touches || this.last.touches.length !== 2) { │ │ │ │ - this.clearTimer() │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.first = this.getEventInfo(evt); │ │ │ │ - var clickEvent = this.single ? OpenLayers.Util.extend({}, evt) : null; │ │ │ │ - this.queuePotentialClick(clickEvent) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - queuePotentialClick: function(evt) { │ │ │ │ - this.timerId = window.setTimeout(OpenLayers.Function.bind(this.delayedCall, this, evt), this.delay) │ │ │ │ - }, │ │ │ │ - passesTolerance: function(evt) { │ │ │ │ - var passes = true; │ │ │ │ - if (this.pixelTolerance != null && this.down && this.down.xy) { │ │ │ │ - passes = this.pixelTolerance >= this.down.xy.distanceTo(evt.xy); │ │ │ │ - if (passes && this.touch && this.down.touches.length === this.last.touches.length) { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - getTouchDistance: function(from, to) { │ │ │ │ - return Math.sqrt(Math.pow(from.clientX - to.clientX, 2) + Math.pow(from.clientY - to.clientY, 2)) │ │ │ │ - }, │ │ │ │ - passesDblclickTolerance: function(evt) { │ │ │ │ - var passes = true; │ │ │ │ - if (this.down && this.first) { │ │ │ │ - passes = this.down.xy.distanceTo(this.first.xy) <= this.dblclickTolerance │ │ │ │ - } │ │ │ │ - return passes │ │ │ │ - }, │ │ │ │ - clearTimer: function() { │ │ │ │ - if (this.timerId != null) { │ │ │ │ - window.clearTimeout(this.timerId); │ │ │ │ - this.timerId = null │ │ │ │ - } │ │ │ │ - if (this.rightclickTimerId != null) { │ │ │ │ - window.clearTimeout(this.rightclickTimerId); │ │ │ │ - this.rightclickTimerId = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - delayedCall: function(evt) { │ │ │ │ - this.timerId = null; │ │ │ │ - if (evt) { │ │ │ │ - this.callback("click", [evt]) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - dragPan: null, │ │ │ │ - dragPanOptions: null, │ │ │ │ - pinchZoom: null, │ │ │ │ - pinchZoomOptions: null, │ │ │ │ - clickHandlerOptions: null, │ │ │ │ - documentDrag: false, │ │ │ │ - autoActivate: true, │ │ │ │ - initialize: function(options) { │ │ │ │ - this.handlers = {}; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.dragPan.activate(); │ │ │ │ - this.handlers.click.activate(); │ │ │ │ - this.pinchZoom.activate(); │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - this.dragPan.deactivate(); │ │ │ │ - this.handlers.click.deactivate(); │ │ │ │ - this.pinchZoom.deactivate(); │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - 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)) │ │ │ │ - }, │ │ │ │ - defaultClick: function(evt) { │ │ │ │ - if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ - this.map.zoomOut() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - defaultDblClick: function(evt) { │ │ │ │ - this.map.zoomTo(this.map.zoom + 1, evt.xy) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.TouchNavigation" │ │ │ │ -}); │ │ │ │ -OpenLayers.Strategy = OpenLayers.Class({ │ │ │ │ - layer: null, │ │ │ │ - options: null, │ │ │ │ - active: null, │ │ │ │ - autoActivate: true, │ │ │ │ - autoDestroy: true, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - this.options = options; │ │ │ │ - this.active = false │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - this.layer = null; │ │ │ │ - this.options = null │ │ │ │ - }, │ │ │ │ - setLayer: function(layer) { │ │ │ │ - this.layer = layer │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (!this.active) { │ │ │ │ - this.active = true; │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (this.active) { │ │ │ │ - this.active = false; │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ -}); │ │ │ │ -OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - preload: false, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - 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.ElementsIndexer = OpenLayers.Class({ │ │ │ │ - maxZIndex: null, │ │ │ │ - order: null, │ │ │ │ - indices: null, │ │ │ │ - compare: null, │ │ │ │ - initialize: function(yOrdering) { │ │ │ │ - this.compare = yOrdering ? OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER : OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER; │ │ │ │ - this.clear() │ │ │ │ - }, │ │ │ │ - insert: function(newNode) { │ │ │ │ - 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); │ │ │ │ - return this.getNextElement(rightIndex) │ │ │ │ - }, │ │ │ │ - remove: function(node) { │ │ │ │ - var nodeId = node.id; │ │ │ │ - var arrayIndex = OpenLayers.Util.indexOf(this.order, nodeId); │ │ │ │ - if (arrayIndex >= 0) { │ │ │ │ - this.order.splice(arrayIndex, 1); │ │ │ │ - delete this.indices[nodeId]; │ │ │ │ - if (this.order.length > 0) { │ │ │ │ - var lastId = this.order[this.order.length - 1]; │ │ │ │ - this.maxZIndex = this.indices[lastId] │ │ │ │ - } else { │ │ │ │ - this.maxZIndex = 0 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clear: function() { │ │ │ │ - this.order = []; │ │ │ │ - this.indices = {}; │ │ │ │ - this.maxZIndex = 0 │ │ │ │ - }, │ │ │ │ - exists: function(node) { │ │ │ │ - return this.indices[node.id] != null │ │ │ │ - }, │ │ │ │ - getZIndex: function(node) { │ │ │ │ - return node._style.graphicZIndex │ │ │ │ - }, │ │ │ │ - determineZIndex: function(node) { │ │ │ │ - var zIndex = node._style.graphicZIndex; │ │ │ │ - if (zIndex == null) { │ │ │ │ - zIndex = this.maxZIndex; │ │ │ │ - node._style.graphicZIndex = zIndex │ │ │ │ - } else if (zIndex > this.maxZIndex) { │ │ │ │ - this.maxZIndex = zIndex │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -OpenLayers.ElementsIndexer.IndexingMethods = { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - Z_ORDER_DRAWING_ORDER: function(indexer, newNode, nextNode) { │ │ │ │ - var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(indexer, newNode, nextNode); │ │ │ │ - if (nextNode && returnVal == 0) { │ │ │ │ - returnVal = 1 │ │ │ │ - } │ │ │ │ - return returnVal │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ - rendererRoot: null, │ │ │ │ - root: null, │ │ │ │ - vectorRoot: null, │ │ │ │ - textRoot: null, │ │ │ │ - xmlns: null, │ │ │ │ - xOffset: 0, │ │ │ │ - indexer: null, │ │ │ │ - BACKGROUND_ID_SUFFIX: "_background", │ │ │ │ - LABEL_ID_SUFFIX: "_label", │ │ │ │ - LABEL_OUTLINE_SUFFIX: "_outline", │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.clear(); │ │ │ │ - this.rendererRoot = null; │ │ │ │ - this.root = null; │ │ │ │ - this.xmlns = null; │ │ │ │ - OpenLayers.Renderer.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - getNodeType: function(geometry, style) {}, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - redrawNode: function(id, geometry, style, featureId) { │ │ │ │ - style = this.applyDefaultSymbolizer(style); │ │ │ │ - var node = this.nodeFactory(id, this.getNodeType(geometry, style)); │ │ │ │ - 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; │ │ │ │ - if (this.indexer) { │ │ │ │ - var insert = this.indexer.insert(node); │ │ │ │ - if (insert) { │ │ │ │ - this.vectorRoot.insertBefore(node, insert) │ │ │ │ - } else { │ │ │ │ - this.vectorRoot.appendChild(node) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (node.parentNode !== this.vectorRoot) { │ │ │ │ - this.vectorRoot.appendChild(node) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.postDraw(node); │ │ │ │ - return drawResult.complete │ │ │ │ - }, │ │ │ │ - redrawBackgroundNode: function(id, geometry, style, featureId) { │ │ │ │ - var backgroundStyle = OpenLayers.Util.extend({}, style); │ │ │ │ - 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; │ │ │ │ - backgroundStyle.backgroundGraphic = null; │ │ │ │ - backgroundStyle.backgroundXOffset = null; │ │ │ │ - backgroundStyle.backgroundYOffset = null; │ │ │ │ - backgroundStyle.backgroundGraphicZIndex = null; │ │ │ │ - return this.redrawNode(id + this.BACKGROUND_ID_SUFFIX, geometry, backgroundStyle, null) │ │ │ │ - }, │ │ │ │ - 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; │ │ │ │ - if (drawn != false) { │ │ │ │ - return { │ │ │ │ - node: this.setStyle(node, style, options, geometry), │ │ │ │ - complete: drawn │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - postDraw: function(node) {}, │ │ │ │ - drawPoint: function(node, geometry) {}, │ │ │ │ - drawLineString: function(node, geometry) {}, │ │ │ │ - drawLinearRing: function(node, geometry) {}, │ │ │ │ - drawPolygon: function(node, geometry) {}, │ │ │ │ - drawRectangle: function(node, geometry) {}, │ │ │ │ - drawCircle: function(node, geometry) {}, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getFeatureIdFromEvent: function(evt) { │ │ │ │ - var target = evt.target; │ │ │ │ - var useElement = target && target.correspondingUseElement; │ │ │ │ - var node = useElement ? useElement : target || evt.srcElement; │ │ │ │ - return node._featureId │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - bElem.parentNode.removeChild(bElem) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - nodeTypeCompare: function(node, type) {}, │ │ │ │ - createNode: function(type, id) {}, │ │ │ │ - moveRoot: function(renderer) { │ │ │ │ - var root = this.root; │ │ │ │ - if (renderer.root.parentNode == this.rendererRoot) { │ │ │ │ - root = renderer.root │ │ │ │ - } │ │ │ │ - root.parentNode.removeChild(root); │ │ │ │ - renderer.rendererRoot.appendChild(root) │ │ │ │ - }, │ │ │ │ - getRenderLayerId: function() { │ │ │ │ - return this.root.parentNode.parentNode.id │ │ │ │ - }, │ │ │ │ - isComplexSymbol: function(graphicName) { │ │ │ │ - return graphicName != "circle" && !!graphicName │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.Elements" │ │ │ │ -}); │ │ │ │ -OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ - xmlns: "http://www.w3.org/2000/svg", │ │ │ │ - xlinkns: "http://www.w3.org/1999/xlink", │ │ │ │ - MAX_PIXEL: 15e3, │ │ │ │ - translationParameters: null, │ │ │ │ - symbolMetrics: null, │ │ │ │ - initialize: function(containerID) { │ │ │ │ - if (!this.supported()) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - OpenLayers.Renderer.Elements.prototype.initialize.apply(this, arguments); │ │ │ │ - this.translationParameters = { │ │ │ │ - x: 0, │ │ │ │ - y: 0 │ │ │ │ - }; │ │ │ │ - this.symbolMetrics = {} │ │ │ │ - }, │ │ │ │ - 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")) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 (resolutionChanged) { │ │ │ │ - this.left = left; │ │ │ │ - this.top = top; │ │ │ │ - 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) { │ │ │ │ - this.setExtent(extent, true) │ │ │ │ - } │ │ │ │ - return coordSysUnchanged && inRange │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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); │ │ │ │ - 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 : -(.5 * width); │ │ │ │ - var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.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)) { │ │ │ │ - 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; │ │ │ │ - var parent = node.parentNode; │ │ │ │ - var nextSibling = node.nextSibling; │ │ │ │ - if (parent) { │ │ │ │ - parent.removeChild(node) │ │ │ │ - } │ │ │ │ - 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); │ │ │ │ - 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"); │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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, ",") │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - createNode: function(type, id) { │ │ │ │ - var node = document.createElementNS(this.xmlns, type); │ │ │ │ - if (id) { │ │ │ │ - node.setAttributeNS(null, "id", id) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - nodeTypeCompare: function(node, type) { │ │ │ │ - return type == node.nodeName │ │ │ │ - }, │ │ │ │ - createRenderRoot: function() { │ │ │ │ - var svg = this.nodeFactory(this.container.id + "_svgRoot", "svg"); │ │ │ │ - svg.style.display = "block"; │ │ │ │ - return svg │ │ │ │ - }, │ │ │ │ - createRoot: function(suffix) { │ │ │ │ - return this.nodeFactory(this.container.id + suffix, "g") │ │ │ │ - }, │ │ │ │ - createDefs: function() { │ │ │ │ - var defs = this.nodeFactory(this.container.id + "_defs", "defs"); │ │ │ │ - this.rendererRoot.appendChild(defs); │ │ │ │ - return defs │ │ │ │ - }, │ │ │ │ - drawPoint: function(node, geometry) { │ │ │ │ - return this.drawCircle(node, geometry, 1) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawText: function(featureId, style, location) { │ │ │ │ - var drawOutline = !!style.labelOutlineWidth; │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 { │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getPosition: function(node) { │ │ │ │ - return { │ │ │ │ - x: parseFloat(node.getAttributeNS(null, "cx")), │ │ │ │ - y: parseFloat(node.getAttributeNS(null, "cy")) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - importSymbol: function(graphicName) { │ │ │ │ - if (!this.defs) { │ │ │ │ - this.defs = this.createDefs() │ │ │ │ - } │ │ │ │ - var id = this.container.id + "-" + graphicName; │ │ │ │ - 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(); │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -OpenLayers.Renderer.SVG.LABEL_ALIGN = { │ │ │ │ - l: "start", │ │ │ │ - r: "end", │ │ │ │ - b: "bottom", │ │ │ │ - t: "hanging" │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.SVG.LABEL_VSHIFT = { │ │ │ │ - t: "-70%", │ │ │ │ - b: "0" │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.SVG.LABEL_VFACTOR = { │ │ │ │ - t: 0, │ │ │ │ - b: -1 │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.SVG.preventDefault = function(e) { │ │ │ │ - OpenLayers.Event.preventDefault(e) │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ - hitDetection: true, │ │ │ │ - hitOverflow: 0, │ │ │ │ - canvas: null, │ │ │ │ - features: null, │ │ │ │ - pendingRedraw: false, │ │ │ │ - cachedSymbolBounds: {}, │ │ │ │ - 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") │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setExtent: function() { │ │ │ │ - OpenLayers.Renderer.prototype.setExtent.apply(this, arguments); │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - eraseGeometry: function(geometry, featureId) { │ │ │ │ - this.eraseFeatures(this.features[featureId][0]) │ │ │ │ - }, │ │ │ │ - supported: function() { │ │ │ │ - return OpenLayers.CANVAS_SUPPORTED │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawFeature: function(feature, style) { │ │ │ │ - var rendered; │ │ │ │ - if (feature.geometry) { │ │ │ │ - style = this.applyDefaultSymbolizer(style || feature.style); │ │ │ │ - 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) { │ │ │ │ - this.features[feature.id] = [feature, style] │ │ │ │ - } else { │ │ │ │ - delete this.features[feature.id] │ │ │ │ - } │ │ │ │ - this.pendingRedraw = true │ │ │ │ - } │ │ │ │ - if (this.pendingRedraw && !this.locked) { │ │ │ │ - this.redraw(); │ │ │ │ - this.pendingRedraw = false │ │ │ │ - } │ │ │ │ - return rendered │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 : -(.5 * width); │ │ │ │ - var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.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 / 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 │ │ │ │ - }, │ │ │ │ - drawNamedSymbol: function(geometry, style, featureId) { │ │ │ │ - var x, y, cx, cy, i, symbolBounds, scaling, angle; │ │ │ │ - var unscaledStrokeWidth; │ │ │ │ - var deg2rad = Math.PI / 180; │ │ │ │ - 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; │ │ │ │ - this.canvas.lineCap = "round"; │ │ │ │ - this.canvas.lineJoin = "round"; │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.lineCap = "round"; │ │ │ │ - this.hitContext.lineJoin = "round" │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - this.canvas.save(); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.save() │ │ │ │ - } │ │ │ │ - this.canvas.translate(p0, p1); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.translate(p0, p1) │ │ │ │ - } │ │ │ │ - angle = deg2rad * style.rotation; │ │ │ │ - if (!isNaN(angle)) { │ │ │ │ - this.canvas.rotate(angle); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.rotate(angle) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - scaling = 2 * style.pointRadius / Math.max(symbolBounds.getWidth(), symbolBounds.getHeight()); │ │ │ │ - this.canvas.scale(scaling, scaling); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.scale(scaling, scaling) │ │ │ │ - } │ │ │ │ - cx = symbolBounds.getCenterLonLat().lon; │ │ │ │ - cy = symbolBounds.getCenterLonLat().lat; │ │ │ │ - this.canvas.translate(-cx, -cy); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.translate(-cx, -cy) │ │ │ │ - } │ │ │ │ - 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") │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - featureIdToHex: function(featureId) { │ │ │ │ - var id = Number(featureId.split("_").pop()) + 1; │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - setHitContextStyle: function(type, featureId, symbolizer, strokeScaling) { │ │ │ │ - var hex = this.featureIdToHex(featureId); │ │ │ │ - if (type == "fill") { │ │ │ │ - this.hitContext.globalAlpha = 1; │ │ │ │ - this.hitContext.fillStyle = hex │ │ │ │ - } else if (type == "stroke") { │ │ │ │ - this.hitContext.globalAlpha = 1; │ │ │ │ - this.hitContext.strokeStyle = hex; │ │ │ │ - if (typeof strokeScaling === "undefined") { │ │ │ │ - this.hitContext.lineWidth = symbolizer.strokeWidth + 2 │ │ │ │ - } else { │ │ │ │ - if (!isNaN(strokeScaling)) { │ │ │ │ - this.hitContext.lineWidth = symbolizer.strokeWidth + 2 / strokeScaling │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.hitContext.globalAlpha = 0; │ │ │ │ - this.hitContext.lineWidth = 1 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawLineString: function(geometry, style, featureId) { │ │ │ │ - style = OpenLayers.Util.applyDefaults({ │ │ │ │ - fill: false │ │ │ │ - }, style); │ │ │ │ - this.drawLinearRing(geometry, style, featureId) │ │ │ │ - }, │ │ │ │ - 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") │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawPolygon: function(geometry, style, featureId) { │ │ │ │ - var components = geometry.components; │ │ │ │ - var len = components.length; │ │ │ │ - this.drawLinearRing(components[0], style, featureId); │ │ │ │ - for (var i = 1; i < len; ++i) { │ │ │ │ - this.canvas.globalCompositeOperation = "destination-out"; │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.globalCompositeOperation = "destination-out" │ │ │ │ - } │ │ │ │ - this.drawLinearRing(components[i], OpenLayers.Util.applyDefaults({ │ │ │ │ - stroke: false, │ │ │ │ - fillOpacity: 1 │ │ │ │ - }, 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawText: function(location, style) { │ │ │ │ - var pt = this.getLocalXY(location); │ │ │ │ - this.setCanvasStyle("reset"); │ │ │ │ - this.canvas.fillStyle = style.fontColor; │ │ │ │ - this.canvas.globalAlpha = style.fontOpacity || 1; │ │ │ │ - var fontStyle = [style.fontStyle ? style.fontStyle : "normal", "normal", 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) { │ │ │ │ - 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; │ │ │ │ - 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) { │ │ │ │ - this.canvas.mozTextStyle = fontStyle; │ │ │ │ - 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") │ │ │ │ - }, │ │ │ │ - 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] │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getFeatureIdFromEvent: function(evt) { │ │ │ │ - var featureId, feature; │ │ │ │ - if (this.hitDetection && this.root.style.display !== "none") { │ │ │ │ - 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) { │ │ │ │ - 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) {} │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return feature │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -OpenLayers.Renderer.Canvas.LABEL_ALIGN = { │ │ │ │ - l: "left", │ │ │ │ - r: "right", │ │ │ │ - t: "top", │ │ │ │ - b: "bottom" │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.Canvas.LABEL_FACTOR = { │ │ │ │ - l: 0, │ │ │ │ - r: -1, │ │ │ │ - t: 0, │ │ │ │ - b: -1 │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.Canvas.drawImageScaleFactor = null; │ │ │ │ -OpenLayers.Format = OpenLayers.Class({ │ │ │ │ - options: null, │ │ │ │ - externalProjection: null, │ │ │ │ - internalProjection: null, │ │ │ │ - data: null, │ │ │ │ - keepData: false, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - this.options = options │ │ │ │ - }, │ │ │ │ - destroy: function() {}, │ │ │ │ - read: function(data) { │ │ │ │ - throw new Error("Read not implemented.") │ │ │ │ - }, │ │ │ │ - write: function(object) { │ │ │ │ - throw new Error("Write not implemented.") │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.JSON = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ - indent: " ", │ │ │ │ - space: " ", │ │ │ │ - newline: "\n", │ │ │ │ - level: 0, │ │ │ │ - pretty: false, │ │ │ │ - nativeJSON: function() { │ │ │ │ - return !!(window.JSON && typeof JSON.parse == "function" && typeof JSON.stringify == "function") │ │ │ │ - }(), │ │ │ │ - read: function(json, filter) { │ │ │ │ - var object; │ │ │ │ - if (this.nativeJSON) { │ │ │ │ - object = JSON.parse(json, filter) │ │ │ │ - } else try { │ │ │ │ - if (/^[\],:{}\s]*$/.test(json.replace(/\\["\\\/bfnrtu]/g, "@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]").replace(/(?:^|:|,)(?:\s*\[)+/g, ""))) { │ │ │ │ - object = eval("(" + json + ")"); │ │ │ │ - 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) {} │ │ │ │ - if (this.keepData) { │ │ │ │ - this.data = object │ │ │ │ - } │ │ │ │ - return object │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - writeIndent: function() { │ │ │ │ - var pieces = []; │ │ │ │ - if (this.pretty) { │ │ │ │ - for (var i = 0; i < this.level; ++i) { │ │ │ │ - pieces.push(this.indent) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return pieces.join("") │ │ │ │ - }, │ │ │ │ - writeNewline: function() { │ │ │ │ - return this.pretty ? this.newline : "" │ │ │ │ - }, │ │ │ │ - writeSpace: function() { │ │ │ │ - return this.pretty ? this.space : "" │ │ │ │ - }, │ │ │ │ - serialize: { │ │ │ │ - object: function(object) { │ │ │ │ - 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)) { │ │ │ │ - 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("") │ │ │ │ - }, │ │ │ │ - array: function(array) { │ │ │ │ - var json; │ │ │ │ - var pieces = ["["]; │ │ │ │ - this.level += 1; │ │ │ │ - for (var i = 0, len = array.length; i < len; ++i) { │ │ │ │ - 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("") │ │ │ │ - }, │ │ │ │ - string: function(string) { │ │ │ │ - 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 + '"' │ │ │ │ - }, │ │ │ │ - number: function(number) { │ │ │ │ - return isFinite(number) ? String(number) : "null" │ │ │ │ - }, │ │ │ │ - boolean: function(bool) { │ │ │ │ - return String(bool) │ │ │ │ - }, │ │ │ │ - date: function(date) { │ │ │ │ - function format(number) { │ │ │ │ - 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.Geometry.Collection = OpenLayers.Class(OpenLayers.Geometry, { │ │ │ │ - components: null, │ │ │ │ - componentTypes: null, │ │ │ │ - initialize: function(components) { │ │ │ │ - OpenLayers.Geometry.prototype.initialize.apply(this, arguments); │ │ │ │ - this.components = []; │ │ │ │ - if (components != null) { │ │ │ │ - this.addComponents(components) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.components.length = 0; │ │ │ │ - this.components = null; │ │ │ │ - OpenLayers.Geometry.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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()) │ │ │ │ - } │ │ │ │ - OpenLayers.Util.applyDefaults(geometry, this); │ │ │ │ - return 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(",") │ │ │ │ - }, │ │ │ │ - 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()) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (bounds.left != null && bounds.bottom != null && bounds.right != null && bounds.top != null) { │ │ │ │ - this.setBounds(bounds) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - addComponents: function(components) { │ │ │ │ - if (!OpenLayers.Util.isArray(components)) { │ │ │ │ - components = [components] │ │ │ │ - } │ │ │ │ - for (var i = 0, len = components.length; i < len; i++) { │ │ │ │ - this.addComponent(components[i]) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - removeComponent: function(component) { │ │ │ │ - OpenLayers.Util.removeItem(this.components, component); │ │ │ │ - this.clearBounds(); │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - getLength: function() { │ │ │ │ - var length = 0; │ │ │ │ - for (var i = 0, len = this.components.length; i < len; i++) { │ │ │ │ - length += this.components[i].getLength() │ │ │ │ - } │ │ │ │ - return length │ │ │ │ - }, │ │ │ │ - getArea: function() { │ │ │ │ - var area = 0; │ │ │ │ - for (var i = 0, len = this.components.length; i < len; i++) { │ │ │ │ - area += this.components[i].getArea() │ │ │ │ - } │ │ │ │ - return area │ │ │ │ - }, │ │ │ │ - getGeodesicArea: function(projection) { │ │ │ │ - var area = 0; │ │ │ │ - for (var i = 0, len = this.components.length; i < len; i++) { │ │ │ │ - area += this.components[i].getGeodesicArea(projection) │ │ │ │ - } │ │ │ │ - return area │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ - areas[i] = 1 │ │ │ │ - } │ │ │ │ - areaSum = areas.length │ │ │ │ - } else { │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - getGeodesicLength: function(projection) { │ │ │ │ - var length = 0; │ │ │ │ - for (var i = 0, len = this.components.length; i < len; i++) { │ │ │ │ - length += this.components[i].getGeodesicLength(projection) │ │ │ │ - } │ │ │ │ - return length │ │ │ │ - }, │ │ │ │ - move: function(x, y) { │ │ │ │ - for (var i = 0, len = this.components.length; i < len; i++) { │ │ │ │ - this.components[i].move(x, y) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - rotate: function(angle, origin) { │ │ │ │ - for (var i = 0, len = this.components.length; i < len; ++i) { │ │ │ │ - this.components[i].rotate(angle, origin) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - resize: function(scale, origin, ratio) { │ │ │ │ - for (var i = 0; i < this.components.length; ++i) { │ │ │ │ - this.components[i].resize(scale, origin, ratio) │ │ │ │ - } │ │ │ │ - return this │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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.MultiPoint = OpenLayers.Class(OpenLayers.Geometry.Collection, { │ │ │ │ - componentTypes: ["OpenLayers.Geometry.Point"], │ │ │ │ - addPoint: function(point, index) { │ │ │ │ - this.addComponent(point, index) │ │ │ │ - }, │ │ │ │ - removePoint: function(point) { │ │ │ │ - this.removeComponent(point) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Geometry.MultiPoint" │ │ │ │ -}); │ │ │ │ -OpenLayers.Geometry.Curve = OpenLayers.Class(OpenLayers.Geometry.MultiPoint, { │ │ │ │ - componentTypes: ["OpenLayers.Geometry.Point"], │ │ │ │ - getLength: function() { │ │ │ │ - var length = 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 │ │ │ │ - }, │ │ │ │ - getGeodesicLength: function(projection) { │ │ │ │ - var geom = this; │ │ │ │ - if (projection) { │ │ │ │ - var gg = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ - if (!gg.equals(projection)) { │ │ │ │ - geom = this.clone().transform(projection, gg) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var length = 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]; │ │ │ │ - length += OpenLayers.Util.distVincenty({ │ │ │ │ - lon: p1.x, │ │ │ │ - lat: p1.y │ │ │ │ - }, { │ │ │ │ - lon: p2.x, │ │ │ │ - lat: p2.y │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return length * 1e3 │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Geometry.Curve" │ │ │ │ -}); │ │ │ │ -OpenLayers.Geometry.LineString = OpenLayers.Class(OpenLayers.Geometry.Curve, { │ │ │ │ - removeComponent: function(point) { │ │ │ │ - var removed = this.components && this.components.length > 2; │ │ │ │ - if (removed) { │ │ │ │ - OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, arguments) │ │ │ │ - } │ │ │ │ - return removed │ │ │ │ - }, │ │ │ │ - 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; │ │ │ │ - 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) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ - if (seg2.x2 < seg1x1) { │ │ │ │ - continue │ │ │ │ - } │ │ │ │ - seg2y1 = seg2.y1; │ │ │ │ - seg2y2 = seg2.y2; │ │ │ │ - if (Math.min(seg2y1, seg2y2) > Math.max(seg1y1, seg1y2)) { │ │ │ │ - continue │ │ │ │ - } │ │ │ │ - if (Math.max(seg2y1, seg2y2) < Math.min(seg1y1, seg1y2)) { │ │ │ │ - continue │ │ │ │ - } │ │ │ │ - if (OpenLayers.Geometry.segmentsIntersect(seg1, seg2)) { │ │ │ │ - intersect = true; │ │ │ │ - break outer │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - intersect = geometry.intersects(this) │ │ │ │ - } │ │ │ │ - return intersect │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - function byX1(seg1, seg2) { │ │ │ │ - return seg1.x1 - seg2.x1 │ │ │ │ - } │ │ │ │ - return segments.sort(byX1) │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - 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) { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - splitWith: function(geometry, options) { │ │ │ │ - return geometry.split(this, options) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 (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) { │ │ │ │ - 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); │ │ │ │ - if (details) { │ │ │ │ - best = { │ │ │ │ - distance: best.distance, │ │ │ │ - x0: best.x1, │ │ │ │ - y0: best.y1, │ │ │ │ - x1: best.x0, │ │ │ │ - y1: best.y0 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return best │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }; │ │ │ │ - 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) { │ │ │ │ - pointIndexsToKeep.push(indexFarthest); │ │ │ │ - douglasPeuckerReduction(points, firstPoint, indexFarthest, tolerance); │ │ │ │ - douglasPeuckerReduction(points, indexFarthest, lastPoint, tolerance) │ │ │ │ - } │ │ │ │ - }; │ │ │ │ - var perpendicularDistance = function(point1, point2, point) { │ │ │ │ - var area = Math.abs(.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 = []; │ │ │ │ - pointIndexsToKeep.push(firstPoint); │ │ │ │ - pointIndexsToKeep.push(lastPoint); │ │ │ │ - while (points[firstPoint].equals(points[lastPoint])) { │ │ │ │ - lastPoint--; │ │ │ │ - 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.MultiLineString = OpenLayers.Class(OpenLayers.Geometry.Collection, { │ │ │ │ - componentTypes: ["OpenLayers.Geometry.LineString"], │ │ │ │ - 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) { │ │ │ │ - splits.unshift(j, 1); │ │ │ │ - Array.prototype.splice.apply(targetParts, splits); │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (!sourceSplit) { │ │ │ │ - if (sourceParts.length) { │ │ │ │ - sourceParts[sourceParts.length - 1].addComponent(sourceLine.clone()) │ │ │ │ - } else { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - 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) { │ │ │ │ - if (targetParts.length) { │ │ │ │ - targetParts[targetParts.length - 1].addComponent(targetLine.clone()) │ │ │ │ - } else { │ │ │ │ - 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.Geometry.LinearRing = OpenLayers.Class(OpenLayers.Geometry.LineString, { │ │ │ │ - componentTypes: ["OpenLayers.Geometry.Point"], │ │ │ │ - addComponent: function(point, index) { │ │ │ │ - var added = false; │ │ │ │ - var lastPoint = this.components.pop(); │ │ │ │ - if (index != null || !point.equals(lastPoint)) { │ │ │ │ - added = OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, arguments) │ │ │ │ - } │ │ │ │ - var firstPoint = this.components[0]; │ │ │ │ - OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, [firstPoint]); │ │ │ │ - return added │ │ │ │ - }, │ │ │ │ - removeComponent: function(point) { │ │ │ │ - var removed = this.components && this.components.length > 3; │ │ │ │ - if (removed) { │ │ │ │ - this.components.pop(); │ │ │ │ - OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, arguments); │ │ │ │ - var firstPoint = this.components[0]; │ │ │ │ - OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, [firstPoint]) │ │ │ │ - } │ │ │ │ - return removed │ │ │ │ - }, │ │ │ │ - move: function(x, y) { │ │ │ │ - for (var i = 0, len = this.components.length; i < len - 1; i++) { │ │ │ │ - this.components[i].move(x, y) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - rotate: function(angle, origin) { │ │ │ │ - for (var i = 0, len = this.components.length; i < len - 1; ++i) { │ │ │ │ - this.components[i].rotate(angle, origin) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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; │ │ │ │ - var sumY = 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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getArea: function() { │ │ │ │ - var area = 0; │ │ │ │ - if (this.components && this.components.length > 2) { │ │ │ │ - var sum = 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 │ │ │ │ - } │ │ │ │ - return area │ │ │ │ - }, │ │ │ │ - getGeodesicArea: function(projection) { │ │ │ │ - var ring = this; │ │ │ │ - if (projection) { │ │ │ │ - var gg = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ - if (!gg.equals(projection)) { │ │ │ │ - ring = this.clone().transform(projection, gg) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var area = 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 * 6378137 / 2 │ │ │ │ - } │ │ │ │ - return area │ │ │ │ - }, │ │ │ │ - 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); │ │ │ │ - if (y1 == y2) { │ │ │ │ - if (py == y1) { │ │ │ │ - if (x1 <= x2 && (px >= x1 && px <= x2) || x1 >= x2 && (px <= x1 && px >= x2)) { │ │ │ │ - crosses = -1; │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - continue │ │ │ │ - } │ │ │ │ - cx = approx(getX(py, x1, y1, x2, y2), digs); │ │ │ │ - if (cx == px) { │ │ │ │ - if (y1 < y2 && (py >= y1 && py <= y2) || y1 > y2 && (py <= y1 && py >= y2)) { │ │ │ │ - crosses = -1; │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (cx <= px) { │ │ │ │ - continue │ │ │ │ - } │ │ │ │ - if (x1 != x2 && (cx < Math.min(x1, x2) || cx > Math.max(x1, x2))) { │ │ │ │ - continue │ │ │ │ - } │ │ │ │ - if (y1 < y2 && (py >= y1 && py < y2) || y1 > y2 && (py < y1 && py >= y2)) { │ │ │ │ - ++crosses │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var contained = crosses == -1 ? 1 : !!(crosses & 1); │ │ │ │ - return contained │ │ │ │ - }, │ │ │ │ - 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 { │ │ │ │ - for (var i = 0, len = geometry.components.length; i < len; ++i) { │ │ │ │ - intersect = geometry.components[i].intersects(this); │ │ │ │ - if (intersect) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return intersect │ │ │ │ - }, │ │ │ │ - getVertices: function(nodes) { │ │ │ │ - return nodes === true ? [] : this.components.slice(0, this.components.length - 1) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Geometry.LinearRing" │ │ │ │ -}); │ │ │ │ -OpenLayers.Geometry.Polygon = OpenLayers.Class(OpenLayers.Geometry.Collection, { │ │ │ │ - componentTypes: ["OpenLayers.Geometry.LinearRing"], │ │ │ │ - getArea: function() { │ │ │ │ - var area = 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 │ │ │ │ - }, │ │ │ │ - getGeodesicArea: function(projection) { │ │ │ │ - var area = 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 │ │ │ │ - }, │ │ │ │ - containsPoint: function(point) { │ │ │ │ - var numRings = this.components.length; │ │ │ │ - var contained = false; │ │ │ │ - if (numRings > 0) { │ │ │ │ - contained = this.components[0].containsPoint(point); │ │ │ │ - if (contained !== 1) { │ │ │ │ - if (contained && numRings > 1) { │ │ │ │ - var hole; │ │ │ │ - for (var i = 1; i < numRings; ++i) { │ │ │ │ - hole = this.components[i].containsPoint(point); │ │ │ │ - if (hole) { │ │ │ │ - if (hole === 1) { │ │ │ │ - contained = 1 │ │ │ │ - } else { │ │ │ │ - contained = false │ │ │ │ - } │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return contained │ │ │ │ - }, │ │ │ │ - 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") { │ │ │ │ - for (i = 0, len = this.components.length; i < len; ++i) { │ │ │ │ - intersect = geometry.intersects(this.components[i]); │ │ │ │ - if (intersect) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (!intersect) { │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (!intersect && geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - distanceTo: function(geometry, options) { │ │ │ │ - var edge = !(options && options.edge === false); │ │ │ │ - var result; │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -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 = OpenLayers.Class(OpenLayers.Geometry.Collection, { │ │ │ │ - componentTypes: ["OpenLayers.Geometry.Polygon"], │ │ │ │ - CLASS_NAME: "OpenLayers.Geometry.MultiPolygon" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.GeoJSON = OpenLayers.Class(OpenLayers.Format.JSON, { │ │ │ │ - ignoreExtraDims: false, │ │ │ │ - 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": │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - OpenLayers.Console.error("Unsupported geometry type: " + obj.type) │ │ │ │ - } else { │ │ │ │ - valid = true │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "FeatureCollection": │ │ │ │ - valid = true; │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - if (obj.type == type) { │ │ │ │ - valid = true │ │ │ │ - } else { │ │ │ │ - OpenLayers.Console.error("Cannot convert types from " + obj.type + " to " + type) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return valid │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - throw err │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.internalProjection && this.externalProjection && !collection) { │ │ │ │ - geometry.transform(this.externalProjection, this.internalProjection) │ │ │ │ - } │ │ │ │ - return geometry │ │ │ │ - }, │ │ │ │ - parseCoords: { │ │ │ │ - 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]) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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])])]) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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]) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - extract: { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - point: function(point) { │ │ │ │ - return [point.x, point.y] │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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.Date = { │ │ │ │ - dateRegEx: /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:(?:T(\d{1,2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|(?:[+-]\d{1,2}(?::(\d{2}))?)))|Z)?$/, │ │ │ │ - toISOString: function() { │ │ │ │ - if ("toISOString" in Date.prototype) { │ │ │ │ - return function(date) { │ │ │ │ - return date.toISOString() │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - return function(date) { │ │ │ │ - var str; │ │ │ │ - if (isNaN(date.getTime())) { │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }(), │ │ │ │ - parse: function(str) { │ │ │ │ - var date; │ │ │ │ - var match = str.match(this.dateRegEx); │ │ │ │ - if (match && (match[1] || match[7])) { │ │ │ │ - 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)); │ │ │ │ - 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(1e3 * (secFrac - seconds)); │ │ │ │ - date.setUTCHours(hours, minutes, seconds, milliseconds); │ │ │ │ - if (type !== "Z") { │ │ │ │ - var hoursOffset = parseInt(type, 10); │ │ │ │ - var minutesOffset = parseInt(match[8], 10) || 0; │ │ │ │ - var offset = -1e3 * (60 * (hoursOffset * 60) + minutesOffset * 60); │ │ │ │ - date = new Date(date.getTime() + offset) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - date = new Date("invalid") │ │ │ │ - } │ │ │ │ - return date │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ - namespaces: null, │ │ │ │ - namespaceAlias: null, │ │ │ │ - defaultPrefix: null, │ │ │ │ - readers: {}, │ │ │ │ - writers: {}, │ │ │ │ - xmldom: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - if (window.ActiveXObject) { │ │ │ │ - this.xmldom = new ActiveXObject("Microsoft.XMLDOM") │ │ │ │ - } │ │ │ │ - OpenLayers.Format.prototype.initialize.apply(this, [options]); │ │ │ │ - this.namespaces = OpenLayers.Util.extend({}, this.namespaces); │ │ │ │ - this.namespaceAlias = {}; │ │ │ │ - for (var alias in this.namespaces) { │ │ │ │ - this.namespaceAlias[this.namespaces[alias]] = alias │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.xmldom = null; │ │ │ │ - OpenLayers.Format.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - setNamespace: function(alias, uri) { │ │ │ │ - this.namespaces[alias] = uri; │ │ │ │ - this.namespaceAlias[uri] = alias │ │ │ │ - }, │ │ │ │ - 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; │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - write: function(node) { │ │ │ │ - var data; │ │ │ │ - if (this.xmldom) { │ │ │ │ - data = node.xml │ │ │ │ - } else { │ │ │ │ - var serializer = new XMLSerializer; │ │ │ │ - if (node.nodeType == 1) { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - createDocumentFragment: function() { │ │ │ │ - var element; │ │ │ │ - if (this.xmldom) { │ │ │ │ - element = this.xmldom.createDocumentFragment() │ │ │ │ - } else { │ │ │ │ - element = document.createDocumentFragment() │ │ │ │ - } │ │ │ │ - return element │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - getElementsByTagNameNS: function(node, uri, name) { │ │ │ │ - var elements = []; │ │ │ │ - if (node.getElementsByTagNameNS) { │ │ │ │ - elements = node.getElementsByTagNameNS(uri, name) │ │ │ │ - } else { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - getChildValue: function(node, def) { │ │ │ │ - var value = def || ""; │ │ │ │ - if (node) { │ │ │ │ - for (var child = node.firstChild; child; child = child.nextSibling) { │ │ │ │ - switch (child.nodeType) { │ │ │ │ - case 3: │ │ │ │ - case 4: │ │ │ │ - value += child.nodeValue │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return value │ │ │ │ - }, │ │ │ │ - isSimpleContent: function(node) { │ │ │ │ - var simple = true; │ │ │ │ - for (var child = node.firstChild; child; child = child.nextSibling) { │ │ │ │ - if (child.nodeType === 1) { │ │ │ │ - simple = false; │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return simple │ │ │ │ - }, │ │ │ │ - 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: │ │ │ │ - complex = true; │ │ │ │ - break; │ │ │ │ - case 8: │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - createElementNSPlus: function(name, options) { │ │ │ │ - options = options || {}; │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - setAttributes: function(node, obj) { │ │ │ │ - var value, uri; │ │ │ │ - for (var name in obj) { │ │ │ │ - if (obj[name] != null && obj[name].toString) { │ │ │ │ - value = obj[name].toString(); │ │ │ │ - uri = this.namespaces[name.substring(0, name.indexOf(":"))] || null; │ │ │ │ - this.setAttributeNS(node, uri, name, value) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - getChildEl: function(node, name, uri) { │ │ │ │ - return node && this.getThisOrNextEl(node.firstChild, name, uri) │ │ │ │ - }, │ │ │ │ - getNextEl: function(node, name, uri) { │ │ │ │ - return node && this.getThisOrNextEl(node.nextSibling, name, uri) │ │ │ │ - }, │ │ │ │ - getThisOrNextEl: function(node, name, uri) { │ │ │ │ - outer: for (var sibling = node; sibling; sibling = sibling.nextSibling) { │ │ │ │ - switch (sibling.nodeType) { │ │ │ │ - case 1: │ │ │ │ - if ((!name || name === (sibling.localName || sibling.nodeName.split(":").pop())) && (!uri || uri === sibling.namespaceURI)) { │ │ │ │ - break outer │ │ │ │ - } │ │ │ │ - sibling = null; │ │ │ │ - break outer; │ │ │ │ - case 3: │ │ │ │ - if (/^\s*$/.test(sibling.nodeValue)) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ - case 4: │ │ │ │ - case 6: │ │ │ │ - case 12: │ │ │ │ - case 10: │ │ │ │ - case 11: │ │ │ │ - sibling = null; │ │ │ │ - break outer │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return sibling || null │ │ │ │ - }, │ │ │ │ - lookupNamespaceURI: function(node, prefix) { │ │ │ │ - var uri = null; │ │ │ │ - if (node) { │ │ │ │ - if (node.lookupNamespaceURI) { │ │ │ │ - uri = node.lookupNamespaceURI(prefix) │ │ │ │ - } else { │ │ │ │ - outer: switch (node.nodeType) { │ │ │ │ - case 1: │ │ │ │ - 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: │ │ │ │ - uri = this.lookupNamespaceURI(node.ownerElement, prefix); │ │ │ │ - break outer; │ │ │ │ - case 9: │ │ │ │ - uri = this.lookupNamespaceURI(node.documentElement, prefix); │ │ │ │ - break outer; │ │ │ │ - case 6: │ │ │ │ - case 12: │ │ │ │ - case 10: │ │ │ │ - case 11: │ │ │ │ - break outer; │ │ │ │ - default: │ │ │ │ - uri = this.lookupNamespaceURI(node.parentNode, prefix); │ │ │ │ - break outer │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return uri │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ -}; │ │ │ │ -OpenLayers.Format.XML.lookupNamespaceURI = OpenLayers.Function.bind(OpenLayers.Format.XML.prototype.lookupNamespaceURI, OpenLayers.Format.XML.prototype); │ │ │ │ -OpenLayers.Format.XML.document = null; │ │ │ │ -OpenLayers.ProxyHost = ""; │ │ │ │ -if (!OpenLayers.Request) { │ │ │ │ - OpenLayers.Request = {} │ │ │ │ -} │ │ │ │ -OpenLayers.Util.extend(OpenLayers.Request, { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - URL_SPLIT_REGEX: /([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/, │ │ │ │ - events: new OpenLayers.Events(this), │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - issue: function(config) { │ │ │ │ - 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); │ │ │ │ - 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) { │ │ │ │ - config.headers["X-Requested-With"] = "XMLHttpRequest" │ │ │ │ + if (customRequestedWithHeader === false) { │ │ │ │ + config.headers["X-Requested-With"] = "XMLHttpRequest" │ │ │ │ } │ │ │ │ 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]) │ │ │ │ @@ -13594,1436 +10777,14 @@ │ │ │ │ } │ │ │ │ } │ │ │ │ if (!OpenLayers.Request) { │ │ │ │ OpenLayers.Request = {} │ │ │ │ } │ │ │ │ OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest │ │ │ │ })(); │ │ │ │ -OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - namespaces: { │ │ │ │ - kml: "http://www.opengis.net/kml/2.2", │ │ │ │ - gx: "http://www.google.com/kml/ext/2.2" │ │ │ │ - }, │ │ │ │ - kmlns: "http://earth.google.com/kml/2.0", │ │ │ │ - placemarksDesc: "No description available", │ │ │ │ - foldersName: "OpenLayers export", │ │ │ │ - foldersDesc: "Exported on " + new Date, │ │ │ │ - extractAttributes: true, │ │ │ │ - kvpAttributes: false, │ │ │ │ - extractStyles: false, │ │ │ │ - extractTracks: false, │ │ │ │ - trackAttributes: null, │ │ │ │ - internalns: null, │ │ │ │ - features: null, │ │ │ │ - styles: null, │ │ │ │ - styleBaseUrl: "", │ │ │ │ - fetched: null, │ │ │ │ - maxDepth: 0, │ │ │ │ - initialize: function(options) { │ │ │ │ - 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 │ │ │ │ - }; │ │ │ │ - this.externalProjection = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - read: function(data) { │ │ │ │ - this.features = []; │ │ │ │ - this.styles = {}; │ │ │ │ - this.fetched = {}; │ │ │ │ - var options = { │ │ │ │ - depth: 0, │ │ │ │ - styleBaseUrl: this.styleBaseUrl │ │ │ │ - }; │ │ │ │ - return this.parseData(data, options) │ │ │ │ - }, │ │ │ │ - parseData: function(data, options) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ - } │ │ │ │ - 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); │ │ │ │ - if (nodes.length == 0) { │ │ │ │ - continue │ │ │ │ - } │ │ │ │ - switch (type.toLowerCase()) { │ │ │ │ - case "link": │ │ │ │ - case "networklink": │ │ │ │ - this.parseLinks(nodes, options); │ │ │ │ - break; │ │ │ │ - case "style": │ │ │ │ - if (this.extractStyles) { │ │ │ │ - this.parseStyles(nodes, options) │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "stylemap": │ │ │ │ - if (this.extractStyles) { │ │ │ │ - this.parseStyleMaps(nodes, options) │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "placemark": │ │ │ │ - this.parseFeatures(nodes, options); │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return this.features │ │ │ │ - }, │ │ │ │ - parseLinks: function(nodes, options) { │ │ │ │ - if (options.depth >= this.maxDepth) { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - 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; │ │ │ │ - var data = this.fetchLink(href); │ │ │ │ - if (data) { │ │ │ │ - this.parseData(data, newOptions) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - fetchLink: function(href) { │ │ │ │ - var request = OpenLayers.Request.GET({ │ │ │ │ - url: href, │ │ │ │ - async: false │ │ │ │ - }); │ │ │ │ - if (request) { │ │ │ │ - return request.responseText │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - var fill = this.parseProperty(styleTypeNode, "*", "fill"); │ │ │ │ - if (fill == "0") { │ │ │ │ - style["fillColor"] = "none" │ │ │ │ - } │ │ │ │ - var outline = this.parseProperty(styleTypeNode, "*", "outline"); │ │ │ │ - if (outline == "0") { │ │ │ │ - style["strokeWidth"] = "0" │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "iconstyle": │ │ │ │ - var scale = parseFloat(this.parseProperty(styleTypeNode, "*", "scale") || 1); │ │ │ │ - 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"); │ │ │ │ - var google = "http://maps.google.com/mapfiles/kml"; │ │ │ │ - if (OpenLayers.String.startsWith(href, google) && !w && !h) { │ │ │ │ - w = 64; │ │ │ │ - h = 64; │ │ │ │ - scale = scale / 2 │ │ │ │ - } │ │ │ │ - w = w || h; │ │ │ │ - h = h || w; │ │ │ │ - if (w) { │ │ │ │ - width = parseInt(w) * scale │ │ │ │ - } │ │ │ │ - if (h) { │ │ │ │ - height = parseInt(h) * scale │ │ │ │ - } │ │ │ │ - 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; │ │ │ │ - style["externalGraphic"] = href │ │ │ │ - } │ │ │ │ - } │ │ │ │ - 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: │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (!style["strokeColor"] && style["fillColor"]) { │ │ │ │ - style["strokeColor"] = style["fillColor"] │ │ │ │ - } │ │ │ │ - var id = node.getAttribute("id"); │ │ │ │ - if (id && style) { │ │ │ │ - style.id = id │ │ │ │ - } │ │ │ │ - return style │ │ │ │ - }, │ │ │ │ - parseStyleMaps: function(nodes, options) { │ │ │ │ - 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]; │ │ │ │ - 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] │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - if (this.extractStyles && feature.attributes && feature.attributes.styleUrl) { │ │ │ │ - feature.style = this.getStyle(feature.attributes.styleUrl, options) │ │ │ │ - } │ │ │ │ - if (this.extractStyles) { │ │ │ │ - var inlineStyleNode = this.getElementsByTagNameNS(featureNode, "*", "Style")[0]; │ │ │ │ - if (inlineStyleNode) { │ │ │ │ - var inlineStyle = this.parseStyle(inlineStyleNode); │ │ │ │ - if (inlineStyle) { │ │ │ │ - feature.style = OpenLayers.Util.extend(feature.style, inlineStyle) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - 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 { │ │ │ │ - features.push(feature) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - throw "Bad Placemark: " + i │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.features = this.features.concat(features) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - parseFeature: function(node) { │ │ │ │ - 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) { │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - getStyle: function(styleUrl, options) { │ │ │ │ - var styleBaseUrl = OpenLayers.Util.removeTail(styleUrl); │ │ │ │ - var newOptions = OpenLayers.Util.extend({}, options); │ │ │ │ - newOptions.depth++; │ │ │ │ - newOptions.styleBaseUrl = styleBaseUrl; │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var style = OpenLayers.Util.extend({}, this.styles[styleUrl]); │ │ │ │ - return style │ │ │ │ - }, │ │ │ │ - parseGeometry: { │ │ │ │ - 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) { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - polygon: function(node) { │ │ │ │ - var nodeList = this.getElementsByTagNameNS(node, this.internalns, "LinearRing"); │ │ │ │ - var numRings = nodeList.length; │ │ │ │ - var components = new Array(numRings); │ │ │ │ - if (numRings > 0) { │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - parseAttributes: function(node) { │ │ │ │ - var attributes = {}; │ │ │ │ - var edNodes = node.getElementsByTagName("ExtendedData"); │ │ │ │ - if (edNodes.length) { │ │ │ │ - attributes = this.parseExtendedData(edNodes[0]) │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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]) │ │ │ │ - }, │ │ │ │ - createFolderXML: function() { │ │ │ │ - var folder = this.createElementNS(this.kmlns, "Folder"); │ │ │ │ - if (this.foldersName) { │ │ │ │ - var folderName = this.createElementNS(this.kmlns, "name"); │ │ │ │ - var folderNameText = this.createTextNode(this.foldersName); │ │ │ │ - folderName.appendChild(folderNameText); │ │ │ │ - folder.appendChild(folderName) │ │ │ │ - } │ │ │ │ - if (this.foldersDesc) { │ │ │ │ - var folderDesc = this.createElementNS(this.kmlns, "description"); │ │ │ │ - var folderDescText = this.createTextNode(this.foldersDesc); │ │ │ │ - folderDesc.appendChild(folderDescText); │ │ │ │ - folder.appendChild(folderDesc) │ │ │ │ - } │ │ │ │ - return folder │ │ │ │ - }, │ │ │ │ - createPlacemarkXML: function(feature) { │ │ │ │ - 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)); │ │ │ │ - var placemarkDesc = this.createElementNS(this.kmlns, "description"); │ │ │ │ - var desc = feature.attributes.description || this.placemarksDesc; │ │ │ │ - placemarkDesc.appendChild(this.createTextNode(desc)); │ │ │ │ - var placemarkNode = this.createElementNS(this.kmlns, "Placemark"); │ │ │ │ - if (feature.fid != null) { │ │ │ │ - placemarkNode.setAttribute("id", feature.fid) │ │ │ │ - } │ │ │ │ - placemarkNode.appendChild(placemarkName); │ │ │ │ - placemarkNode.appendChild(placemarkDesc); │ │ │ │ - var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ - placemarkNode.appendChild(geometryNode); │ │ │ │ - if (feature.attributes) { │ │ │ │ - var edNode = this.buildExtendedData(feature.attributes); │ │ │ │ - if (edNode) { │ │ │ │ - placemarkNode.appendChild(edNode) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return placemarkNode │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - buildGeometry: { │ │ │ │ - point: function(geometry) { │ │ │ │ - var kml = this.createElementNS(this.kmlns, "Point"); │ │ │ │ - kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ - return kml │ │ │ │ - }, │ │ │ │ - multipoint: function(geometry) { │ │ │ │ - return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ - }, │ │ │ │ - linestring: function(geometry) { │ │ │ │ - var kml = this.createElementNS(this.kmlns, "LineString"); │ │ │ │ - kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ - return kml │ │ │ │ - }, │ │ │ │ - multilinestring: function(geometry) { │ │ │ │ - return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ - }, │ │ │ │ - linearring: function(geometry) { │ │ │ │ - var kml = this.createElementNS(this.kmlns, "LinearRing"); │ │ │ │ - kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ - return kml │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - multipolygon: function(geometry) { │ │ │ │ - return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - buildCoordinatesNode: function(geometry) { │ │ │ │ - var coordinatesNode = this.createElementNS(this.kmlns, "coordinates"); │ │ │ │ - var path; │ │ │ │ - var points = geometry.components; │ │ │ │ - if (points) { │ │ │ │ - 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 { │ │ │ │ - path = this.buildCoordinates(geometry) │ │ │ │ - } │ │ │ │ - var txtNode = this.createTextNode(path); │ │ │ │ - coordinatesNode.appendChild(txtNode); │ │ │ │ - return coordinatesNode │ │ │ │ - }, │ │ │ │ - buildCoordinates: function(point) { │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - point = point.clone(); │ │ │ │ - point.transform(this.internalProjection, this.externalProjection) │ │ │ │ - } │ │ │ │ - return point.x + "," + point.y │ │ │ │ - }, │ │ │ │ - buildExtendedData: function(attributes) { │ │ │ │ - var extendedData = this.createElementNS(this.kmlns, "ExtendedData"); │ │ │ │ - for (var attributeName in attributes) { │ │ │ │ - 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") { │ │ │ │ - if (attributes[attributeName].value) { │ │ │ │ - value.appendChild(this.createTextNode(attributes[attributeName].value)) │ │ │ │ - } │ │ │ │ - if (attributes[attributeName].displayName) { │ │ │ │ - var displayName = this.createElementNS(this.kmlns, "displayName"); │ │ │ │ - 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.Handler.Point = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - point: null, │ │ │ │ - layer: null, │ │ │ │ - multi: false, │ │ │ │ - citeCompliant: false, │ │ │ │ - mouseDown: false, │ │ │ │ - stoppedDown: null, │ │ │ │ - lastDown: null, │ │ │ │ - lastUp: null, │ │ │ │ - persist: false, │ │ │ │ - stopDown: false, │ │ │ │ - stopUp: false, │ │ │ │ - layerOptions: null, │ │ │ │ - pixelTolerance: 5, │ │ │ │ - lastTouchPx: null, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (!OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - var options = OpenLayers.Util.extend({ │ │ │ │ - displayInLayerSwitcher: false, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (!OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - this.cancel(); │ │ │ │ - if (this.layer.map != null) { │ │ │ │ - this.destroyFeature(true); │ │ │ │ - this.layer.destroy(false) │ │ │ │ - } │ │ │ │ - this.layer = null; │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - destroyFeature: function(force) { │ │ │ │ - if (this.layer && (force || !this.persist)) { │ │ │ │ - this.layer.destroyFeatures() │ │ │ │ - } │ │ │ │ - this.point = null │ │ │ │ - }, │ │ │ │ - destroyPersistedFeature: function() { │ │ │ │ - var layer = this.layer; │ │ │ │ - if (layer && layer.features.length > 1) { │ │ │ │ - this.layer.features[0].destroy() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - cancel: function() { │ │ │ │ - this.finalize(true) │ │ │ │ - }, │ │ │ │ - click: function(evt) { │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - dblclick: function(evt) { │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - }, │ │ │ │ - drawFeature: function() { │ │ │ │ - this.layer.drawFeature(this.point, this.style) │ │ │ │ - }, │ │ │ │ - getGeometry: function() { │ │ │ │ - var geometry = this.point && this.point.geometry; │ │ │ │ - if (geometry && this.multi) { │ │ │ │ - geometry = new OpenLayers.Geometry.MultiPoint([geometry]) │ │ │ │ - } │ │ │ │ - return geometry │ │ │ │ - }, │ │ │ │ - geometryClone: function() { │ │ │ │ - var geom = this.getGeometry(); │ │ │ │ - return geom && geom.clone() │ │ │ │ - }, │ │ │ │ - mousedown: function(evt) { │ │ │ │ - return this.down(evt) │ │ │ │ - }, │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - this.lastTouchPx = evt.xy; │ │ │ │ - return this.down(evt) │ │ │ │ - }, │ │ │ │ - mousemove: function(evt) { │ │ │ │ - return this.move(evt) │ │ │ │ - }, │ │ │ │ - touchmove: function(evt) { │ │ │ │ - this.lastTouchPx = evt.xy; │ │ │ │ - return this.move(evt) │ │ │ │ - }, │ │ │ │ - mouseup: function(evt) { │ │ │ │ - return this.up(evt) │ │ │ │ - }, │ │ │ │ - touchend: function(evt) { │ │ │ │ - evt.xy = this.lastTouchPx; │ │ │ │ - return this.up(evt) │ │ │ │ - }, │ │ │ │ - down: function(evt) { │ │ │ │ - this.mouseDown = true; │ │ │ │ - this.lastDown = evt.xy; │ │ │ │ - if (!this.touch) { │ │ │ │ - this.modifyFeature(evt.xy) │ │ │ │ - } │ │ │ │ - this.stoppedDown = this.stopDown; │ │ │ │ - return !this.stopDown │ │ │ │ - }, │ │ │ │ - move: function(evt) { │ │ │ │ - if (!this.touch && (!this.mouseDown || this.stoppedDown)) { │ │ │ │ - this.modifyFeature(evt.xy) │ │ │ │ - } │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - up: function(evt) { │ │ │ │ - this.mouseDown = false; │ │ │ │ - this.stoppedDown = this.stopDown; │ │ │ │ - if (!this.checkModifiers(evt)) { │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - mouseout: function(evt) { │ │ │ │ - if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ - this.stoppedDown = this.stopDown; │ │ │ │ - this.mouseDown = false │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 = OpenLayers.Class(OpenLayers.Handler.Point, { │ │ │ │ - line: null, │ │ │ │ - maxVertices: null, │ │ │ │ - doubleTouchTolerance: 20, │ │ │ │ - freehand: false, │ │ │ │ - freehandToggle: "shiftKey", │ │ │ │ - timerId: null, │ │ │ │ - redoStack: null, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - destroyFeature: function(force) { │ │ │ │ - OpenLayers.Handler.Point.prototype.destroyFeature.call(this, force); │ │ │ │ - this.line = null │ │ │ │ - }, │ │ │ │ - destroyPersistedFeature: function() { │ │ │ │ - var layer = this.layer; │ │ │ │ - if (layer && layer.features.length > 2) { │ │ │ │ - this.layer.features[0].destroy() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - removePoint: function() { │ │ │ │ - if (this.point) { │ │ │ │ - this.layer.removeFeatures([this.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 │ │ │ │ - }, │ │ │ │ - insertXY: function(x, y) { │ │ │ │ - this.line.geometry.addComponent(new OpenLayers.Geometry.Point(x, y), this.getCurrentPointIndex()); │ │ │ │ - this.drawFeature(); │ │ │ │ - delete this.redoStack │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - insertDirectionLength: function(direction, length) { │ │ │ │ - direction *= Math.PI / 180; │ │ │ │ - var dx = length * Math.cos(direction); │ │ │ │ - var dy = length * Math.sin(direction); │ │ │ │ - this.insertDeltaXY(dx, dy) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getCurrentPointIndex: function() { │ │ │ │ - return this.line.geometry.components.length - 1 │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - if (this.touch && index > 0) { │ │ │ │ - components = geometry.components; │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - redo: function() { │ │ │ │ - var target = this.redoStack && this.redoStack.pop(); │ │ │ │ - if (target) { │ │ │ │ - this.line.geometry.addComponent(target, this.getCurrentPointIndex()); │ │ │ │ - this.drawFeature() │ │ │ │ - } │ │ │ │ - return !!target │ │ │ │ - }, │ │ │ │ - freehandMode: function(evt) { │ │ │ │ - return this.freehandToggle && evt[this.freehandToggle] ? !this.freehand : this.freehand │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - }, │ │ │ │ - drawFeature: function() { │ │ │ │ - this.layer.drawFeature(this.line, this.style); │ │ │ │ - this.layer.drawFeature(this.point, this.style) │ │ │ │ - }, │ │ │ │ - getSketch: function() { │ │ │ │ - return this.line │ │ │ │ - }, │ │ │ │ - getGeometry: function() { │ │ │ │ - var geometry = this.line && this.line.geometry; │ │ │ │ - if (geometry && this.multi) { │ │ │ │ - geometry = new OpenLayers.Geometry.MultiLineString([geometry]) │ │ │ │ - } │ │ │ │ - return geometry │ │ │ │ - }, │ │ │ │ - touchstart: function(evt) { │ │ │ │ - if (this.timerId && this.passesTolerance(this.lastTouchPx, evt.xy, this.doubleTouchTolerance)) { │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - finishGeometry: function() { │ │ │ │ - var index = this.line.geometry.components.length - 1; │ │ │ │ - this.line.geometry.removeComponent(this.line.geometry.components[index]); │ │ │ │ - this.removePoint(); │ │ │ │ - this.finalize() │ │ │ │ - }, │ │ │ │ - dblclick: function(evt) { │ │ │ │ - if (!this.freehandMode(evt)) { │ │ │ │ - this.finishGeometry() │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Path" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.Polygon = OpenLayers.Class(OpenLayers.Handler.Path, { │ │ │ │ - holeModifier: null, │ │ │ │ - drawingHole: false, │ │ │ │ - polygon: null, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - 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; │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - getCurrentPointIndex: function() { │ │ │ │ - return this.line.geometry.components.length - 2 │ │ │ │ - }, │ │ │ │ - enforceTopology: function(event) { │ │ │ │ - var point = event.vertex; │ │ │ │ - var components = this.line.geometry.components; │ │ │ │ - if (!this.polygon.geometry.intersects(point)) { │ │ │ │ - var last = components[components.length - 3]; │ │ │ │ - point.x = last.x; │ │ │ │ - point.y = last.y │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - finishGeometry: function() { │ │ │ │ - var index = this.line.geometry.components.length - 2; │ │ │ │ - this.line.geometry.removeComponent(this.line.geometry.components[index]); │ │ │ │ - this.removePoint(); │ │ │ │ - this.finalize() │ │ │ │ - }, │ │ │ │ - finalizeInteriorRing: function() { │ │ │ │ - var ring = this.line.geometry; │ │ │ │ - var modified = ring.getArea() !== 0; │ │ │ │ - if (modified) { │ │ │ │ - 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) { │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - cancel: function() { │ │ │ │ - if (this.drawingHole) { │ │ │ │ - this.polygon.geometry.removeComponent(this.line.geometry); │ │ │ │ - this.restoreFeature(true) │ │ │ │ - } │ │ │ │ - return OpenLayers.Handler.Path.prototype.cancel.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - this.control.layer.events.triggerEvent("sketchcomplete", { │ │ │ │ - feature: this.polygon │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroyFeature: function(force) { │ │ │ │ - OpenLayers.Handler.Path.prototype.destroyFeature.call(this, force); │ │ │ │ - this.polygon = null │ │ │ │ - }, │ │ │ │ - drawFeature: function() { │ │ │ │ - this.layer.drawFeature(this.polygon, this.style); │ │ │ │ - this.layer.drawFeature(this.point, this.style) │ │ │ │ - }, │ │ │ │ - getSketch: function() { │ │ │ │ - return this.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.Protocol = OpenLayers.Class({ │ │ │ │ - format: null, │ │ │ │ - options: null, │ │ │ │ - autoDestroy: true, │ │ │ │ - defaultFilter: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - this.options = options │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.options = null; │ │ │ │ - this.format = null │ │ │ │ - }, │ │ │ │ - read: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.filter = this.mergeWithDefaultFilter(options.filter) │ │ │ │ - }, │ │ │ │ - create: function() {}, │ │ │ │ - update: function() {}, │ │ │ │ - delete: function() {}, │ │ │ │ - commit: function() {}, │ │ │ │ - abort: function(response) {}, │ │ │ │ - createCallback: function(method, response, options) { │ │ │ │ - return OpenLayers.Function.bind(function() { │ │ │ │ - method.apply(this, [response, options]) │ │ │ │ - }, this) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol" │ │ │ │ -}); │ │ │ │ -OpenLayers.Protocol.Response = OpenLayers.Class({ │ │ │ │ - code: null, │ │ │ │ - requestType: null, │ │ │ │ - last: true, │ │ │ │ - features: null, │ │ │ │ - data: null, │ │ │ │ - reqFeatures: null, │ │ │ │ - priv: null, │ │ │ │ - error: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options) │ │ │ │ - }, │ │ │ │ - success: function() { │ │ │ │ - return this.code > 0 │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.Response" │ │ │ │ -}); │ │ │ │ -OpenLayers.Protocol.Response.SUCCESS = 1; │ │ │ │ -OpenLayers.Protocol.Response.FAILURE = 0; │ │ │ │ -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) │ │ │ │ -}; │ │ │ │ -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)) │ │ │ │ -}; │ │ │ │ -OpenLayers.Protocol.WFS.DEFAULTS = { │ │ │ │ - version: "1.0.0" │ │ │ │ -}; │ │ │ │ OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ url: null, │ │ │ │ headers: null, │ │ │ │ params: null, │ │ │ │ callback: null, │ │ │ │ scope: null, │ │ │ │ readWithPOST: false, │ │ │ │ @@ -15245,14 +11006,42 @@ │ │ │ │ var opt = options[resp.requestType]; │ │ │ │ if (opt && opt.callback) { │ │ │ │ opt.callback.call(opt.scope, resp) │ │ │ │ } │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Protocol.HTTP" │ │ │ │ }); │ │ │ │ +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) │ │ │ │ +}; │ │ │ │ +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)) │ │ │ │ +}; │ │ │ │ +OpenLayers.Protocol.WFS.DEFAULTS = { │ │ │ │ + version: "1.0.0" │ │ │ │ +}; │ │ │ │ OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ version: null, │ │ │ │ srsName: "EPSG:4326", │ │ │ │ featureType: null, │ │ │ │ featureNS: null, │ │ │ │ geometryName: "the_geom", │ │ │ │ schema: null, │ │ │ │ @@ -15269,163 +11058,593 @@ │ │ │ │ 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) { │ │ │ │ - this.setGeometryName(null) │ │ │ │ + if (!options.geometryName && parseFloat(this.format.version) > 1) { │ │ │ │ + this.setGeometryName(null) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.options && !this.options.format) { │ │ │ │ + this.format.destroy() │ │ │ │ + } │ │ │ │ + this.format = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + setFeatureType: function(featureType) { │ │ │ │ + this.featureType = featureType; │ │ │ │ + this.format.featureType = featureType │ │ │ │ + }, │ │ │ │ + setGeometryName: function(geometryName) { │ │ │ │ + this.geometryName = geometryName; │ │ │ │ + this.format.geometryName = geometryName │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + 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 { │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ + response.error = result │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ + } │ │ │ │ + options.callback.call(options.scope, response) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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; │ │ │ │ + format.autoConfig = false; │ │ │ │ + if (!this.geometryName) { │ │ │ │ + this.setGeometryName(format.geometryName) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return result │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleCommit: function(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + var request = response.priv; │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + response.priv.abort() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.WFS.v1" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format = OpenLayers.Class({ │ │ │ │ + options: null, │ │ │ │ + externalProjection: null, │ │ │ │ + internalProjection: null, │ │ │ │ + data: null, │ │ │ │ + keepData: false, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + this.options = options │ │ │ │ + }, │ │ │ │ + destroy: function() {}, │ │ │ │ + read: function(data) { │ │ │ │ + throw new Error("Read not implemented.") │ │ │ │ + }, │ │ │ │ + write: function(object) { │ │ │ │ + throw new Error("Write not implemented.") │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ + namespaces: null, │ │ │ │ + namespaceAlias: null, │ │ │ │ + defaultPrefix: null, │ │ │ │ + readers: {}, │ │ │ │ + writers: {}, │ │ │ │ + xmldom: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + if (window.ActiveXObject) { │ │ │ │ + this.xmldom = new ActiveXObject("Microsoft.XMLDOM") │ │ │ │ + } │ │ │ │ + OpenLayers.Format.prototype.initialize.apply(this, [options]); │ │ │ │ + this.namespaces = OpenLayers.Util.extend({}, this.namespaces); │ │ │ │ + this.namespaceAlias = {}; │ │ │ │ + for (var alias in this.namespaces) { │ │ │ │ + this.namespaceAlias[this.namespaces[alias]] = alias │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.xmldom = null; │ │ │ │ + OpenLayers.Format.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + setNamespace: function(alias, uri) { │ │ │ │ + this.namespaces[alias] = uri; │ │ │ │ + this.namespaceAlias[uri] = alias │ │ │ │ + }, │ │ │ │ + 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; │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + write: function(node) { │ │ │ │ + var data; │ │ │ │ + if (this.xmldom) { │ │ │ │ + data = node.xml │ │ │ │ + } else { │ │ │ │ + var serializer = new XMLSerializer; │ │ │ │ + if (node.nodeType == 1) { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + createDocumentFragment: function() { │ │ │ │ + var element; │ │ │ │ + if (this.xmldom) { │ │ │ │ + element = this.xmldom.createDocumentFragment() │ │ │ │ + } else { │ │ │ │ + element = document.createDocumentFragment() │ │ │ │ + } │ │ │ │ + return element │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + getElementsByTagNameNS: function(node, uri, name) { │ │ │ │ + var elements = []; │ │ │ │ + if (node.getElementsByTagNameNS) { │ │ │ │ + elements = node.getElementsByTagNameNS(uri, name) │ │ │ │ + } else { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + getChildValue: function(node, def) { │ │ │ │ + var value = def || ""; │ │ │ │ + if (node) { │ │ │ │ + for (var child = node.firstChild; child; child = child.nextSibling) { │ │ │ │ + switch (child.nodeType) { │ │ │ │ + case 3: │ │ │ │ + case 4: │ │ │ │ + value += child.nodeValue │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return value │ │ │ │ + }, │ │ │ │ + isSimpleContent: function(node) { │ │ │ │ + var simple = true; │ │ │ │ + for (var child = node.firstChild; child; child = child.nextSibling) { │ │ │ │ + if (child.nodeType === 1) { │ │ │ │ + simple = false; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return simple │ │ │ │ + }, │ │ │ │ + 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: │ │ │ │ + complex = true; │ │ │ │ + break; │ │ │ │ + case 8: │ │ │ │ + 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 │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.options && !this.options.format) { │ │ │ │ - this.format.destroy() │ │ │ │ + hasAttributeNS: function(node, uri, name) { │ │ │ │ + var found = false; │ │ │ │ + if (node.hasAttributeNS) { │ │ │ │ + found = node.hasAttributeNS(uri, name) │ │ │ │ + } else { │ │ │ │ + found = !!this.getAttributeNodeNS(node, uri, name) │ │ │ │ } │ │ │ │ - this.format = null; │ │ │ │ - OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - setFeatureType: function(featureType) { │ │ │ │ - this.featureType = featureType; │ │ │ │ - this.format.featureType = featureType │ │ │ │ - }, │ │ │ │ - setGeometryName: function(geometryName) { │ │ │ │ - this.geometryName = geometryName; │ │ │ │ - this.format.geometryName = geometryName │ │ │ │ + return found │ │ │ │ }, │ │ │ │ - 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) { │ │ │ │ - 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 │ │ │ │ + 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 { │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ - response.error = result │ │ │ │ + node.setAttribute(name, value) │ │ │ │ } │ │ │ │ } else { │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ + throw "setAttributeNS not implemented" │ │ │ │ } │ │ │ │ - options.callback.call(options.scope, response) │ │ │ │ } │ │ │ │ }, │ │ │ │ - parseResponse: function(request, options) { │ │ │ │ - var doc = request.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = request.responseText │ │ │ │ + createElementNSPlus: function(name, options) { │ │ │ │ + options = options || {}; │ │ │ │ + var uri = options.uri || this.namespaces[options.prefix]; │ │ │ │ + if (!uri) { │ │ │ │ + var loc = name.indexOf(":"); │ │ │ │ + uri = this.namespaces[name.substring(0, loc)] │ │ │ │ } │ │ │ │ - if (!doc || doc.length <= 0) { │ │ │ │ - return null │ │ │ │ + if (!uri) { │ │ │ │ + uri = this.namespaces[this.defaultPrefix] │ │ │ │ } │ │ │ │ - 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; │ │ │ │ - format.autoConfig = false; │ │ │ │ - if (!this.geometryName) { │ │ │ │ - this.setGeometryName(format.geometryName) │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + setAttributes: function(node, obj) { │ │ │ │ + var value, uri; │ │ │ │ + for (var name in obj) { │ │ │ │ + if (obj[name] != null && obj[name].toString) { │ │ │ │ + value = obj[name].toString(); │ │ │ │ + uri = this.namespaces[name.substring(0, name.indexOf(":"))] || null; │ │ │ │ + this.setAttributeNS(node, uri, name, value) │ │ │ │ } │ │ │ │ } │ │ │ │ - return result │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + 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 │ │ │ │ }, │ │ │ │ - handleCommit: function(response, options) { │ │ │ │ - if (options.callback) { │ │ │ │ - var request = response.priv; │ │ │ │ - var data = request.responseXML; │ │ │ │ - if (!data || !data.documentElement) { │ │ │ │ - data = request.responseText │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - var obj = this.format.read(data) || {}; │ │ │ │ - response.insertIds = obj.insertIds || []; │ │ │ │ - if (obj.success) { │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ + } │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + 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 { │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ - response.error = obj │ │ │ │ + prefix = this.defaultPrefix │ │ │ │ } │ │ │ │ - options.callback.call(options.scope, response) │ │ │ │ + local = name │ │ │ │ + } │ │ │ │ + var child = this.writers[prefix][local].apply(this, [obj]); │ │ │ │ + if (parent) { │ │ │ │ + parent.appendChild(child) │ │ │ │ } │ │ │ │ + return child │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + getChildEl: function(node, name, uri) { │ │ │ │ + return node && this.getThisOrNextEl(node.firstChild, name, uri) │ │ │ │ + }, │ │ │ │ + getNextEl: function(node, name, uri) { │ │ │ │ + return node && this.getThisOrNextEl(node.nextSibling, name, uri) │ │ │ │ + }, │ │ │ │ + getThisOrNextEl: function(node, name, uri) { │ │ │ │ + outer: for (var sibling = node; sibling; sibling = sibling.nextSibling) { │ │ │ │ + switch (sibling.nodeType) { │ │ │ │ + case 1: │ │ │ │ + if ((!name || name === (sibling.localName || sibling.nodeName.split(":").pop())) && (!uri || uri === sibling.namespaceURI)) { │ │ │ │ + break outer │ │ │ │ + } │ │ │ │ + sibling = null; │ │ │ │ + break outer; │ │ │ │ + case 3: │ │ │ │ + if (/^\s*$/.test(sibling.nodeValue)) { │ │ │ │ + break │ │ │ │ + } │ │ │ │ + case 4: │ │ │ │ + case 6: │ │ │ │ + case 12: │ │ │ │ + case 10: │ │ │ │ + case 11: │ │ │ │ + sibling = null; │ │ │ │ + break outer │ │ │ │ } │ │ │ │ - }); │ │ │ │ - var deleteNode = this.format.createElementNSPlus("wfs:Delete", { │ │ │ │ - attributes: { │ │ │ │ - typeName: (options.featureNS ? this.featurePrefix + ":" : "") + options.featureType │ │ │ │ + } │ │ │ │ + return sibling || null │ │ │ │ + }, │ │ │ │ + lookupNamespaceURI: function(node, prefix) { │ │ │ │ + var uri = null; │ │ │ │ + if (node) { │ │ │ │ + if (node.lookupNamespaceURI) { │ │ │ │ + uri = node.lookupNamespaceURI(prefix) │ │ │ │ + } else { │ │ │ │ + outer: switch (node.nodeType) { │ │ │ │ + case 1: │ │ │ │ + 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: │ │ │ │ + uri = this.lookupNamespaceURI(node.ownerElement, prefix); │ │ │ │ + break outer; │ │ │ │ + case 9: │ │ │ │ + uri = this.lookupNamespaceURI(node.documentElement, prefix); │ │ │ │ + break outer; │ │ │ │ + case 6: │ │ │ │ + case 12: │ │ │ │ + case 10: │ │ │ │ + case 11: │ │ │ │ + break outer; │ │ │ │ + default: │ │ │ │ + uri = this.lookupNamespaceURI(node.parentNode, prefix); │ │ │ │ + break outer │ │ │ │ + } │ │ │ │ } │ │ │ │ - }); │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ + return uri │ │ │ │ }, │ │ │ │ - abort: function(response) { │ │ │ │ - if (response) { │ │ │ │ - response.priv.abort() │ │ │ │ + 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.Protocol.WFS.v1" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.XML" │ │ │ │ }); │ │ │ │ +OpenLayers.Format.XML.CONTENT_TYPE = { │ │ │ │ + EMPTY: 0, │ │ │ │ + SIMPLE: 1, │ │ │ │ + COMPLEX: 2, │ │ │ │ + MIXED: 3 │ │ │ │ +}; │ │ │ │ +OpenLayers.Format.XML.lookupNamespaceURI = OpenLayers.Function.bind(OpenLayers.Format.XML.prototype.lookupNamespaceURI, OpenLayers.Format.XML.prototype); │ │ │ │ +OpenLayers.Format.XML.document = null; │ │ │ │ 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) │ │ │ │ @@ -15785,14 +12004,145 @@ │ │ │ │ if (filter instanceof OpenLayers.Filter.Spatial && !filter.property) { │ │ │ │ filter.property = this.geometryName │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.WFST.v1" │ │ │ │ }); │ │ │ │ +OpenLayers.Geometry.MultiLineString = OpenLayers.Class(OpenLayers.Geometry.Collection, { │ │ │ │ + componentTypes: ["OpenLayers.Geometry.LineString"], │ │ │ │ + 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) { │ │ │ │ + splits.unshift(j, 1); │ │ │ │ + Array.prototype.splice.apply(targetParts, splits); │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (!sourceSplit) { │ │ │ │ + if (sourceParts.length) { │ │ │ │ + sourceParts[sourceParts.length - 1].addComponent(sourceLine.clone()) │ │ │ │ + } else { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + 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) { │ │ │ │ + if (targetParts.length) { │ │ │ │ + targetParts[targetParts.length - 1].addComponent(targetLine.clone()) │ │ │ │ + } else { │ │ │ │ + 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.Geometry.MultiPolygon = OpenLayers.Class(OpenLayers.Geometry.Collection, { │ │ │ │ + componentTypes: ["OpenLayers.Geometry.Polygon"], │ │ │ │ + CLASS_NAME: "OpenLayers.Geometry.MultiPolygon" │ │ │ │ +}); │ │ │ │ OpenLayers.Format.GML = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ featureNS: "http://mapserver.gis.umn.edu/mapserver", │ │ │ │ featurePrefix: "feature", │ │ │ │ featureName: "featureMember", │ │ │ │ layerName: "features", │ │ │ │ geometryName: "geometry", │ │ │ │ collectionName: "FeatureCollection", │ │ │ │ @@ -17068,14 +13418,62 @@ │ │ │ │ CLASS_NAME: "OpenLayers.Format.Filter" │ │ │ │ }); │ │ │ │ OpenLayers.Filter.Function = OpenLayers.Class(OpenLayers.Filter, { │ │ │ │ name: null, │ │ │ │ params: null, │ │ │ │ CLASS_NAME: "OpenLayers.Filter.Function" │ │ │ │ }); │ │ │ │ +OpenLayers.Date = { │ │ │ │ + dateRegEx: /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:(?:T(\d{1,2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|(?:[+-]\d{1,2}(?::(\d{2}))?)))|Z)?$/, │ │ │ │ + toISOString: function() { │ │ │ │ + if ("toISOString" in Date.prototype) { │ │ │ │ + return function(date) { │ │ │ │ + return date.toISOString() │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + return function(date) { │ │ │ │ + var str; │ │ │ │ + if (isNaN(date.getTime())) { │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }(), │ │ │ │ + parse: function(str) { │ │ │ │ + var date; │ │ │ │ + var match = str.match(this.dateRegEx); │ │ │ │ + if (match && (match[1] || match[7])) { │ │ │ │ + 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)); │ │ │ │ + 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(1e3 * (secFrac - seconds)); │ │ │ │ + date.setUTCHours(hours, minutes, seconds, milliseconds); │ │ │ │ + if (type !== "Z") { │ │ │ │ + var hoursOffset = parseInt(type, 10); │ │ │ │ + var minutesOffset = parseInt(match[8], 10) || 0; │ │ │ │ + var offset = -1e3 * (60 * (hoursOffset * 60) + minutesOffset * 60); │ │ │ │ + date = new Date(date.getTime() + offset) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + date = new Date("invalid") │ │ │ │ + } │ │ │ │ + return date │ │ │ │ + } │ │ │ │ +}; │ │ │ │ OpenLayers.Format.Filter.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ 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" │ │ │ │ }, │ │ │ │ @@ -17598,8 +13996,3610 @@ │ │ │ │ ogc: OpenLayers.Format.Filter.v1_0_0.prototype.writers["ogc"] │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.WFST.v1_0_0" │ │ │ │ }); │ │ │ │ OpenLayers.Protocol.WFS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ version: "1.0.0", │ │ │ │ CLASS_NAME: "OpenLayers.Protocol.WFS.v1_0_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control = OpenLayers.Class({ │ │ │ │ + id: null, │ │ │ │ + map: null, │ │ │ │ + div: null, │ │ │ │ + type: null, │ │ │ │ + allowSelection: false, │ │ │ │ + displayClass: "", │ │ │ │ + title: "", │ │ │ │ + autoActivate: false, │ │ │ │ + active: null, │ │ │ │ + handlerOptions: null, │ │ │ │ + handler: null, │ │ │ │ + eventListeners: null, │ │ │ │ + events: null, │ │ │ │ + initialize: function(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 + "_") │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.events) { │ │ │ │ + if (this.eventListeners) { │ │ │ │ + this.events.un(this.eventListeners) │ │ │ │ + } │ │ │ │ + this.events.destroy(); │ │ │ │ + this.events = null │ │ │ │ + } │ │ │ │ + this.eventListeners = null; │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + this.map = map; │ │ │ │ + if (this.handler) { │ │ │ │ + this.handler.setMap(map) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + moveTo: function(px) { │ │ │ │ + if (px != null && this.div != null) { │ │ │ │ + this.div.style.left = px.x + "px"; │ │ │ │ + this.div.style.top = px.y + "px" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.TYPE_BUTTON = 1; │ │ │ │ +OpenLayers.Control.TYPE_TOGGLE = 2; │ │ │ │ +OpenLayers.Control.TYPE_TOOL = 3; │ │ │ │ +OpenLayers.Events.buttonclick = OpenLayers.Class({ │ │ │ │ + target: null, │ │ │ │ + events: ["mousedown", "mouseup", "click", "dblclick", "touchstart", "touchmove", "touchend", "keydown"], │ │ │ │ + startRegEx: /^mousedown|touchstart$/, │ │ │ │ + cancelRegEx: /^touchmove$/, │ │ │ │ + completeRegEx: /^mouseup|touchend$/, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + for (var i = this.events.length - 1; i >= 0; --i) { │ │ │ │ + this.target.unregister(this.events[i], this, this.buttonClick) │ │ │ │ + } │ │ │ │ + delete this.target │ │ │ │ + }, │ │ │ │ + getPressedButton: function(element) { │ │ │ │ + var depth = 3, │ │ │ │ + button; │ │ │ │ + do { │ │ │ │ + if (OpenLayers.Element.hasClass(element, "olButton")) { │ │ │ │ + button = element; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + element = element.parentNode │ │ │ │ + } while (--depth > 0 && element); │ │ │ │ + return button │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + buttonClick: function(evt) { │ │ │ │ + var propagate = true, │ │ │ │ + element = OpenLayers.Event.element(evt); │ │ │ │ + if (element && (OpenLayers.Event.isLeftClick(evt) || !~evt.type.indexOf("mouse"))) { │ │ │ │ + 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.Panel = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + controls: null, │ │ │ │ + autoActivate: true, │ │ │ │ + defaultControl: null, │ │ │ │ + saveState: false, │ │ │ │ + allowDepress: false, │ │ │ │ + activeState: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.controls = []; │ │ │ │ + this.activeState = {} │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + this.addControlsToMap(controls); │ │ │ │ + this.redraw() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + createControlMarkup: function(control) { │ │ │ │ + return document.createElement("div") │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + iconOn: function() { │ │ │ │ + var d = this.panel_div; │ │ │ │ + var re = new RegExp("\\b(" + this.displayClass + "Item)Inactive\\b"); │ │ │ │ + d.className = d.className.replace(re, "$1Active") │ │ │ │ + }, │ │ │ │ + iconOff: function() { │ │ │ │ + var d = this.panel_div; │ │ │ │ + var re = new RegExp("\\b(" + this.displayClass + "Item)Active\\b"); │ │ │ │ + d.className = d.className.replace(re, "$1Inactive") │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + getControlsByName: function(match) { │ │ │ │ + return this.getControlsBy("name", match) │ │ │ │ + }, │ │ │ │ + getControlsByClass: function(match) { │ │ │ │ + return this.getControlsBy("CLASS_NAME", match) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Panel" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Geolocate = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + geolocation: null, │ │ │ │ + available: "geolocation" in navigator, │ │ │ │ + bind: true, │ │ │ │ + watch: false, │ │ │ │ + geolocationOptions: null, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (this.available && !this.geolocation) { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (this.active && this.watchId !== null) { │ │ │ │ + this.geolocation.clearWatch(this.watchId) │ │ │ │ + } │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + failure: function(error) { │ │ │ │ + this.events.triggerEvent("locationfailed", { │ │ │ │ + error: error │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Geolocate" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Zoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + zoomInText: "+", │ │ │ │ + zoomInId: "olZoomInLink", │ │ │ │ + zoomOutText: "−", │ │ │ │ + zoomOutId: "olZoomOutLink", │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + onZoomClick: function(evt) { │ │ │ │ + var button = evt.buttonElement; │ │ │ │ + if (button === this.zoomInLink) { │ │ │ │ + this.map.zoomIn() │ │ │ │ + } else if (button === this.zoomOutLink) { │ │ │ │ + this.map.zoomOut() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + started: false, │ │ │ │ + stopDown: true, │ │ │ │ + dragging: false, │ │ │ │ + last: null, │ │ │ │ + start: null, │ │ │ │ + lastMoveEvt: null, │ │ │ │ + oldOnselectstart: null, │ │ │ │ + interval: 0, │ │ │ │ + timeoutId: null, │ │ │ │ + documentDrag: false, │ │ │ │ + documentEvents: null, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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]); │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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); │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + down: function(evt) {}, │ │ │ │ + move: function(evt) {}, │ │ │ │ + up: function(evt) {}, │ │ │ │ + out: function(evt) {}, │ │ │ │ + mousedown: function(evt) { │ │ │ │ + return this.dragstart(evt) │ │ │ │ + }, │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + return this.dragstart(evt) │ │ │ │ + }, │ │ │ │ + mousemove: function(evt) { │ │ │ │ + return this.dragmove(evt) │ │ │ │ + }, │ │ │ │ + touchmove: function(evt) { │ │ │ │ + return this.dragmove(evt) │ │ │ │ + }, │ │ │ │ + removeTimeout: function() { │ │ │ │ + this.timeoutId = null; │ │ │ │ + if (this.dragging) { │ │ │ │ + this.mousemove(this.lastMoveEvt) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + mouseup: function(evt) { │ │ │ │ + return this.dragend(evt) │ │ │ │ + }, │ │ │ │ + touchend: function(evt) { │ │ │ │ + evt.xy = this.last; │ │ │ │ + return this.dragend(evt) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + click: function(evt) { │ │ │ │ + return this.start == this.last │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + var activated = false; │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.dragging = false; │ │ │ │ + activated = true │ │ │ │ + } │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + adjustXY: function(evt) { │ │ │ │ + var pos = OpenLayers.Util.pagePosition(this.map.viewPortDiv); │ │ │ │ + evt.xy.x -= pos[0]; │ │ │ │ + evt.xy.y -= pos[1] │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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.Control.DragPan = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ + panned: false, │ │ │ │ + interval: 0, │ │ │ │ + documentDrag: false, │ │ │ │ + kinetic: null, │ │ │ │ + enableKinetic: true, │ │ │ │ + kineticInterval: 10, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + panMapStart: function() { │ │ │ │ + if (this.kinetic) { │ │ │ │ + this.kinetic.begin() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + 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.Handler.Pinch = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + started: false, │ │ │ │ + stopDown: false, │ │ │ │ + pinching: false, │ │ │ │ + last: null, │ │ │ │ + start: null, │ │ │ │ + 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) { │ │ │ │ + return false │ │ │ │ + } else { │ │ │ │ + this.started = false; │ │ │ │ + this.start = null; │ │ │ │ + this.last = null │ │ │ │ + } │ │ │ │ + OpenLayers.Event.preventDefault(evt); │ │ │ │ + return 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; │ │ │ │ + OpenLayers.Event.stop(evt) │ │ │ │ + } else if (this.started) { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + var activated = false; │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.pinching = false; │ │ │ │ + activated = true │ │ │ │ + } │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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)) │ │ │ │ + }, │ │ │ │ + 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.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ + pinchOrigin: null, │ │ │ │ + currentCenter: null, │ │ │ │ + autoActivate: true, │ │ │ │ + preserveCenter: false, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + pinchStart: function(evt, pinchData) { │ │ │ │ + var xy = this.preserveCenter ? this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; │ │ │ │ + this.pinchOrigin = xy; │ │ │ │ + this.currentCenter = xy │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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); │ │ │ │ + this.map.div.clientWidth = this.map.div.clientWidth; │ │ │ │ + this.map.setCenter(location, zoom) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.PinchZoom" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + delay: 300, │ │ │ │ + single: true, │ │ │ │ + double: false, │ │ │ │ + pixelTolerance: 0, │ │ │ │ + dblclickTolerance: 13, │ │ │ │ + stopSingle: false, │ │ │ │ + stopDouble: false, │ │ │ │ + timerId: null, │ │ │ │ + down: null, │ │ │ │ + last: null, │ │ │ │ + first: null, │ │ │ │ + rightclickTimerId: null, │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + this.down = this.getEventInfo(evt); │ │ │ │ + this.last = this.getEventInfo(evt); │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + touchmove: function(evt) { │ │ │ │ + this.last = this.getEventInfo(evt); │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + touchend: function(evt) { │ │ │ │ + if (this.down) { │ │ │ │ + evt.xy = this.last.xy; │ │ │ │ + evt.lastTouches = this.last.touches; │ │ │ │ + this.handleSingle(evt); │ │ │ │ + this.down = null │ │ │ │ + } │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + mousedown: function(evt) { │ │ │ │ + this.down = this.getEventInfo(evt); │ │ │ │ + this.last = this.getEventInfo(evt); │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + mouseup: function(evt) { │ │ │ │ + var propagate = true; │ │ │ │ + if (this.checkModifiers(evt) && this.control.handleRightClicks && OpenLayers.Event.isRightClick(evt)) { │ │ │ │ + propagate = this.rightclick(evt) │ │ │ │ + } │ │ │ │ + return propagate │ │ │ │ + }, │ │ │ │ + rightclick: function(evt) { │ │ │ │ + if (this.passesTolerance(evt)) { │ │ │ │ + if (this.rightclickTimerId != null) { │ │ │ │ + this.clearTimer(); │ │ │ │ + this.callback("dblrightclick", [evt]); │ │ │ │ + return !this.stopDouble │ │ │ │ + } else { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + delayedRightCall: function(evt) { │ │ │ │ + this.rightclickTimerId = null; │ │ │ │ + if (evt) { │ │ │ │ + this.callback("rightclick", [evt]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + click: function(evt) { │ │ │ │ + if (!this.last) { │ │ │ │ + this.last = this.getEventInfo(evt) │ │ │ │ + } │ │ │ │ + this.handleSingle(evt); │ │ │ │ + return !this.stopSingle │ │ │ │ + }, │ │ │ │ + dblclick: function(evt) { │ │ │ │ + this.handleDouble(evt); │ │ │ │ + return !this.stopDouble │ │ │ │ + }, │ │ │ │ + handleDouble: function(evt) { │ │ │ │ + if (this.passesDblclickTolerance(evt)) { │ │ │ │ + if (this["double"]) { │ │ │ │ + this.callback("dblclick", [evt]) │ │ │ │ + } │ │ │ │ + this.clearTimer() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + handleSingle: function(evt) { │ │ │ │ + if (this.passesTolerance(evt)) { │ │ │ │ + if (this.timerId != null) { │ │ │ │ + if (this.last.touches && this.last.touches.length === 1) { │ │ │ │ + if (this["double"]) { │ │ │ │ + OpenLayers.Event.preventDefault(evt) │ │ │ │ + } │ │ │ │ + this.handleDouble(evt) │ │ │ │ + } │ │ │ │ + if (!this.last.touches || this.last.touches.length !== 2) { │ │ │ │ + this.clearTimer() │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.first = this.getEventInfo(evt); │ │ │ │ + var clickEvent = this.single ? OpenLayers.Util.extend({}, evt) : null; │ │ │ │ + this.queuePotentialClick(clickEvent) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + queuePotentialClick: function(evt) { │ │ │ │ + this.timerId = window.setTimeout(OpenLayers.Function.bind(this.delayedCall, this, evt), this.delay) │ │ │ │ + }, │ │ │ │ + passesTolerance: function(evt) { │ │ │ │ + var passes = true; │ │ │ │ + if (this.pixelTolerance != null && this.down && this.down.xy) { │ │ │ │ + passes = this.pixelTolerance >= this.down.xy.distanceTo(evt.xy); │ │ │ │ + if (passes && this.touch && this.down.touches.length === this.last.touches.length) { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + getTouchDistance: function(from, to) { │ │ │ │ + return Math.sqrt(Math.pow(from.clientX - to.clientX, 2) + Math.pow(from.clientY - to.clientY, 2)) │ │ │ │ + }, │ │ │ │ + passesDblclickTolerance: function(evt) { │ │ │ │ + var passes = true; │ │ │ │ + if (this.down && this.first) { │ │ │ │ + passes = this.down.xy.distanceTo(this.first.xy) <= this.dblclickTolerance │ │ │ │ + } │ │ │ │ + return passes │ │ │ │ + }, │ │ │ │ + clearTimer: function() { │ │ │ │ + if (this.timerId != null) { │ │ │ │ + window.clearTimeout(this.timerId); │ │ │ │ + this.timerId = null │ │ │ │ + } │ │ │ │ + if (this.rightclickTimerId != null) { │ │ │ │ + window.clearTimeout(this.rightclickTimerId); │ │ │ │ + this.rightclickTimerId = null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + delayedCall: function(evt) { │ │ │ │ + this.timerId = null; │ │ │ │ + if (evt) { │ │ │ │ + this.callback("click", [evt]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + dragPan: null, │ │ │ │ + dragPanOptions: null, │ │ │ │ + pinchZoom: null, │ │ │ │ + pinchZoomOptions: null, │ │ │ │ + clickHandlerOptions: null, │ │ │ │ + documentDrag: false, │ │ │ │ + autoActivate: true, │ │ │ │ + initialize: function(options) { │ │ │ │ + this.handlers = {}; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.dragPan.activate(); │ │ │ │ + this.handlers.click.activate(); │ │ │ │ + this.pinchZoom.activate(); │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + this.dragPan.deactivate(); │ │ │ │ + this.handlers.click.deactivate(); │ │ │ │ + this.pinchZoom.deactivate(); │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + 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)) │ │ │ │ + }, │ │ │ │ + defaultClick: function(evt) { │ │ │ │ + if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ + this.map.zoomOut() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + defaultDblClick: function(evt) { │ │ │ │ + this.map.zoomTo(this.map.zoom + 1, evt.xy) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.TouchNavigation" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + 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" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + feature: null, │ │ │ │ + lastFeature: null, │ │ │ │ + down: null, │ │ │ │ + up: null, │ │ │ │ + clickTolerance: 4, │ │ │ │ + geometryTypes: null, │ │ │ │ + stopClick: true, │ │ │ │ + stopDown: true, │ │ │ │ + stopUp: false, │ │ │ │ + initialize: function(control, layer, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ + this.layer = layer │ │ │ │ + }, │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + return OpenLayers.Event.isMultiTouch(evt) ? true : this.mousedown(evt) │ │ │ │ + }, │ │ │ │ + touchmove: function(evt) { │ │ │ │ + OpenLayers.Event.preventDefault(evt) │ │ │ │ + }, │ │ │ │ + mousedown: function(evt) { │ │ │ │ + if (OpenLayers.Event.isLeftClick(evt) || OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ + this.down = evt.xy │ │ │ │ + } │ │ │ │ + return this.handle(evt) ? !this.stopDown : true │ │ │ │ + }, │ │ │ │ + mouseup: function(evt) { │ │ │ │ + this.up = evt.xy; │ │ │ │ + return this.handle(evt) ? !this.stopUp : true │ │ │ │ + }, │ │ │ │ + click: function(evt) { │ │ │ │ + return this.handle(evt) ? !this.stopClick : true │ │ │ │ + }, │ │ │ │ + mousemove: function(evt) { │ │ │ │ + if (!this.callbacks["over"] && !this.callbacks["out"]) { │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + this.handle(evt); │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + dblclick: function(evt) { │ │ │ │ + return !this.handle(evt) │ │ │ │ + }, │ │ │ │ + geometryTypeMatches: function(feature) { │ │ │ │ + return this.geometryTypes == null || OpenLayers.Util.indexOf(this.geometryTypes, feature.geometry.CLASS_NAME) > -1 │ │ │ │ + }, │ │ │ │ + handle: function(evt) { │ │ │ │ + if (this.feature && !this.feature.layer) { │ │ │ │ + this.feature = null │ │ │ │ + } │ │ │ │ + var type = evt.type; │ │ │ │ + var handled = false; │ │ │ │ + var previouslyIn = !!this.feature; │ │ │ │ + var click = type == "click" || type == "dblclick" || type == "touchstart"; │ │ │ │ + this.feature = this.layer.getFeatureFromEvent(evt); │ │ │ │ + if (this.feature && !this.feature.layer) { │ │ │ │ + this.feature = null │ │ │ │ + } │ │ │ │ + if (this.lastFeature && !this.lastFeature.layer) { │ │ │ │ + this.lastFeature = null │ │ │ │ + } │ │ │ │ + if (this.feature) { │ │ │ │ + if (type === "touchstart") { │ │ │ │ + OpenLayers.Event.preventDefault(evt) │ │ │ │ + } │ │ │ │ + var inNew = this.feature != this.lastFeature; │ │ │ │ + if (this.geometryTypeMatches(this.feature)) { │ │ │ │ + if (previouslyIn && inNew) { │ │ │ │ + if (this.lastFeature) { │ │ │ │ + this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ + } │ │ │ │ + this.triggerCallback(type, "in", [this.feature]) │ │ │ │ + } else if (!previouslyIn || click) { │ │ │ │ + this.triggerCallback(type, "in", [this.feature]) │ │ │ │ + } │ │ │ │ + this.lastFeature = this.feature; │ │ │ │ + handled = true │ │ │ │ + } else { │ │ │ │ + if (this.lastFeature && (previouslyIn && inNew || click)) { │ │ │ │ + this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ + } │ │ │ │ + this.feature = null │ │ │ │ + } │ │ │ │ + } else if (this.lastFeature && (previouslyIn || click)) { │ │ │ │ + this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ + } │ │ │ │ + return handled │ │ │ │ + }, │ │ │ │ + triggerCallback: function(type, mode, args) { │ │ │ │ + var key = this.EVENTMAP[type][mode]; │ │ │ │ + if (key) { │ │ │ │ + if (type == "click" && this.up && this.down) { │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + this.up = this.down = null │ │ │ │ + } else { │ │ │ │ + this.callback(key, args) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleMapEvents: function(evt) { │ │ │ │ + if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ + this.moveLayerToTop() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + moveLayerToTop: function() { │ │ │ │ + var index = Math.max(this.map.Z_INDEX_BASE["Feature"] - 1, this.layer.getZIndex()) + 1; │ │ │ │ + this.layer.setZIndex(index) │ │ │ │ + }, │ │ │ │ + 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.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ + displayInLayerSwitcher: false, │ │ │ │ + layers: null, │ │ │ │ + display: function() {}, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ + this.collectRoots(); │ │ │ │ + map.events.register("changelayer", this, this.handleChangeLayer) │ │ │ │ + }, │ │ │ │ + removeMap: function(map) { │ │ │ │ + map.events.unregister("changelayer", this, this.handleChangeLayer); │ │ │ │ + this.resetRoots(); │ │ │ │ + OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + collectRoots: function() { │ │ │ │ + var layer; │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + multipleKey: null, │ │ │ │ + toggleKey: null, │ │ │ │ + multiple: false, │ │ │ │ + clickout: true, │ │ │ │ + toggle: false, │ │ │ │ + hover: false, │ │ │ │ + highlightOnly: false, │ │ │ │ + box: false, │ │ │ │ + onBeforeSelect: function() {}, │ │ │ │ + onSelect: function() {}, │ │ │ │ + onUnselect: function() {}, │ │ │ │ + scope: null, │ │ │ │ + geometryTypes: null, │ │ │ │ + layer: null, │ │ │ │ + layers: null, │ │ │ │ + callbacks: null, │ │ │ │ + selectStyle: null, │ │ │ │ + renderIntent: "select", │ │ │ │ + handlers: null, │ │ │ │ + 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" │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + unselectAll: function(options) { │ │ │ │ + var layers = this.layers || [this.layer], │ │ │ │ + layer, feature, l, numExcept; │ │ │ │ + for (l = 0; l < layers.length; ++l) { │ │ │ │ + layer = layers[l]; │ │ │ │ + numExcept = 0; │ │ │ │ + if (layer.selectedFeatures != null) { │ │ │ │ + while (layer.selectedFeatures.length > numExcept) { │ │ │ │ + feature = layer.selectedFeatures[numExcept]; │ │ │ │ + if (!options || options.except != feature) { │ │ │ │ + this.unselect(feature) │ │ │ │ + } else { │ │ │ │ + ++numExcept │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + multipleSelect: function() { │ │ │ │ + return this.multiple || this.handlers.feature.evt && this.handlers.feature.evt[this.multipleKey] │ │ │ │ + }, │ │ │ │ + toggleSelect: function() { │ │ │ │ + return this.toggle || this.handlers.feature.evt && this.handlers.feature.evt[this.toggleKey] │ │ │ │ + }, │ │ │ │ + clickoutFeature: function(feature) { │ │ │ │ + if (!this.hover && this.clickout) { │ │ │ │ + this.unselectAll() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + outFeature: function(feature) { │ │ │ │ + if (this.hover) { │ │ │ │ + if (this.highlightOnly) { │ │ │ │ + if (feature._lastHighlighter == this.id) { │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + unhighlight: function(feature) { │ │ │ │ + var layer = feature.layer; │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + 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 (!this.handlers.feature.lastFeature) { │ │ │ │ + this.handlers.feature.lastFeature = layer.selectedFeatures[0] │ │ │ │ + } │ │ │ │ + layer.events.triggerEvent("featureselected", { │ │ │ │ + feature: feature │ │ │ │ + }); │ │ │ │ + this.onSelect.call(this.scope, feature) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + unselect: function(feature) { │ │ │ │ + var layer = feature.layer; │ │ │ │ + this.unhighlight(feature); │ │ │ │ + OpenLayers.Util.removeItem(layer.selectedFeatures, feature); │ │ │ │ + layer.events.triggerEvent("featureunselected", { │ │ │ │ + feature: feature │ │ │ │ + }); │ │ │ │ + this.onUnselect.call(this.scope, feature) │ │ │ │ + }, │ │ │ │ + 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 (!this.multipleSelect()) { │ │ │ │ + this.unselectAll() │ │ │ │ + } │ │ │ │ + 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]; │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + this.handlers.feature.setMap(map); │ │ │ │ + if (this.box) { │ │ │ │ + this.handlers.box.setMap(map) │ │ │ │ + } │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + 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.Control.Attribution = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + separator: ", ", │ │ │ │ + template: "${layers}", │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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()) { │ │ │ │ + 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.Handler.Keyboard = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + KEY_EVENTS: ["keydown", "keyup"], │ │ │ │ + eventListener: null, │ │ │ │ + observeElement: null, │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ + this.eventListener = OpenLayers.Function.bindAsEventListener(this.handleKeyEvent, this) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + this.eventListener = null; │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleKeyEvent: function(evt) { │ │ │ │ + if (this.checkModifiers(evt)) { │ │ │ │ + this.callback(evt.type, [evt]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Keyboard" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + documentDrag: false, │ │ │ │ + geometryTypes: null, │ │ │ │ + clickout: true, │ │ │ │ + toggle: true, │ │ │ │ + standalone: false, │ │ │ │ + layer: null, │ │ │ │ + feature: null, │ │ │ │ + vertex: null, │ │ │ │ + vertices: null, │ │ │ │ + virtualVertices: null, │ │ │ │ + handlers: null, │ │ │ │ + deleteCodes: null, │ │ │ │ + virtualStyle: null, │ │ │ │ + vertexRenderIntent: null, │ │ │ │ + mode: null, │ │ │ │ + createVertices: true, │ │ │ │ + modified: false, │ │ │ │ + radiusHandle: null, │ │ │ │ + dragHandle: null, │ │ │ │ + onModificationStart: function() {}, │ │ │ │ + onModification: function() {}, │ │ │ │ + onModificationEnd: function() {}, │ │ │ │ + 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 = .3; │ │ │ │ + this.virtualStyle.strokeOpacity = .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] │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + }; │ │ │ │ + var keyboardOptions = { │ │ │ │ + keydown: this.handleKeypress │ │ │ │ + }; │ │ │ │ + this.handlers = { │ │ │ │ + keyboard: new OpenLayers.Handler.Keyboard(this, keyboardOptions), │ │ │ │ + drag: new OpenLayers.Handler.Drag(this, dragCallbacks, dragOptions) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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, []) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = false; │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + beforeSelectFeature: function(feature) { │ │ │ │ + return this.layer.events.triggerEvent("beforefeaturemodified", { │ │ │ │ + feature: 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) │ │ │ │ + } │ │ │ │ + var modified = feature.modified; │ │ │ │ + if (feature.geometry && !(modified && modified.geometry)) { │ │ │ │ + this._originalGeometry = feature.geometry.clone() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + this._unselect = feature │ │ │ │ + } │ │ │ │ + this.selectFeature(feature) │ │ │ │ + } │ │ │ │ + if (feature._sketch || isPoint) { │ │ │ │ + this.vertex = feature; │ │ │ │ + this.handlers.drag.stopDown = true │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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; │ │ │ │ + if (this.feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { │ │ │ │ + this.layer.events.triggerEvent("vertexmodified", { │ │ │ │ + vertex: vertex.geometry, │ │ │ │ + feature: this.feature, │ │ │ │ + pixel: pixel │ │ │ │ + }) │ │ │ │ + } else { │ │ │ │ + if (vertex._index) { │ │ │ │ + vertex.geometry.parent.addComponent(vertex.geometry, vertex._index); │ │ │ │ + delete vertex._index; │ │ │ │ + OpenLayers.Util.removeItem(this.virtualVertices, vertex); │ │ │ │ + this.vertices.push(vertex) │ │ │ │ + } else if (vertex == this.dragHandle) { │ │ │ │ + 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) { │ │ │ │ + this.layer.events.triggerEvent("vertexmodified", { │ │ │ │ + vertex: vertex.geometry, │ │ │ │ + feature: this.feature, │ │ │ │ + pixel: pixel │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + if (this.virtualVertices.length > 0) { │ │ │ │ + this.layer.destroyFeatures(this.virtualVertices, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + this.virtualVertices = [] │ │ │ │ + } │ │ │ │ + this.layer.drawFeature(this.feature, this.standalone ? undefined : "select") │ │ │ │ + } │ │ │ │ + this.layer.drawFeature(vertex) │ │ │ │ + }, │ │ │ │ + dragComplete: function(vertex) { │ │ │ │ + this.resetVertices(); │ │ │ │ + this.setFeatureState(); │ │ │ │ + this.onModification(this.feature); │ │ │ │ + this.layer.events.triggerEvent("featuremodified", { │ │ │ │ + feature: this.feature │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + if (!(this.mode & OpenLayers.Control.ModifyFeature.RESIZE)) { │ │ │ │ + this.collectVertices() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + handleKeypress: function(evt) { │ │ │ │ + var code = evt.keyCode; │ │ │ │ + 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) { │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + 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); │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + 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; │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + this.handlers.drag.setMap(map); │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + handleMapEvents: function(evt) { │ │ │ │ + if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ + this.moveLayerToTop() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + moveLayerToTop: function() { │ │ │ │ + var index = Math.max(this.map.Z_INDEX_BASE["Feature"] - 1, this.layer.getZIndex()) + 1; │ │ │ │ + this.layer.setZIndex(index) │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.ModifyFeature.RESHAPE = 1; │ │ │ │ +OpenLayers.Control.ModifyFeature.RESIZE = 2; │ │ │ │ +OpenLayers.Control.ModifyFeature.ROTATE = 4; │ │ │ │ +OpenLayers.Control.ModifyFeature.DRAG = 8; │ │ │ │ +OpenLayers.Control.DrawFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + layer: null, │ │ │ │ + callbacks: null, │ │ │ │ + multi: false, │ │ │ │ + featureAdded: function() {}, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + insertXY: function(x, y) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertXY(x, y) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + insertDeltaXY: function(dx, dy) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertDeltaXY(dx, dy) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + insertDirectionLength: function(direction, length) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertDirectionLength(direction, length) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + insertDeflectionLength: function(deflection, length) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertDeflectionLength(deflection, length) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + undo: function() { │ │ │ │ + return this.handler.undo && this.handler.undo() │ │ │ │ + }, │ │ │ │ + redo: function() { │ │ │ │ + return this.handler.redo && this.handler.redo() │ │ │ │ + }, │ │ │ │ + finishSketch: function() { │ │ │ │ + this.handler.finishGeometry() │ │ │ │ + }, │ │ │ │ + cancel: function() { │ │ │ │ + this.handler.cancel() │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.DrawFeature" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.JSON = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ + indent: " ", │ │ │ │ + space: " ", │ │ │ │ + newline: "\n", │ │ │ │ + level: 0, │ │ │ │ + pretty: false, │ │ │ │ + nativeJSON: function() { │ │ │ │ + return !!(window.JSON && typeof JSON.parse == "function" && typeof JSON.stringify == "function") │ │ │ │ + }(), │ │ │ │ + read: function(json, filter) { │ │ │ │ + var object; │ │ │ │ + if (this.nativeJSON) { │ │ │ │ + object = JSON.parse(json, filter) │ │ │ │ + } else try { │ │ │ │ + if (/^[\],:{}\s]*$/.test(json.replace(/\\["\\\/bfnrtu]/g, "@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]").replace(/(?:^|:|,)(?:\s*\[)+/g, ""))) { │ │ │ │ + object = eval("(" + json + ")"); │ │ │ │ + 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) {} │ │ │ │ + if (this.keepData) { │ │ │ │ + this.data = object │ │ │ │ + } │ │ │ │ + return object │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + writeIndent: function() { │ │ │ │ + var pieces = []; │ │ │ │ + if (this.pretty) { │ │ │ │ + for (var i = 0; i < this.level; ++i) { │ │ │ │ + pieces.push(this.indent) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return pieces.join("") │ │ │ │ + }, │ │ │ │ + writeNewline: function() { │ │ │ │ + return this.pretty ? this.newline : "" │ │ │ │ + }, │ │ │ │ + writeSpace: function() { │ │ │ │ + return this.pretty ? this.space : "" │ │ │ │ + }, │ │ │ │ + serialize: { │ │ │ │ + object: function(object) { │ │ │ │ + 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)) { │ │ │ │ + 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("") │ │ │ │ + }, │ │ │ │ + array: function(array) { │ │ │ │ + var json; │ │ │ │ + var pieces = ["["]; │ │ │ │ + this.level += 1; │ │ │ │ + for (var i = 0, len = array.length; i < len; ++i) { │ │ │ │ + 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("") │ │ │ │ + }, │ │ │ │ + string: function(string) { │ │ │ │ + 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 + '"' │ │ │ │ + }, │ │ │ │ + number: function(number) { │ │ │ │ + return isFinite(number) ? String(number) : "null" │ │ │ │ + }, │ │ │ │ + boolean: function(bool) { │ │ │ │ + return String(bool) │ │ │ │ + }, │ │ │ │ + date: function(date) { │ │ │ │ + function format(number) { │ │ │ │ + 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 = OpenLayers.Class(OpenLayers.Format.JSON, { │ │ │ │ + ignoreExtraDims: false, │ │ │ │ + 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": │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + OpenLayers.Console.error("Unsupported geometry type: " + obj.type) │ │ │ │ + } else { │ │ │ │ + valid = true │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case "FeatureCollection": │ │ │ │ + valid = true; │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + if (obj.type == type) { │ │ │ │ + valid = true │ │ │ │ + } else { │ │ │ │ + OpenLayers.Console.error("Cannot convert types from " + obj.type + " to " + type) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return valid │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + throw err │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.internalProjection && this.externalProjection && !collection) { │ │ │ │ + geometry.transform(this.externalProjection, this.internalProjection) │ │ │ │ + } │ │ │ │ + return geometry │ │ │ │ + }, │ │ │ │ + parseCoords: { │ │ │ │ + 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]) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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])])]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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]) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + extract: { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + point: function(point) { │ │ │ │ + return [point.x, point.y] │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + namespaces: { │ │ │ │ + kml: "http://www.opengis.net/kml/2.2", │ │ │ │ + gx: "http://www.google.com/kml/ext/2.2" │ │ │ │ + }, │ │ │ │ + kmlns: "http://earth.google.com/kml/2.0", │ │ │ │ + placemarksDesc: "No description available", │ │ │ │ + foldersName: "OpenLayers export", │ │ │ │ + foldersDesc: "Exported on " + new Date, │ │ │ │ + extractAttributes: true, │ │ │ │ + kvpAttributes: false, │ │ │ │ + extractStyles: false, │ │ │ │ + extractTracks: false, │ │ │ │ + trackAttributes: null, │ │ │ │ + internalns: null, │ │ │ │ + features: null, │ │ │ │ + styles: null, │ │ │ │ + styleBaseUrl: "", │ │ │ │ + fetched: null, │ │ │ │ + maxDepth: 0, │ │ │ │ + initialize: function(options) { │ │ │ │ + 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 │ │ │ │ + }; │ │ │ │ + this.externalProjection = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + read: function(data) { │ │ │ │ + this.features = []; │ │ │ │ + this.styles = {}; │ │ │ │ + this.fetched = {}; │ │ │ │ + var options = { │ │ │ │ + depth: 0, │ │ │ │ + styleBaseUrl: this.styleBaseUrl │ │ │ │ + }; │ │ │ │ + return this.parseData(data, options) │ │ │ │ + }, │ │ │ │ + parseData: function(data, options) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ + } │ │ │ │ + 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); │ │ │ │ + if (nodes.length == 0) { │ │ │ │ + continue │ │ │ │ + } │ │ │ │ + switch (type.toLowerCase()) { │ │ │ │ + case "link": │ │ │ │ + case "networklink": │ │ │ │ + this.parseLinks(nodes, options); │ │ │ │ + break; │ │ │ │ + case "style": │ │ │ │ + if (this.extractStyles) { │ │ │ │ + this.parseStyles(nodes, options) │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case "stylemap": │ │ │ │ + if (this.extractStyles) { │ │ │ │ + this.parseStyleMaps(nodes, options) │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case "placemark": │ │ │ │ + this.parseFeatures(nodes, options); │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return this.features │ │ │ │ + }, │ │ │ │ + parseLinks: function(nodes, options) { │ │ │ │ + if (options.depth >= this.maxDepth) { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + 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; │ │ │ │ + var data = this.fetchLink(href); │ │ │ │ + if (data) { │ │ │ │ + this.parseData(data, newOptions) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + fetchLink: function(href) { │ │ │ │ + var request = OpenLayers.Request.GET({ │ │ │ │ + url: href, │ │ │ │ + async: false │ │ │ │ + }); │ │ │ │ + if (request) { │ │ │ │ + return request.responseText │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + var fill = this.parseProperty(styleTypeNode, "*", "fill"); │ │ │ │ + if (fill == "0") { │ │ │ │ + style["fillColor"] = "none" │ │ │ │ + } │ │ │ │ + var outline = this.parseProperty(styleTypeNode, "*", "outline"); │ │ │ │ + if (outline == "0") { │ │ │ │ + style["strokeWidth"] = "0" │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case "iconstyle": │ │ │ │ + var scale = parseFloat(this.parseProperty(styleTypeNode, "*", "scale") || 1); │ │ │ │ + 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"); │ │ │ │ + var google = "http://maps.google.com/mapfiles/kml"; │ │ │ │ + if (OpenLayers.String.startsWith(href, google) && !w && !h) { │ │ │ │ + w = 64; │ │ │ │ + h = 64; │ │ │ │ + scale = scale / 2 │ │ │ │ + } │ │ │ │ + w = w || h; │ │ │ │ + h = h || w; │ │ │ │ + if (w) { │ │ │ │ + width = parseInt(w) * scale │ │ │ │ + } │ │ │ │ + if (h) { │ │ │ │ + height = parseInt(h) * scale │ │ │ │ + } │ │ │ │ + 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; │ │ │ │ + style["externalGraphic"] = href │ │ │ │ + } │ │ │ │ + } │ │ │ │ + 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: │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (!style["strokeColor"] && style["fillColor"]) { │ │ │ │ + style["strokeColor"] = style["fillColor"] │ │ │ │ + } │ │ │ │ + var id = node.getAttribute("id"); │ │ │ │ + if (id && style) { │ │ │ │ + style.id = id │ │ │ │ + } │ │ │ │ + return style │ │ │ │ + }, │ │ │ │ + parseStyleMaps: function(nodes, options) { │ │ │ │ + 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]; │ │ │ │ + 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] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + if (this.extractStyles && feature.attributes && feature.attributes.styleUrl) { │ │ │ │ + feature.style = this.getStyle(feature.attributes.styleUrl, options) │ │ │ │ + } │ │ │ │ + if (this.extractStyles) { │ │ │ │ + var inlineStyleNode = this.getElementsByTagNameNS(featureNode, "*", "Style")[0]; │ │ │ │ + if (inlineStyleNode) { │ │ │ │ + var inlineStyle = this.parseStyle(inlineStyleNode); │ │ │ │ + if (inlineStyle) { │ │ │ │ + feature.style = OpenLayers.Util.extend(feature.style, inlineStyle) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + 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 { │ │ │ │ + features.push(feature) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + throw "Bad Placemark: " + i │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.features = this.features.concat(features) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + parseFeature: function(node) { │ │ │ │ + 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) { │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + getStyle: function(styleUrl, options) { │ │ │ │ + var styleBaseUrl = OpenLayers.Util.removeTail(styleUrl); │ │ │ │ + var newOptions = OpenLayers.Util.extend({}, options); │ │ │ │ + newOptions.depth++; │ │ │ │ + newOptions.styleBaseUrl = styleBaseUrl; │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var style = OpenLayers.Util.extend({}, this.styles[styleUrl]); │ │ │ │ + return style │ │ │ │ + }, │ │ │ │ + parseGeometry: { │ │ │ │ + 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) { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + polygon: function(node) { │ │ │ │ + var nodeList = this.getElementsByTagNameNS(node, this.internalns, "LinearRing"); │ │ │ │ + var numRings = nodeList.length; │ │ │ │ + var components = new Array(numRings); │ │ │ │ + if (numRings > 0) { │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + parseAttributes: function(node) { │ │ │ │ + var attributes = {}; │ │ │ │ + var edNodes = node.getElementsByTagName("ExtendedData"); │ │ │ │ + if (edNodes.length) { │ │ │ │ + attributes = this.parseExtendedData(edNodes[0]) │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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]) │ │ │ │ + }, │ │ │ │ + createFolderXML: function() { │ │ │ │ + var folder = this.createElementNS(this.kmlns, "Folder"); │ │ │ │ + if (this.foldersName) { │ │ │ │ + var folderName = this.createElementNS(this.kmlns, "name"); │ │ │ │ + var folderNameText = this.createTextNode(this.foldersName); │ │ │ │ + folderName.appendChild(folderNameText); │ │ │ │ + folder.appendChild(folderName) │ │ │ │ + } │ │ │ │ + if (this.foldersDesc) { │ │ │ │ + var folderDesc = this.createElementNS(this.kmlns, "description"); │ │ │ │ + var folderDescText = this.createTextNode(this.foldersDesc); │ │ │ │ + folderDesc.appendChild(folderDescText); │ │ │ │ + folder.appendChild(folderDesc) │ │ │ │ + } │ │ │ │ + return folder │ │ │ │ + }, │ │ │ │ + createPlacemarkXML: function(feature) { │ │ │ │ + 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)); │ │ │ │ + var placemarkDesc = this.createElementNS(this.kmlns, "description"); │ │ │ │ + var desc = feature.attributes.description || this.placemarksDesc; │ │ │ │ + placemarkDesc.appendChild(this.createTextNode(desc)); │ │ │ │ + var placemarkNode = this.createElementNS(this.kmlns, "Placemark"); │ │ │ │ + if (feature.fid != null) { │ │ │ │ + placemarkNode.setAttribute("id", feature.fid) │ │ │ │ + } │ │ │ │ + placemarkNode.appendChild(placemarkName); │ │ │ │ + placemarkNode.appendChild(placemarkDesc); │ │ │ │ + var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ + placemarkNode.appendChild(geometryNode); │ │ │ │ + if (feature.attributes) { │ │ │ │ + var edNode = this.buildExtendedData(feature.attributes); │ │ │ │ + if (edNode) { │ │ │ │ + placemarkNode.appendChild(edNode) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return placemarkNode │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + buildGeometry: { │ │ │ │ + point: function(geometry) { │ │ │ │ + var kml = this.createElementNS(this.kmlns, "Point"); │ │ │ │ + kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ + return kml │ │ │ │ + }, │ │ │ │ + multipoint: function(geometry) { │ │ │ │ + return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ + }, │ │ │ │ + linestring: function(geometry) { │ │ │ │ + var kml = this.createElementNS(this.kmlns, "LineString"); │ │ │ │ + kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ + return kml │ │ │ │ + }, │ │ │ │ + multilinestring: function(geometry) { │ │ │ │ + return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ + }, │ │ │ │ + linearring: function(geometry) { │ │ │ │ + var kml = this.createElementNS(this.kmlns, "LinearRing"); │ │ │ │ + kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ + return kml │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + multipolygon: function(geometry) { │ │ │ │ + return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + buildCoordinatesNode: function(geometry) { │ │ │ │ + var coordinatesNode = this.createElementNS(this.kmlns, "coordinates"); │ │ │ │ + var path; │ │ │ │ + var points = geometry.components; │ │ │ │ + if (points) { │ │ │ │ + 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 { │ │ │ │ + path = this.buildCoordinates(geometry) │ │ │ │ + } │ │ │ │ + var txtNode = this.createTextNode(path); │ │ │ │ + coordinatesNode.appendChild(txtNode); │ │ │ │ + return coordinatesNode │ │ │ │ + }, │ │ │ │ + buildCoordinates: function(point) { │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + point = point.clone(); │ │ │ │ + point.transform(this.internalProjection, this.externalProjection) │ │ │ │ + } │ │ │ │ + return point.x + "," + point.y │ │ │ │ + }, │ │ │ │ + buildExtendedData: function(attributes) { │ │ │ │ + var extendedData = this.createElementNS(this.kmlns, "ExtendedData"); │ │ │ │ + for (var attributeName in attributes) { │ │ │ │ + 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") { │ │ │ │ + if (attributes[attributeName].value) { │ │ │ │ + value.appendChild(this.createTextNode(attributes[attributeName].value)) │ │ │ │ + } │ │ │ │ + if (attributes[attributeName].displayName) { │ │ │ │ + var displayName = this.createElementNS(this.kmlns, "displayName"); │ │ │ │ + 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" │ │ │ │ }); │ │ ├── ./usr/share/javascript/openlayers/OpenLayers.tests.js │ │ │ ├── js-beautify {} │ │ │ │ @@ -33176,15 +33176,15 @@ │ │ │ │ │ │ │ │ /** │ │ │ │ * Constant: CORNER_SIZE │ │ │ │ * {Integer} 5. Border space for the RICO corners. │ │ │ │ */ │ │ │ │ OpenLayers.Popup.AnchoredBubble.CORNER_SIZE = 5; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Rule.js │ │ │ │ + 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. */ │ │ │ │ │ │ │ │ @@ -33192,236 +33192,86 @@ │ │ │ │ /** │ │ │ │ * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ * @requires OpenLayers/Util.js │ │ │ │ * @requires OpenLayers/Style.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Rule │ │ │ │ - * This class represents an SLD Rule, as being used for rule-based SLD styling. │ │ │ │ + * Class: OpenLayers.Filter │ │ │ │ + * This class represents an OGC Filter. │ │ │ │ */ │ │ │ │ -OpenLayers.Rule = OpenLayers.Class({ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: id │ │ │ │ - * {String} A unique id for this session. │ │ │ │ - */ │ │ │ │ - id: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: name │ │ │ │ - * {String} name of this rule │ │ │ │ - */ │ │ │ │ - name: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: title │ │ │ │ - * {String} Title of this rule (set if included in SLD) │ │ │ │ - */ │ │ │ │ - title: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: description │ │ │ │ - * {String} Description of this rule (set if abstract is included in SLD) │ │ │ │ - */ │ │ │ │ - description: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: context │ │ │ │ - * {Object} An optional object with properties that the rule should be │ │ │ │ - * evaluated against. If no context is specified, feature.attributes will │ │ │ │ - * be used. │ │ │ │ - */ │ │ │ │ - context: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: filter │ │ │ │ - * {<OpenLayers.Filter>} Optional filter for the rule. │ │ │ │ - */ │ │ │ │ - filter: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: elseFilter │ │ │ │ - * {Boolean} Determines whether this rule is only to be applied only if │ │ │ │ - * no other rules match (ElseFilter according to the SLD specification). │ │ │ │ - * Default is false. For instances of OpenLayers.Rule, if elseFilter is │ │ │ │ - * false, the rule will always apply. For subclasses, the else property is │ │ │ │ - * ignored. │ │ │ │ - */ │ │ │ │ - elseFilter: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: symbolizer │ │ │ │ - * {Object} Symbolizer or hash of symbolizers for this rule. If hash of │ │ │ │ - * symbolizers, keys are one or more of ["Point", "Line", "Polygon"]. The │ │ │ │ - * latter if useful if it is required to style e.g. vertices of a line │ │ │ │ - * with a point symbolizer. Note, however, that this is not implemented │ │ │ │ - * yet in OpenLayers, but it is the way how symbolizers are defined in │ │ │ │ - * SLD. │ │ │ │ - */ │ │ │ │ - symbolizer: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: symbolizers │ │ │ │ - * {Array} Collection of symbolizers associated with this rule. If │ │ │ │ - * provided at construction, the symbolizers array has precedence │ │ │ │ - * over the deprecated symbolizer property. Note that multiple │ │ │ │ - * symbolizers are not currently supported by the vector renderers. │ │ │ │ - * Rules with multiple symbolizers are currently only useful for │ │ │ │ - * maintaining elements in an SLD document. │ │ │ │ - */ │ │ │ │ - symbolizers: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: minScaleDenominator │ │ │ │ - * {Number} or {String} minimum scale at which to draw the feature. │ │ │ │ - * In the case of a String, this can be a combination of text and │ │ │ │ - * propertyNames in the form "literal ${propertyName}" │ │ │ │ - */ │ │ │ │ - minScaleDenominator: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: maxScaleDenominator │ │ │ │ - * {Number} or {String} maximum scale at which to draw the feature. │ │ │ │ - * In the case of a String, this can be a combination of text and │ │ │ │ - * propertyNames in the form "literal ${propertyName}" │ │ │ │ - */ │ │ │ │ - maxScaleDenominator: null, │ │ │ │ +OpenLayers.Filter = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Rule │ │ │ │ - * Creates a Rule. │ │ │ │ + * Constructor: OpenLayers.Filter │ │ │ │ + * This class represents a generic filter. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object with properties to set on the │ │ │ │ - * rule │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Rule>} │ │ │ │ + * {<OpenLayers.Filter>} │ │ │ │ */ │ │ │ │ initialize: function(options) { │ │ │ │ - this.symbolizer = {}; │ │ │ │ OpenLayers.Util.extend(this, options); │ │ │ │ - if (this.symbolizers) { │ │ │ │ - delete this.symbolizer; │ │ │ │ - } │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: destroy │ │ │ │ - * nullify references to prevent circular references and memory leaks │ │ │ │ + * Remove reference to anything added. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - for (var i in this.symbolizer) { │ │ │ │ - this.symbolizer[i] = null; │ │ │ │ - } │ │ │ │ - this.symbolizer = null; │ │ │ │ - delete this.symbolizers; │ │ │ │ - }, │ │ │ │ + destroy: function() {}, │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: evaluate │ │ │ │ - * evaluates this rule for a specific feature │ │ │ │ + * Evaluates this filter in a specific context. Instances or subclasses │ │ │ │ + * are supposed to override this method. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature>} feature to apply the rule to. │ │ │ │ + * 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} true if the rule applies, false if it does not. │ │ │ │ - * This rule is the default rule and always returns true. │ │ │ │ + * {Boolean} The filter applies. │ │ │ │ */ │ │ │ │ - evaluate: function(feature) { │ │ │ │ - var context = this.getContext(feature); │ │ │ │ - var applies = true; │ │ │ │ - │ │ │ │ - if (this.minScaleDenominator || this.maxScaleDenominator) { │ │ │ │ - var scale = feature.layer.map.getScale(); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // check if within minScale/maxScale bounds │ │ │ │ - if (this.minScaleDenominator) { │ │ │ │ - applies = scale >= OpenLayers.Style.createLiteral( │ │ │ │ - this.minScaleDenominator, context); │ │ │ │ - } │ │ │ │ - if (applies && this.maxScaleDenominator) { │ │ │ │ - applies = scale < OpenLayers.Style.createLiteral( │ │ │ │ - this.maxScaleDenominator, context); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // check if optional filter applies │ │ │ │ - if (applies && this.filter) { │ │ │ │ - // feature id filters get the feature, others get the context │ │ │ │ - if (this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") { │ │ │ │ - applies = this.filter.evaluate(feature); │ │ │ │ - } else { │ │ │ │ - applies = this.filter.evaluate(context); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return applies; │ │ │ │ + evaluate: function(context) { │ │ │ │ + return true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getContext │ │ │ │ - * Gets the context for evaluating this rule │ │ │ │ + * APIMethod: clone │ │ │ │ + * Clones this filter. Should be implemented by subclasses. │ │ │ │ * │ │ │ │ - * Paramters: │ │ │ │ - * feature - {<OpenLayers.Feature>} feature to take the context from if │ │ │ │ - * none is specified. │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Filter>} Clone of this filter. │ │ │ │ */ │ │ │ │ - getContext: function(feature) { │ │ │ │ - var context = this.context; │ │ │ │ - if (!context) { │ │ │ │ - context = feature.attributes || feature.data; │ │ │ │ - } │ │ │ │ - if (typeof this.context == "function") { │ │ │ │ - context = this.context(feature); │ │ │ │ - } │ │ │ │ - return context; │ │ │ │ + clone: function() { │ │ │ │ + return null; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Clones this rule. │ │ │ │ - * │ │ │ │ + * APIMethod: toString │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Rule>} Clone of this rule. │ │ │ │ + * {String} Include <OpenLayers.Format.CQL> in your build to get a CQL │ │ │ │ + * representation of the filter returned. Otherwise "[Object object]" │ │ │ │ + * will be returned. │ │ │ │ */ │ │ │ │ - clone: function() { │ │ │ │ - var options = OpenLayers.Util.extend({}, this); │ │ │ │ - if (this.symbolizers) { │ │ │ │ - // clone symbolizers │ │ │ │ - var len = this.symbolizers.length; │ │ │ │ - options.symbolizers = new Array(len); │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ - options.symbolizers[i] = this.symbolizers[i].clone(); │ │ │ │ - } │ │ │ │ + toString: function() { │ │ │ │ + var string; │ │ │ │ + if (OpenLayers.Format && OpenLayers.Format.CQL) { │ │ │ │ + string = OpenLayers.Format.CQL.prototype.write(this); │ │ │ │ } else { │ │ │ │ - // clone symbolizer │ │ │ │ - options.symbolizer = {}; │ │ │ │ - var value, type; │ │ │ │ - for (var key in this.symbolizer) { │ │ │ │ - value = this.symbolizer[key]; │ │ │ │ - type = typeof value; │ │ │ │ - if (type === "object") { │ │ │ │ - options.symbolizer[key] = OpenLayers.Util.extend({}, value); │ │ │ │ - } else if (type === "string") { │ │ │ │ - options.symbolizer[key] = value; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + string = Object.prototype.toString.call(this); │ │ │ │ } │ │ │ │ - // clone filter │ │ │ │ - options.filter = this.filter && this.filter.clone(); │ │ │ │ - // clone context │ │ │ │ - options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ - return new OpenLayers.Rule(options); │ │ │ │ + return string; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Rule" │ │ │ │ + CLASS_NAME: "OpenLayers.Filter" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ 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. │ │ │ │ @@ -33896,468 +33746,14 @@ │ │ │ │ this.tileCache = null; │ │ │ │ this.tileCacheIndex = null; │ │ │ │ this._destroyed = true; │ │ │ │ } │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - 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/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/Icon.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. */ │ │ │ │ @@ -34603,14 +33999,264 @@ │ │ │ │ │ │ │ │ return isDrawn; │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Icon" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ + OpenLayers/Marker.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 │ │ │ │ + * @requires OpenLayers/Icon.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Marker │ │ │ │ + * Instances of OpenLayers.Marker are a combination of a │ │ │ │ + * <OpenLayers.LonLat> and an <OpenLayers.Icon>. │ │ │ │ + * │ │ │ │ + * Markers are generally added to a special layer called │ │ │ │ + * <OpenLayers.Layer.Markers>. │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * (code) │ │ │ │ + * var markers = new OpenLayers.Layer.Markers( "Markers" ); │ │ │ │ + * map.addLayer(markers); │ │ │ │ + * │ │ │ │ + * var size = new OpenLayers.Size(21,25); │ │ │ │ + * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h); │ │ │ │ + * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset); │ │ │ │ + * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon)); │ │ │ │ + * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone())); │ │ │ │ + * │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Note that if you pass an icon into the Marker constructor, it will take │ │ │ │ + * that icon and use it. This means that you should not share icons between │ │ │ │ + * markers -- you use them once, but you should clone() for any additional │ │ │ │ + * markers using that same icon. │ │ │ │ + */ │ │ │ │ +OpenLayers.Marker = OpenLayers.Class({ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: icon │ │ │ │ + * {<OpenLayers.Icon>} The icon used by this marker. │ │ │ │ + */ │ │ │ │ + icon: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: lonlat │ │ │ │ + * {<OpenLayers.LonLat>} location of object │ │ │ │ + */ │ │ │ │ + lonlat: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: events │ │ │ │ + * {<OpenLayers.Events>} the event handler. │ │ │ │ + */ │ │ │ │ + events: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: map │ │ │ │ + * {<OpenLayers.Map>} the map this marker is attached to │ │ │ │ + */ │ │ │ │ + map: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Marker │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * lonlat - {<OpenLayers.LonLat>} the position of this marker │ │ │ │ + * icon - {<OpenLayers.Icon>} the icon for this marker │ │ │ │ + */ │ │ │ │ + initialize: function(lonlat, icon) { │ │ │ │ + this.lonlat = lonlat; │ │ │ │ + │ │ │ │ + var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon(); │ │ │ │ + if (this.icon == null) { │ │ │ │ + this.icon = newIcon; │ │ │ │ + } else { │ │ │ │ + this.icon.url = newIcon.url; │ │ │ │ + this.icon.size = newIcon.size; │ │ │ │ + this.icon.offset = newIcon.offset; │ │ │ │ + this.icon.calculateOffset = newIcon.calculateOffset; │ │ │ │ + } │ │ │ │ + this.events = new OpenLayers.Events(this, this.icon.imageDiv); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Destroy the marker. You must first remove the marker from any │ │ │ │ + * layer which it has been added to, or you will get buggy behavior. │ │ │ │ + * (This can not be done within the marker since the marker does not │ │ │ │ + * know which layer it is attached to.) │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + // erase any drawn features │ │ │ │ + this.erase(); │ │ │ │ + │ │ │ │ + this.map = null; │ │ │ │ + │ │ │ │ + this.events.destroy(); │ │ │ │ + this.events = null; │ │ │ │ + │ │ │ │ + if (this.icon != null) { │ │ │ │ + this.icon.destroy(); │ │ │ │ + this.icon = null; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: draw │ │ │ │ + * Calls draw on the icon, and returns that output. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * px - {<OpenLayers.Pixel>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A new DOM Image with this marker's icon set at the │ │ │ │ + * location passed-in │ │ │ │ + */ │ │ │ │ + draw: function(px) { │ │ │ │ + return this.icon.draw(px); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: erase │ │ │ │ + * Erases any drawn elements for this marker. │ │ │ │ + */ │ │ │ │ + erase: function() { │ │ │ │ + if (this.icon != null) { │ │ │ │ + this.icon.erase(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveTo │ │ │ │ + * Move the marker to the new location. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * px - {<OpenLayers.Pixel>|Object} the pixel position to move to. │ │ │ │ + * An OpenLayers.Pixel or an object with a 'x' and 'y' properties. │ │ │ │ + */ │ │ │ │ + moveTo: function(px) { │ │ │ │ + if ((px != null) && (this.icon != null)) { │ │ │ │ + this.icon.moveTo(px); │ │ │ │ + } │ │ │ │ + this.lonlat = this.map.getLonLatFromLayerPx(px); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: isDrawn │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the marker is drawn. │ │ │ │ + */ │ │ │ │ + isDrawn: function() { │ │ │ │ + var isDrawn = (this.icon && this.icon.isDrawn()); │ │ │ │ + return isDrawn; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: onScreen │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the marker is currently visible on screen. │ │ │ │ + */ │ │ │ │ + onScreen: function() { │ │ │ │ + │ │ │ │ + var onScreen = false; │ │ │ │ + if (this.map) { │ │ │ │ + var screenBounds = this.map.getExtent(); │ │ │ │ + onScreen = screenBounds.containsLonLat(this.lonlat); │ │ │ │ + } │ │ │ │ + return onScreen; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: inflate │ │ │ │ + * Englarges the markers icon by the specified ratio. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * inflate - {float} the ratio to enlarge the marker by (passing 2 │ │ │ │ + * will double the size). │ │ │ │ + */ │ │ │ │ + inflate: function(inflate) { │ │ │ │ + if (this.icon) { │ │ │ │ + this.icon.setSize({ │ │ │ │ + w: this.icon.size.w * inflate, │ │ │ │ + h: this.icon.size.h * inflate │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setOpacity │ │ │ │ + * Change the opacity of the marker by changin the opacity of │ │ │ │ + * its icon │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * opacity - {float} Specified as fraction (0.4, etc) │ │ │ │ + */ │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ + this.icon.setOpacity(opacity); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setUrl │ │ │ │ + * Change URL of the Icon Image. │ │ │ │ + * │ │ │ │ + * url - {String} │ │ │ │ + */ │ │ │ │ + setUrl: function(url) { │ │ │ │ + this.icon.setUrl(url); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: display │ │ │ │ + * Hide or show the icon │ │ │ │ + * │ │ │ │ + * display - {Boolean} │ │ │ │ + */ │ │ │ │ + display: function(display) { │ │ │ │ + this.icon.display(display); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Marker" │ │ │ │ +}); │ │ │ │ + │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Function: defaultIcon │ │ │ │ + * Creates a default <OpenLayers.Icon>. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Icon>} A default OpenLayers.Icon to use for a marker │ │ │ │ + */ │ │ │ │ +OpenLayers.Marker.defaultIcon = function() { │ │ │ │ + return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"), { │ │ │ │ + w: 21, │ │ │ │ + h: 25 │ │ │ │ + }, { │ │ │ │ + x: -10.5, │ │ │ │ + y: -25 │ │ │ │ + }); │ │ │ │ +}; │ │ │ │ + │ │ │ │ + │ │ │ │ +/* ====================================================================== │ │ │ │ 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. */ │ │ │ │ @@ -36430,104 +36076,14 @@ │ │ │ │ * Constant: OpenLayers.Format.WFST.DEFAULTS │ │ │ │ * {Object} Default properties for the WFST format. │ │ │ │ */ │ │ │ │ OpenLayers.Format.WFST.DEFAULTS = { │ │ │ │ "version": "1.0.0" │ │ │ │ }; │ │ │ │ /* ====================================================================== │ │ │ │ - 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/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. */ │ │ │ │ @@ -41833,952 +41389,966 @@ │ │ │ │ OpenLayers.Util.extend(this, options); │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.WPSProcess.ChainLink" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Spherical.js │ │ │ │ + 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/SingleFile.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: Spherical │ │ │ │ - * The OpenLayers.Spherical namespace includes utility functions for │ │ │ │ - * calculations on the basis of a spherical earth (ignoring ellipsoidal │ │ │ │ - * effects), which is accurate enough for most purposes. │ │ │ │ - * │ │ │ │ - * Relevant links: │ │ │ │ - * * http://www.movable-type.co.uk/scripts/latlong.html │ │ │ │ - * * http://code.google.com/apis/maps/documentation/javascript/reference.html#spherical │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ */ │ │ │ │ │ │ │ │ -OpenLayers.Spherical = OpenLayers.Spherical || {}; │ │ │ │ - │ │ │ │ -OpenLayers.Spherical.DEFAULT_RADIUS = 6378137; │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIFunction: computeDistanceBetween │ │ │ │ - * Computes the distance between two LonLats. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * from - {<OpenLayers.LonLat>} or {Object} Starting point. A LonLat or │ │ │ │ - * a JavaScript literal with lon lat properties. │ │ │ │ - * to - {<OpenLayers.LonLat>} or {Object} Ending point. A LonLat or a │ │ │ │ - * JavaScript literal with lon lat properties. │ │ │ │ - * radius - {Float} The radius. Optional. Defaults to 6378137 meters. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Float} The distance in meters. │ │ │ │ + * Class: OpenLayers.Strategy │ │ │ │ + * Abstract vector layer strategy class. Not to be instantiated directly. Use │ │ │ │ + * one of the strategy subclasses instead. │ │ │ │ */ │ │ │ │ -OpenLayers.Spherical.computeDistanceBetween = function(from, to, radius) { │ │ │ │ - var R = radius || OpenLayers.Spherical.DEFAULT_RADIUS; │ │ │ │ - var sinHalfDeltaLon = Math.sin(Math.PI * (to.lon - from.lon) / 360); │ │ │ │ - var sinHalfDeltaLat = Math.sin(Math.PI * (to.lat - from.lat) / 360); │ │ │ │ - var a = sinHalfDeltaLat * sinHalfDeltaLat + │ │ │ │ - sinHalfDeltaLon * sinHalfDeltaLon * Math.cos(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ - return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); │ │ │ │ -}; │ │ │ │ +OpenLayers.Strategy = OpenLayers.Class({ │ │ │ │ │ │ │ │ + /** │ │ │ │ + * Property: layer │ │ │ │ + * {<OpenLayers.Layer.Vector>} The layer this strategy belongs to. │ │ │ │ + */ │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ -/** │ │ │ │ - * APIFunction: computeHeading │ │ │ │ - * Computes the heading from one LonLat to another LonLat. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * from - {<OpenLayers.LonLat>} or {Object} Starting point. A LonLat or │ │ │ │ - * a JavaScript literal with lon lat properties. │ │ │ │ - * to - {<OpenLayers.LonLat>} or {Object} Ending point. A LonLat or a │ │ │ │ - * JavaScript literal with lon lat properties. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Float} The heading in degrees. │ │ │ │ - */ │ │ │ │ -OpenLayers.Spherical.computeHeading = function(from, to) { │ │ │ │ - var y = Math.sin(Math.PI * (from.lon - to.lon) / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ - var x = Math.cos(Math.PI * from.lat / 180) * Math.sin(Math.PI * to.lat / 180) - │ │ │ │ - Math.sin(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180) * Math.cos(Math.PI * (from.lon - to.lon) / 180); │ │ │ │ - return 180 * Math.atan2(y, x) / Math.PI; │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Symbolizer.js │ │ │ │ - ====================================================================== */ │ │ │ │ + /** │ │ │ │ + * Property: options │ │ │ │ + * {Object} Any options sent to the constructor. │ │ │ │ + */ │ │ │ │ + options: null, │ │ │ │ │ │ │ │ -/* 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. */ │ │ │ │ + /** │ │ │ │ + * Property: active │ │ │ │ + * {Boolean} The control is active. │ │ │ │ + */ │ │ │ │ + active: null, │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ - */ │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Symbolizer │ │ │ │ - * Base class representing a symbolizer used for feature rendering. │ │ │ │ - */ │ │ │ │ -OpenLayers.Symbolizer = OpenLayers.Class({ │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: zIndex │ │ │ │ - * {Number} The zIndex determines the rendering order for a symbolizer. │ │ │ │ - * Symbolizers with larger zIndex values are rendered over symbolizers │ │ │ │ - * with smaller zIndex values. Default is 0. │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Clean up the strategy. │ │ │ │ */ │ │ │ │ - zIndex: 0, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + this.layer = null; │ │ │ │ + this.options = null; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Symbolizer │ │ │ │ - * Instances of this class are not useful. See one of the subclasses. │ │ │ │ + * Method: setLayer │ │ │ │ + * Called to set the <layer> property. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ - * construction. │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} │ │ │ │ + */ │ │ │ │ + setLayer: function(layer) { │ │ │ │ + this.layer = layer; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: activate │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * A new symbolizer. │ │ │ │ + * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ + * the strategy was already active. │ │ │ │ */ │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Util.extend(this, config); │ │ │ │ + activate: function() { │ │ │ │ + if (!this.active) { │ │ │ │ + this.active = true; │ │ │ │ + return true; │ │ │ │ + } │ │ │ │ + return false; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Create a copy of this symbolizer. │ │ │ │ + /** │ │ │ │ + * Method: deactivate │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ + * tear-down. │ │ │ │ * │ │ │ │ - * Returns a symbolizer of the same type with the same properties. │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} True if the strategy was successfully deactivated or false if │ │ │ │ + * the strategy was already inactive. │ │ │ │ */ │ │ │ │ - clone: function() { │ │ │ │ - var Type = eval(this.CLASS_NAME); │ │ │ │ - return new Type(OpenLayers.Util.extend({}, this)); │ │ │ │ + deactivate: function() { │ │ │ │ + if (this.active) { │ │ │ │ + this.active = false; │ │ │ │ + return true; │ │ │ │ + } │ │ │ │ + return false; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer" │ │ │ │ - │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ }); │ │ │ │ - │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Marker.js │ │ │ │ + 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/Events.js │ │ │ │ - * @requires OpenLayers/Icon.js │ │ │ │ + * @requires OpenLayers/Animation.js │ │ │ │ */ │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Marker │ │ │ │ - * Instances of OpenLayers.Marker are a combination of a │ │ │ │ - * <OpenLayers.LonLat> and an <OpenLayers.Icon>. │ │ │ │ - * │ │ │ │ - * Markers are generally added to a special layer called │ │ │ │ - * <OpenLayers.Layer.Markers>. │ │ │ │ - * │ │ │ │ - * Example: │ │ │ │ - * (code) │ │ │ │ - * var markers = new OpenLayers.Layer.Markers( "Markers" ); │ │ │ │ - * map.addLayer(markers); │ │ │ │ - * │ │ │ │ - * var size = new OpenLayers.Size(21,25); │ │ │ │ - * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h); │ │ │ │ - * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset); │ │ │ │ - * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon)); │ │ │ │ - * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone())); │ │ │ │ - * │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * Note that if you pass an icon into the Marker constructor, it will take │ │ │ │ - * that icon and use it. This means that you should not share icons between │ │ │ │ - * markers -- you use them once, but you should clone() for any additional │ │ │ │ - * markers using that same icon. │ │ │ │ - */ │ │ │ │ -OpenLayers.Marker = OpenLayers.Class({ │ │ │ │ +OpenLayers.Kinetic = OpenLayers.Class({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: icon │ │ │ │ - * {<OpenLayers.Icon>} The icon used by this marker. │ │ │ │ + /** │ │ │ │ + * Property: threshold │ │ │ │ + * In most cases changing the threshold isn't needed. │ │ │ │ + * In px/ms, default to 0. │ │ │ │ */ │ │ │ │ - icon: null, │ │ │ │ + threshold: 0, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: lonlat │ │ │ │ - * {<OpenLayers.LonLat>} location of object │ │ │ │ + /** │ │ │ │ + * Property: deceleration │ │ │ │ + * {Float} the deseleration in px/ms², default to 0.0035. │ │ │ │ */ │ │ │ │ - lonlat: null, │ │ │ │ + deceleration: 0.0035, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: events │ │ │ │ - * {<OpenLayers.Events>} the event handler. │ │ │ │ + /** │ │ │ │ + * Property: nbPoints │ │ │ │ + * {Integer} the number of points we use to calculate the kinetic │ │ │ │ + * initial values. │ │ │ │ */ │ │ │ │ - events: null, │ │ │ │ + nbPoints: 100, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: map │ │ │ │ - * {<OpenLayers.Map>} the map this marker is attached to │ │ │ │ + /** │ │ │ │ + * Property: delay │ │ │ │ + * {Float} time to consider to calculate the kinetic initial values. │ │ │ │ + * In ms, default to 200. │ │ │ │ */ │ │ │ │ - map: null, │ │ │ │ + delay: 200, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Marker │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * lonlat - {<OpenLayers.LonLat>} the position of this marker │ │ │ │ - * icon - {<OpenLayers.Icon>} the icon for this marker │ │ │ │ + /** │ │ │ │ + * Property: points │ │ │ │ + * List of points use to calculate the kinetic initial values. │ │ │ │ */ │ │ │ │ - initialize: function(lonlat, icon) { │ │ │ │ - this.lonlat = lonlat; │ │ │ │ - │ │ │ │ - var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon(); │ │ │ │ - if (this.icon == null) { │ │ │ │ - this.icon = newIcon; │ │ │ │ - } else { │ │ │ │ - this.icon.url = newIcon.url; │ │ │ │ - this.icon.size = newIcon.size; │ │ │ │ - this.icon.offset = newIcon.offset; │ │ │ │ - this.icon.calculateOffset = newIcon.calculateOffset; │ │ │ │ - } │ │ │ │ - this.events = new OpenLayers.Events(this, this.icon.imageDiv); │ │ │ │ - }, │ │ │ │ + points: undefined, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Destroy the marker. You must first remove the marker from any │ │ │ │ - * layer which it has been added to, or you will get buggy behavior. │ │ │ │ - * (This can not be done within the marker since the marker does not │ │ │ │ - * know which layer it is attached to.) │ │ │ │ + * Property: timerId │ │ │ │ + * ID of the timer. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - // erase any drawn features │ │ │ │ - this.erase(); │ │ │ │ - │ │ │ │ - this.map = null; │ │ │ │ - │ │ │ │ - this.events.destroy(); │ │ │ │ - this.events = null; │ │ │ │ - │ │ │ │ - if (this.icon != null) { │ │ │ │ - this.icon.destroy(); │ │ │ │ - this.icon = null; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + timerId: undefined, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * Calls draw on the icon, and returns that output. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Kinetic │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * px - {<OpenLayers.Pixel>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A new DOM Image with this marker's icon set at the │ │ │ │ - * location passed-in │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ - draw: function(px) { │ │ │ │ - return this.icon.draw(px); │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: erase │ │ │ │ - * Erases any drawn elements for this marker. │ │ │ │ + /** │ │ │ │ + * Method: begin │ │ │ │ + * Begins the dragging. │ │ │ │ */ │ │ │ │ - erase: function() { │ │ │ │ - if (this.icon != null) { │ │ │ │ - this.icon.erase(); │ │ │ │ - } │ │ │ │ + begin: function() { │ │ │ │ + OpenLayers.Animation.stop(this.timerId); │ │ │ │ + this.timerId = undefined; │ │ │ │ + this.points = []; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: moveTo │ │ │ │ - * Move the marker to the new location. │ │ │ │ + * Method: update │ │ │ │ + * Updates during the dragging. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * px - {<OpenLayers.Pixel>|Object} the pixel position to move to. │ │ │ │ - * An OpenLayers.Pixel or an object with a 'x' and 'y' properties. │ │ │ │ + * xy - {<OpenLayers.Pixel>} The new position. │ │ │ │ */ │ │ │ │ - moveTo: function(px) { │ │ │ │ - if ((px != null) && (this.icon != null)) { │ │ │ │ - this.icon.moveTo(px); │ │ │ │ + update: function(xy) { │ │ │ │ + this.points.unshift({ │ │ │ │ + xy: xy, │ │ │ │ + tick: new Date().getTime() │ │ │ │ + }); │ │ │ │ + if (this.points.length > this.nbPoints) { │ │ │ │ + this.points.pop(); │ │ │ │ } │ │ │ │ - this.lonlat = this.map.getLonLatFromLayerPx(px); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: isDrawn │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the marker is drawn. │ │ │ │ - */ │ │ │ │ - isDrawn: function() { │ │ │ │ - var isDrawn = (this.icon && this.icon.isDrawn()); │ │ │ │ - return isDrawn; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onScreen │ │ │ │ + * Method: end │ │ │ │ + * Ends the dragging, start the kinetic. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * xy - {<OpenLayers.Pixel>} The last position. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Whether or not the marker is currently visible on screen. │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - onScreen: function() { │ │ │ │ - │ │ │ │ - var onScreen = false; │ │ │ │ - if (this.map) { │ │ │ │ - var screenBounds = this.map.getExtent(); │ │ │ │ - onScreen = screenBounds.containsLonLat(this.lonlat); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - return onScreen; │ │ │ │ + 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: inflate │ │ │ │ - * Englarges the markers icon by the specified ratio. │ │ │ │ + * Method: move │ │ │ │ + * Launch the kinetic move pan. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * inflate - {float} the ratio to enlarge the marker by (passing 2 │ │ │ │ - * will double the size). │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - inflate: function(inflate) { │ │ │ │ - if (this.icon) { │ │ │ │ - this.icon.setSize({ │ │ │ │ - w: this.icon.size.w * inflate, │ │ │ │ - h: this.icon.size.h * inflate │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + move: function(info, callback) { │ │ │ │ + var v0 = info.speed; │ │ │ │ + var fx = Math.cos(info.theta); │ │ │ │ + var fy = -Math.sin(info.theta); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setOpacity │ │ │ │ - * Change the opacity of the marker by changin the opacity of │ │ │ │ - * its icon │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * opacity - {float} Specified as fraction (0.4, etc) │ │ │ │ - */ │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ - this.icon.setOpacity(opacity); │ │ │ │ - }, │ │ │ │ + var initialTime = new Date().getTime(); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setUrl │ │ │ │ - * Change URL of the Icon Image. │ │ │ │ - * │ │ │ │ - * url - {String} │ │ │ │ - */ │ │ │ │ - setUrl: function(url) { │ │ │ │ - this.icon.setUrl(url); │ │ │ │ - }, │ │ │ │ + var lastX = 0; │ │ │ │ + var lastY = 0; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: display │ │ │ │ - * Hide or show the icon │ │ │ │ - * │ │ │ │ - * display - {Boolean} │ │ │ │ - */ │ │ │ │ - display: function(display) { │ │ │ │ - this.icon.display(display); │ │ │ │ - }, │ │ │ │ + var timerCallback = function() { │ │ │ │ + if (this.timerId == null) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Marker" │ │ │ │ -}); │ │ │ │ + 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; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Function: defaultIcon │ │ │ │ - * Creates a default <OpenLayers.Icon>. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Icon>} A default OpenLayers.Icon to use for a marker │ │ │ │ - */ │ │ │ │ -OpenLayers.Marker.defaultIcon = function() { │ │ │ │ - return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"), { │ │ │ │ - w: 21, │ │ │ │ - h: 25 │ │ │ │ - }, { │ │ │ │ - x: -10.5, │ │ │ │ - y: -25 │ │ │ │ - }); │ │ │ │ -}; │ │ │ │ + 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/Symbolizer/Point.js │ │ │ │ + OpenLayers/Rule.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/Symbolizer.js │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ + * @requires OpenLayers/Style.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Symbolizer.Point │ │ │ │ - * A symbolizer used to render point features. │ │ │ │ + * Class: OpenLayers.Rule │ │ │ │ + * This class represents an SLD Rule, as being used for rule-based SLD styling. │ │ │ │ */ │ │ │ │ -OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ +OpenLayers.Rule = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: strokeColor │ │ │ │ - * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ - * for red). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * Property: id │ │ │ │ + * {String} A unique id for this session. │ │ │ │ */ │ │ │ │ + id: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: strokeOpacity │ │ │ │ - * {Number} Stroke opacity (0-1). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * APIProperty: name │ │ │ │ + * {String} name of this rule │ │ │ │ */ │ │ │ │ + name: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: strokeWidth │ │ │ │ - * {Number} Pixel stroke width. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * Property: title │ │ │ │ + * {String} Title of this rule (set if included in SLD) │ │ │ │ */ │ │ │ │ + title: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: strokeLinecap │ │ │ │ - * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * Property: description │ │ │ │ + * {String} Description of this rule (set if abstract is included in SLD) │ │ │ │ */ │ │ │ │ + description: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: strokeDashstyle │ │ │ │ - * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ - * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ - * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ - * most SLD patterns will render correctly in OpenLayers. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * Property: context │ │ │ │ + * {Object} An optional object with properties that the rule should be │ │ │ │ + * evaluated against. If no context is specified, feature.attributes will │ │ │ │ + * be used. │ │ │ │ */ │ │ │ │ + context: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: fillColor │ │ │ │ - * {String} RGB hex fill color (e.g. "#ff0000" for red). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * Property: filter │ │ │ │ + * {<OpenLayers.Filter>} Optional filter for the rule. │ │ │ │ */ │ │ │ │ + filter: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: fillOpacity │ │ │ │ - * {Number} Fill opacity (0-1). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * Property: elseFilter │ │ │ │ + * {Boolean} Determines whether this rule is only to be applied only if │ │ │ │ + * no other rules match (ElseFilter according to the SLD specification). │ │ │ │ + * Default is false. For instances of OpenLayers.Rule, if elseFilter is │ │ │ │ + * false, the rule will always apply. For subclasses, the else property is │ │ │ │ + * ignored. │ │ │ │ */ │ │ │ │ + elseFilter: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: pointRadius │ │ │ │ - * {Number} Pixel point radius. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * Property: symbolizer │ │ │ │ + * {Object} Symbolizer or hash of symbolizers for this rule. If hash of │ │ │ │ + * symbolizers, keys are one or more of ["Point", "Line", "Polygon"]. The │ │ │ │ + * latter if useful if it is required to style e.g. vertices of a line │ │ │ │ + * with a point symbolizer. Note, however, that this is not implemented │ │ │ │ + * yet in OpenLayers, but it is the way how symbolizers are defined in │ │ │ │ + * SLD. │ │ │ │ */ │ │ │ │ + symbolizer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: externalGraphic │ │ │ │ - * {String} Url to an external graphic that will be used for rendering │ │ │ │ - * points. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * Property: symbolizers │ │ │ │ + * {Array} Collection of symbolizers associated with this rule. If │ │ │ │ + * provided at construction, the symbolizers array has precedence │ │ │ │ + * over the deprecated symbolizer property. Note that multiple │ │ │ │ + * symbolizers are not currently supported by the vector renderers. │ │ │ │ + * Rules with multiple symbolizers are currently only useful for │ │ │ │ + * maintaining elements in an SLD document. │ │ │ │ */ │ │ │ │ + symbolizers: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: graphicWidth │ │ │ │ - * {Number} Pixel width for sizing an external graphic. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * APIProperty: minScaleDenominator │ │ │ │ + * {Number} or {String} minimum scale at which to draw the feature. │ │ │ │ + * In the case of a String, this can be a combination of text and │ │ │ │ + * propertyNames in the form "literal ${propertyName}" │ │ │ │ */ │ │ │ │ + minScaleDenominator: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: graphicHeight │ │ │ │ - * {Number} Pixel height for sizing an external graphic. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * APIProperty: maxScaleDenominator │ │ │ │ + * {Number} or {String} maximum scale at which to draw the feature. │ │ │ │ + * In the case of a String, this can be a combination of text and │ │ │ │ + * propertyNames in the form "literal ${propertyName}" │ │ │ │ */ │ │ │ │ + maxScaleDenominator: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: graphicOpacity │ │ │ │ - * {Number} Opacity (0-1) for an external graphic. │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Rule │ │ │ │ + * Creates a Rule. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object with properties to set on the │ │ │ │ + * rule │ │ │ │ * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Rule>} │ │ │ │ */ │ │ │ │ + initialize: function(options) { │ │ │ │ + this.symbolizer = {}; │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + if (this.symbolizers) { │ │ │ │ + delete this.symbolizer; │ │ │ │ + } │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: graphicXOffset │ │ │ │ - * {Number} Pixel offset along the positive x axis for displacing an │ │ │ │ - * external graphic. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ */ │ │ │ │ + destroy: function() { │ │ │ │ + for (var i in this.symbolizer) { │ │ │ │ + this.symbolizer[i] = null; │ │ │ │ + } │ │ │ │ + this.symbolizer = null; │ │ │ │ + delete this.symbolizers; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: graphicYOffset │ │ │ │ - * {Number} Pixel offset along the positive y axis for displacing an │ │ │ │ - * external graphic. │ │ │ │ + * APIMethod: evaluate │ │ │ │ + * evaluates this rule for a specific feature │ │ │ │ * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: rotation │ │ │ │ - * {Number} The rotation of a graphic in the clockwise direction about its │ │ │ │ - * center point (or any point off center as specified by │ │ │ │ - * <graphicXOffset> and <graphicYOffset>). │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature>} feature to apply the rule to. │ │ │ │ * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} true if the rule applies, false if it does not. │ │ │ │ + * This rule is the default rule and always returns true. │ │ │ │ */ │ │ │ │ + evaluate: function(feature) { │ │ │ │ + var context = this.getContext(feature); │ │ │ │ + var applies = true; │ │ │ │ + │ │ │ │ + if (this.minScaleDenominator || this.maxScaleDenominator) { │ │ │ │ + var scale = feature.layer.map.getScale(); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // check if within minScale/maxScale bounds │ │ │ │ + if (this.minScaleDenominator) { │ │ │ │ + applies = scale >= OpenLayers.Style.createLiteral( │ │ │ │ + this.minScaleDenominator, context); │ │ │ │ + } │ │ │ │ + if (applies && this.maxScaleDenominator) { │ │ │ │ + applies = scale < OpenLayers.Style.createLiteral( │ │ │ │ + this.maxScaleDenominator, context); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // check if optional filter applies │ │ │ │ + if (applies && this.filter) { │ │ │ │ + // feature id filters get the feature, others get the context │ │ │ │ + if (this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") { │ │ │ │ + applies = this.filter.evaluate(feature); │ │ │ │ + } else { │ │ │ │ + applies = this.filter.evaluate(context); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + return applies; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: graphicName │ │ │ │ - * {String} Named graphic to use when rendering points. Supported values │ │ │ │ - * include "circle", "square", "star", "x", "cross", and "triangle". │ │ │ │ + * Method: getContext │ │ │ │ + * Gets the context for evaluating this rule │ │ │ │ * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * Paramters: │ │ │ │ + * feature - {<OpenLayers.Feature>} feature to take the context from if │ │ │ │ + * none is specified. │ │ │ │ */ │ │ │ │ + getContext: function(feature) { │ │ │ │ + var context = this.context; │ │ │ │ + if (!context) { │ │ │ │ + context = feature.attributes || feature.data; │ │ │ │ + } │ │ │ │ + if (typeof this.context == "function") { │ │ │ │ + context = this.context(feature); │ │ │ │ + } │ │ │ │ + return context; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Symbolizer.Point │ │ │ │ - * Create a symbolizer for rendering points. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ - * construction. │ │ │ │ - * │ │ │ │ + * APIMethod: clone │ │ │ │ + * Clones this rule. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * A new point symbolizer. │ │ │ │ + * {<OpenLayers.Rule>} Clone of this rule. │ │ │ │ */ │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ + clone: function() { │ │ │ │ + var options = OpenLayers.Util.extend({}, this); │ │ │ │ + if (this.symbolizers) { │ │ │ │ + // clone symbolizers │ │ │ │ + var len = this.symbolizers.length; │ │ │ │ + options.symbolizers = new Array(len); │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ + options.symbolizers[i] = this.symbolizers[i].clone(); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + // clone symbolizer │ │ │ │ + options.symbolizer = {}; │ │ │ │ + var value, type; │ │ │ │ + for (var key in this.symbolizer) { │ │ │ │ + value = this.symbolizer[key]; │ │ │ │ + type = typeof value; │ │ │ │ + if (type === "object") { │ │ │ │ + options.symbolizer[key] = OpenLayers.Util.extend({}, value); │ │ │ │ + } else if (type === "string") { │ │ │ │ + options.symbolizer[key] = value; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + // clone filter │ │ │ │ + options.filter = this.filter && this.filter.clone(); │ │ │ │ + // clone context │ │ │ │ + options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ + return new OpenLayers.Rule(options); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Point" │ │ │ │ - │ │ │ │ + CLASS_NAME: "OpenLayers.Rule" │ │ │ │ }); │ │ │ │ - │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Symbolizer/Line.js │ │ │ │ + OpenLayers/Spherical.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/Symbolizer.js │ │ │ │ + * @requires OpenLayers/SingleFile.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Symbolizer.Line │ │ │ │ - * A symbolizer used to render line features. │ │ │ │ + * Namespace: Spherical │ │ │ │ + * The OpenLayers.Spherical namespace includes utility functions for │ │ │ │ + * calculations on the basis of a spherical earth (ignoring ellipsoidal │ │ │ │ + * effects), which is accurate enough for most purposes. │ │ │ │ + * │ │ │ │ + * Relevant links: │ │ │ │ + * * http://www.movable-type.co.uk/scripts/latlong.html │ │ │ │ + * * http://code.google.com/apis/maps/documentation/javascript/reference.html#spherical │ │ │ │ */ │ │ │ │ -OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeColor │ │ │ │ - * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ - * for red). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeOpacity │ │ │ │ - * {Number} Stroke opacity (0-1). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeWidth │ │ │ │ - * {Number} Pixel stroke width. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: strokeLinecap │ │ │ │ - * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: strokeDashstyle │ │ │ │ - * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ - * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ - * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ - * most SLD patterns will render correctly in OpenLayers. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ +OpenLayers.Spherical = OpenLayers.Spherical || {}; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Symbolizer.Line │ │ │ │ - * Create a symbolizer for rendering lines. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ - * construction. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * A new line symbolizer. │ │ │ │ - */ │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ - }, │ │ │ │ +OpenLayers.Spherical.DEFAULT_RADIUS = 6378137; │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Line" │ │ │ │ +/** │ │ │ │ + * APIFunction: computeDistanceBetween │ │ │ │ + * Computes the distance between two LonLats. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * from - {<OpenLayers.LonLat>} or {Object} Starting point. A LonLat or │ │ │ │ + * a JavaScript literal with lon lat properties. │ │ │ │ + * to - {<OpenLayers.LonLat>} or {Object} Ending point. A LonLat or a │ │ │ │ + * JavaScript literal with lon lat properties. │ │ │ │ + * radius - {Float} The radius. Optional. Defaults to 6378137 meters. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Float} The distance in meters. │ │ │ │ + */ │ │ │ │ +OpenLayers.Spherical.computeDistanceBetween = function(from, to, radius) { │ │ │ │ + var R = radius || OpenLayers.Spherical.DEFAULT_RADIUS; │ │ │ │ + var sinHalfDeltaLon = Math.sin(Math.PI * (to.lon - from.lon) / 360); │ │ │ │ + var sinHalfDeltaLat = Math.sin(Math.PI * (to.lat - from.lat) / 360); │ │ │ │ + var a = sinHalfDeltaLat * sinHalfDeltaLat + │ │ │ │ + sinHalfDeltaLon * sinHalfDeltaLon * Math.cos(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ + return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); │ │ │ │ +}; │ │ │ │ │ │ │ │ -}); │ │ │ │ │ │ │ │ +/** │ │ │ │ + * APIFunction: computeHeading │ │ │ │ + * Computes the heading from one LonLat to another LonLat. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * from - {<OpenLayers.LonLat>} or {Object} Starting point. A LonLat or │ │ │ │ + * a JavaScript literal with lon lat properties. │ │ │ │ + * to - {<OpenLayers.LonLat>} or {Object} Ending point. A LonLat or a │ │ │ │ + * JavaScript literal with lon lat properties. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Float} The heading in degrees. │ │ │ │ + */ │ │ │ │ +OpenLayers.Spherical.computeHeading = function(from, to) { │ │ │ │ + var y = Math.sin(Math.PI * (from.lon - to.lon) / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ + var x = Math.cos(Math.PI * from.lat / 180) * Math.sin(Math.PI * to.lat / 180) - │ │ │ │ + Math.sin(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180) * Math.cos(Math.PI * (from.lon - to.lon) / 180); │ │ │ │ + return 180 * Math.atan2(y, x) / Math.PI; │ │ │ │ +}; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Symbolizer/Polygon.js │ │ │ │ + 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/Symbolizer.js │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Symbolizer.Polygon │ │ │ │ - * A symbolizer used to render line features. │ │ │ │ + * 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.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ +OpenLayers.Handler = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: strokeColor │ │ │ │ - * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ - * for red). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * Property: id │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ + id: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: strokeOpacity │ │ │ │ - * {Number} Stroke opacity (0-1). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: strokeWidth │ │ │ │ - * {Number} Pixel stroke width. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * Property: map │ │ │ │ + * {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ + map: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: strokeLinecap │ │ │ │ - * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * 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: strokeDashstyle │ │ │ │ - * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ - * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ - * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ - * most SLD patterns will render correctly in OpenLayers. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * Property: active │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ + active: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: fillColor │ │ │ │ - * {String} RGB hex fill color (e.g. "#ff0000" for red). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: fillOpacity │ │ │ │ - * {Number} Fill opacity (0-1). │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * 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.Symbolizer.Polygon │ │ │ │ - * Create a symbolizer for rendering polygons. │ │ │ │ + * Constructor: OpenLayers.Handler │ │ │ │ + * Construct a handler. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ - * construction. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * A new polygon symbolizer. │ │ │ │ + * 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(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Polygon" │ │ │ │ - │ │ │ │ -}); │ │ │ │ - │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Symbolizer/Text.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. */ │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + this.control = control; │ │ │ │ + this.callbacks = callbacks; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Symbolizer.js │ │ │ │ - */ │ │ │ │ + var map = this.map || control.map; │ │ │ │ + if (map) { │ │ │ │ + this.setMap(map); │ │ │ │ + } │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Symbolizer.Text │ │ │ │ - * A symbolizer used to render text labels for features. │ │ │ │ - */ │ │ │ │ -OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: label │ │ │ │ - * {String} The text for the label. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ */ │ │ │ │ + setMap: function(map) { │ │ │ │ + this.map = map; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: fontFamily │ │ │ │ - * {String} The font family for the label. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: fontSize │ │ │ │ - * {String} The font size for the label. │ │ │ │ - * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ - */ │ │ │ │ + /* if it differs from the handler object's key mask, │ │ │ │ + bail out of the event handler */ │ │ │ │ + return (keyModifiers == this.keyMask); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: fontWeight │ │ │ │ - * {String} The font weight for the label. │ │ │ │ + /** │ │ │ │ + * APIMethod: activate │ │ │ │ + * Turn on the handler. Returns false if the handler was already active. │ │ │ │ * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: fontStyle │ │ │ │ - * {String} The font style for the label. │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Turn off the handler. Returns false if the handler was already inactive. │ │ │ │ * │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Symbolizer.Text │ │ │ │ - * Create a symbolizer for rendering text labels. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ - * construction. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * A new text symbolizer. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ + 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]]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Text" │ │ │ │ - │ │ │ │ -}); │ │ │ │ - │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Symbolizer/Raster.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/Symbolizer.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Symbolizer.Raster │ │ │ │ - * A symbolizer used to render raster images. │ │ │ │ - */ │ │ │ │ -OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Symbolizer.Raster │ │ │ │ - * Create a symbolizer for rendering rasters. │ │ │ │ + * Method: callback │ │ │ │ + * Trigger the control's named callback with the given arguments │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ - * construction. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * A new raster symbolizer. │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ + callback: function(name, args) { │ │ │ │ + if (name && this.callbacks[name]) { │ │ │ │ + this.callbacks[name].apply(this.control, args); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Raster" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Style2.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/Rule.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Point.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Line.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Polygon.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Text.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Raster.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Style2 │ │ │ │ - * This class represents a collection of rules for rendering features. │ │ │ │ - */ │ │ │ │ -OpenLayers.Style2 = OpenLayers.Class({ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Property: id │ │ │ │ - * {String} A unique id for this session. │ │ │ │ + * Method: register │ │ │ │ + * register an event on the map │ │ │ │ */ │ │ │ │ - id: null, │ │ │ │ + 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); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: name │ │ │ │ - * {String} Style identifier. │ │ │ │ + * Method: unregister │ │ │ │ + * unregister an event from the map │ │ │ │ */ │ │ │ │ - name: null, │ │ │ │ + unregister: function(name, method) { │ │ │ │ + this.map.events.unregister(name, this, method); │ │ │ │ + this.map.events.unregister(name, this, this.setEvent); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: title │ │ │ │ - * {String} Title of this style. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - title: null, │ │ │ │ + setEvent: function(evt) { │ │ │ │ + this.evt = evt; │ │ │ │ + return true; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: description │ │ │ │ - * {String} Description of this style. │ │ │ │ + * Method: destroy │ │ │ │ + * Deconstruct the handler. │ │ │ │ */ │ │ │ │ - description: null, │ │ │ │ + destroy: function() { │ │ │ │ + // unregister event listeners │ │ │ │ + this.deactivate(); │ │ │ │ + // eliminate circular references │ │ │ │ + this.control = this.map = 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, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler" │ │ │ │ +}); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: isDefault │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - isDefault: false, │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Handler.MOD_NONE │ │ │ │ + * If set as the <keyMask>, <checkModifiers> returns false if any key is down. │ │ │ │ + */ │ │ │ │ +OpenLayers.Handler.MOD_NONE = 0; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: rules │ │ │ │ - * {Array(<OpenLayers.Rule>)} Collection of rendering rules. │ │ │ │ - */ │ │ │ │ - rules: null, │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Handler.MOD_SHIFT │ │ │ │ + * If set as the <keyMask>, <checkModifiers> returns false if Shift is down. │ │ │ │ + */ │ │ │ │ +OpenLayers.Handler.MOD_SHIFT = 1; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Style2 │ │ │ │ - * Creates a style representing a collection of rendering rules. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ - * style. Any documented properties may be set at construction. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Style2>} A new style object. │ │ │ │ - */ │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Util.extend(this, config); │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Handler.MOD_CTRL │ │ │ │ + * If set as the <keyMask>, <checkModifiers> returns false if Ctrl is down. │ │ │ │ + */ │ │ │ │ +OpenLayers.Handler.MOD_CTRL = 2; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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(); │ │ │ │ - } │ │ │ │ - delete this.rules; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * 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; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Clones this style. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Style2>} Clone of this style. │ │ │ │ - */ │ │ │ │ - clone: function() { │ │ │ │ - var config = OpenLayers.Util.extend({}, this); │ │ │ │ - // clone rules │ │ │ │ - if (this.rules) { │ │ │ │ - config.rules = []; │ │ │ │ - for (var i = 0, len = this.rules.length; i < len; ++i) { │ │ │ │ - config.rules.push(this.rules[i].clone()); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return new OpenLayers.Style2(config); │ │ │ │ - }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Style2" │ │ │ │ -}); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Format/WPSDescribeProcess.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 │ │ │ │ @@ -43188,11645 +42758,8166 @@ │ │ │ │ this.servers = null; │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: 'OpenLayers.WPSClient' │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Kinetic.js │ │ │ │ + OpenLayers/Symbolizer.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({ │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Symbolizer │ │ │ │ + * Base class representing a symbolizer used for feature rendering. │ │ │ │ + */ │ │ │ │ +OpenLayers.Symbolizer = OpenLayers.Class({ │ │ │ │ + │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: threshold │ │ │ │ - * In most cases changing the threshold isn't needed. │ │ │ │ - * In px/ms, default to 0. │ │ │ │ + * APIProperty: zIndex │ │ │ │ + * {Number} The zIndex determines the rendering order for a symbolizer. │ │ │ │ + * Symbolizers with larger zIndex values are rendered over symbolizers │ │ │ │ + * with smaller zIndex values. Default is 0. │ │ │ │ */ │ │ │ │ - threshold: 0, │ │ │ │ + zIndex: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: deceleration │ │ │ │ - * {Float} the deseleration in px/ms², default to 0.0035. │ │ │ │ + * Constructor: OpenLayers.Symbolizer │ │ │ │ + * Instances of this class are not useful. See one of the subclasses. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ + * construction. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * A new symbolizer. │ │ │ │ */ │ │ │ │ - deceleration: 0.0035, │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Util.extend(this, config); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: nbPoints │ │ │ │ - * {Integer} the number of points we use to calculate the kinetic │ │ │ │ - * initial values. │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * Create a copy of this symbolizer. │ │ │ │ + * │ │ │ │ + * Returns a symbolizer of the same type with the same properties. │ │ │ │ */ │ │ │ │ - nbPoints: 100, │ │ │ │ + clone: function() { │ │ │ │ + var Type = eval(this.CLASS_NAME); │ │ │ │ + return new Type(OpenLayers.Util.extend({}, this)); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer" │ │ │ │ + │ │ │ │ +}); │ │ │ │ + │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Symbolizer/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/Symbolizer.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Symbolizer.Point │ │ │ │ + * A symbolizer used to render point features. │ │ │ │ + */ │ │ │ │ +OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: delay │ │ │ │ - * {Float} time to consider to calculate the kinetic initial values. │ │ │ │ - * In ms, default to 200. │ │ │ │ + * APIProperty: strokeColor │ │ │ │ + * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ + * for red). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - delay: 200, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: points │ │ │ │ - * List of points use to calculate the kinetic initial values. │ │ │ │ + * APIProperty: strokeOpacity │ │ │ │ + * {Number} Stroke opacity (0-1). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - points: undefined, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: timerId │ │ │ │ - * ID of the timer. │ │ │ │ + * APIProperty: strokeWidth │ │ │ │ + * {Number} Pixel stroke width. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - timerId: undefined, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Kinetic │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ + * APIProperty: strokeLinecap │ │ │ │ + * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: begin │ │ │ │ - * Begins the dragging. │ │ │ │ + * Property: strokeDashstyle │ │ │ │ + * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ + * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ + * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ + * most SLD patterns will render correctly in OpenLayers. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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. │ │ │ │ + * APIProperty: fillColor │ │ │ │ + * {String} RGB hex fill color (e.g. "#ff0000" for red). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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. │ │ │ │ + * APIProperty: fillOpacity │ │ │ │ + * {Number} Fill opacity (0-1). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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). │ │ │ │ + * APIProperty: pointRadius │ │ │ │ + * {Number} Pixel point radius. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ + /** │ │ │ │ + * APIProperty: externalGraphic │ │ │ │ + * {String} Url to an external graphic that will be used for rendering │ │ │ │ + * points. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ - var lastX = 0; │ │ │ │ - var lastY = 0; │ │ │ │ + /** │ │ │ │ + * APIProperty: graphicWidth │ │ │ │ + * {Number} Pixel width for sizing an external graphic. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ - var timerCallback = function() { │ │ │ │ - if (this.timerId == null) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: graphicHeight │ │ │ │ + * {Number} Pixel height for sizing an external graphic. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ - var t = new Date().getTime() - initialTime; │ │ │ │ + /** │ │ │ │ + * APIProperty: graphicOpacity │ │ │ │ + * {Number} Opacity (0-1) for an external graphic. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ - var p = (-this.deceleration * Math.pow(t, 2)) / 2.0 + v0 * t; │ │ │ │ - var x = p * fx; │ │ │ │ - var y = p * fy; │ │ │ │ + /** │ │ │ │ + * APIProperty: graphicXOffset │ │ │ │ + * {Number} Pixel offset along the positive x axis for displacing an │ │ │ │ + * external graphic. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ - var args = {}; │ │ │ │ - args.end = false; │ │ │ │ - var v = -this.deceleration * t + v0; │ │ │ │ + /** │ │ │ │ + * APIProperty: graphicYOffset │ │ │ │ + * {Number} Pixel offset along the positive y axis for displacing an │ │ │ │ + * external graphic. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (v <= 0) { │ │ │ │ - OpenLayers.Animation.stop(this.timerId); │ │ │ │ - this.timerId = null; │ │ │ │ - args.end = true; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: rotation │ │ │ │ + * {Number} The rotation of a graphic in the clockwise direction about its │ │ │ │ + * center point (or any point off center as specified by │ │ │ │ + * <graphicXOffset> and <graphicYOffset>). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ - args.x = x - lastX; │ │ │ │ - args.y = y - lastY; │ │ │ │ - lastX = x; │ │ │ │ - lastY = y; │ │ │ │ - callback(args.x, args.y, args.end); │ │ │ │ - }; │ │ │ │ + /** │ │ │ │ + * APIProperty: graphicName │ │ │ │ + * {String} Named graphic to use when rendering points. Supported values │ │ │ │ + * include "circle", "square", "star", "x", "cross", and "triangle". │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ - this.timerId = OpenLayers.Animation.start( │ │ │ │ - OpenLayers.Function.bind(timerCallback, this) │ │ │ │ - ); │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Symbolizer.Point │ │ │ │ + * Create a symbolizer for rendering points. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ + * construction. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * A new point symbolizer. │ │ │ │ + */ │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Kinetic" │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Point" │ │ │ │ + │ │ │ │ }); │ │ │ │ + │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/GeoRSS.js │ │ │ │ + OpenLayers/Symbolizer/Line.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/Markers.js │ │ │ │ - * @requires OpenLayers/Request/XMLHttpRequest.js │ │ │ │ + * @requires OpenLayers/Symbolizer.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.GeoRSS │ │ │ │ - * Add GeoRSS Point features to your map. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Markers> │ │ │ │ + * Class: OpenLayers.Symbolizer.Line │ │ │ │ + * A symbolizer used to render line features. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.GeoRSS = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: location │ │ │ │ - * {String} store url of text file │ │ │ │ - */ │ │ │ │ - location: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: features │ │ │ │ - * {Array(<OpenLayers.Feature>)} │ │ │ │ - */ │ │ │ │ - features: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: formatOptions │ │ │ │ - * {Object} Hash of options which should be passed to the format when it is │ │ │ │ - * created. Must be passed in the constructor. │ │ │ │ - */ │ │ │ │ - formatOptions: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: selectedFeature │ │ │ │ - * {<OpenLayers.Feature>} │ │ │ │ - */ │ │ │ │ - selectedFeature: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: icon │ │ │ │ - * {<OpenLayers.Icon>}. This determines the Icon to be used on the map │ │ │ │ - * for this GeoRSS layer. │ │ │ │ - */ │ │ │ │ - icon: null, │ │ │ │ +OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: popupSize │ │ │ │ - * {<OpenLayers.Size>} This determines the size of GeoRSS popups. If │ │ │ │ - * not provided, defaults to 250px by 120px. │ │ │ │ - */ │ │ │ │ - popupSize: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: useFeedTitle │ │ │ │ - * {Boolean} Set layer.name to the first <title> element in the feed. Default is true. │ │ │ │ + * APIProperty: strokeColor │ │ │ │ + * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ + * for red). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - useFeedTitle: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.GeoRSS │ │ │ │ - * Create a GeoRSS Layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * location - {String} │ │ │ │ - * options - {Object} │ │ │ │ + * APIProperty: strokeOpacity │ │ │ │ + * {Number} Stroke opacity (0-1). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - initialize: function(name, location, options) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.initialize.apply(this, [name, options]); │ │ │ │ - this.location = location; │ │ │ │ - this.features = []; │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroy │ │ │ │ + * APIProperty: strokeWidth │ │ │ │ + * {Number} Pixel stroke width. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - // Warning: Layer.Markers.destroy() must be called prior to calling │ │ │ │ - // clearFeatures() here, otherwise we leak memory. Indeed, if │ │ │ │ - // Layer.Markers.destroy() is called after clearFeatures(), it won't be │ │ │ │ - // able to remove the marker image elements from the layer's div since │ │ │ │ - // the markers will have been destroyed by clearFeatures(). │ │ │ │ - OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ - this.clearFeatures(); │ │ │ │ - this.features = null; │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: loadRSS │ │ │ │ - * Start the load of the RSS data. Don't do this when we first add the layer, │ │ │ │ - * since we may not be visible at any point, and it would therefore be a waste. │ │ │ │ + * APIProperty: strokeLinecap │ │ │ │ + * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - loadRSS: function() { │ │ │ │ - if (!this.loaded) { │ │ │ │ - this.events.triggerEvent("loadstart"); │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ - url: this.location, │ │ │ │ - success: this.parseData, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.loaded = true; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: moveTo │ │ │ │ - * If layer is visible and RSS has not been loaded, load RSS. │ │ │ │ + * Property: strokeDashstyle │ │ │ │ + * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ + * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ + * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ + * most SLD patterns will render correctly in OpenLayers. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {Object} │ │ │ │ - * zoomChanged - {Object} │ │ │ │ - * minor - {Object} │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ - if (this.visibility && !this.loaded) { │ │ │ │ - this.loadRSS(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseData │ │ │ │ - * Parse the data returned from the Events call. │ │ │ │ + * Constructor: OpenLayers.Symbolizer.Line │ │ │ │ + * Create a symbolizer for rendering lines. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * ajaxRequest - {<OpenLayers.Request.XMLHttpRequest>} │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ + * construction. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * A new line symbolizer. │ │ │ │ */ │ │ │ │ - parseData: function(ajaxRequest) { │ │ │ │ - var doc = ajaxRequest.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = OpenLayers.Format.XML.prototype.read(ajaxRequest.responseText); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.useFeedTitle) { │ │ │ │ - var name = null; │ │ │ │ - try { │ │ │ │ - name = doc.getElementsByTagNameNS('*', 'title')[0].firstChild.nodeValue; │ │ │ │ - } catch (e) { │ │ │ │ - try { │ │ │ │ - name = doc.getElementsByTagName('title')[0].firstChild.nodeValue; │ │ │ │ - } catch (e) {} │ │ │ │ - } │ │ │ │ - if (name) { │ │ │ │ - this.setName(name); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - var options = {}; │ │ │ │ - │ │ │ │ - OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ - options.externalProjection = this.projection; │ │ │ │ - options.internalProjection = this.map.getProjectionObject(); │ │ │ │ - } │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Line" │ │ │ │ │ │ │ │ - var format = new OpenLayers.Format.GeoRSS(options); │ │ │ │ - var features = format.read(doc); │ │ │ │ +}); │ │ │ │ │ │ │ │ - for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ - var data = {}; │ │ │ │ - var feature = features[i]; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Symbolizer/Polygon.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - // we don't support features with no geometry in the GeoRSS │ │ │ │ - // layer at this time. │ │ │ │ - if (!feature.geometry) { │ │ │ │ - continue; │ │ │ │ - } │ │ │ │ +/* 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 title = feature.attributes.title ? │ │ │ │ - feature.attributes.title : "Untitled"; │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Symbolizer.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - var description = feature.attributes.description ? │ │ │ │ - feature.attributes.description : "No description."; │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Symbolizer.Polygon │ │ │ │ + * A symbolizer used to render line features. │ │ │ │ + */ │ │ │ │ +OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ │ │ │ - var link = feature.attributes.link ? feature.attributes.link : ""; │ │ │ │ + /** │ │ │ │ + * APIProperty: strokeColor │ │ │ │ + * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ + * for red). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ - var location = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ + /** │ │ │ │ + * APIProperty: strokeOpacity │ │ │ │ + * {Number} Stroke opacity (0-1). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ + /** │ │ │ │ + * APIProperty: strokeWidth │ │ │ │ + * {Number} Pixel stroke width. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ - data.icon = this.icon == null ? │ │ │ │ - OpenLayers.Marker.defaultIcon() : │ │ │ │ - this.icon.clone(); │ │ │ │ + /** │ │ │ │ + * APIProperty: strokeLinecap │ │ │ │ + * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ - data.popupSize = this.popupSize ? │ │ │ │ - this.popupSize.clone() : │ │ │ │ - new OpenLayers.Size(250, 120); │ │ │ │ + /** │ │ │ │ + * Property: strokeDashstyle │ │ │ │ + * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ + * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ + * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ + * most SLD patterns will render correctly in OpenLayers. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (title || description) { │ │ │ │ - // we have supplemental data, store them. │ │ │ │ - data.title = title; │ │ │ │ - data.description = description; │ │ │ │ + /** │ │ │ │ + * APIProperty: fillColor │ │ │ │ + * {String} RGB hex fill color (e.g. "#ff0000" for red). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ - var contentHTML = '<div class="olLayerGeoRSSClose">[x]</div>'; │ │ │ │ - contentHTML += '<div class="olLayerGeoRSSTitle">'; │ │ │ │ - if (link) { │ │ │ │ - contentHTML += '<a class="link" href="' + link + '" target="_blank">'; │ │ │ │ - } │ │ │ │ - contentHTML += title; │ │ │ │ - if (link) { │ │ │ │ - contentHTML += '</a>'; │ │ │ │ - } │ │ │ │ - contentHTML += '</div>'; │ │ │ │ - contentHTML += '<div style="" class="olLayerGeoRSSDescription">'; │ │ │ │ - contentHTML += description; │ │ │ │ - contentHTML += '</div>'; │ │ │ │ - data['popupContentHTML'] = contentHTML; │ │ │ │ - } │ │ │ │ - var feature = new OpenLayers.Feature(this, location, data); │ │ │ │ - this.features.push(feature); │ │ │ │ - var marker = feature.createMarker(); │ │ │ │ - marker.events.register('click', feature, this.markerClick); │ │ │ │ - this.addMarker(marker); │ │ │ │ - } │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * APIProperty: fillOpacity │ │ │ │ + * {Number} Fill opacity (0-1). │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: markerClick │ │ │ │ + * Constructor: OpenLayers.Symbolizer.Polygon │ │ │ │ + * Create a symbolizer for rendering polygons. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ + * construction. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * A new polygon symbolizer. │ │ │ │ */ │ │ │ │ - markerClick: function(evt) { │ │ │ │ - var sameMarkerClicked = (this == this.layer.selectedFeature); │ │ │ │ - this.layer.selectedFeature = (!sameMarkerClicked) ? this : null; │ │ │ │ - for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ - this.layer.map.removePopup(this.layer.map.popups[i]); │ │ │ │ - } │ │ │ │ - if (!sameMarkerClicked) { │ │ │ │ - var popup = this.createPopup(); │ │ │ │ - OpenLayers.Event.observe(popup.div, "click", │ │ │ │ - OpenLayers.Function.bind(function() { │ │ │ │ - for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ - this.layer.map.removePopup(this.layer.map.popups[i]); │ │ │ │ - } │ │ │ │ - }, this) │ │ │ │ - ); │ │ │ │ - this.layer.map.addPopup(popup); │ │ │ │ - } │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: clearFeatures │ │ │ │ - * Destroy all features in this layer. │ │ │ │ - */ │ │ │ │ - clearFeatures: function() { │ │ │ │ - if (this.features != null) { │ │ │ │ - while (this.features.length > 0) { │ │ │ │ - var feature = this.features[0]; │ │ │ │ - OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ - feature.destroy(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Polygon" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.GeoRSS" │ │ │ │ }); │ │ │ │ + │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/XYZ.js │ │ │ │ + OpenLayers/Symbolizer/Text.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 │ │ │ │ + * @requires OpenLayers/Symbolizer.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> │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Symbolizer.Text │ │ │ │ + * A symbolizer used to render text labels for features. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ +OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * Default is true, as this is designed to be a base tile source. │ │ │ │ + /** │ │ │ │ + * APIProperty: label │ │ │ │ + * {String} The text for the label. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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. │ │ │ │ + /** │ │ │ │ + * APIProperty: fontFamily │ │ │ │ + * {String} The font family for the label. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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. │ │ │ │ + /** │ │ │ │ + * APIProperty: fontSize │ │ │ │ + * {String} The font size for the label. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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. │ │ │ │ + /** │ │ │ │ + * APIProperty: fontWeight │ │ │ │ + * {String} The font weight for the label. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - serverResolutions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.XYZ │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * url - {String} │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ + * Property: fontStyle │ │ │ │ + * {String} The font style for the label. │ │ │ │ + * │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + * Constructor: OpenLayers.Symbolizer.Text │ │ │ │ + * Create a symbolizer for rendering text labels. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * obj - {Object} Is this ever used? │ │ │ │ - * │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ + * construction. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Layer.XYZ>} An exact clone of this OpenLayers.Layer.XYZ │ │ │ │ + * A new text symbolizer. │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.XYZ(this.name, │ │ │ │ - this.url, │ │ │ │ - this.getOptions()); │ │ │ │ - } │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Text" │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ +}); │ │ │ │ │ │ │ │ - return obj; │ │ │ │ - }, │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Symbolizer/Raster.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - } │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - return OpenLayers.String.format(url, xyz); │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Symbolizer.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Symbolizer.Raster │ │ │ │ + * A symbolizer used to render raster images. │ │ │ │ + */ │ │ │ │ +OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getXYZ │ │ │ │ - * Calculates x, y and z for the given bounds. │ │ │ │ + * Constructor: OpenLayers.Symbolizer.Raster │ │ │ │ + * Create a symbolizer for rendering rasters. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ + * construction. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} - an object with x, y and z properties. │ │ │ │ + * A new raster symbolizer. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }; │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - /* 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.Symbolizer.Raster" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.XYZ" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/ArcGISCache.js │ │ │ │ + OpenLayers/Style2.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 │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ + * @requires OpenLayers/Rule.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Point.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Line.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Polygon.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Text.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Raster.js │ │ │ │ */ │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Layer.ArcGISCache │ │ │ │ - * Layer for accessing cached map tiles from an ArcGIS Server style mapcache. │ │ │ │ - * Tile must already be cached for this layer to access it. This does not require │ │ │ │ - * ArcGIS Server itself. │ │ │ │ - * │ │ │ │ - * A few attempts have been made at this kind of layer before. See │ │ │ │ - * http://trac.osgeo.org/openlayers/ticket/1967 │ │ │ │ - * and │ │ │ │ - * http://trac.osgeo.org/openlayers/browser/sandbox/tschaub/arcgiscache/lib/OpenLayers/Layer/ArcGISCache.js │ │ │ │ - * │ │ │ │ - * Typically the problem encountered is that the tiles seem to "jump around". │ │ │ │ - * This is due to the fact that the actual max extent for the tiles on AGS layers │ │ │ │ - * changes at each zoom level due to the way these caches are constructed. │ │ │ │ - * We have attempted to use the resolutions, tile size, and tile origin │ │ │ │ - * from the cache meta data to make the appropriate changes to the max extent │ │ │ │ - * of the tile to compensate for this behavior. This must be done as zoom levels change │ │ │ │ - * and before tiles are requested, which is why methods from base classes are overridden. │ │ │ │ - * │ │ │ │ - * For reference, you can access mapcache meta data in two ways. For accessing a │ │ │ │ - * mapcache through ArcGIS Server, you can simply go to the landing page for the │ │ │ │ - * layer. (ie. http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer) │ │ │ │ - * For accessing it directly through HTTP, there should always be a conf.xml file │ │ │ │ - * in the root directory. │ │ │ │ - * (ie. http://serverx.esri.com/arcgiscache/DG_County_roads_yesA_backgroundDark/Layers/conf.xml) │ │ │ │ - * │ │ │ │ - *Inherits from: │ │ │ │ - * - <OpenLayers.Layer.XYZ> │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Style2 │ │ │ │ + * This class represents a collection of rules for rendering features. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.ArcGISCache = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ +OpenLayers.Style2 = OpenLayers.Class({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: url │ │ │ │ - * {String | Array} The base URL for the layer cache. You can also │ │ │ │ - * provide a list of URL strings for the layer if your cache is │ │ │ │ - * available from multiple origins. This must be set before the layer │ │ │ │ - * is drawn. │ │ │ │ + * Property: id │ │ │ │ + * {String} A unique id for this session. │ │ │ │ */ │ │ │ │ - url: null, │ │ │ │ + id: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: tileOrigin │ │ │ │ - * {<OpenLayers.LonLat>} The location of the tile origin for the cache. │ │ │ │ - * An ArcGIS cache has it's origin at the upper-left (lowest x value │ │ │ │ - * and highest y value of the coordinate system). The units for the │ │ │ │ - * tile origin should be the same as the units for the cached data. │ │ │ │ + * APIProperty: name │ │ │ │ + * {String} Style identifier. │ │ │ │ */ │ │ │ │ - tileOrigin: null, │ │ │ │ + name: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: tileSize │ │ │ │ - * {<OpenLayers.Size>} This size of each tile. Defaults to 256 by 256 pixels. │ │ │ │ + * APIProperty: title │ │ │ │ + * {String} Title of this style. │ │ │ │ */ │ │ │ │ - tileSize: new OpenLayers.Size(256, 256), │ │ │ │ + title: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: useAGS │ │ │ │ - * {Boolean} Indicates if we are going to be accessing the ArcGIS Server (AGS) │ │ │ │ - * cache via an AGS MapServer or directly through HTTP. When accessing via │ │ │ │ - * AGS the path structure uses a standard z/y/x structure. But AGS actually │ │ │ │ - * stores the tile images on disk using a hex based folder structure that looks │ │ │ │ - * like "http://example.com/mylayer/L00/R00000000/C00000000.png". Learn more │ │ │ │ - * about this here: │ │ │ │ - * http://blogs.esri.com/Support/blogs/mappingcenter/archive/2010/08/20/Checking-Your-Local-Cache-Folders.aspx │ │ │ │ - * Defaults to true; │ │ │ │ + * APIProperty: description │ │ │ │ + * {String} Description of this style. │ │ │ │ */ │ │ │ │ - useArcGISServer: true, │ │ │ │ + description: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: type │ │ │ │ - * {String} Image type for the layer. This becomes the filename extension │ │ │ │ - * in tile requests. Default is "png" (generating a url like │ │ │ │ - * "http://example.com/mylayer/L00/R00000000/C00000000.png"). │ │ │ │ + * APIProperty: layerName │ │ │ │ + * {<String>} Name of the layer that this style belongs to, usually │ │ │ │ + * according to the NamedLayer attribute of an SLD document. │ │ │ │ */ │ │ │ │ - type: 'png', │ │ │ │ + layerName: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: useScales │ │ │ │ - * {Boolean} Optional override to indicate that the layer should use 'scale' information │ │ │ │ - * returned from the server capabilities object instead of 'resolution' information. │ │ │ │ - * This can be important if your tile server uses an unusual DPI for the tiles. │ │ │ │ + * APIProperty: isDefault │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - useScales: false, │ │ │ │ + isDefault: false, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: overrideDPI │ │ │ │ - * {Boolean} Optional override to change the OpenLayers.DOTS_PER_INCH setting based │ │ │ │ - * on the tile information in the server capabilities object. This can be useful │ │ │ │ - * if your server has a non-standard DPI setting on its tiles, and you're only using │ │ │ │ - * tiles with that DPI. This value is used while OpenLayers is calculating resolution │ │ │ │ - * using scales, and is not necessary if you have resolution information. (This is │ │ │ │ - * typically the case) Regardless, this setting can be useful, but is dangerous │ │ │ │ - * because it will impact other layers while calculating resolution. Only use this │ │ │ │ - * if you know what you are doing. (See OpenLayers.Util.getResolutionFromScale) │ │ │ │ + /** │ │ │ │ + * APIProperty: rules │ │ │ │ + * {Array(<OpenLayers.Rule>)} Collection of rendering rules. │ │ │ │ */ │ │ │ │ - overrideDPI: false, │ │ │ │ + rules: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.ArcGISCache │ │ │ │ - * Creates a new instance of this class │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * url - {String} │ │ │ │ - * options - {Object} extra layer options │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Style2 │ │ │ │ + * Creates a style representing a collection of rendering rules. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ + * style. Any documented properties may be set at construction. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Style2>} A new style object. │ │ │ │ */ │ │ │ │ - initialize: function(name, url, options) { │ │ │ │ - OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments); │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Util.extend(this, config); │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (this.resolutions) { │ │ │ │ - this.serverResolutions = this.resolutions; │ │ │ │ - this.maxExtent = this.getMaxExtentForResolution(this.resolutions[0]); │ │ │ │ + /** │ │ │ │ + * 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(); │ │ │ │ } │ │ │ │ + delete this.rules; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // this block steps through translating the values from the server layer JSON │ │ │ │ - // capabilities object into values that we can use. This is also a helpful │ │ │ │ - // reference when configuring this layer directly. │ │ │ │ - if (this.layerInfo) { │ │ │ │ - // alias the object │ │ │ │ - var info = this.layerInfo; │ │ │ │ - │ │ │ │ - // build our extents │ │ │ │ - var startingTileExtent = new OpenLayers.Bounds( │ │ │ │ - info.fullExtent.xmin, │ │ │ │ - info.fullExtent.ymin, │ │ │ │ - info.fullExtent.xmax, │ │ │ │ - info.fullExtent.ymax │ │ │ │ - ); │ │ │ │ - │ │ │ │ - // set our projection based on the given spatial reference. │ │ │ │ - // esri uses slightly different IDs, so this may not be comprehensive │ │ │ │ - this.projection = 'EPSG:' + info.spatialReference.wkid; │ │ │ │ - this.sphericalMercator = (info.spatialReference.wkid == 102100); │ │ │ │ - │ │ │ │ - // convert esri units into openlayers units (basic feet or meters only) │ │ │ │ - this.units = (info.units == "esriFeet") ? 'ft' : 'm'; │ │ │ │ - │ │ │ │ - // optional extended section based on whether or not the server returned │ │ │ │ - // specific tile information │ │ │ │ - if (!!info.tileInfo) { │ │ │ │ - // either set the tiles based on rows/columns, or specific width/height │ │ │ │ - this.tileSize = new OpenLayers.Size( │ │ │ │ - info.tileInfo.width || info.tileInfo.cols, │ │ │ │ - info.tileInfo.height || info.tileInfo.rows │ │ │ │ - ); │ │ │ │ - │ │ │ │ - // this must be set when manually configuring this layer │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat( │ │ │ │ - info.tileInfo.origin.x, │ │ │ │ - info.tileInfo.origin.y │ │ │ │ - ); │ │ │ │ - │ │ │ │ - var upperLeft = new OpenLayers.Geometry.Point( │ │ │ │ - startingTileExtent.left, │ │ │ │ - startingTileExtent.top │ │ │ │ - ); │ │ │ │ - │ │ │ │ - var bottomRight = new OpenLayers.Geometry.Point( │ │ │ │ - startingTileExtent.right, │ │ │ │ - startingTileExtent.bottom │ │ │ │ - ); │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * Clones this style. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Style2>} Clone of this style. │ │ │ │ + */ │ │ │ │ + clone: function() { │ │ │ │ + var config = OpenLayers.Util.extend({}, this); │ │ │ │ + // clone rules │ │ │ │ + if (this.rules) { │ │ │ │ + config.rules = []; │ │ │ │ + for (var i = 0, len = this.rules.length; i < len; ++i) { │ │ │ │ + config.rules.push(this.rules[i].clone()); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return new OpenLayers.Style2(config); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (this.useScales) { │ │ │ │ - this.scales = []; │ │ │ │ - } else { │ │ │ │ - this.resolutions = []; │ │ │ │ - } │ │ │ │ + CLASS_NAME: "OpenLayers.Style2" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Tile/UTFGrid.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - this.lods = []; │ │ │ │ - for (var key in info.tileInfo.lods) { │ │ │ │ - if (info.tileInfo.lods.hasOwnProperty(key)) { │ │ │ │ - var lod = info.tileInfo.lods[key]; │ │ │ │ - if (this.useScales) { │ │ │ │ - this.scales.push(lod.scale); │ │ │ │ - } else { │ │ │ │ - this.resolutions.push(lod.resolution); │ │ │ │ - } │ │ │ │ +/* 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 start = this.getContainingTileCoords(upperLeft, lod.resolution); │ │ │ │ - lod.startTileCol = start.x; │ │ │ │ - lod.startTileRow = start.y; │ │ │ │ │ │ │ │ - var end = this.getContainingTileCoords(bottomRight, lod.resolution); │ │ │ │ - lod.endTileCol = end.x; │ │ │ │ - lod.endTileRow = end.y; │ │ │ │ - this.lods.push(lod); │ │ │ │ - } │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Tile.js │ │ │ │ + * @requires OpenLayers/Format/JSON.js │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - this.maxExtent = this.calculateMaxExtentWithLOD(this.lods[0]); │ │ │ │ - this.serverResolutions = this.resolutions; │ │ │ │ - if (this.overrideDPI && info.tileInfo.dpi) { │ │ │ │ - // see comment above for 'overrideDPI' │ │ │ │ - OpenLayers.DOTS_PER_INCH = info.tileInfo.dpi; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Tile.UTFGrid │ │ │ │ + * Instances of OpenLayers.Tile.UTFGrid are used to manage │ │ │ │ + * UTFGrids. This is an unusual tile type in that it doesn't have a │ │ │ │ + * rendered image; only a 'hit grid' that can be used to │ │ │ │ + * look up feature attributes. │ │ │ │ + * │ │ │ │ + * See the <OpenLayers.Tile.UTFGrid> constructor for details on constructing a │ │ │ │ + * new instance. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Tile> │ │ │ │ + */ │ │ │ │ +OpenLayers.Tile.UTFGrid = OpenLayers.Class(OpenLayers.Tile, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getContainingTileCoords │ │ │ │ - * Calculates the x/y pixel corresponding to the position of the tile │ │ │ │ - * that contains the given point and for the for the given resolution. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * point - {<OpenLayers.Geometry.Point>} │ │ │ │ - * res - {Float} The resolution for which to compute the extent. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Pixel>} The x/y pixel corresponding to the position │ │ │ │ - * of the upper left tile for the given resolution. │ │ │ │ + * Property: url │ │ │ │ + * {String} │ │ │ │ + * The URL of the UTFGrid file being requested. Provided by the <getURL> │ │ │ │ + * method. │ │ │ │ */ │ │ │ │ - getContainingTileCoords: function(point, res) { │ │ │ │ - return new OpenLayers.Pixel( │ │ │ │ - Math.max(Math.floor((point.x - this.tileOrigin.lon) / (this.tileSize.w * res)), 0), │ │ │ │ - Math.max(Math.floor((this.tileOrigin.lat - point.y) / (this.tileSize.h * res)), 0) │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ + url: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: calculateMaxExtentWithLOD │ │ │ │ - * Given a Level of Detail object from the server, this function │ │ │ │ - * calculates the actual max extent │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * lod - {Object} a Level of Detail Object from the server capabilities object │ │ │ │ - representing a particular zoom level │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} The actual extent of the tiles for the given zoom level │ │ │ │ + /** │ │ │ │ + * Property: utfgridResolution │ │ │ │ + * {Number} │ │ │ │ + * Ratio of the pixel width to the width of a UTFGrid data point. If an │ │ │ │ + * entry in the grid represents a 4x4 block of pixels, the │ │ │ │ + * utfgridResolution would be 4. Default is 2. │ │ │ │ */ │ │ │ │ - calculateMaxExtentWithLOD: function(lod) { │ │ │ │ - // the max extent we're provided with just overlaps some tiles │ │ │ │ - // our real extent is the bounds of all the tiles we touch │ │ │ │ - │ │ │ │ - var numTileCols = (lod.endTileCol - lod.startTileCol) + 1; │ │ │ │ - var numTileRows = (lod.endTileRow - lod.startTileRow) + 1; │ │ │ │ - │ │ │ │ - var minX = this.tileOrigin.lon + (lod.startTileCol * this.tileSize.w * lod.resolution); │ │ │ │ - var maxX = minX + (numTileCols * this.tileSize.w * lod.resolution); │ │ │ │ - │ │ │ │ - var maxY = this.tileOrigin.lat - (lod.startTileRow * this.tileSize.h * lod.resolution); │ │ │ │ - var minY = maxY - (numTileRows * this.tileSize.h * lod.resolution); │ │ │ │ - return new OpenLayers.Bounds(minX, minY, maxX, maxY); │ │ │ │ - }, │ │ │ │ + utfgridResolution: 2, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: calculateMaxExtentWithExtent │ │ │ │ - * Given a 'suggested' max extent from the server, this function uses │ │ │ │ - * information about the actual tile sizes to determine the actual │ │ │ │ - * extent of the layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * extent - {<OpenLayers.Bounds>} The 'suggested' extent for the layer │ │ │ │ - * res - {Float} The resolution for which to compute the extent. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} The actual extent of the tiles for the given zoom level │ │ │ │ + * Property: json │ │ │ │ + * {Object} │ │ │ │ + * Stores the parsed JSON tile data structure. │ │ │ │ */ │ │ │ │ - calculateMaxExtentWithExtent: function(extent, res) { │ │ │ │ - var upperLeft = new OpenLayers.Geometry.Point(extent.left, extent.top); │ │ │ │ - var bottomRight = new OpenLayers.Geometry.Point(extent.right, extent.bottom); │ │ │ │ - var start = this.getContainingTileCoords(upperLeft, res); │ │ │ │ - var end = this.getContainingTileCoords(bottomRight, res); │ │ │ │ - var lod = { │ │ │ │ - resolution: res, │ │ │ │ - startTileCol: start.x, │ │ │ │ - startTileRow: start.y, │ │ │ │ - endTileCol: end.x, │ │ │ │ - endTileRow: end.y │ │ │ │ - }; │ │ │ │ - return this.calculateMaxExtentWithLOD(lod); │ │ │ │ - }, │ │ │ │ + json: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getUpperLeftTileCoord │ │ │ │ - * Calculates the x/y pixel corresponding to the position │ │ │ │ - * of the upper left tile for the given resolution. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * res - {Float} The resolution for which to compute the extent. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Pixel>} The x/y pixel corresponding to the position │ │ │ │ - * of the upper left tile for the given resolution. │ │ │ │ + * Property: format │ │ │ │ + * {OpenLayers.Format.JSON} │ │ │ │ + * Parser instance used to parse JSON for cross browser support. The native │ │ │ │ + * JSON.parse method will be used where available (all except IE<8). │ │ │ │ */ │ │ │ │ - getUpperLeftTileCoord: function(res) { │ │ │ │ - var upperLeft = new OpenLayers.Geometry.Point( │ │ │ │ - this.maxExtent.left, │ │ │ │ - this.maxExtent.top); │ │ │ │ - return this.getContainingTileCoords(upperLeft, res); │ │ │ │ - }, │ │ │ │ + format: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getLowerRightTileCoord │ │ │ │ - * Calculates the x/y pixel corresponding to the position │ │ │ │ - * of the lower right tile for the given resolution. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * res - {Float} The resolution for which to compute the extent. │ │ │ │ + * Constructor: OpenLayers.Tile.UTFGrid │ │ │ │ + * Constructor for a new <OpenLayers.Tile.UTFGrid> instance. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Pixel>} The x/y pixel corresponding to the position │ │ │ │ - * of the lower right tile for the given resolution. │ │ │ │ + * 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} │ │ │ │ */ │ │ │ │ - getLowerRightTileCoord: function(res) { │ │ │ │ - var bottomRight = new OpenLayers.Geometry.Point( │ │ │ │ - this.maxExtent.right, │ │ │ │ - this.maxExtent.bottom); │ │ │ │ - return this.getContainingTileCoords(bottomRight, res); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getMaxExtentForResolution │ │ │ │ - * Since the max extent of a set of tiles can change from zoom level │ │ │ │ - * to zoom level, we need to be able to calculate that max extent │ │ │ │ - * for a given resolution. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * res - {Float} The resolution for which to compute the extent. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} The extent for this resolution │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Clean up. │ │ │ │ */ │ │ │ │ - getMaxExtentForResolution: function(res) { │ │ │ │ - var start = this.getUpperLeftTileCoord(res); │ │ │ │ - var end = this.getLowerRightTileCoord(res); │ │ │ │ - │ │ │ │ - var numTileCols = (end.x - start.x) + 1; │ │ │ │ - var numTileRows = (end.y - start.y) + 1; │ │ │ │ - │ │ │ │ - var minX = this.tileOrigin.lon + (start.x * this.tileSize.w * res); │ │ │ │ - var maxX = minX + (numTileCols * this.tileSize.w * res); │ │ │ │ - │ │ │ │ - var maxY = this.tileOrigin.lat - (start.y * this.tileSize.h * res); │ │ │ │ - var minY = maxY - (numTileRows * this.tileSize.h * res); │ │ │ │ - return new OpenLayers.Bounds(minX, minY, maxX, maxY); │ │ │ │ + destroy: function() { │ │ │ │ + this.clear(); │ │ │ │ + OpenLayers.Tile.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Returns an exact clone of this OpenLayers.Layer.ArcGISCache │ │ │ │ + /** │ │ │ │ + * Method: draw │ │ │ │ + * Check that a tile should be drawn, and draw it. │ │ │ │ + * In the case of UTFGrids, "drawing" it means fetching and │ │ │ │ + * parsing the json. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * [obj] - {Object} optional object to assign the cloned instance to. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.ArcGISCache>} clone of this instance │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Was a tile drawn? │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.ArcGISCache(this.name, this.url, this.options); │ │ │ │ + draw: function() { │ │ │ │ + var drawn = OpenLayers.Tile.prototype.draw.apply(this, arguments); │ │ │ │ + if (drawn) { │ │ │ │ + if (this.isLoading) { │ │ │ │ + this.abortLoading(); │ │ │ │ + //if we're already loading, send 'reload' instead of 'loadstart'. │ │ │ │ + this.events.triggerEvent("reload"); │ │ │ │ + } else { │ │ │ │ + this.isLoading = true; │ │ │ │ + this.events.triggerEvent("loadstart"); │ │ │ │ + } │ │ │ │ + this.url = this.layer.getURL(this.bounds); │ │ │ │ + │ │ │ │ + if (this.layer.useJSONP) { │ │ │ │ + // Use JSONP method to avoid xbrowser policy │ │ │ │ + var ols = new OpenLayers.Protocol.Script({ │ │ │ │ + url: this.url, │ │ │ │ + callback: function(response) { │ │ │ │ + this.isLoading = false; │ │ │ │ + this.events.triggerEvent("loadend"); │ │ │ │ + this.json = response.data; │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + ols.read(); │ │ │ │ + this.request = ols; │ │ │ │ + } else { │ │ │ │ + // Use standard XHR │ │ │ │ + this.request = OpenLayers.Request.GET({ │ │ │ │ + url: this.url, │ │ │ │ + callback: function(response) { │ │ │ │ + this.isLoading = false; │ │ │ │ + this.events.triggerEvent("loadend"); │ │ │ │ + if (response.status === 200) { │ │ │ │ + this.parseData(response.responseText); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.unload(); │ │ │ │ } │ │ │ │ - return OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ + return drawn; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: initGriddedTiles │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * Method: abortLoading │ │ │ │ + * Cancel a pending request. │ │ │ │ */ │ │ │ │ - initGriddedTiles: function(bounds) { │ │ │ │ - delete this._tileOrigin; │ │ │ │ - OpenLayers.Layer.XYZ.prototype.initGriddedTiles.apply(this, arguments); │ │ │ │ + abortLoading: function() { │ │ │ │ + if (this.request) { │ │ │ │ + this.request.abort(); │ │ │ │ + delete this.request; │ │ │ │ + } │ │ │ │ + this.isLoading = false; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getMaxExtent │ │ │ │ - * Get this layer's maximum extent. │ │ │ │ + * Method: getFeatureInfo │ │ │ │ + * Get feature information associated with a pixel offset. If the pixel │ │ │ │ + * offset corresponds to a feature, the returned object will have id │ │ │ │ + * and data properties. Otherwise, null will be returned. │ │ │ │ + * │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * i - {Number} X-axis pixel offset (from top left of tile) │ │ │ │ + * j - {Number} Y-axis pixel offset (from top left of tile) │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} │ │ │ │ + * {Object} Object with feature id and data properties corresponding to the │ │ │ │ + * given pixel offset. │ │ │ │ */ │ │ │ │ - getMaxExtent: function() { │ │ │ │ - var resolution = this.map.getResolution(); │ │ │ │ - return this.maxExtent = this.getMaxExtentForResolution(resolution); │ │ │ │ + getFeatureInfo: function(i, j) { │ │ │ │ + var info = null; │ │ │ │ + if (this.json) { │ │ │ │ + var id = this.getFeatureId(i, j); │ │ │ │ + if (id !== null) { │ │ │ │ + info = { │ │ │ │ + id: id, │ │ │ │ + data: this.json.data[id] │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return info; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getTileOrigin │ │ │ │ - * Determine the origin for aligning the grid of tiles. │ │ │ │ - * The origin will be derived from the layer's <maxExtent> property. │ │ │ │ + * Method: getFeatureId │ │ │ │ + * Get the identifier for the feature associated with a pixel offset. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * i - {Number} X-axis pixel offset (from top left of tile) │ │ │ │ + * j - {Number} Y-axis pixel offset (from top left of tile) │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.LonLat>} The tile origin. │ │ │ │ + * {Object} The feature identifier corresponding to the given pixel offset. │ │ │ │ + * Returns null if pixel doesn't correspond to a feature. │ │ │ │ */ │ │ │ │ - getTileOrigin: function() { │ │ │ │ - if (!this._tileOrigin) { │ │ │ │ - var extent = this.getMaxExtent(); │ │ │ │ - this._tileOrigin = new OpenLayers.LonLat(extent.left, extent.bottom); │ │ │ │ + getFeatureId: function(i, j) { │ │ │ │ + var id = null; │ │ │ │ + if (this.json) { │ │ │ │ + var resolution = this.utfgridResolution; │ │ │ │ + var row = Math.floor(j / resolution); │ │ │ │ + var col = Math.floor(i / resolution); │ │ │ │ + var charCode = this.json.grid[row].charCodeAt(col); │ │ │ │ + var index = this.indexFromCharCode(charCode); │ │ │ │ + var keys = this.json.keys; │ │ │ │ + if (!isNaN(index) && (index in keys)) { │ │ │ │ + id = keys[index]; │ │ │ │ + } │ │ │ │ } │ │ │ │ - return this._tileOrigin; │ │ │ │ + return id; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getURL │ │ │ │ - * Determine the URL for a tile given the tile bounds. This is should support │ │ │ │ - * urls that access tiles through an ArcGIS Server MapServer or directly through │ │ │ │ - * the hex folder structure using HTTP. Just be sure to set the useArcGISServer │ │ │ │ - * property appropriately! This is basically the same as │ │ │ │ - * 'OpenLayers.Layer.TMS.getURL', but with the addition of hex addressing, │ │ │ │ - * and tile rounding. │ │ │ │ + * Method: indexFromCharCode │ │ │ │ + * Given a character code for one of the UTFGrid "grid" characters, │ │ │ │ + * resolve the integer index for the feature id in the UTFGrid "keys" │ │ │ │ + * array. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * charCode - {Integer} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} The URL for a tile based on given bounds. │ │ │ │ + * {Integer} Index for the feature id from the keys array. │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - var res = this.getResolution(); │ │ │ │ - │ │ │ │ - // tile center │ │ │ │ - var originTileX = (this.tileOrigin.lon + (res * this.tileSize.w / 2)); │ │ │ │ - var originTileY = (this.tileOrigin.lat - (res * this.tileSize.h / 2)); │ │ │ │ - │ │ │ │ - var center = bounds.getCenterLonLat(); │ │ │ │ - var point = { │ │ │ │ - x: center.lon, │ │ │ │ - y: center.lat │ │ │ │ - }; │ │ │ │ - var x = (Math.round(Math.abs((center.lon - originTileX) / (res * this.tileSize.w)))); │ │ │ │ - var y = (Math.round(Math.abs((originTileY - center.lat) / (res * this.tileSize.h)))); │ │ │ │ - var z = this.map.getZoom(); │ │ │ │ - │ │ │ │ - // this prevents us from getting pink tiles (non-existant tiles) │ │ │ │ - if (this.lods) { │ │ │ │ - var lod = this.lods[this.map.getZoom()]; │ │ │ │ - if ((x < lod.startTileCol || x > lod.endTileCol) || │ │ │ │ - (y < lod.startTileRow || y > lod.endTileRow)) { │ │ │ │ - return null; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - var start = this.getUpperLeftTileCoord(res); │ │ │ │ - var end = this.getLowerRightTileCoord(res); │ │ │ │ - if ((x < start.x || x >= end.x) || │ │ │ │ - (y < start.y || y >= end.y)) { │ │ │ │ - return null; │ │ │ │ - } │ │ │ │ + indexFromCharCode: function(charCode) { │ │ │ │ + if (charCode >= 93) { │ │ │ │ + charCode--; │ │ │ │ } │ │ │ │ - │ │ │ │ - // Construct the url string │ │ │ │ - var url = this.url; │ │ │ │ - var s = '' + x + y + z; │ │ │ │ - │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(s, url); │ │ │ │ + if (charCode >= 35) { │ │ │ │ + charCode--; │ │ │ │ } │ │ │ │ + return charCode - 32; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // Accessing tiles through ArcGIS Server uses a different path │ │ │ │ - // structure than direct access via the folder structure. │ │ │ │ - if (this.useArcGISServer) { │ │ │ │ - // AGS MapServers have pretty url access to tiles │ │ │ │ - url = url + '/tile/${z}/${y}/${x}'; │ │ │ │ - } else { │ │ │ │ - // The tile images are stored using hex values on disk. │ │ │ │ - x = 'C' + OpenLayers.Number.zeroPad(x, 8, 16); │ │ │ │ - y = 'R' + OpenLayers.Number.zeroPad(y, 8, 16); │ │ │ │ - z = 'L' + OpenLayers.Number.zeroPad(z, 2, 10); │ │ │ │ - url = url + '/${z}/${y}/${x}.' + this.type; │ │ │ │ + /** │ │ │ │ + * Method: parseData │ │ │ │ + * Parse the JSON from a request │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * str - {String} UTFGrid as a JSON string. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} parsed javascript data │ │ │ │ + */ │ │ │ │ + parseData: function(str) { │ │ │ │ + if (!this.format) { │ │ │ │ + this.format = new OpenLayers.Format.JSON(); │ │ │ │ } │ │ │ │ + this.json = this.format.read(str); │ │ │ │ + }, │ │ │ │ │ │ │ │ - // Write the values into our formatted url │ │ │ │ - url = OpenLayers.String.format(url, { │ │ │ │ - 'x': x, │ │ │ │ - 'y': y, │ │ │ │ - 'z': z │ │ │ │ - }); │ │ │ │ - │ │ │ │ - return OpenLayers.Util.urlAppend( │ │ │ │ - url, OpenLayers.Util.getParameterString(this.params) │ │ │ │ - ); │ │ │ │ + /** │ │ │ │ + * Method: clear │ │ │ │ + * Delete data stored with this tile. │ │ │ │ + */ │ │ │ │ + clear: function() { │ │ │ │ + this.json = null; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: 'OpenLayers.Layer.ArcGISCache' │ │ │ │ + CLASS_NAME: "OpenLayers.Tile.UTFGrid" │ │ │ │ + │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/Bing.js │ │ │ │ + OpenLayers/Tile/Image/IFrame.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 │ │ │ │ + * @requires OpenLayers/Tile/Image.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> │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Tile.Image.IFrame │ │ │ │ + * Mixin for tiles that use form-encoded POST requests to get images from │ │ │ │ + * remote services. Images will be loaded using HTTP-POST into an IFrame. │ │ │ │ + * │ │ │ │ + * This mixin will be applied to <OpenLayers.Tile.Image> instances │ │ │ │ + * configured with <OpenLayers.Tile.Image.maxGetUrlLength> set. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ +OpenLayers.Tile.Image.IFrame = { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: key │ │ │ │ - * {String} API key for Bing maps, get your own key │ │ │ │ - * at http://bingmapsportal.com/ . │ │ │ │ + * Property: useIFrame │ │ │ │ + * {Boolean} true if we are currently using an IFrame to render POST │ │ │ │ + * responses, false if we are using an img element to render GET responses. │ │ │ │ */ │ │ │ │ - key: null, │ │ │ │ + useIFrame: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: serverResolutions │ │ │ │ - * {Array} the resolutions provided by the Bing servers. │ │ │ │ + * Property: blankImageUrl │ │ │ │ + * {String} Using a data scheme url is not supported by all browsers, but │ │ │ │ + * we don't care because we either set it as css backgroundImage, or the │ │ │ │ + * image's display style is set to "none" when we use it. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - ], │ │ │ │ + blankImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: attributionTemplate │ │ │ │ - * {String} │ │ │ │ + * Method: draw │ │ │ │ + * Set useIFrame in the instance, and operate the image/iframe switch. │ │ │ │ + * Then call Tile.Image.draw. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - 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>', │ │ │ │ + draw: function() { │ │ │ │ + var draw = OpenLayers.Tile.Image.prototype.shouldDraw.call(this); │ │ │ │ + if (draw) { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: metadata │ │ │ │ - * {Object} Metadata for this layer, as returned by the callback script │ │ │ │ - */ │ │ │ │ - metadata: null, │ │ │ │ + // this.url isn't set to the currect value yet, so we call getURL │ │ │ │ + // on the layer and store the result in a local variable │ │ │ │ + var url = this.layer.getURL(this.bounds); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: protocolRegex │ │ │ │ - * {RegExp} Regular expression to match and replace http: in bing urls │ │ │ │ - */ │ │ │ │ - protocolRegex: /^http:/i, │ │ │ │ + var usedIFrame = this.useIFrame; │ │ │ │ + this.useIFrame = this.maxGetUrlLength !== null && │ │ │ │ + !this.layer.async && │ │ │ │ + url.length > this.maxGetUrlLength; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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", │ │ │ │ + var fromIFrame = usedIFrame && !this.useIFrame; │ │ │ │ + var toIFrame = !usedIFrame && this.useIFrame; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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", │ │ │ │ + if (fromIFrame || toIFrame) { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + // Switching between GET (image) and POST (iframe). │ │ │ │ │ │ │ │ - /** APIProperty: tileOptions │ │ │ │ - * {Object} optional configuration options for <OpenLayers.Tile> instances │ │ │ │ - * created by this Layer. Default is │ │ │ │ - * │ │ │ │ - * (code) │ │ │ │ - * {crossOriginKeyword: 'anonymous'} │ │ │ │ - * (end) │ │ │ │ - */ │ │ │ │ - tileOptions: null, │ │ │ │ + // We remove the imgDiv (really either an image or an iframe) │ │ │ │ + // from the frame and set it to null to make sure initImage │ │ │ │ + // will call getImage. │ │ │ │ │ │ │ │ - /** 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:', │ │ │ │ + if (this.imgDiv && this.imgDiv.parentNode === this.frame) { │ │ │ │ + this.frame.removeChild(this.imgDiv); │ │ │ │ + } │ │ │ │ + this.imgDiv = null; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + // And if we had an iframe we also remove the event pane. │ │ │ │ │ │ │ │ - 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(); │ │ │ │ + if (fromIFrame) { │ │ │ │ + this.frame.removeChild(this.frame.firstChild); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return OpenLayers.Tile.Image.prototype.draw.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: loadMetadata │ │ │ │ + * Method: getImage │ │ │ │ + * Creates the content for the frame on the tile. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - }, │ │ │ │ + getImage: function() { │ │ │ │ + if (this.useIFrame === true) { │ │ │ │ + if (!this.frame.childNodes.length) { │ │ │ │ + var eventPane = document.createElement("div"), │ │ │ │ + style = eventPane.style; │ │ │ │ + style.position = "absolute"; │ │ │ │ + style.width = "100%"; │ │ │ │ + style.height = "100%"; │ │ │ │ + style.zIndex = 1; │ │ │ │ + style.backgroundImage = "url(" + this.blankImageUrl + ")"; │ │ │ │ + this.frame.appendChild(eventPane); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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(); │ │ │ │ + var id = this.id + '_iFrame', │ │ │ │ + iframe; │ │ │ │ + if (parseFloat(navigator.appVersion.split("MSIE")[1]) < 9) { │ │ │ │ + // Older IE versions do not set the name attribute of an iFrame │ │ │ │ + // properly via DOM manipulation, so we need to do it on our own with │ │ │ │ + // this hack. │ │ │ │ + iframe = document.createElement('<iframe name="' + id + '">'); │ │ │ │ + │ │ │ │ + // IFrames in older IE versions are not transparent, if you set │ │ │ │ + // the backgroundColor transparent. This is a workaround to get │ │ │ │ + // transparent iframes. │ │ │ │ + iframe.style.backgroundColor = '#FFFFFF'; │ │ │ │ + iframe.style.filter = 'chroma(color=#FFFFFF)'; │ │ │ │ + } else { │ │ │ │ + iframe = document.createElement('iframe'); │ │ │ │ + iframe.style.backgroundColor = 'transparent'; │ │ │ │ + │ │ │ │ + // iframe.name needs to be an unique id, otherwise it │ │ │ │ + // could happen that other iframes are overwritten. │ │ │ │ + iframe.name = id; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // some special properties to avoid scaling the images and scrollbars │ │ │ │ + // in the iframe │ │ │ │ + iframe.scrolling = 'no'; │ │ │ │ + iframe.marginWidth = '0px'; │ │ │ │ + iframe.marginHeight = '0px'; │ │ │ │ + iframe.frameBorder = '0'; │ │ │ │ + │ │ │ │ + iframe.style.position = "absolute"; │ │ │ │ + iframe.style.width = "100%"; │ │ │ │ + iframe.style.height = "100%"; │ │ │ │ + │ │ │ │ + if (this.layer.opacity < 1) { │ │ │ │ + OpenLayers.Util.modifyDOMElement(iframe, null, null, null, │ │ │ │ + null, null, null, this.layer.opacity); │ │ │ │ + } │ │ │ │ + this.frame.appendChild(iframe); │ │ │ │ + this.imgDiv = iframe; │ │ │ │ + return iframe; │ │ │ │ + } else { │ │ │ │ + return OpenLayers.Tile.Image.prototype.getImage.apply(this, arguments); │ │ │ │ } │ │ │ │ - this.updateAttribution(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getURL │ │ │ │ + * Method: createRequestForm │ │ │ │ + * Create the html <form> element with width, height, bbox and all │ │ │ │ + * parameters specified in the layer params. │ │ │ │ * │ │ │ │ - * Paramters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} The form element which sends the HTTP-POST request to the │ │ │ │ + * WMS. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + createRequestForm: function() { │ │ │ │ + // creation of the form element │ │ │ │ + var form = document.createElement('form'); │ │ │ │ + form.method = 'POST'; │ │ │ │ + var cacheId = this.layer.params["_OLSALT"]; │ │ │ │ + cacheId = (cacheId ? cacheId + "_" : "") + this.bounds.toBBOX(); │ │ │ │ + form.action = OpenLayers.Util.urlAppend(this.layer.url, cacheId); │ │ │ │ + form.target = this.id + '_iFrame'; │ │ │ │ + │ │ │ │ + // adding all parameters in layer params as hidden fields to the html │ │ │ │ + // form element │ │ │ │ + var imageSize = this.layer.getImageSize(), │ │ │ │ + params = OpenLayers.Util.getParameters(this.url), │ │ │ │ + field; │ │ │ │ + │ │ │ │ + for (var par in params) { │ │ │ │ + field = document.createElement('input'); │ │ │ │ + field.type = 'hidden'; │ │ │ │ + field.name = par; │ │ │ │ + field.value = params[par]; │ │ │ │ + form.appendChild(field); │ │ │ │ } │ │ │ │ - var quadKey = quadDigits.join(""); │ │ │ │ - var url = this.selectUrl('' + x + y + z, this.url); │ │ │ │ │ │ │ │ - return OpenLayers.String.format(url, { │ │ │ │ - 'quadkey': quadKey │ │ │ │ - }); │ │ │ │ + return form; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: updateAttribution │ │ │ │ - * Updates the attribution according to the requirements outlined in │ │ │ │ - * http://gis.638310.n2.nabble.com/Bing-imagery-td5789168.html │ │ │ │ + * Method: setImgSrc │ │ │ │ + * Sets the source for the tile image │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * url - {String} │ │ │ │ */ │ │ │ │ - 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 + " "; │ │ │ │ - } │ │ │ │ + setImgSrc: function(url) { │ │ │ │ + if (this.useIFrame === true) { │ │ │ │ + if (url) { │ │ │ │ + var form = this.createRequestForm(); │ │ │ │ + this.frame.appendChild(form); │ │ │ │ + form.submit(); │ │ │ │ + this.frame.removeChild(form); │ │ │ │ + } else if (this.imgDiv.parentNode === this.frame) { │ │ │ │ + // we don't reuse iframes to avoid caching issues │ │ │ │ + this.frame.removeChild(this.imgDiv); │ │ │ │ + this.imgDiv = null; │ │ │ │ } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Tile.Image.prototype.setImgSrc.apply(this, arguments); │ │ │ │ } │ │ │ │ - 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 │ │ │ │ + * Method: onImageLoad │ │ │ │ + * Handler for the image onload event │ │ │ │ */ │ │ │ │ - setMap: function() { │ │ │ │ - OpenLayers.Layer.XYZ.prototype.setMap.apply(this, arguments); │ │ │ │ - this.map.events.register("moveend", this, this.updateAttribution); │ │ │ │ + onImageLoad: function() { │ │ │ │ + //TODO de-uglify opacity handling │ │ │ │ + OpenLayers.Tile.Image.prototype.onImageLoad.apply(this, arguments); │ │ │ │ + if (this.useIFrame === true) { │ │ │ │ + this.imgDiv.style.opacity = 1; │ │ │ │ + this.frame.style.opacity = this.layer.opacity; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * obj - {Object} │ │ │ │ - * │ │ │ │ + * Method: createBackBuffer │ │ │ │ + * Override createBackBuffer to do nothing when we use an iframe. Moving an │ │ │ │ + * iframe from one element to another makes it necessary to reload the iframe │ │ │ │ + * because its content is lost. So we just give up. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Layer.Bing>} An exact clone of this <OpenLayers.Layer.Bing> │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.Bing(this.options); │ │ │ │ + createBackBuffer: function() { │ │ │ │ + var backBuffer; │ │ │ │ + if (this.useIFrame === false) { │ │ │ │ + backBuffer = OpenLayers.Tile.Image.prototype.createBackBuffer.call(this); │ │ │ │ } │ │ │ │ - //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; │ │ │ │ - }, │ │ │ │ + return backBuffer; │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/io.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - this.map && │ │ │ │ - this.map.events.unregister("moveend", this, this.updateAttribution); │ │ │ │ - OpenLayers.Layer.XYZ.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Malafaya │ │ │ │ + */ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Bing" │ │ │ │ -}); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Namespace: OpenLayers.Lang["io"] │ │ │ │ + * Dictionary for Ido. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -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.Lang["io"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Skalo = 1 : ${scaleDenom}" │ │ │ │ + │ │ │ │ +}); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/Google.js │ │ │ │ + OpenLayers/Lang/be-tarask.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. */ │ │ │ │ - │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - EugeneZelenko │ │ │ │ + * - Jim-by │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * @requires OpenLayers/Layer/SphericalMercator.js │ │ │ │ - * @requires OpenLayers/Layer/EventPane.js │ │ │ │ - * @requires OpenLayers/Layer/FixedZoomLevels.js │ │ │ │ * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.Google │ │ │ │ - * │ │ │ │ - * Provides a wrapper for Google's Maps API │ │ │ │ - * Normally the Terms of Use for this API do not allow wrapping, but Google │ │ │ │ - * have provided written consent to OpenLayers for this - see email in │ │ │ │ - * http://osgeo-org.1560.n6.nabble.com/Google-Maps-API-Terms-of-Use-changes-tp4910013p4911981.html │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.SphericalMercator> │ │ │ │ - * - <OpenLayers.Layer.EventPane> │ │ │ │ - * - <OpenLayers.Layer.FixedZoomLevels> │ │ │ │ + * Namespace: OpenLayers.Lang["be-tarask"] │ │ │ │ + * Dictionary for Беларуская (тарашкевіца). Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.Google = OpenLayers.Class( │ │ │ │ - OpenLayers.Layer.EventPane, │ │ │ │ - OpenLayers.Layer.FixedZoomLevels, { │ │ │ │ +OpenLayers.Lang["be-tarask"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: MIN_ZOOM_LEVEL │ │ │ │ - * {Integer} 0 │ │ │ │ - */ │ │ │ │ - MIN_ZOOM_LEVEL: 0, │ │ │ │ + 'unhandledRequest': "Неапрацаваны вынік запыту ${statusText}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: MAX_ZOOM_LEVEL │ │ │ │ - * {Integer} 21 │ │ │ │ - */ │ │ │ │ - MAX_ZOOM_LEVEL: 21, │ │ │ │ + 'Permalink': "Сталая спасылка", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: RESOLUTIONS │ │ │ │ - * {Array(Float)} Hardcode these resolutions so that they are more closely │ │ │ │ - * tied with the standard wms projection │ │ │ │ - */ │ │ │ │ - RESOLUTIONS: [ │ │ │ │ - 1.40625, │ │ │ │ - 0.703125, │ │ │ │ - 0.3515625, │ │ │ │ - 0.17578125, │ │ │ │ - 0.087890625, │ │ │ │ - 0.0439453125, │ │ │ │ - 0.02197265625, │ │ │ │ - 0.010986328125, │ │ │ │ - 0.0054931640625, │ │ │ │ - 0.00274658203125, │ │ │ │ - 0.001373291015625, │ │ │ │ - 0.0006866455078125, │ │ │ │ - 0.00034332275390625, │ │ │ │ - 0.000171661376953125, │ │ │ │ - 0.0000858306884765625, │ │ │ │ - 0.00004291534423828125, │ │ │ │ - 0.00002145767211914062, │ │ │ │ - 0.00001072883605957031, │ │ │ │ - 0.00000536441802978515, │ │ │ │ - 0.00000268220901489257, │ │ │ │ - 0.0000013411045074462891, │ │ │ │ - 0.00000067055225372314453 │ │ │ │ - ], │ │ │ │ + 'Overlays': "Слаі", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: type │ │ │ │ - * {GMapType} │ │ │ │ - */ │ │ │ │ - type: null, │ │ │ │ + 'Base Layer': "Базавы слой", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: wrapDateLine │ │ │ │ - * {Boolean} Allow user to pan forever east/west. Default is true. │ │ │ │ - * Setting this to false only restricts panning if │ │ │ │ - * <sphericalMercator> is true. │ │ │ │ - */ │ │ │ │ - wrapDateLine: true, │ │ │ │ + 'noFID': "Немагчыма абнавіць магчымасьць, для якога не існуе FID.", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: sphericalMercator │ │ │ │ - * {Boolean} Should the map act as a mercator-projected map? This will │ │ │ │ - * cause all interactions with the map to be in the actual map │ │ │ │ - * projection, which allows support for vector drawing, overlaying │ │ │ │ - * other maps, etc. │ │ │ │ - */ │ │ │ │ - sphericalMercator: false, │ │ │ │ + 'browserNotSupported': "Ваш браўзэр не падтрымлівае вэктарную графіку. У цяперашні момант падтрымліваюцца: ${renderers}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {Number} The version of the Google Maps API │ │ │ │ - */ │ │ │ │ - version: null, │ │ │ │ + 'minZoomLevelError': "Уласьцівасьць minZoomLevel прызначана толькі для выкарыстаньня са слаямі вытворнымі ад FixedZoomLevels. Тое, што гэты wfs-слой правяраецца на minZoomLevel — рэха прошлага. Але мы ня можам выдаліць гэтую магчымасьць, таму што ад яе залежаць некаторыя заснаваныя на OL дастасаваньні. Тым ня менш, праверка minZoomLevel будзе выдаленая ў вэрсіі 3.0. Калі ласка, выкарыстоўваеце замест яе ўстаноўкі мінімальнага/максымальнага памераў, як апісана тут: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.Google │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} A name for the layer. │ │ │ │ - * options - {Object} An optional object whose properties will be set │ │ │ │ - * on the layer. │ │ │ │ - */ │ │ │ │ - initialize: function(name, options) { │ │ │ │ - options = options || {}; │ │ │ │ - if (!options.version) { │ │ │ │ - options.version = typeof GMap2 === "function" ? "2" : "3"; │ │ │ │ - } │ │ │ │ - var mixin = OpenLayers.Layer.Google["v" + │ │ │ │ - options.version.replace(/\./g, "_")]; │ │ │ │ - if (mixin) { │ │ │ │ - OpenLayers.Util.applyDefaults(options, mixin); │ │ │ │ - } else { │ │ │ │ - throw "Unsupported Google Maps API version: " + options.version; │ │ │ │ - } │ │ │ │ + 'commitSuccess': "WFS-транзакцыя: ПОСЬПЕХ ${response}", │ │ │ │ │ │ │ │ - OpenLayers.Util.applyDefaults(options, mixin.DEFAULTS); │ │ │ │ - if (options.maxExtent) { │ │ │ │ - options.maxExtent = options.maxExtent.clone(); │ │ │ │ - } │ │ │ │ + 'commitFailed': "WFS-транзакцыя: ПАМЫЛКА ${response}", │ │ │ │ │ │ │ │ - OpenLayers.Layer.EventPane.prototype.initialize.apply(this, │ │ │ │ - [name, options]); │ │ │ │ - OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, │ │ │ │ - [name, options]); │ │ │ │ + 'googleWarning': "Не атрымалася загрузіць слой Google. \x3cbr\x3e\x3cbr\x3eКаб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.\x3cbr\x3e\x3cbr\x3e Хутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі Google Maps ня быў уключаныя альбо не ўтрымлівае слушны API-ключ для Вашага сайта.\x3cbr\x3e\x3cbr\x3eРаспрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eнацісьніце тут\x3c/a\x3e", │ │ │ │ │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator); │ │ │ │ - this.initMercatorParameters(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'getLayerWarning': "Немагчыма загрузіць слой ${layerType}.\x3cbr\x3e\x3cbr\x3eКаб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.\x3cbr\x3e\x3cbr\x3eХутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі ${layerLib} ня быў слушна ўключаны.\x3cbr\x3e\x3cbr\x3eРаспрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eнацісьніце тут\x3c/a\x3e", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.Google>} An exact clone of this layer │ │ │ │ - */ │ │ │ │ - clone: function() { │ │ │ │ - /** │ │ │ │ - * This method isn't intended to be called by a subclass and it │ │ │ │ - * doesn't call the same method on the superclass. We don't call │ │ │ │ - * the super's clone because we don't want properties that are set │ │ │ │ - * on this layer after initialize (i.e. this.mapObject etc.). │ │ │ │ - */ │ │ │ │ - return new OpenLayers.Layer.Google( │ │ │ │ - this.name, this.getOptions() │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Маштаб = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: setVisibility │ │ │ │ - * Set the visibility flag for the layer and hide/show & redraw │ │ │ │ - * accordingly. Fire event unless otherwise specified │ │ │ │ - * │ │ │ │ - * Note that visibility is no longer simply whether or not the layer's │ │ │ │ - * style.display is set to "block". Now we store a 'visibility' state │ │ │ │ - * property on the layer class, this allows us to remember whether or │ │ │ │ - * not we *desire* for a layer to be visible. In the case where the │ │ │ │ - * map's resolution is out of the layer's range, this desire may be │ │ │ │ - * subverted. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * visible - {Boolean} Display the layer (if in range) │ │ │ │ - */ │ │ │ │ - setVisibility: function(visible) { │ │ │ │ - // sharing a map container, opacity has to be set per layer │ │ │ │ - var opacity = this.opacity == null ? 1 : this.opacity; │ │ │ │ - OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this, arguments); │ │ │ │ - this.setOpacity(opacity); │ │ │ │ - }, │ │ │ │ + 'W': "З", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: display │ │ │ │ - * Hide or show the Layer │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * visible - {Boolean} │ │ │ │ - */ │ │ │ │ - display: function(visible) { │ │ │ │ - if (!this._dragging) { │ │ │ │ - this.setGMapVisibility(visible); │ │ │ │ - } │ │ │ │ - OpenLayers.Layer.EventPane.prototype.display.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + 'E': "У", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: moveTo │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to │ │ │ │ - * do some init work in that case. │ │ │ │ - * dragging - {Boolean} │ │ │ │ - */ │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - this._dragging = dragging; │ │ │ │ - OpenLayers.Layer.EventPane.prototype.moveTo.apply(this, arguments); │ │ │ │ - delete this._dragging; │ │ │ │ - }, │ │ │ │ + 'N': "Пн", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: setOpacity │ │ │ │ - * Sets the opacity for the entire layer (all images) │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * opacity - {Float} │ │ │ │ - */ │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ - if (opacity !== this.opacity) { │ │ │ │ - if (this.map != null) { │ │ │ │ - this.map.events.triggerEvent("changelayer", { │ │ │ │ - layer: this, │ │ │ │ - property: "opacity" │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - this.opacity = opacity; │ │ │ │ - } │ │ │ │ - // Though this layer's opacity may not change, we're sharing a container │ │ │ │ - // and need to update the opacity for the entire container. │ │ │ │ - if (this.getVisibility()) { │ │ │ │ - var container = this.getMapContainer(); │ │ │ │ - OpenLayers.Util.modifyDOMElement( │ │ │ │ - container, null, null, null, null, null, null, opacity │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'S': "Пд", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Clean up this layer. │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - /** │ │ │ │ - * We have to override this method because the event pane destroy │ │ │ │ - * deletes the mapObject reference before removing this layer from │ │ │ │ - * the map. │ │ │ │ - */ │ │ │ │ - if (this.map) { │ │ │ │ - this.setGMapVisibility(false); │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache && cache.count <= 1) { │ │ │ │ - this.removeGMapElements(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - OpenLayers.Layer.EventPane.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + 'reprojectDeprecated': "Вы выкарыстоўваеце ўстаноўку \'reproject\' для слоя ${layerName}. Гэтая ўстаноўка зьяўляецца састарэлай: яна выкарыстоўвалася для падтрымкі паказу зьвестак на камэрцыйных базавых мапах, але гэта функцыя цяпер рэалізаваная ў убудаванай падтрымцы сфэрычнай праекцыі Мэркатара. Дадатковая інфармацыя ёсьць на http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: removeGMapElements │ │ │ │ - * Remove all elements added to the dom. This should only be called if │ │ │ │ - * this is the last of the Google layers for the given map. │ │ │ │ - */ │ │ │ │ - removeGMapElements: function() { │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - // remove shared elements from dom │ │ │ │ - var container = this.mapObject && this.getMapContainer(); │ │ │ │ - if (container && container.parentNode) { │ │ │ │ - container.parentNode.removeChild(container); │ │ │ │ - } │ │ │ │ - var termsOfUse = cache.termsOfUse; │ │ │ │ - if (termsOfUse && termsOfUse.parentNode) { │ │ │ │ - termsOfUse.parentNode.removeChild(termsOfUse); │ │ │ │ - } │ │ │ │ - var poweredBy = cache.poweredBy; │ │ │ │ - if (poweredBy && poweredBy.parentNode) { │ │ │ │ - poweredBy.parentNode.removeChild(poweredBy); │ │ │ │ - } │ │ │ │ - if (this.mapObject && window.google && google.maps && │ │ │ │ - google.maps.event && google.maps.event.clearListeners) { │ │ │ │ - google.maps.event.clearListeners(this.mapObject, 'tilesloaded'); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'methodDeprecated': "Гэты мэтад састарэлы і будзе выдалены ў вэрсіі 3.0. Калі ласка, замест яго выкарыстоўвайце ${newMethod}." │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: removeMap │ │ │ │ - * On being removed from the map, also remove termsOfUse and poweredBy divs │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ - */ │ │ │ │ - removeMap: function(map) { │ │ │ │ - // hide layer before removing │ │ │ │ - if (this.visibility && this.mapObject) { │ │ │ │ - this.setGMapVisibility(false); │ │ │ │ - } │ │ │ │ - // check to see if last Google layer in this map │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[map.id]; │ │ │ │ - if (cache) { │ │ │ │ - if (cache.count <= 1) { │ │ │ │ - this.removeGMapElements(); │ │ │ │ - delete OpenLayers.Layer.Google.cache[map.id]; │ │ │ │ - } else { │ │ │ │ - // decrement the layer count │ │ │ │ - --cache.count; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - // remove references to gmap elements │ │ │ │ - delete this.termsOfUse; │ │ │ │ - delete this.poweredBy; │ │ │ │ - delete this.mapObject; │ │ │ │ - delete this.dragObject; │ │ │ │ - OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments); │ │ │ │ - }, │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/gsw.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - // │ │ │ │ - // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ - // │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Als-Holder │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getOLBoundsFromMapObjectBounds │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moBounds - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} An <OpenLayers.Bounds>, translated from the │ │ │ │ - * passed-in MapObject Bounds. │ │ │ │ - * Returns null if null value is passed in. │ │ │ │ - */ │ │ │ │ - getOLBoundsFromMapObjectBounds: function(moBounds) { │ │ │ │ - var olBounds = null; │ │ │ │ - if (moBounds != null) { │ │ │ │ - var sw = moBounds.getSouthWest(); │ │ │ │ - var ne = moBounds.getNorthEast(); │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - sw = this.forwardMercator(sw.lng(), sw.lat()); │ │ │ │ - ne = this.forwardMercator(ne.lng(), ne.lat()); │ │ │ │ - } else { │ │ │ │ - sw = new OpenLayers.LonLat(sw.lng(), sw.lat()); │ │ │ │ - ne = new OpenLayers.LonLat(ne.lng(), ne.lat()); │ │ │ │ - } │ │ │ │ - olBounds = new OpenLayers.Bounds(sw.lon, │ │ │ │ - sw.lat, │ │ │ │ - ne.lon, │ │ │ │ - ne.lat); │ │ │ │ - } │ │ │ │ - return olBounds; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getWarningHTML │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} String with information on why layer is broken, how to get │ │ │ │ - * it working. │ │ │ │ - */ │ │ │ │ - getWarningHTML: function() { │ │ │ │ - return OpenLayers.i18n("googleWarning"); │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["gsw"] │ │ │ │ + * Dictionary for Alemannisch. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["gsw"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ + 'unhandledRequest': "Nit behandleti Aafrogsruckmäldig ${statusText}", │ │ │ │ │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Interface Controls * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ + 'Permalink': "Permalink", │ │ │ │ │ │ │ │ + 'Overlays': "Iberlagerige", │ │ │ │ │ │ │ │ - // Get&Set Center, Zoom │ │ │ │ + 'Base Layer': "Grundcharte", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectCenter │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} The mapObject's current center in Map Object format │ │ │ │ - */ │ │ │ │ - getMapObjectCenter: function() { │ │ │ │ - return this.mapObject.getCenter(); │ │ │ │ - }, │ │ │ │ + 'noFID': "E Feature, wu s kei FID derfir git, cha nit aktualisiert wäre.", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectZoom │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} The mapObject's current zoom, in Map Object format │ │ │ │ - */ │ │ │ │ - getMapObjectZoom: function() { │ │ │ │ - return this.mapObject.getZoom(); │ │ │ │ - }, │ │ │ │ + 'browserNotSupported': "Dyy Browser unterstitzt kei Vektordarstellig. Aktuäll unterstitzti Renderer:\n${renderers}", │ │ │ │ │ │ │ │ + 'minZoomLevelError': "D minZoomLevel-Eigeschaft isch nume dänk fir d Layer, wu vu dr FixedZoomLevels abstamme. Ass dää wfs-Layer minZoomLevel prieft, scih e Relikt us dr Vergangeheit. Mir chenne s aber nit ändere ohni OL_basierti Aawändige villicht kaputt gehn, wu dervu abhänge. Us däm Grund het die Funktion d Eigeschaft \'deprecated\' iberchuu. D minZoomLevel-Priefig unte wird in dr Version 3.0 usegnuu. Bitte verwänd statt däm e min/max-Uflesig wie s do bschriben isch: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Primitives * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ + 'commitSuccess': "WFS-Transaktion: ERFOLGRYCH ${response}", │ │ │ │ │ │ │ │ + 'commitFailed': "WFS-Transaktion: FÄHLGSCHLAA ${response}", │ │ │ │ │ │ │ │ - // LonLat │ │ │ │ + 'googleWarning': "Dr Google-Layer het nit korräkt chenne glade wäre.\x3cbr\x3e\x3cbr\x3eGo die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.\x3cbr\x3e\x3cbr\x3eDää Fähler git s seli hyfig, wel s Skript vu dr Google-Maps-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.\x3cbr\x3e\x3cbr\x3eEntwickler: Fir Hilf zum korräkte Yybinde vum Google-Layer \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3edoo drucke\x3c/a\x3e", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getLongitudeFromMapObjectLonLat │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moLonLat - {Object} MapObject LonLat format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Float} Longitude of the given MapObject LonLat │ │ │ │ - */ │ │ │ │ - getLongitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - return this.sphericalMercator ? │ │ │ │ - this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon : │ │ │ │ - moLonLat.lng(); │ │ │ │ - }, │ │ │ │ + 'getLayerWarning': "Dr ${layerType}-Layer het nit korräkt chenne glade wäre.\x3cbr\x3e\x3cbr\x3eGo die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.\x3cbr\x3e\x3cbr\x3eDää Fähler git s seli hyfig, wel s Skript vu dr \'${layerLib}\'-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.\x3cbr\x3e\x3cbr\x3eEntwickler: Fir Hilf zum korräkte Yybinde vu Layer \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3edoo drucke\x3c/a\x3e", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getLatitudeFromMapObjectLonLat │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moLonLat - {Object} MapObject LonLat format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Float} Latitude of the given MapObject LonLat │ │ │ │ - */ │ │ │ │ - getLatitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - var lat = this.sphericalMercator ? │ │ │ │ - this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat : │ │ │ │ - moLonLat.lat(); │ │ │ │ - return lat; │ │ │ │ - }, │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Maßstab = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - // Pixel │ │ │ │ + 'W': "W", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getXFromMapObjectPixel │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moPixel - {Object} MapObject Pixel format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} X value of the MapObject Pixel │ │ │ │ - */ │ │ │ │ - getXFromMapObjectPixel: function(moPixel) { │ │ │ │ - return moPixel.x; │ │ │ │ - }, │ │ │ │ + 'E': "O", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getYFromMapObjectPixel │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moPixel - {Object} MapObject Pixel format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} Y value of the MapObject Pixel │ │ │ │ - */ │ │ │ │ - getYFromMapObjectPixel: function(moPixel) { │ │ │ │ - return moPixel.y; │ │ │ │ - }, │ │ │ │ + 'N': "N", │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Google" │ │ │ │ - }); │ │ │ │ + 'S': "S", │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Property: OpenLayers.Layer.Google.cache │ │ │ │ - * {Object} Cache for elements that should only be created once per map. │ │ │ │ - */ │ │ │ │ -OpenLayers.Layer.Google.cache = {}; │ │ │ │ + 'reprojectDeprecated': "Du bruchsch d \'reproject\'-Option bim ${layerName}-Layer. Die Option isch nimi giltig: si isch aagleit wore go Date iber kommerziälli Grundcharte lege, aber des sott mer jetz mache mit dr Unterstitzig vu Spherical Mercator. Meh Informatione git s uf http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + │ │ │ │ + 'methodDeprecated': "Die Methode isch veraltet un wird us dr Version 3.0 usegnuu. Bitte verwäbnd statt däm ${newMethod}." │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/fi.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Nike │ │ │ │ + * - Str4nd │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Layer.Google.v2 │ │ │ │ - * │ │ │ │ - * Mixin providing functionality specific to the Google Maps API v2. │ │ │ │ - * │ │ │ │ - * This API has been deprecated by Google. │ │ │ │ - * Developers are encouraged to migrate to v3 of the API; support for this │ │ │ │ - * is provided by <OpenLayers.Layer.Google.v3> │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.Google.v2 = { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: termsOfUse │ │ │ │ - * {DOMElement} Div for Google's copyright and terms of use link │ │ │ │ - */ │ │ │ │ - termsOfUse: null, │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["fi"] │ │ │ │ + * Dictionary for Suomi. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["fi"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: poweredBy │ │ │ │ - * {DOMElement} Div for Google's powered by logo and link │ │ │ │ - */ │ │ │ │ - poweredBy: null, │ │ │ │ + 'Permalink': "Ikilinkki", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: dragObject │ │ │ │ - * {GDraggableObject} Since 2.93, Google has exposed the ability to get │ │ │ │ - * the maps GDraggableObject. We can now use this for smooth panning │ │ │ │ - */ │ │ │ │ - dragObject: null, │ │ │ │ + 'Overlays': "Kerrokset", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: loadMapObject │ │ │ │ - * Load the GMap and register appropriate event listeners. If we can't │ │ │ │ - * load GMap2, then display a warning message. │ │ │ │ - */ │ │ │ │ - loadMapObject: function() { │ │ │ │ - if (!this.type) { │ │ │ │ - this.type = G_NORMAL_MAP; │ │ │ │ - } │ │ │ │ - var mapObject, termsOfUse, poweredBy; │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - // there are already Google layers added to this map │ │ │ │ - mapObject = cache.mapObject; │ │ │ │ - termsOfUse = cache.termsOfUse; │ │ │ │ - poweredBy = cache.poweredBy; │ │ │ │ - // increment the layer count │ │ │ │ - ++cache.count; │ │ │ │ - } else { │ │ │ │ - // this is the first Google layer for this map │ │ │ │ + 'Base Layer': "Peruskerros", │ │ │ │ │ │ │ │ - var container = this.map.viewPortDiv; │ │ │ │ - var div = document.createElement("div"); │ │ │ │ - div.id = this.map.id + "_GMap2Container"; │ │ │ │ - div.style.position = "absolute"; │ │ │ │ - div.style.width = "100%"; │ │ │ │ - div.style.height = "100%"; │ │ │ │ - container.appendChild(div); │ │ │ │ + 'W': "L", │ │ │ │ │ │ │ │ - // create GMap and shuffle elements │ │ │ │ - try { │ │ │ │ - mapObject = new GMap2(div); │ │ │ │ + 'E': "I", │ │ │ │ │ │ │ │ - // move the ToS and branding stuff up to the container div │ │ │ │ - termsOfUse = div.lastChild; │ │ │ │ - container.appendChild(termsOfUse); │ │ │ │ - termsOfUse.style.zIndex = "1100"; │ │ │ │ - termsOfUse.style.right = ""; │ │ │ │ - termsOfUse.style.bottom = ""; │ │ │ │ - termsOfUse.className = "olLayerGoogleCopyright"; │ │ │ │ + 'N': "P", │ │ │ │ │ │ │ │ - poweredBy = div.lastChild; │ │ │ │ - container.appendChild(poweredBy); │ │ │ │ - poweredBy.style.zIndex = "1100"; │ │ │ │ - poweredBy.style.right = ""; │ │ │ │ - poweredBy.style.bottom = ""; │ │ │ │ - poweredBy.className = "olLayerGooglePoweredBy gmnoprint"; │ │ │ │ + 'S': "E" │ │ │ │ │ │ │ │ - } catch (e) { │ │ │ │ - throw (e); │ │ │ │ - } │ │ │ │ - // cache elements for use by any other google layers added to │ │ │ │ - // this same map │ │ │ │ - OpenLayers.Layer.Google.cache[this.map.id] = { │ │ │ │ - mapObject: mapObject, │ │ │ │ - termsOfUse: termsOfUse, │ │ │ │ - poweredBy: poweredBy, │ │ │ │ - count: 1 │ │ │ │ - }; │ │ │ │ - } │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/hu.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - this.mapObject = mapObject; │ │ │ │ - this.termsOfUse = termsOfUse; │ │ │ │ - this.poweredBy = poweredBy; │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - City-busz │ │ │ │ + * - Glanthor Reviol │ │ │ │ + */ │ │ │ │ │ │ │ │ - // ensure this layer type is one of the mapObject types │ │ │ │ - if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(), │ │ │ │ - this.type) === -1) { │ │ │ │ - this.mapObject.addMapType(this.type); │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - //since v 2.93 getDragObject is now available. │ │ │ │ - if (typeof mapObject.getDragObject == "function") { │ │ │ │ - this.dragObject = mapObject.getDragObject(); │ │ │ │ - } else { │ │ │ │ - this.dragPanMapObject = null; │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["hu"] │ │ │ │ + * Dictionary for Magyar. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["hu"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - if (this.isBaseLayer === false) { │ │ │ │ - this.setGMapVisibility(this.div.style.display !== "none"); │ │ │ │ - } │ │ │ │ + 'unhandledRequest': "Nem kezelt kérés visszatérése ${statusText}", │ │ │ │ │ │ │ │ - }, │ │ │ │ + 'Permalink': "Permalink", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: onMapResize │ │ │ │ - */ │ │ │ │ - onMapResize: function() { │ │ │ │ - // workaround for resizing of invisible or not yet fully loaded layers │ │ │ │ - // where GMap2.checkResize() does not work. We need to load the GMap │ │ │ │ - // for the old div size, then checkResize(), and then call │ │ │ │ - // layer.moveTo() to trigger GMap.setCenter() (which will finish │ │ │ │ - // the GMap initialization). │ │ │ │ - if (this.visibility && this.mapObject.isLoaded()) { │ │ │ │ - this.mapObject.checkResize(); │ │ │ │ - } else { │ │ │ │ - if (!this._resized) { │ │ │ │ - var layer = this; │ │ │ │ - var handle = GEvent.addListener(this.mapObject, "load", function() { │ │ │ │ - GEvent.removeListener(handle); │ │ │ │ - delete layer._resized; │ │ │ │ - layer.mapObject.checkResize(); │ │ │ │ - layer.moveTo(layer.map.getCenter(), layer.map.getZoom()); │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - this._resized = true; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'Overlays': "Rávetítések", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setGMapVisibility │ │ │ │ - * Display the GMap container and associated elements. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * visible - {Boolean} Display the GMap elements. │ │ │ │ - */ │ │ │ │ - setGMapVisibility: function(visible) { │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - var container = this.mapObject.getContainer(); │ │ │ │ - if (visible === true) { │ │ │ │ - this.mapObject.setMapType(this.type); │ │ │ │ - container.style.display = ""; │ │ │ │ - this.termsOfUse.style.left = ""; │ │ │ │ - this.termsOfUse.style.display = ""; │ │ │ │ - this.poweredBy.style.display = ""; │ │ │ │ - cache.displayed = this.id; │ │ │ │ - } else { │ │ │ │ - if (cache.displayed === this.id) { │ │ │ │ - delete cache.displayed; │ │ │ │ - } │ │ │ │ - if (!cache.displayed) { │ │ │ │ - container.style.display = "none"; │ │ │ │ - this.termsOfUse.style.display = "none"; │ │ │ │ - // move ToU far to the left in addition to setting display │ │ │ │ - // to "none", because at the end of the GMap2 load │ │ │ │ - // sequence, display: none will be unset and ToU would be │ │ │ │ - // visible after loading a map with a google layer that is │ │ │ │ - // initially hidden. │ │ │ │ - this.termsOfUse.style.left = "-9999px"; │ │ │ │ - this.poweredBy.style.display = "none"; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'Base Layer': "Alapréteg", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getMapContainer │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} the GMap container's div │ │ │ │ - */ │ │ │ │ - getMapContainer: function() { │ │ │ │ - return this.mapObject.getContainer(); │ │ │ │ - }, │ │ │ │ + 'noFID': "Nem frissíthető olyan jellemző, amely nem rendelkezik FID-del.", │ │ │ │ │ │ │ │ - // │ │ │ │ - // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ - // │ │ │ │ + 'browserNotSupported': "A böngészője nem támogatja a vektoros renderelést. A jelenleg támogatott renderelők:\n${renderers}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectBoundsFromOLBounds │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * olBounds - {<OpenLayers.Bounds>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} A MapObject Bounds, translated from olBounds │ │ │ │ - * Returns null if null value is passed in │ │ │ │ - */ │ │ │ │ - getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ - var moBounds = null; │ │ │ │ - if (olBounds != null) { │ │ │ │ - var sw = this.sphericalMercator ? │ │ │ │ - this.inverseMercator(olBounds.bottom, olBounds.left) : │ │ │ │ - new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ - var ne = this.sphericalMercator ? │ │ │ │ - this.inverseMercator(olBounds.top, olBounds.right) : │ │ │ │ - new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ - moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon), │ │ │ │ - new GLatLng(ne.lat, ne.lon)); │ │ │ │ - } │ │ │ │ - return moBounds; │ │ │ │ - }, │ │ │ │ + 'minZoomLevelError': "A minZoomLevel tulajdonságot csak a következővel való használatra szánták: FixedZoomLevels-leszármazott fóliák. Ez azt jelenti, hogy a minZoomLevel wfs fólia jelölőnégyzetei már a múlté. Mi azonban nem távolíthatjuk el annak a veszélye nélkül, hogy az esetlegesen ettől függő OL alapú alkalmazásokat tönkretennénk. Ezért ezt érvénytelenítjük -- a minZoomLevel az alul levő jelölőnégyzet a 3.0-s verzióból el lesz távolítva. Kérjük, helyette használja a min/max felbontás beállítást, amelyről az alábbi helyen talál leírást: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ + 'commitSuccess': "WFS tranzakció: SIKERES ${response}", │ │ │ │ │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Interface Controls * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ + 'commitFailed': "WFS tranzakció: SIKERTELEN ${response}", │ │ │ │ │ │ │ │ + 'googleWarning': "A Google fólia betöltése sikertelen.\x3cbr\x3e\x3cbr\x3eAhhoz, hogy ez az üzenet eltűnjön, válasszon egy új BaseLayer fóliát a jobb felső sarokban található fóliakapcsoló segítségével.\x3cbr\x3e\x3cbr\x3eNagy valószínűséggel ez azért van, mert a Google Maps könyvtár parancsfájlja nem található, vagy nem tartalmazza az Ön oldalához tartozó megfelelő API-kulcsot.\x3cbr\x3e\x3cbr\x3eFejlesztőknek: A helyes működtetésre vonatkozó segítség az alábbi helyen érhető el, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3ekattintson ide\x3c/a\x3e", │ │ │ │ │ │ │ │ - // Get&Set Center, Zoom │ │ │ │ + 'getLayerWarning': "A(z) ${layerType} fólia nem töltődött be helyesen.\x3cbr\x3e\x3cbr\x3eAhhoz, hogy ez az üzenet eltűnjön, válasszon egy új BaseLayer fóliát a jobb felső sarokban található fóliakapcsoló segítségével.\x3cbr\x3e\x3cbr\x3eNagy valószínűséggel ez azért van, mert a(z) ${layerLib} könyvtár parancsfájlja helytelen.\x3cbr\x3e\x3cbr\x3eFejlesztőknek: A helyes működtetésre vonatkozó segítség az alábbi helyen érhető el, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3ekattintson ide\x3c/a\x3e", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: setMapObjectCenter │ │ │ │ - * Set the mapObject to the specified center and zoom │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * center - {Object} MapObject LonLat format │ │ │ │ - * zoom - {int} MapObject zoom format │ │ │ │ - */ │ │ │ │ - setMapObjectCenter: function(center, zoom) { │ │ │ │ - this.mapObject.setCenter(center, zoom); │ │ │ │ - }, │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Lépték = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: dragPanMapObject │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * dX - {Integer} │ │ │ │ - * dY - {Integer} │ │ │ │ - */ │ │ │ │ - dragPanMapObject: function(dX, dY) { │ │ │ │ - this.dragObject.moveBy(new GSize(-dX, dY)); │ │ │ │ - }, │ │ │ │ + 'W': "Ny", │ │ │ │ │ │ │ │ + 'E': "K", │ │ │ │ │ │ │ │ - // LonLat - Pixel Translation │ │ │ │ + 'N': "É", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectLonLatFromMapObjectPixel │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moPixel - {Object} MapObject Pixel format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject LonLat translated from MapObject Pixel │ │ │ │ - */ │ │ │ │ - getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ - return this.mapObject.fromContainerPixelToLatLng(moPixel); │ │ │ │ - }, │ │ │ │ + 'S': "D", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectPixelFromMapObjectLonLat │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moLonLat - {Object} MapObject LonLat format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject Pixel transtlated from MapObject LonLat │ │ │ │ - */ │ │ │ │ - getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - return this.mapObject.fromLatLngToContainerPixel(moLonLat); │ │ │ │ - }, │ │ │ │ + 'reprojectDeprecated': "Ön a \'reproject\' beállítást használja a(z) ${layerName} fólián. Ez a beállítás érvénytelen: használata az üzleti alaptérképek fölötti adatok megjelenítésének támogatására szolgált, de ezt a funkció ezentúl a Gömbi Mercator használatával érhető el. További információ az alábbi helyen érhető el: http://trac.openlayers.org/wiki/SphericalMercator", │ │ │ │ │ │ │ │ + 'methodDeprecated': "Ez a módszer érvénytelenítve lett és a 3.0-s verzióból el lesz távolítva. Használja a(z) ${newMethod} módszert helyette." │ │ │ │ │ │ │ │ - // Bounds │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/bg.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectZoomFromMapObjectBounds │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moBounds - {Object} MapObject Bounds format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject Zoom for specified MapObject Bounds │ │ │ │ - */ │ │ │ │ - getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ - return this.mapObject.getBoundsZoomLevel(moBounds); │ │ │ │ - }, │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - DCLXVI │ │ │ │ + */ │ │ │ │ │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Primitives * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["bg"] │ │ │ │ + * Dictionary for Български. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["bg"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - // LonLat │ │ │ │ + 'Permalink': "Постоянна препратка", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectLonLatFromLonLat │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * lon - {Float} │ │ │ │ - * lat - {Float} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject LonLat built from lon and lat params │ │ │ │ - */ │ │ │ │ - getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ - var gLatLng; │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - var lonlat = this.inverseMercator(lon, lat); │ │ │ │ - gLatLng = new GLatLng(lonlat.lat, lonlat.lon); │ │ │ │ - } else { │ │ │ │ - gLatLng = new GLatLng(lat, lon); │ │ │ │ - } │ │ │ │ - return gLatLng; │ │ │ │ - }, │ │ │ │ + 'Base Layer': "Основен слой", │ │ │ │ │ │ │ │ - // Pixel │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Мащаб = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectPixelFromXY │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * x - {Integer} │ │ │ │ - * y - {Integer} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject Pixel from x and y parameters │ │ │ │ - */ │ │ │ │ - getMapObjectPixelFromXY: function(x, y) { │ │ │ │ - return new GPoint(x, y); │ │ │ │ - } │ │ │ │ + 'methodDeprecated': "Този метод е остарял и ще бъде премахват в 3.0. Вместо него използвайте ${newMethod}." │ │ │ │ │ │ │ │ -}; │ │ │ │ +}); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/WorldWind.js │ │ │ │ + OpenLayers/Lang/nb.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 │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.WorldWind │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * Namespace: OpenLayers.Lang["nb"] │ │ │ │ + * Dictionary for norwegian bokmål (Norway). Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.WorldWind = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ +OpenLayers.Lang["nb"] = { │ │ │ │ │ │ │ │ - DEFAULT_PARAMS: {}, │ │ │ │ + 'unhandledRequest': "Ubehandlet forespørsel returnerte ${statusText}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} WorldWind layer is a base layer by default. │ │ │ │ - */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + 'Permalink': "Kobling til denne siden", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: lzd │ │ │ │ - * {Float} LevelZeroTileSizeDegrees │ │ │ │ - */ │ │ │ │ - lzd: null, │ │ │ │ + 'Overlays': "Kartlag", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: zoomLevels │ │ │ │ - * {Integer} Number of zoom levels. │ │ │ │ - */ │ │ │ │ - zoomLevels: null, │ │ │ │ + 'Base Layer': "Bakgrunnskart", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.WorldWind │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} Name of Layer │ │ │ │ - * url - {String} Base URL │ │ │ │ - * lzd - {Float} Level zero tile size degrees │ │ │ │ - * zoomLevels - {Integer} number of zoom levels │ │ │ │ - * params - {Object} additional parameters │ │ │ │ - * options - {Object} additional options │ │ │ │ - */ │ │ │ │ - initialize: function(name, url, lzd, zoomLevels, params, options) { │ │ │ │ - this.lzd = lzd; │ │ │ │ - this.zoomLevels = zoomLevels; │ │ │ │ - var newArguments = []; │ │ │ │ - newArguments.push(name, url, params, options); │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments); │ │ │ │ - this.params = OpenLayers.Util.applyDefaults( │ │ │ │ - this.params, this.DEFAULT_PARAMS │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ + 'noFID': "Kan ikke oppdatere et feature (et objekt) som ikke har FID.", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getZoom │ │ │ │ - * Convert map zoom to WW zoom. │ │ │ │ - */ │ │ │ │ - getZoom: function() { │ │ │ │ - var zoom = this.map.getZoom(); │ │ │ │ - var extent = this.map.getMaxExtent(); │ │ │ │ - zoom = zoom - Math.log(this.maxResolution / (this.lzd / 512)) / Math.log(2); │ │ │ │ - return zoom; │ │ │ │ - }, │ │ │ │ + 'browserNotSupported': "Din nettleser støtter ikke vektortegning. Tegnemetodene som støttes er:\n${renderers}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var zoom = this.getZoom(); │ │ │ │ - var extent = this.map.getMaxExtent(); │ │ │ │ - var deg = this.lzd / Math.pow(2, this.getZoom()); │ │ │ │ - var x = Math.floor((bounds.left - extent.left) / deg); │ │ │ │ - var y = Math.floor((bounds.bottom - extent.bottom) / deg); │ │ │ │ - if (this.map.getResolution() <= (this.lzd / 512) && │ │ │ │ - this.getZoom() <= this.zoomLevels) { │ │ │ │ - return this.getFullRequestString({ │ │ │ │ - L: zoom, │ │ │ │ - X: x, │ │ │ │ - Y: y │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - return OpenLayers.Util.getImageLocation("blank.gif"); │ │ │ │ - } │ │ │ │ + // console message │ │ │ │ + 'minZoomLevelError': "Egenskapen minZoomLevel er kun ment til bruk på lag " + │ │ │ │ + "basert på FixedZoomLevels. At dette wfs-laget sjekker " + │ │ │ │ + "minZoomLevel er en etterlevning fra tidligere versjoner. Det kan dog ikke " + │ │ │ │ + "tas bort uten å risikere at OL-baserte applikasjoner " + │ │ │ │ + "slutter å virke, så det er merket som foreldet: " + │ │ │ │ + "minZoomLevel i sjekken nedenfor vil fjernes i 3.0. " + │ │ │ │ + "Vennligst bruk innstillingene for min/maks oppløsning " + │ │ │ │ + "som er beskrevet her: " + │ │ │ │ + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - }, │ │ │ │ + 'commitSuccess': "WFS-transaksjon: LYKTES ${response}", │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.WorldWind" │ │ │ │ -}); │ │ │ │ + 'commitFailed': "WFS-transaksjon: MISLYKTES ${response}", │ │ │ │ + │ │ │ │ + 'googleWarning': "Google-laget kunne ikke lastes.<br><br>" + │ │ │ │ + "Bytt til et annet bakgrunnslag i lagvelgeren i " + │ │ │ │ + "øvre høyre hjørne for å slippe denne meldingen.<br><br>" + │ │ │ │ + "Sannsynligvis forårsakes feilen av at Google Maps-biblioteket " + │ │ │ │ + "ikke er riktig inkludert på nettsiden, eller at det ikke er " + │ │ │ │ + "angitt riktig API-nøkkel for nettstedet.<br><br>" + │ │ │ │ + "Utviklere: For hjelp til å få dette til å virke se " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ + "target='_blank'>her</a>.", │ │ │ │ + │ │ │ │ + 'getLayerWarning': "${layerType}-laget kunne ikke lastes.<br><br>" + │ │ │ │ + "Bytt til et annet bakgrunnslag i lagvelgeren i " + │ │ │ │ + "øvre høyre hjørne for å slippe denne meldingen.<br><br>" + │ │ │ │ + "Sannsynligvis forårsakes feilen av at " + │ │ │ │ + "${layerLib}-biblioteket ikke var riktig inkludert " + │ │ │ │ + "på nettsiden.<br><br>" + │ │ │ │ + "Utviklere: For hjelp til å få dette til å virke se " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ + "target='_blank'>her</a>.", │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "<strong>Skala</strong> 1 : ${scaleDenom}", │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'reprojectDeprecated': "Du bruker innstillingen 'reproject' på laget ${layerName}. " + │ │ │ │ + "Denne innstillingen er foreldet, den var ment for å støtte " + │ │ │ │ + "visning av kartdata over kommersielle bakgrunnskart, men det " + │ │ │ │ + "bør nå gjøres med støtten for Spherical Mercator. Mer informasjon " + │ │ │ │ + "finnes på http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'methodDeprecated': "Denne metoden er markert som foreldet og vil bli fjernet i 3.0. " + │ │ │ │ + "Vennligst bruk ${newMethod} i stedet.", │ │ │ │ + │ │ │ │ + 'end': '' │ │ │ │ +}; │ │ │ │ + │ │ │ │ +OpenLayers.Lang["no"] = OpenLayers.Lang["nb"]; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/TileCache.js │ │ │ │ + OpenLayers/Lang/pt.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. */ │ │ │ │ - │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Hamilton Abreu │ │ │ │ + * - Malafaya │ │ │ │ + * - Waldir │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.TileCache │ │ │ │ - * A read only TileCache layer. Used to requests tiles cached by TileCache in │ │ │ │ - * a web accessible cache. This means that you have to pre-populate your │ │ │ │ - * cache before this layer can be used. It is meant only to read tiles │ │ │ │ - * created by TileCache, and not to make calls to TileCache for tile │ │ │ │ - * creation. Create a new instance with the │ │ │ │ - * <OpenLayers.Layer.TileCache> constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * Namespace: OpenLayers.Lang["pt"] │ │ │ │ + * Dictionary for Português. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.TileCache = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ +OpenLayers.Lang["pt"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} Treat this layer as a base layer. Default is true. │ │ │ │ - */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + 'unhandledRequest': "Servidor devolveu erro não contemplado ${statusText}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: format │ │ │ │ - * {String} Mime type of the images returned. Default is image/png. │ │ │ │ - */ │ │ │ │ - format: 'image/png', │ │ │ │ + 'Permalink': "Ligação permanente", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. (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, │ │ │ │ + 'Overlays': "Sobreposições", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.TileCache │ │ │ │ - * Create a new read only TileCache layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} Name of the layer displayed in the interface │ │ │ │ - * url - {String} Location of the web accessible cache (not the location of │ │ │ │ - * your tilecache script!) │ │ │ │ - * layername - {String} Layer name as defined in the TileCache │ │ │ │ - * configuration │ │ │ │ - * options - {Object} Optional object with properties to be set on the │ │ │ │ - * layer. Note that you should speficy your resolutions to match │ │ │ │ - * your TileCache configuration. This can be done by setting │ │ │ │ - * the resolutions array directly (here or on the map), by setting │ │ │ │ - * maxResolution and numZoomLevels, or by using scale based properties. │ │ │ │ - */ │ │ │ │ - initialize: function(name, url, layername, options) { │ │ │ │ - this.layername = layername; │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, │ │ │ │ - [name, url, {}, options]); │ │ │ │ - this.extension = this.format.split('/')[1].toLowerCase(); │ │ │ │ - this.extension = (this.extension == 'jpg') ? 'jpeg' : this.extension; │ │ │ │ - }, │ │ │ │ + 'Base Layer': "Camada Base", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * obj - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.TileCache>} An exact clone of this │ │ │ │ - * <OpenLayers.Layer.TileCache> │ │ │ │ - */ │ │ │ │ - clone: function(obj) { │ │ │ │ + 'noFID': "Não é possível atualizar um elemento para a qual não há FID.", │ │ │ │ │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.TileCache(this.name, │ │ │ │ - this.url, │ │ │ │ - this.layername, │ │ │ │ - this.getOptions()); │ │ │ │ - } │ │ │ │ + 'browserNotSupported': "O seu navegador não suporta renderização vetorial. Actualmente os renderizadores suportados são:\n${renderers}", │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + 'minZoomLevelError': "A propriedade minZoomLevel só deve ser usada com as camadas descendentes da FixedZoomLevels. A verificação da propriedade por esta camada wfs é uma relíquia do passado. No entanto, não podemos removê-la sem correr o risco de afectar aplicações OL que dependam dela. Portanto, estamos a torná-la obsoleta -- a verificação minZoomLevel será removida na versão 3.0. Em vez dela, por favor, use as opções de resolução min/max descritas aqui: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - // copy/set any non-init, non-simple values here │ │ │ │ + 'commitSuccess': "Transacção WFS: SUCESSO ${response}", │ │ │ │ │ │ │ │ - return obj; │ │ │ │ - }, │ │ │ │ + 'commitFailed': "Transacção WFS: FALHOU ${response}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 res = this.getServerResolution(); │ │ │ │ - var bbox = this.maxExtent; │ │ │ │ - var size = this.tileSize; │ │ │ │ - var tileX = Math.round((bounds.left - bbox.left) / (res * size.w)); │ │ │ │ - var tileY = Math.round((bounds.bottom - bbox.bottom) / (res * size.h)); │ │ │ │ - var tileZ = this.serverResolutions != null ? │ │ │ │ - OpenLayers.Util.indexOf(this.serverResolutions, res) : │ │ │ │ - this.map.getZoom(); │ │ │ │ + 'googleWarning': "A Camada Google não foi correctamente carregada.\x3cbr\x3e\x3cbr\x3ePara deixar de receber esta mensagem, seleccione uma nova Camada-Base no \'\'switcher\'\' de camadas no canto superior direito.\x3cbr\x3e\x3cbr\x3eProvavelmente, isto acontece porque o \'\'script\'\' da biblioteca do Google Maps não foi incluído ou não contém a chave API correcta para o seu sítio.\x3cbr\x3e\x3cbr\x3eProgramadores: Para ajuda sobre como solucionar o problema \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclique aqui\x3c/a\x3e .", │ │ │ │ │ │ │ │ - var components = [ │ │ │ │ - this.layername, │ │ │ │ - OpenLayers.Number.zeroPad(tileZ, 2), │ │ │ │ - OpenLayers.Number.zeroPad(parseInt(tileX / 1000000), 3), │ │ │ │ - OpenLayers.Number.zeroPad((parseInt(tileX / 1000) % 1000), 3), │ │ │ │ - OpenLayers.Number.zeroPad((parseInt(tileX) % 1000), 3), │ │ │ │ - OpenLayers.Number.zeroPad(parseInt(tileY / 1000000), 3), │ │ │ │ - OpenLayers.Number.zeroPad((parseInt(tileY / 1000) % 1000), 3), │ │ │ │ - OpenLayers.Number.zeroPad((parseInt(tileY) % 1000), 3) + '.' + this.extension │ │ │ │ - ]; │ │ │ │ - var path = components.join('/'); │ │ │ │ - var url = this.url; │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(path, url); │ │ │ │ - } │ │ │ │ - url = (url.charAt(url.length - 1) == '/') ? url : url + '/'; │ │ │ │ - return url + path; │ │ │ │ - }, │ │ │ │ + 'getLayerWarning': "A camada ${layerType} não foi correctamente carregada.\x3cbr\x3e\x3cbr\x3ePara desactivar esta mensagem, seleccione uma nova Camada-Base no \'\'switcher\'\' de camadas no canto superior direito.\x3cbr\x3e\x3cbr\x3eProvavelmente, isto acontece porque o \'\'script\'\' da biblioteca ${layerLib} não foi incluído correctamente.\x3cbr\x3e\x3cbr\x3eProgramadores: Para ajuda sobre como solucionar o problema \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclique aqui\x3c/a\x3e .", │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Escala = 1 : ${scaleDenom}", │ │ │ │ + │ │ │ │ + 'W': "O", │ │ │ │ + │ │ │ │ + 'E': "E", │ │ │ │ + │ │ │ │ + 'N': "N", │ │ │ │ + │ │ │ │ + 'S': "S", │ │ │ │ + │ │ │ │ + 'reprojectDeprecated': "Está usando a opção \'reproject\' na camada ${layerName}. Esta opção é obsoleta: foi concebida para permitir a apresentação de dados sobre mapas-base comerciais, mas esta funcionalidade é agora suportada pelo Mercator Esférico. Mais informação está disponível em http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + │ │ │ │ + 'methodDeprecated': "Este método foi declarado obsoleto e será removido na versão 3.0. Por favor, use ${newMethod} em vez disso." │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.TileCache" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/Text.js │ │ │ │ + OpenLayers/Lang/en.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/Feature/Vector.js │ │ │ │ - * @requires OpenLayers/Geometry/Point.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.Text │ │ │ │ - * Read Text format. Create a new instance with the <OpenLayers.Format.Text> │ │ │ │ - * constructor. This reads text which is formatted like CSV text, using │ │ │ │ - * tabs as the seperator by default. It provides parsing of data originally │ │ │ │ - * used in the MapViewerService, described on the wiki. This Format is used │ │ │ │ - * by the <OpenLayers.Layer.Text> class. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format> │ │ │ │ + * Namespace: OpenLayers.Lang["en"] │ │ │ │ + * Dictionary for English. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Format.Text = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ +OpenLayers.Lang.en = { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: defaultStyle │ │ │ │ - * defaultStyle allows one to control the default styling of the features. │ │ │ │ - * It should be a symbolizer hash. By default, this is set to match the │ │ │ │ - * Layer.Text behavior, which is to use the default OpenLayers Icon. │ │ │ │ - */ │ │ │ │ - defaultStyle: null, │ │ │ │ + 'unhandledRequest': "Unhandled request return ${statusText}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: extractStyles │ │ │ │ - * set to true to extract styles from the TSV files, using information │ │ │ │ - * from the image or icon, iconSize and iconOffset fields. This will result │ │ │ │ - * in features with a symbolizer (style) property set, using the │ │ │ │ - * default symbolizer specified in <defaultStyle>. Set to false if you │ │ │ │ - * wish to use a styleMap or OpenLayers.Style options to style your │ │ │ │ - * layer instead. │ │ │ │ - */ │ │ │ │ - extractStyles: true, │ │ │ │ + 'Permalink': "Permalink", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.Text │ │ │ │ - * Create a new parser for TSV Text. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ + 'Overlays': "Overlays", │ │ │ │ │ │ │ │ - if (options.extractStyles !== false) { │ │ │ │ - options.defaultStyle = { │ │ │ │ - 'externalGraphic': OpenLayers.Util.getImageLocation("marker.png"), │ │ │ │ - 'graphicWidth': 21, │ │ │ │ - 'graphicHeight': 25, │ │ │ │ - 'graphicXOffset': -10.5, │ │ │ │ - 'graphicYOffset': -12.5 │ │ │ │ - }; │ │ │ │ - } │ │ │ │ + 'Base Layer': "Base Layer", │ │ │ │ │ │ │ │ - OpenLayers.Format.prototype.initialize.apply(this, [options]); │ │ │ │ - }, │ │ │ │ + 'noFID': "Can't update a feature for which there is no FID.", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Return a list of features from a Tab Seperated Values text string. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * text - {String} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ - */ │ │ │ │ - read: function(text) { │ │ │ │ - var lines = text.split('\n'); │ │ │ │ - var columns; │ │ │ │ - var features = []; │ │ │ │ - // length - 1 to allow for trailing new line │ │ │ │ - for (var lcv = 0; lcv < (lines.length - 1); lcv++) { │ │ │ │ - var currLine = lines[lcv].replace(/^\s*/, '').replace(/\s*$/, ''); │ │ │ │ + 'browserNotSupported': "Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}", │ │ │ │ │ │ │ │ - if (currLine.charAt(0) != '#') { │ │ │ │ - /* not a comment */ │ │ │ │ + // console message │ │ │ │ + 'minZoomLevelError': "The minZoomLevel property is only intended for use " + │ │ │ │ + "with the FixedZoomLevels-descendent layers. That this " + │ │ │ │ + "wfs layer checks for minZoomLevel is a relic of the" + │ │ │ │ + "past. We cannot, however, remove it without possibly " + │ │ │ │ + "breaking OL based applications that may depend on it." + │ │ │ │ + " Therefore we are deprecating it -- the minZoomLevel " + │ │ │ │ + "check below will be removed at 3.0. Please instead " + │ │ │ │ + "use min/max resolution setting as described here: " + │ │ │ │ + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - if (!columns) { │ │ │ │ - //First line is columns │ │ │ │ - columns = currLine.split('\t'); │ │ │ │ - } else { │ │ │ │ - var vals = currLine.split('\t'); │ │ │ │ - var geometry = new OpenLayers.Geometry.Point(0, 0); │ │ │ │ - var attributes = {}; │ │ │ │ - var style = this.defaultStyle ? │ │ │ │ - OpenLayers.Util.applyDefaults({}, this.defaultStyle) : │ │ │ │ - null; │ │ │ │ - var icon, iconSize, iconOffset, overflow; │ │ │ │ - var set = false; │ │ │ │ - for (var valIndex = 0; valIndex < vals.length; valIndex++) { │ │ │ │ - if (vals[valIndex]) { │ │ │ │ - if (columns[valIndex] == 'point') { │ │ │ │ - var coords = vals[valIndex].split(','); │ │ │ │ - geometry.y = parseFloat(coords[0]); │ │ │ │ - geometry.x = parseFloat(coords[1]); │ │ │ │ - set = true; │ │ │ │ - } else if (columns[valIndex] == 'lat') { │ │ │ │ - geometry.y = parseFloat(vals[valIndex]); │ │ │ │ - set = true; │ │ │ │ - } else if (columns[valIndex] == 'lon') { │ │ │ │ - geometry.x = parseFloat(vals[valIndex]); │ │ │ │ - set = true; │ │ │ │ - } else if (columns[valIndex] == 'title') │ │ │ │ - attributes['title'] = vals[valIndex]; │ │ │ │ - else if (columns[valIndex] == 'image' || │ │ │ │ - columns[valIndex] == 'icon' && style) { │ │ │ │ - style['externalGraphic'] = vals[valIndex]; │ │ │ │ - } else if (columns[valIndex] == 'iconSize' && style) { │ │ │ │ - var size = vals[valIndex].split(','); │ │ │ │ - style['graphicWidth'] = parseFloat(size[0]); │ │ │ │ - style['graphicHeight'] = parseFloat(size[1]); │ │ │ │ - } else if (columns[valIndex] == 'iconOffset' && style) { │ │ │ │ - var offset = vals[valIndex].split(','); │ │ │ │ - style['graphicXOffset'] = parseFloat(offset[0]); │ │ │ │ - style['graphicYOffset'] = parseFloat(offset[1]); │ │ │ │ - } else if (columns[valIndex] == 'description') { │ │ │ │ - attributes['description'] = vals[valIndex]; │ │ │ │ - } else if (columns[valIndex] == 'overflow') { │ │ │ │ - attributes['overflow'] = vals[valIndex]; │ │ │ │ - } else { │ │ │ │ - // For StyleMap filtering, allow additional │ │ │ │ - // columns to be stored as attributes. │ │ │ │ - attributes[columns[valIndex]] = vals[valIndex]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (set) { │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - geometry.transform(this.externalProjection, │ │ │ │ - this.internalProjection); │ │ │ │ - } │ │ │ │ - var feature = new OpenLayers.Feature.Vector(geometry, attributes, style); │ │ │ │ - features.push(feature); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return features; │ │ │ │ - }, │ │ │ │ + 'commitSuccess': "WFS Transaction: SUCCESS ${response}", │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.Text" │ │ │ │ -}); │ │ │ │ + 'commitFailed': "WFS Transaction: FAILED ${response}", │ │ │ │ + │ │ │ │ + 'googleWarning': "The Google Layer was unable to load correctly.<br><br>" + │ │ │ │ + "To get rid of this message, select a new BaseLayer " + │ │ │ │ + "in the layer switcher in the upper-right corner.<br><br>" + │ │ │ │ + "Most likely, this is because the Google Maps library " + │ │ │ │ + "script was either not included, or does not contain the " + │ │ │ │ + "correct API key for your site.<br><br>" + │ │ │ │ + "Developers: For help getting this working correctly, " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ + "target='_blank'>click here</a>", │ │ │ │ + │ │ │ │ + 'getLayerWarning': "The ${layerType} Layer was unable to load correctly.<br><br>" + │ │ │ │ + "To get rid of this message, select a new BaseLayer " + │ │ │ │ + "in the layer switcher in the upper-right corner.<br><br>" + │ │ │ │ + "Most likely, this is because the ${layerLib} library " + │ │ │ │ + "script was not correctly included.<br><br>" + │ │ │ │ + "Developers: For help getting this working correctly, " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ + "target='_blank'>click here</a>", │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Scale = 1 : ${scaleDenom}", │ │ │ │ + │ │ │ │ + //labels for the graticule control │ │ │ │ + 'W': 'W', │ │ │ │ + 'E': 'E', │ │ │ │ + 'N': 'N', │ │ │ │ + 'S': 'S', │ │ │ │ + 'Graticule': 'Graticule', │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'reprojectDeprecated': "You are using the 'reproject' option " + │ │ │ │ + "on the ${layerName} layer. This option is deprecated: " + │ │ │ │ + "its use was designed to support displaying data over commercial " + │ │ │ │ + "basemaps, but that functionality should now be achieved by using " + │ │ │ │ + "Spherical Mercator support. More information is available from " + │ │ │ │ + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'methodDeprecated': "This method has been deprecated and will be removed in 3.0. " + │ │ │ │ + "Please use ${newMethod} instead.", │ │ │ │ + │ │ │ │ + // **** end **** │ │ │ │ + 'end': '' │ │ │ │ + │ │ │ │ +}; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/Text.js │ │ │ │ + OpenLayers/Lang/fr.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. */ │ │ │ │ - │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Damouns │ │ │ │ + * - IAlex │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * @requires OpenLayers/Layer/Markers.js │ │ │ │ - * @requires OpenLayers/Format/Text.js │ │ │ │ - * @requires OpenLayers/Request/XMLHttpRequest.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.Text │ │ │ │ - * This layer creates markers given data in a text file. The <location> │ │ │ │ - * property of the layer (specified as a property of the options argument │ │ │ │ - * in the <OpenLayers.Layer.Text> constructor) points to a tab delimited │ │ │ │ - * file with data used to create markers. │ │ │ │ - * │ │ │ │ - * The first row of the data file should be a header line with the column names │ │ │ │ - * of the data. Each column should be delimited by a tab space. The │ │ │ │ - * possible columns are: │ │ │ │ - * - *point* lat,lon of the point where a marker is to be placed │ │ │ │ - * - *lat* Latitude of the point where a marker is to be placed │ │ │ │ - * - *lon* Longitude of the point where a marker is to be placed │ │ │ │ - * - *icon* or *image* URL of marker icon to use. │ │ │ │ - * - *iconSize* Size of Icon to use. │ │ │ │ - * - *iconOffset* Where the top-left corner of the icon is to be placed │ │ │ │ - * relative to the latitude and longitude of the point. │ │ │ │ - * - *title* The text of the 'title' is placed inside an 'h2' marker │ │ │ │ - * inside a popup, which opens when the marker is clicked. │ │ │ │ - * - *description* The text of the 'description' is placed below the h2 │ │ │ │ - * in the popup. this can be plain text or HTML. │ │ │ │ - * │ │ │ │ - * Example text file: │ │ │ │ - * (code) │ │ │ │ - * lat lon title description iconSize iconOffset icon │ │ │ │ - * 10 20 title description 21,25 -10,-25 http://www.openlayers.org/dev/img/marker.png │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Markers> │ │ │ │ + * Namespace: OpenLayers.Lang["fr"] │ │ │ │ + * Dictionary for Français. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.Text = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ +OpenLayers.Lang["fr"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: location │ │ │ │ - * {String} URL of text file. Must be specified in the "options" argument │ │ │ │ - * of the constructor. Can not be changed once passed in. │ │ │ │ - */ │ │ │ │ - location: null, │ │ │ │ + 'unhandledRequest': "Requête non gérée, retournant ${statusText}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: features │ │ │ │ - * {Array(<OpenLayers.Feature>)} │ │ │ │ - */ │ │ │ │ - features: null, │ │ │ │ + 'Permalink': "Permalien", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: formatOptions │ │ │ │ - * {Object} Hash of options which should be passed to the format when it is │ │ │ │ - * created. Must be passed in the constructor. │ │ │ │ - */ │ │ │ │ - formatOptions: null, │ │ │ │ + 'Overlays': "Calques", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: selectedFeature │ │ │ │ - * {<OpenLayers.Feature>} │ │ │ │ - */ │ │ │ │ - selectedFeature: null, │ │ │ │ + 'Base Layer': "Calque de base", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.Text │ │ │ │ - * Create a text layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * options - {Object} Object with properties to be set on the layer. │ │ │ │ - * Must include <location> property. │ │ │ │ - */ │ │ │ │ - initialize: function(name, options) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.initialize.apply(this, arguments); │ │ │ │ - this.features = []; │ │ │ │ - }, │ │ │ │ + 'noFID': "Impossible de mettre à jour un objet sans identifiant (fid).", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - // Warning: Layer.Markers.destroy() must be called prior to calling │ │ │ │ - // clearFeatures() here, otherwise we leak memory. Indeed, if │ │ │ │ - // Layer.Markers.destroy() is called after clearFeatures(), it won't be │ │ │ │ - // able to remove the marker image elements from the layer's div since │ │ │ │ - // the markers will have been destroyed by clearFeatures(). │ │ │ │ - OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ - this.clearFeatures(); │ │ │ │ - this.features = null; │ │ │ │ - }, │ │ │ │ + 'browserNotSupported': "Votre navigateur ne supporte pas le rendu vectoriel. Les renderers actuellement supportés sont : \n${renderers}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: loadText │ │ │ │ - * Start the load of the Text data. Don't do this when we first add the layer, │ │ │ │ - * since we may not be visible at any point, and it would therefore be a waste. │ │ │ │ - */ │ │ │ │ - loadText: function() { │ │ │ │ - if (!this.loaded) { │ │ │ │ - if (this.location != null) { │ │ │ │ + 'minZoomLevelError': "La propriété minZoomLevel doit seulement être utilisée pour des couches FixedZoomLevels-descendent. Le fait que cette couche WFS vérifie la présence de minZoomLevel est une relique du passé. Nous ne pouvons toutefois la supprimer sans casser des applications qui pourraient en dépendre. C\'est pourquoi nous la déprécions -- la vérification du minZoomLevel sera supprimée en version 3.0. A la place, merci d\'utiliser les paramètres de résolutions min/max tel que décrit sur : http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - var onFail = function(e) { │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ - }; │ │ │ │ + 'commitSuccess': "Transaction WFS : SUCCES ${response}", │ │ │ │ │ │ │ │ - this.events.triggerEvent("loadstart"); │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ - url: this.location, │ │ │ │ - success: this.parseData, │ │ │ │ - failure: onFail, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.loaded = true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'commitFailed': "Transaction WFS : ECHEC ${response}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: moveTo │ │ │ │ - * If layer is visible and Text has not been loaded, load Text. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {Object} │ │ │ │ - * zoomChanged - {Object} │ │ │ │ - * minor - {Object} │ │ │ │ - */ │ │ │ │ - moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ - if (this.visibility && !this.loaded) { │ │ │ │ - this.loadText(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'googleWarning': "La couche Google n\'a pas été en mesure de se charger correctement.\x3cbr\x3e\x3cbr\x3ePour supprimer ce message, choisissez une nouvelle BaseLayer dans le sélecteur de couche en haut à droite.\x3cbr\x3e\x3cbr\x3eCela est possiblement causé par la non-inclusion de la librairie Google Maps, ou alors parce que la clé de l\'API ne correspond pas à votre site.\x3cbr\x3e\x3cbr\x3eDéveloppeurs : pour savoir comment corriger ceci, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3ecliquez ici\x3c/a\x3e", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: parseData │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * ajaxRequest - {<OpenLayers.Request.XMLHttpRequest>} │ │ │ │ - */ │ │ │ │ - parseData: function(ajaxRequest) { │ │ │ │ - var text = ajaxRequest.responseText; │ │ │ │ + 'getLayerWarning': "La couche ${layerType} n\'est pas en mesure de se charger correctement.\x3cbr\x3e\x3cbr\x3ePour supprimer ce message, choisissez une nouvelle BaseLayer dans le sélecteur de couche en haut à droite.\x3cbr\x3e\x3cbr\x3eCela est possiblement causé par la non-inclusion de la librairie ${layerLib}.\x3cbr\x3e\x3cbr\x3eDéveloppeurs : pour savoir comment corriger ceci, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3ecliquez ici\x3c/a\x3e", │ │ │ │ │ │ │ │ - var options = {}; │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Echelle ~ 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ + 'W': "O", │ │ │ │ │ │ │ │ - if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ - options.externalProjection = this.projection; │ │ │ │ - options.internalProjection = this.map.getProjectionObject(); │ │ │ │ - } │ │ │ │ + 'E': "E", │ │ │ │ │ │ │ │ - var parser = new OpenLayers.Format.Text(options); │ │ │ │ - var features = parser.read(text); │ │ │ │ - for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ - var data = {}; │ │ │ │ - var feature = features[i]; │ │ │ │ - var location; │ │ │ │ - var iconSize, iconOffset; │ │ │ │ + 'N': "N", │ │ │ │ │ │ │ │ - location = new OpenLayers.LonLat(feature.geometry.x, │ │ │ │ - feature.geometry.y); │ │ │ │ + 'S': "S", │ │ │ │ │ │ │ │ - if (feature.style.graphicWidth && │ │ │ │ - feature.style.graphicHeight) { │ │ │ │ - iconSize = new OpenLayers.Size( │ │ │ │ - feature.style.graphicWidth, │ │ │ │ - feature.style.graphicHeight); │ │ │ │ - } │ │ │ │ + 'reprojectDeprecated': "Vous utilisez l\'option \'reproject\' sur la couche ${layerName}. Cette option est dépréciée : Son usage permettait d\'afficher des données au dessus de couches raster commerciales.Cette fonctionalité est maintenant supportée en utilisant le support de la projection Mercator Sphérique. Plus d\'information est disponible sur http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ │ │ │ │ - // FIXME: At the moment, we only use this if we have an │ │ │ │ - // externalGraphic, because icon has no setOffset API Method. │ │ │ │ - /** │ │ │ │ - * FIXME FIRST!! │ │ │ │ - * The Text format does all sorts of parseFloating │ │ │ │ - * The result of a parseFloat for a bogus string is NaN. That │ │ │ │ - * means the three possible values here are undefined, NaN, or a │ │ │ │ - * number. The previous check was an identity check for null. This │ │ │ │ - * means it was failing for all undefined or NaN. A slightly better │ │ │ │ - * check is for undefined. An even better check is to see if the │ │ │ │ - * value is a number (see #1441). │ │ │ │ - */ │ │ │ │ - if (feature.style.graphicXOffset !== undefined && │ │ │ │ - feature.style.graphicYOffset !== undefined) { │ │ │ │ - iconOffset = new OpenLayers.Pixel( │ │ │ │ - feature.style.graphicXOffset, │ │ │ │ - feature.style.graphicYOffset); │ │ │ │ - } │ │ │ │ + 'methodDeprecated': "Cette méthode est dépréciée, et sera supprimée à la version 3.0. Merci d\'utiliser ${newMethod} à la place." │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/de.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - if (feature.style.externalGraphic != null) { │ │ │ │ - data.icon = new OpenLayers.Icon(feature.style.externalGraphic, │ │ │ │ - iconSize, │ │ │ │ - iconOffset); │ │ │ │ - } else { │ │ │ │ - data.icon = OpenLayers.Marker.defaultIcon(); │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Grille chompa │ │ │ │ + * - Nikiwaibel │ │ │ │ + * - Umherirrender │ │ │ │ + */ │ │ │ │ │ │ │ │ - //allows for the case where the image url is not │ │ │ │ - // specified but the size is. use a default icon │ │ │ │ - // but change the size │ │ │ │ - if (iconSize != null) { │ │ │ │ - data.icon.setSize(iconSize); │ │ │ │ - } │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - if ((feature.attributes.title != null) && │ │ │ │ - (feature.attributes.description != null)) { │ │ │ │ - data['popupContentHTML'] = │ │ │ │ - '<h2>' + feature.attributes.title + '</h2>' + │ │ │ │ - '<p>' + feature.attributes.description + '</p>'; │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["de"] │ │ │ │ + * Dictionary for Deutsch. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["de"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - data['overflow'] = feature.attributes.overflow || "auto"; │ │ │ │ + 'unhandledRequest': "Unbehandelte Anfragerückmeldung ${statusText}", │ │ │ │ │ │ │ │ - var markerFeature = new OpenLayers.Feature(this, location, data); │ │ │ │ - this.features.push(markerFeature); │ │ │ │ - var marker = markerFeature.createMarker(); │ │ │ │ - if ((feature.attributes.title != null) && │ │ │ │ - (feature.attributes.description != null)) { │ │ │ │ - marker.events.register('click', markerFeature, this.markerClick); │ │ │ │ - } │ │ │ │ - this.addMarker(marker); │ │ │ │ - } │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ - }, │ │ │ │ + 'Permalink': "Permalink", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: markerClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ - * Context: │ │ │ │ - * - {<OpenLayers.Feature>} │ │ │ │ - */ │ │ │ │ - markerClick: function(evt) { │ │ │ │ - var sameMarkerClicked = (this == this.layer.selectedFeature); │ │ │ │ - this.layer.selectedFeature = (!sameMarkerClicked) ? this : null; │ │ │ │ - for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ - this.layer.map.removePopup(this.layer.map.popups[i]); │ │ │ │ - } │ │ │ │ - if (!sameMarkerClicked) { │ │ │ │ - this.layer.map.addPopup(this.createPopup()); │ │ │ │ - } │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - }, │ │ │ │ + 'Overlays': "Overlays", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: clearFeatures │ │ │ │ - */ │ │ │ │ - clearFeatures: function() { │ │ │ │ - if (this.features != null) { │ │ │ │ - while (this.features.length > 0) { │ │ │ │ - var feature = this.features[0]; │ │ │ │ - OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ - feature.destroy(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'Base Layer': "Grundkarte", │ │ │ │ + │ │ │ │ + 'noFID': "Ein Feature, für das keine FID existiert, kann nicht aktualisiert werden.", │ │ │ │ + │ │ │ │ + 'browserNotSupported': "Ihr Browser unterstützt keine Vektordarstellung. Aktuell unterstützte Renderer:\n${renderers}", │ │ │ │ + │ │ │ │ + 'minZoomLevelError': "Die \x3ccode\x3eminZoomLevel\x3c/code\x3e-Eigenschaft ist nur für die Verwendung mit \x3ccode\x3eFixedZoomLevels\x3c/code\x3e-untergeordneten Layers vorgesehen. Das dieser \x3ctt\x3ewfs\x3c/tt\x3e-Layer die \x3ccode\x3eminZoomLevel\x3c/code\x3e-Eigenschaft überprüft ist ein Relikt der Vergangenheit. Wir können diese Überprüfung nicht entfernen, ohne das OL basierende Applikationen nicht mehr funktionieren. Daher markieren wir es als veraltet - die \x3ccode\x3eminZoomLevel\x3c/code\x3e-Überprüfung wird in Version 3.0 entfernt werden. Bitte verwenden Sie stattdessen die Min-/Max-Lösung, wie sie unter http://trac.openlayers.org/wiki/SettingZoomLevels beschrieben ist.", │ │ │ │ + │ │ │ │ + 'commitSuccess': "WFS-Transaktion: Erfolgreich ${response}", │ │ │ │ + │ │ │ │ + 'commitFailed': "WFS-Transaktion: Fehlgeschlagen ${response}", │ │ │ │ + │ │ │ │ + 'googleWarning': "Der Google-Layer konnte nicht korrekt geladen werden.\x3cbr\x3e\x3cbr\x3eUm diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.\x3cbr\x3e\x3cbr\x3eSehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der Google-Maps-Bibliothek nicht eingebunden wurde oder keinen gültigen API-Schlüssel für Ihre URL enthält.\x3cbr\x3e\x3cbr\x3eEntwickler: Besuche \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3edas Wiki\x3c/a\x3e für Hilfe zum korrekten Einbinden des Google-Layers", │ │ │ │ + │ │ │ │ + 'getLayerWarning': "Der ${layerType}-Layer konnte nicht korrekt geladen werden.\x3cbr\x3e\x3cbr\x3eUm diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.\x3cbr\x3e\x3cbr\x3eSehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der \'${layerLib}\'-Bibliothek nicht eingebunden wurde.\x3cbr\x3e\x3cbr\x3eEntwickler: Besuche \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3edas Wiki\x3c/a\x3e für Hilfe zum korrekten Einbinden von Layern", │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Maßstab = 1 : ${scaleDenom}", │ │ │ │ + │ │ │ │ + 'W': "W", │ │ │ │ + │ │ │ │ + 'E': "O", │ │ │ │ + │ │ │ │ + 'N': "N", │ │ │ │ + │ │ │ │ + 'S': "S", │ │ │ │ + │ │ │ │ + 'reprojectDeprecated': "Sie verwenden die „Reproject“-Option des Layers ${layerName}. Diese Option ist veraltet: Sie wurde entwickelt um die Anzeige von Daten auf kommerziellen Basiskarten zu unterstützen, aber diese Funktion sollte jetzt durch Unterstützung der „Spherical Mercator“ erreicht werden. Weitere Informationen sind unter http://trac.openlayers.org/wiki/SphericalMercator verfügbar.", │ │ │ │ + │ │ │ │ + 'methodDeprecated': "Die Methode ist veraltet und wird in 3.0 entfernt. Bitte verwende stattdessen ${newMethod}." │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Text" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/Boxes.js │ │ │ │ + OpenLayers/Lang/km.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. */ │ │ │ │ - │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - វ័ណថារិទ្ធ │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * @requires OpenLayers/Layer.js │ │ │ │ - * @requires OpenLayers/Layer/Markers.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.Boxes │ │ │ │ - * Draw divs as 'boxes' on the layer. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Markers> │ │ │ │ + * Namespace: OpenLayers.Lang["km"] │ │ │ │ + * Dictionary for ភាសាខ្មែរ. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.Boxes = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.Boxes │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ - */ │ │ │ │ +OpenLayers.Lang["km"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: drawMarker │ │ │ │ - * Calculate the pixel location for the marker, create it, and │ │ │ │ - * add it to the layer's div │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * marker - {<OpenLayers.Marker.Box>} │ │ │ │ - */ │ │ │ │ - drawMarker: function(marker) { │ │ │ │ - var topleft = this.map.getLayerPxFromLonLat({ │ │ │ │ - lon: marker.bounds.left, │ │ │ │ - lat: marker.bounds.top │ │ │ │ - }); │ │ │ │ - var botright = this.map.getLayerPxFromLonLat({ │ │ │ │ - lon: marker.bounds.right, │ │ │ │ - lat: marker.bounds.bottom │ │ │ │ - }); │ │ │ │ - if (botright == null || topleft == null) { │ │ │ │ - marker.display(false); │ │ │ │ - } else { │ │ │ │ - var markerDiv = marker.draw(topleft, { │ │ │ │ - w: Math.max(1, botright.x - topleft.x), │ │ │ │ - h: Math.max(1, botright.y - topleft.y) │ │ │ │ - }); │ │ │ │ - if (!marker.drawn) { │ │ │ │ - this.div.appendChild(markerDiv); │ │ │ │ - marker.drawn = true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'Permalink': "តំណភ្ជាប់អចិន្ត្រៃយ៍", │ │ │ │ │ │ │ │ + 'Base Layer': "ស្រទាប់បាត​", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: removeMarker │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * marker - {<OpenLayers.Marker.Box>} │ │ │ │ - */ │ │ │ │ - removeMarker: function(marker) { │ │ │ │ - OpenLayers.Util.removeItem(this.markers, marker); │ │ │ │ - if ((marker.div != null) && │ │ │ │ - (marker.div.parentNode == this.div)) { │ │ │ │ - this.div.removeChild(marker.div); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "មាត្រដ្ឋាន = ១ ៖ ${scaleDenom}" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Boxes" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/PointTrack.js │ │ │ │ + OpenLayers/Lang/ro.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/Lang.js │ │ │ │ + */ │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["ro"] │ │ │ │ + * Dictionary for Romanian. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang.ro = { │ │ │ │ + 'unhandledRequest': "Cerere nesoluționată return ${statusText}", │ │ │ │ + 'Permalink': "Legatură permanentă", │ │ │ │ + 'Overlays': "Straturi vector", │ │ │ │ + 'Base Layer': "Straturi de bază", │ │ │ │ + 'noFID': "Nu pot actualiza un feature pentru care nu există FID.", │ │ │ │ + 'browserNotSupported': "Browserul tău nu suportă afișarea vectorilor. Supoetul curent pentru randare:\n${renderers}", │ │ │ │ + // console message │ │ │ │ + 'minZoomLevelError': "Proprietatea minZoomLevel este doar pentru a fi folosită " + │ │ │ │ + "cu straturile FixedZoomLevels-descendent. De aceea acest " + │ │ │ │ + "strat wfs verifică dacă minZoomLevel este o relicvă" + │ │ │ │ + ". Nu îl putem , oricum, înlătura fără " + │ │ │ │ + "a afecta aplicațiile Openlayers care depind de ea." + │ │ │ │ + " De aceea considerăm depreciat -- minZoomLevel " + │ │ │ │ + "și îl vom înlătura în 3.0. Folosește " + │ │ │ │ + "min/max resolution cum este descrisă aici: " + │ │ │ │ + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + 'commitSuccess': "Tranzacție WFS: SUCCES ${response}", │ │ │ │ + 'commitFailed': "Tranzacție WFS : EȘEC ${response}", │ │ │ │ + 'googleWarning': "Stratul Google nu a putut fi încărcat corect.<br><br>" + │ │ │ │ + "Pentru a elimina acest mesaj, selectează un nou strat de bază " + │ │ │ │ + "în Layerswitcher din colțul dreata-sus.<br><br>" + │ │ │ │ + "Asta datorită, faptului că Google Maps library " + │ │ │ │ + "script nu este inclus, sau nu conține " + │ │ │ │ + "cheia API corectă pentru situl tău.<br><br>" + │ │ │ │ + "Developeri: Pentru ajutor, " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ + "target='_blank'>apăsați aici</a>", │ │ │ │ + 'getLayerWarning': "Stratul ${layerType} nu a putut fi încărcat corect.<br><br>" + │ │ │ │ + "pentru a înlătura acest mesaj, selectează un nou strat de bază " + │ │ │ │ + "Acesta eroare apare de obicei când ${layerLib} library " + │ │ │ │ + "script nu a fost încărcat corect.<br><br>" + │ │ │ │ + "Developeri: Pentru ajutor privind utilizarea corectă, " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ + "target='_blank'>apasă aici</a>", │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Scara = 1 : ${scaleDenom}", │ │ │ │ + //labels for the graticule control │ │ │ │ + 'W': 'V', │ │ │ │ + 'E': 'E', │ │ │ │ + 'N': 'N', │ │ │ │ + 'S': 'S', │ │ │ │ + 'Graticule': 'Graticule', │ │ │ │ + // console message │ │ │ │ + 'reprojectDeprecated': "folosești opțiunea 'reproject' " + │ │ │ │ + "pentru stratul ${layerName} . Această opțiune este depreciată: " + │ │ │ │ + "a fost utilizată pentru afișarea straturilor de bază comerciale " + │ │ │ │ + "Mai multe informații despre proiecția Mercator sunt disponibile aici " + │ │ │ │ + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + // console message │ │ │ │ + 'methodDeprecated': "Această metodă este depreciată și va fi înlăturată in versiunea 3.0. " + │ │ │ │ + "folosește metoda ${newMethod}.", │ │ │ │ + // **** end **** │ │ │ │ + 'end': '' │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/cs-CZ.js │ │ │ │ + ====================================================================== */ │ │ │ │ + │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Mormegil │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * @requires OpenLayers/Layer/Vector.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.PointTrack │ │ │ │ - * Vector layer to display ordered point features as a line, creating one │ │ │ │ - * LineString feature for each pair of two points. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Vector> │ │ │ │ + * Namespace: OpenLayers.Lang["cs-CZ"] │ │ │ │ + * Dictionary for Česky. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.PointTrack = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ +OpenLayers.Lang["cs-CZ"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: dataFrom │ │ │ │ - * {<OpenLayers.Layer.PointTrack.TARGET_NODE>} or │ │ │ │ - * {<OpenLayers.Layer.PointTrack.SOURCE_NODE>} optional. If the lines │ │ │ │ - * should get the data/attributes from one of the two points it is │ │ │ │ - * composed of, which one should it be? │ │ │ │ - */ │ │ │ │ - dataFrom: null, │ │ │ │ + 'unhandledRequest': "Nezpracovaná návratová hodnota ${statusText}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: styleFrom │ │ │ │ - * {<OpenLayers.Layer.PointTrack.TARGET_NODE>} or │ │ │ │ - * {<OpenLayers.Layer.PointTrack.SOURCE_NODE>} optional. If the lines │ │ │ │ - * should get the style from one of the two points it is composed of, │ │ │ │ - * which one should it be? │ │ │ │ - */ │ │ │ │ - styleFrom: null, │ │ │ │ + 'Permalink': "Trvalý odkaz", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.PointTrack │ │ │ │ - * Constructor for a new OpenLayers.PointTrack instance. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} name of the layer │ │ │ │ - * options - {Object} Optional object with properties to tag onto the │ │ │ │ - * instance. │ │ │ │ - */ │ │ │ │ + 'Overlays': "Překryvné vrstvy", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: addNodes │ │ │ │ - * Adds point features that will be used to create lines from, using point │ │ │ │ - * pairs. The first point of a pair will be the source node, the second │ │ │ │ - * will be the target node. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * pointFeatures - {Array(<OpenLayers.Feature>)} │ │ │ │ - * options - {Object} │ │ │ │ - * │ │ │ │ - * Supported options: │ │ │ │ - * silent - {Boolean} true to suppress (before)feature(s)added events │ │ │ │ - */ │ │ │ │ - addNodes: function(pointFeatures, options) { │ │ │ │ - if (pointFeatures.length < 2) { │ │ │ │ - throw new Error("At least two point features have to be added to " + │ │ │ │ - "create a line from"); │ │ │ │ - } │ │ │ │ + 'Base Layer': "Podkladové vrstvy", │ │ │ │ │ │ │ │ - var lines = new Array(pointFeatures.length - 1); │ │ │ │ + 'noFID': "Nelze aktualizovat prvek, pro který neexistuje FID.", │ │ │ │ │ │ │ │ - var pointFeature, startPoint, endPoint; │ │ │ │ - for (var i = 0, len = pointFeatures.length; i < len; i++) { │ │ │ │ - pointFeature = pointFeatures[i]; │ │ │ │ - endPoint = pointFeature.geometry; │ │ │ │ + 'browserNotSupported': "Váš prohlížeč nepodporuje vykreslování vektorů. Momentálně podporované nástroje jsou::\n${renderers}", │ │ │ │ │ │ │ │ - if (!endPoint) { │ │ │ │ - var lonlat = pointFeature.lonlat; │ │ │ │ - endPoint = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat); │ │ │ │ - } else if (endPoint.CLASS_NAME != "OpenLayers.Geometry.Point") { │ │ │ │ - throw new TypeError("Only features with point geometries are supported."); │ │ │ │ - } │ │ │ │ + 'minZoomLevelError': "Vlastnost minZoomLevel by se měla používat pouze s potomky FixedZoomLevels vrstvami. To znamená, že vrstva wfs kontroluje, zda-li minZoomLevel není zbytek z minulosti.Nelze to ovšem vyjmout bez možnosti, že bychom rozbili aplikace postavené na OL, které by na tom mohly záviset. Proto tuto vlastnost nedoporučujeme používat -- kontrola minZoomLevel bude odstraněna ve verzi 3.0. Použijte prosím raději nastavení min/max podle příkaldu popsaného na: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - if (i > 0) { │ │ │ │ - var attributes = (this.dataFrom != null) ? │ │ │ │ - (pointFeatures[i + this.dataFrom].data || │ │ │ │ - pointFeatures[i + this.dataFrom].attributes) : │ │ │ │ - null; │ │ │ │ - var style = (this.styleFrom != null) ? │ │ │ │ - (pointFeatures[i + this.styleFrom].style) : │ │ │ │ - null; │ │ │ │ - var line = new OpenLayers.Geometry.LineString([startPoint, │ │ │ │ - endPoint │ │ │ │ - ]); │ │ │ │ + 'commitSuccess': "WFS Transaction: ÚSPĚCH ${response}", │ │ │ │ │ │ │ │ - lines[i - 1] = new OpenLayers.Feature.Vector(line, attributes, │ │ │ │ - style); │ │ │ │ - } │ │ │ │ + 'commitFailed': "WFS Transaction: CHYBA ${response}", │ │ │ │ │ │ │ │ - startPoint = endPoint; │ │ │ │ - } │ │ │ │ + 'googleWarning': "Nepodařilo se správně načíst vrstvu Google.\x3cbr\x3e\x3cbr\x3eAbyste se zbavili této zprávy, zvolte jinou základní vrstvu v přepínači vrstev.\x3cbr\x3e\x3cbr\x3eTo se většinou stává, pokud nebyl načten skript, nebo neobsahuje správný klíč pro API pro tuto stránku.\x3cbr\x3e\x3cbr\x3eVývojáři: Pro pomoc, aby tohle fungovalo , \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eklikněte sem\x3c/a\x3e", │ │ │ │ │ │ │ │ - this.addFeatures(lines, options); │ │ │ │ - }, │ │ │ │ + 'getLayerWarning': "The ${layerType} Layer was unable to load correctly.\x3cbr\x3e\x3cbr\x3eTo get rid of this message, select a new BaseLayer in the layer switcher in the upper-right corner.\x3cbr\x3e\x3cbr\x3eMost likely, this is because the ${layerLib} library script was either not correctly included.\x3cbr\x3e\x3cbr\x3eDevelopers: For help getting this working correctly, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclick here\x3c/a\x3e", │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Měřítko = 1 : ${scaleDenom}", │ │ │ │ + │ │ │ │ + 'reprojectDeprecated': "Použil jste volbu \'reproject\' ve vrstvě ${layerName}. Tato volba není doporučená: byla zde proto, aby bylo možno zobrazovat data z okomerčních serverů, ale tato funkce je nyní zajištěna pomocí podpory Spherical Mercator. Více informací naleznete na http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + │ │ │ │ + 'methodDeprecated': "Tato metoda je zavržená a bude ve verzi 3.0 odstraněna. Prosím, použijte raději ${newMethod}." │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.PointTrack" │ │ │ │ }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/te.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Layer.PointTrack.SOURCE_NODE │ │ │ │ - * {Number} value for <OpenLayers.Layer.PointTrack.dataFrom> and │ │ │ │ - * <OpenLayers.Layer.PointTrack.styleFrom> │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Veeven │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.PointTrack.SOURCE_NODE = -1; │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Layer.PointTrack.TARGET_NODE │ │ │ │ - * {Number} value for <OpenLayers.Layer.PointTrack.dataFrom> and │ │ │ │ - * <OpenLayers.Layer.PointTrack.styleFrom> │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.PointTrack.TARGET_NODE = 0; │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Layer.PointTrack.dataFrom │ │ │ │ - * {Object} with the following keys - *deprecated* │ │ │ │ - * - SOURCE_NODE: take data/attributes from the source node of the line │ │ │ │ - * - TARGET_NODE: take data/attributes from the target node of the line │ │ │ │ + * Namespace: OpenLayers.Lang["te"] │ │ │ │ + * Dictionary for తెలుగు. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.PointTrack.dataFrom = { │ │ │ │ - 'SOURCE_NODE': -1, │ │ │ │ - 'TARGET_NODE': 0 │ │ │ │ -}; │ │ │ │ +OpenLayers.Lang["te"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + │ │ │ │ + 'Permalink': "స్థిరలింకు", │ │ │ │ + │ │ │ │ + 'W': "ప", │ │ │ │ + │ │ │ │ + 'E': "తూ", │ │ │ │ + │ │ │ │ + 'N': "ఉ", │ │ │ │ + │ │ │ │ + 'S': "ద" │ │ │ │ + │ │ │ │ +}); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Tile/UTFGrid.js │ │ │ │ + OpenLayers/Lang/hsb.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. */ │ │ │ │ - │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Michawiki │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * @requires OpenLayers/Tile.js │ │ │ │ - * @requires OpenLayers/Format/JSON.js │ │ │ │ - * @requires OpenLayers/Request.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Tile.UTFGrid │ │ │ │ - * Instances of OpenLayers.Tile.UTFGrid are used to manage │ │ │ │ - * UTFGrids. This is an unusual tile type in that it doesn't have a │ │ │ │ - * rendered image; only a 'hit grid' that can be used to │ │ │ │ - * look up feature attributes. │ │ │ │ - * │ │ │ │ - * See the <OpenLayers.Tile.UTFGrid> constructor for details on constructing a │ │ │ │ - * new instance. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Tile> │ │ │ │ + * Namespace: OpenLayers.Lang["hsb"] │ │ │ │ + * Dictionary for Hornjoserbsce. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Tile.UTFGrid = OpenLayers.Class(OpenLayers.Tile, { │ │ │ │ +OpenLayers.Lang["hsb"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: url │ │ │ │ - * {String} │ │ │ │ - * The URL of the UTFGrid file being requested. Provided by the <getURL> │ │ │ │ - * method. │ │ │ │ - */ │ │ │ │ - url: null, │ │ │ │ + 'unhandledRequest': "Wotmołwa njewobdźěłaneho naprašowanja ${statusText}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: utfgridResolution │ │ │ │ - * {Number} │ │ │ │ - * Ratio of the pixel width to the width of a UTFGrid data point. If an │ │ │ │ - * entry in the grid represents a 4x4 block of pixels, the │ │ │ │ - * utfgridResolution would be 4. Default is 2. │ │ │ │ - */ │ │ │ │ - utfgridResolution: 2, │ │ │ │ + 'Permalink': "Trajny wotkaz", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: json │ │ │ │ - * {Object} │ │ │ │ - * Stores the parsed JSON tile data structure. │ │ │ │ - */ │ │ │ │ - json: null, │ │ │ │ + 'Overlays': "Naworštowanja", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: format │ │ │ │ - * {OpenLayers.Format.JSON} │ │ │ │ - * Parser instance used to parse JSON for cross browser support. The native │ │ │ │ - * JSON.parse method will be used where available (all except IE<8). │ │ │ │ - */ │ │ │ │ - format: null, │ │ │ │ + 'Base Layer': "Zakładna runina", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Tile.UTFGrid │ │ │ │ - * Constructor for a new <OpenLayers.Tile.UTFGrid> 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} │ │ │ │ - */ │ │ │ │ + 'noFID': "Funkcija, za kotruž FID njeje, njeda so aktualizować.", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Clean up. │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - this.clear(); │ │ │ │ - OpenLayers.Tile.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + 'browserNotSupported': "Twój wobhladowak wektorowe rysowanje njepodpěruje. Tuchwilu podpěrowane rysowaki su:\n${renderers}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * Check that a tile should be drawn, and draw it. │ │ │ │ - * In the case of UTFGrids, "drawing" it means fetching and │ │ │ │ - * parsing the json. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Was a tile drawn? │ │ │ │ - */ │ │ │ │ - draw: function() { │ │ │ │ - var drawn = OpenLayers.Tile.prototype.draw.apply(this, arguments); │ │ │ │ - if (drawn) { │ │ │ │ - if (this.isLoading) { │ │ │ │ - this.abortLoading(); │ │ │ │ - //if we're already loading, send 'reload' instead of 'loadstart'. │ │ │ │ - this.events.triggerEvent("reload"); │ │ │ │ - } else { │ │ │ │ - this.isLoading = true; │ │ │ │ - this.events.triggerEvent("loadstart"); │ │ │ │ - } │ │ │ │ - this.url = this.layer.getURL(this.bounds); │ │ │ │ + 'minZoomLevelError': "Kajkosć minZoomLevel je jenož za wužiwanje z worštami myslena, kotrež wot FixedZoomLevels pochadźeja. Zo tuta woršta wfs za minZoomLevel přepruwuje, je relikt zańdźenosće. Njemóžemy wšak ju wotstronić, bjeztoho zo aplikacije, kotrež na OpenLayers bazěruja a snano tutu kajkosć wužiwaja, hižo njefunguja. Tohodla smy ju jako zestarjenu woznamjenili -- přepruwowanje za minZoomLevel budu so we wersiji 3.0 wotstronjeć. Prošu wužij město toho nastajenje min/max, kaž je tu wopisane: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - if (this.layer.useJSONP) { │ │ │ │ - // Use JSONP method to avoid xbrowser policy │ │ │ │ - var ols = new OpenLayers.Protocol.Script({ │ │ │ │ - url: this.url, │ │ │ │ - callback: function(response) { │ │ │ │ - this.isLoading = false; │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ - this.json = response.data; │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - ols.read(); │ │ │ │ - this.request = ols; │ │ │ │ - } else { │ │ │ │ - // Use standard XHR │ │ │ │ - this.request = OpenLayers.Request.GET({ │ │ │ │ - url: this.url, │ │ │ │ - callback: function(response) { │ │ │ │ - this.isLoading = false; │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ - if (response.status === 200) { │ │ │ │ - this.parseData(response.responseText); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.unload(); │ │ │ │ - } │ │ │ │ - return drawn; │ │ │ │ - }, │ │ │ │ + 'commitSuccess': "WFS-Transakcija: WUSPĚŠNA ${response}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: abortLoading │ │ │ │ - * Cancel a pending request. │ │ │ │ - */ │ │ │ │ - abortLoading: function() { │ │ │ │ - if (this.request) { │ │ │ │ - this.request.abort(); │ │ │ │ - delete this.request; │ │ │ │ - } │ │ │ │ - this.isLoading = false; │ │ │ │ - }, │ │ │ │ + 'commitFailed': "WFS-Transakcija: NJEPORADŹENA ${response}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getFeatureInfo │ │ │ │ - * Get feature information associated with a pixel offset. If the pixel │ │ │ │ - * offset corresponds to a feature, the returned object will have id │ │ │ │ - * and data properties. Otherwise, null will be returned. │ │ │ │ - * │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * i - {Number} X-axis pixel offset (from top left of tile) │ │ │ │ - * j - {Number} Y-axis pixel offset (from top left of tile) │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} Object with feature id and data properties corresponding to the │ │ │ │ - * given pixel offset. │ │ │ │ - */ │ │ │ │ - getFeatureInfo: function(i, j) { │ │ │ │ - var info = null; │ │ │ │ - if (this.json) { │ │ │ │ - var id = this.getFeatureId(i, j); │ │ │ │ - if (id !== null) { │ │ │ │ - info = { │ │ │ │ - id: id, │ │ │ │ - data: this.json.data[id] │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return info; │ │ │ │ - }, │ │ │ │ + 'googleWarning': "Woršta Google njemóžeše so korektnje začitać.\x3cbr\x3e\x3cbr\x3eZo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.\x3cbr\x3e\x3cbr\x3eNajskerje so to stawa, dokelž skript biblioteki Google Maps pak njebu zapřijaty pak njewobsahuje korektny kluč API za twoje sydło.\x3cbr\x3e\x3cbr\x3eWuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3etu kliknyć\x3c/a\x3e", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getFeatureId │ │ │ │ - * Get the identifier for the feature associated with a pixel offset. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * i - {Number} X-axis pixel offset (from top left of tile) │ │ │ │ - * j - {Number} Y-axis pixel offset (from top left of tile) │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} The feature identifier corresponding to the given pixel offset. │ │ │ │ - * Returns null if pixel doesn't correspond to a feature. │ │ │ │ - */ │ │ │ │ - getFeatureId: function(i, j) { │ │ │ │ - var id = null; │ │ │ │ - if (this.json) { │ │ │ │ - var resolution = this.utfgridResolution; │ │ │ │ - var row = Math.floor(j / resolution); │ │ │ │ - var col = Math.floor(i / resolution); │ │ │ │ - var charCode = this.json.grid[row].charCodeAt(col); │ │ │ │ - var index = this.indexFromCharCode(charCode); │ │ │ │ - var keys = this.json.keys; │ │ │ │ - if (!isNaN(index) && (index in keys)) { │ │ │ │ - id = keys[index]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return id; │ │ │ │ - }, │ │ │ │ + 'getLayerWarning': "Woršta ${layerType} njemóžeše so korektnje začitać.\x3cbr\x3e\x3cbr\x3eZo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.\x3cbr\x3e\x3cbr\x3eNajskerje so to stawa, dokelž skript biblioteki ${layerLib} njebu korektnje zapřijaty.\x3cbr\x3e\x3cbr\x3eWuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3etu kliknyć\x3c/a\x3e", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: indexFromCharCode │ │ │ │ - * Given a character code for one of the UTFGrid "grid" characters, │ │ │ │ - * resolve the integer index for the feature id in the UTFGrid "keys" │ │ │ │ - * array. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * charCode - {Integer} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} Index for the feature id from the keys array. │ │ │ │ - */ │ │ │ │ - indexFromCharCode: function(charCode) { │ │ │ │ - if (charCode >= 93) { │ │ │ │ - charCode--; │ │ │ │ - } │ │ │ │ - if (charCode >= 35) { │ │ │ │ - charCode--; │ │ │ │ - } │ │ │ │ - return charCode - 32; │ │ │ │ - }, │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Měritko = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: parseData │ │ │ │ - * Parse the JSON from a request │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * str - {String} UTFGrid as a JSON string. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} parsed javascript data │ │ │ │ - */ │ │ │ │ - parseData: function(str) { │ │ │ │ - if (!this.format) { │ │ │ │ - this.format = new OpenLayers.Format.JSON(); │ │ │ │ - } │ │ │ │ - this.json = this.format.read(str); │ │ │ │ - }, │ │ │ │ + 'W': "Z", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: clear │ │ │ │ - * Delete data stored with this tile. │ │ │ │ - */ │ │ │ │ - clear: function() { │ │ │ │ - this.json = null; │ │ │ │ - }, │ │ │ │ + 'E': "W", │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Tile.UTFGrid" │ │ │ │ + 'N': "S", │ │ │ │ + │ │ │ │ + 'S': "J", │ │ │ │ + │ │ │ │ + 'reprojectDeprecated': "Wužiwaš opciju \"reproject\" wořšty ${layerName}. Tuta opcija je zestarjena: jeje wužiwanje bě myslene, zo by zwobraznjenje datow nad komercielnymi bazowymi kartami podpěrało, ale funkcionalnosć měła so nětko z pomocu Sperical Mercator docpěć. Dalše informacije steja na http://trac.openlayers.org/wiki/SphericalMercator k dispoziciji.", │ │ │ │ + │ │ │ │ + 'methodDeprecated': "Tuta metoda je so njeschwaliła a budźe so w 3.0 wotstronjeć. Prošu wužij ${newMethod} město toho." │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/UTFGrid.js │ │ │ │ + OpenLayers/Lang/ca.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 │ │ │ │ - * @requires OpenLayers/Tile/UTFGrid.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Layer.UTFGrid │ │ │ │ - * This Layer reads from UTFGrid tiled data sources. Since UTFGrids are │ │ │ │ - * essentially JSON-based ASCII art with attached attributes, they are not │ │ │ │ - * visibly rendered. In order to use them in the map, you must add a │ │ │ │ - * <OpenLayers.Control.UTFGrid> control as well. │ │ │ │ - * │ │ │ │ - * Example: │ │ │ │ - * │ │ │ │ - * (start code) │ │ │ │ - * var world_utfgrid = new OpenLayers.Layer.UTFGrid({ │ │ │ │ - * url: "/tiles/world_utfgrid/${z}/${x}/${y}.json", │ │ │ │ - * utfgridResolution: 4, │ │ │ │ - * displayInLayerSwitcher: false │ │ │ │ - * ); │ │ │ │ - * map.addLayer(world_utfgrid); │ │ │ │ - * │ │ │ │ - * var control = new OpenLayers.Control.UTFGrid({ │ │ │ │ - * layers: [world_utfgrid], │ │ │ │ - * handlerMode: 'move', │ │ │ │ - * callback: function(dataLookup) { │ │ │ │ - * // do something with returned data │ │ │ │ - * } │ │ │ │ - * }) │ │ │ │ - * (end code) │ │ │ │ - * │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.XYZ> │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["ca"] │ │ │ │ + * Dictionary for Catalan, UTF8 encoding. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.UTFGrid = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ +OpenLayers.Lang.ca = { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * Default is false, as UTFGrids are designed to be a transparent overlay layer. │ │ │ │ - */ │ │ │ │ - isBaseLayer: false, │ │ │ │ + 'unhandledRequest': "Resposta a petició no gestionada ${statusText}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: projection │ │ │ │ - * {<OpenLayers.Projection>} │ │ │ │ - * Source projection for the UTFGrids. Default is "EPSG:900913". │ │ │ │ - */ │ │ │ │ - projection: new OpenLayers.Projection("EPSG:900913"), │ │ │ │ + 'Permalink': "Enllaç permanent", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: useJSONP │ │ │ │ - * {Boolean} │ │ │ │ - * Should we use a JSONP script approach instead of a standard AJAX call? │ │ │ │ - * │ │ │ │ - * Set to true for using utfgrids from another server. │ │ │ │ - * Avoids same-domain policy restrictions. │ │ │ │ - * Note that this only works if the server accepts │ │ │ │ - * the callback GET parameter and dynamically │ │ │ │ - * wraps the returned json in a function call. │ │ │ │ - * │ │ │ │ - * Default is false │ │ │ │ - */ │ │ │ │ - useJSONP: false, │ │ │ │ + 'Overlays': "Capes addicionals", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: url │ │ │ │ - * {String} │ │ │ │ - * URL tempate for UTFGrid tiles. Include x, y, and z parameters. │ │ │ │ - * E.g. "/tiles/${z}/${x}/${y}.json" │ │ │ │ - */ │ │ │ │ + 'Base Layer': "Capa Base", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: utfgridResolution │ │ │ │ - * {Number} │ │ │ │ - * Ratio of the pixel width to the width of a UTFGrid data point. If an │ │ │ │ - * entry in the grid represents a 4x4 block of pixels, the │ │ │ │ - * utfgridResolution would be 4. Default is 2 (specified in │ │ │ │ - * <OpenLayers.Tile.UTFGrid>). │ │ │ │ - */ │ │ │ │ + 'noFID': "No es pot actualitzar un element per al que no existeix FID.", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: tileClass │ │ │ │ - * {<OpenLayers.Tile>} The tile class to use for this layer. │ │ │ │ - * Defaults is <OpenLayers.Tile.UTFGrid>. │ │ │ │ - */ │ │ │ │ - tileClass: OpenLayers.Tile.UTFGrid, │ │ │ │ + 'browserNotSupported': "El seu navegador no suporta renderització vectorial. Els renderitzadors suportats actualment són:\n${renderers}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.UTFGrid │ │ │ │ - * Create a new UTFGrid layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * config - {Object} Configuration properties for the layer. │ │ │ │ - * │ │ │ │ - * Required configuration properties: │ │ │ │ - * url - {String} The url template for UTFGrid tiles. See the <url> property. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply( │ │ │ │ - this, [options.name, options.url, {}, options] │ │ │ │ - ); │ │ │ │ - this.tileOptions = OpenLayers.Util.extend({ │ │ │ │ - utfgridResolution: this.utfgridResolution │ │ │ │ - }, this.tileOptions); │ │ │ │ - }, │ │ │ │ + // console message │ │ │ │ + 'minZoomLevelError': "La propietat minZoomLevel s'ha d'utilitzar només " + │ │ │ │ + "amb les capes que tenen FixedZoomLevels. El fet que " + │ │ │ │ + "una capa wfs comprovi minZoomLevel és una relíquia del " + │ │ │ │ + "passat. No podem, però, eliminar-la sense trencar " + │ │ │ │ + "les aplicacions d'OpenLayers que en puguin dependre. " + │ │ │ │ + "Així doncs estem fent-la obsoleta -- la comprovació " + │ │ │ │ + "minZoomLevel s'eliminarà a la versió 3.0. Feu servir " + │ │ │ │ + "els paràmetres min/max resolution en substitució, tal com es descriu aquí: " + │ │ │ │ + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: createBackBuffer │ │ │ │ - * The UTFGrid cannot create a back buffer, so this method is overriden. │ │ │ │ - */ │ │ │ │ - createBackBuffer: function() {}, │ │ │ │ + 'commitSuccess': "Transacció WFS: CORRECTA ${response}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * obj - {Object} Only used by a subclass of this layer. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.UTFGrid>} An exact clone of this OpenLayers.Layer.UTFGrid │ │ │ │ - */ │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.UTFGrid(this.getOptions()); │ │ │ │ - } │ │ │ │ + 'commitFailed': "Transacció WFS: HA FALLAT ${response}", │ │ │ │ │ │ │ │ - // get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + 'googleWarning': "La capa Google no s'ha pogut carregar correctament.<br><br>" + │ │ │ │ + "Per evitar aquest missatge, seleccioneu una nova Capa Base " + │ │ │ │ + "al gestor de capes de la cantonada superior dreta.<br><br>" + │ │ │ │ + "Probablement això és degut a que l'script de la biblioteca de " + │ │ │ │ + "Google Maps no ha estat inclòs a la vostra pàgina, o no " + │ │ │ │ + "conté la clau de l'API correcta per a la vostra adreça.<br><br>" + │ │ │ │ + "Desenvolupadors: Per obtenir consells sobre com fer anar això, " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ + "target='_blank'>féu clic aquí</a>", │ │ │ │ │ │ │ │ - return obj; │ │ │ │ - }, │ │ │ │ + 'getLayerWarning': "Per evitar aquest missatge, seleccioneu una nova Capa Base " + │ │ │ │ + "al gestor de capes de la cantonada superior dreta.<br><br>" + │ │ │ │ + "Probablement això és degut a que l'script de la biblioteca " + │ │ │ │ + "${layerLib} " + │ │ │ │ + "no ha estat inclòs a la vostra pàgina.<br><br>" + │ │ │ │ + "Desenvolupadors: Per obtenir consells sobre com fer anar això, " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ + "target='_blank'>féu clic aquí</a>", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: getFeatureInfo │ │ │ │ - * Get details about a feature associated with a map location. The object │ │ │ │ - * returned will have id and data properties. If the given location │ │ │ │ - * doesn't correspond to a feature, null will be returned. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * location - {<OpenLayers.LonLat>} map location │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} Object representing the feature id and UTFGrid data │ │ │ │ - * corresponding to the given map location. Returns null if the given │ │ │ │ - * location doesn't hit a feature. │ │ │ │ - */ │ │ │ │ - getFeatureInfo: function(location) { │ │ │ │ - var info = null; │ │ │ │ - var tileInfo = this.getTileData(location); │ │ │ │ - if (tileInfo && tileInfo.tile) { │ │ │ │ - info = tileInfo.tile.getFeatureInfo(tileInfo.i, tileInfo.j); │ │ │ │ - } │ │ │ │ - return info; │ │ │ │ - }, │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Escala = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getFeatureId │ │ │ │ - * Get the identifier for the feature associated with a map location. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * location - {<OpenLayers.LonLat>} map location │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} The feature identifier corresponding to the given map location. │ │ │ │ - * Returns null if the location doesn't hit a feature. │ │ │ │ - */ │ │ │ │ - getFeatureId: function(location) { │ │ │ │ - var id = null; │ │ │ │ - var info = this.getTileData(location); │ │ │ │ - if (info.tile) { │ │ │ │ - id = info.tile.getFeatureId(info.i, info.j); │ │ │ │ - } │ │ │ │ - return id; │ │ │ │ - }, │ │ │ │ + //labels for the graticule control │ │ │ │ + 'W': 'O', │ │ │ │ + 'E': 'E', │ │ │ │ + 'N': 'N', │ │ │ │ + 'S': 'S', │ │ │ │ + 'Graticule': 'Retícula', │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'reprojectDeprecated': "Esteu fent servir l'opció 'reproject' a la capa " + │ │ │ │ + "${layerName}. Aquesta opció és obsoleta: el seu ús fou concebut " + │ │ │ │ + "per suportar la visualització de dades sobre mapes base comercials, " + │ │ │ │ + "però ara aquesta funcionalitat s'hauria d'assolir mitjançant el suport " + │ │ │ │ + "de la projecció Spherical Mercator. Més informació disponible a " + │ │ │ │ + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'methodDeprecated': "Aquest mètode és obsolet i s'eliminarà a la versió 3.0. " + │ │ │ │ + "Si us plau feu servir em mètode alternatiu ${newMethod}.", │ │ │ │ + │ │ │ │ + // **** end **** │ │ │ │ + 'end': '' │ │ │ │ + │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/nn.js │ │ │ │ + ====================================================================== */ │ │ │ │ + │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Harald Khan │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["nn"] │ │ │ │ + * Dictionary for ‪Norsk (nynorsk)‬. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["nn"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Skala = 1 : ${scaleDenom}" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.UTFGrid" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/PointGrid.js │ │ │ │ + OpenLayers/Lang/ar.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. */ │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Meno25 │ │ │ │ + * - Mutarjem horr │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * @requires OpenLayers/Layer/Vector.js │ │ │ │ - * @requires OpenLayers/Geometry/Polygon.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.PointGrid │ │ │ │ - * A point grid layer dynamically generates a regularly spaced grid of point │ │ │ │ - * features. This is a specialty layer for cases where an application needs │ │ │ │ - * a regular grid of points. It can be used, for example, in an editing │ │ │ │ - * environment to snap to a grid. │ │ │ │ - * │ │ │ │ - * Create a new vector layer with the <OpenLayers.Layer.PointGrid> constructor. │ │ │ │ - * (code) │ │ │ │ - * // create a grid with points spaced at 10 map units │ │ │ │ - * var points = new OpenLayers.Layer.PointGrid({dx: 10, dy: 10}); │ │ │ │ - * │ │ │ │ - * // create a grid with different x/y spacing rotated 15 degrees clockwise. │ │ │ │ - * var points = new OpenLayers.Layer.PointGrid({dx: 5, dy: 10, rotation: 15}); │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Vector> │ │ │ │ + * Namespace: OpenLayers.Lang["ar"] │ │ │ │ + * Dictionary for العربية. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.PointGrid = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ +OpenLayers.Lang["ar"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: dx │ │ │ │ - * {Number} Point grid spacing in the x-axis direction (map units). │ │ │ │ - * Read-only. Use the <setSpacing> method to modify this value. │ │ │ │ - */ │ │ │ │ - dx: null, │ │ │ │ + 'Permalink': "وصلة دائمة", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: dy │ │ │ │ - * {Number} Point grid spacing in the y-axis direction (map units). │ │ │ │ - * Read-only. Use the <setSpacing> method to modify this value. │ │ │ │ - */ │ │ │ │ - dy: null, │ │ │ │ + 'Base Layer': "الطبقة الاساسية", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: ratio │ │ │ │ - * {Number} Ratio of the desired grid size to the map viewport size. │ │ │ │ - * Default is 1.5. Larger ratios mean the grid is recalculated less often │ │ │ │ - * while panning. The <maxFeatures> setting has precedence when determining │ │ │ │ - * grid size. Read-only. Use the <setRatio> method to modify this value. │ │ │ │ - */ │ │ │ │ - ratio: 1.5, │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "النسبة = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: maxFeatures │ │ │ │ - * {Number} The maximum number of points to generate in the grid. Default │ │ │ │ - * is 250. Read-only. Use the <setMaxFeatures> method to modify this value. │ │ │ │ - */ │ │ │ │ - maxFeatures: 250, │ │ │ │ + 'W': "غ", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: rotation │ │ │ │ - * {Number} Grid rotation (in degrees clockwise from the positive x-axis). │ │ │ │ - * Default is 0. Read-only. Use the <setRotation> method to modify this │ │ │ │ - * value. │ │ │ │ - */ │ │ │ │ - rotation: 0, │ │ │ │ + 'E': "شر", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: origin │ │ │ │ - * {<OpenLayers.LonLat>} Grid origin. The grid lattice will be aligned with │ │ │ │ - * the origin. If not set at construction, the center of the map's maximum │ │ │ │ - * extent is used. Read-only. Use the <setOrigin> method to modify this │ │ │ │ - * value. │ │ │ │ - */ │ │ │ │ - origin: null, │ │ │ │ + 'N': "شم", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: gridBounds │ │ │ │ - * {<OpenLayers.Bounds>} Internally cached grid bounds (with optional │ │ │ │ - * rotation applied). │ │ │ │ - */ │ │ │ │ - gridBounds: null, │ │ │ │ + 'S': "ج" │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.PointGrid │ │ │ │ - * Creates a new point grid layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * config - {Object} An object containing all configuration properties for │ │ │ │ - * the layer. The <dx> and <dy> properties are required to be set at │ │ │ │ - * construction. Any other layer properties may be set in this object. │ │ │ │ - */ │ │ │ │ - initialize: function(config) { │ │ │ │ - config = config || {}; │ │ │ │ - OpenLayers.Layer.Vector.prototype.initialize.apply(this, [config.name, config]); │ │ │ │ - }, │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/ja.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * The layer has been added to the map. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ - */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ - map.events.register("moveend", this, this.onMoveEnd); │ │ │ │ - }, │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Fryed-peach │ │ │ │ + * - Mage Whopper │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: removeMap │ │ │ │ - * The layer has been removed from the map. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ - */ │ │ │ │ - removeMap: function(map) { │ │ │ │ - map.events.unregister("moveend", this, this.onMoveEnd); │ │ │ │ - OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments); │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: setRatio │ │ │ │ - * Set the grid <ratio> property and update the grid. Can only be called │ │ │ │ - * after the layer has been added to a map with a center/extent. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * ratio - {Number} │ │ │ │ - */ │ │ │ │ - setRatio: function(ratio) { │ │ │ │ - this.ratio = ratio; │ │ │ │ - this.updateGrid(true); │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["ja"] │ │ │ │ + * Dictionary for 日本語. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["ja"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: setMaxFeatures │ │ │ │ - * Set the grid <maxFeatures> property and update the grid. Can only be │ │ │ │ - * called after the layer has been added to a map with a center/extent. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * maxFeatures - {Number} │ │ │ │ - */ │ │ │ │ - setMaxFeatures: function(maxFeatures) { │ │ │ │ - this.maxFeatures = maxFeatures; │ │ │ │ - this.updateGrid(true); │ │ │ │ - }, │ │ │ │ + 'unhandledRequest': "未処理の要求は ${statusText} を返します", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: setSpacing │ │ │ │ - * Set the grid <dx> and <dy> properties and update the grid. If only one │ │ │ │ - * argument is provided, it will be set as <dx> and <dy>. Can only be │ │ │ │ - * called after the layer has been added to a map with a center/extent. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * dx - {Number} │ │ │ │ - * dy - {Number} │ │ │ │ - */ │ │ │ │ - setSpacing: function(dx, dy) { │ │ │ │ - this.dx = dx; │ │ │ │ - this.dy = dy || dx; │ │ │ │ - this.updateGrid(true); │ │ │ │ - }, │ │ │ │ + 'Permalink': "パーマリンク", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: setOrigin │ │ │ │ - * Set the grid <origin> property and update the grid. Can only be called │ │ │ │ - * after the layer has been added to a map with a center/extent. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * origin - {<OpenLayers.LonLat>} │ │ │ │ - */ │ │ │ │ - setOrigin: function(origin) { │ │ │ │ - this.origin = origin; │ │ │ │ - this.updateGrid(true); │ │ │ │ - }, │ │ │ │ + 'Overlays': "オーバーレイ", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getOrigin │ │ │ │ - * Get the grid <origin> property. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.LonLat>} The grid origin. │ │ │ │ - */ │ │ │ │ - getOrigin: function() { │ │ │ │ - if (!this.origin) { │ │ │ │ - this.origin = this.map.getExtent().getCenterLonLat(); │ │ │ │ - } │ │ │ │ - return this.origin; │ │ │ │ - }, │ │ │ │ + 'Base Layer': "基底レイヤー", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: setRotation │ │ │ │ - * Set the grid <rotation> property and update the grid. Rotation values │ │ │ │ - * are in degrees clockwise from the positive x-axis (negative values │ │ │ │ - * for counter-clockwise rotation). Can only be called after the layer │ │ │ │ - * has been added to a map with a center/extent. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * rotation - {Number} Degrees clockwise from the positive x-axis. │ │ │ │ - */ │ │ │ │ - setRotation: function(rotation) { │ │ │ │ - this.rotation = rotation; │ │ │ │ - this.updateGrid(true); │ │ │ │ - }, │ │ │ │ + 'noFID': "FID のない地物は更新できません。", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: onMoveEnd │ │ │ │ - * Listener for map "moveend" events. │ │ │ │ - */ │ │ │ │ - onMoveEnd: function() { │ │ │ │ - this.updateGrid(); │ │ │ │ - }, │ │ │ │ + 'browserNotSupported': "あなたのブラウザはベクターグラフィックスの描写に対応していません。現時点で対応しているソフトウェアは以下のものです。\n${renderers}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getViewBounds │ │ │ │ - * Gets the (potentially rotated) view bounds for grid calculations. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} │ │ │ │ - */ │ │ │ │ - getViewBounds: function() { │ │ │ │ - var bounds = this.map.getExtent(); │ │ │ │ - if (this.rotation) { │ │ │ │ - var origin = this.getOrigin(); │ │ │ │ - var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); │ │ │ │ - var rect = bounds.toGeometry(); │ │ │ │ - rect.rotate(-this.rotation, rotationOrigin); │ │ │ │ - bounds = rect.getBounds(); │ │ │ │ - } │ │ │ │ - return bounds; │ │ │ │ - }, │ │ │ │ + 'minZoomLevelError': "minZoomLevel プロパティは FixedZoomLevels を継承するレイヤーでの使用のみを想定しています。この minZoomLevel に対する WFS レイヤーの検査は歴史的なものです。しかしながら、この検査を除去するとそれに依存する OpenLayers ベースのアプリケーションを破壊してしまう可能性があります。よって廃止が予定されており、この minZoomLevel 検査はバージョン3.0で除去されます。代わりに、http://trac.openlayers.org/wiki/SettingZoomLevels で解説されている、最小および最大解像度設定を使用してください。", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: updateGrid │ │ │ │ - * Update the grid. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * force - {Boolean} Update the grid even if the previous bounds are still │ │ │ │ - * valid. │ │ │ │ - */ │ │ │ │ - updateGrid: function(force) { │ │ │ │ - if (force || this.invalidBounds()) { │ │ │ │ - var viewBounds = this.getViewBounds(); │ │ │ │ - var origin = this.getOrigin(); │ │ │ │ - var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); │ │ │ │ - var viewBoundsWidth = viewBounds.getWidth(); │ │ │ │ - var viewBoundsHeight = viewBounds.getHeight(); │ │ │ │ - var aspectRatio = viewBoundsWidth / viewBoundsHeight; │ │ │ │ - var maxHeight = Math.sqrt(this.dx * this.dy * this.maxFeatures / aspectRatio); │ │ │ │ - var maxWidth = maxHeight * aspectRatio; │ │ │ │ - var gridWidth = Math.min(viewBoundsWidth * this.ratio, maxWidth); │ │ │ │ - var gridHeight = Math.min(viewBoundsHeight * this.ratio, maxHeight); │ │ │ │ - var center = viewBounds.getCenterLonLat(); │ │ │ │ - this.gridBounds = new OpenLayers.Bounds( │ │ │ │ - center.lon - (gridWidth / 2), │ │ │ │ - center.lat - (gridHeight / 2), │ │ │ │ - center.lon + (gridWidth / 2), │ │ │ │ - center.lat + (gridHeight / 2) │ │ │ │ - ); │ │ │ │ - var rows = Math.floor(gridHeight / this.dy); │ │ │ │ - var cols = Math.floor(gridWidth / this.dx); │ │ │ │ - var gridLeft = origin.lon + (this.dx * Math.ceil((this.gridBounds.left - origin.lon) / this.dx)); │ │ │ │ - var gridBottom = origin.lat + (this.dy * Math.ceil((this.gridBounds.bottom - origin.lat) / this.dy)); │ │ │ │ - var features = new Array(rows * cols); │ │ │ │ - var x, y, point; │ │ │ │ - for (var i = 0; i < cols; ++i) { │ │ │ │ - x = gridLeft + (i * this.dx); │ │ │ │ - for (var j = 0; j < rows; ++j) { │ │ │ │ - y = gridBottom + (j * this.dy); │ │ │ │ - point = new OpenLayers.Geometry.Point(x, y); │ │ │ │ - if (this.rotation) { │ │ │ │ - point.rotate(this.rotation, rotationOrigin); │ │ │ │ - } │ │ │ │ - features[(i * rows) + j] = new OpenLayers.Feature.Vector(point); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.destroyFeatures(this.features, { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ - this.addFeatures(features, { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'commitSuccess': "WFS トランザクション: 成功 ${response}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: invalidBounds │ │ │ │ - * Determine whether the previously generated point grid is invalid. │ │ │ │ - * This occurs when the map bounds extends beyond the previously │ │ │ │ - * generated grid bounds. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - invalidBounds: function() { │ │ │ │ - return !this.gridBounds || !this.gridBounds.containsBounds(this.getViewBounds()); │ │ │ │ - }, │ │ │ │ + 'commitFailed': "WFS トランザクション: 失敗 ${response}", │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.PointGrid" │ │ │ │ + 'googleWarning': "Google レイヤーが正しく読み込みを行えませんでした。\x3cbr\x3e\x3cbr\x3eこのメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。\x3cbr\x3e\x3cbr\x3eおそらく、これは Google マップ用ライブラリのスクリプトが組み込まれていないか、あなたのサイトに対応する正しい API キーが設定されていないためです。\x3cbr\x3e\x3cbr\x3e開発者の方へ: 正しい動作をさせるために\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eこちらのウィキ\x3c/a\x3eを参照してください。", │ │ │ │ + │ │ │ │ + 'getLayerWarning': "${layerType} レイヤーが正しく読み込みを行えませんでした。\x3cbr\x3e\x3cbr\x3eこのメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。\x3cbr\x3e\x3cbr\x3eおそらく、これは ${layerLib} ライブラリのスクリプトが正しく組み込まれていないためです。\x3cbr\x3e\x3cbr\x3e開発者の方へ: 正しい動作をさせるために\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eこちらのウィキ\x3c/a\x3eを参照してください。", │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "縮尺 = 1 : ${scaleDenom}", │ │ │ │ + │ │ │ │ + 'W': "西", │ │ │ │ + │ │ │ │ + 'E': "東", │ │ │ │ + │ │ │ │ + 'N': "北", │ │ │ │ + │ │ │ │ + 'S': "南", │ │ │ │ + │ │ │ │ + 'reprojectDeprecated': "あなたは「${layerName}」レイヤーで reproject オプションを使っています。このオプションは商用の基底地図上に情報を表示する目的で設計されましたが、現在ではその機能は Spherical Mercator サポートを利用して実現されており、このオプションの使用は非推奨です。追加の情報は http://trac.openlayers.org/wiki/SphericalMercator で入手できます。", │ │ │ │ + │ │ │ │ + 'methodDeprecated': "このメソッドは廃止が予定されており、バージョン3.0で除去されます。代わりに ${newMethod} を使用してください。" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/Zoomify.js │ │ │ │ + OpenLayers/Lang/hr.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. */ │ │ │ │ - │ │ │ │ -/* │ │ │ │ - * Development supported by a R&D grant DC08P02OUK006 - Old Maps Online │ │ │ │ - * (www.oldmapsonline.org) from Ministry of Culture of the Czech Republic. │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Mvrban │ │ │ │ */ │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.Zoomify │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * Namespace: OpenLayers.Lang["hr"] │ │ │ │ + * Dictionary for Hrvatski. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.Zoomify = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: size │ │ │ │ - * {<OpenLayers.Size>} The Zoomify image size in pixels. │ │ │ │ - */ │ │ │ │ - size: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - isBaseLayer: true, │ │ │ │ +OpenLayers.Lang["hr"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: standardTileSize │ │ │ │ - * {Integer} The size of a standard (non-border) square tile in pixels. │ │ │ │ - */ │ │ │ │ - standardTileSize: 256, │ │ │ │ + 'unhandledRequest': "Nepodržani zahtjev ${statusText}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: tileOriginCorner │ │ │ │ - * {String} This layer uses top-left as tile origin │ │ │ │ - **/ │ │ │ │ - tileOriginCorner: "tl", │ │ │ │ + 'Permalink': "Permalink", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: numberOfTiers │ │ │ │ - * {Integer} Depth of the Zoomify pyramid, number of tiers (zoom levels) │ │ │ │ - * - filled during Zoomify pyramid initialization. │ │ │ │ - */ │ │ │ │ - numberOfTiers: 0, │ │ │ │ + 'Overlays': "Overlays", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: tileCountUpToTier │ │ │ │ - * {Array(Integer)} Number of tiles up to the given tier of pyramid. │ │ │ │ - * - filled during Zoomify pyramid initialization. │ │ │ │ - */ │ │ │ │ - tileCountUpToTier: null, │ │ │ │ + 'Base Layer': "Osnovna karta", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: tierSizeInTiles │ │ │ │ - * {Array(<OpenLayers.Size>)} Size (in tiles) for each tier of pyramid. │ │ │ │ - * - filled during Zoomify pyramid initialization. │ │ │ │ - */ │ │ │ │ - tierSizeInTiles: null, │ │ │ │ + 'noFID': "Ne mogu ažurirati značajku za koju ne postoji FID.", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: tierImageSize │ │ │ │ - * {Array(<OpenLayers.Size>)} Image size in pixels for each pyramid tier. │ │ │ │ - * - filled during Zoomify pyramid initialization. │ │ │ │ - */ │ │ │ │ - tierImageSize: null, │ │ │ │ + 'browserNotSupported': "Vaš preglednik ne podržava vektorsko renderiranje. Trenutno podržani rendereri su: ${renderers}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.Zoomify │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} A name for the layer. │ │ │ │ - * url - {String} - Relative or absolute path to the image or more │ │ │ │ - * precisly to the TileGroup[X] directories root. │ │ │ │ - * Flash plugin use the variable name "zoomifyImagePath" for this. │ │ │ │ - * size - {<OpenLayers.Size>} The size (in pixels) of the image. │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ - */ │ │ │ │ - initialize: function(name, url, size, options) { │ │ │ │ + 'commitSuccess': "WFS Transakcija: USPJEŠNA ${response}", │ │ │ │ │ │ │ │ - // initilize the Zoomify pyramid for given size │ │ │ │ - this.initializeZoomify(size); │ │ │ │ + 'commitFailed': "WFS Transakcija: NEUSPJEŠNA ${response}", │ │ │ │ │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, [ │ │ │ │ - name, url, size, {}, │ │ │ │ - options │ │ │ │ - ]); │ │ │ │ - }, │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Mjerilo = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: initializeZoomify │ │ │ │ - * It generates constants for all tiers of the Zoomify pyramid │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * size - {<OpenLayers.Size>} The size of the image in pixels │ │ │ │ - * │ │ │ │ - */ │ │ │ │ - initializeZoomify: function(size) { │ │ │ │ + 'methodDeprecated': "Ova metoda nije odobrena i biti će maknuta u 3.0. Koristite ${newMethod}." │ │ │ │ │ │ │ │ - var imageSize = size.clone(); │ │ │ │ - this.size = size.clone(); │ │ │ │ - var tiles = new OpenLayers.Size( │ │ │ │ - Math.ceil(imageSize.w / this.standardTileSize), │ │ │ │ - Math.ceil(imageSize.h / this.standardTileSize) │ │ │ │ - ); │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/sv-SE.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - this.tierSizeInTiles = [tiles]; │ │ │ │ - this.tierImageSize = [imageSize]; │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Sannab │ │ │ │ + */ │ │ │ │ │ │ │ │ - while (imageSize.w > this.standardTileSize || │ │ │ │ - imageSize.h > this.standardTileSize) { │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - imageSize = new OpenLayers.Size( │ │ │ │ - Math.floor(imageSize.w / 2), │ │ │ │ - Math.floor(imageSize.h / 2) │ │ │ │ - ); │ │ │ │ - tiles = new OpenLayers.Size( │ │ │ │ - Math.ceil(imageSize.w / this.standardTileSize), │ │ │ │ - Math.ceil(imageSize.h / this.standardTileSize) │ │ │ │ - ); │ │ │ │ - this.tierSizeInTiles.push(tiles); │ │ │ │ - this.tierImageSize.push(imageSize); │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["sv"] │ │ │ │ + * Dictionary for Svenska. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["sv"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - this.tierSizeInTiles.reverse(); │ │ │ │ - this.tierImageSize.reverse(); │ │ │ │ + 'unhandledRequest': "Ej hanterad fråga retur ${statusText}", │ │ │ │ │ │ │ │ - this.numberOfTiers = this.tierSizeInTiles.length; │ │ │ │ - var resolutions = [1]; │ │ │ │ - this.tileCountUpToTier = [0]; │ │ │ │ - for (var i = 1; i < this.numberOfTiers; i++) { │ │ │ │ - resolutions.unshift(Math.pow(2, i)); │ │ │ │ - this.tileCountUpToTier.push( │ │ │ │ - this.tierSizeInTiles[i - 1].w * this.tierSizeInTiles[i - 1].h + │ │ │ │ - this.tileCountUpToTier[i - 1] │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (!this.serverResolutions) { │ │ │ │ - this.serverResolutions = resolutions; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'Permalink': "Permalänk", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod:destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - // for now, nothing special to do here. │ │ │ │ - OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments); │ │ │ │ + 'Overlays': "Kartlager", │ │ │ │ │ │ │ │ - // Remove from memory the Zoomify pyramid - is that enough? │ │ │ │ - this.tileCountUpToTier.length = 0; │ │ │ │ - this.tierSizeInTiles.length = 0; │ │ │ │ - this.tierImageSize.length = 0; │ │ │ │ + 'Base Layer': "Bakgrundskarta", │ │ │ │ │ │ │ │ - }, │ │ │ │ + 'noFID': "Kan ej uppdatera feature (objekt) för vilket FID saknas.", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * obj - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.Zoomify>} An exact clone of this <OpenLayers.Layer.Zoomify> │ │ │ │ - */ │ │ │ │ - clone: function(obj) { │ │ │ │ + 'browserNotSupported': "Din webbläsare stöder inte vektorvisning. För närvarande stöds följande visning:\n${renderers}", │ │ │ │ │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.Zoomify(this.name, │ │ │ │ - this.url, │ │ │ │ - this.size, │ │ │ │ - this.options); │ │ │ │ - } │ │ │ │ + 'minZoomLevelError': "Egenskapen minZoomLevel är endast avsedd att användas med lager med FixedZoomLevels. Att detta WFS-lager kontrollerar minZoomLevel är en relik från äldre versioner. Vi kan dock inte ta bort det utan att riskera att OL-baserade tillämpningar som använder detta slutar fungera. Därför är det satt som deprecated, minZoomLevel kommer att tas bort i version 3.0. Använd i stället inställning av min/max resolution som beskrivs här: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + 'commitSuccess': "WFS-transaktion: LYCKADES ${response}", │ │ │ │ │ │ │ │ - // copy/set any non-init, non-simple values here │ │ │ │ + 'commitFailed': "WFS-transaktion: MISSLYCKADES ${response}", │ │ │ │ │ │ │ │ - return obj; │ │ │ │ - }, │ │ │ │ + 'googleWarning': "Google-lagret kunde inte laddas korrekt.\x3cbr\x3e\x3cbr\x3eFör att slippa detta meddelande, välj en annan bakgrundskarta i lagerväljaren i övre högra hörnet.\x3cbr\x3e\x3cbr\x3eSannolikt beror felet på att Google Maps-biblioteket inte är inkluderat på webbsidan eller på att sidan inte anger korrekt API-nyckel för webbplatsen.\x3cbr\x3e\x3cbr\x3eUtvecklare: hjälp för att åtgärda detta, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eklicka här\x3c/a\x3e.", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ - var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ - var z = this.getZoomForResolution(res); │ │ │ │ + 'getLayerWarning': "${layerType}-lagret kunde inte laddas korrekt.\x3cbr\x3e\x3cbr\x3eFör att slippa detta meddelande, välj en annan bakgrundskarta i lagerväljaren i övre högra hörnet.\x3cbr\x3e\x3cbr\x3eSannolikt beror felet på att ${layerLib}-biblioteket inte är inkluderat på webbsidan.\x3cbr\x3e\x3cbr\x3eUtvecklare: hjälp för att åtgärda detta, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklicka här\x3c/a\x3e.", │ │ │ │ │ │ │ │ - var tileIndex = x + y * this.tierSizeInTiles[z].w + this.tileCountUpToTier[z]; │ │ │ │ - var path = "TileGroup" + Math.floor((tileIndex) / 256) + │ │ │ │ - "/" + z + "-" + x + "-" + y + ".jpg"; │ │ │ │ - var url = this.url; │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(path, url); │ │ │ │ - } │ │ │ │ - return url + path; │ │ │ │ - }, │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "\x3cstrong\x3eSkala\x3c/strong\x3e 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getImageSize │ │ │ │ - * getImageSize returns size for a particular tile. If bounds are given as │ │ │ │ - * first argument, size is calculated (bottom-right tiles are non square). │ │ │ │ - * │ │ │ │ - */ │ │ │ │ - getImageSize: function() { │ │ │ │ - if (arguments.length > 0) { │ │ │ │ - var bounds = this.adjustBounds(arguments[0]); │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ - var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ - var z = this.getZoomForResolution(res); │ │ │ │ - var w = this.standardTileSize; │ │ │ │ - var h = this.standardTileSize; │ │ │ │ - if (x == this.tierSizeInTiles[z].w - 1) { │ │ │ │ - var w = this.tierImageSize[z].w % this.standardTileSize; │ │ │ │ - } │ │ │ │ - if (y == this.tierSizeInTiles[z].h - 1) { │ │ │ │ - var h = this.tierImageSize[z].h % this.standardTileSize; │ │ │ │ - } │ │ │ │ - return (new OpenLayers.Size(w, h)); │ │ │ │ - } else { │ │ │ │ - return this.tileSize; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'reprojectDeprecated': "Du använder inställningen \'reproject\' på lagret ${layerName}. Denna inställning markerad som deprecated: den var avsedd att användas för att stödja visning av kartdata på kommersiella bakgrundskartor, men nu bör man i stället använda Spherical Mercator-stöd för den funktionaliteten. Mer information finns på http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left, │ │ │ │ - this.map.maxExtent.top); │ │ │ │ - }, │ │ │ │ + 'methodDeprecated': "Denna metod är markerad som deprecated och kommer att tas bort i 3.0. Använd ${newMethod} i stället." │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Zoomify" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/TMS.js │ │ │ │ + OpenLayers/Lang/en-CA.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 │ │ │ │ + * @requires OpenLayers/Lang/en.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.TMS │ │ │ │ - * Create a layer for accessing tiles from services that conform with the │ │ │ │ - * Tile Map Service Specification │ │ │ │ - * (http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification). │ │ │ │ - * │ │ │ │ - * Example: │ │ │ │ - * (code) │ │ │ │ - * var layer = new OpenLayers.Layer.TMS( │ │ │ │ - * "My Layer", // name for display in LayerSwitcher │ │ │ │ - * "http://tilecache.osgeo.org/wms-c/Basic.py/", // service endpoint │ │ │ │ - * {layername: "basic", type: "png"} // required properties │ │ │ │ - * ); │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * Namespace: OpenLayers.Lang["en-CA"] │ │ │ │ + * Dictionary for English-CA. This dictionary inherits from the standard │ │ │ │ + * English dictionary. Override only those entries with language specific │ │ │ │ + * to the CA region. │ │ │ │ + * │ │ │ │ + * Keys for entries are used in calls to <OpenLayers.Lang.translate>. Entry │ │ │ │ + * bodies are normal strings or strings formatted for use with │ │ │ │ + * <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.TMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ +OpenLayers.Lang['en-CA'] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: serviceVersion │ │ │ │ - * {String} Service version for tile requests. Default is "1.0.0". │ │ │ │ - */ │ │ │ │ - serviceVersion: "1.0.0", │ │ │ │ + // add any entries specific for this region here │ │ │ │ + // e.g. │ │ │ │ + // "someKey": "Some regionally specific value" │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: layername │ │ │ │ - * {String} The identifier for the <TileMap> as advertised by the service. │ │ │ │ - * For example, if the service advertises a <TileMap> with │ │ │ │ - * 'href="http://tms.osgeo.org/1.0.0/vmap0"', the <layername> property │ │ │ │ - * would be set to "vmap0". │ │ │ │ - */ │ │ │ │ - layername: null, │ │ │ │ +}, OpenLayers.Lang["en"]); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/lt.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: type │ │ │ │ - * {String} The format extension corresponding to the requested tile image │ │ │ │ - * type. This is advertised in a <TileFormat> element as the │ │ │ │ - * "extension" attribute. For example, if the service advertises a │ │ │ │ - * <TileMap> with <TileFormat width="256" height="256" mime-type="image/jpeg" extension="jpg" />, │ │ │ │ - * the <type> property would be set to "jpg". │ │ │ │ - */ │ │ │ │ - type: null, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} Make this layer a base layer. Default is true. Set false to │ │ │ │ - * use the layer as an overlay. │ │ │ │ - */ │ │ │ │ - isBaseLayer: true, │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["lt"] │ │ │ │ + * Dictionary for Lithuanian. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang['lt'] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 bottom-left │ │ │ │ - * corner of the map's <maxExtent>. Default is ``null``. │ │ │ │ - * │ │ │ │ - * Example: │ │ │ │ - * (code) │ │ │ │ - * var layer = new OpenLayers.Layer.TMS( │ │ │ │ - * "My Layer", │ │ │ │ - * "http://tilecache.osgeo.org/wms-c/Basic.py/", │ │ │ │ - * { │ │ │ │ - * layername: "basic", │ │ │ │ - * type: "png", │ │ │ │ - * // set if different than the bottom left of map.maxExtent │ │ │ │ - * tileOrigin: new OpenLayers.LonLat(-180, -90) │ │ │ │ - * } │ │ │ │ - * ); │ │ │ │ - * (end) │ │ │ │ - */ │ │ │ │ - tileOrigin: null, │ │ │ │ + 'unhandledRequest': "Neapdorota užklausa gražino ${statusText}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + 'Permalink': "Pastovi nuoroda", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + 'Overlays': "Papildomi sluoksniai", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.TMS │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} Title to be displayed in a <OpenLayers.Control.LayerSwitcher> │ │ │ │ - * url - {String} Service endpoint (without the version number). E.g. │ │ │ │ - * "http://tms.osgeo.org/". │ │ │ │ - * options - {Object} Additional properties to be set on the layer. The │ │ │ │ - * <layername> and <type> properties must be set here. │ │ │ │ - */ │ │ │ │ - initialize: function(name, url, options) { │ │ │ │ - var newArguments = []; │ │ │ │ - newArguments.push(name, url, {}, options); │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments); │ │ │ │ - }, │ │ │ │ + 'Base Layer': "Pagrindinis sluoksnis", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * Create a complete copy of this layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * obj - {Object} Should only be provided by subclasses that call this │ │ │ │ - * method. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.TMS>} An exact clone of this <OpenLayers.Layer.TMS> │ │ │ │ - */ │ │ │ │ - clone: function(obj) { │ │ │ │ + 'noFID': "Negaliu atnaujinti objekto, kuris neturi FID.", │ │ │ │ │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.TMS(this.name, │ │ │ │ - this.url, │ │ │ │ - this.getOptions()); │ │ │ │ - } │ │ │ │ + 'browserNotSupported': "Jūsų naršyklė nemoka parodyti vektorių. Šiuo metu galima naudotis tokiais rodymo varikliais:\n{renderers}", │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + 'commitSuccess': "WFS Tranzakcija: PAVYKO ${response}", │ │ │ │ │ │ │ │ - // copy/set any non-init, non-simple values here │ │ │ │ + 'commitFailed': "WFS Tranzakcija: ŽLUGO ${response}", │ │ │ │ │ │ │ │ - return obj; │ │ │ │ - }, │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Mastelis = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ - var y = Math.round((bounds.bottom - this.tileOrigin.lat) / (res * this.tileSize.h)); │ │ │ │ - var z = this.getServerZoom(); │ │ │ │ - var path = this.serviceVersion + "/" + this.layername + "/" + z + "/" + x + "/" + y + "." + this.type; │ │ │ │ - var url = this.url; │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(path, url); │ │ │ │ - } │ │ │ │ - return url + path; │ │ │ │ - }, │ │ │ │ + //labels for the graticule control │ │ │ │ + 'W': 'V', │ │ │ │ + 'E': 'R', │ │ │ │ + 'N': 'Š', │ │ │ │ + 'S': 'P', │ │ │ │ + 'Graticule': 'Tinklelis', │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: 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.map.maxExtent.left, │ │ │ │ - this.map.maxExtent.bottom); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + // console message │ │ │ │ + 'methodDeprecated': "Šis metodas yra pasenęs ir 3.0 versijoje bus pašalintas. " + │ │ │ │ + "Prašome naudoti ${newMethod}.", │ │ │ │ + │ │ │ │ + // **** end **** │ │ │ │ + 'end': '' │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.TMS" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/ArcXML.js │ │ │ │ + OpenLayers/Lang/is.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. */ │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Ævar Arnfjörð Bjarmason │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * @requires OpenLayers/Format/XML.js │ │ │ │ - * @requires OpenLayers/Geometry/Polygon.js │ │ │ │ - * @requires OpenLayers/Geometry/Point.js │ │ │ │ - * @requires OpenLayers/Geometry/MultiPolygon.js │ │ │ │ - * @requires OpenLayers/Geometry/LinearRing.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.ArcXML │ │ │ │ - * Read/Write ArcXML. Create a new instance with the <OpenLayers.Format.ArcXML> │ │ │ │ - * constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ + * Namespace: OpenLayers.Lang["is"] │ │ │ │ + * Dictionary for Íslenska. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Format.ArcXML = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ +OpenLayers.Lang["is"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: fontStyleKeys │ │ │ │ - * {Array} List of keys used in font styling. │ │ │ │ - */ │ │ │ │ - fontStyleKeys: [ │ │ │ │ - 'antialiasing', 'blockout', 'font', 'fontcolor', 'fontsize', 'fontstyle', │ │ │ │ - 'glowing', 'interval', 'outline', 'printmode', 'shadow', 'transparency' │ │ │ │ - ], │ │ │ │ + 'Permalink': "Varanlegur tengill", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: request │ │ │ │ - * A get_image request destined for an ArcIMS server. │ │ │ │ - */ │ │ │ │ - request: null, │ │ │ │ + 'Overlays': "Þekjur", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: response │ │ │ │ - * A parsed response from an ArcIMS server. │ │ │ │ - */ │ │ │ │ - response: null, │ │ │ │ + 'Base Layer': "Grunnlag", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.ArcXML │ │ │ │ - * Create a new parser/writer for ArcXML. Create an instance of this class │ │ │ │ - * to begin authoring a request to an ArcIMS service. This is used │ │ │ │ - * primarily by the ArcIMS layer, but could be used to do other wild │ │ │ │ - * stuff, like geocoding. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - this.request = new OpenLayers.Format.ArcXML.Request(); │ │ │ │ - this.response = new OpenLayers.Format.ArcXML.Response(); │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Skali = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - if (options) { │ │ │ │ - if (options.requesttype == "feature") { │ │ │ │ - this.request.get_image = null; │ │ │ │ + 'methodDeprecated': "Þetta fall hefur verið úrelt og verður fjarlægt í 3.0. Notaðu ${newMethod} í staðin." │ │ │ │ │ │ │ │ - var qry = this.request.get_feature.query; │ │ │ │ - this.addCoordSys(qry.featurecoordsys, options.featureCoordSys); │ │ │ │ - this.addCoordSys(qry.filtercoordsys, options.filterCoordSys); │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/gl.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - if (options.polygon) { │ │ │ │ - qry.isspatial = true; │ │ │ │ - qry.spatialfilter.polygon = options.polygon; │ │ │ │ - } else if (options.envelope) { │ │ │ │ - qry.isspatial = true; │ │ │ │ - qry.spatialfilter.envelope = { │ │ │ │ - minx: 0, │ │ │ │ - miny: 0, │ │ │ │ - maxx: 0, │ │ │ │ - maxy: 0 │ │ │ │ - }; │ │ │ │ - this.parseEnvelope(qry.spatialfilter.envelope, options.envelope); │ │ │ │ - } │ │ │ │ - } else if (options.requesttype == "image") { │ │ │ │ - this.request.get_feature = null; │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Toliño │ │ │ │ + */ │ │ │ │ │ │ │ │ - var props = this.request.get_image.properties; │ │ │ │ - this.parseEnvelope(props.envelope, options.envelope); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - this.addLayers(props.layerlist, options.layers); │ │ │ │ - this.addImageSize(props.imagesize, options.tileSize); │ │ │ │ - this.addCoordSys(props.featurecoordsys, options.featureCoordSys); │ │ │ │ - this.addCoordSys(props.filtercoordsys, options.filterCoordSys); │ │ │ │ - } else { │ │ │ │ - // if an arcxml object is being created with no request type, it is │ │ │ │ - // probably going to consume a response, so do not throw an error if │ │ │ │ - // the requesttype is not defined │ │ │ │ - this.request = null; │ │ │ │ - } │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["gl"] │ │ │ │ + * Dictionary for Galego. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["gl"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ - }, │ │ │ │ + 'unhandledRequest': "Solicitude non xerada; a resposta foi: ${statusText}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: parseEnvelope │ │ │ │ - * Parse an array of coordinates into an ArcXML envelope structure. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * env - {Object} An envelope object that will contain the parsed coordinates. │ │ │ │ - * arr - {Array(double)} An array of coordinates in the order: [ minx, miny, maxx, maxy ] │ │ │ │ - */ │ │ │ │ - parseEnvelope: function(env, arr) { │ │ │ │ - if (arr && arr.length == 4) { │ │ │ │ - env.minx = arr[0]; │ │ │ │ - env.miny = arr[1]; │ │ │ │ - env.maxx = arr[2]; │ │ │ │ - env.maxy = arr[3]; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'Permalink': "Ligazón permanente", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: addLayers │ │ │ │ - * Add a collection of layers to another collection of layers. Each layer in the list is tuple of │ │ │ │ - * { id, visible }. These layer collections represent the │ │ │ │ - * /ARCXML/REQUEST/get_image/PROPERTIES/LAYERLIST/LAYERDEF items in ArcXML │ │ │ │ - * │ │ │ │ - * TODO: Add support for dynamic layer rendering. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * ll - {Array({id,visible})} A list of layer definitions. │ │ │ │ - * lyrs - {Array({id,visible})} A list of layer definitions. │ │ │ │ - */ │ │ │ │ - addLayers: function(ll, lyrs) { │ │ │ │ - for (var lind = 0, len = lyrs.length; lind < len; lind++) { │ │ │ │ - ll.push(lyrs[lind]); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'Overlays': "Capas superpostas", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: addImageSize │ │ │ │ - * Set the size of the requested image. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * imsize - {Object} An ArcXML imagesize object. │ │ │ │ - * olsize - {<OpenLayers.Size>} The image size to set. │ │ │ │ - */ │ │ │ │ - addImageSize: function(imsize, olsize) { │ │ │ │ - if (olsize !== null) { │ │ │ │ - imsize.width = olsize.w; │ │ │ │ - imsize.height = olsize.h; │ │ │ │ - imsize.printwidth = olsize.w; │ │ │ │ - imsize.printheight = olsize.h; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'Base Layer': "Capa base", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: addCoordSys │ │ │ │ - * Add the coordinate system information to an object. The object may be │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * featOrFilt - {Object} A featurecoordsys or filtercoordsys ArcXML structure. │ │ │ │ - * fsys - {String} or {<OpenLayers.Projection>} or {filtercoordsys} or │ │ │ │ - * {featurecoordsys} A projection representation. If it's a {String}, │ │ │ │ - * the value is assumed to be the SRID. If it's a {OpenLayers.Projection} │ │ │ │ - * AND Proj4js is available, the projection number and name are extracted │ │ │ │ - * from there. If it's a filter or feature ArcXML structure, it is copied. │ │ │ │ - */ │ │ │ │ - addCoordSys: function(featOrFilt, fsys) { │ │ │ │ - if (typeof fsys == "string") { │ │ │ │ - featOrFilt.id = parseInt(fsys); │ │ │ │ - featOrFilt.string = fsys; │ │ │ │ - } │ │ │ │ - // is this a proj4js instance? │ │ │ │ - else if (typeof fsys == "object" && fsys.proj !== null) { │ │ │ │ - featOrFilt.id = fsys.proj.srsProjNumber; │ │ │ │ - featOrFilt.string = fsys.proj.srsCode; │ │ │ │ - } else { │ │ │ │ - featOrFilt = fsys; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'noFID': "Non se pode actualizar a funcionalidade para a que non hai FID.", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: iserror │ │ │ │ - * Check to see if the response from the server was an error. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. If nothing is supplied, │ │ │ │ - * the current response is examined. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} true if the response was an error. │ │ │ │ - */ │ │ │ │ - iserror: function(data) { │ │ │ │ - var ret = null; │ │ │ │ + 'browserNotSupported': "O seu navegador non soporta a renderización de vectores. Os renderizadores soportados actualmente son:\n${renderers}", │ │ │ │ │ │ │ │ - if (!data) { │ │ │ │ - ret = (this.response.error !== ''); │ │ │ │ - } else { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - var errorNodes = data.documentElement.getElementsByTagName("ERROR"); │ │ │ │ - ret = (errorNodes !== null && errorNodes.length > 0); │ │ │ │ - } │ │ │ │ + 'minZoomLevelError': "A propiedade minZoomLevel é só para uso conxuntamente coas capas FixedZoomLevels-descendent. O feito de que esa capa wfs verifique o minZoomLevel é unha reliquia do pasado. Non podemos, con todo, eliminala sen a posibilidade de non romper as aplicacións baseadas en OL que poidan depender dela. Por iso a estamos deixando obsoleta (a comprobación minZoomLevel de embaixo será eliminada na versión 3.0). Por favor, no canto diso use o axuste de resolución mín/máx tal e como está descrito aquí: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - return ret; │ │ │ │ - }, │ │ │ │ + 'commitSuccess': "Transacción WFS: ÉXITO ${response}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read data from a string, and return an response. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Format.ArcXML.Response>} An ArcXML response. Note that this response │ │ │ │ - * data may change in the future. │ │ │ │ - */ │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - } │ │ │ │ + 'commitFailed': "Transacción WFS: FALLIDA ${response}", │ │ │ │ │ │ │ │ - var arcNode = null; │ │ │ │ - if (data && data.documentElement) { │ │ │ │ - if (data.documentElement.nodeName == "ARCXML") { │ │ │ │ - arcNode = data.documentElement; │ │ │ │ - } else { │ │ │ │ - arcNode = data.documentElement.getElementsByTagName("ARCXML")[0]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 'googleWarning': "A capa do Google non puido cargarse correctamente.\x3cbr\x3e\x3cbr\x3ePara evitar esta mensaxe, escolla unha nova capa base no seleccionador de capas na marxe superior dereita.\x3cbr\x3e\x3cbr\x3eProbablemente, isto acontece porque a escritura da libraría do Google Maps ou ben non foi incluída ou ben non contén a clave API correcta para o seu sitio.\x3cbr\x3e\x3cbr\x3eDesenvolvedores: para axudar a facer funcionar isto correctamente, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3epremede aquí\x3c/a\x3e", │ │ │ │ │ │ │ │ - // in Safari, arcNode will be there but will have a child named │ │ │ │ - // parsererror │ │ │ │ - if (!arcNode || arcNode.firstChild.nodeName === 'parsererror') { │ │ │ │ - var error, source; │ │ │ │ - try { │ │ │ │ - error = data.firstChild.nodeValue; │ │ │ │ - source = data.firstChild.childNodes[1].firstChild.nodeValue; │ │ │ │ - } catch (err) { │ │ │ │ - // pass │ │ │ │ - } │ │ │ │ - throw { │ │ │ │ - message: "Error parsing the ArcXML request", │ │ │ │ - error: error, │ │ │ │ - source: source │ │ │ │ - }; │ │ │ │ - } │ │ │ │ + 'getLayerWarning': "A capa ${layerType} foi incapaz de cargarse correctamente.\x3cbr\x3e\x3cbr\x3ePara evitar esta mensaxe, escolla unha nova capa base no seleccionador de capas na marxe superior dereita.\x3cbr\x3e\x3cbr\x3eProbablemente, isto acontece porque a escritura da libraría ${layerLib} non foi ben incluída.\x3cbr\x3e\x3cbr\x3eDesenvolvedores: para axudar a facer funcionar isto correctamente, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3epremede aquí\x3c/a\x3e", │ │ │ │ │ │ │ │ - var response = this.parseResponse(arcNode); │ │ │ │ - return response; │ │ │ │ - }, │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Escala = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Generate an ArcXml document string for sending to an ArcIMS server. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A string representing the ArcXML document request. │ │ │ │ - */ │ │ │ │ - write: function(request) { │ │ │ │ - if (!request) { │ │ │ │ - request = this.request; │ │ │ │ - } │ │ │ │ - var root = this.createElementNS("", "ARCXML"); │ │ │ │ - root.setAttribute("version", "1.1"); │ │ │ │ + 'W': "O", │ │ │ │ │ │ │ │ - var reqElem = this.createElementNS("", "REQUEST"); │ │ │ │ + 'E': "L", │ │ │ │ │ │ │ │ - if (request.get_image != null) { │ │ │ │ - var getElem = this.createElementNS("", "GET_IMAGE"); │ │ │ │ - reqElem.appendChild(getElem); │ │ │ │ + 'N': "N", │ │ │ │ │ │ │ │ - var propElem = this.createElementNS("", "PROPERTIES"); │ │ │ │ - getElem.appendChild(propElem); │ │ │ │ + 'S': "S", │ │ │ │ │ │ │ │ - var props = request.get_image.properties; │ │ │ │ - if (props.featurecoordsys != null) { │ │ │ │ - var feat = this.createElementNS("", "FEATURECOORDSYS"); │ │ │ │ - propElem.appendChild(feat); │ │ │ │ + 'reprojectDeprecated': "Está usando a opción \"reproject\" na capa ${layerName}. Esta opción está obsoleta: o seu uso foi deseñado para a visualización de datos sobre mapas base comerciais, pero esta funcionalidade debera agora ser obtida utilizando a proxección Spherical Mercator. Hai dispoñible máis información en http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ │ │ │ │ - if (props.featurecoordsys.id === 0) { │ │ │ │ - feat.setAttribute("string", props.featurecoordsys['string']); │ │ │ │ - } else { │ │ │ │ - feat.setAttribute("id", props.featurecoordsys.id); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 'methodDeprecated': "Este método está obsoleto e será eliminado na versión 3.0. Por favor, no canto deste use ${newMethod}." │ │ │ │ │ │ │ │ - if (props.filtercoordsys != null) { │ │ │ │ - var filt = this.createElementNS("", "FILTERCOORDSYS"); │ │ │ │ - propElem.appendChild(filt); │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/nds.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - if (props.filtercoordsys.id === 0) { │ │ │ │ - filt.setAttribute("string", props.filtercoordsys.string); │ │ │ │ - } else { │ │ │ │ - filt.setAttribute("id", props.filtercoordsys.id); │ │ │ │ - } │ │ │ │ - } │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Slomox │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (props.envelope != null) { │ │ │ │ - var env = this.createElementNS("", "ENVELOPE"); │ │ │ │ - propElem.appendChild(env); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - env.setAttribute("minx", props.envelope.minx); │ │ │ │ - env.setAttribute("miny", props.envelope.miny); │ │ │ │ - env.setAttribute("maxx", props.envelope.maxx); │ │ │ │ - env.setAttribute("maxy", props.envelope.maxy); │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["nds"] │ │ │ │ + * Dictionary for Plattdüütsch. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["nds"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - var imagesz = this.createElementNS("", "IMAGESIZE"); │ │ │ │ - propElem.appendChild(imagesz); │ │ │ │ + 'unhandledRequest': "Unbehannelt Trüchmellels för de Anfraag ${statusText}", │ │ │ │ │ │ │ │ - imagesz.setAttribute("height", props.imagesize.height); │ │ │ │ - imagesz.setAttribute("width", props.imagesize.width); │ │ │ │ + 'Permalink': "Permalink", │ │ │ │ │ │ │ │ - if (props.imagesize.height != props.imagesize.printheight || │ │ │ │ - props.imagesize.width != props.imagesize.printwidth) { │ │ │ │ - imagesz.setAttribute("printheight", props.imagesize.printheight); │ │ │ │ - imagesz.setArrtibute("printwidth", props.imagesize.printwidth); │ │ │ │ - } │ │ │ │ + 'Overlays': "Overlays", │ │ │ │ │ │ │ │ - if (props.background != null) { │ │ │ │ - var backgrnd = this.createElementNS("", "BACKGROUND"); │ │ │ │ - propElem.appendChild(backgrnd); │ │ │ │ + 'Base Layer': "Achtergrundkoort", │ │ │ │ │ │ │ │ - backgrnd.setAttribute("color", │ │ │ │ - props.background.color.r + "," + │ │ │ │ - props.background.color.g + "," + │ │ │ │ - props.background.color.b); │ │ │ │ + 'noFID': "En Feature, dat keen FID hett, kann nich aktuell maakt warrn.", │ │ │ │ │ │ │ │ - if (props.background.transcolor !== null) { │ │ │ │ - backgrnd.setAttribute("transcolor", │ │ │ │ - props.background.transcolor.r + "," + │ │ │ │ - props.background.transcolor.g + "," + │ │ │ │ - props.background.transcolor.b); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 'browserNotSupported': "Dien Browser ünnerstütt keen Vektorbiller. Ünnerstütt Renderers:\n${renderers}", │ │ │ │ │ │ │ │ - if (props.layerlist != null && props.layerlist.length > 0) { │ │ │ │ - var layerlst = this.createElementNS("", "LAYERLIST"); │ │ │ │ - propElem.appendChild(layerlst); │ │ │ │ + 'commitSuccess': "WFS-Transakschoon: hett klappt ${response}", │ │ │ │ │ │ │ │ - for (var ld = 0; ld < props.layerlist.length; ld++) { │ │ │ │ - var ldef = this.createElementNS("", "LAYERDEF"); │ │ │ │ - layerlst.appendChild(ldef); │ │ │ │ + 'commitFailed': "WFS-Transakschoon: hett nich klappt ${response}", │ │ │ │ │ │ │ │ - ldef.setAttribute("id", props.layerlist[ld].id); │ │ │ │ - ldef.setAttribute("visible", props.layerlist[ld].visible); │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Skaal = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - if (typeof props.layerlist[ld].query == "object") { │ │ │ │ - var query = props.layerlist[ld].query; │ │ │ │ + 'methodDeprecated': "Disse Methood is oold un schall dat in 3.0 nich mehr geven. Bruuk dor man beter ${newMethod} för." │ │ │ │ │ │ │ │ - if (query.where.length < 0) { │ │ │ │ - continue; │ │ │ │ - } │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/fur.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - var queryElem = null; │ │ │ │ - if (typeof query.spatialfilter == "boolean" && query.spatialfilter) { │ │ │ │ - // handle spatial filter madness │ │ │ │ - queryElem = this.createElementNS("", "SPATIALQUERY"); │ │ │ │ - } else { │ │ │ │ - queryElem = this.createElementNS("", "QUERY"); │ │ │ │ - } │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Klenje │ │ │ │ + */ │ │ │ │ │ │ │ │ - queryElem.setAttribute("where", query.where); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (typeof query.accuracy == "number" && query.accuracy > 0) { │ │ │ │ - queryElem.setAttribute("accuracy", query.accuracy); │ │ │ │ - } │ │ │ │ - if (typeof query.featurelimit == "number" && query.featurelimit < 2000) { │ │ │ │ - queryElem.setAttribute("featurelimit", query.featurelimit); │ │ │ │ - } │ │ │ │ - if (typeof query.subfields == "string" && query.subfields != "#ALL#") { │ │ │ │ - queryElem.setAttribute("subfields", query.subfields); │ │ │ │ - } │ │ │ │ - if (typeof query.joinexpression == "string" && query.joinexpression.length > 0) { │ │ │ │ - queryElem.setAttribute("joinexpression", query.joinexpression); │ │ │ │ - } │ │ │ │ - if (typeof query.jointables == "string" && query.jointables.length > 0) { │ │ │ │ - queryElem.setAttribute("jointables", query.jointables); │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["fur"] │ │ │ │ + * Dictionary for Furlan. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["fur"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - ldef.appendChild(queryElem); │ │ │ │ - } │ │ │ │ + 'Permalink': "Leam Permanent", │ │ │ │ │ │ │ │ - if (typeof props.layerlist[ld].renderer == "object") { │ │ │ │ - this.addRenderer(ldef, props.layerlist[ld].renderer); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else if (request.get_feature != null) { │ │ │ │ - var getElem = this.createElementNS("", "GET_FEATURES"); │ │ │ │ - getElem.setAttribute("outputmode", "newxml"); │ │ │ │ - getElem.setAttribute("checkesc", "true"); │ │ │ │ + 'Overlays': "Livei parsore", │ │ │ │ │ │ │ │ - if (request.get_feature.geometry) { │ │ │ │ - getElem.setAttribute("geometry", request.get_feature.geometry); │ │ │ │ - } else { │ │ │ │ - getElem.setAttribute("geometry", "false"); │ │ │ │ - } │ │ │ │ + 'Base Layer': "Livel di base", │ │ │ │ │ │ │ │ - if (request.get_feature.compact) { │ │ │ │ - getElem.setAttribute("compact", request.get_feature.compact); │ │ │ │ - } │ │ │ │ + 'browserNotSupported': "Il to sgarfadôr nol supuarte la renderizazion vetoriâl. Al moment a son supuartâts:\n${renderers}", │ │ │ │ │ │ │ │ - if (request.get_feature.featurelimit == "number") { │ │ │ │ - getElem.setAttribute("featurelimit", request.get_feature.featurelimit); │ │ │ │ - } │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Scjale = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - getElem.setAttribute("globalenvelope", "true"); │ │ │ │ - reqElem.appendChild(getElem); │ │ │ │ + 'W': "O", │ │ │ │ │ │ │ │ - if (request.get_feature.layer != null && request.get_feature.layer.length > 0) { │ │ │ │ - var lyrElem = this.createElementNS("", "LAYER"); │ │ │ │ - lyrElem.setAttribute("id", request.get_feature.layer); │ │ │ │ - getElem.appendChild(lyrElem); │ │ │ │ - } │ │ │ │ + 'E': "E", │ │ │ │ │ │ │ │ - var fquery = request.get_feature.query; │ │ │ │ - if (fquery != null) { │ │ │ │ - var qElem = null; │ │ │ │ - if (fquery.isspatial) { │ │ │ │ - qElem = this.createElementNS("", "SPATIALQUERY"); │ │ │ │ - } else { │ │ │ │ - qElem = this.createElementNS("", "QUERY"); │ │ │ │ - } │ │ │ │ - getElem.appendChild(qElem); │ │ │ │ + 'N': "N", │ │ │ │ │ │ │ │ - if (typeof fquery.accuracy == "number") { │ │ │ │ - qElem.setAttribute("accuracy", fquery.accuracy); │ │ │ │ - } │ │ │ │ - //qElem.setAttribute("featurelimit", "5"); │ │ │ │ + 'S': "S" │ │ │ │ │ │ │ │ - if (fquery.featurecoordsys != null) { │ │ │ │ - var fcsElem1 = this.createElementNS("", "FEATURECOORDSYS"); │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/pt-BR.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - if (fquery.featurecoordsys.id == 0) { │ │ │ │ - fcsElem1.setAttribute("string", fquery.featurecoordsys.string); │ │ │ │ - } else { │ │ │ │ - fcsElem1.setAttribute("id", fquery.featurecoordsys.id); │ │ │ │ - } │ │ │ │ - qElem.appendChild(fcsElem1); │ │ │ │ - } │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Luckas Blade │ │ │ │ + * - Rodrigo Avila │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (fquery.filtercoordsys != null) { │ │ │ │ - var fcsElem2 = this.createElementNS("", "FILTERCOORDSYS"); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (fquery.filtercoordsys.id === 0) { │ │ │ │ - fcsElem2.setAttribute("string", fquery.filtercoordsys.string); │ │ │ │ - } else { │ │ │ │ - fcsElem2.setAttribute("id", fquery.filtercoordsys.id); │ │ │ │ - } │ │ │ │ - qElem.appendChild(fcsElem2); │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["pt-br"] │ │ │ │ + * Dictionary for Português do Brasil. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["pt-BR"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - if (fquery.buffer > 0) { │ │ │ │ - var bufElem = this.createElementNS("", "BUFFER"); │ │ │ │ - bufElem.setAttribute("distance", fquery.buffer); │ │ │ │ - qElem.appendChild(bufElem); │ │ │ │ - } │ │ │ │ + 'unhandledRequest': "A requisição retornou um erro não tratado: ${statusText}", │ │ │ │ │ │ │ │ - if (fquery.isspatial) { │ │ │ │ - var spfElem = this.createElementNS("", "SPATIALFILTER"); │ │ │ │ - spfElem.setAttribute("relation", fquery.spatialfilter.relation); │ │ │ │ - qElem.appendChild(spfElem); │ │ │ │ + 'Permalink': "Link para essa página", │ │ │ │ │ │ │ │ - if (fquery.spatialfilter.envelope) { │ │ │ │ - var envElem = this.createElementNS("", "ENVELOPE"); │ │ │ │ - envElem.setAttribute("minx", fquery.spatialfilter.envelope.minx); │ │ │ │ - envElem.setAttribute("miny", fquery.spatialfilter.envelope.miny); │ │ │ │ - envElem.setAttribute("maxx", fquery.spatialfilter.envelope.maxx); │ │ │ │ - envElem.setAttribute("maxy", fquery.spatialfilter.envelope.maxy); │ │ │ │ - spfElem.appendChild(envElem); │ │ │ │ - } else if (typeof fquery.spatialfilter.polygon == "object") { │ │ │ │ - spfElem.appendChild(this.writePolygonGeometry(fquery.spatialfilter.polygon)); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 'Overlays': "Camadas de Sobreposição", │ │ │ │ │ │ │ │ - if (fquery.where != null && fquery.where.length > 0) { │ │ │ │ - qElem.setAttribute("where", fquery.where); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 'Base Layer': "Camada Base", │ │ │ │ │ │ │ │ - root.appendChild(reqElem); │ │ │ │ + 'noFID': "Não é possível atualizar uma feição que não tenha um FID.", │ │ │ │ │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [root]); │ │ │ │ - }, │ │ │ │ + 'browserNotSupported': "Seu navegador não suporta renderização de vetores. Os renderizadores suportados atualmente são:\n${renderers}", │ │ │ │ │ │ │ │ + 'minZoomLevelError': "A propriedade minZoomLevel é de uso restrito das camadas descendentes de FixedZoomLevels. A verificação dessa propriedade pelas camadas wfs é um resíduo do passado. Não podemos, entretanto não é possível removê-la sem possívelmente quebrar o funcionamento de aplicações OL que possuem depência com ela. Portanto estamos tornando seu uso obsoleto -- a verificação desse atributo será removida na versão 3.0. Ao invés, use as opções de resolução min/max como descrito em: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - addGroupRenderer: function(ldef, toprenderer) { │ │ │ │ - var topRelem = this.createElementNS("", "GROUPRENDERER"); │ │ │ │ - ldef.appendChild(topRelem); │ │ │ │ + 'commitSuccess': "Transação WFS : SUCESSO ${response}", │ │ │ │ │ │ │ │ - for (var rind = 0; rind < toprenderer.length; rind++) { │ │ │ │ - var renderer = toprenderer[rind]; │ │ │ │ - this.addRenderer(topRelem, renderer); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'commitFailed': "Transação WFS : ERRO ${response}", │ │ │ │ │ │ │ │ + 'googleWarning': "Não foi possível carregar a camada Google corretamente.\x3cbr\x3e\x3cbr\x3ePara se livrar dessa mensagem, selecione uma nova Camada Base, na ferramenta de alternação de camadas localização do canto superior direito.\x3cbr\x3e\x3cbr\x3eMuito provavelmente, isso foi causado porque o script da biblioteca do Google Maps não foi incluído, ou porque ele não contém a chave correta da API para o seu site.\x3cbr\x3e\x3cbr\x3eDesenvolvedores: Para obter ajuda em solucionar esse problema \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3ecliquem aqui\x3c/a\x3e", │ │ │ │ │ │ │ │ - addRenderer: function(topRelem, renderer) { │ │ │ │ - if (OpenLayers.Util.isArray(renderer)) { │ │ │ │ - this.addGroupRenderer(topRelem, renderer); │ │ │ │ - } else { │ │ │ │ - var renderElem = this.createElementNS("", renderer.type.toUpperCase() + "RENDERER"); │ │ │ │ - topRelem.appendChild(renderElem); │ │ │ │ + 'getLayerWarning': "Não foi possível carregar a camada ${layerType} corretamente.\x3cbr\x3e\x3cbr\x3ePara se livrar dessa mensagem, selecione uma nova Camada Base, na ferramenta de alternação de camadas localização do canto superior direito.\x3cbr\x3e\x3cbr\x3eMuito provavelmente, isso foi causado porque o script da biblioteca ${layerLib} não foi incluído corretamente.\x3cbr\x3e\x3cbr\x3eDesenvolvedores: Para obter ajuda em solucionar esse problema \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3ecliquem aqui\x3c/a\x3e", │ │ │ │ │ │ │ │ - if (renderElem.tagName == "VALUEMAPRENDERER") { │ │ │ │ - this.addValueMapRenderer(renderElem, renderer); │ │ │ │ - } else if (renderElem.tagName == "VALUEMAPLABELRENDERER") { │ │ │ │ - this.addValueMapLabelRenderer(renderElem, renderer); │ │ │ │ - } else if (renderElem.tagName == "SIMPLELABELRENDERER") { │ │ │ │ - this.addSimpleLabelRenderer(renderElem, renderer); │ │ │ │ - } else if (renderElem.tagName == "SCALEDEPENDENTRENDERER") { │ │ │ │ - this.addScaleDependentRenderer(renderElem, renderer); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Escala = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ + 'W': "O", │ │ │ │ │ │ │ │ - addScaleDependentRenderer: function(renderElem, renderer) { │ │ │ │ - if (typeof renderer.lower == "string" || typeof renderer.lower == "number") { │ │ │ │ - renderElem.setAttribute("lower", renderer.lower); │ │ │ │ - } │ │ │ │ - if (typeof renderer.upper == "string" || typeof renderer.upper == "number") { │ │ │ │ - renderElem.setAttribute("upper", renderer.upper); │ │ │ │ - } │ │ │ │ + 'E': "L", │ │ │ │ │ │ │ │ - this.addRenderer(renderElem, renderer.renderer); │ │ │ │ - }, │ │ │ │ + 'N': "N", │ │ │ │ │ │ │ │ + 'S': "S", │ │ │ │ │ │ │ │ - addValueMapLabelRenderer: function(renderElem, renderer) { │ │ │ │ - renderElem.setAttribute("lookupfield", renderer.lookupfield); │ │ │ │ - renderElem.setAttribute("labelfield", renderer.labelfield); │ │ │ │ + 'reprojectDeprecated': "Você está usando a opção \'reproject\' na camada ${layerName}. Essa opção está obsoleta: seu uso foi projetado para suportar a visualização de dados sobre bases de mapas comerciais, entretanto essa funcionalidade deve agora ser alcançada usando o suporte à projeção Mercator. Mais informação está disponível em: http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ │ │ │ │ - if (typeof renderer.exacts == "object") { │ │ │ │ - for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) { │ │ │ │ - var exact = renderer.exacts[ext]; │ │ │ │ + 'methodDeprecated': "Esse método está obsoleto e será removido na versão 3.0. Ao invés, por favor use ${newMethod}." │ │ │ │ │ │ │ │ - var eelem = this.createElementNS("", "EXACT"); │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/ia.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - if (typeof exact.value == "string") { │ │ │ │ - eelem.setAttribute("value", exact.value); │ │ │ │ - } │ │ │ │ - if (typeof exact.label == "string") { │ │ │ │ - eelem.setAttribute("label", exact.label); │ │ │ │ - } │ │ │ │ - if (typeof exact.method == "string") { │ │ │ │ - eelem.setAttribute("method", exact.method); │ │ │ │ - } │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - McDutchie │ │ │ │ + */ │ │ │ │ │ │ │ │ - renderElem.appendChild(eelem); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (typeof exact.symbol == "object") { │ │ │ │ - var selem = null; │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["ia"] │ │ │ │ + * Dictionary for Interlingua. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["ia"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - if (exact.symbol.type == "text") { │ │ │ │ - selem = this.createElementNS("", "TEXTSYMBOL"); │ │ │ │ - } │ │ │ │ + 'unhandledRequest': "Le responsa a un requesta non esseva maneate: ${statusText}", │ │ │ │ │ │ │ │ - if (selem != null) { │ │ │ │ - var keys = this.fontStyleKeys; │ │ │ │ - for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ - var key = keys[i]; │ │ │ │ - if (exact.symbol[key]) { │ │ │ │ - selem.setAttribute(key, exact.symbol[key]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - eelem.appendChild(selem); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } // for each exact │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'Permalink': "Permaligamine", │ │ │ │ │ │ │ │ - addValueMapRenderer: function(renderElem, renderer) { │ │ │ │ - renderElem.setAttribute("lookupfield", renderer.lookupfield); │ │ │ │ + 'Overlays': "Superpositiones", │ │ │ │ │ │ │ │ - if (typeof renderer.ranges == "object") { │ │ │ │ - for (var rng = 0, rnglen = renderer.ranges.length; rng < rnglen; rng++) { │ │ │ │ - var range = renderer.ranges[rng]; │ │ │ │ + 'Base Layer': "Strato de base", │ │ │ │ │ │ │ │ - var relem = this.createElementNS("", "RANGE"); │ │ │ │ - relem.setAttribute("lower", range.lower); │ │ │ │ - relem.setAttribute("upper", range.upper); │ │ │ │ + 'noFID': "Non pote actualisar un elemento sin FID.", │ │ │ │ │ │ │ │ - renderElem.appendChild(relem); │ │ │ │ + 'browserNotSupported': "Tu navigator non supporta le rendition de vectores. Le renditores actualmente supportate es:\n${renderers}", │ │ │ │ │ │ │ │ - if (typeof range.symbol == "object") { │ │ │ │ - var selem = null; │ │ │ │ + 'minZoomLevelError': "Le proprietate minZoomLevel es solmente pro uso con le stratos descendente de FixedZoomLevels. Le facto que iste strato WFS verifica minZoomLevel es un reliquia del passato. Nonobstante, si nos lo remove immediatemente, nos pote rumper applicationes a base de OL que depende de illo. Ergo nos lo declara obsolete; le verification de minZoomLevel in basso essera removite in version 3.0. Per favor usa in su loco le configuration de resolutiones min/max como describite a: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - if (range.symbol.type == "simplepolygon") { │ │ │ │ - selem = this.createElementNS("", "SIMPLEPOLYGONSYMBOL"); │ │ │ │ - } │ │ │ │ + 'commitSuccess': "Transaction WFS: SUCCESSO ${response}", │ │ │ │ │ │ │ │ - if (selem != null) { │ │ │ │ - if (typeof range.symbol.boundarycolor == "string") { │ │ │ │ - selem.setAttribute("boundarycolor", range.symbol.boundarycolor); │ │ │ │ - } │ │ │ │ - if (typeof range.symbol.fillcolor == "string") { │ │ │ │ - selem.setAttribute("fillcolor", range.symbol.fillcolor); │ │ │ │ - } │ │ │ │ - if (typeof range.symbol.filltransparency == "number") { │ │ │ │ - selem.setAttribute("filltransparency", range.symbol.filltransparency); │ │ │ │ - } │ │ │ │ - relem.appendChild(selem); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } // for each range │ │ │ │ - } else if (typeof renderer.exacts == "object") { │ │ │ │ - for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) { │ │ │ │ - var exact = renderer.exacts[ext]; │ │ │ │ + 'commitFailed': "Transaction WFS: FALLEVA ${response}", │ │ │ │ │ │ │ │ - var eelem = this.createElementNS("", "EXACT"); │ │ │ │ - if (typeof exact.value == "string") { │ │ │ │ - eelem.setAttribute("value", exact.value); │ │ │ │ - } │ │ │ │ - if (typeof exact.label == "string") { │ │ │ │ - eelem.setAttribute("label", exact.label); │ │ │ │ - } │ │ │ │ - if (typeof exact.method == "string") { │ │ │ │ - eelem.setAttribute("method", exact.method); │ │ │ │ - } │ │ │ │ + 'googleWarning': "Le strato Google non poteva esser cargate correctemente.\x3cbr\x3e\x3cbr\x3ePro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.\x3cbr\x3e\x3cbr\x3eMulto probabilemente, isto es proque le script del libreria de Google Maps non esseva includite o non contine le clave API correcte pro tu sito.\x3cbr\x3e\x3cbr\x3eDisveloppatores: Pro adjuta de corriger isto, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclicca hic\x3c/a", │ │ │ │ │ │ │ │ - renderElem.appendChild(eelem); │ │ │ │ + 'getLayerWarning': "Le strato ${layerType} non poteva esser cargate correctemente.\x3cbr\x3e\x3cbr\x3ePro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.\x3cbr\x3e\x3cbr\x3eMulto probabilemente, isto es proque le script del libreria de ${layerLib} non esseva correctemente includite.\x3cbr\x3e\x3cbr\x3eDisveloppatores: Pro adjuta de corriger isto, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclicca hic\x3c/a\x3e", │ │ │ │ │ │ │ │ - if (typeof exact.symbol == "object") { │ │ │ │ - var selem = null; │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Scala = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - if (exact.symbol.type == "simplemarker") { │ │ │ │ - selem = this.createElementNS("", "SIMPLEMARKERSYMBOL"); │ │ │ │ - } │ │ │ │ + 'W': "W", │ │ │ │ │ │ │ │ - if (selem != null) { │ │ │ │ - if (typeof exact.symbol.antialiasing == "string") { │ │ │ │ - selem.setAttribute("antialiasing", exact.symbol.antialiasing); │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.color == "string") { │ │ │ │ - selem.setAttribute("color", exact.symbol.color); │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.outline == "string") { │ │ │ │ - selem.setAttribute("outline", exact.symbol.outline); │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.overlap == "string") { │ │ │ │ - selem.setAttribute("overlap", exact.symbol.overlap); │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.shadow == "string") { │ │ │ │ - selem.setAttribute("shadow", exact.symbol.shadow); │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.transparency == "number") { │ │ │ │ - selem.setAttribute("transparency", exact.symbol.transparency); │ │ │ │ - } │ │ │ │ - //if (typeof exact.symbol.type == "string") │ │ │ │ - // selem.setAttribute("type", exact.symbol.type); │ │ │ │ - if (typeof exact.symbol.usecentroid == "string") { │ │ │ │ - selem.setAttribute("usecentroid", exact.symbol.usecentroid); │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.width == "number") { │ │ │ │ - selem.setAttribute("width", exact.symbol.width); │ │ │ │ - } │ │ │ │ + 'E': "E", │ │ │ │ │ │ │ │ - eelem.appendChild(selem); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } // for each exact │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'N': "N", │ │ │ │ │ │ │ │ + 'S': "S", │ │ │ │ │ │ │ │ - addSimpleLabelRenderer: function(renderElem, renderer) { │ │ │ │ - renderElem.setAttribute("field", renderer.field); │ │ │ │ - var keys = ['featureweight', 'howmanylabels', 'labelbufferratio', │ │ │ │ - 'labelpriorities', 'labelweight', 'linelabelposition', │ │ │ │ - 'rotationalangles' │ │ │ │ - ]; │ │ │ │ - for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ - var key = keys[i]; │ │ │ │ - if (renderer[key]) { │ │ │ │ - renderElem.setAttribute(key, renderer[key]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 'reprojectDeprecated': "Tu usa le option \'reproject\' in le strato ${layerName} layer. Iste option es obsolescente: illo esseva pro poter monstrar datos super cartas de base commercial, ma iste functionalitate pote ora esser attingite con le uso de Spherical Mercator. Ulterior information es disponibile a http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ │ │ │ │ - if (renderer.symbol.type == "text") { │ │ │ │ - var symbol = renderer.symbol; │ │ │ │ - var selem = this.createElementNS("", "TEXTSYMBOL"); │ │ │ │ - renderElem.appendChild(selem); │ │ │ │ + 'methodDeprecated': "Iste methodo ha essite declarate obsolescente e essera removite in version 3.0. Per favor usa ${newMethod} in su loco." │ │ │ │ │ │ │ │ - var keys = this.fontStyleKeys; │ │ │ │ - for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ - var key = keys[i]; │ │ │ │ - if (symbol[key]) { │ │ │ │ - selem.setAttribute(key, renderer[key]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/zh-TW.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - writePolygonGeometry: function(polygon) { │ │ │ │ - if (!(polygon instanceof OpenLayers.Geometry.Polygon)) { │ │ │ │ - throw { │ │ │ │ - message: 'Cannot write polygon geometry to ArcXML with an ' + │ │ │ │ - polygon.CLASS_NAME + ' object.', │ │ │ │ - geometry: polygon │ │ │ │ - }; │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - var polyElem = this.createElementNS("", "POLYGON"); │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["zh-TW"] │ │ │ │ + * Dictionary for Traditional Chinese. (Used Mainly in Taiwan) │ │ │ │ + * Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["zh-TW"] = { │ │ │ │ │ │ │ │ - for (var ln = 0, lnlen = polygon.components.length; ln < lnlen; ln++) { │ │ │ │ - var ring = polygon.components[ln]; │ │ │ │ - var ringElem = this.createElementNS("", "RING"); │ │ │ │ + 'unhandledRequest': "未處理的請求,傳回值為 ${statusText}。", │ │ │ │ │ │ │ │ - for (var rn = 0, rnlen = ring.components.length; rn < rnlen; rn++) { │ │ │ │ - var point = ring.components[rn]; │ │ │ │ - var pointElem = this.createElementNS("", "POINT"); │ │ │ │ + 'Permalink': "永久連結", │ │ │ │ │ │ │ │ - pointElem.setAttribute("x", point.x); │ │ │ │ - pointElem.setAttribute("y", point.y); │ │ │ │ + 'Overlays': "額外圖層", │ │ │ │ │ │ │ │ - ringElem.appendChild(pointElem); │ │ │ │ - } │ │ │ │ + 'Base Layer': "基礎圖層", │ │ │ │ │ │ │ │ - polyElem.appendChild(ringElem); │ │ │ │ - } │ │ │ │ + 'noFID': "因為沒有 FID 所以無法更新 feature。", │ │ │ │ │ │ │ │ - return polyElem; │ │ │ │ - }, │ │ │ │ + 'browserNotSupported': "您的瀏覽器未支援向量渲染. 目前支援的渲染方式是:\n${renderers}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: parseResponse │ │ │ │ - * Take an ArcXML response, and parse in into this object's internal properties. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} The ArcXML response, as either a string or the │ │ │ │ - * top level DOMElement of the response. │ │ │ │ - */ │ │ │ │ - parseResponse: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - var newData = new OpenLayers.Format.XML(); │ │ │ │ - data = newData.read(data); │ │ │ │ - } │ │ │ │ - var response = new OpenLayers.Format.ArcXML.Response(); │ │ │ │ + // console message │ │ │ │ + 'minZoomLevelError': "minZoomLevel 屬性僅適合用在 " + │ │ │ │ + "FixedZoomLevels-descendent 類型的圖層. 這個" + │ │ │ │ + "wfs layer 的 minZoomLevel 是過去所遺留下來的," + │ │ │ │ + "然而我們不能移除它而不讓它將" + │ │ │ │ + "過去的程式相容性給破壞掉。" + │ │ │ │ + "因此我們將會迴避使用它 -- minZoomLevel " + │ │ │ │ + "會在3.0被移除,請改" + │ │ │ │ + "用在這邊描述的 min/max resolution 設定: " + │ │ │ │ + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - var errorNode = data.getElementsByTagName("ERROR"); │ │ │ │ + 'commitSuccess': "WFS Transaction: 成功 ${response}", │ │ │ │ │ │ │ │ - if (errorNode != null && errorNode.length > 0) { │ │ │ │ - response.error = this.getChildValue(errorNode, "Unknown error."); │ │ │ │ - } else { │ │ │ │ - var responseNode = data.getElementsByTagName("RESPONSE"); │ │ │ │ + 'commitFailed': "WFS Transaction: 失敗 ${response}", │ │ │ │ │ │ │ │ - if (responseNode == null || responseNode.length == 0) { │ │ │ │ - response.error = "No RESPONSE tag found in ArcXML response."; │ │ │ │ - return response; │ │ │ │ - } │ │ │ │ + 'googleWarning': "The Google Layer 圖層無法被正確的載入。<br><br>" + │ │ │ │ + "要迴避這個訊息, 請在右上角的圖層改變器裡," + │ │ │ │ + "選一個新的基礎圖層。<br><br>" + │ │ │ │ + "很有可能是因為 Google Maps 的函式庫" + │ │ │ │ + "腳本沒有被正確的置入,或沒有包含 " + │ │ │ │ + "您網站上正確的 API key <br><br>" + │ │ │ │ + "開發者: 要幫助這個行為正確完成," + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ + "target='_blank'>請按這裡</a>", │ │ │ │ │ │ │ │ - var rtype = responseNode[0].firstChild.nodeName; │ │ │ │ - if (rtype == "#text") { │ │ │ │ - rtype = responseNode[0].firstChild.nextSibling.nodeName; │ │ │ │ - } │ │ │ │ + 'getLayerWarning': "${layerType} 圖層無法被正確的載入。<br><br>" + │ │ │ │ + "要迴避這個訊息, 請在右上角的圖層改變器裡," + │ │ │ │ + "選一個新的基礎圖層。<br><br>" + │ │ │ │ + "很有可能是因為 ${layerLib} 的函式庫" + │ │ │ │ + "腳本沒有被正確的置入。<br><br>" + │ │ │ │ + "開發者: 要幫助這個行為正確完成," + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ + "target='_blank'>請按這裡</a>", │ │ │ │ │ │ │ │ - if (rtype == "IMAGE") { │ │ │ │ - var envelopeNode = data.getElementsByTagName("ENVELOPE"); │ │ │ │ - var outputNode = data.getElementsByTagName("OUTPUT"); │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Scale = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - if (envelopeNode == null || envelopeNode.length == 0) { │ │ │ │ - response.error = "No ENVELOPE tag found in ArcXML response."; │ │ │ │ - } else if (outputNode == null || outputNode.length == 0) { │ │ │ │ - response.error = "No OUTPUT tag found in ArcXML response."; │ │ │ │ - } else { │ │ │ │ - var envAttr = this.parseAttributes(envelopeNode[0]); │ │ │ │ - var outputAttr = this.parseAttributes(outputNode[0]); │ │ │ │ + // console message │ │ │ │ + 'reprojectDeprecated': "你正使用 'reproject' 這個選項 " + │ │ │ │ + "在 ${layerName} 層。這個選項已經不再使用:" + │ │ │ │ + "它的使用原本是設計用來支援在商業地圖上秀出資料," + │ │ │ │ + "但這個功能已經被" + │ │ │ │ + "Spherical Mercator所取代。更多的資訊可以在 " + │ │ │ │ + "http://trac.openlayers.org/wiki/SphericalMercator 找到。", │ │ │ │ │ │ │ │ - if (typeof outputAttr.type == "string") { │ │ │ │ - response.image = { │ │ │ │ - envelope: envAttr, │ │ │ │ - output: { │ │ │ │ - type: outputAttr.type, │ │ │ │ - data: this.getChildValue(outputNode[0]) │ │ │ │ - } │ │ │ │ - }; │ │ │ │ - } else { │ │ │ │ - response.image = { │ │ │ │ - envelope: envAttr, │ │ │ │ - output: outputAttr │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else if (rtype == "FEATURES") { │ │ │ │ - var features = responseNode[0].getElementsByTagName("FEATURES"); │ │ │ │ + // console message │ │ │ │ + 'methodDeprecated': "這個方法已經不再使用且在3.0將會被移除," + │ │ │ │ + "請使用 ${newMethod} 來代替。", │ │ │ │ │ │ │ │ - // get the feature count │ │ │ │ - var featureCount = features[0].getElementsByTagName("FEATURECOUNT"); │ │ │ │ - response.features.featurecount = featureCount[0].getAttribute("count"); │ │ │ │ + 'end': '' │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/vi.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - if (response.features.featurecount > 0) { │ │ │ │ - // get the feature envelope │ │ │ │ - var envelope = features[0].getElementsByTagName("ENVELOPE"); │ │ │ │ - response.features.envelope = this.parseAttributes(envelope[0], typeof(0)); │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Minh Nguyen │ │ │ │ + */ │ │ │ │ │ │ │ │ - // get the field values per feature │ │ │ │ - var featureList = features[0].getElementsByTagName("FEATURE"); │ │ │ │ - for (var fn = 0; fn < featureList.length; fn++) { │ │ │ │ - var feature = new OpenLayers.Feature.Vector(); │ │ │ │ - var fields = featureList[fn].getElementsByTagName("FIELD"); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - for (var fdn = 0; fdn < fields.length; fdn++) { │ │ │ │ - var fieldName = fields[fdn].getAttribute("name"); │ │ │ │ - var fieldValue = fields[fdn].getAttribute("value"); │ │ │ │ - feature.attributes[fieldName] = fieldValue; │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["vi"] │ │ │ │ + * Dictionary for Tiếng Việt. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["vi"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - var geom = featureList[fn].getElementsByTagName("POLYGON"); │ │ │ │ + 'unhandledRequest': "Không xử lý được phản hồi ${statusText} cho yêu cầu", │ │ │ │ │ │ │ │ - if (geom.length > 0) { │ │ │ │ - // if there is a polygon, create an openlayers polygon, and assign │ │ │ │ - // it to the .geometry property of the feature │ │ │ │ - var ring = geom[0].getElementsByTagName("RING"); │ │ │ │ + 'Permalink': "Liên kết thường trực", │ │ │ │ │ │ │ │ - var polys = []; │ │ │ │ - for (var rn = 0; rn < ring.length; rn++) { │ │ │ │ - var linearRings = []; │ │ │ │ - linearRings.push(this.parsePointGeometry(ring[rn])); │ │ │ │ + 'Overlays': "Lấp bản đồ", │ │ │ │ │ │ │ │ - var holes = ring[rn].getElementsByTagName("HOLE"); │ │ │ │ - for (var hn = 0; hn < holes.length; hn++) { │ │ │ │ - linearRings.push(this.parsePointGeometry(holes[hn])); │ │ │ │ - } │ │ │ │ - holes = null; │ │ │ │ - polys.push(new OpenLayers.Geometry.Polygon(linearRings)); │ │ │ │ - linearRings = null; │ │ │ │ - } │ │ │ │ - ring = null; │ │ │ │ + 'Base Layer': "Lớp nền", │ │ │ │ │ │ │ │ - if (polys.length == 1) { │ │ │ │ - feature.geometry = polys[0]; │ │ │ │ - } else { │ │ │ │ - feature.geometry = new OpenLayers.Geometry.MultiPolygon(polys); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 'noFID': "Không thể cập nhật tính năng thiếu FID.", │ │ │ │ │ │ │ │ - response.features.feature.push(feature); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - response.error = "Unidentified response type."; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return response; │ │ │ │ - }, │ │ │ │ + 'browserNotSupported': "Trình duyệt của bạn không hỗ trợ chức năng vẽ bằng vectơ. Hiện hỗ trợ các bộ kết xuất:\n${renderers}", │ │ │ │ │ │ │ │ + 'minZoomLevelError': "Chỉ nên sử dụng thuộc tính minZoomLevel với các lớp FixedZoomLevels-descendent. Việc lớp wfs này tìm cho minZoomLevel là di tích còn lại từ xưa. Tuy nhiên, nếu chúng tôi dời nó thì sẽ vỡ các chương trình OpenLayers mà dựa trên nó. Bởi vậy chúng tôi phản đối sử dụng nó\x26nbsp;– bước tìm cho minZoomLevel sẽ được dời vào phiên bản 3.0. Xin sử dụng thiết lập độ phân tích tối thiểu / tối đa thay thế, theo hướng dẫn này: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: parseAttributes │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {<DOMElement>} An element to parse attributes from. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An attributes object, with properties set to attribute values. │ │ │ │ - */ │ │ │ │ - parseAttributes: function(node, type) { │ │ │ │ - var attributes = {}; │ │ │ │ - for (var attr = 0; attr < node.attributes.length; attr++) { │ │ │ │ - if (type == "number") { │ │ │ │ - attributes[node.attributes[attr].nodeName] = parseFloat(node.attributes[attr].nodeValue); │ │ │ │ - } else { │ │ │ │ - attributes[node.attributes[attr].nodeName] = node.attributes[attr].nodeValue; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return attributes; │ │ │ │ - }, │ │ │ │ + 'commitSuccess': "Giao dịch WFS: THÀNH CÔNG ${response}", │ │ │ │ │ │ │ │ + 'commitFailed': "Giao dịch WFS: THẤT BẠI ${response}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: parsePointGeometry │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {<DOMElement>} An element to parse <COORDS> or <POINT> arcxml data from. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Geometry.LinearRing>} A linear ring represented by the node's points. │ │ │ │ - */ │ │ │ │ - parsePointGeometry: function(node) { │ │ │ │ - var ringPoints = []; │ │ │ │ - var coords = node.getElementsByTagName("COORDS"); │ │ │ │ + 'googleWarning': "Không thể tải lớp Google đúng đắn.\x3cbr\x3e\x3cbr\x3eĐể tránh thông báo này lần sau, hãy chọn BaseLayer mới dùng điều khiển chọn lớp ở góc trên phải.\x3cbr\x3e\x3cbr\x3eChắc script thư viện Google Maps hoặc không được bao gồm hoặc không chứa khóa API hợp với website của bạn.\x3cbr\x3e\x3cbr\x3e\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eTrợ giúp về tính năng này\x3c/a\x3e cho người phát triển.", │ │ │ │ │ │ │ │ - if (coords.length > 0) { │ │ │ │ - // if coords is present, it's the only coords item │ │ │ │ - var coordArr = this.getChildValue(coords[0]); │ │ │ │ - coordArr = coordArr.split(/;/); │ │ │ │ - for (var cn = 0; cn < coordArr.length; cn++) { │ │ │ │ - var coordItems = coordArr[cn].split(/ /); │ │ │ │ - ringPoints.push(new OpenLayers.Geometry.Point(coordItems[0], coordItems[1])); │ │ │ │ - } │ │ │ │ - coords = null; │ │ │ │ - } else { │ │ │ │ - var point = node.getElementsByTagName("POINT"); │ │ │ │ - if (point.length > 0) { │ │ │ │ - for (var pn = 0; pn < point.length; pn++) { │ │ │ │ - ringPoints.push( │ │ │ │ - new OpenLayers.Geometry.Point( │ │ │ │ - parseFloat(point[pn].getAttribute("x")), │ │ │ │ - parseFloat(point[pn].getAttribute("y")) │ │ │ │ - ) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - point = null; │ │ │ │ - } │ │ │ │ + 'getLayerWarning': "Không thể tải lớp ${layerType} đúng đắn.\x3cbr\x3e\x3cbr\x3eĐể tránh thông báo này lần sau, hãy chọn BaseLayer mới dùng điều khiển chọn lớp ở góc trên phải.\x3cbr\x3e\x3cbr\x3eChắc script thư viện ${layerLib} không được bao gồm đúng kiểu.\x3cbr\x3e\x3cbr\x3e\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eTrợ giúp về tính năng này\x3c/a\x3e cho người phát triển.", │ │ │ │ │ │ │ │ - return new OpenLayers.Geometry.LinearRing(ringPoints); │ │ │ │ - }, │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Tỷ lệ = 1 : ${scaleDenom}", │ │ │ │ + │ │ │ │ + 'W': "T", │ │ │ │ + │ │ │ │ + 'E': "Đ", │ │ │ │ + │ │ │ │ + 'N': "B", │ │ │ │ + │ │ │ │ + 'S': "N", │ │ │ │ + │ │ │ │ + 'reprojectDeprecated': "Bạn đang áp dụng chế độ “reproject” vào lớp ${layerName}. Chế độ này đã bị phản đối: nó có mục đích hỗ trợ lấp dữ liệu trên các nền bản đồ thương mại; nên thực hiện hiệu ứng đó dùng tính năng Mercator Hình cầu. Có sẵn thêm chi tiết tại http://trac.openlayers.org/wiki/SphericalMercator .", │ │ │ │ + │ │ │ │ + 'methodDeprecated': "Phương thức này đã bị phản đối và sẽ bị dời vào phiên bản 3.0. Xin hãy sử dụng ${newMethod} thay thế." │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.ArcXML" │ │ │ │ }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/nl.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ -OpenLayers.Format.ArcXML.Request = OpenLayers.Class({ │ │ │ │ - initialize: function(params) { │ │ │ │ - var defaults = { │ │ │ │ - get_image: { │ │ │ │ - properties: { │ │ │ │ - background: null, │ │ │ │ - /*{ │ │ │ │ - color: { r:255, g:255, b:255 }, │ │ │ │ - transcolor: null │ │ │ │ - },*/ │ │ │ │ - draw: true, │ │ │ │ - envelope: { │ │ │ │ - minx: 0, │ │ │ │ - miny: 0, │ │ │ │ - maxx: 0, │ │ │ │ - maxy: 0 │ │ │ │ - }, │ │ │ │ - featurecoordsys: { │ │ │ │ - id: 0, │ │ │ │ - string: "", │ │ │ │ - datumtransformid: 0, │ │ │ │ - datumtransformstring: "" │ │ │ │ - }, │ │ │ │ - filtercoordsys: { │ │ │ │ - id: 0, │ │ │ │ - string: "", │ │ │ │ - datumtransformid: 0, │ │ │ │ - datumtransformstring: "" │ │ │ │ - }, │ │ │ │ - imagesize: { │ │ │ │ - height: 0, │ │ │ │ - width: 0, │ │ │ │ - dpi: 96, │ │ │ │ - printheight: 0, │ │ │ │ - printwidth: 0, │ │ │ │ - scalesymbols: false │ │ │ │ - }, │ │ │ │ - layerlist: [], │ │ │ │ - /* no support for legends */ │ │ │ │ - output: { │ │ │ │ - baseurl: "", │ │ │ │ - legendbaseurl: "", │ │ │ │ - legendname: "", │ │ │ │ - legendpath: "", │ │ │ │ - legendurl: "", │ │ │ │ - name: "", │ │ │ │ - path: "", │ │ │ │ - type: "jpg", │ │ │ │ - url: "" │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Siebrand │ │ │ │ + */ │ │ │ │ │ │ │ │ - get_feature: { │ │ │ │ - layer: "", │ │ │ │ - query: { │ │ │ │ - isspatial: false, │ │ │ │ - featurecoordsys: { │ │ │ │ - id: 0, │ │ │ │ - string: "", │ │ │ │ - datumtransformid: 0, │ │ │ │ - datumtransformstring: "" │ │ │ │ - }, │ │ │ │ - filtercoordsys: { │ │ │ │ - id: 0, │ │ │ │ - string: "", │ │ │ │ - datumtransformid: 0, │ │ │ │ - datumtransformstring: "" │ │ │ │ - }, │ │ │ │ - buffer: 0, │ │ │ │ - where: "", │ │ │ │ - spatialfilter: { │ │ │ │ - relation: "envelope_intersection", │ │ │ │ - envelope: null │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - environment: { │ │ │ │ - separators: { │ │ │ │ - cs: " ", │ │ │ │ - ts: ";" │ │ │ │ - } │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["nl"] │ │ │ │ + * Dictionary for Nederlands. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["nl"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - layer: [], │ │ │ │ - workspaces: [] │ │ │ │ - }; │ │ │ │ + 'unhandledRequest': "Het verzoek is niet afgehandeld met de volgende melding: ${statusText}", │ │ │ │ │ │ │ │ - return OpenLayers.Util.extend(this, defaults); │ │ │ │ - }, │ │ │ │ + 'Permalink': "Permanente verwijzing", │ │ │ │ + │ │ │ │ + 'Overlays': "Overlays", │ │ │ │ + │ │ │ │ + 'Base Layer': "Achtergrondkaart", │ │ │ │ + │ │ │ │ + 'noFID': "Een optie die geen FID heeft kan niet bijgewerkt worden.", │ │ │ │ + │ │ │ │ + 'browserNotSupported': "Uw browser ondersteunt het weergeven van vectoren niet.\nMomenteel ondersteunde weergavemogelijkheden:\n${renderers}", │ │ │ │ + │ │ │ │ + 'minZoomLevelError': "De eigenschap minZoomLevel is alleen bedoeld voor gebruik lagen met die afstammen van FixedZoomLevels-lagen.\nDat deze WFS-laag minZoomLevel controleert, is een overblijfsel uit het verleden.\nWe kunnen deze controle echter niet verwijderen zonder op OL gebaseerde applicaties die hervan afhankelijk zijn stuk te maken.\nDaarom heeft deze functionaliteit de eigenschap \'deprecated\' gekregen - de minZoomLevel wordt verwijderd in versie 3.0.\nGebruik in plaats van deze functie de mogelijkheid om min/max voor resolutie in te stellen zoals op de volgende pagina wordt beschreven:\nhttp://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + │ │ │ │ + 'commitSuccess': "WFS-transactie: succesvol ${response}", │ │ │ │ + │ │ │ │ + 'commitFailed': "WFS-transactie: mislukt ${response}", │ │ │ │ + │ │ │ │ + 'googleWarning': "De Google-Layer kon niet correct geladen worden.\x3cbr /\x3e\x3cbr /\x3e\nOm deze melding niet meer te krijgen, moet u een andere achtergrondkaart kiezen in de laagwisselaar in de rechterbovenhoek.\x3cbr /\x3e\x3cbr /\x3e\nDit komt waarschijnlijk doordat de bibliotheek ${layerLib} niet correct ingevoegd is.\x3cbr /\x3e\x3cbr /\x3e\nOntwikkelaars: \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik hier\x3c/a\x3e om dit werkend te krijgen.", │ │ │ │ + │ │ │ │ + 'getLayerWarning': "De laag ${layerType} kon niet goed geladen worden.\x3cbr /\x3e\x3cbr /\x3e\nOm deze melding niet meer te krijgen, moet u een andere achtergrondkaart kiezen in de laagwisselaar in de rechterbovenhoek.\x3cbr /\x3e\x3cbr /\x3e\nDit komt waarschijnlijk doordat de bibliotheek ${layerLib} niet correct is ingevoegd.\x3cbr /\x3e\x3cbr /\x3e\nOntwikkelaars: \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik hier\x3c/a\x3e om dit werkend te krijgen.", │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Schaal = 1 : ${scaleDenom}", │ │ │ │ + │ │ │ │ + 'W': "W", │ │ │ │ + │ │ │ │ + 'E': "O", │ │ │ │ + │ │ │ │ + 'N': "N", │ │ │ │ + │ │ │ │ + 'S': "Z", │ │ │ │ + │ │ │ │ + 'reprojectDeprecated': "U gebruikt de optie \'reproject\' op de laag ${layerName}.\nDeze optie is vervallen: deze optie was ontwikkeld om gegevens over commerciële basiskaarten weer te geven, maar deze functionaliteit wordt nu bereikt door ondersteuning van Spherical Mercator.\nMeer informatie is beschikbaar op http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + │ │ │ │ + 'methodDeprecated': "Deze methode is verouderd en wordt verwijderd in versie 3.0.\nGebruik ${newMethod}." │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.ArcXML.Request" │ │ │ │ }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/id.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ -OpenLayers.Format.ArcXML.Response = OpenLayers.Class({ │ │ │ │ - initialize: function(params) { │ │ │ │ - var defaults = { │ │ │ │ - image: { │ │ │ │ - envelope: null, │ │ │ │ - output: '' │ │ │ │ - }, │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Irwangatot │ │ │ │ + * - IvanLanin │ │ │ │ + */ │ │ │ │ │ │ │ │ - features: { │ │ │ │ - featurecount: 0, │ │ │ │ - envelope: null, │ │ │ │ - feature: [] │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - error: '' │ │ │ │ - }; │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["id"] │ │ │ │ + * Dictionary for Bahasa Indonesia. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["id"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - return OpenLayers.Util.extend(this, defaults); │ │ │ │ - }, │ │ │ │ + 'unhandledRequest': "Permintaan yang tak tertangani menghasilkan ${statusText}", │ │ │ │ + │ │ │ │ + 'Permalink': "Pranala permanen", │ │ │ │ + │ │ │ │ + 'Overlays': "Hamparan", │ │ │ │ + │ │ │ │ + 'Base Layer': "Lapisan Dasar", │ │ │ │ + │ │ │ │ + 'noFID': "Tidak dapat memperbarui fitur yang tidak memiliki FID.", │ │ │ │ + │ │ │ │ + 'browserNotSupported': "Peramban Anda tidak mendukung penggambaran vektor. Penggambar yang didukung saat ini adalah:\n${renderers}", │ │ │ │ + │ │ │ │ + 'minZoomLevelError': "Properti minZoomLevel hanya ditujukan bekerja dengan lapisan FixedZoomLevels-descendent. Pengecekan minZoomLevel oleh lapisan wfs adalah peninggalan masa lalu. Kami tidak dapat menghapusnya tanpa kemungkinan merusak aplikasi berbasis OL yang mungkin bergantung padanya. Karenanya, kami menganggapnya tidak berlaku -- Cek minZoomLevel di bawah ini akan dihapus pada 3.0. Silakan gunakan penyetelan resolusi min/maks seperti dijabarkan di sini: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + │ │ │ │ + 'commitSuccess': "WFS Transaksi: BERHASIL ${respon}", │ │ │ │ + │ │ │ │ + 'commitFailed': "WFS Transaksi: GAGAL ${respon}", │ │ │ │ + │ │ │ │ + 'googleWarning': "Lapisan Google tidak dapat dimuat dengan benar.\x3cbr\x3e\x3cbr\x3eUntuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.\x3cbr\x3e\x3cbr\x3eKemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan atau tidak mengandung kunci API yang tepat untuk situs Anda.\x3cbr\x3e\x3cbr\x3ePengembang: Untuk bantuan mengatasi masalah ini, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eklik di sini\x3c/a\x3e", │ │ │ │ + │ │ │ │ + 'getLayerWarning': "Lapisan ${layerType} tidak dapat dimuat dengan benar.\x3cbr\x3e\x3cbr\x3eUntuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.\x3cbr\x3e\x3cbr\x3eKemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan dengan benar.\x3cbr\x3e\x3cbr\x3ePengembang: Untuk bantuan mengatasi masalah ini, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik di sini\x3c/a\x3e", │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Sekala = 1 : ${scaleDenom}", │ │ │ │ + │ │ │ │ + 'W': "B", │ │ │ │ + │ │ │ │ + 'E': "T", │ │ │ │ + │ │ │ │ + 'N': "U", │ │ │ │ + │ │ │ │ + 'S': "S", │ │ │ │ + │ │ │ │ + 'reprojectDeprecated': "Anda menggunakan opsi \'reproject\' pada lapisan ${layerName}. Opsi ini telah ditinggalkan: penggunaannya dirancang untuk mendukung tampilan data melalui peta dasar komersial, tapi fungsionalitas tersebut saat ini harus dilakukan dengan menggunakan dukungan Spherical Mercator. Informasi lebih lanjut tersedia di http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + │ │ │ │ + 'methodDeprecated': "Metode ini telah usang dan akan dihapus di 3.0. Sebaliknya, harap gunakan ${newMethod}." │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.ArcXML.Response" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/ArcIMS.js │ │ │ │ + OpenLayers/Lang/oc.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. */ │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Cedric31 │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ - * @requires OpenLayers/Format/ArcXML.js │ │ │ │ - * @requires OpenLayers/Request.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.ArcIMS │ │ │ │ - * Instances of OpenLayers.Layer.ArcIMS are used to display data from ESRI ArcIMS │ │ │ │ - * Mapping Services. Create a new ArcIMS layer with the <OpenLayers.Layer.ArcIMS> │ │ │ │ - * constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * Namespace: OpenLayers.Lang["oc"] │ │ │ │ + * Dictionary for Occitan. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.ArcIMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ +OpenLayers.Lang["oc"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: DEFAULT_PARAMS │ │ │ │ - * {Object} Default query string parameters. │ │ │ │ - */ │ │ │ │ - DEFAULT_PARAMS: { │ │ │ │ - ClientVersion: "9.2", │ │ │ │ - ServiceName: '' │ │ │ │ - }, │ │ │ │ + 'unhandledRequest': "Requèsta pas gerida, retorna ${statusText}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: featureCoordSys │ │ │ │ - * {String} Code for feature coordinate system. Default is "4326". │ │ │ │ - */ │ │ │ │ - featureCoordSys: "4326", │ │ │ │ + 'Permalink': "Permaligam", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: filterCoordSys │ │ │ │ - * {String} Code for filter coordinate system. Default is "4326". │ │ │ │ - */ │ │ │ │ - filterCoordSys: "4326", │ │ │ │ + 'Overlays': "Calques", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: layers │ │ │ │ - * {Array} An array of objects with layer properties. │ │ │ │ - */ │ │ │ │ - layers: null, │ │ │ │ + 'Base Layer': "Calc de basa", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: async │ │ │ │ - * {Boolean} Request images asynchronously. Default is true. │ │ │ │ - */ │ │ │ │ - async: true, │ │ │ │ + 'noFID': "Impossible de metre a jorn un objècte sens identificant (fid).", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: name │ │ │ │ - * {String} Layer name. Default is "ArcIMS". │ │ │ │ - */ │ │ │ │ - name: "ArcIMS", │ │ │ │ + 'browserNotSupported': "Vòstre navegidor supòrta pas lo rendut vectorial. Los renderers actualament suportats son : \n${renderers}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} The layer is a base layer. Default is true. │ │ │ │ - */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + 'minZoomLevelError': "La proprietat minZoomLevel deu èsser utilizada solament per de jaces FixedZoomLevels-descendent. Lo fach qu\'aqueste jaç WFS verifique la preséncia de minZoomLevel es una relica del passat. Çaquelà, la podèm suprimir sens copar d\'aplicacions que ne poirián dependre. Es per aquò que la depreciam -- la verificacion del minZoomLevel serà suprimida en version 3.0. A la plaça, mercés d\'utilizar los paramètres de resolucions min/max tal coma descrich sus : http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: DEFAULT_OPTIONS │ │ │ │ - * {Object} Default layers properties. │ │ │ │ - */ │ │ │ │ - DEFAULT_OPTIONS: { │ │ │ │ - tileSize: new OpenLayers.Size(512, 512), │ │ │ │ - featureCoordSys: "4326", │ │ │ │ - filterCoordSys: "4326", │ │ │ │ - layers: null, │ │ │ │ - isBaseLayer: true, │ │ │ │ - async: true, │ │ │ │ - name: "ArcIMS" │ │ │ │ - }, │ │ │ │ + 'commitSuccess': "Transaccion WFS : SUCCES ${response}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.ArcIMS │ │ │ │ - * Create a new ArcIMS layer object. │ │ │ │ - * │ │ │ │ - * Example: │ │ │ │ - * (code) │ │ │ │ - * var arcims = new OpenLayers.Layer.ArcIMS( │ │ │ │ - * "Global Sample", │ │ │ │ - * "http://sample.avencia.com/servlet/com.esri.esrimap.Esrimap", │ │ │ │ - * { │ │ │ │ - * service: "OpenLayers_Sample", │ │ │ │ - * layers: [ │ │ │ │ - * // layers to manipulate │ │ │ │ - * {id: "1", visible: true} │ │ │ │ - * ] │ │ │ │ - * } │ │ │ │ - * ); │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} A name for the layer │ │ │ │ - * url - {String} Base url for the ArcIMS server │ │ │ │ - * options - {Object} Optional object with properties to be set on the │ │ │ │ - * layer. │ │ │ │ - */ │ │ │ │ - initialize: function(name, url, options) { │ │ │ │ + 'commitFailed': "Transaccion WFS : FRACAS ${response}", │ │ │ │ │ │ │ │ - this.tileSize = new OpenLayers.Size(512, 512); │ │ │ │ + 'googleWarning': "Lo jaç Google es pas estat en mesura de se cargar corrèctament.\x3cbr\x3e\x3cbr\x3ePer suprimir aqueste messatge, causissètz una BaseLayer novèla dins lo selector de jaç en naut a drecha.\x3cbr\x3e\x3cbr\x3eAquò es possiblament causat par la non-inclusion de la librariá Google Maps, o alara perque que la clau de l\'API correspond pas a vòstre site.\x3cbr\x3e\x3cbr\x3eDesvolopaires : per saber cossí corregir aquò, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclicatz aicí\x3c/a\x3e", │ │ │ │ │ │ │ │ - // parameters │ │ │ │ - this.params = OpenLayers.Util.applyDefaults({ │ │ │ │ - ServiceName: options.serviceName │ │ │ │ - }, │ │ │ │ - this.DEFAULT_PARAMS │ │ │ │ - ); │ │ │ │ - this.options = OpenLayers.Util.applyDefaults( │ │ │ │ - options, this.DEFAULT_OPTIONS │ │ │ │ - ); │ │ │ │ + 'getLayerWarning': "Lo jaç ${layerType} es pas en mesura de se cargar corrèctament.\x3cbr\x3e\x3cbr\x3ePer suprimir aqueste messatge, causissètz una BaseLayer novèla dins lo selector de jaç en naut a drecha.\x3cbr\x3e\x3cbr\x3eAquò es possiblament causat per la non-inclusion de la librariá ${layerLib}.\x3cbr\x3e\x3cbr\x3eDesvolopaires : per saber cossí corregir aquí, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclicatz aicí\x3c/a\x3e", │ │ │ │ │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply( │ │ │ │ - this, [name, url, this.params, options] │ │ │ │ - ); │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Escala ~ 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - //layer is transparent │ │ │ │ - if (this.transparent) { │ │ │ │ + 'W': "O", │ │ │ │ │ │ │ │ - // unless explicitly set in options, make layer an overlay │ │ │ │ - if (!this.isBaseLayer) { │ │ │ │ - this.isBaseLayer = false; │ │ │ │ - } │ │ │ │ + 'E': "È", │ │ │ │ │ │ │ │ - // jpegs can never be transparent, so intelligently switch the │ │ │ │ - // format, depending on the browser's capabilities │ │ │ │ - if (this.format == "image/jpeg") { │ │ │ │ - this.format = OpenLayers.Util.alphaHack() ? "image/gif" : "image/png"; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 'N': "N", │ │ │ │ │ │ │ │ - // create an empty layer list if no layers specified in the options │ │ │ │ - if (this.options.layers === null) { │ │ │ │ - this.options.layers = []; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'S': "S", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getURL │ │ │ │ - * Return an image url this layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the │ │ │ │ - * request. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A string with the map image's url. │ │ │ │ - */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - var url = ""; │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ + 'reprojectDeprecated': "Utilizatz l\'opcion \'reproject\' sul jaç ${layerName}. Aquesta opcion es despreciada : Son usatge permetiá d\'afichar de donadas al dessús de jaces raster comercials. Aquesta foncionalitat ara es suportada en utilizant lo supòrt de la projeccion Mercator Esferica. Mai d\'informacion es disponibla sus http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ │ │ │ │ - // create an arcxml request to generate the image │ │ │ │ - var axlReq = new OpenLayers.Format.ArcXML( │ │ │ │ - OpenLayers.Util.extend(this.options, { │ │ │ │ - requesttype: "image", │ │ │ │ - envelope: bounds.toArray(), │ │ │ │ - tileSize: this.tileSize │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ + 'methodDeprecated': "Aqueste metòde es despreciada, e serà suprimida a la version 3.0. Mercés d\'utilizar ${newMethod} a la plaça." │ │ │ │ │ │ │ │ - // create a synchronous ajax request to get an arcims image │ │ │ │ - var req = new OpenLayers.Request.POST({ │ │ │ │ - url: this.getFullRequestString(), │ │ │ │ - data: axlReq.write(), │ │ │ │ - async: false │ │ │ │ - }); │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/ru.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - // if the response exists │ │ │ │ - if (req != null) { │ │ │ │ - var doc = req.responseXML; │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Ferrer │ │ │ │ + * - Komzpa │ │ │ │ + * - Lockal │ │ │ │ + * - Александр Сигачёв │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = req.responseText; │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - // create a new arcxml format to read the response │ │ │ │ - var axlResp = new OpenLayers.Format.ArcXML(); │ │ │ │ - var arcxml = axlResp.read(doc); │ │ │ │ - url = this.getUrlOrImage(arcxml.image.output); │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["ru"] │ │ │ │ + * Dictionary for Русский. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["ru"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - return url; │ │ │ │ - }, │ │ │ │ + 'unhandledRequest': "Необработанный запрос вернул ${statusText}", │ │ │ │ │ │ │ │ + 'Permalink': "Постоянная ссылка", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getURLasync │ │ │ │ - * Get an image url this layer asynchronously, and execute a callback │ │ │ │ - * when the image url is generated. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the │ │ │ │ - * request. │ │ │ │ - * callback - {Function} Function to call when image url is retrieved. │ │ │ │ - * scope - {Object} The scope of the callback method. │ │ │ │ - */ │ │ │ │ - getURLasync: function(bounds, callback, scope) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ + 'Overlays': "Слои", │ │ │ │ │ │ │ │ - // create an arcxml request to generate the image │ │ │ │ - var axlReq = new OpenLayers.Format.ArcXML( │ │ │ │ - OpenLayers.Util.extend(this.options, { │ │ │ │ - requesttype: "image", │ │ │ │ - envelope: bounds.toArray(), │ │ │ │ - tileSize: this.tileSize │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ + 'Base Layer': "Основной слой", │ │ │ │ │ │ │ │ - // create an asynchronous ajax request to get an arcims image │ │ │ │ - OpenLayers.Request.POST({ │ │ │ │ - url: this.getFullRequestString(), │ │ │ │ - async: true, │ │ │ │ - data: axlReq.write(), │ │ │ │ - callback: function(req) { │ │ │ │ - // process the response from ArcIMS, and call the callback function │ │ │ │ - // to set the image URL │ │ │ │ - var doc = req.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = req.responseText; │ │ │ │ - } │ │ │ │ + 'noFID': "Невозможно обновить объект, для которого нет FID.", │ │ │ │ │ │ │ │ - // create a new arcxml format to read the response │ │ │ │ - var axlResp = new OpenLayers.Format.ArcXML(); │ │ │ │ - var arcxml = axlResp.read(doc); │ │ │ │ + 'browserNotSupported': "Ваш браузер не поддерживает векторную графику. На данный момент поддерживаются:\n${renderers}", │ │ │ │ │ │ │ │ - callback.call(scope, this.getUrlOrImage(arcxml.image.output)); │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ + 'minZoomLevelError': "Свойство minZoomLevel предназначено только для использования со слоями, являющимися потомками FixedZoomLevels. То, что этот WFS-слой проверяется на minZoomLevel — реликт прошлого. Однако мы не можем удалить эту функцию, так как, возможно, от неё зависят некоторые основанные на OpenLayers приложения. Функция объявлена устаревшей — проверка minZoomLevel будет удалена в 3.0. Пожалуйста, используйте вместо неё настройку мин/макс разрешения, описанную здесь: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getUrlOrImage │ │ │ │ - * Extract a url or image from the ArcXML image output. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * output - {Object} The image.output property of the object returned from │ │ │ │ - * the ArcXML format read method. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A URL for an image (potentially with the data protocol). │ │ │ │ - */ │ │ │ │ - getUrlOrImage: function(output) { │ │ │ │ - var ret = ""; │ │ │ │ - if (output.url) { │ │ │ │ - // If the image response output url is a string, then the image │ │ │ │ - // data is not inline. │ │ │ │ - ret = output.url; │ │ │ │ - } else if (output.data) { │ │ │ │ - // The image data is inline and base64 encoded, create a data │ │ │ │ - // url for the image. This will only work for small images, │ │ │ │ - // due to browser url length limits. │ │ │ │ - ret = "data:image/" + output.type + │ │ │ │ - ";base64," + output.data; │ │ │ │ - } │ │ │ │ - return ret; │ │ │ │ - }, │ │ │ │ + 'commitSuccess': "Транзакция WFS: УСПЕШНО ${response}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setLayerQuery │ │ │ │ - * Set the query definition on this layer. Query definitions are used to │ │ │ │ - * render parts of the spatial data in an image, and can be used to │ │ │ │ - * filter features or layers in the ArcIMS service. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * id - {String} The ArcIMS layer ID. │ │ │ │ - * querydef - {Object} The query definition to apply to this layer. │ │ │ │ - */ │ │ │ │ - setLayerQuery: function(id, querydef) { │ │ │ │ - // find the matching layer, if it exists │ │ │ │ - for (var lyr = 0; lyr < this.options.layers.length; lyr++) { │ │ │ │ - if (id == this.options.layers[lyr].id) { │ │ │ │ - // replace this layer definition │ │ │ │ - this.options.layers[lyr].query = querydef; │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 'commitFailed': "Транзакция WFS: ОШИБКА ${response}", │ │ │ │ │ │ │ │ - // no layer found, create a new definition │ │ │ │ - this.options.layers.push({ │ │ │ │ - id: id, │ │ │ │ - visible: true, │ │ │ │ - query: querydef │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ + 'googleWarning': "Слой Google не удалось нормально загрузить.\x3cbr\x3e\x3cbr\x3eЧтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.\x3cbr\x3e\x3cbr\x3eСкорее всего, причина в том, что библиотека Google Maps не была включена или не содержит корректного API-ключа для вашего сайта.\x3cbr\x3e\x3cbr\x3eРазработчикам: чтобы узнать, как сделать, чтобы всё заработало, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eщёлкните тут\x3c/a\x3e", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getFeatureInfo │ │ │ │ - * Get feature information from ArcIMS. Using the applied geometry, apply │ │ │ │ - * the options to the query (buffer, area/envelope intersection), and │ │ │ │ - * query the ArcIMS service. │ │ │ │ - * │ │ │ │ - * A note about accuracy: │ │ │ │ - * ArcIMS interprets the accuracy attribute in feature requests to be │ │ │ │ - * something like the 'modulus' operator on feature coordinates, │ │ │ │ - * applied to the database geometry of the feature. It doesn't round, │ │ │ │ - * so your feature coordinates may be up to (1 x accuracy) offset from │ │ │ │ - * the actual feature coordinates. If the accuracy of the layer is not │ │ │ │ - * specified, the accuracy will be computed to be approximately 1 │ │ │ │ - * feature coordinate per screen pixel. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.LonLat>} or {<OpenLayers.Geometry.Polygon>} The │ │ │ │ - * geometry to use when making the query. This should be a closed │ │ │ │ - * polygon for behavior approximating a free selection. │ │ │ │ - * layer - {Object} The ArcIMS layer definition. This is an anonymous object │ │ │ │ - * that looks like: │ │ │ │ - * (code) │ │ │ │ - * { │ │ │ │ - * id: "ArcXML layer ID", // the ArcXML layer ID │ │ │ │ - * query: { │ │ │ │ - * where: "STATE = 'PA'", // the where clause of the query │ │ │ │ - * accuracy: 100 // the accuracy of the returned feature │ │ │ │ - * } │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ - * options - {Object} Object with non-default properties to set on the layer. │ │ │ │ - * Supported properties are buffer, callback, scope, and any other │ │ │ │ - * properties applicable to the ArcXML format. Set the 'callback' and │ │ │ │ - * 'scope' for an object and function to recieve the parsed features │ │ │ │ - * from ArcIMS. │ │ │ │ - */ │ │ │ │ - getFeatureInfo: function(geometry, layer, options) { │ │ │ │ - // set the buffer to 1 unit (dd/m/ft?) by default │ │ │ │ - var buffer = options.buffer || 1; │ │ │ │ - // empty callback by default │ │ │ │ - var callback = options.callback || function() {}; │ │ │ │ - // default scope is window (global) │ │ │ │ - var scope = options.scope || window; │ │ │ │ + 'getLayerWarning': "Слой ${layerType} не удалось нормально загрузить. \x3cbr\x3e\x3cbr\x3eЧтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.\x3cbr\x3e\x3cbr\x3eСкорее всего, причина в том, что библиотека ${layerLib} не была включена или была включена некорректно.\x3cbr\x3e\x3cbr\x3eРазработчикам: чтобы узнать, как сделать, чтобы всё заработало, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eщёлкните тут\x3c/a\x3e", │ │ │ │ │ │ │ │ - // apply these option to the request options │ │ │ │ - var requestOptions = {}; │ │ │ │ - OpenLayers.Util.extend(requestOptions, this.options); │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Масштаб = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - // this is a feature request │ │ │ │ - requestOptions.requesttype = "feature"; │ │ │ │ + 'W': "З", │ │ │ │ │ │ │ │ - if (geometry instanceof OpenLayers.LonLat) { │ │ │ │ - // create an envelope if the geometry is really a lon/lat │ │ │ │ - requestOptions.polygon = null; │ │ │ │ - requestOptions.envelope = [ │ │ │ │ - geometry.lon - buffer, │ │ │ │ - geometry.lat - buffer, │ │ │ │ - geometry.lon + buffer, │ │ │ │ - geometry.lat + buffer │ │ │ │ - ]; │ │ │ │ - } else if (geometry instanceof OpenLayers.Geometry.Polygon) { │ │ │ │ - // use the polygon assigned, and empty the envelope │ │ │ │ - requestOptions.envelope = null; │ │ │ │ - requestOptions.polygon = geometry; │ │ │ │ - } │ │ │ │ + 'E': "В", │ │ │ │ │ │ │ │ - // create an arcxml request to get feature requests │ │ │ │ - var arcxml = new OpenLayers.Format.ArcXML(requestOptions); │ │ │ │ + 'N': "С", │ │ │ │ │ │ │ │ - // apply any get feature options to the arcxml request │ │ │ │ - OpenLayers.Util.extend(arcxml.request.get_feature, options); │ │ │ │ + 'S': "Ю", │ │ │ │ │ │ │ │ - arcxml.request.get_feature.layer = layer.id; │ │ │ │ - if (typeof layer.query.accuracy == "number") { │ │ │ │ - // set the accuracy if it was specified │ │ │ │ - arcxml.request.get_feature.query.accuracy = layer.query.accuracy; │ │ │ │ - } else { │ │ │ │ - // guess that the accuracy is 1 per screen pixel │ │ │ │ - var mapCenter = this.map.getCenter(); │ │ │ │ - var viewPx = this.map.getViewPortPxFromLonLat(mapCenter); │ │ │ │ - viewPx.x++; │ │ │ │ - var mapOffCenter = this.map.getLonLatFromPixel(viewPx); │ │ │ │ - arcxml.request.get_feature.query.accuracy = mapOffCenter.lon - mapCenter.lon; │ │ │ │ - } │ │ │ │ + 'reprojectDeprecated': "Вы используете опцию \'reproject\' для слоя ${layerName}. Эта опция является устаревшей: ее использование предполагалось для поддержки показа данных поверх коммерческих базовых карт, но теперь этот функционал несёт встроенная поддержка сферической проекции Меркатора. Больше сведений доступно на http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ │ │ │ │ - // set the get_feature query to be the same as the layer passed in │ │ │ │ - arcxml.request.get_feature.query.where = layer.query.where; │ │ │ │ + 'methodDeprecated': "Этот метод считается устаревшим и будет удалён в версии 3.0. Пожалуйста, пользуйтесь ${newMethod}." │ │ │ │ │ │ │ │ - // use area_intersection │ │ │ │ - arcxml.request.get_feature.query.spatialfilter.relation = "area_intersection"; │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/pl.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - // create a new asynchronous request to get the feature info │ │ │ │ - OpenLayers.Request.POST({ │ │ │ │ - url: this.getFullRequestString({ │ │ │ │ - 'CustomService': 'Query' │ │ │ │ - }), │ │ │ │ - data: arcxml.write(), │ │ │ │ - callback: function(request) { │ │ │ │ - // parse the arcxml response │ │ │ │ - var response = arcxml.parseResponse(request.responseText); │ │ │ │ +/* Translators: │ │ │ │ + * - Arkadiusz Grabka │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (!arcxml.iserror()) { │ │ │ │ - // if the arcxml is not an error, call the callback with the features parsed │ │ │ │ - callback.call(scope, response.features); │ │ │ │ - } else { │ │ │ │ - // if the arcxml is an error, return null features selected │ │ │ │ - callback.call(scope, null); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.ArcIMS>} An exact clone of this layer │ │ │ │ - */ │ │ │ │ - clone: function(obj) { │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["pl"] │ │ │ │ + * Dictionary for Polish. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["pl"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.ArcIMS(this.name, │ │ │ │ - this.url, │ │ │ │ - this.getOptions()); │ │ │ │ - } │ │ │ │ + 'unhandledRequest': "Nieobsługiwane żądanie zwróciło ${statusText}", │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + 'Permalink': "Permalink", │ │ │ │ │ │ │ │ - // copy/set any non-init, non-simple values here │ │ │ │ + 'Overlays': "Nakładki", │ │ │ │ │ │ │ │ - return obj; │ │ │ │ - }, │ │ │ │ + 'Base Layer': "Warstwa podstawowa", │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.ArcIMS" │ │ │ │ + 'noFID': "Nie można zaktualizować funkcji, dla których nie ma FID.", │ │ │ │ + │ │ │ │ + 'browserNotSupported': "Twoja przeglądarka nie obsługuje renderowania wektorów. Obecnie obsługiwane renderowanie to:\n${renderers}", │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'minZoomLevelError': "Właściwość minZoomLevel jest przeznaczona tylko do użytku " + │ │ │ │ + "z warstwami FixedZoomLevels-descendent." + │ │ │ │ + "Warstwa wfs, która sprawdza minZoomLevel jest reliktem przeszłości." + │ │ │ │ + "Nie możemy jej jednak usunąc bez mozliwości łamania OL aplikacji, " + │ │ │ │ + "które mogą być od niej zależne. " + │ │ │ │ + "Dlatego jesteśmy za deprecjację -- minZoomLevel " + │ │ │ │ + "zostanie usunięta w wersji 3.0. W zamian prosze użyj " + │ │ │ │ + "min/max rozdzielczości w sposób opisany tutaj: " + │ │ │ │ + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + │ │ │ │ + 'commitSuccess': "Transakcja WFS: SUKCES ${response}", │ │ │ │ + │ │ │ │ + 'commitFailed': "Transakcja WFS: FAILED ${response}", │ │ │ │ + │ │ │ │ + 'googleWarning': "Warstwa Google nie był w stanie załadować się poprawnie.<br><br>" + │ │ │ │ + "Aby pozbyć się tej wiadomości, wybierz nową Warstwe podstawową " + │ │ │ │ + "w przełączniku warstw w górnym prawym rogu mapy.<br><br>" + │ │ │ │ + "Najprawdopodobniej jest to spowodowane tym, że biblioteka Google Maps " + │ │ │ │ + "nie jest załadowana, lub nie zawiera poprawnego klucza do API dla twojej strony<br><br>" + │ │ │ │ + "Programisto: Aby uzyskać pomoc , " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ + "target='_blank'>kliknij tutaj</a>", │ │ │ │ + │ │ │ │ + 'getLayerWarning': "Warstwa ${layerType} nie mogła zostać załadowana poprawnie.<br><br>" + │ │ │ │ + "Aby pozbyć się tej wiadomości, wybierz nową Warstwe podstawową " + │ │ │ │ + "w przełączniku warstw w górnym prawym rogu mapy.<br><br>" + │ │ │ │ + "Najprawdopodobniej jest to spowodowane tym, że biblioteka ${layerLib} " + │ │ │ │ + "nie jest załadowana, lub może(o ile biblioteka tego wymaga) " + │ │ │ │ + "byc potrzebny klucza do API dla twojej strony<br><br>" + │ │ │ │ + "Programisto: Aby uzyskać pomoc , " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ + "target='_blank'>kliknij tutaj</a>", │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Skala = 1 : ${scaleDenom}", │ │ │ │ + │ │ │ │ + //labels for the graticule control │ │ │ │ + 'W': 'ZACH', │ │ │ │ + 'E': 'WSCH', │ │ │ │ + 'N': 'PN', │ │ │ │ + 'S': 'PD', │ │ │ │ + 'Graticule': 'Siatka', │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'reprojectDeprecated': "w warstwie ${layerName} używasz opcji 'reproject'. " + │ │ │ │ + "Ta opcja jest przestarzała: " + │ │ │ │ + "jej zastosowanie został zaprojektowany, aby wspierać wyświetlania danych przez komercyjne mapy, " + │ │ │ │ + "jednak obecnie ta funkcjonalność powinien zostać osiągnięty za pomocą Spherical Mercator " + │ │ │ │ + "its use was designed to support displaying data over commercial. Więcje informacji na ten temat możesz znaleźć na stronie " + │ │ │ │ + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'methodDeprecated': "Ta metoda jest przestarzała i będzie usunięta od wersji 3.0. " + │ │ │ │ + "W zamian użyj ${newMethod}." │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/ArcGIS93Rest.js │ │ │ │ + OpenLayers/Lang/ksh.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. */ │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Purodha │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.ArcGIS93Rest │ │ │ │ - * Instances of OpenLayers.Layer.ArcGIS93Rest are used to display data from │ │ │ │ - * ESRI ArcGIS Server 9.3 (and up?) Mapping Services using the REST API. │ │ │ │ - * Create a new ArcGIS93Rest layer with the <OpenLayers.Layer.ArcGIS93Rest> │ │ │ │ - * constructor. More detail on the REST API is available at │ │ │ │ - * http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/index.html ; │ │ │ │ - * specifically, the URL provided to this layer should be an export service │ │ │ │ - * URL: http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/export.html │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * Namespace: OpenLayers.Lang["ksh"] │ │ │ │ + * Dictionary for Ripoarisch. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.ArcGIS93Rest = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ +OpenLayers.Lang["ksh"] = OpenLayers.Util.applyDefaults({ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: DEFAULT_PARAMS │ │ │ │ - * {Object} Hashtable of default parameter key/value pairs │ │ │ │ - */ │ │ │ │ - DEFAULT_PARAMS: { │ │ │ │ - format: "png" │ │ │ │ - }, │ │ │ │ + 'unhandledRequest': "Met dä Antwoot op en Aanfrooch ham_mer nix aanjefange: ${statusText}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} Default is true for ArcGIS93Rest layer │ │ │ │ - */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + 'Permalink': "Lengk op Duuer", │ │ │ │ │ │ │ │ + 'Overlays': "Drövver jelaat", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.ArcGIS93Rest │ │ │ │ - * Create a new ArcGIS93Rest layer object. │ │ │ │ - * │ │ │ │ - * Example: │ │ │ │ - * (code) │ │ │ │ - * var arcims = new OpenLayers.Layer.ArcGIS93Rest("MyName", │ │ │ │ - * "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/export", │ │ │ │ - * { │ │ │ │ - * layers: "0,1,2" │ │ │ │ - * }); │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} A name for the layer │ │ │ │ - * url - {String} Base url for the ArcGIS server REST service │ │ │ │ - * options - {Object} An object with key/value pairs representing the │ │ │ │ - * options and option values. │ │ │ │ - * │ │ │ │ - * Valid Options: │ │ │ │ - * format - {String} MIME type of desired image type. │ │ │ │ - * layers - {String} Comma-separated list of layers to display. │ │ │ │ - * srs - {String} Projection ID. │ │ │ │ - */ │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - var newArguments = []; │ │ │ │ - //uppercase params │ │ │ │ - params = OpenLayers.Util.upperCaseObject(params); │ │ │ │ - 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) │ │ │ │ - ); │ │ │ │ + 'Base Layer': "Jrund-Nivoh", │ │ │ │ │ │ │ │ - //layer is transparent │ │ │ │ - if (this.params.TRANSPARENT && │ │ │ │ - this.params.TRANSPARENT.toString().toLowerCase() == "true") { │ │ │ │ + 'noFID': "En Saach, woh kein \x3ci lang=\"en\"\x3eFID\x3c/i\x3e för doh es, löht sesch nit ändere.", │ │ │ │ │ │ │ │ - // unless explicitly set in options, make layer an overlay │ │ │ │ - if ((options == null) || (!options.isBaseLayer)) { │ │ │ │ - this.isBaseLayer = false; │ │ │ │ - } │ │ │ │ + 'browserNotSupported': "Dinge Brauser kann kein Väktore ußjävve. De Zoote Ußjaabe, di em Momang jon, sen:\n${renderers}", │ │ │ │ │ │ │ │ - // jpegs can never be transparent, so intelligently switch the │ │ │ │ - // format, depending on the browser's capabilities │ │ │ │ - if (this.params.FORMAT == "jpg") { │ │ │ │ - this.params.FORMAT = OpenLayers.Util.alphaHack() ? "gif" : │ │ │ │ - "png"; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'minZoomLevelError': "De Eijeschaff „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“ es bloß doför jedaach, dat mer se met dä Nivvohß bruch, di vun \x3ccode lang=\"en\"\x3eFixedZoomLevels\x3c/code\x3e affhange don. Dat dat \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Nivvoh övverhoup de Eijeschaff „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“ pröhfe deiht, es noch övveresch vun fröhjer. Mer künne dat ävver jez nit fott lohße, oohne dat mer Jevaa loufe, dat Aanwendunge vun OpenLayers nit mieh loufe, di sesch doh velleijsch noch drop am verlohße sin. Dröm sare mer, dat mer et nit mieh han welle, un de „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“-Eijeschaff weed hee vun de Version 3.0 af nit mieh jeprööf wäde. Nemm doför de Enstellung för de hühßte un de kleinßte Oplöhsung, esu wi et en http://trac.openlayers.org/wiki/SettingZoomLevels opjeschrevve es.", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.ArcGIS93Rest>} An exact clone of this layer │ │ │ │ - */ │ │ │ │ - clone: function(obj) { │ │ │ │ + 'commitSuccess': "Dä \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Vörjang es joot jeloufe: ${response}", │ │ │ │ │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.ArcGIS93Rest(this.name, │ │ │ │ - this.url, │ │ │ │ - this.params, │ │ │ │ - this.getOptions()); │ │ │ │ - } │ │ │ │ + 'commitFailed': "Dä \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Vörjang es scheif jejange: ${response}", │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + 'googleWarning': "Dat Nivvoh \x3ccode lang=\"en\"\x3eGoogle\x3c/code\x3e kunnt nit reschtesch jelaade wääde.\x3cbr /\x3e\x3cbr /\x3eÖm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhke, rähß bovve en de Äk.\x3cbr /\x3e\x3cbr /\x3eWascheinlesch es dat wiel dat \x3ci lang=\"en\"\x3eGoogle-Maps\x3c/i\x3e-Skrepp entweeder nit reschtesch enjebonge wood, udder nit dä reschtejje \x3ci lang=\"en\"\x3eAPI\x3c/i\x3e-Schlößel för Ding Web-ßait scheke deiht.\x3cbr /\x3e\x3cbr /\x3eFör Projrammierer jidd_et Hölp do_drövver, \x3ca href=\"http://trac.openlayers.org/wiki/Google\" target=\"_blank\"\x3ewi mer dat aan et Loufe brengk\x3c/a\x3e.", │ │ │ │ │ │ │ │ - // copy/set any non-init, non-simple values here │ │ │ │ + 'getLayerWarning': "Dat Nivvoh \x3ccode\x3e${layerType}\x3c/code\x3e kunnt nit reschtesch jelaade wääde.\x3cbr /\x3e\x3cbr /\x3eÖm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhkre, rähß bovve en de Äk.\x3cbr /\x3e\x3cbr /\x3eWascheinlesch es dat, wiel dat Skrepp \x3ccode\x3e${layerLib}\x3c/code\x3e nit reschtesch enjebonge wood.\x3cbr /\x3e\x3cbr /\x3eFör Projrammierer jidd_Et Hölp do_drövver, \x3ca href=\"http://trac.openlayers.org/wiki/${layerLib}\" target=\"_blank\"\x3ewi mer dat aan et Loufe brengk\x3c/a\x3e.", │ │ │ │ │ │ │ │ - return obj; │ │ │ │ - }, │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Mohßshtaab = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ + 'W': "W", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getURL │ │ │ │ - * Return an image url this layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the │ │ │ │ - * request. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A string with the map image's url. │ │ │ │ - */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ + 'E': "O", │ │ │ │ │ │ │ │ - // ArcGIS Server only wants the numeric portion of the projection ID. │ │ │ │ - var projWords = this.projection.getCode().split(":"); │ │ │ │ - var srid = projWords[projWords.length - 1]; │ │ │ │ + 'N': "N", │ │ │ │ │ │ │ │ - var imageSize = this.getImageSize(); │ │ │ │ - var newParams = { │ │ │ │ - 'BBOX': bounds.toBBOX(), │ │ │ │ - 'SIZE': imageSize.w + "," + imageSize.h, │ │ │ │ - // We always want image, the other options were json, image with a whole lotta html around it, etc. │ │ │ │ - 'F': "image", │ │ │ │ - 'BBOXSR': srid, │ │ │ │ - 'IMAGESR': srid │ │ │ │ - }; │ │ │ │ + 'S': "S", │ │ │ │ │ │ │ │ - // Now add the filter parameters. │ │ │ │ - if (this.layerDefs) { │ │ │ │ - var layerDefStrList = []; │ │ │ │ - var layerID; │ │ │ │ - for (layerID in this.layerDefs) { │ │ │ │ - if (this.layerDefs.hasOwnProperty(layerID)) { │ │ │ │ - if (this.layerDefs[layerID]) { │ │ │ │ - layerDefStrList.push(layerID); │ │ │ │ - layerDefStrList.push(":"); │ │ │ │ - layerDefStrList.push(this.layerDefs[layerID]); │ │ │ │ - layerDefStrList.push(";"); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (layerDefStrList.length > 0) { │ │ │ │ - newParams['LAYERDEFS'] = layerDefStrList.join(""); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var requestString = this.getFullRequestString(newParams); │ │ │ │ - return requestString; │ │ │ │ - }, │ │ │ │ + 'reprojectDeprecated': "Do bruchs de Ußwahl \x3ccode\x3ereproject\x3c/code\x3e op däm Nivvoh \x3ccode\x3e${layerName}\x3c/code\x3e. Di Ußwahl es nit mieh jähn jesinn. Se wohr doför jedaach, öm Date op jeschääfsmäßesch eruß jejovve Kaate bovve drop ze moole, wat ävver enzwesche besser met dä Öngershtözung för de ßfääresche Mäkaator Beldscher jeiht. Doh kanns De mieh drövver fenge op dä Sigg: http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setLayerFilter │ │ │ │ - * addTile creates a tile, initializes it, and adds it to the layer div. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * id - {String} The id of the layer to which the filter applies. │ │ │ │ - * queryDef - {String} A sql-ish query filter, for more detail see the ESRI │ │ │ │ - * documentation at http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/export.html │ │ │ │ - */ │ │ │ │ - setLayerFilter: function(id, queryDef) { │ │ │ │ - if (!this.layerDefs) { │ │ │ │ - this.layerDefs = {}; │ │ │ │ - } │ │ │ │ - if (queryDef) { │ │ │ │ - this.layerDefs[id] = queryDef; │ │ │ │ - } else { │ │ │ │ - delete this.layerDefs[id]; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + 'methodDeprecated': "Hee di Metood es nim_mih aktoäll un et weed se en dä Version 3.0 nit mieh jävve. Nemm \x3ccode\x3e${newMethod}\x3c/code\x3e doföör." │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: clearLayerFilter │ │ │ │ - * Clears layer filters, either from a specific layer, │ │ │ │ - * or all of them. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * id - {String} The id of the layer from which to remove any │ │ │ │ - * filter. If unspecified/blank, all filters │ │ │ │ - * will be removed. │ │ │ │ - */ │ │ │ │ - clearLayerFilter: function(id) { │ │ │ │ - if (id) { │ │ │ │ - delete this.layerDefs[id]; │ │ │ │ - } else { │ │ │ │ - delete this.layerDefs; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/es.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["es"] │ │ │ │ + * Dictionary for Spanish, UTF8 encoding. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang.es = { │ │ │ │ + │ │ │ │ + 'unhandledRequest': "Respuesta a petición no gestionada ${statusText}", │ │ │ │ + │ │ │ │ + 'Permalink': "Enlace permanente", │ │ │ │ + │ │ │ │ + 'Overlays': "Capas superpuestas", │ │ │ │ + │ │ │ │ + 'Base Layer': "Capa Base", │ │ │ │ + │ │ │ │ + 'noFID': "No se puede actualizar un elemento para el que no existe FID.", │ │ │ │ + │ │ │ │ + 'browserNotSupported': "Su navegador no soporta renderización vectorial. Los renderizadores soportados actualmente son:\n${renderers}", │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'minZoomLevelError': "La propiedad minZoomLevel debe sólo utilizarse " + │ │ │ │ + "con las capas que tienen FixedZoomLevels. El hecho de que " + │ │ │ │ + "una capa wfs compruebe minZoomLevel es una reliquia del " + │ │ │ │ + "pasado. Sin embargo, no podemos eliminarla sin discontinuar " + │ │ │ │ + "probablemente las aplicaciones OL que puedan depender de ello. " + │ │ │ │ + "Así pues estamos haciéndolo obsoleto --la comprobación " + │ │ │ │ + "minZoomLevel se eliminará en la versión 3.0. Utilice el ajuste " + │ │ │ │ + "de resolution min/max en su lugar, tal como se describe aquí: " + │ │ │ │ + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + │ │ │ │ + 'commitSuccess': "Transacción WFS: ÉXITO ${response}", │ │ │ │ + │ │ │ │ + 'commitFailed': "Transacción WFS: FALLÓ ${response}", │ │ │ │ + │ │ │ │ + 'googleWarning': "La capa Google no pudo ser cargada correctamente.<br><br>" + │ │ │ │ + "Para evitar este mensaje, seleccione una nueva Capa Base " + │ │ │ │ + "en el selector de capas en la esquina superior derecha.<br><br>" + │ │ │ │ + "Probablemente, esto se debe a que el script de la biblioteca de " + │ │ │ │ + "Google Maps no fue correctamente incluido en su página, o no " + │ │ │ │ + "contiene la clave del API correcta para su sitio.<br><br>" + │ │ │ │ + "Desarrolladores: Para ayudar a hacer funcionar esto correctamente, " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ + "target='_blank'>haga clic aquí</a>", │ │ │ │ + │ │ │ │ + 'getLayerWarning': "La capa ${layerType} no pudo ser cargada correctamente.<br><br>" + │ │ │ │ + "Para evitar este mensaje, seleccione una nueva Capa Base " + │ │ │ │ + "en el selector de capas en la esquina superior derecha.<br><br>" + │ │ │ │ + "Probablemente, esto se debe a que el script de " + │ │ │ │ + "la biblioteca ${layerLib} " + │ │ │ │ + "no fue correctamente incluido en su página.<br><br>" + │ │ │ │ + "Desarrolladores: Para ayudar a hacer funcionar esto correctamente, " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ + "target='_blank'>haga clic aquí</a>", │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Escala = 1 : ${scaleDenom}", │ │ │ │ + │ │ │ │ + //labels for the graticule control │ │ │ │ + 'W': 'O', │ │ │ │ + 'E': 'E', │ │ │ │ + 'N': 'N', │ │ │ │ + 'S': 'S', │ │ │ │ + 'Graticule': 'Retícula', │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'reprojectDeprecated': "Está usando la opción 'reproject' en la capa " + │ │ │ │ + "${layerName}. Esta opción es obsoleta: su uso fue diseñado " + │ │ │ │ + "para soportar la visualización de datos sobre mapas base comerciales, " + │ │ │ │ + "pero ahora esa funcionalidad debería conseguirse mediante el soporte " + │ │ │ │ + "de la proyección Spherical Mercator. Más información disponible en " + │ │ │ │ + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'methodDeprecated': "Este método es obsoleto y se eliminará en la versión 3.0. " + │ │ │ │ + "Por favor utilice el método ${newMethod} en su lugar.", │ │ │ │ + │ │ │ │ + // **** end **** │ │ │ │ + 'end': '' │ │ │ │ + │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/el.js │ │ │ │ + ====================================================================== */ │ │ │ │ + │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Omnipaedista │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["el"] │ │ │ │ + * Dictionary for Ελληνικά. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["el"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Κλίμακα ~ 1 : ${scaleDenom}" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.ArcGIS93Rest" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/OSM.js │ │ │ │ + OpenLayers/Lang/it.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/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * @requires OpenLayers/Layer/XYZ.js │ │ │ │ + * Namespace: OpenLayers.Lang["it"] │ │ │ │ + * Dictionary for Italian. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ +OpenLayers.Lang.it = { │ │ │ │ + │ │ │ │ + 'unhandledRequest': "Codice di ritorno della richiesta ${statusText}", │ │ │ │ + │ │ │ │ + 'Permalink': "Permalink", │ │ │ │ + │ │ │ │ + 'Overlays': "Overlays", │ │ │ │ + │ │ │ │ + 'Base Layer': "Livello base", │ │ │ │ + │ │ │ │ + 'noFID': "Impossibile aggiornare un elemento grafico che non abbia il FID.", │ │ │ │ + │ │ │ │ + 'browserNotSupported': "Il tuo browser non supporta il rendering vettoriale. I renderizzatore attualemnte supportati sono:\n${renderers}", │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'minZoomLevelError': "La proprietà minZoomLevel è da utilizzare solamente " + │ │ │ │ + "con livelli che abbiano FixedZoomLevels. Il fatto che " + │ │ │ │ + "questo livello wfs controlli la proprietà minZoomLevel è " + │ │ │ │ + "un retaggio del passato. Non possiamo comunque rimuoverla " + │ │ │ │ + "senza rompere le vecchie applicazioni che dipendono su di essa." + │ │ │ │ + "Quindi siamo costretti a deprecarla -- minZoomLevel " + │ │ │ │ + "e sarà rimossa dalla vesione 3.0. Si prega di utilizzare i " + │ │ │ │ + "settaggi di risoluzione min/max come descritto qui: " + │ │ │ │ + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + │ │ │ │ + 'commitSuccess': "Transazione WFS: SUCCESS ${response}", │ │ │ │ + │ │ │ │ + 'commitFailed': "Transazione WFS: FAILED ${response}", │ │ │ │ + │ │ │ │ + 'googleWarning': "Il livello Google non è riuscito a caricare correttamente.<br><br>" + │ │ │ │ + "Per evitare questo messaggio, seleziona un nuovo BaseLayer " + │ │ │ │ + "nel selettore di livelli nell'angolo in alto a destra.<br><br>" + │ │ │ │ + "Più precisamente, ciò accade perchè la libreria Google Maps " + │ │ │ │ + "non è stata inclusa nella pagina, oppure non contiene la " + │ │ │ │ + "corretta API key per il tuo sito.<br><br>" + │ │ │ │ + "Sviluppatori: Per aiuto su come farlo funzionare correttamente, " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ + "target='_blank'>clicca qui</a>", │ │ │ │ + │ │ │ │ + 'getLayerWarning': "Il livello ${layerType} non è riuscito a caricare correttamente.<br><br>" + │ │ │ │ + "Per evitare questo messaggio, seleziona un nuovo BaseLayer " + │ │ │ │ + "nel selettore di livelli nell'angolo in alto a destra.<br><br>" + │ │ │ │ + "Più precisamente, ciò accade perchè la libreria ${layerLib} " + │ │ │ │ + "non è stata inclusa nella pagina.<br><br>" + │ │ │ │ + "Sviluppatori: Per aiuto su come farlo funzionare correttamente, " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ + "target='_blank'>clicca qui</a>", │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Scala = 1 : ${scaleDenom}", │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'reprojectDeprecated': "Stai utilizzando l'opzione 'reproject' sul livello ${layerName}. " + │ │ │ │ + "Questa opzione è deprecata: il suo utilizzo è stato introdotto per" + │ │ │ │ + "supportare il disegno dei dati sopra mappe commerciali, ma tale " + │ │ │ │ + "funzionalità dovrebbe essere ottenuta tramite l'utilizzo della proiezione " + │ │ │ │ + "Spherical Mercator. Per maggiori informazioni consultare qui " + │ │ │ │ + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'methodDeprecated': "Questo metodo è stato deprecato e sarà rimosso dalla versione 3.0. " + │ │ │ │ + "Si prega di utilizzare il metodo ${newMethod} in alternativa.", │ │ │ │ + │ │ │ │ + 'end': '' │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/da-DK.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> │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ -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", │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["da-DK"] │ │ │ │ + * Dictionary for Danish. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang['da-DK'] = { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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' │ │ │ │ - ], │ │ │ │ + 'unhandledRequest': "En ikke håndteret forespørgsel returnerede ${statusText}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: attribution │ │ │ │ - * {String} The layer attribution. │ │ │ │ - */ │ │ │ │ - attribution: "© <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors", │ │ │ │ + 'Permalink': "Permalink", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: sphericalMercator │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - sphericalMercator: true, │ │ │ │ + 'Overlays': "Kortlag", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: wrapDateLine │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - wrapDateLine: true, │ │ │ │ + 'Base Layer': "Baggrundslag", │ │ │ │ │ │ │ │ - /** 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, │ │ │ │ + 'noFID': "Kan ikke opdateret en feature (et objekt) der ikke har et FID.", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - }, │ │ │ │ + 'browserNotSupported': "Din browser understøtter ikke vektor visning. Følgende vektor visninger understøttes:\n${renderers}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - }, │ │ │ │ + // console message │ │ │ │ + 'minZoomLevelError': "Egenskaben minZoomLevel er kun beregnet til brug " + │ │ │ │ + "med FixedZoomLevels. At dette WFS lag kontrollerer " + │ │ │ │ + "minZoomLevel egenskaben, er et levn fra en tidligere " + │ │ │ │ + "version. Vi kan desværre ikke fjerne dette uden at risikere " + │ │ │ │ + "at ødelægge eksisterende OL baserede programmer der " + │ │ │ │ + " benytter denne funktionalitet. " + │ │ │ │ + "Egenskaben bør derfor ikke anvendes, og minZoomLevel " + │ │ │ │ + "kontrollen herunder vil blive fjernet i version 3.0. " + │ │ │ │ + "Benyt istedet min/max opløsnings indstillingerne, som " + │ │ │ │ + "er beskrevet her: " + │ │ │ │ + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.OSM" │ │ │ │ -}); │ │ │ │ + 'commitSuccess': "WFS transaktion: LYKKEDES ${response}", │ │ │ │ + │ │ │ │ + 'commitFailed': "WFS transaktion: MISLYKKEDES ${response}", │ │ │ │ + │ │ │ │ + 'googleWarning': "Google laget kunne ikke indlæses.<br><br>" + │ │ │ │ + "For at fjerne denne besked, vælg et nyt bagrundskort i " + │ │ │ │ + "lagskifteren i øverste højre hjørne.<br><br>" + │ │ │ │ + "Fejlen skyldes formentlig at Google Maps bibliotekts " + │ │ │ │ + "scriptet ikke er inkluderet, eller ikke indeholder den " + │ │ │ │ + "korrkte API nøgle for dit site.<br><br>" + │ │ │ │ + "Udviklere: For hjælp til at få dette til at fungere, " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ + "target='_blank'>klik her</a>", │ │ │ │ + │ │ │ │ + 'getLayerWarning': "${layerType}-laget kunne ikke indlæses.<br><br>" + │ │ │ │ + "For at fjerne denne besked, vælg et nyt bagrundskort i " + │ │ │ │ + "lagskifteren i øverste højre hjørne.<br><br>" + │ │ │ │ + "Fejlen skyldes formentlig at ${layerLib} bibliotekts " + │ │ │ │ + "scriptet ikke er inkluderet.<br><br>" + │ │ │ │ + "Udviklere: For hjælp til at få dette til at fungere, " + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ + "target='_blank'>klik her</a>", │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Målforhold = 1 : ${scaleDenom}", │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'reprojectDeprecated': "Du anvender indstillingen 'reproject' på laget ${layerName}." + │ │ │ │ + "Denne indstilling bør ikke længere anvendes. Den var beregnet " + │ │ │ │ + "til at vise data ovenpå kommercielle grundkort, men den funktionalitet " + │ │ │ │ + "bør nu opnås ved at anvende Spherical Mercator understøttelsen. " + │ │ │ │ + "Mere information er tilgængelig her: " + │ │ │ │ + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + │ │ │ │ + // console message │ │ │ │ + 'methodDeprecated': "Denne funktion bør ikke længere anvendes, og vil blive fjernet i version 3.0. " + │ │ │ │ + "Anvend venligst funktionen ${newMethod} istedet." │ │ │ │ +}; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/KaMap.js │ │ │ │ + OpenLayers/Lang/br.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. */ │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Fulup │ │ │ │ + */ │ │ │ │ │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ + * Namespace: OpenLayers.Lang["br"] │ │ │ │ + * Dictionary for Brezhoneg. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ */ │ │ │ │ +OpenLayers.Lang["br"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + │ │ │ │ + 'unhandledRequest': "Distro evel reked anveret ${statusText}", │ │ │ │ + │ │ │ │ + 'Permalink': "Peurliamm", │ │ │ │ + │ │ │ │ + 'Overlays': "Gwiskadoù", │ │ │ │ + │ │ │ │ + 'Base Layer': "Gwiskad diazez", │ │ │ │ + │ │ │ │ + 'noFID': "N\'haller ket hizivaat un elfenn ma n\'eus ket a niverenn-anaout (FID) eviti.", │ │ │ │ + │ │ │ │ + 'browserNotSupported': "N\'eo ket skoret an daskor vektorel gant ho merdeer. Setu aze an daskorerioù skoret evit ar poent :\n${renderers}", │ │ │ │ + │ │ │ │ + 'minZoomLevelError': "Ne zleer implijout ar perzh minZoomLevel nemet evit gwiskadoù FixedZoomLevels-descendent. Ar fed ma wiria ar gwiskad WHS-se hag-eñ ez eus eus minZoomLevel zo un aspadenn gozh. Koulskoude n\'omp ket evit e ziverkañ kuit da derriñ arloadoù diazezet war OL a c\'hallfe bezañ stag outañ. Setu perak eo dispredet -- Lamet kuit e vo ar gwiriañ minZoomLevel a-is er stumm 3.0. Ober gant an arventennoù bihanañ/brasañ evel deskrivet amañ e plas : http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + │ │ │ │ + 'commitSuccess': "Treuzgread WFS : MAT EO ${response}", │ │ │ │ + │ │ │ │ + 'commitFailed': "Treuzgread WFS Transaction: C\'HWITET ${response}", │ │ │ │ + │ │ │ │ + 'googleWarning': "N\'eus ket bet gallet kargañ ar gwiskad Google ent reizh.\x3cbr\x3e\x3cbr\x3eEvit en em zizober eus ar c\'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c\'horn dehoù el laez.\x3cbr\x3e\x3cbr\x3eSur a-walc\'h eo peogwir n\'eo ket bet ensoc\'het levraoueg Google Maps pe neuze ne glot ket an alc\'hwez API gant ho lec\'hienn.\x3cbr\x3e\x3cbr\x3eDiorroerien : Evit reizhañ an dra-se, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclick here\x3c/a\x3e", │ │ │ │ + │ │ │ │ + 'getLayerWarning': "N\'haller ket kargañ ar gwiskad ${layerType} ent reizh.\x3cbr\x3e\x3cbr\x3eEvit en em zizober eus ar c\'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c\'horn dehoù el laez.\x3cbr\x3e\x3cbr\x3eSur a-walc\'h eo peogwir n\'eo ket bet ensoc\'het mat al levraoueg ${layerLib}.\x3cbr\x3e\x3cbr\x3eDiorroerien : Evit gouzout penaos reizhañ an dra-se, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclick here\x3c/a\x3e", │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Skeul = 1 : ${scaleDenom}", │ │ │ │ + │ │ │ │ + 'W': "K", │ │ │ │ + │ │ │ │ + 'E': "R", │ │ │ │ + │ │ │ │ + 'N': "N", │ │ │ │ + │ │ │ │ + 'S': "S", │ │ │ │ + │ │ │ │ + 'reprojectDeprecated': "Emaoc\'h oc\'h implijout an dibarzh \'reproject\' war ar gwiskad ${layerName}. Dispredet eo an dibarzh-mañ : bet eo hag e talveze da ziskwel roadennoù war-c\'horre kartennoù diazez kenwerzhel, un dra hag a c\'haller ober bremañ gant an arc\'hwel dre skor banndres boullek Mercator. Muioc\'h a ditouroù a c\'haller da gaout war http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + │ │ │ │ + 'methodDeprecated': "Dispredet eo an daore-se ha tennet e vo kuit eus ar stumm 3.0. Grit gant ${newMethod} e plas." │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/zh-CN.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.KaMap │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.KaMap = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} KaMap Layer is always a base layer │ │ │ │ - */ │ │ │ │ - isBaseLayer: true, │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["zh-CN"] │ │ │ │ + * Dictionary for Simplified Chinese. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["zh-CN"] = { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: DEFAULT_PARAMS │ │ │ │ - * {Object} parameters set by default. The default parameters set │ │ │ │ - * the format via the 'i' parameter to 'jpeg'. │ │ │ │ - */ │ │ │ │ - DEFAULT_PARAMS: { │ │ │ │ - i: 'jpeg', │ │ │ │ - map: '' │ │ │ │ - }, │ │ │ │ + 'unhandledRequest': "未处理的请求,返回值为 ${statusText}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.KaMap │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * url - {String} │ │ │ │ - * params - {Object} Parameters to be sent to the HTTP server in the │ │ │ │ - * query string for the tile. The format can be set via the 'i' │ │ │ │ - * parameter (defaults to jpg) , and the map should be set via │ │ │ │ - * the 'map' parameter. It has been reported that ka-Map may behave │ │ │ │ - * inconsistently if your format parameter does not match the format │ │ │ │ - * parameter configured in your config.php. (See ticket #327 for more │ │ │ │ - * information.) │ │ │ │ - * options - {Object} Additional options for the layer. Any of the │ │ │ │ - * APIProperties listed on this layer, and any layer types it │ │ │ │ - * extends, can be overridden through the options parameter. │ │ │ │ - */ │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ - this.params = OpenLayers.Util.applyDefaults( │ │ │ │ - this.params, this.DEFAULT_PARAMS │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ + 'Permalink': "永久链接", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ - var scale = Math.round((this.map.getScale() * 10000)) / 10000; │ │ │ │ - var pX = Math.round(bounds.left / mapRes); │ │ │ │ - var pY = -Math.round(bounds.top / mapRes); │ │ │ │ - return this.getFullRequestString({ │ │ │ │ - t: pY, │ │ │ │ - l: pX, │ │ │ │ - s: scale │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ + 'Overlays': "叠加层", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: calculateGridLayout │ │ │ │ - * ka-Map uses the center point of the map as an origin for │ │ │ │ - * its tiles. Override calculateGridLayout to center tiles │ │ │ │ - * correctly for this case. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bound>} │ │ │ │ - * origin - {<OpenLayers.LonLat>} │ │ │ │ - * 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; │ │ │ │ + 'Base Layer': "基础图层", │ │ │ │ │ │ │ │ - var offsetlon = bounds.left; │ │ │ │ - var tilecol = Math.floor(offsetlon / tilelon) - this.buffer; │ │ │ │ + 'noFID': "无法更新feature,缺少FID。", │ │ │ │ │ │ │ │ - var offsetlat = bounds.top; │ │ │ │ - var tilerow = Math.floor(offsetlat / tilelat) + this.buffer; │ │ │ │ + 'browserNotSupported': "你使用的浏览器不支持矢量渲染。当前支持的渲染方式包括:\n${renderers}", │ │ │ │ │ │ │ │ - return { │ │ │ │ - tilelon: tilelon, │ │ │ │ - tilelat: tilelat, │ │ │ │ - startcol: tilecol, │ │ │ │ - startrow: tilerow │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ + // console message │ │ │ │ + 'minZoomLevelError': "minZoomLevel属性仅适合用于" + │ │ │ │ + "使用了固定缩放级别的图层。这个 " + │ │ │ │ + "wfs 图层检查 minZoomLevel 是过去遗留下来的。" + │ │ │ │ + "然而,我们不能移除它," + │ │ │ │ + "而破坏依赖于它的基于OL的应用程序。" + │ │ │ │ + "因此,我们废除了它 -- minZoomLevel " + │ │ │ │ + "将会在3.0中被移除。请改用 " + │ │ │ │ + "min/max resolution 设置,参考:" + │ │ │ │ + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 minX = (tileLayout.startcol + col) * tilelon; │ │ │ │ - var minY = (tileLayout.startrow - row) * tilelat; │ │ │ │ - return new OpenLayers.Bounds( │ │ │ │ - minX, minY, │ │ │ │ - minX + tilelon, minY + tilelat │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ + 'commitSuccess': "WFS Transaction: 成功。 ${response}", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * obj - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.Kamap>} An exact clone of this OpenLayers.Layer.KaMap │ │ │ │ - */ │ │ │ │ - clone: function(obj) { │ │ │ │ + 'commitFailed': "WFS Transaction: 失败。 ${response}", │ │ │ │ │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.KaMap(this.name, │ │ │ │ - this.url, │ │ │ │ - this.params, │ │ │ │ - this.getOptions()); │ │ │ │ - } │ │ │ │ + 'googleWarning': "Google图层不能正确加载。<br><br>" + │ │ │ │ + "要消除这个信息,请在右上角的" + │ │ │ │ + "图层控制面板中选择其他的基础图层。<br><br>" + │ │ │ │ + "这种情况很可能是没有正确的包含Google地图脚本库," + │ │ │ │ + "或者是没有包含在你的站点上" + │ │ │ │ + "使用的正确的Google Maps API密匙。<br><br>" + │ │ │ │ + "开发者:获取使其正确工作的帮助信息," + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ + "target='_blank'>点击这里</a>", │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + 'getLayerWarning': "${layerType} 图层不能正确加载。<br><br>" + │ │ │ │ + "要消除这个信息,请在右上角的" + │ │ │ │ + "图层控制面板中选择其他的基础图层。<br><br>" + │ │ │ │ + "这种情况很可能是没有正确的包含" + │ │ │ │ + "${layerLib} 脚本库。<br><br>" + │ │ │ │ + "开发者:获取使其正确工作的帮助信息," + │ │ │ │ + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ + "target='_blank'>点击这里</a>", │ │ │ │ │ │ │ │ - // copy/set any non-init, non-simple values here │ │ │ │ - if (this.tileSize != null) { │ │ │ │ - obj.tileSize = this.tileSize.clone(); │ │ │ │ - } │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "比例尺 = 1 : ${scaleDenom}", │ │ │ │ │ │ │ │ - // we do not want to copy reference to grid, so we make a new array │ │ │ │ - obj.grid = []; │ │ │ │ + // console message │ │ │ │ + 'reprojectDeprecated': "你正在使用 ${layerName} 图层上的'reproject'选项。" + │ │ │ │ + "这个选项已经不再使用:" + │ │ │ │ + "它是被设计用来支持显示商业的地图数据," + │ │ │ │ + "不过现在该功能可以通过使用Spherical Mercator来实现。" + │ │ │ │ + "更多信息可以参阅" + │ │ │ │ + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ │ │ │ │ - return obj; │ │ │ │ - }, │ │ │ │ + // console message │ │ │ │ + 'methodDeprecated': "该方法已经不再被支持,并且将在3.0中被移除。" + │ │ │ │ + "请使用 ${newMethod} 方法来替代。", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 resolution = this.getResolution(); │ │ │ │ - var tileMapWidth = resolution * this.tileSize.w; │ │ │ │ - var tileMapHeight = resolution * this.tileSize.h; │ │ │ │ - var mapPoint = this.getLonLatFromViewPortPx(viewPortPx); │ │ │ │ - var tileLeft = tileMapWidth * Math.floor(mapPoint.lon / tileMapWidth); │ │ │ │ - var tileBottom = tileMapHeight * Math.floor(mapPoint.lat / tileMapHeight); │ │ │ │ - return new OpenLayers.Bounds(tileLeft, tileBottom, │ │ │ │ - tileLeft + tileMapWidth, │ │ │ │ - tileBottom + tileMapHeight); │ │ │ │ - }, │ │ │ │ + 'end': '' │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Lang/sk.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.KaMap" │ │ │ │ +/* Translators (2009 onwards): │ │ │ │ + * - Helix84 │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Namespace: OpenLayers.Lang["sk"] │ │ │ │ + * Dictionary for Slovenčina. Keys for entries are used in calls to │ │ │ │ + * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ + * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ + */ │ │ │ │ +OpenLayers.Lang["sk"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + │ │ │ │ + 'unhandledRequest': "Neobslúžené požiadavky vracajú ${statusText}", │ │ │ │ + │ │ │ │ + 'Permalink': "Trvalý odkaz", │ │ │ │ + │ │ │ │ + 'Overlays': "Prekrytia", │ │ │ │ + │ │ │ │ + 'Base Layer': "Základná vrstva", │ │ │ │ + │ │ │ │ + 'noFID': "Nie je možné aktualizovať vlastnosť, pre ktorú neexistuje FID.", │ │ │ │ + │ │ │ │ + 'browserNotSupported': "Váš prehliadač nepodporuje vykresľovanie vektorov. Momentálne podporované vykresľovače sú:\n${renderers}", │ │ │ │ + │ │ │ │ + 'minZoomLevelError': "Vlastnosť minZoomLevel je určený iba na použitie s vrstvami odvodenými od FixedZoomLevels. To, že táto wfs vrstva kontroluje minZoomLevel je pozostatok z minulosti. Nemôžeme ho však odstrániť, aby sme sa vyhli možnému porušeniu aplikácií založených na Open Layers, ktoré na tomto môže závisieť. Preto ho označujeme ako zavrhovaný - dolu uvedená kontrola minZoomLevel bude odstránená vo verzii 3.0. Použite prosím namiesto toho kontrolu min./max. rozlíšenia podľa tu uvedeného popisu: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + │ │ │ │ + 'commitSuccess': "Transakcia WFS: ÚSPEŠNÁ ${response}", │ │ │ │ + │ │ │ │ + 'commitFailed': "Transakcia WFS: ZLYHALA ${response}", │ │ │ │ + │ │ │ │ + 'googleWarning': "Vrstvu Google nebolo možné správne načítať.\x3cbr\x3e\x3cbr\x3eAby ste sa tejto správy zbavili vyberte novú BaseLayer v prepínači vrstiev v pravom hornom rohu.\x3cbr\x3e\x3cbr\x3eToto sa stalo pravdepodobne preto, že skript knižnice Google Maps buď nebol načítaný alebo neobsahuje správny kľúč API pre vašu lokalitu.\x3cbr\x3e\x3cbr\x3eVývojári: Tu môžete získať \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3epomoc so sfunkčnením\x3c/a\x3e", │ │ │ │ + │ │ │ │ + 'getLayerWarning': "Vrstvu ${layerType} nebolo možné správne načítať.\x3cbr\x3e\x3cbr\x3eAby ste sa tejto správy zbavili vyberte novú BaseLayer v prepínači vrstiev v pravom hornom rohu.\x3cbr\x3e\x3cbr\x3eToto sa stalo pravdepodobne preto, že skript knižnice ${layerType} buď nebol načítaný alebo neobsahuje správny kľúč API pre vašu lokalitu.\x3cbr\x3e\x3cbr\x3eVývojári: Tu môžete získať \x3ca href=\'http://trac.openlayers.org/wiki/${layerType}\' target=\'_blank\'\x3epomoc so sfunkčnením\x3c/a\x3e", │ │ │ │ + │ │ │ │ + 'Scale = 1 : ${scaleDenom}': "Mierka = 1 : ${scaleDenom}", │ │ │ │ + │ │ │ │ + 'reprojectDeprecated': "Používate voľby „reproject“ vrstvy ${layerType}. Táto voľba je zzavrhovaná: jej použitie bolo navrhnuté na podporu zobrazovania údajov nad komerčnými základovými mapami, ale túto funkcionalitu je teraz možné dosiahnuť pomocou Spherical Mercator. Ďalšie informácie získate na stránke http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + │ │ │ │ + 'methodDeprecated': "Táto metóda je zavrhovaná a bude odstránená vo verzii 3.0. Použite prosím namiesto nej metódu ${newMethod}." │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/KaMapCache.js │ │ │ │ + OpenLayers/Marker/Box.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 │ │ │ │ - * @requires OpenLayers/Layer/KaMap.js │ │ │ │ + * @requires OpenLayers/Marker.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.KaMapCache │ │ │ │ - * │ │ │ │ - * This class is designed to talk directly to a web-accessible ka-Map │ │ │ │ - * cache generated by the precache2.php script. │ │ │ │ - * │ │ │ │ - * To create a a new KaMapCache layer, you must indicate also the "i" parameter │ │ │ │ - * (that will be used to calculate the file extension), and another special │ │ │ │ - * parameter, object names "metaTileSize", with "h" (height) and "w" (width) │ │ │ │ - * properties. │ │ │ │ - * │ │ │ │ - * // Create a new kaMapCache layer. │ │ │ │ - * var kamap_base = new OpenLayers.Layer.KaMapCache( │ │ │ │ - * "Satellite", │ │ │ │ - * "http://www.example.org/web/acessible/cache", │ │ │ │ - * {g: "satellite", map: "world", i: 'png24', metaTileSize: {w: 5, h: 5} } │ │ │ │ - * ); │ │ │ │ - * │ │ │ │ - * // Create an kaMapCache overlay layer (using "isBaseLayer: false"). │ │ │ │ - * // Forces the output to be a "gif", using the "i" parameter. │ │ │ │ - * var kamap_overlay = new OpenLayers.Layer.KaMapCache( │ │ │ │ - * "Streets", │ │ │ │ - * "http://www.example.org/web/acessible/cache", │ │ │ │ - * {g: "streets", map: "world", i: "gif", metaTileSize: {w: 5, h: 5} }, │ │ │ │ - * {isBaseLayer: false} │ │ │ │ - * ); │ │ │ │ - * │ │ │ │ - * The cache URLs must look like: │ │ │ │ - * var/cache/World/50000/Group_Name/def/t-440320/l20480 │ │ │ │ - * │ │ │ │ - * This means that the cache generated via tile.php will *not* work with │ │ │ │ - * this class, and should instead use the KaMap layer. │ │ │ │ + * Class: OpenLayers.Marker.Box │ │ │ │ * │ │ │ │ - * More information is available in Ticket #1518. │ │ │ │ - * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.KaMap> │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * - <OpenLayers.Marker> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.KaMapCache = OpenLayers.Class(OpenLayers.Layer.KaMap, { │ │ │ │ +OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: IMAGE_EXTENSIONS │ │ │ │ - * {Object} Simple hash map to convert format to extension. │ │ │ │ + /** │ │ │ │ + * Property: bounds │ │ │ │ + * {<OpenLayers.Bounds>} │ │ │ │ */ │ │ │ │ - IMAGE_EXTENSIONS: { │ │ │ │ - 'jpeg': 'jpg', │ │ │ │ - 'gif': 'gif', │ │ │ │ - 'png': 'png', │ │ │ │ - 'png8': 'png', │ │ │ │ - 'png24': 'png', │ │ │ │ - 'dithered': 'png' │ │ │ │ + bounds: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: div │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + div: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Marker.Box │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * borderColor - {String} │ │ │ │ + * borderWidth - {int} │ │ │ │ + */ │ │ │ │ + initialize: function(bounds, borderColor, borderWidth) { │ │ │ │ + this.bounds = bounds; │ │ │ │ + this.div = OpenLayers.Util.createDiv(); │ │ │ │ + this.div.style.overflow = 'hidden'; │ │ │ │ + this.events = new OpenLayers.Events(this, this.div); │ │ │ │ + this.setBorder(borderColor, borderWidth); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: DEFAULT_FORMAT │ │ │ │ - * {Object} Simple hash map to convert format to extension. │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - DEFAULT_FORMAT: 'jpeg', │ │ │ │ + destroy: function() { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Layer.KaMapCache │ │ │ │ + this.bounds = null; │ │ │ │ + this.div = null; │ │ │ │ + │ │ │ │ + OpenLayers.Marker.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setBorder │ │ │ │ + * Allow the user to change the box's color and border width │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * url - {String} │ │ │ │ - * params - {Object} Parameters to be sent to the HTTP server in the │ │ │ │ - * query string for the tile. The format can be set via the 'i' │ │ │ │ - * parameter (defaults to jpg) , and the map should be set via │ │ │ │ - * the 'map' parameter. It has been reported that ka-Map may behave │ │ │ │ - * inconsistently if your format parameter does not match the format │ │ │ │ - * parameter configured in your config.php. (See ticket #327 for more │ │ │ │ - * information.) │ │ │ │ - * options - {Object} Additional options for the layer. Any of the │ │ │ │ - * APIProperties listed on this layer, and any layer types it │ │ │ │ - * extends, can be overridden through the options parameter. │ │ │ │ + * color - {String} Default is "red" │ │ │ │ + * width - {int} Default is 2 │ │ │ │ */ │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - OpenLayers.Layer.KaMap.prototype.initialize.apply(this, arguments); │ │ │ │ - this.extension = this.IMAGE_EXTENSIONS[this.params.i.toLowerCase() || this.DEFAULT_FORMAT]; │ │ │ │ + setBorder: function(color, width) { │ │ │ │ + if (!color) { │ │ │ │ + color = "red"; │ │ │ │ + } │ │ │ │ + if (!width) { │ │ │ │ + width = 2; │ │ │ │ + } │ │ │ │ + this.div.style.border = width + "px solid " + color; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getURL │ │ │ │ + /** │ │ │ │ + * Method: draw │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * px - {<OpenLayers.Pixel>} │ │ │ │ + * sz - {<OpenLayers.Size>} │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {String} A string with the layer's url and parameters and also the │ │ │ │ - * passed-in bounds and appropriate tile size specified as │ │ │ │ - * parameters │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A new DOM Image with this marker's icon set at the │ │ │ │ + * location passed-in │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ - var scale = Math.round((this.map.getScale() * 10000)) / 10000; │ │ │ │ - var pX = Math.round(bounds.left / mapRes); │ │ │ │ - var pY = -Math.round(bounds.top / mapRes); │ │ │ │ - │ │ │ │ - var metaX = Math.floor(pX / this.tileSize.w / this.params.metaTileSize.w) * this.tileSize.w * this.params.metaTileSize.w; │ │ │ │ - var metaY = Math.floor(pY / this.tileSize.h / this.params.metaTileSize.h) * this.tileSize.h * this.params.metaTileSize.h; │ │ │ │ - │ │ │ │ - var components = [ │ │ │ │ - "/", │ │ │ │ - this.params.map, │ │ │ │ - "/", │ │ │ │ - scale, │ │ │ │ - "/", │ │ │ │ - this.params.g.replace(/\s/g, '_'), │ │ │ │ - "/def/t", │ │ │ │ - metaY, │ │ │ │ - "/l", │ │ │ │ - metaX, │ │ │ │ - "/t", │ │ │ │ - pY, │ │ │ │ - "l", │ │ │ │ - pX, │ │ │ │ - ".", │ │ │ │ - this.extension │ │ │ │ - ]; │ │ │ │ - │ │ │ │ - var url = this.url; │ │ │ │ + draw: function(px, sz) { │ │ │ │ + OpenLayers.Util.modifyDOMElement(this.div, null, px, sz); │ │ │ │ + return this.div; │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(components.join(''), url); │ │ │ │ + /** │ │ │ │ + * Method: onScreen │ │ │ │ + * │ │ │ │ + * Rreturn: │ │ │ │ + * {Boolean} Whether or not the marker is currently visible on screen. │ │ │ │ + */ │ │ │ │ + onScreen: function() { │ │ │ │ + var onScreen = false; │ │ │ │ + if (this.map) { │ │ │ │ + var screenBounds = this.map.getExtent(); │ │ │ │ + onScreen = screenBounds.containsBounds(this.bounds, true, true); │ │ │ │ } │ │ │ │ - return url + components.join(""); │ │ │ │ + return onScreen; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.KaMapCache" │ │ │ │ + /** │ │ │ │ + * Method: display │ │ │ │ + * Hide or show the icon │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * display - {Boolean} │ │ │ │ + */ │ │ │ │ + display: function(display) { │ │ │ │ + this.div.style.display = (display) ? "" : "none"; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Marker.Box" │ │ │ │ }); │ │ │ │ + │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Layer/Image.js │ │ │ │ + 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/Layer.js │ │ │ │ - * @requires OpenLayers/Tile/Image.js │ │ │ │ + * @requires OpenLayers/Renderer.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.Image │ │ │ │ - * Instances of OpenLayers.Layer.Image are used to display data from a web │ │ │ │ - * accessible image as a map layer. Create a new image layer with the │ │ │ │ - * <OpenLayers.Layer.Image> constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer> │ │ │ │ + * Class: OpenLayers.Renderer.Canvas │ │ │ │ + * A renderer based on the 2D 'canvas' drawing element. │ │ │ │ + * │ │ │ │ + * Inherits: │ │ │ │ + * - <OpenLayers.Renderer> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.Image = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ +OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: isBaseLayer │ │ │ │ - * {Boolean} The layer is a base layer. Default is true. Set this property │ │ │ │ - * in the layer options │ │ │ │ + * APIProperty: hitDetection │ │ │ │ + * {Boolean} Allow for hit detection of features. Default is true. │ │ │ │ */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + hitDetection: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: url │ │ │ │ - * {String} URL of the image to use │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - url: null, │ │ │ │ + hitOverflow: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: extent │ │ │ │ - * {<OpenLayers.Bounds>} The image bounds in map units. This extent will │ │ │ │ - * also be used as the default maxExtent for the layer. If you wish │ │ │ │ - * to have a maxExtent that is different than the image extent, set the │ │ │ │ - * maxExtent property of the options argument (as with any other layer). │ │ │ │ + * Property: canvas │ │ │ │ + * {Canvas} The canvas context object. │ │ │ │ */ │ │ │ │ - extent: null, │ │ │ │ + canvas: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: size │ │ │ │ - * {<OpenLayers.Size>} The image size in pixels │ │ │ │ + * Property: features │ │ │ │ + * {Object} Internal object of feature/style pairs for use in redrawing the layer. │ │ │ │ */ │ │ │ │ - size: null, │ │ │ │ + features: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: tile │ │ │ │ - * {<OpenLayers.Tile.Image>} │ │ │ │ + * Property: pendingRedraw │ │ │ │ + * {Boolean} The renderer needs a redraw call to render features added while │ │ │ │ + * the renderer was locked. │ │ │ │ */ │ │ │ │ - tile: null, │ │ │ │ + pendingRedraw: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: aspectRatio │ │ │ │ - * {Float} The ratio of height/width represented by a single pixel in the │ │ │ │ - * graphic │ │ │ │ + * Property: cachedSymbolBounds │ │ │ │ + * {Object} Internal cache of calculated symbol extents. │ │ │ │ */ │ │ │ │ - aspectRatio: null, │ │ │ │ + cachedSymbolBounds: {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.Image │ │ │ │ - * Create a new image layer │ │ │ │ + * Constructor: OpenLayers.Renderer.Canvas │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} A name for the layer. │ │ │ │ - * url - {String} Relative or absolute path to the image │ │ │ │ - * extent - {<OpenLayers.Bounds>} The extent represented by the image │ │ │ │ - * size - {<OpenLayers.Size>} The size (in pixels) of the image │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ - */ │ │ │ │ - initialize: function(name, url, extent, size, options) { │ │ │ │ - this.url = url; │ │ │ │ - this.extent = extent; │ │ │ │ - this.maxExtent = extent; │ │ │ │ - this.size = size; │ │ │ │ - OpenLayers.Layer.prototype.initialize.apply(this, [name, options]); │ │ │ │ - │ │ │ │ - this.aspectRatio = (this.extent.getHeight() / this.size.h) / │ │ │ │ - (this.extent.getWidth() / this.size.w); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - * Destroy this layer │ │ │ │ + * containerID - {<String>} │ │ │ │ + * options - {Object} Optional properties to be set on the renderer. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.tile) { │ │ │ │ - this.removeTileMonitoringHooks(this.tile); │ │ │ │ - this.tile.destroy(); │ │ │ │ - this.tile = null; │ │ │ │ + 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"); │ │ │ │ } │ │ │ │ - OpenLayers.Layer.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ + * Method: setExtent │ │ │ │ + * Set the visible part of the layer. │ │ │ │ * │ │ │ │ - * Paramters: │ │ │ │ - * obj - {Object} An optional layer (is this ever used?) │ │ │ │ + * Parameters: │ │ │ │ + * extent - {<OpenLayers.Bounds>} │ │ │ │ + * resolutionChanged - {Boolean} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Layer.Image>} An exact copy of this layer │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.Image(this.name, │ │ │ │ - this.url, │ │ │ │ - this.extent, │ │ │ │ - this.size, │ │ │ │ - this.getOptions()); │ │ │ │ - } │ │ │ │ - │ │ │ │ - //get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]); │ │ │ │ - │ │ │ │ - // copy/set any non-init, non-simple values here │ │ │ │ + setExtent: function() { │ │ │ │ + OpenLayers.Renderer.prototype.setExtent.apply(this, arguments); │ │ │ │ + // always redraw features │ │ │ │ + return false; │ │ │ │ + }, │ │ │ │ │ │ │ │ - return obj; │ │ │ │ + /** │ │ │ │ + * 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: setMap │ │ │ │ + * 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: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * size - {<OpenLayers.Size>} │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - /** │ │ │ │ - * If nothing to do with resolutions has been set, assume a single │ │ │ │ - * resolution determined by ratio*extent/size - if an image has a │ │ │ │ - * pixel aspect ratio different than one (as calculated above), the │ │ │ │ - * image will be stretched in one dimension only. │ │ │ │ - */ │ │ │ │ - if (this.options.maxResolution == null) { │ │ │ │ - this.options.maxResolution = this.aspectRatio * │ │ │ │ - this.extent.getWidth() / │ │ │ │ - this.size.w; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - OpenLayers.Layer.prototype.setMap.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: moveTo │ │ │ │ - * Create the tile for the image or resize it for the new resolution │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: drawFeature │ │ │ │ + * Draw the feature. Stores the feature in the features list, │ │ │ │ + * then redraws the layer. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - * zoomChanged - {Boolean} │ │ │ │ - * dragging - {Boolean} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ - │ │ │ │ - var firstRendering = (this.tile == null); │ │ │ │ - │ │ │ │ - if (zoomChanged || firstRendering) { │ │ │ │ + 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(); │ │ │ │ │ │ │ │ - //determine new tile size │ │ │ │ - this.setTileSize(); │ │ │ │ + var worldBounds; │ │ │ │ + if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) { │ │ │ │ + worldBounds = this.map.getMaxExtent(); │ │ │ │ + } │ │ │ │ │ │ │ │ - //determine new position (upper left corner of new bounds) │ │ │ │ - var ulPx = this.map.getLayerPxFromLonLat({ │ │ │ │ - lon: this.extent.left, │ │ │ │ - lat: this.extent.top │ │ │ │ + var intersects = bounds && bounds.intersectsBounds(this.extent, { │ │ │ │ + worldBounds: worldBounds │ │ │ │ }); │ │ │ │ │ │ │ │ - if (firstRendering) { │ │ │ │ - //create the new tile │ │ │ │ - this.tile = new OpenLayers.Tile.Image(this, ulPx, this.extent, │ │ │ │ - null, this.tileSize); │ │ │ │ - this.addTileMonitoringHooks(this.tile); │ │ │ │ + rendered = (style.display !== "none") && !!bounds && intersects; │ │ │ │ + if (rendered) { │ │ │ │ + // keep track of what we have rendered for redraw │ │ │ │ + this.features[feature.id] = [feature, style]; │ │ │ │ } else { │ │ │ │ - //just resize the tile and set it's new position │ │ │ │ - this.tile.size = this.tileSize.clone(); │ │ │ │ - this.tile.position = ulPx.clone(); │ │ │ │ + // remove from features tracked for redraw │ │ │ │ + delete(this.features[feature.id]); │ │ │ │ } │ │ │ │ - this.tile.draw(); │ │ │ │ + this.pendingRedraw = true; │ │ │ │ + } │ │ │ │ + if (this.pendingRedraw && !this.locked) { │ │ │ │ + this.redraw(); │ │ │ │ + this.pendingRedraw = false; │ │ │ │ } │ │ │ │ + return rendered; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Set the tile size based on the map size. │ │ │ │ + /** │ │ │ │ + * Method: drawGeometry │ │ │ │ + * Used when looping (in redraw) over the features; draws │ │ │ │ + * the canvas. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ */ │ │ │ │ - setTileSize: function() { │ │ │ │ - var tileWidth = this.extent.getWidth() / this.map.getResolution(); │ │ │ │ - var tileHeight = this.extent.getHeight() / this.map.getResolution(); │ │ │ │ - this.tileSize = new OpenLayers.Size(tileWidth, tileHeight); │ │ │ │ + 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: 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. │ │ │ │ + /** │ │ │ │ + * Method: drawExternalGraphic │ │ │ │ + * Called to draw External graphics. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * tile - {<OpenLayers.Tile>} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - addTileMonitoringHooks: function(tile) { │ │ │ │ - tile.onLoadStart = function() { │ │ │ │ - this.events.triggerEvent("loadstart"); │ │ │ │ - }; │ │ │ │ - tile.events.register("loadstart", this, tile.onLoadStart); │ │ │ │ + drawExternalGraphic: function(geometry, style, featureId) { │ │ │ │ + var img = new Image(); │ │ │ │ │ │ │ │ - tile.onLoadEnd = function() { │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ }; │ │ │ │ - tile.events.register("loadend", this, tile.onLoadEnd); │ │ │ │ - tile.events.register("unload", this, tile.onLoadEnd); │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ + img.onload = OpenLayers.Function.bind(onLoad, this); │ │ │ │ + img.src = style.externalGraphic; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setUrl │ │ │ │ + * Method: drawNamedSymbol │ │ │ │ + * Called to draw Well Known Graphic Symbol Name. │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * newUrl - {String} │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - setUrl: function(newUrl) { │ │ │ │ - this.url = newUrl; │ │ │ │ - this.tile.draw(); │ │ │ │ - }, │ │ │ │ + drawNamedSymbol: function(geometry, style, featureId) { │ │ │ │ + var x, y, cx, cy, i, symbolBounds, scaling, angle; │ │ │ │ + var unscaledStrokeWidth; │ │ │ │ + var deg2rad = Math.PI / 180.0; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getURL │ │ │ │ - * The url we return is always the same (the image itself never changes) │ │ │ │ - * so we can ignore the bounds parameter (it will always be the same, │ │ │ │ - * anyways) │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - return this.url; │ │ │ │ - }, │ │ │ │ + var symbol = OpenLayers.Renderer.symbol[style.graphicName]; │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Image" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Layer/WMTS.js │ │ │ │ - ====================================================================== */ │ │ │ │ + if (!symbol) { │ │ │ │ + throw new Error(style.graphicName + ' is not a valid symbol name'); │ │ │ │ + } │ │ │ │ │ │ │ │ -/* 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. */ │ │ │ │ + if (!symbol.length || symbol.length < 2) return; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ - */ │ │ │ │ + var pt = this.getLocalXY(geometry); │ │ │ │ + var p0 = pt[0]; │ │ │ │ + var p1 = pt[1]; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Layer.WMTS │ │ │ │ - * Instances of the WMTS class allow viewing of tiles from a service that │ │ │ │ - * implements the OGC WMTS specification version 1.0.0. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ - */ │ │ │ │ -OpenLayers.Layer.WMTS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + if (isNaN(p0) || isNaN(p1)) return; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} The layer will be considered a base layer. Default is true. │ │ │ │ - */ │ │ │ │ - isBaseLayer: true, │ │ │ │ + // Use rounded line caps │ │ │ │ + this.canvas.lineCap = "round"; │ │ │ │ + this.canvas.lineJoin = "round"; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} WMTS version. Default is "1.0.0". │ │ │ │ - */ │ │ │ │ - version: "1.0.0", │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.lineCap = "round"; │ │ │ │ + this.hitContext.lineJoin = "round"; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: requestEncoding │ │ │ │ - * {String} Request encoding. Can be "REST" or "KVP". Default is "KVP". │ │ │ │ - */ │ │ │ │ - requestEncoding: "KVP", │ │ │ │ + // 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; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: url │ │ │ │ - * {String|Array(String)} The base URL or request URL template for the WMTS │ │ │ │ - * service. Must be provided. Array is only supported for base URLs, not │ │ │ │ - * for request URL templates. URL templates are only supported for │ │ │ │ - * REST <requestEncoding>. │ │ │ │ - */ │ │ │ │ - url: null, │ │ │ │ + // 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(); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: layer │ │ │ │ - * {String} The layer identifier advertised by the WMTS service. Must be │ │ │ │ - * provided. │ │ │ │ - */ │ │ │ │ - layer: null, │ │ │ │ + // Step 3: place symbol at the desired location │ │ │ │ + this.canvas.translate(p0, p1); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.translate(p0, p1); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: matrixSet │ │ │ │ - * {String} One of the advertised matrix set identifiers. Must be provided. │ │ │ │ - */ │ │ │ │ - matrixSet: null, │ │ │ │ + // 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: style │ │ │ │ - * {String} One of the advertised layer styles. Must be provided. │ │ │ │ - */ │ │ │ │ - style: null, │ │ │ │ + // // 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); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: format │ │ │ │ - * {String} The image MIME type. Default is "image/jpeg". │ │ │ │ - */ │ │ │ │ - format: "image/jpeg", │ │ │ │ + // 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); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: tileOrigin │ │ │ │ - * {<OpenLayers.LonLat>} The top-left corner of the tile matrix in map │ │ │ │ - * units. If the tile origin for each matrix in a set is different, │ │ │ │ - * the <matrixIds> should include a topLeftCorner property. If │ │ │ │ - * not provided, the tile origin will default to the top left corner │ │ │ │ - * of the layer <maxExtent>. │ │ │ │ - */ │ │ │ │ - tileOrigin: null, │ │ │ │ + // 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; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: tileFullExtent │ │ │ │ - * {<OpenLayers.Bounds>} The full extent of the tile set. If not supplied, │ │ │ │ - * the layer's <maxExtent> property will be used. │ │ │ │ - */ │ │ │ │ - tileFullExtent: null, │ │ │ │ + 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(); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: formatSuffix │ │ │ │ - * {String} For REST request encoding, an image format suffix must be │ │ │ │ - * included in the request. If not provided, the suffix will be derived │ │ │ │ - * from the <format> property. │ │ │ │ - */ │ │ │ │ - formatSuffix: null, │ │ │ │ + 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(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: matrixIds │ │ │ │ - * {Array} A list of tile matrix identifiers. If not provided, the matrix │ │ │ │ - * identifiers will be assumed to be integers corresponding to the │ │ │ │ - * map zoom level. If a list of strings is provided, each item should │ │ │ │ - * be the matrix identifier that corresponds to the map zoom level. │ │ │ │ - * Additionally, a list of objects can be provided. Each object should │ │ │ │ - * describe the matrix as presented in the WMTS capabilities. These │ │ │ │ - * objects should have the propertes shown below. │ │ │ │ - * │ │ │ │ - * Matrix properties: │ │ │ │ - * identifier - {String} The matrix identifier (required). │ │ │ │ - * scaleDenominator - {Number} The matrix scale denominator. │ │ │ │ - * topLeftCorner - {<OpenLayers.LonLat>} The top left corner of the │ │ │ │ - * matrix. Must be provided if different than the layer <tileOrigin>. │ │ │ │ - * tileWidth - {Number} The tile width for the matrix. Must be provided │ │ │ │ - * if different than the width given in the layer <tileSize>. │ │ │ │ - * tileHeight - {Number} The tile height for the matrix. Must be provided │ │ │ │ - * if different than the height given in the layer <tileSize>. │ │ │ │ - */ │ │ │ │ - matrixIds: null, │ │ │ │ + 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(); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: dimensions │ │ │ │ - * {Array} For RESTful request encoding, extra dimensions may be specified. │ │ │ │ - * Items in this list should be property names in the <params> object. │ │ │ │ - * Values of extra dimensions will be determined from the corresponding │ │ │ │ - * values in the <params> object. │ │ │ │ - */ │ │ │ │ - dimensions: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: params │ │ │ │ - * {Object} Extra parameters to include in tile requests. For KVP │ │ │ │ - * <requestEncoding>, these properties will be encoded in the request │ │ │ │ - * query string. For REST <requestEncoding>, these properties will │ │ │ │ - * become part of the request path, with order determined by the │ │ │ │ - * <dimensions> list. │ │ │ │ - */ │ │ │ │ - params: null, │ │ │ │ + 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(); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: zoomOffset │ │ │ │ - * {Number} If your cache has more 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). Additionally, if this layer is to be used │ │ │ │ - * as an overlay and the cache has fewer zoom levels than the base │ │ │ │ - * layer, you can supply a negative zoomOffset. For example, if a │ │ │ │ - * map zoom level of 1 corresponds to your cache level zero, you would │ │ │ │ - * supply a -1 zoomOffset (and set the maxResolution of the layer │ │ │ │ - * appropriately). The zoomOffset value has no effect if complete │ │ │ │ - * matrix definitions (including scaleDenominator) are supplied in │ │ │ │ - * the <matrixIds> property. Defaults to 0 (no zoom offset). │ │ │ │ - */ │ │ │ │ - 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, │ │ │ │ + style.strokeWidth = unscaledStrokeWidth; │ │ │ │ + this.canvas.restore(); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.restore(); │ │ │ │ + } │ │ │ │ + this.setCanvasStyle("reset"); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: formatSuffixMap │ │ │ │ - * {Object} a map between WMTS 'format' request parameter and tile image file suffix │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - formatSuffixMap: { │ │ │ │ - "image/png": "png", │ │ │ │ - "image/png8": "png", │ │ │ │ - "image/png24": "png", │ │ │ │ - "image/png32": "png", │ │ │ │ - "png": "png", │ │ │ │ - "image/jpeg": "jpg", │ │ │ │ - "image/jpg": "jpg", │ │ │ │ - "jpeg": "jpg", │ │ │ │ - "jpg": "jpg" │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: matrix │ │ │ │ - * {Object} Matrix definition for the current map resolution. Updated by │ │ │ │ - * the <updateMatrixProperties> method. │ │ │ │ + * Method: featureIdToHex │ │ │ │ + * Convert a feature ID string into an RGB hex string. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * featureId - {String} Feature id │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} RGB hex string. │ │ │ │ */ │ │ │ │ - matrix: null, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.WMTS │ │ │ │ - * Create a new WMTS layer. │ │ │ │ - * │ │ │ │ - * Example: │ │ │ │ - * (code) │ │ │ │ - * var wmts = new OpenLayers.Layer.WMTS({ │ │ │ │ - * name: "My WMTS Layer", │ │ │ │ - * url: "http://example.com/wmts", │ │ │ │ - * layer: "layer_id", │ │ │ │ - * style: "default", │ │ │ │ - * matrixSet: "matrix_id" │ │ │ │ - * }); │ │ │ │ - * (end) │ │ │ │ + * Method: setHitContextStyle │ │ │ │ + * Prepare the hit canvas for drawing by setting various global settings. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * config - {Object} Configuration properties for the layer. │ │ │ │ - * │ │ │ │ - * Required configuration properties: │ │ │ │ - * url - {String} The base url for the service. See the <url> property. │ │ │ │ - * layer - {String} The layer identifier. See the <layer> property. │ │ │ │ - * style - {String} The layer style identifier. See the <style> property. │ │ │ │ - * matrixSet - {String} The tile matrix set identifier. See the <matrixSet> │ │ │ │ - * property. │ │ │ │ - * │ │ │ │ - * Any other documented layer properties can be provided in the config object. │ │ │ │ + * type - {String} one of 'stroke', 'fill', or 'reset' │ │ │ │ + * featureId - {String} The feature id. │ │ │ │ + * symbolizer - {<OpenLayers.Symbolizer>} The symbolizer. │ │ │ │ */ │ │ │ │ - initialize: function(config) { │ │ │ │ - │ │ │ │ - // confirm required properties are supplied │ │ │ │ - var required = { │ │ │ │ - url: true, │ │ │ │ - layer: true, │ │ │ │ - style: true, │ │ │ │ - matrixSet: true │ │ │ │ - }; │ │ │ │ - for (var prop in required) { │ │ │ │ - if (!(prop in config)) { │ │ │ │ - throw new Error("Missing property '" + prop + "' in layer configuration."); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - config.params = OpenLayers.Util.upperCaseObject(config.params); │ │ │ │ - var args = [config.name, config.url, config.params, config]; │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, args); │ │ │ │ - │ │ │ │ - │ │ │ │ - // determine format suffix (for REST) │ │ │ │ - if (!this.formatSuffix) { │ │ │ │ - this.formatSuffix = this.formatSuffixMap[this.format] || this.format.split("/").pop(); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - // expand matrixIds (may be array of string or array of object) │ │ │ │ - if (this.matrixIds) { │ │ │ │ - var len = this.matrixIds.length; │ │ │ │ - if (len && typeof this.matrixIds[0] === "string") { │ │ │ │ - var ids = this.matrixIds; │ │ │ │ - this.matrixIds = new Array(len); │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ - this.matrixIds[i] = { │ │ │ │ - identifier: ids[i] │ │ │ │ - }; │ │ │ │ + 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: setMap │ │ │ │ + * Method: drawLineString │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - setMap: function() { │ │ │ │ - OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); │ │ │ │ + drawLineString: function(geometry, style, featureId) { │ │ │ │ + style = OpenLayers.Util.applyDefaults({ │ │ │ │ + fill: false │ │ │ │ + }, style); │ │ │ │ + this.drawLinearRing(geometry, style, featureId); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: updateMatrixProperties │ │ │ │ - * Called when map resolution changes to update matrix related properties. │ │ │ │ + * Method: drawLinearRing │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - updateMatrixProperties: function() { │ │ │ │ - this.matrix = this.getMatrix(); │ │ │ │ - if (this.matrix) { │ │ │ │ - if (this.matrix.topLeftCorner) { │ │ │ │ - this.tileOrigin = this.matrix.topLeftCorner; │ │ │ │ - } │ │ │ │ - if (this.matrix.tileWidth && this.matrix.tileHeight) { │ │ │ │ - this.tileSize = new OpenLayers.Size( │ │ │ │ - this.matrix.tileWidth, this.matrix.tileHeight │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (!this.tileOrigin) { │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat( │ │ │ │ - this.maxExtent.left, this.maxExtent.top │ │ │ │ - ); │ │ │ │ + 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 (!this.tileFullExtent) { │ │ │ │ - this.tileFullExtent = this.maxExtent; │ │ │ │ + } │ │ │ │ + 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: 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} │ │ │ │ + * Method: renderPath │ │ │ │ + * Render a path with stroke and optional fill. │ │ │ │ */ │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - if (zoomChanged || !this.matrix) { │ │ │ │ - this.updateMatrixProperties(); │ │ │ │ + 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(); │ │ │ │ + } │ │ │ │ } │ │ │ │ - return OpenLayers.Layer.Grid.prototype.moveTo.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: clone │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * obj - {Object} │ │ │ │ + * Method: drawPolygon │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.WMTS>} An exact clone of this <OpenLayers.Layer.WMTS> │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * featureId - {String} │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.WMTS(this.options); │ │ │ │ + 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 │ │ │ │ + ); │ │ │ │ } │ │ │ │ - //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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getIdentifier │ │ │ │ - * Get the current index in the matrixIds array. │ │ │ │ + * Method: drawText │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * location - {<OpenLayers.Point>} │ │ │ │ + * style - {Object} │ │ │ │ */ │ │ │ │ - getIdentifier: function() { │ │ │ │ - return this.getServerZoom(); │ │ │ │ - }, │ │ │ │ + drawText: function(location, style) { │ │ │ │ + var pt = this.getLocalXY(location); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getMatrix │ │ │ │ - * Get the appropriate matrix definition for the current map resolution. │ │ │ │ - */ │ │ │ │ - getMatrix: function() { │ │ │ │ - var matrix; │ │ │ │ - if (!this.matrixIds || this.matrixIds.length === 0) { │ │ │ │ - matrix = { │ │ │ │ - identifier: this.getIdentifier() │ │ │ │ - }; │ │ │ │ - } else { │ │ │ │ - // get appropriate matrix given the map scale if possible │ │ │ │ - if ("scaleDenominator" in this.matrixIds[0]) { │ │ │ │ - // scale denominator calculation based on WMTS spec │ │ │ │ - var denom = │ │ │ │ - OpenLayers.METERS_PER_INCH * │ │ │ │ - OpenLayers.INCHES_PER_UNIT[this.units] * │ │ │ │ - this.getServerResolution() / 0.28E-3; │ │ │ │ - var diff = Number.POSITIVE_INFINITY; │ │ │ │ - var delta; │ │ │ │ - for (var i = 0, ii = this.matrixIds.length; i < ii; ++i) { │ │ │ │ - delta = Math.abs(1 - (this.matrixIds[i].scaleDenominator / denom)); │ │ │ │ - if (delta < diff) { │ │ │ │ - diff = delta; │ │ │ │ - matrix = this.matrixIds[i]; │ │ │ │ - } │ │ │ │ + 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(); │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - // fall back on zoom as index │ │ │ │ - matrix = this.matrixIds[this.getIdentifier()]; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ } │ │ │ │ - return matrix; │ │ │ │ + this.setCanvasStyle("reset"); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getTileInfo │ │ │ │ - * Get tile information for a given location at the current map resolution. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * loc - {<OpenLayers.LonLat} A location in map coordinates. │ │ │ │ + /** │ │ │ │ + * Method: getLocalXY │ │ │ │ + * transform geographic xy into pixel xy │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An object with "col", "row", "i", and "j" properties. The col │ │ │ │ - * and row values are zero based tile indexes from the top left. The │ │ │ │ - * i and j values are the number of pixels to the left and top │ │ │ │ - * (respectively) of the given location within the target tile. │ │ │ │ + * Parameters: │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} │ │ │ │ */ │ │ │ │ - getTileInfo: function(loc) { │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - │ │ │ │ - var fx = (loc.lon - this.tileOrigin.lon) / (res * this.tileSize.w); │ │ │ │ - var fy = (this.tileOrigin.lat - loc.lat) / (res * this.tileSize.h); │ │ │ │ - │ │ │ │ - var col = Math.floor(fx); │ │ │ │ - var row = Math.floor(fy); │ │ │ │ + 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]; │ │ │ │ + }, │ │ │ │ │ │ │ │ - return { │ │ │ │ - col: col, │ │ │ │ - row: row, │ │ │ │ - i: Math.floor((fx - col) * this.tileSize.w), │ │ │ │ - j: Math.floor((fy - row) * this.tileSize.h) │ │ │ │ - }; │ │ │ │ + /** │ │ │ │ + * 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: getURL │ │ │ │ + * Method: getFeatureIdFromEvent │ │ │ │ + * Returns a feature id from an event on the renderer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - * │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {String} A URL for the tile corresponding to the given bounds. │ │ │ │ + * {<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. │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var url = ""; │ │ │ │ - if (!this.tileFullExtent || this.tileFullExtent.intersectsBounds(bounds)) { │ │ │ │ - │ │ │ │ - var center = bounds.getCenterLonLat(); │ │ │ │ - var info = this.getTileInfo(center); │ │ │ │ - var matrixId = this.matrix.identifier; │ │ │ │ - var dimensions = this.dimensions, │ │ │ │ - params; │ │ │ │ - │ │ │ │ - if (OpenLayers.Util.isArray(this.url)) { │ │ │ │ - url = this.selectUrl([ │ │ │ │ - this.version, this.style, this.matrixSet, │ │ │ │ - this.matrix.identifier, info.row, info.col │ │ │ │ - ].join(","), this.url); │ │ │ │ - } else { │ │ │ │ - url = this.url; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.requestEncoding.toUpperCase() === "REST") { │ │ │ │ - params = this.params; │ │ │ │ - if (url.indexOf("{") !== -1) { │ │ │ │ - var template = url.replace(/\{/g, "${"); │ │ │ │ - var context = { │ │ │ │ - // spec does not make clear if capital S or not │ │ │ │ - style: this.style, │ │ │ │ - Style: this.style, │ │ │ │ - TileMatrixSet: this.matrixSet, │ │ │ │ - TileMatrix: this.matrix.identifier, │ │ │ │ - TileRow: info.row, │ │ │ │ - TileCol: info.col │ │ │ │ - }; │ │ │ │ - if (dimensions) { │ │ │ │ - var dimension, i; │ │ │ │ - for (i = dimensions.length - 1; i >= 0; --i) { │ │ │ │ - dimension = dimensions[i]; │ │ │ │ - context[dimension] = params[dimension.toUpperCase()]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - url = OpenLayers.String.format(template, context); │ │ │ │ - } else { │ │ │ │ - // include 'version', 'layer' and 'style' in tile resource url │ │ │ │ - var path = this.version + "/" + this.layer + "/" + this.style + "/"; │ │ │ │ + getFeatureIdFromEvent: function(evt) { │ │ │ │ + var featureId, feature; │ │ │ │ │ │ │ │ - // append optional dimension path elements │ │ │ │ - if (dimensions) { │ │ │ │ - for (var i = 0; i < dimensions.length; i++) { │ │ │ │ - if (params[dimensions[i]]) { │ │ │ │ - path = path + params[dimensions[i]] + "/"; │ │ │ │ - } │ │ │ │ + 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. │ │ │ │ } │ │ │ │ } │ │ │ │ - │ │ │ │ - // append other required path elements │ │ │ │ - path = path + this.matrixSet + "/" + this.matrix.identifier + │ │ │ │ - "/" + info.row + "/" + info.col + "." + this.formatSuffix; │ │ │ │ - │ │ │ │ - if (!url.match(/\/$/)) { │ │ │ │ - url = url + "/"; │ │ │ │ - } │ │ │ │ - url = url + path; │ │ │ │ } │ │ │ │ - } else if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ - │ │ │ │ - // assemble all required parameters │ │ │ │ - params = { │ │ │ │ - SERVICE: "WMTS", │ │ │ │ - REQUEST: "GetTile", │ │ │ │ - VERSION: this.version, │ │ │ │ - LAYER: this.layer, │ │ │ │ - STYLE: this.style, │ │ │ │ - TILEMATRIXSET: this.matrixSet, │ │ │ │ - TILEMATRIX: this.matrix.identifier, │ │ │ │ - TILEROW: info.row, │ │ │ │ - TILECOL: info.col, │ │ │ │ - FORMAT: this.format │ │ │ │ - }; │ │ │ │ - url = OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this, [params]); │ │ │ │ - │ │ │ │ } │ │ │ │ } │ │ │ │ - return url; │ │ │ │ + return feature; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: mergeNewParams │ │ │ │ - * Extend the existing layer <params> with new properties. Tiles will be │ │ │ │ - * reloaded with updated params in the request. │ │ │ │ + * Method: eraseFeatures │ │ │ │ + * This is called by the layer to erase features; removes the feature from │ │ │ │ + * the list, then redraws the layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * newParams - {Object} Properties to extend to existing <params>. │ │ │ │ + * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ */ │ │ │ │ - mergeNewParams: function(newParams) { │ │ │ │ - if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ - return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply( │ │ │ │ - this, [OpenLayers.Util.upperCaseObject(newParams)] │ │ │ │ - ); │ │ │ │ + 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(); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.WMTS" │ │ │ │ + /** │ │ │ │ + * 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/Layer/MapGuide.js │ │ │ │ + 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/Request/XMLHttpRequest.js │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ + * @requires OpenLayers/Renderer/Elements.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Layer.MapGuide │ │ │ │ - * Instances of OpenLayers.Layer.MapGuide are used to display │ │ │ │ - * data from a MapGuide OS instance. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Layer.Grid> │ │ │ │ + * Class: OpenLayers.Renderer.SVG │ │ │ │ + * │ │ │ │ + * Inherits: │ │ │ │ + * - <OpenLayers.Renderer.Elements> │ │ │ │ */ │ │ │ │ -OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ +OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ - * {Boolean} Treat this layer as a base layer. Default is true. │ │ │ │ - **/ │ │ │ │ - isBaseLayer: true, │ │ │ │ + * Property: xmlns │ │ │ │ + * {String} │ │ │ │ + */ │ │ │ │ + xmlns: "http://www.w3.org/2000/svg", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: useHttpTile │ │ │ │ - * {Boolean} use a tile cache exposed directly via a webserver rather than the │ │ │ │ - * via mapguide server. This does require extra configuration on the Mapguide Server, │ │ │ │ - * and will only work when singleTile is false. The url for the layer must be set to the │ │ │ │ - * webserver path rather than the Mapguide mapagent. │ │ │ │ - * See http://trac.osgeo.org/mapguide/wiki/CodeSamples/Tiles/ServingTilesViaHttp │ │ │ │ - **/ │ │ │ │ - useHttpTile: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: singleTile │ │ │ │ - * {Boolean} use tile server or request single tile image. │ │ │ │ - **/ │ │ │ │ - singleTile: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: useOverlay │ │ │ │ - * {Boolean} flag to indicate if the layer should be retrieved using │ │ │ │ - * GETMAPIMAGE (default) or using GETDYNAMICOVERLAY requests. │ │ │ │ - **/ │ │ │ │ - useOverlay: false, │ │ │ │ + * Property: xlinkns │ │ │ │ + * {String} │ │ │ │ + */ │ │ │ │ + xlinkns: "http://www.w3.org/1999/xlink", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: useAsyncOverlay │ │ │ │ - * {Boolean} indicates if the MapGuide site supports the asynchronous │ │ │ │ - * GETDYNAMICOVERLAY requests which is available in MapGuide Enterprise 2010 │ │ │ │ - * and MapGuide Open Source v2.0.3 or higher. The newer versions of MG │ │ │ │ - * is called asynchronously, allows selections to be drawn separately from │ │ │ │ - * the map and offers styling options. │ │ │ │ - * │ │ │ │ - * With older versions of MapGuide, set useAsyncOverlay=false. Note that in │ │ │ │ - * this case a synchronous AJAX call is issued and the mapname and session │ │ │ │ - * parameters must be used to initialize the layer, not the mapdefinition │ │ │ │ - * parameter. Also note that this will issue a synchronous AJAX request │ │ │ │ - * before the image request can be issued so the users browser may lock │ │ │ │ - * up if the MG Web tier does not respond in a timely fashion. │ │ │ │ - **/ │ │ │ │ - useAsyncOverlay: true, │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: TILE_PARAMS │ │ │ │ - * {Object} Hashtable of default parameter key/value pairs for tiled layer │ │ │ │ + * Property: translationParameters │ │ │ │ + * {Object} Hash with "x" and "y" properties │ │ │ │ */ │ │ │ │ - TILE_PARAMS: { │ │ │ │ - operation: 'GETTILEIMAGE', │ │ │ │ - version: '1.2.0' │ │ │ │ - }, │ │ │ │ + translationParameters: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: SINGLE_TILE_PARAMS │ │ │ │ - * {Object} Hashtable of default parameter key/value pairs for untiled layer │ │ │ │ + * 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]. │ │ │ │ */ │ │ │ │ - SINGLE_TILE_PARAMS: { │ │ │ │ - operation: 'GETMAPIMAGE', │ │ │ │ - format: 'PNG', │ │ │ │ - locale: 'en', │ │ │ │ - clip: '1', │ │ │ │ - version: '1.0.0' │ │ │ │ - }, │ │ │ │ + symbolMetrics: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OVERLAY_PARAMS │ │ │ │ - * {Object} Hashtable of default parameter key/value pairs for untiled layer │ │ │ │ + * Constructor: OpenLayers.Renderer.SVG │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * containerID - {String} │ │ │ │ */ │ │ │ │ - OVERLAY_PARAMS: { │ │ │ │ - operation: 'GETDYNAMICMAPOVERLAYIMAGE', │ │ │ │ - format: 'PNG', │ │ │ │ - locale: 'en', │ │ │ │ - clip: '1', │ │ │ │ - version: '2.0.0' │ │ │ │ + initialize: function(containerID) { │ │ │ │ + if (!this.supported()) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + OpenLayers.Renderer.Elements.prototype.initialize.apply(this, │ │ │ │ + arguments); │ │ │ │ + this.translationParameters = { │ │ │ │ + x: 0, │ │ │ │ + y: 0 │ │ │ │ + }; │ │ │ │ + │ │ │ │ + this.symbolMetrics = {}; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: FOLDER_PARAMS │ │ │ │ - * {Object} Hashtable of parameter key/value pairs which describe │ │ │ │ - * the folder structure for tiles as configured in the mapguide │ │ │ │ - * serverconfig.ini section [TileServiceProperties] │ │ │ │ + /** │ │ │ │ + * APIMethod: supported │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the browser supports the SVG renderer │ │ │ │ */ │ │ │ │ - FOLDER_PARAMS: { │ │ │ │ - tileColumnsPerFolder: 30, │ │ │ │ - tileRowsPerFolder: 30, │ │ │ │ - format: 'png', │ │ │ │ - querystring: null │ │ │ │ + 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"))); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: defaultSize │ │ │ │ - * {<OpenLayers.Size>} Tile size as produced by MapGuide server │ │ │ │ - **/ │ │ │ │ - defaultSize: new OpenLayers.Size(300, 300), │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: tileOriginCorner │ │ │ │ - * {String} MapGuide tile server uses top-left as tile origin │ │ │ │ - **/ │ │ │ │ - tileOriginCorner: "tl", │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Layer.MapGuide │ │ │ │ - * Create a new Mapguide layer, either tiled or untiled. │ │ │ │ - * │ │ │ │ - * For tiled layers, the 'groupName' and 'mapDefinition' values │ │ │ │ - * must be specified as parameters in the constructor. │ │ │ │ - * │ │ │ │ - * For untiled base layers, specify either combination of 'mapName' and │ │ │ │ - * 'session', or 'mapDefinition' and 'locale'. │ │ │ │ - * │ │ │ │ - * For older versions of MapGuide and overlay layers, set useAsyncOverlay │ │ │ │ - * to false and in this case mapName and session are required parameters │ │ │ │ - * for the constructor. │ │ │ │ - * │ │ │ │ - * NOTE: MapGuide OS uses a DPI value and degrees to meters conversion │ │ │ │ - * factor that are different than the defaults used in OpenLayers, │ │ │ │ - * so these must be adjusted accordingly in your application. │ │ │ │ - * See the MapGuide example for how to set these values for MGOS. │ │ │ │ + * Method: inValidRange │ │ │ │ + * See #669 for more information │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} Name of the layer displayed in the interface │ │ │ │ - * url - {String} Location of the MapGuide mapagent executable │ │ │ │ - * (e.g. http://localhost:8008/mapguide/mapagent/mapagent.fcgi) │ │ │ │ - * params - {Object} hashtable of additional parameters to use. Some │ │ │ │ - * parameters may require additional code on the server. The ones that │ │ │ │ - * you may want to use are: │ │ │ │ - * - mapDefinition - {String} The MapGuide resource definition │ │ │ │ - * (e.g. Library://Samples/Gmap/Maps/gmapTiled.MapDefinition) │ │ │ │ - * - locale - Locale setting │ │ │ │ - * (for untiled overlays layers only) │ │ │ │ - * - mapName - {String} Name of the map as stored in the MapGuide session. │ │ │ │ - * (for untiled layers with a session parameter only) │ │ │ │ - * - session - { String} MapGuide session ID │ │ │ │ - * (for untiled overlays layers only) │ │ │ │ - * - basemaplayergroupname - {String} GroupName for tiled MapGuide layers only │ │ │ │ - * - format - Image format to be returned (for untiled overlay layers only) │ │ │ │ - * - showLayers - {String} A comma separated list of GUID's for the │ │ │ │ - * layers to display eg: 'cvc-xcv34,453-345-345sdf'. │ │ │ │ - * - hideLayers - {String} A comma separated list of GUID's for the │ │ │ │ - * layers to hide eg: 'cvc-xcv34,453-345-345sdf'. │ │ │ │ - * - showGroups - {String} A comma separated list of GUID's for the │ │ │ │ - * groups to display eg: 'cvc-xcv34,453-345-345sdf'. │ │ │ │ - * - hideGroups - {String} A comma separated list of GUID's for the │ │ │ │ - * groups to hide eg: 'cvc-xcv34,453-345-345sdf' │ │ │ │ - * - selectionXml - {String} A selection xml string Some server plumbing │ │ │ │ - * is required to read such a value. │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer; │ │ │ │ - * will vary depending if tiled or untiled maps are being requested │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ + 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); │ │ │ │ + }, │ │ │ │ │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ │ │ │ │ - // unless explicitly set in options, if the layer is transparent, │ │ │ │ - // it will be an overlay │ │ │ │ - if (options == null || options.isBaseLayer == null) { │ │ │ │ - this.isBaseLayer = ((this.transparent != "true") && │ │ │ │ - (this.transparent != true)); │ │ │ │ - } │ │ │ │ + var resolution = this.getResolution(), │ │ │ │ + left = -extent.left / resolution, │ │ │ │ + top = extent.top / resolution; │ │ │ │ │ │ │ │ - if (options && options.useOverlay != null) { │ │ │ │ - this.useOverlay = options.useOverlay; │ │ │ │ - } │ │ │ │ + // 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; │ │ │ │ │ │ │ │ - //initialize for untiled layers │ │ │ │ - if (this.singleTile) { │ │ │ │ - if (this.useOverlay) { │ │ │ │ - OpenLayers.Util.applyDefaults( │ │ │ │ - this.params, │ │ │ │ - this.OVERLAY_PARAMS │ │ │ │ - ); │ │ │ │ - if (!this.useAsyncOverlay) { │ │ │ │ - this.params.version = "1.0.0"; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Util.applyDefaults( │ │ │ │ - this.params, │ │ │ │ - this.SINGLE_TILE_PARAMS │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + this.rendererRoot.setAttributeNS(null, "viewBox", extentString); │ │ │ │ + this.translate(this.xOffset, 0); │ │ │ │ + return true; │ │ │ │ } else { │ │ │ │ - //initialize for tiled layers │ │ │ │ - if (this.useHttpTile) { │ │ │ │ - OpenLayers.Util.applyDefaults( │ │ │ │ - this.params, │ │ │ │ - this.FOLDER_PARAMS │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - OpenLayers.Util.applyDefaults( │ │ │ │ - this.params, │ │ │ │ - this.TILE_PARAMS │ │ │ │ - ); │ │ │ │ + var inRange = this.translate(left - this.left + this.xOffset, top - this.top); │ │ │ │ + if (!inRange) { │ │ │ │ + // recenter the coordinate system │ │ │ │ + this.setExtent(extent, true); │ │ │ │ } │ │ │ │ - this.setTileSize(this.defaultSize); │ │ │ │ + return coordSysUnchanged && inRange; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clone │ │ │ │ - * Create a clone of this layer │ │ │ │ - * │ │ │ │ + * Method: translate │ │ │ │ + * Transforms the SVG coordinate system │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * x - {Float} │ │ │ │ + * y - {Float} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Layer.MapGuide>} An exact clone of this layer │ │ │ │ + * {Boolean} true if the translation parameters are in the valid coordinates │ │ │ │ + * range, false otherwise. │ │ │ │ */ │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.MapGuide(this.name, │ │ │ │ - this.url, │ │ │ │ - this.params, │ │ │ │ - this.getOptions()); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - //get all additions from superclasses │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - │ │ │ │ - return obj; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getURL │ │ │ │ - * Return a query string for this layer │ │ │ │ - * │ │ │ │ + * Method: setSize │ │ │ │ + * Sets the size of the drawing surface. │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * size - {<OpenLayers.Size>} The size of the drawing surface │ │ │ │ */ │ │ │ │ - getURL: function(bounds) { │ │ │ │ - var url; │ │ │ │ - var center = bounds.getCenterLonLat(); │ │ │ │ - var mapSize = this.map.getSize(); │ │ │ │ - │ │ │ │ - if (this.singleTile) { │ │ │ │ - //set up the call for GETMAPIMAGE or GETDYNAMICMAPOVERLAY with │ │ │ │ - //dynamic map parameters │ │ │ │ - var params = { │ │ │ │ - setdisplaydpi: OpenLayers.DOTS_PER_INCH, │ │ │ │ - setdisplayheight: mapSize.h * this.ratio, │ │ │ │ - setdisplaywidth: mapSize.w * this.ratio, │ │ │ │ - setviewcenterx: center.lon, │ │ │ │ - setviewcentery: center.lat, │ │ │ │ - setviewscale: this.map.getScale() │ │ │ │ - }; │ │ │ │ - │ │ │ │ - if (this.useOverlay && !this.useAsyncOverlay) { │ │ │ │ - //first we need to call GETVISIBLEMAPEXTENT to set the extent │ │ │ │ - var getVisParams = {}; │ │ │ │ - getVisParams = OpenLayers.Util.extend(getVisParams, params); │ │ │ │ - getVisParams.operation = "GETVISIBLEMAPEXTENT"; │ │ │ │ - getVisParams.version = "1.0.0"; │ │ │ │ - getVisParams.session = this.params.session; │ │ │ │ - getVisParams.mapName = this.params.mapName; │ │ │ │ - getVisParams.format = 'text/xml'; │ │ │ │ - url = this.getFullRequestString(getVisParams); │ │ │ │ - │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ - url: url, │ │ │ │ - async: false │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - //construct the full URL │ │ │ │ - url = this.getFullRequestString(params); │ │ │ │ - } else { │ │ │ │ - │ │ │ │ - //tiled version │ │ │ │ - var currentRes = this.map.getResolution(); │ │ │ │ - var colidx = Math.floor((bounds.left - this.maxExtent.left) / currentRes); │ │ │ │ - colidx = Math.round(colidx / this.tileSize.w); │ │ │ │ - var rowidx = Math.floor((this.maxExtent.top - bounds.top) / currentRes); │ │ │ │ - rowidx = Math.round(rowidx / this.tileSize.h); │ │ │ │ - │ │ │ │ - if (this.useHttpTile) { │ │ │ │ - url = this.getImageFilePath({ │ │ │ │ - tilecol: colidx, │ │ │ │ - tilerow: rowidx, │ │ │ │ - scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ - }); │ │ │ │ + setSize: function(size) { │ │ │ │ + OpenLayers.Renderer.prototype.setSize.apply(this, arguments); │ │ │ │ │ │ │ │ - } else { │ │ │ │ - url = this.getFullRequestString({ │ │ │ │ - tilecol: colidx, │ │ │ │ - tilerow: rowidx, │ │ │ │ - scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return url; │ │ │ │ + this.rendererRoot.setAttributeNS(null, "width", this.size.w); │ │ │ │ + this.rendererRoot.setAttributeNS(null, "height", this.size.h); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getFullRequestString │ │ │ │ - * getFullRequestString on MapGuide layers is special, because we │ │ │ │ - * do a regular expression replace on ',' in parameters to '+'. │ │ │ │ - * This is why it is subclassed here. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: getNodeType │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * altUrl - {String} Alternative base URL to use. │ │ │ │ - * │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {String} A string with the layer's url appropriately encoded for MapGuide │ │ │ │ + * {String} The corresponding node type for the specified geometry │ │ │ │ */ │ │ │ │ - getFullRequestString: function(newParams, altUrl) { │ │ │ │ - // use layer's url unless altUrl passed in │ │ │ │ - var url = (altUrl == null) ? this.url : altUrl; │ │ │ │ - │ │ │ │ - // if url is not a string, it should be an array of strings, │ │ │ │ - // in which case we will randomly select one of them in order │ │ │ │ - // to evenly distribute requests to different urls. │ │ │ │ - if (typeof url == "object") { │ │ │ │ - url = url[Math.floor(Math.random() * url.length)]; │ │ │ │ - } │ │ │ │ - // requestString always starts with url │ │ │ │ - var requestString = 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); │ │ │ │ - // 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]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ - │ │ │ │ - /* MapGuide needs '+' seperating things like bounds/height/width. │ │ │ │ - Since typically this is URL encoded, we use a slight hack: we │ │ │ │ - depend on the list-like functionality of getParameterString to │ │ │ │ - leave ',' only in the case of list items (since otherwise it is │ │ │ │ - encoded) then do a regular expression replace on the , characters │ │ │ │ - to '+' */ │ │ │ │ - paramsString = paramsString.replace(/,/g, "+"); │ │ │ │ - │ │ │ │ - if (paramsString != "") { │ │ │ │ - var lastServerChar = url.charAt(url.length - 1); │ │ │ │ - if ((lastServerChar == "&") || (lastServerChar == "?")) { │ │ │ │ - requestString += paramsString; │ │ │ │ - } else { │ │ │ │ - if (url.indexOf('?') == -1) { │ │ │ │ - //serverPath has no ? -- add one │ │ │ │ - requestString += '?' + paramsString; │ │ │ │ + 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 { │ │ │ │ - //serverPath contains ?, so must already have paramsString at the end │ │ │ │ - requestString += '&' + paramsString; │ │ │ │ + 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 requestString; │ │ │ │ + return nodeType; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getImageFilePath │ │ │ │ - * special handler to request mapguide tiles from an http exposed tilecache │ │ │ │ + * 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: │ │ │ │ - * altUrl - {String} Alternative base URL to use. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A string with the url for the tile image │ │ │ │ + * node - {SVGDomElement} An SVG element to decorate │ │ │ │ + * style - {Object} │ │ │ │ + * options - {Object} Currently supported options include │ │ │ │ + * 'isFilled' {Boolean} and │ │ │ │ + * 'isStroked' {Boolean} │ │ │ │ */ │ │ │ │ - getImageFilePath: function(newParams, altUrl) { │ │ │ │ - // use layer's url unless altUrl passed in │ │ │ │ - var url = (altUrl == null) ? this.url : altUrl; │ │ │ │ + setStyle: function(node, style, options) { │ │ │ │ + style = style || node._style; │ │ │ │ + options = options || node._options; │ │ │ │ │ │ │ │ - // if url is not a string, it should be an array of strings, │ │ │ │ - // in which case we will randomly select one of them in order │ │ │ │ - // to evenly distribute requests to different urls. │ │ │ │ - if (typeof url == "object") { │ │ │ │ - url = url[Math.floor(Math.random() * url.length)]; │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ } │ │ │ │ - // requestString always starts with url │ │ │ │ - var requestString = url; │ │ │ │ │ │ │ │ - var tileRowGroup = ""; │ │ │ │ - var tileColGroup = ""; │ │ │ │ + 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); │ │ │ │ │ │ │ │ - if (newParams.tilerow < 0) { │ │ │ │ - tileRowGroup = '-'; │ │ │ │ - } │ │ │ │ + var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ │ │ │ │ - if (newParams.tilerow == 0) { │ │ │ │ - tileRowGroup += '0'; │ │ │ │ - } else { │ │ │ │ - tileRowGroup += Math.floor(Math.abs(newParams.tilerow / this.params.tileRowsPerFolder)) * this.params.tileRowsPerFolder; │ │ │ │ + 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 (newParams.tilecol < 0) { │ │ │ │ - tileColGroup = '-'; │ │ │ │ + if (options.isFilled) { │ │ │ │ + node.setAttributeNS(null, "fill", style.fillColor); │ │ │ │ + node.setAttributeNS(null, "fill-opacity", style.fillOpacity); │ │ │ │ + } else { │ │ │ │ + node.setAttributeNS(null, "fill", "none"); │ │ │ │ } │ │ │ │ │ │ │ │ - if (newParams.tilecol == 0) { │ │ │ │ - tileColGroup += '0'; │ │ │ │ + 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 { │ │ │ │ - tileColGroup += Math.floor(Math.abs(newParams.tilecol / this.params.tileColumnsPerFolder)) * this.params.tileColumnsPerFolder; │ │ │ │ + node.setAttributeNS(null, "stroke", "none"); │ │ │ │ } │ │ │ │ │ │ │ │ - var tilePath = '/S' + Math.floor(newParams.scaleindex) + │ │ │ │ - '/' + this.params.basemaplayergroupname + │ │ │ │ - '/R' + tileRowGroup + │ │ │ │ - '/C' + tileColGroup + │ │ │ │ - '/' + (newParams.tilerow % this.params.tileRowsPerFolder) + │ │ │ │ - '_' + (newParams.tilecol % this.params.tileColumnsPerFolder) + │ │ │ │ - '.' + this.params.format; │ │ │ │ + if (style.pointerEvents) { │ │ │ │ + node.setAttributeNS(null, "pointer-events", style.pointerEvents); │ │ │ │ + } │ │ │ │ │ │ │ │ - if (this.params.querystring) { │ │ │ │ - tilePath += "?" + this.params.querystring; │ │ │ │ + if (style.cursor != null) { │ │ │ │ + node.setAttributeNS(null, "cursor", style.cursor); │ │ │ │ } │ │ │ │ │ │ │ │ - requestString += tilePath; │ │ │ │ - return requestString; │ │ │ │ + return node; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.MapGuide" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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 │ │ │ │ - */ │ │ │ │ + /** │ │ │ │ + * 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, ","); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ -/** │ │ │ │ - * 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, { │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: displayInLayerSwitcher │ │ │ │ - * Set to false for this layer type │ │ │ │ + /** │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - displayInLayerSwitcher: false, │ │ │ │ + nodeTypeCompare: function(node, type) { │ │ │ │ + return (type == node.nodeName); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layers │ │ │ │ - * Layers that are attached to this container. Required config option. │ │ │ │ + * Method: createRenderRoot │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} The specific render engine's root element │ │ │ │ */ │ │ │ │ - layers: null, │ │ │ │ + createRenderRoot: function() { │ │ │ │ + var svg = this.nodeFactory(this.container.id + "_svgRoot", "svg"); │ │ │ │ + svg.style.display = "block"; │ │ │ │ + return svg; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + * Method: createRoot │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} A name for the layer │ │ │ │ - * options - {Object} Optional object with non-default properties to set on │ │ │ │ - * the layer. │ │ │ │ + * suffix - {String} suffix to append to the id │ │ │ │ * │ │ │ │ - * 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 │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ + createRoot: function(suffix) { │ │ │ │ + return this.nodeFactory(this.container.id + suffix, "g"); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: display │ │ │ │ + * Method: createDefs │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} The element to which we'll add the symbol definitions │ │ │ │ */ │ │ │ │ - display: function() {}, │ │ │ │ + createDefs: function() { │ │ │ │ + var defs = this.nodeFactory(this.container.id + "_defs", "defs"); │ │ │ │ + this.rendererRoot.appendChild(defs); │ │ │ │ + return defs; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /************************************** │ │ │ │ + * * │ │ │ │ + * GEOMETRY DRAWING FUNCTIONS * │ │ │ │ + * * │ │ │ │ + **************************************/ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getFeatureFromEvent │ │ │ │ - * walk through the layers to find the feature returned by the event │ │ │ │ + * Method: drawPoint │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} event object with a feature property │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} │ │ │ │ + * {DOMElement} or false if the renderer could not draw the point │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + drawPoint: function(node, geometry) { │ │ │ │ + return this.drawCircle(node, geometry, 1); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setMap │ │ │ │ + * Method: drawCircle │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * radius - {Float} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} or false if the renderer could not draw the circle │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ - this.collectRoots(); │ │ │ │ - map.events.register("changelayer", this, this.handleChangeLayer); │ │ │ │ + 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: removeMap │ │ │ │ + * Method: drawLineString │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - removeMap: function(map) { │ │ │ │ - map.events.unregister("changelayer", this, this.handleChangeLayer); │ │ │ │ - this.resetRoots(); │ │ │ │ - OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments); │ │ │ │ + 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: collectRoots │ │ │ │ - * Collects the root nodes of all layers this control is configured with │ │ │ │ - * and moveswien the nodes to this control's layer │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + 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: resetRoots │ │ │ │ - * Resets the root nodes back into the layers they belong to. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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: 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. │ │ │ │ + * Method: drawRectangle │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} or false if the renderer could not draw the rectangle │ │ │ │ */ │ │ │ │ - handleChangeLayer: function(evt) { │ │ │ │ - var layer = evt.layer; │ │ │ │ - if (evt.property == "order" && │ │ │ │ - OpenLayers.Util.indexOf(this.layers, layer) != -1) { │ │ │ │ - this.resetRoots(); │ │ │ │ - this.collectRoots(); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Vector.RootContainer" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Layer/Google/v3.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. */ │ │ │ │ - │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ + } │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Layer/Google.js │ │ │ │ - */ │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Layer.Google.v3 │ │ │ │ - * │ │ │ │ - * Mixin providing functionality specific to the Google Maps API v3. │ │ │ │ - * │ │ │ │ - * To use this layer, you must include the GMaps v3 API in your html. │ │ │ │ - * │ │ │ │ - * Note that this layer configures the google.maps.map object with the │ │ │ │ - * "disableDefaultUI" option set to true. Using UI controls that the Google │ │ │ │ - * Maps API provides is not supported by the OpenLayers API. │ │ │ │ - */ │ │ │ │ -OpenLayers.Layer.Google.v3 = { │ │ │ │ + var x = ((location.x - this.featureDx) / resolution + this.left); │ │ │ │ + var y = (location.y / resolution - this.top); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: DEFAULTS │ │ │ │ - * {Object} It is not recommended to change the properties set here. Note │ │ │ │ - * that Google.v3 layers only work when sphericalMercator is set to true. │ │ │ │ - * │ │ │ │ - * (code) │ │ │ │ - * { │ │ │ │ - * sphericalMercator: true, │ │ │ │ - * projection: "EPSG:900913" │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ - */ │ │ │ │ - DEFAULTS: { │ │ │ │ - sphericalMercator: true, │ │ │ │ - projection: "EPSG:900913" │ │ │ │ - }, │ │ │ │ + var suffix = (drawOutline) ? this.LABEL_OUTLINE_SUFFIX : this.LABEL_ID_SUFFIX; │ │ │ │ + var label = this.nodeFactory(featureId + suffix, "text"); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: animationEnabled │ │ │ │ - * {Boolean} If set to true, the transition between zoom levels will be │ │ │ │ - * animated (if supported by the GMaps API for the device used). Set to │ │ │ │ - * false to match the zooming experience of other layer types. Default │ │ │ │ - * is true. Note that the GMaps API does not give us control over zoom │ │ │ │ - * animation, so if set to false, when zooming, this will make the │ │ │ │ - * layer temporarily invisible, wait until GMaps reports the map being │ │ │ │ - * idle, and make it visible again. The result will be a blank layer │ │ │ │ - * for a few moments while zooming. │ │ │ │ - */ │ │ │ │ - animationEnabled: true, │ │ │ │ + label.setAttributeNS(null, "x", x); │ │ │ │ + label.setAttributeNS(null, "y", -y); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: loadMapObject │ │ │ │ - * Load the GMap and register appropriate event listeners. │ │ │ │ - */ │ │ │ │ - loadMapObject: function() { │ │ │ │ - if (!this.type) { │ │ │ │ - this.type = google.maps.MapTypeId.ROADMAP; │ │ │ │ + if (style.fontColor) { │ │ │ │ + label.setAttributeNS(null, "fill", style.fontColor); │ │ │ │ } │ │ │ │ - var mapObject; │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - // there are already Google layers added to this map │ │ │ │ - mapObject = cache.mapObject; │ │ │ │ - // increment the layer count │ │ │ │ - ++cache.count; │ │ │ │ + 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 { │ │ │ │ - // this is the first Google layer for this map │ │ │ │ - // create GMap │ │ │ │ - var center = this.map.getCenter(); │ │ │ │ - var container = document.createElement('div'); │ │ │ │ - container.className = "olForeignContainer"; │ │ │ │ - container.style.width = '100%'; │ │ │ │ - container.style.height = '100%'; │ │ │ │ - mapObject = new google.maps.Map(container, { │ │ │ │ - center: center ? │ │ │ │ - new google.maps.LatLng(center.lat, center.lon) : new google.maps.LatLng(0, 0), │ │ │ │ - zoom: this.map.getZoom() || 0, │ │ │ │ - mapTypeId: this.type, │ │ │ │ - disableDefaultUI: true, │ │ │ │ - keyboardShortcuts: false, │ │ │ │ - draggable: false, │ │ │ │ - disableDoubleClickZoom: true, │ │ │ │ - scrollwheel: false, │ │ │ │ - streetViewControl: false │ │ │ │ - }); │ │ │ │ - var googleControl = document.createElement('div'); │ │ │ │ - googleControl.style.width = '100%'; │ │ │ │ - googleControl.style.height = '100%'; │ │ │ │ - mapObject.controls[google.maps.ControlPosition.TOP_LEFT].push(googleControl); │ │ │ │ + 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"); │ │ │ │ │ │ │ │ - // cache elements for use by any other google layers added to │ │ │ │ - // this same map │ │ │ │ - cache = { │ │ │ │ - googleControl: googleControl, │ │ │ │ - mapObject: mapObject, │ │ │ │ - count: 1 │ │ │ │ - }; │ │ │ │ - OpenLayers.Layer.Google.cache[this.map.id] = cache; │ │ │ │ + if (OpenLayers.IS_GECKO === true) { │ │ │ │ + label.setAttributeNS(null, "dominant-baseline", │ │ │ │ + OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]] || "central"); │ │ │ │ } │ │ │ │ - this.mapObject = mapObject; │ │ │ │ - this.setGMapVisibility(this.visibility); │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: onMapResize │ │ │ │ - */ │ │ │ │ - onMapResize: function() { │ │ │ │ - if (this.visibility) { │ │ │ │ - google.maps.event.trigger(this.mapObject, "resize"); │ │ │ │ + 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: setGMapVisibility │ │ │ │ - * Display the GMap container and associated elements. │ │ │ │ + /** │ │ │ │ + * Method: getComponentString │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * visible - {Boolean} Display the GMap elements. │ │ │ │ + * 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) │ │ │ │ */ │ │ │ │ - setGMapVisibility: function(visible) { │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - var map = this.map; │ │ │ │ - if (cache) { │ │ │ │ - var type = this.type; │ │ │ │ - var layers = map.layers; │ │ │ │ - var layer; │ │ │ │ - for (var i = layers.length - 1; i >= 0; --i) { │ │ │ │ - layer = layers[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.Google && │ │ │ │ - layer.visibility === true && layer.inRange === true) { │ │ │ │ - type = layer.type; │ │ │ │ - visible = true; │ │ │ │ - break; │ │ │ │ + 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])); │ │ │ │ + } │ │ │ │ } │ │ │ │ - } │ │ │ │ - var container = this.mapObject.getDiv(); │ │ │ │ - if (visible === true) { │ │ │ │ - if (container.parentNode !== map.div) { │ │ │ │ - if (!cache.rendered) { │ │ │ │ - var me = this; │ │ │ │ - google.maps.event.addListenerOnce(this.mapObject, 'tilesloaded', function() { │ │ │ │ - cache.rendered = true; │ │ │ │ - me.setGMapVisibility(me.getVisibility()); │ │ │ │ - me.moveTo(me.map.getCenter()); │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - map.div.appendChild(container); │ │ │ │ - cache.googleControl.appendChild(map.viewPortDiv); │ │ │ │ - google.maps.event.trigger(this.mapObject, 'resize'); │ │ │ │ + if (i < len - 1) { │ │ │ │ + if (this.getShortString(components[i + 1])) { │ │ │ │ + strings.push(this.clipLine(components[i], │ │ │ │ + components[i + 1])); │ │ │ │ } │ │ │ │ } │ │ │ │ - this.mapObject.setMapTypeId(type); │ │ │ │ - } else if (cache.googleControl.hasChildNodes()) { │ │ │ │ - map.div.appendChild(map.viewPortDiv); │ │ │ │ - map.div.removeChild(container); │ │ │ │ + complete = false; │ │ │ │ } │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getMapContainer │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} the GMap container's div │ │ │ │ - */ │ │ │ │ - getMapContainer: function() { │ │ │ │ - return this.mapObject.getDiv(); │ │ │ │ + return { │ │ │ │ + path: strings.join(separator || ","), │ │ │ │ + complete: complete │ │ │ │ + }; │ │ │ │ }, │ │ │ │ │ │ │ │ - // │ │ │ │ - // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ - // │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectBoundsFromOLBounds │ │ │ │ + * 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: │ │ │ │ - * olBounds - {<OpenLayers.Bounds>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} A MapObject Bounds, translated from olBounds │ │ │ │ - * Returns null if null value is passed in │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ - var moBounds = null; │ │ │ │ - if (olBounds != null) { │ │ │ │ - var sw = this.sphericalMercator ? │ │ │ │ - this.inverseMercator(olBounds.bottom, olBounds.left) : │ │ │ │ - new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ - var ne = this.sphericalMercator ? │ │ │ │ - this.inverseMercator(olBounds.top, olBounds.right) : │ │ │ │ - new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ - moBounds = new google.maps.LatLngBounds( │ │ │ │ - new google.maps.LatLng(sw.lat, sw.lon), │ │ │ │ - new google.maps.LatLng(ne.lat, ne.lon) │ │ │ │ - ); │ │ │ │ + clipLine: function(badComponent, goodComponent) { │ │ │ │ + if (goodComponent.equals(badComponent)) { │ │ │ │ + return ""; │ │ │ │ } │ │ │ │ - return moBounds; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Interface Controls * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ - │ │ │ │ - │ │ │ │ - // LonLat - Pixel Translation │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectLonLatFromMapObjectPixel │ │ │ │ + /** │ │ │ │ + * Method: getShortString │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * moPixel - {Object} MapObject Pixel format │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} MapObject LonLat translated from MapObject Pixel │ │ │ │ + * {String} or false if point is outside the valid range │ │ │ │ */ │ │ │ │ - getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ - var size = this.map.getSize(); │ │ │ │ - var lon = this.getLongitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ - var lat = this.getLatitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - │ │ │ │ - var delta_x = moPixel.x - (size.w / 2); │ │ │ │ - var delta_y = moPixel.y - (size.h / 2); │ │ │ │ - │ │ │ │ - var lonlat = new OpenLayers.LonLat( │ │ │ │ - lon + delta_x * res, │ │ │ │ - lat - delta_y * res │ │ │ │ - ); │ │ │ │ + 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.wrapDateLine) { │ │ │ │ - lonlat = lonlat.wrapDateLine(this.maxExtent); │ │ │ │ + if (this.inValidRange(x, y)) { │ │ │ │ + return x + "," + y; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ } │ │ │ │ - return this.getMapObjectLonLatFromLonLat(lonlat.lon, lonlat.lat); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectPixelFromMapObjectLonLat │ │ │ │ + * Method: getPosition │ │ │ │ + * Finds the position of an svg node. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * moLonLat - {Object} MapObject LonLat format │ │ │ │ + * node - {DOMElement} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} MapObject Pixel transtlated from MapObject LonLat │ │ │ │ + * {Object} hash with x and y properties, representing the coordinates │ │ │ │ + * within the svg coordinate system │ │ │ │ */ │ │ │ │ - getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); │ │ │ │ - var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - var extent = this.map.getExtent(); │ │ │ │ - return this.getMapObjectPixelFromXY((1 / res * (lon - extent.left)), │ │ │ │ - (1 / res * (extent.top - lat))); │ │ │ │ + getPosition: function(node) { │ │ │ │ + return ({ │ │ │ │ + x: parseFloat(node.getAttributeNS(null, "cx")), │ │ │ │ + y: parseFloat(node.getAttributeNS(null, "cy")) │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: setMapObjectCenter │ │ │ │ - * Set the mapObject to the specified center and zoom │ │ │ │ + /** │ │ │ │ + * Method: importSymbol │ │ │ │ + * add a new symbol definition from the rendererer's symbol hash │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * center - {Object} MapObject LonLat format │ │ │ │ - * zoom - {int} MapObject zoom format │ │ │ │ + * graphicName - {String} name of the symbol to import │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} - the imported symbol │ │ │ │ */ │ │ │ │ - setMapObjectCenter: function(center, zoom) { │ │ │ │ - if (this.animationEnabled === false && zoom != this.mapObject.zoom) { │ │ │ │ - var mapContainer = this.getMapContainer(); │ │ │ │ - google.maps.event.addListenerOnce( │ │ │ │ - this.mapObject, │ │ │ │ - "idle", │ │ │ │ - function() { │ │ │ │ - mapContainer.style.visibility = ""; │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - mapContainer.style.visibility = "hidden"; │ │ │ │ + importSymbol: function(graphicName) { │ │ │ │ + if (!this.defs) { │ │ │ │ + // create svg defs tag │ │ │ │ + this.defs = this.createDefs(); │ │ │ │ } │ │ │ │ - this.mapObject.setOptions({ │ │ │ │ - center: center, │ │ │ │ - zoom: zoom │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ + var id = this.container.id + "-" + graphicName; │ │ │ │ │ │ │ │ + // check if symbol already exists in the defs │ │ │ │ + var existing = document.getElementById(id); │ │ │ │ + if (existing != null) { │ │ │ │ + return existing; │ │ │ │ + } │ │ │ │ │ │ │ │ - // Bounds │ │ │ │ + var symbol = OpenLayers.Renderer.symbol[graphicName]; │ │ │ │ + if (!symbol) { │ │ │ │ + throw new Error(graphicName + ' is not a valid symbol name'); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectZoomFromMapObjectBounds │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * moBounds - {Object} MapObject Bounds format │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject Zoom for specified MapObject Bounds │ │ │ │ - */ │ │ │ │ - getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ - return this.mapObject.getBoundsZoomLevel(moBounds); │ │ │ │ - }, │ │ │ │ + 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); │ │ │ │ │ │ │ │ - /************************************ │ │ │ │ - * * │ │ │ │ - * MapObject Primitives * │ │ │ │ - * * │ │ │ │ - ************************************/ │ │ │ │ + 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(" ")); │ │ │ │ │ │ │ │ - // LonLat │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getMapObjectLonLatFromLonLat │ │ │ │ + * Method: getFeatureIdFromEvent │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * lon - {Float} │ │ │ │ - * lat - {Float} │ │ │ │ - * │ │ │ │ + * evt - {Object} An <OpenLayers.Event> object │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} MapObject LonLat built from lon and lat params │ │ │ │ + * {String} A feature id or undefined. │ │ │ │ */ │ │ │ │ - getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ - var gLatLng; │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - var lonlat = this.inverseMercator(lon, lat); │ │ │ │ - gLatLng = new google.maps.LatLng(lonlat.lat, lonlat.lon); │ │ │ │ - } else { │ │ │ │ - gLatLng = new google.maps.LatLng(lat, lon); │ │ │ │ + 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 gLatLng; │ │ │ │ + return featureId; │ │ │ │ }, │ │ │ │ │ │ │ │ - // Pixel │ │ │ │ + CLASS_NAME: "OpenLayers.Renderer.SVG" │ │ │ │ +}); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: getMapObjectPixelFromXY │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * x - {Integer} │ │ │ │ - * y - {Integer} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} MapObject Pixel from x and y parameters │ │ │ │ - */ │ │ │ │ - getMapObjectPixelFromXY: function(x, y) { │ │ │ │ - return new google.maps.Point(x, y); │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * 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/Events/buttonclick.js │ │ │ │ + OpenLayers/Renderer/VML.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/Renderer/Elements.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>. │ │ │ │ + * Class: OpenLayers.Renderer.VML │ │ │ │ + * Render vector features in browsers with VML capability. Construct a new │ │ │ │ + * VML renderer with the <OpenLayers.Renderer.VML> constructor. │ │ │ │ + * │ │ │ │ + * Note that for all calculations in this class, we use (num | 0) to truncate a │ │ │ │ + * float value to an integer. This is done because it seems that VML doesn't │ │ │ │ + * support float values. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Renderer.Elements> │ │ │ │ */ │ │ │ │ -OpenLayers.Events.buttonclick = OpenLayers.Class({ │ │ │ │ +OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: target │ │ │ │ - * {<OpenLayers.Events>} The events instance that the buttonclick event will │ │ │ │ - * be triggered on. │ │ │ │ + * Property: xmlns │ │ │ │ + * {String} XML Namespace URN │ │ │ │ */ │ │ │ │ - target: null, │ │ │ │ + xmlns: "urn:schemas-microsoft-com:vml", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: events │ │ │ │ - * {Array} Events to observe and conditionally stop from propagating when │ │ │ │ - * an element with the olButton class (or its olAlphaImg child) is │ │ │ │ - * clicked. │ │ │ │ + * Property: symbolCache │ │ │ │ + * {DOMElement} node holding symbols. This hash is keyed by symbol name, │ │ │ │ + * and each value is a hash with a "path" and an "extent" property. │ │ │ │ */ │ │ │ │ - events: [ │ │ │ │ - 'mousedown', 'mouseup', 'click', 'dblclick', │ │ │ │ - 'touchstart', 'touchmove', 'touchend', 'keydown' │ │ │ │ - ], │ │ │ │ + symbolCache: {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: startRegEx │ │ │ │ - * {RegExp} Regular expression to test Event.type for events that start │ │ │ │ - * a buttonclick sequence. │ │ │ │ + * Property: offset │ │ │ │ + * {Object} Hash with "x" and "y" properties │ │ │ │ */ │ │ │ │ - startRegEx: /^mousedown|touchstart$/, │ │ │ │ + offset: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: cancelRegEx │ │ │ │ - * {RegExp} Regular expression to test Event.type for events that cancel │ │ │ │ - * a buttonclick sequence. │ │ │ │ + * Constructor: OpenLayers.Renderer.VML │ │ │ │ + * Create a new VML renderer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * containerID - {String} The id for the element that contains the renderer │ │ │ │ */ │ │ │ │ - cancelRegEx: /^touchmove$/, │ │ │ │ + initialize: function(containerID) { │ │ │ │ + if (!this.supported()) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + if (!document.namespaces.olv) { │ │ │ │ + document.namespaces.add("olv", this.xmlns); │ │ │ │ + var style = document.createStyleSheet(); │ │ │ │ + var shapes = ['shape', 'rect', 'oval', 'fill', 'stroke', 'imagedata', 'group', 'textbox']; │ │ │ │ + for (var i = 0, len = shapes.length; i < len; i++) { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: completeRegEx │ │ │ │ - * {RegExp} Regular expression to test Event.type for events that complete │ │ │ │ - * a buttonclick sequence. │ │ │ │ - */ │ │ │ │ - completeRegEx: /^mouseup|touchend$/, │ │ │ │ + style.addRule('olv\\:' + shapes[i], "behavior: url(#default#VML); " + │ │ │ │ + "position: absolute; display: inline-block;"); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + OpenLayers.Renderer.Elements.prototype.initialize.apply(this, │ │ │ │ + arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: startEvt │ │ │ │ - * {Event} The event that started the click sequence │ │ │ │ + * APIMethod: supported │ │ │ │ + * Determine whether a browser supports this renderer. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The browser supports the VML renderer │ │ │ │ */ │ │ │ │ + supported: function() { │ │ │ │ + return !!(document.namespaces); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: setExtent │ │ │ │ + * Set the renderer's extent │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * target - {<OpenLayers.Events>} The events instance that the buttonclick │ │ │ │ - * event will be triggered on. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + setExtent: function(extent, resolutionChanged) { │ │ │ │ + var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + │ │ │ │ + var left = (extent.left / resolution) | 0; │ │ │ │ + var top = (extent.top / resolution - this.size.h) | 0; │ │ │ │ + if (resolutionChanged || !this.offset) { │ │ │ │ + this.offset = { │ │ │ │ + x: left, │ │ │ │ + y: top │ │ │ │ + }; │ │ │ │ + left = 0; │ │ │ │ + top = 0; │ │ │ │ + } else { │ │ │ │ + left = left - this.offset.x; │ │ │ │ + top = top - this.offset.y; │ │ │ │ + } │ │ │ │ + │ │ │ │ + │ │ │ │ + var org = (left - this.xOffset) + " " + top; │ │ │ │ + this.root.coordorigin = org; │ │ │ │ + var roots = [this.root, this.vectorRoot, this.textRoot]; │ │ │ │ + var root; │ │ │ │ + for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ + root = roots[i]; │ │ │ │ + │ │ │ │ + var size = this.size.w + " " + this.size.h; │ │ │ │ + root.coordsize = size; │ │ │ │ + │ │ │ │ } │ │ │ │ + // flip the VML display Y axis upside down so it │ │ │ │ + // matches the display Y axis of the map │ │ │ │ + this.root.style.flip = "y"; │ │ │ │ + │ │ │ │ + return coordSysUnchanged; │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: destroy │ │ │ │ + * Method: setSize │ │ │ │ + * Set the size of the drawing surface │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * size - {<OpenLayers.Size>} the size of the drawing surface │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - for (var i = this.events.length - 1; i >= 0; --i) { │ │ │ │ - this.target.unregister(this.events[i], this, this.buttonClick); │ │ │ │ + setSize: function(size) { │ │ │ │ + OpenLayers.Renderer.prototype.setSize.apply(this, arguments); │ │ │ │ + │ │ │ │ + // setting width and height on all roots to avoid flicker which we │ │ │ │ + // would get with 100% width and height on child roots │ │ │ │ + var roots = [ │ │ │ │ + this.rendererRoot, │ │ │ │ + this.root, │ │ │ │ + this.vectorRoot, │ │ │ │ + this.textRoot │ │ │ │ + ]; │ │ │ │ + var w = this.size.w + "px"; │ │ │ │ + var h = this.size.h + "px"; │ │ │ │ + var root; │ │ │ │ + for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ + root = roots[i]; │ │ │ │ + root.style.width = w; │ │ │ │ + root.style.height = h; │ │ │ │ } │ │ │ │ - delete this.target; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getPressedButton │ │ │ │ - * Get the pressed button, if any. Returns undefined if no button │ │ │ │ - * was pressed. │ │ │ │ + * Method: getNodeType │ │ │ │ + * Get the node type for a geometry and style │ │ │ │ * │ │ │ │ - * Arguments: │ │ │ │ - * element - {DOMElement} The event target. │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * style - {Object} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} The button element, or undefined. │ │ │ │ + * {String} The corresponding node type for the specified geometry │ │ │ │ */ │ │ │ │ - getPressedButton: function(element) { │ │ │ │ - var depth = 3, // limit the search depth │ │ │ │ - button; │ │ │ │ - do { │ │ │ │ - if (OpenLayers.Element.hasClass(element, "olButton")) { │ │ │ │ - // hit! │ │ │ │ - button = element; │ │ │ │ + getNodeType: function(geometry, style) { │ │ │ │ + var nodeType = null; │ │ │ │ + switch (geometry.CLASS_NAME) { │ │ │ │ + case "OpenLayers.Geometry.Point": │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + nodeType = "olv:rect"; │ │ │ │ + } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ + nodeType = "olv:shape"; │ │ │ │ + } else { │ │ │ │ + nodeType = "olv:oval"; │ │ │ │ + } │ │ │ │ break; │ │ │ │ - } │ │ │ │ - element = element.parentNode; │ │ │ │ - } while (--depth > 0 && element); │ │ │ │ - return button; │ │ │ │ + case "OpenLayers.Geometry.Rectangle": │ │ │ │ + nodeType = "olv:rect"; │ │ │ │ + break; │ │ │ │ + case "OpenLayers.Geometry.LineString": │ │ │ │ + case "OpenLayers.Geometry.LinearRing": │ │ │ │ + case "OpenLayers.Geometry.Polygon": │ │ │ │ + case "OpenLayers.Geometry.Curve": │ │ │ │ + nodeType = "olv:shape"; │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + return nodeType; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: ignore │ │ │ │ - * Check for event target elements that should be ignored by OpenLayers. │ │ │ │ + * Method: setStyle │ │ │ │ + * Use to set all the style attributes to a VML node. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * element - {DOMElement} The event target. │ │ │ │ + * node - {DOMElement} An VML element to decorate │ │ │ │ + * style - {Object} │ │ │ │ + * options - {Object} Currently supported options include │ │ │ │ + * 'isFilled' {Boolean} and │ │ │ │ + * 'isStroked' {Boolean} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ */ │ │ │ │ - ignore: function(element) { │ │ │ │ - var depth = 3, │ │ │ │ - ignore = false; │ │ │ │ - do { │ │ │ │ - if (element.nodeName.toLowerCase() === 'a') { │ │ │ │ - ignore = true; │ │ │ │ - break; │ │ │ │ + setStyle: function(node, style, options, geometry) { │ │ │ │ + style = style || node._style; │ │ │ │ + options = options || node._options; │ │ │ │ + var fillColor = style.fillColor; │ │ │ │ + │ │ │ │ + var title = style.title || style.graphicTitle; │ │ │ │ + if (title) { │ │ │ │ + node.title = title; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + options.isFilled = true; │ │ │ │ + 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 resolution = this.getResolution(); │ │ │ │ + var xOffset = (style.graphicXOffset != undefined) ? │ │ │ │ + style.graphicXOffset : -(0.5 * width); │ │ │ │ + var yOffset = (style.graphicYOffset != undefined) ? │ │ │ │ + style.graphicYOffset : -(0.5 * height); │ │ │ │ + │ │ │ │ + node.style.left = ((((geometry.x - this.featureDx) / resolution - this.offset.x) + xOffset) | 0) + "px"; │ │ │ │ + node.style.top = (((geometry.y / resolution - this.offset.y) - (yOffset + height)) | 0) + "px"; │ │ │ │ + node.style.width = width + "px"; │ │ │ │ + node.style.height = height + "px"; │ │ │ │ + node.style.flip = "y"; │ │ │ │ + │ │ │ │ + // modify fillColor and options for stroke styling below │ │ │ │ + fillColor = "none"; │ │ │ │ + options.isStroked = false; │ │ │ │ + } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ + var cache = this.importSymbol(style.graphicName); │ │ │ │ + node.path = cache.path; │ │ │ │ + node.coordorigin = cache.left + "," + cache.bottom; │ │ │ │ + var size = cache.size; │ │ │ │ + node.coordsize = size + "," + size; │ │ │ │ + this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ + node.style.flip = "y"; │ │ │ │ + } else { │ │ │ │ + this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + // fill │ │ │ │ + if (options.isFilled) { │ │ │ │ + node.fillcolor = fillColor; │ │ │ │ + } else { │ │ │ │ + node.filled = "false"; │ │ │ │ + } │ │ │ │ + var fills = node.getElementsByTagName("fill"); │ │ │ │ + var fill = (fills.length == 0) ? null : fills[0]; │ │ │ │ + if (!options.isFilled) { │ │ │ │ + if (fill) { │ │ │ │ + node.removeChild(fill); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (!fill) { │ │ │ │ + fill = this.createNode('olv:fill', node.id + "_fill"); │ │ │ │ + } │ │ │ │ + fill.opacity = style.fillOpacity; │ │ │ │ │ │ │ │ - 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 (node._geometryClass === "OpenLayers.Geometry.Point" && │ │ │ │ + style.externalGraphic) { │ │ │ │ + │ │ │ │ + // override fillOpacity │ │ │ │ + if (style.graphicOpacity) { │ │ │ │ + fill.opacity = style.graphicOpacity; │ │ │ │ } │ │ │ │ - if (this.startRegEx.test(evt.type)) { │ │ │ │ - this.startEvt = evt; │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - propagate = false; │ │ │ │ + │ │ │ │ + fill.src = style.externalGraphic; │ │ │ │ + fill.type = "frame"; │ │ │ │ + │ │ │ │ + if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ + fill.aspect = "atmost"; │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - propagate = !this.ignore(OpenLayers.Event.element(evt)); │ │ │ │ - delete this.startEvt; │ │ │ │ + } │ │ │ │ + if (fill.parentNode != node) { │ │ │ │ + node.appendChild(fill); │ │ │ │ } │ │ │ │ } │ │ │ │ - return propagate; │ │ │ │ - } │ │ │ │ │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/Panel.js │ │ │ │ - ====================================================================== */ │ │ │ │ + // additional rendering for rotated graphics or symbols │ │ │ │ + var rotation = style.rotation; │ │ │ │ + if ((rotation !== undefined || node._rotation !== undefined)) { │ │ │ │ + node._rotation = rotation; │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ + // make the fill fully transparent, because we now have │ │ │ │ + // the graphic as imagedata element. We cannot just remove │ │ │ │ + // the fill, because this is part of the hack described │ │ │ │ + // in graphicRotate │ │ │ │ + fill.opacity = 0; │ │ │ │ + } else if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ + node.style.rotation = rotation || 0; │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ -/* 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. */ │ │ │ │ + // stroke │ │ │ │ + var strokes = node.getElementsByTagName("stroke"); │ │ │ │ + var stroke = (strokes.length == 0) ? null : strokes[0]; │ │ │ │ + if (!options.isStroked) { │ │ │ │ + node.stroked = false; │ │ │ │ + if (stroke) { │ │ │ │ + stroke.on = false; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (!stroke) { │ │ │ │ + stroke = this.createNode('olv:stroke', node.id + "_stroke"); │ │ │ │ + node.appendChild(stroke); │ │ │ │ + } │ │ │ │ + stroke.on = true; │ │ │ │ + stroke.color = style.strokeColor; │ │ │ │ + stroke.weight = style.strokeWidth + "px"; │ │ │ │ + stroke.opacity = style.strokeOpacity; │ │ │ │ + stroke.endcap = style.strokeLinecap == 'butt' ? 'flat' : │ │ │ │ + (style.strokeLinecap || 'round'); │ │ │ │ + if (style.strokeDashstyle) { │ │ │ │ + stroke.dashstyle = this.dashStyle(style); │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Control.js │ │ │ │ - * @requires OpenLayers/Events/buttonclick.js │ │ │ │ - */ │ │ │ │ + if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ + node.style.cursor = style.cursor; │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ │ │ │ │ -/** │ │ │ │ - * 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>)} │ │ │ │ + * Method: graphicRotate │ │ │ │ + * If a point is to be styled with externalGraphic and rotation, VML fills │ │ │ │ + * cannot be used to display the graphic, because rotation of graphic │ │ │ │ + * fills is not supported by the VML implementation of Internet Explorer. │ │ │ │ + * This method creates a olv:imagedata element inside the VML node, │ │ │ │ + * DXImageTransform.Matrix and BasicImage filters for rotation and │ │ │ │ + * opacity, and a 3-step hack to remove rendering artefacts from the │ │ │ │ + * graphic and preserve the ability of graphics to trigger events. │ │ │ │ + * Finally, OpenLayers methods are used to determine the correct │ │ │ │ + * insertion point of the rotated image, because DXImageTransform.Matrix │ │ │ │ + * does the rotation without the ability to specify a rotation center │ │ │ │ + * point. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * xOffset - {Number} rotation center relative to image, x coordinate │ │ │ │ + * yOffset - {Number} rotation center relative to image, y coordinate │ │ │ │ + * style - {Object} │ │ │ │ */ │ │ │ │ - controls: null, │ │ │ │ + graphicRotate: function(node, xOffset, yOffset, style) { │ │ │ │ + var style = style || node._style; │ │ │ │ + var rotation = style.rotation || 0; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ - */ │ │ │ │ - autoActivate: true, │ │ │ │ + var aspectRatio, size; │ │ │ │ + if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ + // load the image to determine its size │ │ │ │ + var img = new Image(); │ │ │ │ + img.onreadystatechange = OpenLayers.Function.bind(function() { │ │ │ │ + if (img.readyState == "complete" || │ │ │ │ + img.readyState == "interactive") { │ │ │ │ + aspectRatio = img.width / img.height; │ │ │ │ + size = Math.max(style.pointRadius * 2, │ │ │ │ + style.graphicWidth || 0, │ │ │ │ + style.graphicHeight || 0); │ │ │ │ + xOffset = xOffset * aspectRatio; │ │ │ │ + style.graphicWidth = size * aspectRatio; │ │ │ │ + style.graphicHeight = size; │ │ │ │ + this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ + } │ │ │ │ + }, this); │ │ │ │ + img.src = style.externalGraphic; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + // will be called again by the onreadystate handler │ │ │ │ + return; │ │ │ │ + } else { │ │ │ │ + size = Math.max(style.graphicWidth, style.graphicHeight); │ │ │ │ + aspectRatio = style.graphicWidth / style.graphicHeight; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + var width = Math.round(style.graphicWidth || size * aspectRatio); │ │ │ │ + var height = Math.round(style.graphicHeight || size); │ │ │ │ + node.style.width = width + "px"; │ │ │ │ + node.style.height = height + "px"; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ + // Three steps are required to remove artefacts for images with │ │ │ │ + // transparent backgrounds (resulting from using DXImageTransform │ │ │ │ + // filters on svg objects), while preserving awareness for browser │ │ │ │ + // events on images: │ │ │ │ + // - Use the fill as usual (like for unrotated images) to handle │ │ │ │ + // events │ │ │ │ + // - specify an imagedata element with the same src as the fill │ │ │ │ + // - style the imagedata element with an AlphaImageLoader filter │ │ │ │ + // with empty src │ │ │ │ + var image = document.getElementById(node.id + "_image"); │ │ │ │ + if (!image) { │ │ │ │ + image = this.createNode("olv:imagedata", node.id + "_image"); │ │ │ │ + node.appendChild(image); │ │ │ │ + } │ │ │ │ + image.style.width = width + "px"; │ │ │ │ + image.style.height = height + "px"; │ │ │ │ + image.src = style.externalGraphic; │ │ │ │ + image.style.filter = │ │ │ │ + "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + │ │ │ │ + "src='', sizingMethod='scale')"; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: activeState │ │ │ │ - * {Object} stores the active state of this panel's controls. │ │ │ │ - */ │ │ │ │ - activeState: null, │ │ │ │ + var rot = rotation * Math.PI / 180; │ │ │ │ + var sintheta = Math.sin(rot); │ │ │ │ + var costheta = Math.cos(rot); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 = {}; │ │ │ │ + // do the rotation on the image │ │ │ │ + var filter = │ │ │ │ + "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta + │ │ │ │ + ",M12=" + (-sintheta) + ",M21=" + sintheta + ",M22=" + costheta + │ │ │ │ + ",SizingMethod='auto expand')\n"; │ │ │ │ + │ │ │ │ + // set the opacity (needed for the imagedata) │ │ │ │ + var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ + if (opacity && opacity != 1) { │ │ │ │ + filter += │ │ │ │ + "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + │ │ │ │ + opacity + ")\n"; │ │ │ │ + } │ │ │ │ + node.style.filter = filter; │ │ │ │ + │ │ │ │ + // do the rotation again on a box, so we know the insertion point │ │ │ │ + var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset); │ │ │ │ + var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry(); │ │ │ │ + imgBox.rotate(style.rotation, centerPoint); │ │ │ │ + var imgBounds = imgBox.getBounds(); │ │ │ │ + │ │ │ │ + node.style.left = Math.round( │ │ │ │ + parseInt(node.style.left) + imgBounds.left) + "px"; │ │ │ │ + node.style.top = Math.round( │ │ │ │ + parseInt(node.style.top) - imgBounds.bottom) + "px"; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ + * Method: postDraw │ │ │ │ + * Does some node postprocessing to work around browser issues: │ │ │ │ + * - Some versions of Internet Explorer seem to be unable to set fillcolor │ │ │ │ + * and strokecolor to "none" correctly before the fill node is appended │ │ │ │ + * to a visible vml node. This method takes care of that and sets │ │ │ │ + * fillcolor and strokecolor again if needed. │ │ │ │ + * - In some cases, a node won't become visible after being drawn. Setting │ │ │ │ + * style.visibility to "visible" works around that. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ + postDraw: function(node) { │ │ │ │ + node.style.visibility = "visible"; │ │ │ │ + var fillColor = node._style.fillColor; │ │ │ │ + var strokeColor = node._style.strokeColor; │ │ │ │ + if (fillColor == "none" && │ │ │ │ + node.fillcolor != fillColor) { │ │ │ │ + node.fillcolor = fillColor; │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + if (strokeColor == "none" && │ │ │ │ + node.strokecolor != strokeColor) { │ │ │ │ + node.strokecolor = strokeColor; │ │ │ │ } │ │ │ │ - this.activeState = null; │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * APIMethod: activate │ │ │ │ + * Method: setNodeDimension │ │ │ │ + * Get the geometry's bounds, convert it to our vml coordinate system, │ │ │ │ + * then set the node's position, size, and local coordinate system. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + setNodeDimension: function(node, geometry) { │ │ │ │ + │ │ │ │ + var bbox = geometry.getBounds(); │ │ │ │ + if (bbox) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + │ │ │ │ + var scaledBox = │ │ │ │ + new OpenLayers.Bounds(((bbox.left - this.featureDx) / resolution - this.offset.x) | 0, │ │ │ │ + (bbox.bottom / resolution - this.offset.y) | 0, │ │ │ │ + ((bbox.right - this.featureDx) / resolution - this.offset.x) | 0, │ │ │ │ + (bbox.top / resolution - this.offset.y) | 0); │ │ │ │ + │ │ │ │ + // Set the internal coordinate system to draw the path │ │ │ │ + node.style.left = scaledBox.left + "px"; │ │ │ │ + node.style.top = scaledBox.top + "px"; │ │ │ │ + node.style.width = scaledBox.getWidth() + "px"; │ │ │ │ + node.style.height = scaledBox.getHeight() + "px"; │ │ │ │ + │ │ │ │ + node.coordorigin = scaledBox.left + " " + scaledBox.top; │ │ │ │ + node.coordsize = scaledBox.getWidth() + " " + scaledBox.getHeight(); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ + /** │ │ │ │ + * Method: dashStyle │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * style - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A VML compliant 'stroke-dasharray' value │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + dashStyle: function(style) { │ │ │ │ + var dash = style.strokeDashstyle; │ │ │ │ + switch (dash) { │ │ │ │ + case 'solid': │ │ │ │ + case 'dot': │ │ │ │ + case 'dash': │ │ │ │ + case 'dashdot': │ │ │ │ + case 'longdash': │ │ │ │ + case 'longdashdot': │ │ │ │ + return dash; │ │ │ │ + default: │ │ │ │ + // very basic guessing of dash style patterns │ │ │ │ + var parts = dash.split(/[ ,]/); │ │ │ │ + if (parts.length == 2) { │ │ │ │ + if (1 * parts[0] >= 2 * parts[1]) { │ │ │ │ + return "longdash"; │ │ │ │ + } │ │ │ │ + return (parts[0] == 1 || parts[1] == 1) ? "dot" : "dash"; │ │ │ │ + } else if (parts.length == 4) { │ │ │ │ + return (1 * parts[0] >= 2 * parts[1]) ? "longdashdot" : │ │ │ │ + "dashdot"; │ │ │ │ + } │ │ │ │ + return "solid"; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: draw │ │ │ │ + * Method: createNode │ │ │ │ + * Create a new node │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * type - {String} Kind of node to draw │ │ │ │ + * id - {String} Id for node │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * {DOMElement} A new node of the given type and id │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + createNode: function(type, id) { │ │ │ │ + var node = document.createElement(type); │ │ │ │ + if (id) { │ │ │ │ + node.id = id; │ │ │ │ } │ │ │ │ - this.addControlsToMap(this.controls); │ │ │ │ - return this.div; │ │ │ │ + │ │ │ │ + // IE hack to make elements unselectable, to prevent 'blue flash' │ │ │ │ + // while dragging vectors; #1410 │ │ │ │ + node.unselectable = 'on'; │ │ │ │ + node.onselectstart = OpenLayers.Function.False; │ │ │ │ + │ │ │ │ + return node; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: redraw │ │ │ │ + * Method: nodeTypeCompare │ │ │ │ + * Determine whether a node is of a given type │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} An VML element │ │ │ │ + * type - {String} Kind of node │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Whether or not the specified node is of the specified type │ │ │ │ */ │ │ │ │ - redraw: function() { │ │ │ │ - for (var l = this.div.childNodes.length, i = l - 1; i >= 0; i--) { │ │ │ │ - this.div.removeChild(this.div.childNodes[i]); │ │ │ │ + nodeTypeCompare: function(node, type) { │ │ │ │ + │ │ │ │ + //split type │ │ │ │ + var subType = type; │ │ │ │ + var splitIndex = subType.indexOf(":"); │ │ │ │ + if (splitIndex != -1) { │ │ │ │ + subType = subType.substr(splitIndex + 1); │ │ │ │ } │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + │ │ │ │ + //split nodeName │ │ │ │ + var nodeName = node.nodeName; │ │ │ │ + splitIndex = nodeName.indexOf(":"); │ │ │ │ + if (splitIndex != -1) { │ │ │ │ + nodeName = nodeName.substr(splitIndex + 1); │ │ │ │ } │ │ │ │ + │ │ │ │ + return (subType == nodeName); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: activateControl │ │ │ │ - * This method is called when the user click on the icon representing a │ │ │ │ - * control in the panel. │ │ │ │ + * Method: createRenderRoot │ │ │ │ + * Create the renderer root │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * control - {<OpenLayers.Control>} │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} The specific render engine's root element │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ + createRenderRoot: function() { │ │ │ │ + return this.nodeFactory(this.container.id + "_vmlRoot", "div"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + * Method: createRoot │ │ │ │ + * Create the main root element │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * controls - {<OpenLayers.Control>} Controls to add in the panel. │ │ │ │ + * suffix - {String} suffix to append to the id │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - addControls: function(controls) { │ │ │ │ - if (!(OpenLayers.Util.isArray(controls))) { │ │ │ │ - controls = [controls]; │ │ │ │ - } │ │ │ │ - this.controls = this.controls.concat(controls); │ │ │ │ + createRoot: function(suffix) { │ │ │ │ + return this.nodeFactory(this.container.id + suffix, "olv:group"); │ │ │ │ + }, │ │ │ │ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + /************************************** │ │ │ │ + * * │ │ │ │ + * GEOMETRY DRAWING FUNCTIONS * │ │ │ │ + * * │ │ │ │ + **************************************/ │ │ │ │ │ │ │ │ - if (this.map) { // map.addControl() has already been called on the panel │ │ │ │ - this.addControlsToMap(controls); │ │ │ │ - this.redraw(); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Method: drawPoint │ │ │ │ + * Render a point │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} or false if the point could not be drawn │ │ │ │ + */ │ │ │ │ + drawPoint: function(node, geometry) { │ │ │ │ + return this.drawCircle(node, geometry, 1); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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) │ │ │ │ - * │ │ │ │ + * Method: drawCircle │ │ │ │ + * Render a circle. │ │ │ │ + * Size and Center a circle given geometry (x,y center) and radius │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * control - {<OpenLayers.Control>} The control to create the HTML │ │ │ │ - * markup for. │ │ │ │ - * │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * radius - {float} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} The markup. │ │ │ │ + * {DOMElement} or false if the circle could not ne drawn │ │ │ │ */ │ │ │ │ - createControlMarkup: function(control) { │ │ │ │ - return document.createElement("div"); │ │ │ │ + drawCircle: function(node, geometry, radius) { │ │ │ │ + if (!isNaN(geometry.x) && !isNaN(geometry.y)) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + │ │ │ │ + node.style.left = ((((geometry.x - this.featureDx) / resolution - this.offset.x) | 0) - radius) + "px"; │ │ │ │ + node.style.top = (((geometry.y / resolution - this.offset.y) | 0) - radius) + "px"; │ │ │ │ + │ │ │ │ + var diameter = radius * 2; │ │ │ │ + │ │ │ │ + node.style.width = diameter + "px"; │ │ │ │ + node.style.height = diameter + "px"; │ │ │ │ + return node; │ │ │ │ + } │ │ │ │ + return false; │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: addControlsToMap │ │ │ │ - * Only for internal use in draw() and addControls() methods. │ │ │ │ - * │ │ │ │ + * Method: drawLineString │ │ │ │ + * Render a linestring. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * controls - {Array(<OpenLayers.Control>)} Controls to add into map. │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ - } │ │ │ │ + drawLineString: function(node, geometry) { │ │ │ │ + return this.drawLine(node, geometry, false); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: iconOn │ │ │ │ - * Internal use, for use only with "controls[i].events.on/un". │ │ │ │ + * Method: drawLinearRing │ │ │ │ + * Render a linearring │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ + drawLinearRing: function(node, geometry) { │ │ │ │ + return this.drawLine(node, geometry, true); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: iconOff │ │ │ │ - * Internal use, for use only with "controls[i].events.on/un". │ │ │ │ + * Method: DrawLine │ │ │ │ + * Render a line. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * closeLine - {Boolean} Close the line? (make it a ring?) │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ + drawLine: function(node, geometry, closeLine) { │ │ │ │ + │ │ │ │ + this.setNodeDimension(node, geometry); │ │ │ │ + │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var numComponents = geometry.components.length; │ │ │ │ + var parts = new Array(numComponents); │ │ │ │ + │ │ │ │ + var comp, x, y; │ │ │ │ + for (var i = 0; i < numComponents; i++) { │ │ │ │ + comp = geometry.components[i]; │ │ │ │ + x = ((comp.x - this.featureDx) / resolution - this.offset.x) | 0; │ │ │ │ + y = (comp.y / resolution - this.offset.y) | 0; │ │ │ │ + parts[i] = " " + x + "," + y + " l "; │ │ │ │ + } │ │ │ │ + var end = (closeLine) ? " x e" : " e"; │ │ │ │ + node.path = "m" + parts.join("") + end; │ │ │ │ + return node; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onButtonClick │ │ │ │ - * │ │ │ │ + * Method: drawPolygon │ │ │ │ + * Render a polygon │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + drawPolygon: function(node, geometry) { │ │ │ │ + this.setNodeDimension(node, geometry); │ │ │ │ + │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + │ │ │ │ + var path = []; │ │ │ │ + var j, jj, points, area, first, second, i, ii, comp, pathComp, x, y; │ │ │ │ + for (j = 0, jj = geometry.components.length; j < jj; j++) { │ │ │ │ + path.push("m"); │ │ │ │ + points = geometry.components[j].components; │ │ │ │ + // we only close paths of interior rings with area │ │ │ │ + area = (j === 0); │ │ │ │ + first = null; │ │ │ │ + second = null; │ │ │ │ + for (i = 0, ii = points.length; i < ii; i++) { │ │ │ │ + comp = points[i]; │ │ │ │ + x = ((comp.x - this.featureDx) / resolution - this.offset.x) | 0; │ │ │ │ + y = (comp.y / resolution - this.offset.y) | 0; │ │ │ │ + pathComp = " " + x + "," + y; │ │ │ │ + path.push(pathComp); │ │ │ │ + if (i == 0) { │ │ │ │ + path.push(" l"); │ │ │ │ + } │ │ │ │ + if (!area) { │ │ │ │ + // IE improperly renders sub-paths that have no area. │ │ │ │ + // Instead of checking the area of every ring, we confirm │ │ │ │ + // the ring has at least three distinct points. This does │ │ │ │ + // not catch all non-zero area cases, but it greatly improves │ │ │ │ + // interior ring digitizing and is a minor performance hit │ │ │ │ + // when rendering rings with many points. │ │ │ │ + if (!first) { │ │ │ │ + first = pathComp; │ │ │ │ + } else if (first != pathComp) { │ │ │ │ + if (!second) { │ │ │ │ + second = pathComp; │ │ │ │ + } else if (second != pathComp) { │ │ │ │ + // stop looking │ │ │ │ + area = true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ + path.push(area ? " x " : " "); │ │ │ │ } │ │ │ │ + path.push("e"); │ │ │ │ + node.path = path.join(""); │ │ │ │ + return node; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getControlsBy │ │ │ │ - * Get a list of controls with properties matching the given criteria. │ │ │ │ - * │ │ │ │ + * Method: drawRectangle │ │ │ │ + * Render a rectangle │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ - * │ │ │ │ + * node - {DOMElement} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Array(<OpenLayers.Control>)} A list of controls matching the given criteria. │ │ │ │ - * An empty array is returned if no matches are found. │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + drawRectangle: function(node, geometry) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + │ │ │ │ + node.style.left = (((geometry.x - this.featureDx) / resolution - this.offset.x) | 0) + "px"; │ │ │ │ + node.style.top = ((geometry.y / resolution - this.offset.y) | 0) + "px"; │ │ │ │ + node.style.width = ((geometry.width / resolution) | 0) + "px"; │ │ │ │ + node.style.height = ((geometry.height / resolution) | 0) + "px"; │ │ │ │ + │ │ │ │ + return node; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getControlsByName │ │ │ │ - * Get a list of contorls with names matching the given name. │ │ │ │ - * │ │ │ │ + * 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 label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect"); │ │ │ │ + var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox"); │ │ │ │ + │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + label.style.left = (((location.x - this.featureDx) / resolution - this.offset.x) | 0) + "px"; │ │ │ │ + label.style.top = ((location.y / resolution - this.offset.y) | 0) + "px"; │ │ │ │ + label.style.flip = "y"; │ │ │ │ + │ │ │ │ + textbox.innerText = style.label; │ │ │ │ + │ │ │ │ + if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ + textbox.style.cursor = style.cursor; │ │ │ │ + } │ │ │ │ + if (style.fontColor) { │ │ │ │ + textbox.style.color = style.fontColor; │ │ │ │ + } │ │ │ │ + if (style.fontOpacity) { │ │ │ │ + textbox.style.filter = 'alpha(opacity=' + (style.fontOpacity * 100) + ')'; │ │ │ │ + } │ │ │ │ + if (style.fontFamily) { │ │ │ │ + textbox.style.fontFamily = style.fontFamily; │ │ │ │ + } │ │ │ │ + if (style.fontSize) { │ │ │ │ + textbox.style.fontSize = style.fontSize; │ │ │ │ + } │ │ │ │ + if (style.fontWeight) { │ │ │ │ + textbox.style.fontWeight = style.fontWeight; │ │ │ │ + } │ │ │ │ + if (style.fontStyle) { │ │ │ │ + textbox.style.fontStyle = style.fontStyle; │ │ │ │ + } │ │ │ │ + if (style.labelSelect === true) { │ │ │ │ + label._featureId = featureId; │ │ │ │ + textbox._featureId = featureId; │ │ │ │ + textbox._geometry = location; │ │ │ │ + textbox._geometryClass = location.CLASS_NAME; │ │ │ │ + } │ │ │ │ + textbox.style.whiteSpace = "nowrap"; │ │ │ │ + // fun with IE: IE7 in standards compliant mode does not display any │ │ │ │ + // text with a left inset of 0. So we set this to 1px and subtract one │ │ │ │ + // pixel later when we set label.style.left │ │ │ │ + textbox.inset = "1px,0px,0px,0px"; │ │ │ │ + │ │ │ │ + if (!label.parentNode) { │ │ │ │ + label.appendChild(textbox); │ │ │ │ + this.textRoot.appendChild(label); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var align = style.labelAlign || "cm"; │ │ │ │ + if (align.length == 1) { │ │ │ │ + align += "m"; │ │ │ │ + } │ │ │ │ + var xshift = textbox.clientWidth * │ │ │ │ + (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0, 1)]); │ │ │ │ + var yshift = textbox.clientHeight * │ │ │ │ + (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1, 1)]); │ │ │ │ + label.style.left = parseInt(label.style.left) - xshift - 1 + "px"; │ │ │ │ + label.style.top = parseInt(label.style.top) + yshift + "px"; │ │ │ │ + │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveRoot │ │ │ │ + * moves this renderer's root to a different renderer. │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ - * │ │ │ │ + * renderer - {<OpenLayers.Renderer>} target renderer for the moved root │ │ │ │ + * root - {DOMElement} optional root node. To be used when this renderer │ │ │ │ + * holds roots from multiple layers to tell this method which one to │ │ │ │ + * detach │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Array(<OpenLayers.Control>)} A list of controls matching the given name. │ │ │ │ - * An empty array is returned if no matches are found. │ │ │ │ + * {Boolean} true if successful, false otherwise │ │ │ │ */ │ │ │ │ - getControlsByName: function(match) { │ │ │ │ - return this.getControlsBy("name", match); │ │ │ │ + moveRoot: function(renderer) { │ │ │ │ + var layer = this.map.getLayer(renderer.container.id); │ │ │ │ + if (layer instanceof OpenLayers.Layer.Vector.RootContainer) { │ │ │ │ + layer = this.map.getLayer(this.container.id); │ │ │ │ + } │ │ │ │ + layer && layer.renderer.clear(); │ │ │ │ + OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments); │ │ │ │ + layer && layer.redraw(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getControlsByClass │ │ │ │ - * Get a list of controls of a given type (CLASS_NAME). │ │ │ │ - * │ │ │ │ + * Method: importSymbol │ │ │ │ + * add a new symbol definition from the rendererer's symbol hash │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ - * │ │ │ │ + * graphicName - {String} name of the symbol to import │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Array(<OpenLayers.Control>)} A list of controls matching the given type. │ │ │ │ - * An empty array is returned if no matches are found. │ │ │ │ + * {Object} - hash of {DOMElement} "symbol" and {Number} "size" │ │ │ │ */ │ │ │ │ - getControlsByClass: function(match) { │ │ │ │ - return this.getControlsBy("CLASS_NAME", match); │ │ │ │ + importSymbol: function(graphicName) { │ │ │ │ + var id = this.container.id + "-" + graphicName; │ │ │ │ + │ │ │ │ + // check if symbol already exists in the cache │ │ │ │ + var cache = this.symbolCache[id]; │ │ │ │ + if (cache) { │ │ │ │ + return cache; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var symbol = OpenLayers.Renderer.symbol[graphicName]; │ │ │ │ + if (!symbol) { │ │ │ │ + throw new Error(graphicName + ' is not a valid symbol name'); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var symbolExtent = new OpenLayers.Bounds( │ │ │ │ + Number.MAX_VALUE, Number.MAX_VALUE, 0, 0); │ │ │ │ + │ │ │ │ + var pathitems = ["m"]; │ │ │ │ + for (var i = 0; i < symbol.length; i = i + 2) { │ │ │ │ + var x = symbol[i]; │ │ │ │ + var 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); │ │ │ │ + │ │ │ │ + pathitems.push(x); │ │ │ │ + pathitems.push(y); │ │ │ │ + if (i == 0) { │ │ │ │ + pathitems.push("l"); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + pathitems.push("x e"); │ │ │ │ + var path = pathitems.join(" "); │ │ │ │ + │ │ │ │ + var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2; │ │ │ │ + if (diff > 0) { │ │ │ │ + symbolExtent.bottom = symbolExtent.bottom - diff; │ │ │ │ + symbolExtent.top = symbolExtent.top + diff; │ │ │ │ + } else { │ │ │ │ + symbolExtent.left = symbolExtent.left + diff; │ │ │ │ + symbolExtent.right = symbolExtent.right - diff; │ │ │ │ + } │ │ │ │ + │ │ │ │ + cache = { │ │ │ │ + path: path, │ │ │ │ + size: symbolExtent.getWidth(), // equals getHeight() now │ │ │ │ + left: symbolExtent.left, │ │ │ │ + bottom: symbolExtent.bottom │ │ │ │ + }; │ │ │ │ + this.symbolCache[id] = cache; │ │ │ │ + │ │ │ │ + return cache; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Panel" │ │ │ │ + CLASS_NAME: "OpenLayers.Renderer.VML" │ │ │ │ }); │ │ │ │ │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Renderer.VML.LABEL_SHIFT │ │ │ │ + * {Object} │ │ │ │ + */ │ │ │ │ +OpenLayers.Renderer.VML.LABEL_SHIFT = { │ │ │ │ + "l": 0, │ │ │ │ + "c": .5, │ │ │ │ + "r": 1, │ │ │ │ + "t": 0, │ │ │ │ + "m": .5, │ │ │ │ + "b": 1 │ │ │ │ +}; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Snapping.js │ │ │ │ + OpenLayers/Strategy/Cluster.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/Layer/Vector.js │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Snapping │ │ │ │ - * Acts as a snapping agent while editing vector features. │ │ │ │ + * Class: OpenLayers.Strategy.Cluster │ │ │ │ + * Strategy for vector feature clustering. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * - <OpenLayers.Strategy> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.Snapping = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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>): │ │ │ │ - * beforesnap - Triggered before a snap occurs. Listeners receive an │ │ │ │ - * event object with *point*, *x*, *y*, *distance*, *layer*, and │ │ │ │ - * *snapType* properties. The point property will be original point │ │ │ │ - * geometry considered for snapping. The x and y properties represent │ │ │ │ - * coordinates the point will receive. The distance is the distance │ │ │ │ - * of the snap. The layer is the target layer. The snapType property │ │ │ │ - * will be one of "node", "vertex", or "edge". Return false to stop │ │ │ │ - * snapping from occurring. │ │ │ │ - * snap - Triggered when a snap occurs. Listeners receive an event with │ │ │ │ - * *point*, *snapType*, *layer*, and *distance* properties. The point │ │ │ │ - * will be the location snapped to. The snapType will be one of "node", │ │ │ │ - * "vertex", or "edge". The layer will be the target layer. The │ │ │ │ - * distance will be the distance of the snap in map units. │ │ │ │ - * unsnap - Triggered when a vertex is unsnapped. Listeners receive an │ │ │ │ - * event with a *point* property. │ │ │ │ + /** │ │ │ │ + * APIProperty: distance │ │ │ │ + * {Integer} Pixel distance between features that should be considered a │ │ │ │ + * single cluster. Default is 20 pixels. │ │ │ │ */ │ │ │ │ + distance: 20, │ │ │ │ │ │ │ │ /** │ │ │ │ - * CONSTANT: DEFAULTS │ │ │ │ - * Default target properties. │ │ │ │ + * APIProperty: threshold │ │ │ │ + * {Integer} Optional threshold below which original features will be │ │ │ │ + * added to the layer instead of clusters. For example, a threshold │ │ │ │ + * of 3 would mean that any time there are 2 or fewer features in │ │ │ │ + * a cluster, those features will be added directly to the layer instead │ │ │ │ + * of a cluster representing those features. Default is null (which is │ │ │ │ + * equivalent to 1 - meaning that clusters may contain just one feature). │ │ │ │ */ │ │ │ │ - DEFAULTS: { │ │ │ │ - tolerance: 10, │ │ │ │ - node: true, │ │ │ │ - edge: true, │ │ │ │ - vertex: true │ │ │ │ - }, │ │ │ │ + threshold: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: greedy │ │ │ │ - * {Boolean} Snap to closest feature in first layer with an eligible │ │ │ │ - * feature. Default is true. │ │ │ │ + * Property: features │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} Cached features. │ │ │ │ */ │ │ │ │ - greedy: true, │ │ │ │ + features: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: precedence │ │ │ │ - * {Array} List representing precedence of different snapping types. │ │ │ │ - * Default is "node", "vertex", "edge". │ │ │ │ + * Property: clusters │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} Calculated clusters. │ │ │ │ */ │ │ │ │ - precedence: ["node", "vertex", "edge"], │ │ │ │ + clusters: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: resolution │ │ │ │ - * {Float} The map resolution for the previously considered snap. │ │ │ │ + * Property: clustering │ │ │ │ + * {Boolean} The strategy is currently clustering features. │ │ │ │ */ │ │ │ │ - resolution: null, │ │ │ │ + clustering: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: geoToleranceCache │ │ │ │ - * {Object} A cache of geo-tolerances. Tolerance values (in map units) are │ │ │ │ - * calculated when the map resolution changes. │ │ │ │ + * Property: resolution │ │ │ │ + * {Float} The resolution (map units per pixel) of the current cluster set. │ │ │ │ */ │ │ │ │ - geoToleranceCache: null, │ │ │ │ + resolution: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: layer │ │ │ │ - * {<OpenLayers.Layer.Vector>} The current editable layer. Set at │ │ │ │ - * construction or after construction with <setLayer>. │ │ │ │ + * Constructor: OpenLayers.Strategy.Cluster │ │ │ │ + * Create a new clustering strategy. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - layer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: feature │ │ │ │ - * {<OpenLayers.Feature.Vector>} The current editable feature. │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The strategy was successfully activated. │ │ │ │ */ │ │ │ │ - feature: null, │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + "beforefeaturesadded": this.cacheFeatures, │ │ │ │ + "featuresremoved": this.clearCache, │ │ │ │ + "moveend": this.cluster, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + return activated; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: point │ │ │ │ - * {<OpenLayers.Geometry.Point>} The currently snapped vertex. │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ + * tear-down. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ */ │ │ │ │ - point: null, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.clearCache(); │ │ │ │ + this.layer.events.un({ │ │ │ │ + "beforefeaturesadded": this.cacheFeatures, │ │ │ │ + "featuresremoved": this.clearCache, │ │ │ │ + "moveend": this.cluster, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + return deactivated; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.Snapping │ │ │ │ - * Creates a new snapping control. A control is constructed with an editable │ │ │ │ - * layer and a set of configuration objects for target layers. While the │ │ │ │ - * control is active, dragging vertices while drawing new features or │ │ │ │ - * modifying existing features on the editable layer will engage │ │ │ │ - * snapping to features on the target layers. Whether a vertex snaps to │ │ │ │ - * a feature on a target layer depends on the target layer configuration. │ │ │ │ + * Method: cacheFeatures │ │ │ │ + * Cache features before they are added to the layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An object containing all configuration properties for │ │ │ │ - * the control. │ │ │ │ - * │ │ │ │ - * Valid options: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} The editable layer. Features from this │ │ │ │ - * layer that are digitized or modified may have vertices snapped to │ │ │ │ - * features from any of the target layers. │ │ │ │ - * targets - {Array(Object | OpenLayers.Layer.Vector)} A list of objects for │ │ │ │ - * configuring target layers. See valid properties of the target │ │ │ │ - * objects below. If the items in the targets list are vector layers │ │ │ │ - * (instead of configuration objects), the defaults from the <defaults> │ │ │ │ - * property will apply. The editable layer itself may be a target │ │ │ │ - * layer, allowing newly created or edited features to be snapped to │ │ │ │ - * existing features from the same layer. If no targets are provided │ │ │ │ - * the layer given in the constructor (as <layer>) will become the │ │ │ │ - * initial target. │ │ │ │ - * defaults - {Object} An object with default properties to be applied │ │ │ │ - * to all target objects. │ │ │ │ - * greedy - {Boolean} Snap to closest feature in first target layer that │ │ │ │ - * applies. Default is true. If false, all features in all target │ │ │ │ - * layers will be checked and the closest feature in all target layers │ │ │ │ - * will be chosen. The greedy property determines if the order of the │ │ │ │ - * target layers is significant. By default, the order of the target │ │ │ │ - * layers is significant where layers earlier in the target layer list │ │ │ │ - * have precedence over layers later in the list. Within a single │ │ │ │ - * layer, the closest feature is always chosen for snapping. This │ │ │ │ - * property only determines whether the search for a closer feature │ │ │ │ - * continues after an eligible feature is found in a target layer. │ │ │ │ - * │ │ │ │ - * Valid target properties: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} A target layer. Features from this │ │ │ │ - * layer will be eligible to act as snapping target for the editable │ │ │ │ - * layer. │ │ │ │ - * tolerance - {Float} The distance (in pixels) at which snapping may occur. │ │ │ │ - * Default is 10. │ │ │ │ - * node - {Boolean} Snap to nodes (first or last point in a geometry) in │ │ │ │ - * target layer. Default is true. │ │ │ │ - * nodeTolerance - {Float} Optional distance at which snapping may occur │ │ │ │ - * for nodes specifically. If none is provided, <tolerance> will be │ │ │ │ - * used. │ │ │ │ - * vertex - {Boolean} Snap to vertices in target layer. Default is true. │ │ │ │ - * vertexTolerance - {Float} Optional distance at which snapping may occur │ │ │ │ - * for vertices specifically. If none is provided, <tolerance> will be │ │ │ │ - * used. │ │ │ │ - * edge - {Boolean} Snap to edges in target layer. Default is true. │ │ │ │ - * edgeTolerance - {Float} Optional distance at which snapping may occur │ │ │ │ - * for edges specifically. If none is provided, <tolerance> will be │ │ │ │ - * used. │ │ │ │ - * filter - {<OpenLayers.Filter>} Optional filter to evaluate to determine if │ │ │ │ - * feature is eligible for snapping. If filter evaluates to true for a │ │ │ │ - * target feature a vertex may be snapped to the feature. │ │ │ │ - * minResolution - {Number} If a minResolution is provided, snapping to this │ │ │ │ - * target will only be considered if the map resolution is greater than │ │ │ │ - * or equal to this value (the minResolution is inclusive). Default is │ │ │ │ - * no minimum resolution limit. │ │ │ │ - * maxResolution - {Number} If a maxResolution is provided, snapping to this │ │ │ │ - * target will only be considered if the map resolution is strictly │ │ │ │ - * less than this value (the maxResolution is exclusive). Default is │ │ │ │ - * no maximum resolution limit. │ │ │ │ + * event - {Object} The event that this was listening for. This will come │ │ │ │ + * with a batch of features to be clustered. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} False to stop features from being added to the layer. │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.options = options || {}; // TODO: this could be done by the super │ │ │ │ - │ │ │ │ - // set the editable layer if provided │ │ │ │ - if (this.options.layer) { │ │ │ │ - this.setLayer(this.options.layer); │ │ │ │ - } │ │ │ │ - // configure target layers │ │ │ │ - var defaults = OpenLayers.Util.extend({}, this.options.defaults); │ │ │ │ - this.defaults = OpenLayers.Util.applyDefaults(defaults, this.DEFAULTS); │ │ │ │ - this.setTargets(this.options.targets); │ │ │ │ - if (this.targets.length === 0 && this.layer) { │ │ │ │ - this.addTargetLayer(this.layer); │ │ │ │ + cacheFeatures: function(event) { │ │ │ │ + var propagate = true; │ │ │ │ + if (!this.clustering) { │ │ │ │ + this.clearCache(); │ │ │ │ + this.features = event.features; │ │ │ │ + this.cluster(); │ │ │ │ + propagate = false; │ │ │ │ } │ │ │ │ - │ │ │ │ - this.geoToleranceCache = {}; │ │ │ │ + return propagate; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setLayer │ │ │ │ - * Set the editable layer. Call the setLayer method if the editable layer │ │ │ │ - * changes and the same control should be used on a new editable layer. │ │ │ │ - * If the control is already active, it will be active after the new │ │ │ │ - * layer is set. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} The new editable layer. │ │ │ │ + * Method: clearCache │ │ │ │ + * Clear out the cached features. │ │ │ │ */ │ │ │ │ - setLayer: function(layer) { │ │ │ │ - if (this.active) { │ │ │ │ - this.deactivate(); │ │ │ │ - this.layer = layer; │ │ │ │ - this.activate(); │ │ │ │ - } else { │ │ │ │ - this.layer = layer; │ │ │ │ + clearCache: function() { │ │ │ │ + if (!this.clustering) { │ │ │ │ + this.features = null; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setTargets │ │ │ │ - * Set the targets for the snapping agent. │ │ │ │ + * Method: cluster │ │ │ │ + * Cluster features based on some threshold distance. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * targets - {Array} An array of target configs or target layers. │ │ │ │ + * event - {Object} The event received when cluster is called as a │ │ │ │ + * result of a moveend event. │ │ │ │ */ │ │ │ │ - setTargets: function(targets) { │ │ │ │ - this.targets = []; │ │ │ │ - if (targets && targets.length) { │ │ │ │ - var target; │ │ │ │ - for (var i = 0, len = targets.length; i < len; ++i) { │ │ │ │ - target = targets[i]; │ │ │ │ - if (target instanceof OpenLayers.Layer.Vector) { │ │ │ │ - this.addTargetLayer(target); │ │ │ │ - } else { │ │ │ │ - this.addTarget(target); │ │ │ │ + cluster: function(event) { │ │ │ │ + if ((!event || event.zoomChanged) && this.features) { │ │ │ │ + var resolution = this.layer.map.getResolution(); │ │ │ │ + if (resolution != this.resolution || !this.clustersExist()) { │ │ │ │ + this.resolution = resolution; │ │ │ │ + var clusters = []; │ │ │ │ + var feature, clustered, cluster; │ │ │ │ + for (var i = 0; i < this.features.length; ++i) { │ │ │ │ + feature = this.features[i]; │ │ │ │ + if (feature.geometry) { │ │ │ │ + clustered = false; │ │ │ │ + for (var j = clusters.length - 1; j >= 0; --j) { │ │ │ │ + cluster = clusters[j]; │ │ │ │ + if (this.shouldCluster(cluster, feature)) { │ │ │ │ + this.addToCluster(cluster, feature); │ │ │ │ + clustered = true; │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (!clustered) { │ │ │ │ + clusters.push(this.createCluster(this.features[i])); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.clustering = true; │ │ │ │ + this.layer.removeAllFeatures(); │ │ │ │ + this.clustering = false; │ │ │ │ + if (clusters.length > 0) { │ │ │ │ + if (this.threshold > 1) { │ │ │ │ + var clone = clusters.slice(); │ │ │ │ + clusters = []; │ │ │ │ + var candidate; │ │ │ │ + for (var i = 0, len = clone.length; i < len; ++i) { │ │ │ │ + candidate = clone[i]; │ │ │ │ + if (candidate.attributes.count < this.threshold) { │ │ │ │ + Array.prototype.push.apply(clusters, candidate.cluster); │ │ │ │ + } else { │ │ │ │ + clusters.push(candidate); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.clustering = true; │ │ │ │ + // A legitimate feature addition could occur during this │ │ │ │ + // addFeatures call. For clustering to behave well, features │ │ │ │ + // should be removed from a layer before requesting a new batch. │ │ │ │ + this.layer.addFeatures(clusters); │ │ │ │ + this.clustering = false; │ │ │ │ } │ │ │ │ + this.clusters = clusters; │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: addTargetLayer │ │ │ │ - * Add a target layer with the default target config. │ │ │ │ + * Method: clustersExist │ │ │ │ + * Determine whether calculated clusters are already on the layer. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} A target layer. │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The calculated clusters are already on the layer. │ │ │ │ */ │ │ │ │ - addTargetLayer: function(layer) { │ │ │ │ - this.addTarget({ │ │ │ │ - layer: layer │ │ │ │ - }); │ │ │ │ + clustersExist: function() { │ │ │ │ + var exist = false; │ │ │ │ + if (this.clusters && this.clusters.length > 0 && │ │ │ │ + this.clusters.length == this.layer.features.length) { │ │ │ │ + exist = true; │ │ │ │ + for (var i = 0; i < this.clusters.length; ++i) { │ │ │ │ + if (this.clusters[i] != this.layer.features[i]) { │ │ │ │ + exist = false; │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return exist; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: addTarget │ │ │ │ - * Add a configured target layer. │ │ │ │ + * Method: shouldCluster │ │ │ │ + * Determine whether to include a feature in a given cluster. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * target - {Object} A target config. │ │ │ │ + * cluster - {<OpenLayers.Feature.Vector>} A cluster. │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} A feature. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The feature should be included in the cluster. │ │ │ │ */ │ │ │ │ - addTarget: function(target) { │ │ │ │ - target = OpenLayers.Util.applyDefaults(target, this.defaults); │ │ │ │ - target.nodeTolerance = target.nodeTolerance || target.tolerance; │ │ │ │ - target.vertexTolerance = target.vertexTolerance || target.tolerance; │ │ │ │ - target.edgeTolerance = target.edgeTolerance || target.tolerance; │ │ │ │ - this.targets.push(target); │ │ │ │ + shouldCluster: function(cluster, feature) { │ │ │ │ + var cc = cluster.geometry.getBounds().getCenterLonLat(); │ │ │ │ + var fc = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ + var distance = ( │ │ │ │ + Math.sqrt( │ │ │ │ + Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2) │ │ │ │ + ) / this.resolution │ │ │ │ + ); │ │ │ │ + return (distance <= this.distance); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: removeTargetLayer │ │ │ │ - * Remove a target layer. │ │ │ │ + * Method: addToCluster │ │ │ │ + * Add a feature to a cluster. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} The target layer to remove. │ │ │ │ + * cluster - {<OpenLayers.Feature.Vector>} A cluster. │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} A feature. │ │ │ │ */ │ │ │ │ - removeTargetLayer: function(layer) { │ │ │ │ - var target; │ │ │ │ - for (var i = this.targets.length - 1; i >= 0; --i) { │ │ │ │ - target = this.targets[i]; │ │ │ │ - if (target.layer === layer) { │ │ │ │ - this.removeTarget(target); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + addToCluster: function(cluster, feature) { │ │ │ │ + cluster.cluster.push(feature); │ │ │ │ + cluster.attributes.count += 1; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: removeTarget │ │ │ │ - * Remove a target. │ │ │ │ + * Method: createCluster │ │ │ │ + * Given a feature, create a cluster. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * target - {Object} A target config. │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Array} The targets array. │ │ │ │ + * {<OpenLayers.Feature.Vector>} A cluster. │ │ │ │ */ │ │ │ │ - removeTarget: function(target) { │ │ │ │ - return OpenLayers.Util.removeItem(this.targets, target); │ │ │ │ + createCluster: function(feature) { │ │ │ │ + var center = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ + var cluster = new OpenLayers.Feature.Vector( │ │ │ │ + new OpenLayers.Geometry.Point(center.lon, center.lat), { │ │ │ │ + count: 1 │ │ │ │ + } │ │ │ │ + ); │ │ │ │ + cluster.cluster = [feature]; │ │ │ │ + return cluster; │ │ │ │ }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Cluster" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Strategy/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/Strategy.js │ │ │ │ + * @requires OpenLayers/Filter.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Strategy.Filter │ │ │ │ + * Strategy for limiting features that get added to a layer by │ │ │ │ + * evaluating a filter. The strategy maintains a cache of │ │ │ │ + * all features until removeFeatures is called on the layer. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Strategy> │ │ │ │ + */ │ │ │ │ +OpenLayers.Strategy.Filter = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the control. Activating the control registers listeners for │ │ │ │ - * editing related events so that during feature creation and │ │ │ │ - * modification, moving vertices will trigger snapping. │ │ │ │ + * APIProperty: filter │ │ │ │ + * {<OpenLayers.Filter>} Filter for limiting features sent to the layer. │ │ │ │ + * Use the <setFilter> method to update this filter after construction. │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - if (this.layer && this.layer.events) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - sketchstarted: this.onSketchModified, │ │ │ │ - sketchmodified: this.onSketchModified, │ │ │ │ - vertexmodified: this.onVertexModified, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return activated; │ │ │ │ - }, │ │ │ │ + filter: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the control. Deactivating the control unregisters listeners │ │ │ │ - * so feature editing may proceed without engaging the snapping agent. │ │ │ │ + * Property: cache │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} List of currently cached │ │ │ │ + * features. │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - if (this.layer && this.layer.events) { │ │ │ │ - this.layer.events.un({ │ │ │ │ - sketchstarted: this.onSketchModified, │ │ │ │ - sketchmodified: this.onSketchModified, │ │ │ │ - vertexmodified: this.onVertexModified, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.feature = null; │ │ │ │ - this.point = null; │ │ │ │ - return deactivated; │ │ │ │ - }, │ │ │ │ + cache: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onSketchModified │ │ │ │ - * Registered as a listener for the sketchmodified event on the editable │ │ │ │ - * layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * event - {Object} The sketch modified event. │ │ │ │ + * Property: caching │ │ │ │ + * {Boolean} The filter is currently caching features. │ │ │ │ */ │ │ │ │ - onSketchModified: function(event) { │ │ │ │ - this.feature = event.feature; │ │ │ │ - this.considerSnapping(event.vertex, event.vertex); │ │ │ │ - }, │ │ │ │ + caching: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onVertexModified │ │ │ │ - * Registered as a listener for the vertexmodified event on the editable │ │ │ │ - * layer. │ │ │ │ + * Constructor: OpenLayers.Strategy.Filter │ │ │ │ + * Create a new filter strategy. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * event - {Object} The vertex modified event. │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - onVertexModified: function(event) { │ │ │ │ - this.feature = event.feature; │ │ │ │ - var loc = this.layer.map.getLonLatFromViewPortPx(event.pixel); │ │ │ │ - this.considerSnapping( │ │ │ │ - event.vertex, new OpenLayers.Geometry.Point(loc.lon, loc.lat) │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: considerSnapping │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ + * By default, this strategy automatically activates itself when a layer │ │ │ │ + * is added to a map. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * point - {<OpenLayers.Geometry.Point>} The vertex to be snapped (or │ │ │ │ - * unsnapped). │ │ │ │ - * loc - {<OpenLayers.Geometry.Point>} The location of the mouse in map │ │ │ │ - * coords. │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ + * the strategy was already active. │ │ │ │ */ │ │ │ │ - considerSnapping: function(point, loc) { │ │ │ │ - var best = { │ │ │ │ - rank: Number.POSITIVE_INFINITY, │ │ │ │ - dist: Number.POSITIVE_INFINITY, │ │ │ │ - x: null, │ │ │ │ - y: null │ │ │ │ - }; │ │ │ │ - var snapped = false; │ │ │ │ - var result, target; │ │ │ │ - for (var i = 0, len = this.targets.length; i < len; ++i) { │ │ │ │ - target = this.targets[i]; │ │ │ │ - result = this.testTarget(target, loc); │ │ │ │ - if (result) { │ │ │ │ - if (this.greedy) { │ │ │ │ - best = result; │ │ │ │ - best.target = target; │ │ │ │ - snapped = true; │ │ │ │ - break; │ │ │ │ - } else { │ │ │ │ - if ((result.rank < best.rank) || │ │ │ │ - (result.rank === best.rank && result.dist < best.dist)) { │ │ │ │ - best = result; │ │ │ │ - best.target = target; │ │ │ │ - snapped = true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (snapped) { │ │ │ │ - var proceed = this.events.triggerEvent("beforesnap", { │ │ │ │ - point: point, │ │ │ │ - x: best.x, │ │ │ │ - y: best.y, │ │ │ │ - distance: best.dist, │ │ │ │ - layer: best.target.layer, │ │ │ │ - snapType: this.precedence[best.rank] │ │ │ │ - }); │ │ │ │ - if (proceed !== false) { │ │ │ │ - point.x = best.x; │ │ │ │ - point.y = best.y; │ │ │ │ - this.point = point; │ │ │ │ - this.events.triggerEvent("snap", { │ │ │ │ - point: point, │ │ │ │ - snapType: this.precedence[best.rank], │ │ │ │ - layer: best.target.layer, │ │ │ │ - distance: best.dist │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - snapped = false; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.point && !snapped) { │ │ │ │ - point.x = loc.x; │ │ │ │ - point.y = loc.y; │ │ │ │ - this.point = null; │ │ │ │ - this.events.triggerEvent("unsnap", { │ │ │ │ - point: point │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments); │ │ │ │ + if (activated) { │ │ │ │ + this.cache = []; │ │ │ │ + this.layer.events.on({ │ │ │ │ + "beforefeaturesadded": this.handleAdd, │ │ │ │ + "beforefeaturesremoved": this.handleRemove, │ │ │ │ + scope: this │ │ │ │ }); │ │ │ │ } │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: testTarget │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * target - {Object} Object with target layer configuration. │ │ │ │ - * loc - {<OpenLayers.Geometry.Point>} The location of the mouse in map │ │ │ │ - * coords. │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the strategy. Clear the feature cache. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} A result object with rank, dist, x, and y properties. │ │ │ │ - * Returns null if candidate is not eligible for snapping. │ │ │ │ + * {Boolean} True if the strategy was successfully deactivated or false if │ │ │ │ + * the strategy was already inactive. │ │ │ │ */ │ │ │ │ - testTarget: function(target, loc) { │ │ │ │ - var resolution = this.layer.map.getResolution(); │ │ │ │ - if ("minResolution" in target) { │ │ │ │ - if (resolution < target.minResolution) { │ │ │ │ - return null; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if ("maxResolution" in target) { │ │ │ │ - if (resolution >= target.maxResolution) { │ │ │ │ - return null; │ │ │ │ - } │ │ │ │ + deactivate: function() { │ │ │ │ + this.cache = null; │ │ │ │ + if (this.layer && this.layer.events) { │ │ │ │ + this.layer.events.un({ │ │ │ │ + "beforefeaturesadded": this.handleAdd, │ │ │ │ + "beforefeaturesremoved": this.handleRemove, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ } │ │ │ │ - var tolerance = { │ │ │ │ - node: this.getGeoTolerance(target.nodeTolerance, resolution), │ │ │ │ - vertex: this.getGeoTolerance(target.vertexTolerance, resolution), │ │ │ │ - edge: this.getGeoTolerance(target.edgeTolerance, resolution) │ │ │ │ - }; │ │ │ │ - // this could be cached if we don't support setting tolerance values directly │ │ │ │ - var maxTolerance = Math.max( │ │ │ │ - tolerance.node, tolerance.vertex, tolerance.edge │ │ │ │ - ); │ │ │ │ - var result = { │ │ │ │ - rank: Number.POSITIVE_INFINITY, │ │ │ │ - dist: Number.POSITIVE_INFINITY │ │ │ │ - }; │ │ │ │ - var eligible = false; │ │ │ │ - var features = target.layer.features; │ │ │ │ - var feature, type, vertices, vertex, closest, dist, found; │ │ │ │ - var numTypes = this.precedence.length; │ │ │ │ - var ll = new OpenLayers.LonLat(loc.x, loc.y); │ │ │ │ - for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - if (feature !== this.feature && !feature._sketch && │ │ │ │ - feature.state !== OpenLayers.State.DELETE && │ │ │ │ - (!target.filter || target.filter.evaluate(feature))) { │ │ │ │ - if (feature.atPoint(ll, maxTolerance, maxTolerance)) { │ │ │ │ - for (var j = 0, stop = Math.min(result.rank + 1, numTypes); j < stop; ++j) { │ │ │ │ - type = this.precedence[j]; │ │ │ │ - if (target[type]) { │ │ │ │ - if (type === "edge") { │ │ │ │ - closest = feature.geometry.distanceTo(loc, { │ │ │ │ - details: true │ │ │ │ - }); │ │ │ │ - dist = closest.distance; │ │ │ │ - if (dist <= tolerance[type] && dist < result.dist) { │ │ │ │ - result = { │ │ │ │ - rank: j, │ │ │ │ - dist: dist, │ │ │ │ - x: closest.x0, │ │ │ │ - y: closest.y0 // closest coords on feature │ │ │ │ - }; │ │ │ │ - eligible = true; │ │ │ │ - // don't look for lower precedence types for this feature │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - // look for nodes or vertices │ │ │ │ - vertices = feature.geometry.getVertices(type === "node"); │ │ │ │ - found = false; │ │ │ │ - for (var k = 0, klen = vertices.length; k < klen; ++k) { │ │ │ │ - vertex = vertices[k]; │ │ │ │ - dist = vertex.distanceTo(loc); │ │ │ │ - if (dist <= tolerance[type] && │ │ │ │ - (j < result.rank || (j === result.rank && dist < result.dist))) { │ │ │ │ - result = { │ │ │ │ - rank: j, │ │ │ │ - dist: dist, │ │ │ │ - x: vertex.x, │ │ │ │ - y: vertex.y │ │ │ │ - }; │ │ │ │ - eligible = true; │ │ │ │ - found = true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (found) { │ │ │ │ - // don't look for lower precedence types for this feature │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + return OpenLayers.Strategy.prototype.deactivate.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: handleAdd │ │ │ │ + */ │ │ │ │ + handleAdd: function(event) { │ │ │ │ + if (!this.caching && this.filter) { │ │ │ │ + var features = event.features; │ │ │ │ + event.features = []; │ │ │ │ + var feature; │ │ │ │ + for (var i = 0, ii = features.length; i < ii; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + if (this.filter.evaluate(feature)) { │ │ │ │ + event.features.push(feature); │ │ │ │ + } else { │ │ │ │ + this.cache.push(feature); │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ - return eligible ? result : null; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getGeoTolerance │ │ │ │ - * Calculate a tolerance in map units given a tolerance in pixels. This │ │ │ │ - * takes advantage of the <geoToleranceCache> when the map resolution │ │ │ │ - * has not changed. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * tolerance - {Number} A tolerance value in pixels. │ │ │ │ - * resolution - {Number} Map resolution. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Number} A tolerance value in map units. │ │ │ │ + * Method: handleRemove │ │ │ │ */ │ │ │ │ - getGeoTolerance: function(tolerance, resolution) { │ │ │ │ - if (resolution !== this.resolution) { │ │ │ │ - this.resolution = resolution; │ │ │ │ - this.geoToleranceCache = {}; │ │ │ │ - } │ │ │ │ - var geoTolerance = this.geoToleranceCache[tolerance]; │ │ │ │ - if (geoTolerance === undefined) { │ │ │ │ - geoTolerance = tolerance * resolution; │ │ │ │ - this.geoToleranceCache[tolerance] = geoTolerance; │ │ │ │ + handleRemove: function(event) { │ │ │ │ + if (!this.caching) { │ │ │ │ + this.cache = []; │ │ │ │ } │ │ │ │ - return geoTolerance; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - * Clean up the control. │ │ │ │ + /** │ │ │ │ + * APIMethod: setFilter │ │ │ │ + * Update the filter for this strategy. This will re-evaluate │ │ │ │ + * any features on the layer and in the cache. Only features │ │ │ │ + * for which filter.evalute(feature) returns true will be │ │ │ │ + * added to the layer. Others will be cached by the strategy. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * filter - {<OpenLayers.Filter>} A filter for evaluating features. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.active) { │ │ │ │ - this.deactivate(); // TODO: this should be handled by the super │ │ │ │ + setFilter: function(filter) { │ │ │ │ + this.filter = filter; │ │ │ │ + var previousCache = this.cache; │ │ │ │ + this.cache = []; │ │ │ │ + // look through layer for features to remove from layer │ │ │ │ + this.handleAdd({ │ │ │ │ + features: this.layer.features │ │ │ │ + }); │ │ │ │ + // cache now contains features to remove from layer │ │ │ │ + if (this.cache.length > 0) { │ │ │ │ + this.caching = true; │ │ │ │ + this.layer.removeFeatures(this.cache.slice()); │ │ │ │ + this.caching = false; │ │ │ │ + } │ │ │ │ + // now look through previous cache for features to add to layer │ │ │ │ + if (previousCache.length > 0) { │ │ │ │ + var event = { │ │ │ │ + features: previousCache │ │ │ │ + }; │ │ │ │ + this.handleAdd(event); │ │ │ │ + if (event.features.length > 0) { │ │ │ │ + // event has features to add to layer │ │ │ │ + this.caching = true; │ │ │ │ + this.layer.addFeatures(event.features); │ │ │ │ + this.caching = false; │ │ │ │ + } │ │ │ │ } │ │ │ │ - delete this.layer; │ │ │ │ - delete this.targets; │ │ │ │ - OpenLayers.Control.prototype.destroy.call(this); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Snapping" │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Filter" │ │ │ │ + │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/CacheWrite.js │ │ │ │ + OpenLayers/Strategy/Refresh.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/Request.js │ │ │ │ - * @requires OpenLayers/Console.js │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.CacheWrite │ │ │ │ - * A control for caching image tiles in the browser's local storage. The │ │ │ │ - * <OpenLayers.Control.CacheRead> control is used to fetch and use the cached │ │ │ │ - * tile images. │ │ │ │ - * │ │ │ │ - * Note: Before using this control on any layer that is not your own, make sure │ │ │ │ - * that the terms of service of the tile provider allow local storage of tiles. │ │ │ │ + * Class: OpenLayers.Strategy.Refresh │ │ │ │ + * A strategy that refreshes the layer. By default the strategy waits for a │ │ │ │ + * call to <refresh> before refreshing. By configuring the strategy with │ │ │ │ + * the <interval> option, refreshing can take place automatically. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * - <OpenLayers.Strategy> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: events │ │ │ │ - * {<OpenLayers.Events>} Events instance for listeners and triggering │ │ │ │ - * control specific events. │ │ │ │ - * │ │ │ │ - * To register events in the constructor, configure <eventListeners>. │ │ │ │ - * │ │ │ │ - * 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>): │ │ │ │ - * cachefull - Triggered when the cache is full. Listeners receive an │ │ │ │ - * object with a tile property as first argument. The tile references │ │ │ │ - * the tile that couldn't be cached. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: eventListeners │ │ │ │ - * {Object} Object with event listeners, keyed by event name. An optional │ │ │ │ - * scope property defines the scope that listeners will be executed in. │ │ │ │ - */ │ │ │ │ +OpenLayers.Strategy.Refresh = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layers │ │ │ │ - * {Array(<OpenLayers.Layer.Grid>)}. Optional. If provided, caching │ │ │ │ - * will be enabled for these layers only, otherwise for all cacheable │ │ │ │ - * layers. │ │ │ │ + * Property: force │ │ │ │ + * {Boolean} Force a refresh on the layer. Default is false. │ │ │ │ */ │ │ │ │ - layers: null, │ │ │ │ + force: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: imageFormat │ │ │ │ - * {String} The image format used for caching. The default is "image/png". │ │ │ │ - * Supported formats depend on the user agent. If an unsupported │ │ │ │ - * <imageFormat> is provided, "image/png" will be used. For aerial │ │ │ │ - * imagery, "image/jpeg" is recommended. │ │ │ │ + * Property: interval │ │ │ │ + * {Number} Auto-refresh. Default is 0. If > 0, layer will be refreshed │ │ │ │ + * every N milliseconds. │ │ │ │ */ │ │ │ │ - imageFormat: "image/png", │ │ │ │ + interval: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: quotaRegEx │ │ │ │ - * {RegExp} │ │ │ │ + * Property: timer │ │ │ │ + * {Number} The id of the timer. │ │ │ │ */ │ │ │ │ - quotaRegEx: (/quota/i), │ │ │ │ + timer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.CacheWrite │ │ │ │ + * Constructor: OpenLayers.Strategy.Refresh │ │ │ │ + * Create a new Refresh strategy. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Object with API properties for this control. │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * Set the map property for the control. │ │ │ │ + /** │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} True if the strategy was successfully activated. │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - var i, layers = this.layers || map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.addLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - if (!this.layers) { │ │ │ │ - map.events.on({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + if (this.layer.visibility === true) { │ │ │ │ + this.start(); │ │ │ │ + } │ │ │ │ + this.layer.events.on({ │ │ │ │ + "visibilitychanged": this.reset, │ │ │ │ scope: this │ │ │ │ }); │ │ │ │ } │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: addLayer │ │ │ │ - * Adds a layer to the control. Once added, tiles requested for this layer │ │ │ │ - * will be cached. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} Object with a layer property referencing an │ │ │ │ - * <OpenLayers.Layer> instance │ │ │ │ - */ │ │ │ │ - addLayer: function(evt) { │ │ │ │ - evt.layer.events.on({ │ │ │ │ - tileloadstart: this.makeSameOrigin, │ │ │ │ - tileloaded: this.onTileLoaded, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: removeLayer │ │ │ │ - * Removes a layer from the control. Once removed, tiles requested for this │ │ │ │ - * layer will no longer be cached. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} Object with a layer property referencing an │ │ │ │ - * <OpenLayers.Layer> instance │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ + * tear-down. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} True if the strategy was successfully deactivated. │ │ │ │ */ │ │ │ │ - removeLayer: function(evt) { │ │ │ │ - evt.layer.events.un({ │ │ │ │ - tileloadstart: this.makeSameOrigin, │ │ │ │ - tileloaded: this.onTileLoaded, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.stop(); │ │ │ │ + this.layer.events.un({ │ │ │ │ + "visibilitychanged": this.reset, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: makeSameOrigin │ │ │ │ - * If the tile does not have CORS image loading enabled and is from a │ │ │ │ - * different origin, use OpenLayers.ProxyHost to make it a same origin url. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ + * Method: reset │ │ │ │ + * Start or cancel the refresh interval depending on the visibility of │ │ │ │ + * the layer. │ │ │ │ */ │ │ │ │ - makeSameOrigin: function(evt) { │ │ │ │ - if (this.active) { │ │ │ │ - var tile = evt.tile; │ │ │ │ - if (tile instanceof OpenLayers.Tile.Image && │ │ │ │ - !tile.crossOriginKeyword && │ │ │ │ - tile.url.substr(0, 5) !== "data:") { │ │ │ │ - var sameOriginUrl = OpenLayers.Request.makeSameOrigin( │ │ │ │ - tile.url, OpenLayers.ProxyHost │ │ │ │ - ); │ │ │ │ - OpenLayers.Control.CacheWrite.urlMap[sameOriginUrl] = tile.url; │ │ │ │ - tile.url = sameOriginUrl; │ │ │ │ - } │ │ │ │ + reset: function() { │ │ │ │ + if (this.layer.visibility === true) { │ │ │ │ + this.start(); │ │ │ │ + } else { │ │ │ │ + this.stop(); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onTileLoaded │ │ │ │ - * Decides whether a tile can be cached and calls the cache method. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * Method: start │ │ │ │ + * Start the refresh interval. │ │ │ │ */ │ │ │ │ - onTileLoaded: function(evt) { │ │ │ │ - if (this.active && !evt.aborted && │ │ │ │ - evt.tile instanceof OpenLayers.Tile.Image && │ │ │ │ - evt.tile.url.substr(0, 5) !== 'data:') { │ │ │ │ - this.cache({ │ │ │ │ - tile: evt.tile │ │ │ │ - }); │ │ │ │ - delete OpenLayers.Control.CacheWrite.urlMap[evt.tile.url]; │ │ │ │ + start: function() { │ │ │ │ + if (this.interval && typeof this.interval === "number" && │ │ │ │ + this.interval > 0) { │ │ │ │ + │ │ │ │ + this.timer = window.setInterval( │ │ │ │ + OpenLayers.Function.bind(this.refresh, this), │ │ │ │ + this.interval); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: cache │ │ │ │ - * Adds a tile to the cache. When the cache is full, the "cachefull" event │ │ │ │ - * is triggered. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * obj - {Object} Object with a tile property, tile being the │ │ │ │ - * <OpenLayers.Tile.Image> with the data to add to the cache │ │ │ │ + * APIMethod: refresh │ │ │ │ + * Tell the strategy to refresh which will refresh the layer. │ │ │ │ */ │ │ │ │ - cache: function(obj) { │ │ │ │ - if (window.localStorage) { │ │ │ │ - var tile = obj.tile; │ │ │ │ - try { │ │ │ │ - var canvasContext = tile.getCanvasContext(); │ │ │ │ - if (canvasContext) { │ │ │ │ - var urlMap = OpenLayers.Control.CacheWrite.urlMap; │ │ │ │ - var url = urlMap[tile.url] || tile.url; │ │ │ │ - window.localStorage.setItem( │ │ │ │ - "olCache_" + url, │ │ │ │ - canvasContext.canvas.toDataURL(this.imageFormat) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } catch (e) { │ │ │ │ - // local storage full or CORS violation │ │ │ │ - var reason = e.name || e.message; │ │ │ │ - if (reason && this.quotaRegEx.test(reason)) { │ │ │ │ - this.events.triggerEvent("cachefull", { │ │ │ │ - tile: tile │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - OpenLayers.Console.error(e.toString()); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + refresh: function() { │ │ │ │ + if (this.layer && this.layer.refresh && │ │ │ │ + typeof this.layer.refresh == "function") { │ │ │ │ + │ │ │ │ + this.layer.refresh({ │ │ │ │ + force: this.force │ │ │ │ + }); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: stop │ │ │ │ + * Cancels the refresh interval. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.layers || this.map) { │ │ │ │ - var i, layers = this.layers || this.map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.removeLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.un({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ + stop: function() { │ │ │ │ + if (this.timer !== null) { │ │ │ │ + window.clearInterval(this.timer); │ │ │ │ + this.timer = null; │ │ │ │ } │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.CacheWrite" │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Refresh" │ │ │ │ }); │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * APIFunction: OpenLayers.Control.CacheWrite.clearCache │ │ │ │ - * Clears all tiles cached with <OpenLayers.Control.CacheWrite> from the cache. │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.CacheWrite.clearCache = function() { │ │ │ │ - if (!window.localStorage) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - var i, key; │ │ │ │ - for (i = window.localStorage.length - 1; i >= 0; --i) { │ │ │ │ - key = window.localStorage.key(i); │ │ │ │ - if (key.substr(0, 8) === "olCache_") { │ │ │ │ - window.localStorage.removeItem(key); │ │ │ │ - } │ │ │ │ - } │ │ │ │ -}; │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Property: OpenLayers.Control.CacheWrite.urlMap │ │ │ │ - * {Object} Mapping of same origin urls to cache url keys. Entries will be │ │ │ │ - * deleted as soon as a tile was cached. │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.CacheWrite.urlMap = {}; │ │ │ │ - │ │ │ │ - │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Handler/Drag.js │ │ │ │ + OpenLayers/Strategy/Paging.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/Strategy.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. │ │ │ │ + * Class: OpenLayers.Strategy.Paging │ │ │ │ + * Strategy for vector feature paging │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Handler> │ │ │ │ + * - <OpenLayers.Strategy> │ │ │ │ */ │ │ │ │ -OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ +OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ + /** │ │ │ │ + * Property: features │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} Cached features. │ │ │ │ */ │ │ │ │ - started: false, │ │ │ │ + features: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: stopDown │ │ │ │ - * {Boolean} Stop propagation of mousedown events from getting to listeners │ │ │ │ - * on the same element. Default is true. │ │ │ │ + * Property: length │ │ │ │ + * {Integer} Number of features per page. Default is 10. │ │ │ │ */ │ │ │ │ - stopDown: true, │ │ │ │ + length: 10, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: dragging │ │ │ │ - * {Boolean} │ │ │ │ + /** │ │ │ │ + * Property: num │ │ │ │ + * {Integer} The currently displayed page number. │ │ │ │ */ │ │ │ │ - dragging: false, │ │ │ │ + num: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: last │ │ │ │ - * {<OpenLayers.Pixel>} The last pixel location of the drag. │ │ │ │ + /** │ │ │ │ + * Property: paging │ │ │ │ + * {Boolean} The strategy is currently changing pages. │ │ │ │ */ │ │ │ │ - last: null, │ │ │ │ + paging: false, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: start │ │ │ │ - * {<OpenLayers.Pixel>} The first pixel location of the drag. │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Strategy.Paging │ │ │ │ + * Create a new paging strategy. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - start: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: lastMoveEvt │ │ │ │ - * {Object} The last mousemove event that occurred. Used to │ │ │ │ - * position the map correctly when our "delay drag" │ │ │ │ - * timeout expired. │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The strategy was successfully activated. │ │ │ │ */ │ │ │ │ - lastMoveEvt: null, │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + "beforefeaturesadded": this.cacheFeatures, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + return activated; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: oldOnselectstart │ │ │ │ - * {Function} │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ + * tear-down. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ */ │ │ │ │ - oldOnselectstart: null, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.clearCache(); │ │ │ │ + this.layer.events.un({ │ │ │ │ + "beforefeaturesadded": this.cacheFeatures, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + return deactivated; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: cacheFeatures │ │ │ │ + * Cache features before they are added to the layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * event - {Object} The event that this was listening for. This will come │ │ │ │ + * with a batch of features to be paged. │ │ │ │ */ │ │ │ │ - interval: 0, │ │ │ │ + cacheFeatures: function(event) { │ │ │ │ + if (!this.paging) { │ │ │ │ + this.clearCache(); │ │ │ │ + this.features = event.features; │ │ │ │ + this.pageNext(event); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: timeoutId │ │ │ │ - * {String} The id of the timeout used for the mousedown interval. │ │ │ │ - * This is "private", and should be left alone. │ │ │ │ + * Method: clearCache │ │ │ │ + * Clear out the cached features. This destroys features, assuming │ │ │ │ + * nothing else has a reference. │ │ │ │ */ │ │ │ │ - timeoutId: null, │ │ │ │ + clearCache: function() { │ │ │ │ + if (this.features) { │ │ │ │ + for (var i = 0; i < this.features.length; ++i) { │ │ │ │ + this.features[i].destroy(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.features = null; │ │ │ │ + this.num = 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. │ │ │ │ + * APIMethod: pageCount │ │ │ │ + * Get the total count of pages given the current cache of features. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} The page count. │ │ │ │ */ │ │ │ │ - documentDrag: false, │ │ │ │ + pageCount: function() { │ │ │ │ + var numFeatures = this.features ? this.features.length : 0; │ │ │ │ + return Math.ceil(numFeatures / this.length); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: documentEvents │ │ │ │ - * {Boolean} Are we currently observing document events? │ │ │ │ + * APIMethod: pageNum │ │ │ │ + * Get the zero based page number. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} The current page number being displayed. │ │ │ │ */ │ │ │ │ - documentEvents: null, │ │ │ │ + pageNum: function() { │ │ │ │ + return this.num; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Handler.Drag │ │ │ │ - * Returns OpenLayers.Handler.Drag │ │ │ │ - * │ │ │ │ + * APIMethod: pageLength │ │ │ │ + * Gets or sets page length. │ │ │ │ + * │ │ │ │ * 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} │ │ │ │ + * newLength - {Integer} Optional length to be set. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} The length of a page (number of features per page). │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - }; │ │ │ │ + pageLength: function(newLength) { │ │ │ │ + if (newLength && newLength > 0) { │ │ │ │ + this.length = newLength; │ │ │ │ } │ │ │ │ + return this.length; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: dragstart │ │ │ │ - * This private method is factorized from mousedown and touchstart methods │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} The event │ │ │ │ + * APIMethod: pageNext │ │ │ │ + * Display the next page of features. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * {Boolean} A new page was displayed. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + pageNext: function(event) { │ │ │ │ + var changed = false; │ │ │ │ + if (this.features) { │ │ │ │ + if (this.num === null) { │ │ │ │ + this.num = -1; │ │ │ │ } │ │ │ │ - document.onselectstart = OpenLayers.Function.False; │ │ │ │ - │ │ │ │ - propagate = !this.stopDown; │ │ │ │ - } else { │ │ │ │ - this.started = false; │ │ │ │ - this.start = null; │ │ │ │ - this.last = null; │ │ │ │ + var start = (this.num + 1) * this.length; │ │ │ │ + changed = this.page(start, event); │ │ │ │ } │ │ │ │ - return propagate; │ │ │ │ + return changed; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: dragmove │ │ │ │ - * This private method is factorized from mousemove and touchmove methods │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} The event │ │ │ │ + * APIMethod: pagePrevious │ │ │ │ + * Display the previous page of features. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * {Boolean} A new page was displayed. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + pagePrevious: function() { │ │ │ │ + var changed = false; │ │ │ │ + if (this.features) { │ │ │ │ + if (this.num === null) { │ │ │ │ + this.num = this.pageCount(); │ │ │ │ } │ │ │ │ - this.last = evt.xy; │ │ │ │ + var start = (this.num - 1) * this.length; │ │ │ │ + changed = this.page(start); │ │ │ │ } │ │ │ │ - return true; │ │ │ │ + return changed; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: dragend │ │ │ │ - * This private method is factorized from mouseup and touchend methods │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} The event │ │ │ │ + * Method: page │ │ │ │ + * Display the page starting at the given index from the cache. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * {Boolean} A new page was displayed. │ │ │ │ */ │ │ │ │ - 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]); │ │ │ │ + page: function(start, event) { │ │ │ │ + var changed = false; │ │ │ │ + if (this.features) { │ │ │ │ + if (start >= 0 && start < this.features.length) { │ │ │ │ + var num = Math.floor(start / this.length); │ │ │ │ + if (num != this.num) { │ │ │ │ + this.paging = true; │ │ │ │ + var features = this.features.slice(start, start + this.length); │ │ │ │ + this.layer.removeFeatures(this.layer.features); │ │ │ │ + this.num = num; │ │ │ │ + // modify the event if any │ │ │ │ + if (event && event.features) { │ │ │ │ + // this.was called by an event listener │ │ │ │ + event.features = features; │ │ │ │ + } else { │ │ │ │ + // this was called directly on the strategy │ │ │ │ + this.layer.addFeatures(features); │ │ │ │ + } │ │ │ │ + this.paging = false; │ │ │ │ + changed = true; │ │ │ │ + } │ │ │ │ } │ │ │ │ - document.onselectstart = this.oldOnselectstart; │ │ │ │ } │ │ │ │ - return true; │ │ │ │ + return changed; │ │ │ │ }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Paging" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * The four methods below (down, move, up, and out) are used by subclasses │ │ │ │ - * to do their own processing related to these mouse events. │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: down │ │ │ │ - * This method is called during the handling of the mouse down event. │ │ │ │ - * Subclasses can do their own processing here. │ │ │ │ + * Constructor: OpenLayers.Strategy.Fixed │ │ │ │ + * Create a new Fixed strategy. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} The mouse down event │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - move: function(evt) {}, │ │ │ │ + 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: 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 │ │ │ │ + * Method: deactivate │ │ │ │ + * Deactivate the strategy. Undo what is done in <activate>. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ */ │ │ │ │ - up: function(evt) {}, │ │ │ │ + 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: out │ │ │ │ - * This method is called during the handling of the mouse out event. │ │ │ │ - * Subclasses can do their own processing here. │ │ │ │ + * Method: load │ │ │ │ + * Tells protocol to load data and unhooks the visibilitychanged event │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} The mouse out event │ │ │ │ + * options - {Object} options to pass to protocol read. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + 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: mouseout │ │ │ │ - * Handle mouseout events │ │ │ │ + * 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: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * resp - {<OpenLayers.Protocol.Response>} The response object passed │ │ │ │ + * by the protocol. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - 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); │ │ │ │ + layer.events.triggerEvent("loadend", { │ │ │ │ + response: resp │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Drag" │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Fixed" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Handler/Feature.js │ │ │ │ + OpenLayers/Strategy/Save.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/Strategy.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. │ │ │ │ + * Class: OpenLayers.Strategy.Save │ │ │ │ + * A strategy that commits newly created or modified features. By default │ │ │ │ + * the strategy waits for a call to <save> before persisting changes. By │ │ │ │ + * configuring the strategy with the <auto> option, changes can be saved │ │ │ │ + * automatically. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Handler> │ │ │ │ + * - <OpenLayers.Strategy> │ │ │ │ */ │ │ │ │ -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, │ │ │ │ +OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: geometryTypes │ │ │ │ - * To restrict dragging to a limited set of geometry types, send a list │ │ │ │ - * of strings corresponding to the geometry class names. │ │ │ │ + * APIProperty: events │ │ │ │ + * {<OpenLayers.Events>} An events object that handles all │ │ │ │ + * events on the strategy object. │ │ │ │ + * │ │ │ │ + * Register a listener for a particular event with the following syntax: │ │ │ │ + * (code) │ │ │ │ + * strategy.events.register(type, obj, listener); │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Supported event types: │ │ │ │ + * start - Triggered before saving │ │ │ │ + * success - Triggered after a successful transaction │ │ │ │ + * fail - Triggered after a failed transaction │ │ │ │ * │ │ │ │ - * @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. │ │ │ │ + /** │ │ │ │ + * Property: events │ │ │ │ + * {<OpenLayers.Events>} Events instance for triggering this protocol │ │ │ │ + * events. │ │ │ │ */ │ │ │ │ - stopUp: false, │ │ │ │ + events: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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} │ │ │ │ + * APIProperty: auto │ │ │ │ + * {Boolean | Number} Auto-save. Default is false. If true, features will be │ │ │ │ + * saved immediately after being added to the layer and with each │ │ │ │ + * modification or deletion. If auto is a number, features will be │ │ │ │ + * saved on an interval provided by the value (in seconds). │ │ │ │ */ │ │ │ │ - initialize: function(control, layer, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ - this.layer = layer; │ │ │ │ - }, │ │ │ │ + auto: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: touchstart │ │ │ │ - * Handle touchstart events │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * Property: timer │ │ │ │ + * {Number} The id of the timer. │ │ │ │ */ │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - return OpenLayers.Event.isMultiTouch(evt) ? │ │ │ │ - true : this.mousedown(evt); │ │ │ │ - }, │ │ │ │ + timer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Constructor: OpenLayers.Strategy.Save │ │ │ │ + * Create a new Save strategy. │ │ │ │ * │ │ │ │ * 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} │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - mouseup: function(evt) { │ │ │ │ - this.up = evt.xy; │ │ │ │ - return this.handle(evt) ? !this.stopUp : true; │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Strategy.prototype.initialize.apply(this, [options]); │ │ │ │ + this.events = new OpenLayers.Events(this); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: click │ │ │ │ - * Handle click. Call the "click" callback if click on a feature, │ │ │ │ - * or the "clickout" callback if click outside any feature. │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} │ │ │ │ + * {Boolean} The strategy was successfully activated. │ │ │ │ */ │ │ │ │ - click: function(evt) { │ │ │ │ - return this.handle(evt) ? !this.stopClick : true; │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + if (this.auto) { │ │ │ │ + if (typeof this.auto === "number") { │ │ │ │ + this.timer = window.setInterval( │ │ │ │ + OpenLayers.Function.bind(this.save, this), │ │ │ │ + this.auto * 1000 │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + this.layer.events.on({ │ │ │ │ + "featureadded": this.triggerSave, │ │ │ │ + "afterfeaturemodified": this.triggerSave, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ + * tear-down. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ */ │ │ │ │ - mousemove: function(evt) { │ │ │ │ - if (!this.callbacks['over'] && !this.callbacks['out']) { │ │ │ │ - return true; │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + if (this.auto) { │ │ │ │ + if (typeof this.auto === "number") { │ │ │ │ + window.clearInterval(this.timer); │ │ │ │ + } else { │ │ │ │ + this.layer.events.un({ │ │ │ │ + "featureadded": this.triggerSave, │ │ │ │ + "afterfeaturemodified": this.triggerSave, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - 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); │ │ │ │ + return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: geometryTypeMatches │ │ │ │ - * Return true if the geometry type of the passed feature matches │ │ │ │ - * one of the geometry types in the geometryTypes array. │ │ │ │ + * Method: triggerSave │ │ │ │ + * Registered as a listener. Calls save if a feature has insert, update, │ │ │ │ + * or delete state. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Vector.Feature>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} │ │ │ │ + * event - {Object} The event this function is listening for. │ │ │ │ */ │ │ │ │ - geometryTypeMatches: function(feature) { │ │ │ │ - return this.geometryTypes == null || │ │ │ │ - OpenLayers.Util.indexOf(this.geometryTypes, │ │ │ │ - feature.geometry.CLASS_NAME) > -1; │ │ │ │ + triggerSave: function(event) { │ │ │ │ + var feature = event.feature; │ │ │ │ + if (feature.state === OpenLayers.State.INSERT || │ │ │ │ + feature.state === OpenLayers.State.UPDATE || │ │ │ │ + feature.state === OpenLayers.State.DELETE) { │ │ │ │ + this.save([event.feature]); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handle │ │ │ │ + * APIMethod: save │ │ │ │ + * Tell the layer protocol to commit unsaved features. If the layer │ │ │ │ + * projection differs from the map projection, features will be │ │ │ │ + * transformed into the layer projection before being committed. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The event occurred over a relevant feature. │ │ │ │ + * features - {Array} Features to be saved. If null, then default is all │ │ │ │ + * features in the layer. Features are assumed to be in the map │ │ │ │ + * projection. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + save: function(features) { │ │ │ │ + if (!features) { │ │ │ │ + features = this.layer.features; │ │ │ │ } │ │ │ │ - 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]); │ │ │ │ + this.events.triggerEvent("start", { │ │ │ │ + features: features │ │ │ │ + }); │ │ │ │ + var remote = this.layer.projection; │ │ │ │ + var local = this.layer.map.getProjectionObject(); │ │ │ │ + if (!local.equals(remote)) { │ │ │ │ + var len = features.length; │ │ │ │ + var clones = new Array(len); │ │ │ │ + var orig, clone; │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ + orig = features[i]; │ │ │ │ + clone = orig.clone(); │ │ │ │ + clone.fid = orig.fid; │ │ │ │ + clone.state = orig.state; │ │ │ │ + if (orig.url) { │ │ │ │ + clone.url = orig.url; │ │ │ │ } │ │ │ │ - // 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; │ │ │ │ + clone._original = orig; │ │ │ │ + clone.geometry.transform(local, remote); │ │ │ │ + clones[i] = clone; │ │ │ │ } │ │ │ │ - } else if (this.lastFeature && (previouslyIn || click)) { │ │ │ │ - this.triggerCallback(type, 'out', [this.lastFeature]); │ │ │ │ + features = clones; │ │ │ │ } │ │ │ │ - return handled; │ │ │ │ + this.layer.protocol.commit(features, { │ │ │ │ + callback: this.onCommit, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: triggerCallback │ │ │ │ - * Call the callback keyed in the event map with the supplied arguments. │ │ │ │ - * For click and clickout, the <clickTolerance> is checked first. │ │ │ │ + * Method: onCommit │ │ │ │ + * Called after protocol commit. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * type - {String} │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} A response object. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + onCommit: function(response) { │ │ │ │ + var evt = { │ │ │ │ + "response": response │ │ │ │ + }; │ │ │ │ + if (response.success()) { │ │ │ │ + var features = response.reqFeatures; │ │ │ │ + // deal with inserts, updates, and deletes │ │ │ │ + var state, feature; │ │ │ │ + var destroys = []; │ │ │ │ + var insertIds = response.insertIds || []; │ │ │ │ + var j = 0; │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + // if projection was different, we may be dealing with clones │ │ │ │ + feature = feature._original || feature; │ │ │ │ + state = feature.state; │ │ │ │ + if (state) { │ │ │ │ + if (state == OpenLayers.State.DELETE) { │ │ │ │ + destroys.push(feature); │ │ │ │ + } else if (state == OpenLayers.State.INSERT) { │ │ │ │ + feature.fid = insertIds[j]; │ │ │ │ + ++j; │ │ │ │ + } │ │ │ │ + feature.state = null; │ │ │ │ } │ │ │ │ - // 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); │ │ │ │ + if (destroys.length > 0) { │ │ │ │ + this.layer.destroyFeatures(destroys); │ │ │ │ + } │ │ │ │ │ │ │ │ - }, │ │ │ │ + this.events.triggerEvent("success", evt); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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)); │ │ │ │ + this.events.triggerEvent("fail", evt); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Feature" │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Save" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/DragFeature.js │ │ │ │ + OpenLayers/Strategy/BBOX.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/Feature.js │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ + * @requires OpenLayers/Filter/Spatial.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.DragFeature │ │ │ │ - * The DragFeature control moves a feature with a drag of the mouse. Create a │ │ │ │ - * new control with the <OpenLayers.Control.DragFeature> constructor. │ │ │ │ + * Class: OpenLayers.Strategy.BBOX │ │ │ │ + * A simple strategy that reads new features when the viewport invalidates │ │ │ │ + * some bounds. │ │ │ │ * │ │ │ │ - * Inherits From: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Strategy> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.DragFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: geometryTypes │ │ │ │ - * {Array(String)} To restrict dragging to a limited set of geometry types, │ │ │ │ - * send a list of strings corresponding to the geometry class names. │ │ │ │ - */ │ │ │ │ - geometryTypes: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: onStart │ │ │ │ - * {Function} Define this function if you want to know when a drag starts. │ │ │ │ - * The function should expect to receive two arguments: the feature │ │ │ │ - * that is about to be dragged and the pixel location of the mouse. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature that is about to be │ │ │ │ - * dragged. │ │ │ │ - * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. │ │ │ │ - */ │ │ │ │ - onStart: function(feature, pixel) {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: onDrag │ │ │ │ - * {Function} Define this function if you want to know about each move of a │ │ │ │ - * feature. The function should expect to receive two arguments: the │ │ │ │ - * feature that is being dragged and the pixel location of the mouse. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. │ │ │ │ - * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. │ │ │ │ - */ │ │ │ │ - onDrag: function(feature, pixel) {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: onComplete │ │ │ │ - * {Function} Define this function if you want to know when a feature is │ │ │ │ - * done dragging. The function should expect to receive two arguments: │ │ │ │ - * the feature that is being dragged and the pixel location of the │ │ │ │ - * mouse. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. │ │ │ │ - * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. │ │ │ │ - */ │ │ │ │ - onComplete: function(feature, pixel) {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: onEnter │ │ │ │ - * {Function} Define this function if you want to know when the mouse │ │ │ │ - * goes over a feature and thereby makes this feature a candidate │ │ │ │ - * for dragging. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature that is ready │ │ │ │ - * to be dragged. │ │ │ │ - */ │ │ │ │ - onEnter: function(feature) {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: onLeave │ │ │ │ - * {Function} Define this function if you want to know when the mouse │ │ │ │ - * goes out of the feature that was dragged. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. │ │ │ │ - */ │ │ │ │ - onLeave: function(feature) {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ +OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: layer │ │ │ │ - * {<OpenLayers.Layer.Vector>} │ │ │ │ + * Property: bounds │ │ │ │ + * {<OpenLayers.Bounds>} The current data bounds (in the same projection │ │ │ │ + * as the layer - not always the same projection as the map). │ │ │ │ */ │ │ │ │ - layer: null, │ │ │ │ + bounds: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: feature │ │ │ │ - * {<OpenLayers.Feature.Vector>} │ │ │ │ + /** │ │ │ │ + * Property: resolution │ │ │ │ + * {Float} The current data resolution. │ │ │ │ */ │ │ │ │ - feature: null, │ │ │ │ + resolution: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: dragCallbacks │ │ │ │ - * {Object} The functions that are sent to the drag handler for callback. │ │ │ │ + * APIProperty: ratio │ │ │ │ + * {Float} The ratio of the data bounds to the viewport bounds (in each │ │ │ │ + * dimension). Default is 2. │ │ │ │ */ │ │ │ │ - dragCallbacks: {}, │ │ │ │ + ratio: 2, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: featureCallbacks │ │ │ │ - * {Object} The functions that are sent to the feature handler for callback. │ │ │ │ + /** │ │ │ │ + * Property: resFactor │ │ │ │ + * {Float} Optional factor used to determine when previously requested │ │ │ │ + * features are invalid. If set, the resFactor will be compared to the │ │ │ │ + * resolution of the previous request to the current map resolution. │ │ │ │ + * If resFactor > (old / new) and 1/resFactor < (old / new). If you │ │ │ │ + * set a resFactor of 1, data will be requested every time the │ │ │ │ + * resolution changes. If you set a resFactor of 3, data will be │ │ │ │ + * requested if the old resolution is 3 times the new, or if the new is │ │ │ │ + * 3 times the old. If the old bounds do not contain the new bounds │ │ │ │ + * new data will always be requested (with or without considering │ │ │ │ + * resFactor). │ │ │ │ */ │ │ │ │ - featureCallbacks: {}, │ │ │ │ + resFactor: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: lastPixel │ │ │ │ - * {<OpenLayers.Pixel>} │ │ │ │ + * Property: response │ │ │ │ + * {<OpenLayers.Protocol.Response>} The protocol response object returned │ │ │ │ + * by the layer protocol. │ │ │ │ */ │ │ │ │ - lastPixel: null, │ │ │ │ + response: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.DragFeature │ │ │ │ - * Create a new control to drag features. │ │ │ │ + * Constructor: OpenLayers.Strategy.BBOX │ │ │ │ + * Create a new BBOX strategy. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} The layer containing features to be │ │ │ │ - * dragged. │ │ │ │ * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * control. │ │ │ │ - */ │ │ │ │ - initialize: function(layer, options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.layer = layer; │ │ │ │ - this.handlers = { │ │ │ │ - drag: new OpenLayers.Handler.Drag( │ │ │ │ - this, OpenLayers.Util.extend({ │ │ │ │ - down: this.downFeature, │ │ │ │ - move: this.moveFeature, │ │ │ │ - up: this.upFeature, │ │ │ │ - out: this.cancel, │ │ │ │ - done: this.doneDragging │ │ │ │ - }, this.dragCallbacks), { │ │ │ │ - documentDrag: this.documentDrag │ │ │ │ - } │ │ │ │ - ), │ │ │ │ - feature: new OpenLayers.Handler.Feature( │ │ │ │ - this, this.layer, OpenLayers.Util.extend({ │ │ │ │ - // 'click' and 'clickout' callback are for the mobile │ │ │ │ - // support: no 'over' or 'out' in touch based browsers. │ │ │ │ - click: this.clickFeature, │ │ │ │ - clickout: this.clickoutFeature, │ │ │ │ - over: this.overFeature, │ │ │ │ - out: this.outFeature │ │ │ │ - }, this.featureCallbacks), { │ │ │ │ - geometryTypes: this.geometryTypes │ │ │ │ - } │ │ │ │ - ) │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: clickFeature │ │ │ │ - * Called when the feature handler detects a click-in on a feature. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - clickFeature: function(feature) { │ │ │ │ - if (this.handlers.feature.touch && !this.over && this.overFeature(feature)) { │ │ │ │ - this.handlers.drag.dragstart(this.handlers.feature.evt); │ │ │ │ - // to let the events propagate to the feature handler (click callback) │ │ │ │ - this.handlers.drag.stopDown = false; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: clickoutFeature │ │ │ │ - * Called when the feature handler detects a click-out on a feature. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - clickoutFeature: function(feature) { │ │ │ │ - if (this.handlers.feature.touch && this.over) { │ │ │ │ - this.outFeature(feature); │ │ │ │ - this.handlers.drag.stopDown = true; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Take care of things that are not handled in superclass │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - this.layer = null; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, []); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the control and the feature handler. │ │ │ │ + * Method: activate │ │ │ │ + * Set up strategy with regard to reading new batches of remote data. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Successfully activated the control and feature handler. │ │ │ │ + * {Boolean} The strategy was successfully activated. │ │ │ │ */ │ │ │ │ activate: function() { │ │ │ │ - return (this.handlers.feature.activate() && │ │ │ │ - OpenLayers.Control.prototype.activate.apply(this, arguments)); │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + "moveend": this.update, │ │ │ │ + "refresh": this.update, │ │ │ │ + "visibilitychanged": this.update, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.update(); │ │ │ │ + } │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the control and all handlers. │ │ │ │ + * Method: deactivate │ │ │ │ + * Tear down strategy with regard to reading new batches of remote data. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Successfully deactivated the control. │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ */ │ │ │ │ deactivate: function() { │ │ │ │ - // the return from the handlers is unimportant in this case │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ - this.handlers.feature.deactivate(); │ │ │ │ - this.feature = null; │ │ │ │ - this.dragging = false; │ │ │ │ - this.lastPixel = null; │ │ │ │ - OpenLayers.Element.removeClass( │ │ │ │ - this.map.viewPortDiv, this.displayClass + "Over" │ │ │ │ - ); │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply(this, arguments); │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.layer.events.un({ │ │ │ │ + "moveend": this.update, │ │ │ │ + "refresh": this.update, │ │ │ │ + "visibilitychanged": this.update, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: overFeature │ │ │ │ - * Called when the feature handler detects a mouse-over on a feature. │ │ │ │ - * This activates the drag handler. │ │ │ │ + * Method: update │ │ │ │ + * Callback function called on "moveend" or "refresh" layer events. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The selected feature. │ │ │ │ + * options - {Object} Optional object whose properties will determine │ │ │ │ + * the behaviour of this Strategy │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Successfully activated the drag handler. │ │ │ │ + * Valid options include: │ │ │ │ + * force - {Boolean} if true, new data must be unconditionally read. │ │ │ │ + * noAbort - {Boolean} if true, do not abort previous requests. │ │ │ │ */ │ │ │ │ - overFeature: function(feature) { │ │ │ │ - var activated = false; │ │ │ │ - if (!this.handlers.drag.dragging) { │ │ │ │ - this.feature = feature; │ │ │ │ - this.handlers.drag.activate(); │ │ │ │ - activated = true; │ │ │ │ - this.over = true; │ │ │ │ - OpenLayers.Element.addClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ - this.onEnter(feature); │ │ │ │ - } else { │ │ │ │ - if (this.feature.id == feature.id) { │ │ │ │ - this.over = true; │ │ │ │ - } else { │ │ │ │ - this.over = false; │ │ │ │ - } │ │ │ │ + update: function(options) { │ │ │ │ + var mapBounds = this.getMapBounds(); │ │ │ │ + if (mapBounds !== null && ((options && options.force) || │ │ │ │ + (this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds)))) { │ │ │ │ + this.calculateBounds(mapBounds); │ │ │ │ + this.resolution = this.layer.map.getResolution(); │ │ │ │ + this.triggerRead(options); │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: downFeature │ │ │ │ - * Called when the drag handler detects a mouse-down. │ │ │ │ + * Method: getMapBounds │ │ │ │ + * Get the map bounds expressed in the same projection as this layer. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * pixel - {<OpenLayers.Pixel>} Location of the mouse event. │ │ │ │ - */ │ │ │ │ - downFeature: function(pixel) { │ │ │ │ - this.lastPixel = pixel; │ │ │ │ - this.onStart(this.feature, pixel); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: moveFeature │ │ │ │ - * Called when the drag handler detects a mouse-move. Also calls the │ │ │ │ - * optional onDrag method. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * pixel - {<OpenLayers.Pixel>} Location of the mouse event. │ │ │ │ - */ │ │ │ │ - moveFeature: function(pixel) { │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - this.feature.geometry.move(res * (pixel.x - this.lastPixel.x), │ │ │ │ - res * (this.lastPixel.y - pixel.y)); │ │ │ │ - this.layer.drawFeature(this.feature); │ │ │ │ - this.lastPixel = pixel; │ │ │ │ - this.onDrag(this.feature, pixel); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: upFeature │ │ │ │ - * Called when the drag handler detects a mouse-up. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * pixel - {<OpenLayers.Pixel>} Location of the mouse event. │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} Map bounds in the projection of the layer. │ │ │ │ */ │ │ │ │ - upFeature: function(pixel) { │ │ │ │ - if (!this.over) { │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ + getMapBounds: function() { │ │ │ │ + if (this.layer.map === null) { │ │ │ │ + return null; │ │ │ │ } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: doneDragging │ │ │ │ - * Called when the drag handler is done dragging. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * pixel - {<OpenLayers.Pixel>} The last event pixel location. If this event │ │ │ │ - * came from a mouseout, this may not be in the map viewport. │ │ │ │ - */ │ │ │ │ - doneDragging: function(pixel) { │ │ │ │ - this.onComplete(this.feature, pixel); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: outFeature │ │ │ │ - * Called when the feature handler detects a mouse-out on a feature. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature that the mouse left. │ │ │ │ - */ │ │ │ │ - outFeature: function(feature) { │ │ │ │ - if (!this.handlers.drag.dragging) { │ │ │ │ - this.over = false; │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ - OpenLayers.Element.removeClass( │ │ │ │ - this.map.viewPortDiv, this.displayClass + "Over" │ │ │ │ + var bounds = this.layer.map.getExtent(); │ │ │ │ + if (bounds && !this.layer.projection.equals( │ │ │ │ + this.layer.map.getProjectionObject())) { │ │ │ │ + bounds = bounds.clone().transform( │ │ │ │ + this.layer.map.getProjectionObject(), this.layer.projection │ │ │ │ ); │ │ │ │ - this.onLeave(feature); │ │ │ │ - this.feature = null; │ │ │ │ - } else { │ │ │ │ - if (this.feature.id == feature.id) { │ │ │ │ - this.over = false; │ │ │ │ - } │ │ │ │ } │ │ │ │ + return bounds; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: cancel │ │ │ │ - * Called when the drag handler detects a mouse-out (from the map viewport). │ │ │ │ - */ │ │ │ │ - cancel: function() { │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ - this.over = false; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - this.handlers.feature.setMap(map); │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.DragFeature" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Handler/RegularPolygon.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/Drag.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Handler.RegularPolygon │ │ │ │ - * Handler to draw a regular polygon on the map. Polygon is displayed on mouse │ │ │ │ - * down, moves or is modified on mouse move, and is finished on mouse up. │ │ │ │ - * The handler triggers callbacks for 'done' and 'cancel'. Create a new │ │ │ │ - * instance with the <OpenLayers.Handler.RegularPolygon> constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Handler.Drag> │ │ │ │ - */ │ │ │ │ -OpenLayers.Handler.RegularPolygon = OpenLayers.Class(OpenLayers.Handler.Drag, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: sides │ │ │ │ - * {Integer} Number of sides for the regular polygon. Needs to be greater │ │ │ │ - * than 2. Defaults to 4. │ │ │ │ - */ │ │ │ │ - sides: 4, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: radius │ │ │ │ - * {Float} Optional radius in map units of the regular polygon. If this is │ │ │ │ - * set to some non-zero value, a polygon with a fixed radius will be │ │ │ │ - * drawn and dragged with mose movements. If this property is not │ │ │ │ - * set, dragging changes the radius of the polygon. Set to null by │ │ │ │ - * default. │ │ │ │ - */ │ │ │ │ - radius: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: snapAngle │ │ │ │ - * {Float} If set to a non-zero value, the handler will snap the polygon │ │ │ │ - * rotation to multiples of the snapAngle. Value is an angle measured │ │ │ │ - * in degrees counterclockwise from the positive x-axis. │ │ │ │ - */ │ │ │ │ - snapAngle: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: snapToggle │ │ │ │ - * {String} If set, snapToggle is checked on mouse events and will set │ │ │ │ - * the snap mode to the opposite of what it currently is. To disallow │ │ │ │ - * toggling between snap and non-snap mode, set freehandToggle to │ │ │ │ - * null. Acceptable toggle values are 'shiftKey', 'ctrlKey', and │ │ │ │ - * 'altKey'. Snap mode is only possible if this.snapAngle is set to a │ │ │ │ - * non-zero value. │ │ │ │ - */ │ │ │ │ - snapToggle: 'shiftKey', │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: layerOptions │ │ │ │ - * {Object} Any optional properties to be set on the sketch layer. │ │ │ │ - */ │ │ │ │ - layerOptions: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: persist │ │ │ │ - * {Boolean} Leave the feature rendered until clear is called. Default │ │ │ │ - * is false. If set to true, the feature remains rendered until │ │ │ │ - * clear is called, typically by deactivating the handler or starting │ │ │ │ - * another drawing. │ │ │ │ - */ │ │ │ │ - persist: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: irregular │ │ │ │ - * {Boolean} Draw an irregular polygon instead of a regular polygon. │ │ │ │ - * Default is false. If true, the initial mouse down will represent │ │ │ │ - * one corner of the polygon bounds and with each mouse movement, the │ │ │ │ - * polygon will be stretched so the opposite corner of its bounds │ │ │ │ - * follows the mouse position. This property takes precedence over │ │ │ │ - * the radius property. If set to true, the radius property will │ │ │ │ - * be ignored. │ │ │ │ - */ │ │ │ │ - irregular: 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: angle │ │ │ │ - * {Float} The angle from the origin (mouse down) to the current mouse │ │ │ │ - * position, in radians. This is measured counterclockwise from the │ │ │ │ - * positive x-axis. │ │ │ │ - */ │ │ │ │ - angle: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: fixedRadius │ │ │ │ - * {Boolean} The polygon has a fixed radius. True if a radius is set before │ │ │ │ - * drawing begins. False otherwise. │ │ │ │ - */ │ │ │ │ - fixedRadius: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: feature │ │ │ │ - * {<OpenLayers.Feature.Vector>} The currently drawn polygon feature │ │ │ │ - */ │ │ │ │ - feature: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: layer │ │ │ │ - * {<OpenLayers.Layer.Vector>} The temporary drawing layer │ │ │ │ - */ │ │ │ │ - layer: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: origin │ │ │ │ - * {<OpenLayers.Geometry.Point>} Location of the first mouse down │ │ │ │ - */ │ │ │ │ - origin: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Handler.RegularPolygon │ │ │ │ - * Create a new regular 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 object with properties to be set on the handler. │ │ │ │ - * If the options.sides property is not specified, the number of sides │ │ │ │ - * will default to 4. │ │ │ │ + * Method: invalidBounds │ │ │ │ + * Determine whether the previously requested set of features is invalid. │ │ │ │ + * This occurs when the new map bounds do not contain the previously │ │ │ │ + * requested bounds. In addition, if <resFactor> is set, it will be │ │ │ │ + * considered. │ │ │ │ * │ │ │ │ - * Named callbacks: │ │ │ │ - * create - Called when a sketch is first created. Callback called with │ │ │ │ - * the creation point geometry and sketch feature. │ │ │ │ - * done - Called when the sketch drawing is finished. The callback will │ │ │ │ - * recieve a single argument, the sketch 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.Drag.prototype.initialize.apply(this, │ │ │ │ - [control, callbacks, options]); │ │ │ │ - this.options = (options) ? options : {}; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: setOptions │ │ │ │ - * │ │ │ │ * Parameters: │ │ │ │ - * newOptions - {Object} │ │ │ │ - */ │ │ │ │ - setOptions: function(newOptions) { │ │ │ │ - OpenLayers.Util.extend(this.options, newOptions); │ │ │ │ - OpenLayers.Util.extend(this, newOptions); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Turn on the handler. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The handler was successfully activated │ │ │ │ - */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (OpenLayers.Handler.Drag.prototype.activate.apply(this, arguments)) { │ │ │ │ - // create temporary vector layer for rendering geometry sketch │ │ │ │ - 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); │ │ │ │ - activated = true; │ │ │ │ - } │ │ │ │ - return activated; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Turn off the handler. │ │ │ │ + * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be │ │ │ │ + * retrieved from the map object if not provided │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} The handler was successfully deactivated │ │ │ │ - */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = false; │ │ │ │ - if (OpenLayers.Handler.Drag.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - // call the cancel callback if mid-drawing │ │ │ │ - if (this.dragging) { │ │ │ │ - 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.layer.destroy(false); │ │ │ │ - if (this.feature) { │ │ │ │ - this.feature.destroy(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.layer = null; │ │ │ │ - this.feature = null; │ │ │ │ - deactivated = true; │ │ │ │ - } │ │ │ │ - return deactivated; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: down │ │ │ │ - * Start drawing a new feature │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} The drag start event │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - down: function(evt) { │ │ │ │ - this.fixedRadius = !!(this.radius); │ │ │ │ - var maploc = this.layer.getLonLatFromViewPortPx(evt.xy); │ │ │ │ - this.origin = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat); │ │ │ │ - // create the new polygon │ │ │ │ - if (!this.fixedRadius || this.irregular) { │ │ │ │ - // smallest radius should not be less one pixel in map units │ │ │ │ - // VML doesn't behave well with smaller │ │ │ │ - this.radius = this.map.getResolution(); │ │ │ │ + invalidBounds: function(mapBounds) { │ │ │ │ + if (!mapBounds) { │ │ │ │ + mapBounds = this.getMapBounds(); │ │ │ │ } │ │ │ │ - if (this.persist) { │ │ │ │ - this.clear(); │ │ │ │ + var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds); │ │ │ │ + if (!invalid && this.resFactor) { │ │ │ │ + var ratio = this.resolution / this.layer.map.getResolution(); │ │ │ │ + invalid = (ratio >= this.resFactor || ratio <= (1 / this.resFactor)); │ │ │ │ } │ │ │ │ - this.feature = new OpenLayers.Feature.Vector(); │ │ │ │ - this.createGeometry(); │ │ │ │ - this.callback("create", [this.origin, this.feature]); │ │ │ │ - this.layer.addFeatures([this.feature], { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ - this.layer.drawFeature(this.feature, this.style); │ │ │ │ + return invalid; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: move │ │ │ │ - * Respond to drag move events │ │ │ │ + * Method: calculateBounds │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Evt} The move event │ │ │ │ + * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be │ │ │ │ + * retrieved from the map object if not provided │ │ │ │ */ │ │ │ │ - move: function(evt) { │ │ │ │ - var maploc = this.layer.getLonLatFromViewPortPx(evt.xy); │ │ │ │ - var point = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat); │ │ │ │ - if (this.irregular) { │ │ │ │ - var ry = Math.sqrt(2) * Math.abs(point.y - this.origin.y) / 2; │ │ │ │ - this.radius = Math.max(this.map.getResolution() / 2, ry); │ │ │ │ - } else if (this.fixedRadius) { │ │ │ │ - this.origin = point; │ │ │ │ - } else { │ │ │ │ - this.calculateAngle(point, evt); │ │ │ │ - this.radius = Math.max(this.map.getResolution() / 2, │ │ │ │ - point.distanceTo(this.origin)); │ │ │ │ - } │ │ │ │ - this.modifyGeometry(); │ │ │ │ - if (this.irregular) { │ │ │ │ - var dx = point.x - this.origin.x; │ │ │ │ - var dy = point.y - this.origin.y; │ │ │ │ - var ratio; │ │ │ │ - if (dy == 0) { │ │ │ │ - ratio = dx / (this.radius * Math.sqrt(2)); │ │ │ │ - } else { │ │ │ │ - ratio = dx / dy; │ │ │ │ - } │ │ │ │ - this.feature.geometry.resize(1, this.origin, ratio); │ │ │ │ - this.feature.geometry.move(dx / 2, dy / 2); │ │ │ │ + calculateBounds: function(mapBounds) { │ │ │ │ + if (!mapBounds) { │ │ │ │ + mapBounds = this.getMapBounds(); │ │ │ │ } │ │ │ │ - this.layer.drawFeature(this.feature, this.style); │ │ │ │ + var center = mapBounds.getCenterLonLat(); │ │ │ │ + var dataWidth = mapBounds.getWidth() * this.ratio; │ │ │ │ + var dataHeight = mapBounds.getHeight() * this.ratio; │ │ │ │ + this.bounds = new OpenLayers.Bounds( │ │ │ │ + center.lon - (dataWidth / 2), │ │ │ │ + center.lat - (dataHeight / 2), │ │ │ │ + center.lon + (dataWidth / 2), │ │ │ │ + center.lat + (dataHeight / 2) │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: up │ │ │ │ - * Finish drawing the feature │ │ │ │ + * Method: triggerRead │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} The mouse up event │ │ │ │ - */ │ │ │ │ - up: function(evt) { │ │ │ │ - this.finalize(); │ │ │ │ - // the mouseup method of superclass doesn't call the │ │ │ │ - // "done" callback if there's been no move between │ │ │ │ - // down and up │ │ │ │ - if (this.start == this.last) { │ │ │ │ - this.callback("done", [evt.xy]); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: out │ │ │ │ - * Finish drawing the feature. │ │ │ │ + * options - {Object} Additional options for the protocol's read method │ │ │ │ + * (optional) │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} The mouse out event │ │ │ │ - */ │ │ │ │ - out: function(evt) { │ │ │ │ - this.finalize(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: createGeometry │ │ │ │ - * Create the new polygon geometry. This is called at the start of the │ │ │ │ - * drag and at any point during the drag if the number of sides │ │ │ │ - * changes. │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Protocol.Response>} The protocol response object │ │ │ │ + * returned by the layer protocol. │ │ │ │ */ │ │ │ │ - createGeometry: function() { │ │ │ │ - this.angle = Math.PI * ((1 / this.sides) - (1 / 2)); │ │ │ │ - if (this.snapAngle) { │ │ │ │ - this.angle += this.snapAngle * (Math.PI / 180); │ │ │ │ + triggerRead: function(options) { │ │ │ │ + if (this.response && !(options && options.noAbort === true)) { │ │ │ │ + this.layer.protocol.abort(this.response); │ │ │ │ + this.layer.events.triggerEvent("loadend"); │ │ │ │ } │ │ │ │ - this.feature.geometry = OpenLayers.Geometry.Polygon.createRegularPolygon( │ │ │ │ - this.origin, this.radius, this.sides, this.snapAngle │ │ │ │ - ); │ │ │ │ + var evt = { │ │ │ │ + filter: this.createFilter() │ │ │ │ + }; │ │ │ │ + this.layer.events.triggerEvent("loadstart", evt); │ │ │ │ + this.response = this.layer.protocol.read( │ │ │ │ + OpenLayers.Util.applyDefaults({ │ │ │ │ + filter: evt.filter, │ │ │ │ + callback: this.merge, │ │ │ │ + scope: this │ │ │ │ + }, options)); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: modifyGeometry │ │ │ │ - * Modify the polygon geometry in place. │ │ │ │ + * Method: createFilter │ │ │ │ + * Creates a spatial BBOX filter. If the layer that this strategy belongs │ │ │ │ + * to has a filter property, this filter will be combined with the BBOX │ │ │ │ + * filter. │ │ │ │ + * │ │ │ │ + * Returns │ │ │ │ + * {<OpenLayers.Filter>} The filter object. │ │ │ │ */ │ │ │ │ - modifyGeometry: function() { │ │ │ │ - var angle, point; │ │ │ │ - var ring = this.feature.geometry.components[0]; │ │ │ │ - // if the number of sides ever changes, create a new geometry │ │ │ │ - if (ring.components.length != (this.sides + 1)) { │ │ │ │ - this.createGeometry(); │ │ │ │ - ring = this.feature.geometry.components[0]; │ │ │ │ - } │ │ │ │ - for (var i = 0; i < this.sides; ++i) { │ │ │ │ - point = ring.components[i]; │ │ │ │ - angle = this.angle + (i * 2 * Math.PI / this.sides); │ │ │ │ - point.x = this.origin.x + (this.radius * Math.cos(angle)); │ │ │ │ - point.y = this.origin.y + (this.radius * Math.sin(angle)); │ │ │ │ - point.clearBounds(); │ │ │ │ + createFilter: function() { │ │ │ │ + var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ + value: this.bounds, │ │ │ │ + projection: this.layer.projection │ │ │ │ + }); │ │ │ │ + if (this.layer.filter) { │ │ │ │ + filter = new OpenLayers.Filter.Logical({ │ │ │ │ + type: OpenLayers.Filter.Logical.AND, │ │ │ │ + filters: [this.layer.filter, filter] │ │ │ │ + }); │ │ │ │ } │ │ │ │ + return filter; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: calculateAngle │ │ │ │ - * Calculate the angle based on settings. │ │ │ │ + * Method: merge │ │ │ │ + * Given a list of features, determine which ones to add 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: │ │ │ │ - * point - {<OpenLayers.Geometry.Point>} │ │ │ │ - * evt - {Event} │ │ │ │ + * resp - {<OpenLayers.Protocol.Response>} The response object passed │ │ │ │ + * by the protocol. │ │ │ │ */ │ │ │ │ - calculateAngle: function(point, evt) { │ │ │ │ - var alpha = Math.atan2(point.y - this.origin.y, │ │ │ │ - point.x - this.origin.x); │ │ │ │ - if (this.snapAngle && (this.snapToggle && !evt[this.snapToggle])) { │ │ │ │ - var snapAngleRad = (Math.PI / 180) * this.snapAngle; │ │ │ │ - this.angle = Math.round(alpha / snapAngleRad) * snapAngleRad; │ │ │ │ + merge: function(resp) { │ │ │ │ + this.layer.destroyFeatures(); │ │ │ │ + if (resp.success()) { │ │ │ │ + var features = resp.features; │ │ │ │ + if (features && features.length > 0) { │ │ │ │ + var remote = this.layer.projection; │ │ │ │ + var local = this.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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.layer.addFeatures(features); │ │ │ │ + } │ │ │ │ } else { │ │ │ │ - this.angle = alpha; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: cancel │ │ │ │ - * Finish the geometry and call the "cancel" callback. │ │ │ │ - */ │ │ │ │ - cancel: function() { │ │ │ │ - // the polygon geometry gets cloned in the callback method │ │ │ │ - this.callback("cancel", null); │ │ │ │ - this.finalize(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: finalize │ │ │ │ - * Finish the geometry and call the "done" callback. │ │ │ │ - */ │ │ │ │ - finalize: function() { │ │ │ │ - this.origin = null; │ │ │ │ - this.radius = this.options.radius; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: clear │ │ │ │ - * Clear any rendered features on the temporary layer. This is called │ │ │ │ - * when the handler is deactivated, canceled, or done (unless persist │ │ │ │ - * is true). │ │ │ │ - */ │ │ │ │ - clear: function() { │ │ │ │ - if (this.layer) { │ │ │ │ - this.layer.renderer.clear(); │ │ │ │ - this.layer.destroyFeatures(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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 with which to call the callback │ │ │ │ - * (defined by the control). │ │ │ │ - */ │ │ │ │ - callback: function(name, args) { │ │ │ │ - // override the callback method to always send the polygon geometry │ │ │ │ - if (this.callbacks[name]) { │ │ │ │ - this.callbacks[name].apply(this.control, │ │ │ │ - [this.feature.geometry.clone()]); │ │ │ │ - } │ │ │ │ - // since sketch features are added to the temporary layer │ │ │ │ - // they must be cleared here if done or cancel │ │ │ │ - if (!this.persist && (name == "done" || name == "cancel")) { │ │ │ │ - this.clear(); │ │ │ │ + this.bounds = null; │ │ │ │ } │ │ │ │ + this.response = null; │ │ │ │ + this.layer.events.triggerEvent("loadend", { │ │ │ │ + response: resp │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.RegularPolygon" │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.BBOX" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ 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. │ │ │ │ @@ -56252,14 +52343,1644 @@ │ │ │ │ } │ │ │ │ return geometry; │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Handler.Polygon" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ + OpenLayers/Handler/Hover.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.Hover │ │ │ │ + * The hover handler is to be used to emulate mouseovers on objects │ │ │ │ + * on the map that aren't DOM elements. For example one can use │ │ │ │ + * this handler to send WMS/GetFeatureInfo requests as the user │ │ │ │ + * moves the mouve over the map. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ + */ │ │ │ │ +OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: delay │ │ │ │ + * {Integer} - Number of milliseconds between mousemoves before │ │ │ │ + * the event is considered a hover. Default is 500. │ │ │ │ + */ │ │ │ │ + delay: 500, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: pixelTolerance │ │ │ │ + * {Integer} - Maximum number of pixels between mousemoves for │ │ │ │ + * an event to be considered a hover. Default is null. │ │ │ │ + */ │ │ │ │ + pixelTolerance: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: stopMove │ │ │ │ + * {Boolean} - Stop other listeners from being notified on mousemoves. │ │ │ │ + * Default is false. │ │ │ │ + */ │ │ │ │ + stopMove: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: px │ │ │ │ + * {<OpenLayers.Pixel>} - The location of the last mousemove, expressed │ │ │ │ + * in pixels. │ │ │ │ + */ │ │ │ │ + px: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: timerId │ │ │ │ + * {Number} - The id of the timer. │ │ │ │ + */ │ │ │ │ + timerId: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Handler.Hover │ │ │ │ + * Construct a hover 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. │ │ │ │ + * callbacks - {Object} An object with keys corresponding to callbacks │ │ │ │ + * that will be called by the handler. The callbacks should │ │ │ │ + * expect to receive a single argument, the event. Callbacks for │ │ │ │ + * 'move', the mouse is moving, and 'pause', the mouse is pausing, │ │ │ │ + * are supported. │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * the handler. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: mousemove │ │ │ │ + * Called when the mouse moves on the map. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Continue propagating this event. │ │ │ │ + */ │ │ │ │ + mousemove: function(evt) { │ │ │ │ + if (this.passesTolerance(evt.xy)) { │ │ │ │ + this.clearTimer(); │ │ │ │ + this.callback('move', [evt]); │ │ │ │ + this.px = evt.xy; │ │ │ │ + // clone the evt so original properties can be accessed even │ │ │ │ + // if the browser deletes them during the delay │ │ │ │ + evt = OpenLayers.Util.extend({}, evt); │ │ │ │ + this.timerId = window.setTimeout( │ │ │ │ + OpenLayers.Function.bind(this.delayedCall, this, evt), │ │ │ │ + this.delay │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return !this.stopMove; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: mouseout │ │ │ │ + * Called when the mouse goes out of the map. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Continue propagating this event. │ │ │ │ + */ │ │ │ │ + mouseout: function(evt) { │ │ │ │ + if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ + this.clearTimer(); │ │ │ │ + this.callback('move', [evt]); │ │ │ │ + } │ │ │ │ + return true; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: passesTolerance │ │ │ │ + * Determine whether the mouse move is within the optional pixel tolerance. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * px - {<OpenLayers.Pixel>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The mouse move is within the pixel tolerance. │ │ │ │ + */ │ │ │ │ + passesTolerance: function(px) { │ │ │ │ + var passes = true; │ │ │ │ + if (this.pixelTolerance && this.px) { │ │ │ │ + var dpx = Math.sqrt( │ │ │ │ + Math.pow(this.px.x - px.x, 2) + │ │ │ │ + Math.pow(this.px.y - px.y, 2) │ │ │ │ + ); │ │ │ │ + if (dpx < this.pixelTolerance) { │ │ │ │ + passes = false; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: delayedCall │ │ │ │ + * Triggers pause callback. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ + */ │ │ │ │ + delayedCall: function(evt) { │ │ │ │ + this.callback('pause', [evt]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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(); │ │ │ │ + deactivated = true; │ │ │ │ + } │ │ │ │ + return deactivated; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Hover" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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/RegularPolygon.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/Drag.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Handler.RegularPolygon │ │ │ │ + * Handler to draw a regular polygon on the map. Polygon is displayed on mouse │ │ │ │ + * down, moves or is modified on mouse move, and is finished on mouse up. │ │ │ │ + * The handler triggers callbacks for 'done' and 'cancel'. Create a new │ │ │ │ + * instance with the <OpenLayers.Handler.RegularPolygon> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Handler.Drag> │ │ │ │ + */ │ │ │ │ +OpenLayers.Handler.RegularPolygon = OpenLayers.Class(OpenLayers.Handler.Drag, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: sides │ │ │ │ + * {Integer} Number of sides for the regular polygon. Needs to be greater │ │ │ │ + * than 2. Defaults to 4. │ │ │ │ + */ │ │ │ │ + sides: 4, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: radius │ │ │ │ + * {Float} Optional radius in map units of the regular polygon. If this is │ │ │ │ + * set to some non-zero value, a polygon with a fixed radius will be │ │ │ │ + * drawn and dragged with mose movements. If this property is not │ │ │ │ + * set, dragging changes the radius of the polygon. Set to null by │ │ │ │ + * default. │ │ │ │ + */ │ │ │ │ + radius: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: snapAngle │ │ │ │ + * {Float} If set to a non-zero value, the handler will snap the polygon │ │ │ │ + * rotation to multiples of the snapAngle. Value is an angle measured │ │ │ │ + * in degrees counterclockwise from the positive x-axis. │ │ │ │ + */ │ │ │ │ + snapAngle: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: snapToggle │ │ │ │ + * {String} If set, snapToggle is checked on mouse events and will set │ │ │ │ + * the snap mode to the opposite of what it currently is. To disallow │ │ │ │ + * toggling between snap and non-snap mode, set freehandToggle to │ │ │ │ + * null. Acceptable toggle values are 'shiftKey', 'ctrlKey', and │ │ │ │ + * 'altKey'. Snap mode is only possible if this.snapAngle is set to a │ │ │ │ + * non-zero value. │ │ │ │ + */ │ │ │ │ + snapToggle: 'shiftKey', │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: layerOptions │ │ │ │ + * {Object} Any optional properties to be set on the sketch layer. │ │ │ │ + */ │ │ │ │ + layerOptions: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: persist │ │ │ │ + * {Boolean} Leave the feature rendered until clear is called. Default │ │ │ │ + * is false. If set to true, the feature remains rendered until │ │ │ │ + * clear is called, typically by deactivating the handler or starting │ │ │ │ + * another drawing. │ │ │ │ + */ │ │ │ │ + persist: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: irregular │ │ │ │ + * {Boolean} Draw an irregular polygon instead of a regular polygon. │ │ │ │ + * Default is false. If true, the initial mouse down will represent │ │ │ │ + * one corner of the polygon bounds and with each mouse movement, the │ │ │ │ + * polygon will be stretched so the opposite corner of its bounds │ │ │ │ + * follows the mouse position. This property takes precedence over │ │ │ │ + * the radius property. If set to true, the radius property will │ │ │ │ + * be ignored. │ │ │ │ + */ │ │ │ │ + irregular: 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: angle │ │ │ │ + * {Float} The angle from the origin (mouse down) to the current mouse │ │ │ │ + * position, in radians. This is measured counterclockwise from the │ │ │ │ + * positive x-axis. │ │ │ │ + */ │ │ │ │ + angle: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: fixedRadius │ │ │ │ + * {Boolean} The polygon has a fixed radius. True if a radius is set before │ │ │ │ + * drawing begins. False otherwise. │ │ │ │ + */ │ │ │ │ + fixedRadius: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: feature │ │ │ │ + * {<OpenLayers.Feature.Vector>} The currently drawn polygon feature │ │ │ │ + */ │ │ │ │ + feature: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: layer │ │ │ │ + * {<OpenLayers.Layer.Vector>} The temporary drawing layer │ │ │ │ + */ │ │ │ │ + layer: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: origin │ │ │ │ + * {<OpenLayers.Geometry.Point>} Location of the first mouse down │ │ │ │ + */ │ │ │ │ + origin: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Handler.RegularPolygon │ │ │ │ + * Create a new regular 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 object with properties to be set on the handler. │ │ │ │ + * If the options.sides property is not specified, the number of sides │ │ │ │ + * will default to 4. │ │ │ │ + * │ │ │ │ + * Named callbacks: │ │ │ │ + * create - Called when a sketch is first created. Callback called with │ │ │ │ + * the creation point geometry and sketch feature. │ │ │ │ + * done - Called when the sketch drawing is finished. The callback will │ │ │ │ + * recieve a single argument, the sketch 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.Drag.prototype.initialize.apply(this, │ │ │ │ + [control, callbacks, options]); │ │ │ │ + this.options = (options) ? options : {}; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setOptions │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * newOptions - {Object} │ │ │ │ + */ │ │ │ │ + setOptions: function(newOptions) { │ │ │ │ + OpenLayers.Util.extend(this.options, newOptions); │ │ │ │ + OpenLayers.Util.extend(this, newOptions); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: activate │ │ │ │ + * Turn on the handler. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The handler was successfully activated │ │ │ │ + */ │ │ │ │ + activate: function() { │ │ │ │ + var activated = false; │ │ │ │ + if (OpenLayers.Handler.Drag.prototype.activate.apply(this, arguments)) { │ │ │ │ + // create temporary vector layer for rendering geometry sketch │ │ │ │ + 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); │ │ │ │ + activated = true; │ │ │ │ + } │ │ │ │ + return activated; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Turn off the handler. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The handler was successfully deactivated │ │ │ │ + */ │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = false; │ │ │ │ + if (OpenLayers.Handler.Drag.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + // call the cancel callback if mid-drawing │ │ │ │ + if (this.dragging) { │ │ │ │ + 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.layer.destroy(false); │ │ │ │ + if (this.feature) { │ │ │ │ + this.feature.destroy(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.layer = null; │ │ │ │ + this.feature = null; │ │ │ │ + deactivated = true; │ │ │ │ + } │ │ │ │ + return deactivated; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: down │ │ │ │ + * Start drawing a new feature │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} The drag start event │ │ │ │ + */ │ │ │ │ + down: function(evt) { │ │ │ │ + this.fixedRadius = !!(this.radius); │ │ │ │ + var maploc = this.layer.getLonLatFromViewPortPx(evt.xy); │ │ │ │ + this.origin = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat); │ │ │ │ + // create the new polygon │ │ │ │ + if (!this.fixedRadius || this.irregular) { │ │ │ │ + // smallest radius should not be less one pixel in map units │ │ │ │ + // VML doesn't behave well with smaller │ │ │ │ + this.radius = this.map.getResolution(); │ │ │ │ + } │ │ │ │ + if (this.persist) { │ │ │ │ + this.clear(); │ │ │ │ + } │ │ │ │ + this.feature = new OpenLayers.Feature.Vector(); │ │ │ │ + this.createGeometry(); │ │ │ │ + this.callback("create", [this.origin, this.feature]); │ │ │ │ + this.layer.addFeatures([this.feature], { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + this.layer.drawFeature(this.feature, this.style); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: move │ │ │ │ + * Respond to drag move events │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Evt} The move event │ │ │ │ + */ │ │ │ │ + move: function(evt) { │ │ │ │ + var maploc = this.layer.getLonLatFromViewPortPx(evt.xy); │ │ │ │ + var point = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat); │ │ │ │ + if (this.irregular) { │ │ │ │ + var ry = Math.sqrt(2) * Math.abs(point.y - this.origin.y) / 2; │ │ │ │ + this.radius = Math.max(this.map.getResolution() / 2, ry); │ │ │ │ + } else if (this.fixedRadius) { │ │ │ │ + this.origin = point; │ │ │ │ + } else { │ │ │ │ + this.calculateAngle(point, evt); │ │ │ │ + this.radius = Math.max(this.map.getResolution() / 2, │ │ │ │ + point.distanceTo(this.origin)); │ │ │ │ + } │ │ │ │ + this.modifyGeometry(); │ │ │ │ + if (this.irregular) { │ │ │ │ + var dx = point.x - this.origin.x; │ │ │ │ + var dy = point.y - this.origin.y; │ │ │ │ + var ratio; │ │ │ │ + if (dy == 0) { │ │ │ │ + ratio = dx / (this.radius * Math.sqrt(2)); │ │ │ │ + } else { │ │ │ │ + ratio = dx / dy; │ │ │ │ + } │ │ │ │ + this.feature.geometry.resize(1, this.origin, ratio); │ │ │ │ + this.feature.geometry.move(dx / 2, dy / 2); │ │ │ │ + } │ │ │ │ + this.layer.drawFeature(this.feature, this.style); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: up │ │ │ │ + * Finish drawing the feature │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} The mouse up event │ │ │ │ + */ │ │ │ │ + up: function(evt) { │ │ │ │ + this.finalize(); │ │ │ │ + // the mouseup method of superclass doesn't call the │ │ │ │ + // "done" callback if there's been no move between │ │ │ │ + // down and up │ │ │ │ + if (this.start == this.last) { │ │ │ │ + this.callback("done", [evt.xy]); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: out │ │ │ │ + * Finish drawing the feature. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} The mouse out event │ │ │ │ + */ │ │ │ │ + out: function(evt) { │ │ │ │ + this.finalize(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: createGeometry │ │ │ │ + * Create the new polygon geometry. This is called at the start of the │ │ │ │ + * drag and at any point during the drag if the number of sides │ │ │ │ + * changes. │ │ │ │ + */ │ │ │ │ + createGeometry: function() { │ │ │ │ + this.angle = Math.PI * ((1 / this.sides) - (1 / 2)); │ │ │ │ + if (this.snapAngle) { │ │ │ │ + this.angle += this.snapAngle * (Math.PI / 180); │ │ │ │ + } │ │ │ │ + this.feature.geometry = OpenLayers.Geometry.Polygon.createRegularPolygon( │ │ │ │ + this.origin, this.radius, this.sides, this.snapAngle │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: modifyGeometry │ │ │ │ + * Modify the polygon geometry in place. │ │ │ │ + */ │ │ │ │ + modifyGeometry: function() { │ │ │ │ + var angle, point; │ │ │ │ + var ring = this.feature.geometry.components[0]; │ │ │ │ + // if the number of sides ever changes, create a new geometry │ │ │ │ + if (ring.components.length != (this.sides + 1)) { │ │ │ │ + this.createGeometry(); │ │ │ │ + ring = this.feature.geometry.components[0]; │ │ │ │ + } │ │ │ │ + for (var i = 0; i < this.sides; ++i) { │ │ │ │ + point = ring.components[i]; │ │ │ │ + angle = this.angle + (i * 2 * Math.PI / this.sides); │ │ │ │ + point.x = this.origin.x + (this.radius * Math.cos(angle)); │ │ │ │ + point.y = this.origin.y + (this.radius * Math.sin(angle)); │ │ │ │ + point.clearBounds(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: calculateAngle │ │ │ │ + * Calculate the angle based on settings. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} │ │ │ │ + * evt - {Event} │ │ │ │ + */ │ │ │ │ + calculateAngle: function(point, evt) { │ │ │ │ + var alpha = Math.atan2(point.y - this.origin.y, │ │ │ │ + point.x - this.origin.x); │ │ │ │ + if (this.snapAngle && (this.snapToggle && !evt[this.snapToggle])) { │ │ │ │ + var snapAngleRad = (Math.PI / 180) * this.snapAngle; │ │ │ │ + this.angle = Math.round(alpha / snapAngleRad) * snapAngleRad; │ │ │ │ + } else { │ │ │ │ + this.angle = alpha; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: cancel │ │ │ │ + * Finish the geometry and call the "cancel" callback. │ │ │ │ + */ │ │ │ │ + cancel: function() { │ │ │ │ + // the polygon geometry gets cloned in the callback method │ │ │ │ + this.callback("cancel", null); │ │ │ │ + this.finalize(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: finalize │ │ │ │ + * Finish the geometry and call the "done" callback. │ │ │ │ + */ │ │ │ │ + finalize: function() { │ │ │ │ + this.origin = null; │ │ │ │ + this.radius = this.options.radius; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: clear │ │ │ │ + * Clear any rendered features on the temporary layer. This is called │ │ │ │ + * when the handler is deactivated, canceled, or done (unless persist │ │ │ │ + * is true). │ │ │ │ + */ │ │ │ │ + clear: function() { │ │ │ │ + if (this.layer) { │ │ │ │ + this.layer.renderer.clear(); │ │ │ │ + this.layer.destroyFeatures(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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 with which to call the callback │ │ │ │ + * (defined by the control). │ │ │ │ + */ │ │ │ │ + callback: function(name, args) { │ │ │ │ + // override the callback method to always send the polygon geometry │ │ │ │ + if (this.callbacks[name]) { │ │ │ │ + this.callbacks[name].apply(this.control, │ │ │ │ + [this.feature.geometry.clone()]); │ │ │ │ + } │ │ │ │ + // since sketch features are added to the temporary layer │ │ │ │ + // they must be cleared here if done or cancel │ │ │ │ + if (!this.persist && (name == "done" || name == "cancel")) { │ │ │ │ + this.clear(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.RegularPolygon" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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/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. */ │ │ │ │ @@ -56761,4277 +54482,12037 @@ │ │ │ │ } │ │ │ │ return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Handler.Click" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/SLD.js │ │ │ │ + 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/Format/XML/VersionedOGC.js │ │ │ │ - * @requires OpenLayers/Style.js │ │ │ │ - * @requires OpenLayers/Rule.js │ │ │ │ - * @requires OpenLayers/Filter/FeatureId.js │ │ │ │ - * @requires OpenLayers/Filter/Logical.js │ │ │ │ - * @requires OpenLayers/Filter/Comparison.js │ │ │ │ - * @requires OpenLayers/Filter/Spatial.js │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.SLD │ │ │ │ - * Read/Write SLD. Create a new instance with the <OpenLayers.Format.SLD> │ │ │ │ - * constructor. │ │ │ │ + * Class: OpenLayers.handler.Keyboard │ │ │ │ + * A handler for keyboard events. Create a new instance with the │ │ │ │ + * <OpenLayers.Handler.Keyboard> constructor. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.SLD = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ +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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: profile │ │ │ │ - * {String} If provided, use a custom profile. │ │ │ │ - * │ │ │ │ - * Currently supported profiles: │ │ │ │ - * - GeoServer - parses GeoServer vendor specific capabilities for SLD. │ │ │ │ + * Property: observeElement │ │ │ │ + * {DOMElement|String} The DOM element on which we listen for │ │ │ │ + * key events. Default to the document. │ │ │ │ */ │ │ │ │ - profile: null, │ │ │ │ + observeElement: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "1.0.0". │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - defaultVersion: "1.0.0", │ │ │ │ + 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 │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: stringifyOutput │ │ │ │ - * {Boolean} If true, write will return a string otherwise a DOMElement. │ │ │ │ - * Default is true. │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - stringifyOutput: true, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + this.eventListener = null; │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: namedLayersAsArray │ │ │ │ - * {Boolean} Generate a namedLayers array. If false, the namedLayers │ │ │ │ - * property value will be an object keyed by layer name. Default is │ │ │ │ - * false. │ │ │ │ + * Method: activate │ │ │ │ */ │ │ │ │ - namedLayersAsArray: false, │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Write a SLD document given a list of styles. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * sld - {Object} An object representing the SLD. │ │ │ │ - * options - {Object} Optional configuration object. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} An SLD document string. │ │ │ │ + * 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; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read and SLD doc and return an object representing the SLD. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String | DOMElement} Data to read. │ │ │ │ - * options - {Object} Options for the reader. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An object representing the SLD. │ │ │ │ + * Method: handleKeyEvent │ │ │ │ */ │ │ │ │ + handleKeyEvent: function(evt) { │ │ │ │ + if (this.checkModifiers(evt)) { │ │ │ │ + this.callback(evt.type, [evt]); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SLD" │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Keyboard" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/GML/v2.js │ │ │ │ + OpenLayers/Handler/Box.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 │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ + * @requires OpenLayers/Handler/Drag.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.GML.v2 │ │ │ │ - * Parses GML version 2. │ │ │ │ + * Class: OpenLayers.Handler.Box │ │ │ │ + * Handler for dragging a rectangle across the map. Box is displayed │ │ │ │ + * on mouse down, moves on mouse move, and is finished on mouse up. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.GML.Base> │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, { │ │ │ │ +OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} Schema location for a particular minor version. │ │ │ │ + /** │ │ │ │ + * Property: dragHandler │ │ │ │ + * {<OpenLayers.Handler.Drag>} │ │ │ │ */ │ │ │ │ - schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd", │ │ │ │ + dragHandler: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: boxDivClassName │ │ │ │ + * {String} The CSS class to use for drawing the box. Default is │ │ │ │ + * olHandlerBoxZoomBox │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]); │ │ │ │ - }, │ │ │ │ + boxDivClassName: 'olHandlerBoxZoomBox', │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: boxOffsets │ │ │ │ + * {Object} Caches box offsets from css. This is used by the getBoxOffsets │ │ │ │ + * method. │ │ │ │ */ │ │ │ │ - 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"] │ │ │ │ - }, │ │ │ │ + boxOffsets: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: write │ │ │ │ + * Constructor: OpenLayers.Handler.Box │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector} │ │ │ │ - * An array of features or a single feature. │ │ │ │ + * control - {<OpenLayers.Control>} │ │ │ │ + * callbacks - {Object} An object with a properties whose values are │ │ │ │ + * functions. Various callbacks described below. │ │ │ │ + * options - {Object} │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Named callbacks: │ │ │ │ + * start - Called when the box drag operation starts. │ │ │ │ + * done - Called when the box drag operation is finished. │ │ │ │ + * The callback should expect to receive a single argument, the box │ │ │ │ + * bounds or a pixel. If the box dragging didn't span more than a 5 │ │ │ │ + * pixel distance, a pixel will be returned instead of a bounds object. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ + this.dragHandler = new OpenLayers.Handler.Drag( │ │ │ │ + this, { │ │ │ │ + down: this.startBox, │ │ │ │ + move: this.moveBox, │ │ │ │ + out: this.removeBox, │ │ │ │ + up: this.endBox │ │ │ │ + }, { │ │ │ │ + keyMask: this.keyMask │ │ │ │ + } │ │ │ │ ); │ │ │ │ + }, │ │ │ │ │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [root]); │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ + if (this.dragHandler) { │ │ │ │ + this.dragHandler.destroy(); │ │ │ │ + this.dragHandler = null; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: setMap │ │ │ │ */ │ │ │ │ - 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"] │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Handler.prototype.setMap.apply(this, arguments); │ │ │ │ + if (this.dragHandler) { │ │ │ │ + this.dragHandler.setMap(map); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.GML.v2" │ │ │ │ + /** │ │ │ │ + * Method: startBox │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * xy - {<OpenLayers.Pixel>} │ │ │ │ + */ │ │ │ │ + startBox: function(xy) { │ │ │ │ + this.callback("start", []); │ │ │ │ + this.zoomBox = OpenLayers.Util.createDiv('zoomBox', { │ │ │ │ + x: -9999, │ │ │ │ + y: -9999 │ │ │ │ + }); │ │ │ │ + this.zoomBox.className = this.boxDivClassName; │ │ │ │ + this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1; │ │ │ │ │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ - ====================================================================== */ │ │ │ │ + this.map.viewPortDiv.appendChild(this.zoomBox); │ │ │ │ │ │ │ │ -/* 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. */ │ │ │ │ + OpenLayers.Element.addClass( │ │ │ │ + this.map.viewPortDiv, "olDrawBox" │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Format/GML/v2.js │ │ │ │ - * @requires OpenLayers/Format/Filter/v1.js │ │ │ │ - */ │ │ │ │ + /** │ │ │ │ + * Method: moveBox │ │ │ │ + */ │ │ │ │ + moveBox: function(xy) { │ │ │ │ + var startX = this.dragHandler.start.x; │ │ │ │ + var startY = this.dragHandler.start.y; │ │ │ │ + var deltaX = Math.abs(startX - xy.x); │ │ │ │ + var deltaY = Math.abs(startY - xy.y); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * 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, { │ │ │ │ + var offset = this.getBoxOffsets(); │ │ │ │ + this.zoomBox.style.width = (deltaX + offset.width + 1) + "px"; │ │ │ │ + this.zoomBox.style.height = (deltaY + offset.height + 1) + "px"; │ │ │ │ + this.zoomBox.style.left = (xy.x < startX ? │ │ │ │ + startX - deltaX - offset.left : startX - offset.left) + "px"; │ │ │ │ + this.zoomBox.style.top = (xy.y < startY ? │ │ │ │ + startY - deltaY - offset.top : startY - offset.top) + "px"; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: VERSION │ │ │ │ - * {String} 1.0.0 │ │ │ │ - */ │ │ │ │ - VERSION: "1.0.0", │ │ │ │ + /** │ │ │ │ + * Method: endBox │ │ │ │ + */ │ │ │ │ + endBox: function(end) { │ │ │ │ + var result; │ │ │ │ + if (Math.abs(this.dragHandler.start.x - end.x) > 5 || │ │ │ │ + Math.abs(this.dragHandler.start.y - end.y) > 5) { │ │ │ │ + var start = this.dragHandler.start; │ │ │ │ + var top = Math.min(start.y, end.y); │ │ │ │ + var bottom = Math.max(start.y, end.y); │ │ │ │ + var left = Math.min(start.x, end.x); │ │ │ │ + var right = Math.max(start.x, end.x); │ │ │ │ + result = new OpenLayers.Bounds(left, bottom, right, top); │ │ │ │ + } else { │ │ │ │ + result = this.dragHandler.start.clone(); // i.e. OL.Pixel │ │ │ │ + } │ │ │ │ + this.removeBox(); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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", │ │ │ │ + this.callback("done", [result]); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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] │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Method: removeBox │ │ │ │ + * Remove the zoombox from the screen and nullify our reference to it. │ │ │ │ + */ │ │ │ │ + removeBox: function() { │ │ │ │ + this.map.viewPortDiv.removeChild(this.zoomBox); │ │ │ │ + this.zoomBox = null; │ │ │ │ + this.boxOffsets = null; │ │ │ │ + OpenLayers.Element.removeClass( │ │ │ │ + this.map.viewPortDiv, "olDrawBox" │ │ │ │ + ); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: activate │ │ │ │ + */ │ │ │ │ + activate: function() { │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.dragHandler.activate(); │ │ │ │ + return true; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + /** │ │ │ │ + * Method: deactivate │ │ │ │ + */ │ │ │ │ + deactivate: function() { │ │ │ │ + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + if (this.dragHandler.deactivate()) { │ │ │ │ + if (this.zoomBox) { │ │ │ │ + this.removeBox(); │ │ │ │ } │ │ │ │ - node.appendChild(child); │ │ │ │ } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ + return true; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ + /** │ │ │ │ + * Method: getBoxOffsets │ │ │ │ + * Determines border offsets for a box, according to the box model. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} an object with the following offsets: │ │ │ │ + * - left │ │ │ │ + * - right │ │ │ │ + * - top │ │ │ │ + * - bottom │ │ │ │ + * - width │ │ │ │ + * - height │ │ │ │ + */ │ │ │ │ + getBoxOffsets: function() { │ │ │ │ + if (!this.boxOffsets) { │ │ │ │ + // Determine the box model. If the testDiv's clientWidth is 3, then │ │ │ │ + // the borders are outside and we are dealing with the w3c box │ │ │ │ + // model. Otherwise, the browser uses the traditional box model and │ │ │ │ + // the borders are inside the box bounds, leaving us with a │ │ │ │ + // clientWidth of 1. │ │ │ │ + var testDiv = document.createElement("div"); │ │ │ │ + //testDiv.style.visibility = "hidden"; │ │ │ │ + testDiv.style.position = "absolute"; │ │ │ │ + testDiv.style.border = "1px solid black"; │ │ │ │ + testDiv.style.width = "3px"; │ │ │ │ + document.body.appendChild(testDiv); │ │ │ │ + var w3cBoxModel = testDiv.clientWidth == 3; │ │ │ │ + document.body.removeChild(testDiv); │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.Filter.v1_0_0" │ │ │ │ + var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ + "border-left-width")); │ │ │ │ + var right = parseInt(OpenLayers.Element.getStyle( │ │ │ │ + this.zoomBox, "border-right-width")); │ │ │ │ + var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ + "border-top-width")); │ │ │ │ + var bottom = parseInt(OpenLayers.Element.getStyle( │ │ │ │ + this.zoomBox, "border-bottom-width")); │ │ │ │ + this.boxOffsets = { │ │ │ │ + left: left, │ │ │ │ + right: right, │ │ │ │ + top: top, │ │ │ │ + bottom: bottom, │ │ │ │ + width: w3cBoxModel === false ? left + right : 0, │ │ │ │ + height: w3cBoxModel === false ? top + bottom : 0 │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + return this.boxOffsets; │ │ │ │ + }, │ │ │ │ │ │ │ │ - }); │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Box" │ │ │ │ +}); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/SLD/v1.js │ │ │ │ + OpenLayers/Handler/MouseWheel.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/Rule.js │ │ │ │ - * @requires OpenLayers/Format/SLD.js │ │ │ │ - * @requires OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Point.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Line.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Polygon.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Text.js │ │ │ │ - * @requires OpenLayers/Symbolizer/Raster.js │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.SLD.v1 │ │ │ │ - * Superclass for SLD version 1 parsers. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Handler.MouseWheel │ │ │ │ + * Handler for wheel up/down events. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.Filter.v1_0_0> │ │ │ │ + * - <OpenLayers.Handler> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ +OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + /** │ │ │ │ + * Property: wheelListener │ │ │ │ + * {function} │ │ │ │ */ │ │ │ │ - namespaces: { │ │ │ │ - sld: "http://www.opengis.net/sld", │ │ │ │ - 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" │ │ │ │ - }, │ │ │ │ + wheelListener: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ + * Property: interval │ │ │ │ + * {Integer} In order to increase server performance, an interval (in │ │ │ │ + * milliseconds) can be set to reduce the number of up/down events │ │ │ │ + * called. If set, a new up/down event will not be set until the │ │ │ │ + * interval has passed. │ │ │ │ + * Defaults to 0, meaning no interval. │ │ │ │ */ │ │ │ │ - defaultPrefix: "sld", │ │ │ │ + interval: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} Schema location for a particular minor version. │ │ │ │ + * Property: maxDelta │ │ │ │ + * {Integer} Maximum delta to collect before breaking from the current │ │ │ │ + * interval. In cumulative mode, this also limits the maximum delta │ │ │ │ + * returned from the handler. Default is Number.POSITIVE_INFINITY. │ │ │ │ */ │ │ │ │ - schemaLocation: null, │ │ │ │ + maxDelta: Number.POSITIVE_INFINITY, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: multipleSymbolizers │ │ │ │ - * {Boolean} Support multiple symbolizers per rule. Default is false. if │ │ │ │ - * true, an OpenLayers.Style2 instance will be created to represent │ │ │ │ - * user styles instead of an OpenLayers.Style instace. The │ │ │ │ - * OpenLayers.Style2 class allows collections of rules with multiple │ │ │ │ - * symbolizers, but is not currently useful for client side rendering. │ │ │ │ - * If multiple symbolizers is true, multiple FeatureTypeStyle elements │ │ │ │ - * are preserved in reading/writing by setting symbolizer zIndex values. │ │ │ │ - * In addition, the <defaultSymbolizer> property is ignored if │ │ │ │ - * multiple symbolizers are supported (defaults should be applied │ │ │ │ - * when rendering). │ │ │ │ + /** │ │ │ │ + * Property: delta │ │ │ │ + * {Integer} When interval is set, delta collects the mousewheel z-deltas │ │ │ │ + * of the events that occur within the interval. │ │ │ │ + * See also the cumulative option │ │ │ │ */ │ │ │ │ - multipleSymbolizers: false, │ │ │ │ + delta: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: featureTypeCounter │ │ │ │ - * {Number} Private counter for multiple feature type styles. │ │ │ │ + * Property: cumulative │ │ │ │ + * {Boolean} When interval is set: true to collect all the mousewheel │ │ │ │ + * z-deltas, false to only record the delta direction (positive or │ │ │ │ + * negative) │ │ │ │ */ │ │ │ │ - featureTypeCounter: null, │ │ │ │ + cumulative: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: defaultSymbolizer. │ │ │ │ - * {Object} A symbolizer with the SLD defaults. │ │ │ │ - */ │ │ │ │ - defaultSymbolizer: { │ │ │ │ - fillColor: "#808080", │ │ │ │ - fillOpacity: 1, │ │ │ │ - strokeColor: "#000000", │ │ │ │ - strokeOpacity: 1, │ │ │ │ - strokeWidth: 1, │ │ │ │ - strokeDashstyle: "solid", │ │ │ │ - pointRadius: 3, │ │ │ │ - graphicName: "square" │ │ │ │ + * Constructor: OpenLayers.Handler.MouseWheel │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * control - {<OpenLayers.Control>} │ │ │ │ + * 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 point geometry. │ │ │ │ + * options - {Object} │ │ │ │ + */ │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ + this.wheelListener = OpenLayers.Function.bindAsEventListener( │ │ │ │ + this.onWheelEvent, this │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ + this.wheelListener = null; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/ │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: onWheelEvent │ │ │ │ + * Catch the wheel event and handle it xbrowserly │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * e - {Event} │ │ │ │ + */ │ │ │ │ + onWheelEvent: function(e) { │ │ │ │ + │ │ │ │ + // make sure we have a map and check keyboard modifiers │ │ │ │ + if (!this.map || !this.checkModifiers(e)) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // Ride up the element's DOM hierarchy to determine if it or any of │ │ │ │ + // its ancestors was: │ │ │ │ + // * specifically marked as scrollable (CSS overflow property) │ │ │ │ + // * one of our layer divs or a div marked as scrollable │ │ │ │ + // ('olScrollable' CSS class) │ │ │ │ + // * the map div │ │ │ │ + // │ │ │ │ + var overScrollableDiv = false; │ │ │ │ + var allowScroll = false; │ │ │ │ + var overMapDiv = false; │ │ │ │ + │ │ │ │ + var elem = OpenLayers.Event.element(e); │ │ │ │ + while ((elem != null) && !overMapDiv && !overScrollableDiv) { │ │ │ │ + │ │ │ │ + if (!overScrollableDiv) { │ │ │ │ + try { │ │ │ │ + var overflow; │ │ │ │ + if (elem.currentStyle) { │ │ │ │ + overflow = elem.currentStyle["overflow"]; │ │ │ │ + } else { │ │ │ │ + var style = │ │ │ │ + document.defaultView.getComputedStyle(elem, null); │ │ │ │ + overflow = style.getPropertyValue("overflow"); │ │ │ │ + } │ │ │ │ + overScrollableDiv = (overflow && │ │ │ │ + (overflow == "auto") || (overflow == "scroll")); │ │ │ │ + } catch (err) { │ │ │ │ + //sometimes when scrolling in a popup, this causes │ │ │ │ + // obscure browser error │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (!allowScroll) { │ │ │ │ + allowScroll = OpenLayers.Element.hasClass(elem, 'olScrollable'); │ │ │ │ + if (!allowScroll) { │ │ │ │ + for (var i = 0, len = this.map.layers.length; i < len; i++) { │ │ │ │ + // Are we in the layer div? Note that we have two cases │ │ │ │ + // here: one is to catch EventPane layers, which have a │ │ │ │ + // pane above the layer (layer.pane) │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + if (elem == layer.div || elem == layer.pane) { │ │ │ │ + allowScroll = true; │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + overMapDiv = (elem == this.map.div); │ │ │ │ + │ │ │ │ + elem = elem.parentNode; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // Logic below is the following: │ │ │ │ + // │ │ │ │ + // If we are over a scrollable div or not over the map div: │ │ │ │ + // * do nothing (let the browser handle scrolling) │ │ │ │ + // │ │ │ │ + // otherwise │ │ │ │ + // │ │ │ │ + // If we are over the layer div or a 'olScrollable' div: │ │ │ │ + // * zoom/in out │ │ │ │ + // then │ │ │ │ + // * kill event (so as not to also scroll the page after zooming) │ │ │ │ + // │ │ │ │ + // otherwise │ │ │ │ + // │ │ │ │ + // Kill the event (dont scroll the page if we wheel over the │ │ │ │ + // layerswitcher or the pan/zoom control) │ │ │ │ + // │ │ │ │ + if (!overScrollableDiv && overMapDiv) { │ │ │ │ + if (allowScroll) { │ │ │ │ + var delta = 0; │ │ │ │ + │ │ │ │ + if (e.wheelDelta) { │ │ │ │ + delta = e.wheelDelta; │ │ │ │ + if (delta % 160 === 0) { │ │ │ │ + // opera have steps of 160 instead of 120 │ │ │ │ + delta = delta * 0.75; │ │ │ │ + } │ │ │ │ + delta = delta / 120; │ │ │ │ + } else if (e.detail) { │ │ │ │ + // detail in Firefox on OS X is 1/3 of Windows │ │ │ │ + // so force delta 1 / -1 │ │ │ │ + delta = -(e.detail / Math.abs(e.detail)); │ │ │ │ + } │ │ │ │ + this.delta += delta; │ │ │ │ + │ │ │ │ + window.clearTimeout(this._timeoutId); │ │ │ │ + if (this.interval && Math.abs(this.delta) < this.maxDelta) { │ │ │ │ + // store e because window.event might change during delay │ │ │ │ + var evt = OpenLayers.Util.extend({}, e); │ │ │ │ + this._timeoutId = window.setTimeout( │ │ │ │ + OpenLayers.Function.bind(function() { │ │ │ │ + this.wheelZoom(evt); │ │ │ │ + }, this), │ │ │ │ + this.interval │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + this.wheelZoom(e); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: wheelZoom │ │ │ │ + * Given the wheel event, we carry out the appropriate zooming in or out, │ │ │ │ + * based on the 'wheelDelta' or 'detail' property of the event. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * e - {Event} │ │ │ │ + */ │ │ │ │ + wheelZoom: function(e) { │ │ │ │ + var delta = this.delta; │ │ │ │ + this.delta = 0; │ │ │ │ + │ │ │ │ + if (delta) { │ │ │ │ + e.xy = this.map.events.getMousePosition(e); │ │ │ │ + if (delta < 0) { │ │ │ │ + this.callback("down", │ │ │ │ + [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]); │ │ │ │ + } else { │ │ │ │ + this.callback("up", │ │ │ │ + [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: activate │ │ │ │ + */ │ │ │ │ + activate: function(evt) { │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + //register mousewheel events specifically on the window and document │ │ │ │ + var wheelListener = this.wheelListener; │ │ │ │ + OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener); │ │ │ │ + OpenLayers.Event.observe(window, "mousewheel", wheelListener); │ │ │ │ + OpenLayers.Event.observe(document, "mousewheel", wheelListener); │ │ │ │ + return true; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: deactivate │ │ │ │ + */ │ │ │ │ + deactivate: function(evt) { │ │ │ │ + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + // unregister mousewheel events specifically on the window and document │ │ │ │ + var wheelListener = this.wheelListener; │ │ │ │ + OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener); │ │ │ │ + OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener); │ │ │ │ + OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener); │ │ │ │ + return true; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.MouseWheel" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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/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/UTFGrid.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 │ │ │ │ + * @requires OpenLayers/Tile/UTFGrid.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.UTFGrid │ │ │ │ + * This Layer reads from UTFGrid tiled data sources. Since UTFGrids are │ │ │ │ + * essentially JSON-based ASCII art with attached attributes, they are not │ │ │ │ + * visibly rendered. In order to use them in the map, you must add a │ │ │ │ + * <OpenLayers.Control.UTFGrid> control as well. │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * │ │ │ │ + * (start code) │ │ │ │ + * var world_utfgrid = new OpenLayers.Layer.UTFGrid({ │ │ │ │ + * url: "/tiles/world_utfgrid/${z}/${x}/${y}.json", │ │ │ │ + * utfgridResolution: 4, │ │ │ │ + * displayInLayerSwitcher: false │ │ │ │ + * ); │ │ │ │ + * map.addLayer(world_utfgrid); │ │ │ │ + * │ │ │ │ + * var control = new OpenLayers.Control.UTFGrid({ │ │ │ │ + * layers: [world_utfgrid], │ │ │ │ + * handlerMode: 'move', │ │ │ │ + * callback: function(dataLookup) { │ │ │ │ + * // do something with returned data │ │ │ │ + * } │ │ │ │ + * }) │ │ │ │ + * (end code) │ │ │ │ + * │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.XYZ> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.UTFGrid = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * Default is false, as UTFGrids are designed to be a transparent overlay layer. │ │ │ │ + */ │ │ │ │ + isBaseLayer: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: projection │ │ │ │ + * {<OpenLayers.Projection>} │ │ │ │ + * Source projection for the UTFGrids. Default is "EPSG:900913". │ │ │ │ + */ │ │ │ │ + projection: new OpenLayers.Projection("EPSG:900913"), │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: useJSONP │ │ │ │ + * {Boolean} │ │ │ │ + * Should we use a JSONP script approach instead of a standard AJAX call? │ │ │ │ + * │ │ │ │ + * Set to true for using utfgrids from another server. │ │ │ │ + * Avoids same-domain policy restrictions. │ │ │ │ + * Note that this only works if the server accepts │ │ │ │ + * the callback GET parameter and dynamically │ │ │ │ + * wraps the returned json in a function call. │ │ │ │ + * │ │ │ │ + * Default is false │ │ │ │ + */ │ │ │ │ + useJSONP: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: url │ │ │ │ + * {String} │ │ │ │ + * URL tempate for UTFGrid tiles. Include x, y, and z parameters. │ │ │ │ + * E.g. "/tiles/${z}/${x}/${y}.json" │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: utfgridResolution │ │ │ │ + * {Number} │ │ │ │ + * Ratio of the pixel width to the width of a UTFGrid data point. If an │ │ │ │ + * entry in the grid represents a 4x4 block of pixels, the │ │ │ │ + * utfgridResolution would be 4. Default is 2 (specified in │ │ │ │ + * <OpenLayers.Tile.UTFGrid>). │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: tileClass │ │ │ │ + * {<OpenLayers.Tile>} The tile class to use for this layer. │ │ │ │ + * Defaults is <OpenLayers.Tile.UTFGrid>. │ │ │ │ + */ │ │ │ │ + tileClass: OpenLayers.Tile.UTFGrid, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.UTFGrid │ │ │ │ + * Create a new UTFGrid layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * config - {Object} Configuration properties for the layer. │ │ │ │ + * │ │ │ │ + * Required configuration properties: │ │ │ │ + * url - {String} The url template for UTFGrid tiles. See the <url> property. │ │ │ │ + */ │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply( │ │ │ │ + this, [options.name, options.url, {}, options] │ │ │ │ + ); │ │ │ │ + this.tileOptions = OpenLayers.Util.extend({ │ │ │ │ + utfgridResolution: this.utfgridResolution │ │ │ │ + }, this.tileOptions); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: createBackBuffer │ │ │ │ + * The UTFGrid cannot create a back buffer, so this method is overriden. │ │ │ │ + */ │ │ │ │ + createBackBuffer: function() {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {Object} Only used by a subclass of this layer. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.UTFGrid>} An exact clone of this OpenLayers.Layer.UTFGrid │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.UTFGrid(this.getOptions()); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // get all additions from superclasses │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + │ │ │ │ + return obj; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: getFeatureInfo │ │ │ │ + * Get details about a feature associated with a map location. The object │ │ │ │ + * returned will have id and data properties. If the given location │ │ │ │ + * doesn't correspond to a feature, null will be returned. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * location - {<OpenLayers.LonLat>} map location │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} Object representing the feature id and UTFGrid data │ │ │ │ + * corresponding to the given map location. Returns null if the given │ │ │ │ + * location doesn't hit a feature. │ │ │ │ + */ │ │ │ │ + getFeatureInfo: function(location) { │ │ │ │ + var info = null; │ │ │ │ + var tileInfo = this.getTileData(location); │ │ │ │ + if (tileInfo && tileInfo.tile) { │ │ │ │ + info = tileInfo.tile.getFeatureInfo(tileInfo.i, tileInfo.j); │ │ │ │ + } │ │ │ │ + return info; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getFeatureId │ │ │ │ + * Get the identifier for the feature associated with a map location. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * location - {<OpenLayers.LonLat>} map location │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} The feature identifier corresponding to the given map location. │ │ │ │ + * Returns null if the location doesn't hit a feature. │ │ │ │ + */ │ │ │ │ + getFeatureId: function(location) { │ │ │ │ + var id = null; │ │ │ │ + var info = this.getTileData(location); │ │ │ │ + if (info.tile) { │ │ │ │ + id = info.tile.getFeatureId(info.i, info.j); │ │ │ │ + } │ │ │ │ + return id; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.UTFGrid" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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/Layer/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/Layer.js │ │ │ │ + * @requires OpenLayers/Tile/Image.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.Image │ │ │ │ + * Instances of OpenLayers.Layer.Image are used to display data from a web │ │ │ │ + * accessible image as a map layer. Create a new image layer with the │ │ │ │ + * <OpenLayers.Layer.Image> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Image = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: isBaseLayer │ │ │ │ + * {Boolean} The layer is a base layer. Default is true. Set this property │ │ │ │ + * in the layer options │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: url │ │ │ │ + * {String} URL of the image to use │ │ │ │ + */ │ │ │ │ + url: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: extent │ │ │ │ + * {<OpenLayers.Bounds>} The image bounds in map units. This extent will │ │ │ │ + * also be used as the default maxExtent for the layer. If you wish │ │ │ │ + * to have a maxExtent that is different than the image extent, set the │ │ │ │ + * maxExtent property of the options argument (as with any other layer). │ │ │ │ + */ │ │ │ │ + extent: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: size │ │ │ │ + * {<OpenLayers.Size>} The image size in pixels │ │ │ │ + */ │ │ │ │ + size: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: tile │ │ │ │ + * {<OpenLayers.Tile.Image>} │ │ │ │ + */ │ │ │ │ + tile: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: aspectRatio │ │ │ │ + * {Float} The ratio of height/width represented by a single pixel in the │ │ │ │ + * graphic │ │ │ │ + */ │ │ │ │ + aspectRatio: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.Image │ │ │ │ + * Create a new image layer │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} A name for the layer. │ │ │ │ + * url - {String} Relative or absolute path to the image │ │ │ │ + * extent - {<OpenLayers.Bounds>} The extent represented by the image │ │ │ │ + * size - {<OpenLayers.Size>} The size (in pixels) of the image │ │ │ │ + * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, extent, size, options) { │ │ │ │ + this.url = url; │ │ │ │ + this.extent = extent; │ │ │ │ + this.maxExtent = extent; │ │ │ │ + this.size = size; │ │ │ │ + OpenLayers.Layer.prototype.initialize.apply(this, [name, options]); │ │ │ │ + │ │ │ │ + this.aspectRatio = (this.extent.getHeight() / this.size.h) / │ │ │ │ + (this.extent.getWidth() / this.size.w); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + * Destroy this layer │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + if (this.tile) { │ │ │ │ + this.removeTileMonitoringHooks(this.tile); │ │ │ │ + this.tile.destroy(); │ │ │ │ + this.tile = null; │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ + * Paramters: │ │ │ │ + * obj - {Object} An optional layer (is this ever used?) │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.Image>} An exact copy of this layer │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.Image(this.name, │ │ │ │ + this.url, │ │ │ │ + this.extent, │ │ │ │ + this.size, │ │ │ │ + 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: setMap │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + setMap: function(map) { │ │ │ │ + /** │ │ │ │ + * If nothing to do with resolutions has been set, assume a single │ │ │ │ + * resolution determined by ratio*extent/size - if an image has a │ │ │ │ + * pixel aspect ratio different than one (as calculated above), the │ │ │ │ + * image will be stretched in one dimension only. │ │ │ │ + */ │ │ │ │ + if (this.options.maxResolution == null) { │ │ │ │ + this.options.maxResolution = this.aspectRatio * │ │ │ │ + this.extent.getWidth() / │ │ │ │ + this.size.w; │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.prototype.setMap.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveTo │ │ │ │ + * Create the tile for the image or resize it for the new resolution │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * zoomChanged - {Boolean} │ │ │ │ + * dragging - {Boolean} │ │ │ │ + */ │ │ │ │ + moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ + OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ + │ │ │ │ + var firstRendering = (this.tile == null); │ │ │ │ + │ │ │ │ + if (zoomChanged || firstRendering) { │ │ │ │ + │ │ │ │ + //determine new tile size │ │ │ │ + this.setTileSize(); │ │ │ │ + │ │ │ │ + //determine new position (upper left corner of new bounds) │ │ │ │ + var ulPx = this.map.getLayerPxFromLonLat({ │ │ │ │ + lon: this.extent.left, │ │ │ │ + lat: this.extent.top │ │ │ │ + }); │ │ │ │ + │ │ │ │ + if (firstRendering) { │ │ │ │ + //create the new tile │ │ │ │ + this.tile = new OpenLayers.Tile.Image(this, ulPx, this.extent, │ │ │ │ + null, this.tileSize); │ │ │ │ + this.addTileMonitoringHooks(this.tile); │ │ │ │ + } else { │ │ │ │ + //just resize the tile and set it's new position │ │ │ │ + this.tile.size = this.tileSize.clone(); │ │ │ │ + this.tile.position = ulPx.clone(); │ │ │ │ + } │ │ │ │ + this.tile.draw(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Set the tile size based on the map size. │ │ │ │ + */ │ │ │ │ + setTileSize: function() { │ │ │ │ + var tileWidth = this.extent.getWidth() / this.map.getResolution(); │ │ │ │ + var tileHeight = this.extent.getHeight() / this.map.getResolution(); │ │ │ │ + this.tileSize = new OpenLayers.Size(tileWidth, tileHeight); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ + tile.onLoadStart = function() { │ │ │ │ + this.events.triggerEvent("loadstart"); │ │ │ │ + }; │ │ │ │ + tile.events.register("loadstart", this, tile.onLoadStart); │ │ │ │ + │ │ │ │ + tile.onLoadEnd = function() { │ │ │ │ + this.events.triggerEvent("loadend"); │ │ │ │ + }; │ │ │ │ + tile.events.register("loadend", this, tile.onLoadEnd); │ │ │ │ + tile.events.register("unload", this, tile.onLoadEnd); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setUrl │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * newUrl - {String} │ │ │ │ + */ │ │ │ │ + setUrl: function(newUrl) { │ │ │ │ + this.url = newUrl; │ │ │ │ + this.tile.draw(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getURL │ │ │ │ + * The url we return is always the same (the image itself never changes) │ │ │ │ + * so we can ignore the bounds parameter (it will always be the same, │ │ │ │ + * anyways) │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + */ │ │ │ │ + getURL: function(bounds) { │ │ │ │ + return this.url; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Image" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/KaMap.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.KaMap │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.KaMap = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} KaMap Layer is always a base layer │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: DEFAULT_PARAMS │ │ │ │ + * {Object} parameters set by default. The default parameters set │ │ │ │ + * the format via the 'i' parameter to 'jpeg'. │ │ │ │ + */ │ │ │ │ + DEFAULT_PARAMS: { │ │ │ │ + i: 'jpeg', │ │ │ │ + map: '' │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.KaMap │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} │ │ │ │ + * url - {String} │ │ │ │ + * params - {Object} Parameters to be sent to the HTTP server in the │ │ │ │ + * query string for the tile. The format can be set via the 'i' │ │ │ │ + * parameter (defaults to jpg) , and the map should be set via │ │ │ │ + * the 'map' parameter. It has been reported that ka-Map may behave │ │ │ │ + * inconsistently if your format parameter does not match the format │ │ │ │ + * parameter configured in your config.php. (See ticket #327 for more │ │ │ │ + * information.) │ │ │ │ + * options - {Object} Additional options for the layer. Any of the │ │ │ │ + * APIProperties listed on this layer, and any layer types it │ │ │ │ + * extends, can be overridden through the options parameter. │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ + this.params = OpenLayers.Util.applyDefaults( │ │ │ │ + this.params, this.DEFAULT_PARAMS │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ + var scale = Math.round((this.map.getScale() * 10000)) / 10000; │ │ │ │ + var pX = Math.round(bounds.left / mapRes); │ │ │ │ + var pY = -Math.round(bounds.top / mapRes); │ │ │ │ + return this.getFullRequestString({ │ │ │ │ + t: pY, │ │ │ │ + l: pX, │ │ │ │ + s: scale │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: calculateGridLayout │ │ │ │ + * ka-Map uses the center point of the map as an origin for │ │ │ │ + * its tiles. Override calculateGridLayout to center tiles │ │ │ │ + * correctly for this case. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bound>} │ │ │ │ + * origin - {<OpenLayers.LonLat>} │ │ │ │ + * 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; │ │ │ │ + var tilecol = Math.floor(offsetlon / tilelon) - this.buffer; │ │ │ │ + │ │ │ │ + var offsetlat = bounds.top; │ │ │ │ + var tilerow = Math.floor(offsetlat / tilelat) + this.buffer; │ │ │ │ + │ │ │ │ + return { │ │ │ │ + tilelon: tilelon, │ │ │ │ + tilelat: tilelat, │ │ │ │ + startcol: tilecol, │ │ │ │ + startrow: tilerow │ │ │ │ + }; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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 minX = (tileLayout.startcol + col) * tilelon; │ │ │ │ + var minY = (tileLayout.startrow - row) * tilelat; │ │ │ │ + return new OpenLayers.Bounds( │ │ │ │ + minX, minY, │ │ │ │ + minX + tilelon, minY + tilelat │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.Kamap>} An exact clone of this OpenLayers.Layer.KaMap │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.KaMap(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 │ │ │ │ + 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 = []; │ │ │ │ + │ │ │ │ + return obj; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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 resolution = this.getResolution(); │ │ │ │ + var tileMapWidth = resolution * this.tileSize.w; │ │ │ │ + var tileMapHeight = resolution * this.tileSize.h; │ │ │ │ + var mapPoint = this.getLonLatFromViewPortPx(viewPortPx); │ │ │ │ + var tileLeft = tileMapWidth * Math.floor(mapPoint.lon / tileMapWidth); │ │ │ │ + var tileBottom = tileMapHeight * Math.floor(mapPoint.lat / tileMapHeight); │ │ │ │ + return new OpenLayers.Bounds(tileLeft, tileBottom, │ │ │ │ + tileLeft + tileMapWidth, │ │ │ │ + tileBottom + tileMapHeight); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.KaMap" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/PointGrid.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 │ │ │ │ + * @requires OpenLayers/Geometry/Polygon.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.PointGrid │ │ │ │ + * A point grid layer dynamically generates a regularly spaced grid of point │ │ │ │ + * features. This is a specialty layer for cases where an application needs │ │ │ │ + * a regular grid of points. It can be used, for example, in an editing │ │ │ │ + * environment to snap to a grid. │ │ │ │ + * │ │ │ │ + * Create a new vector layer with the <OpenLayers.Layer.PointGrid> constructor. │ │ │ │ + * (code) │ │ │ │ + * // create a grid with points spaced at 10 map units │ │ │ │ + * var points = new OpenLayers.Layer.PointGrid({dx: 10, dy: 10}); │ │ │ │ + * │ │ │ │ + * // create a grid with different x/y spacing rotated 15 degrees clockwise. │ │ │ │ + * var points = new OpenLayers.Layer.PointGrid({dx: 5, dy: 10, rotation: 15}); │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Vector> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.PointGrid = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: dx │ │ │ │ + * {Number} Point grid spacing in the x-axis direction (map units). │ │ │ │ + * Read-only. Use the <setSpacing> method to modify this value. │ │ │ │ + */ │ │ │ │ + dx: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: dy │ │ │ │ + * {Number} Point grid spacing in the y-axis direction (map units). │ │ │ │ + * Read-only. Use the <setSpacing> method to modify this value. │ │ │ │ + */ │ │ │ │ + dy: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: ratio │ │ │ │ + * {Number} Ratio of the desired grid size to the map viewport size. │ │ │ │ + * Default is 1.5. Larger ratios mean the grid is recalculated less often │ │ │ │ + * while panning. The <maxFeatures> setting has precedence when determining │ │ │ │ + * grid size. Read-only. Use the <setRatio> method to modify this value. │ │ │ │ + */ │ │ │ │ + ratio: 1.5, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: maxFeatures │ │ │ │ + * {Number} The maximum number of points to generate in the grid. Default │ │ │ │ + * is 250. Read-only. Use the <setMaxFeatures> method to modify this value. │ │ │ │ + */ │ │ │ │ + maxFeatures: 250, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: rotation │ │ │ │ + * {Number} Grid rotation (in degrees clockwise from the positive x-axis). │ │ │ │ + * Default is 0. Read-only. Use the <setRotation> method to modify this │ │ │ │ + * value. │ │ │ │ + */ │ │ │ │ + rotation: 0, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: origin │ │ │ │ + * {<OpenLayers.LonLat>} Grid origin. The grid lattice will be aligned with │ │ │ │ + * the origin. If not set at construction, the center of the map's maximum │ │ │ │ + * extent is used. Read-only. Use the <setOrigin> method to modify this │ │ │ │ + * value. │ │ │ │ + */ │ │ │ │ + origin: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: gridBounds │ │ │ │ + * {<OpenLayers.Bounds>} Internally cached grid bounds (with optional │ │ │ │ + * rotation applied). │ │ │ │ + */ │ │ │ │ + gridBounds: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.PointGrid │ │ │ │ + * Creates a new point grid layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * config - {Object} An object containing all configuration properties for │ │ │ │ + * the layer. The <dx> and <dy> properties are required to be set at │ │ │ │ + * construction. Any other layer properties may be set in this object. │ │ │ │ + */ │ │ │ │ + initialize: function(config) { │ │ │ │ + config = config || {}; │ │ │ │ + OpenLayers.Layer.Vector.prototype.initialize.apply(this, [config.name, config]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ + * The layer has been added to the map. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ + map.events.register("moveend", this, this.onMoveEnd); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: removeMap │ │ │ │ + * The layer has been removed from the map. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + removeMap: function(map) { │ │ │ │ + map.events.unregister("moveend", this, this.onMoveEnd); │ │ │ │ + OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setRatio │ │ │ │ + * Set the grid <ratio> property and update the grid. Can only be called │ │ │ │ + * after the layer has been added to a map with a center/extent. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * ratio - {Number} │ │ │ │ + */ │ │ │ │ + setRatio: function(ratio) { │ │ │ │ + this.ratio = ratio; │ │ │ │ + this.updateGrid(true); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setMaxFeatures │ │ │ │ + * Set the grid <maxFeatures> property and update the grid. Can only be │ │ │ │ + * called after the layer has been added to a map with a center/extent. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * maxFeatures - {Number} │ │ │ │ + */ │ │ │ │ + setMaxFeatures: function(maxFeatures) { │ │ │ │ + this.maxFeatures = maxFeatures; │ │ │ │ + this.updateGrid(true); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setSpacing │ │ │ │ + * Set the grid <dx> and <dy> properties and update the grid. If only one │ │ │ │ + * argument is provided, it will be set as <dx> and <dy>. Can only be │ │ │ │ + * called after the layer has been added to a map with a center/extent. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * dx - {Number} │ │ │ │ + * dy - {Number} │ │ │ │ + */ │ │ │ │ + setSpacing: function(dx, dy) { │ │ │ │ + this.dx = dx; │ │ │ │ + this.dy = dy || dx; │ │ │ │ + this.updateGrid(true); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setOrigin │ │ │ │ + * Set the grid <origin> property and update the grid. Can only be called │ │ │ │ + * after the layer has been added to a map with a center/extent. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * origin - {<OpenLayers.LonLat>} │ │ │ │ + */ │ │ │ │ + setOrigin: function(origin) { │ │ │ │ + this.origin = origin; │ │ │ │ + this.updateGrid(true); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getOrigin │ │ │ │ + * Get the grid <origin> property. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.LonLat>} The grid origin. │ │ │ │ + */ │ │ │ │ + getOrigin: function() { │ │ │ │ + if (!this.origin) { │ │ │ │ + this.origin = this.map.getExtent().getCenterLonLat(); │ │ │ │ + } │ │ │ │ + return this.origin; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setRotation │ │ │ │ + * Set the grid <rotation> property and update the grid. Rotation values │ │ │ │ + * are in degrees clockwise from the positive x-axis (negative values │ │ │ │ + * for counter-clockwise rotation). Can only be called after the layer │ │ │ │ + * has been added to a map with a center/extent. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * rotation - {Number} Degrees clockwise from the positive x-axis. │ │ │ │ + */ │ │ │ │ + setRotation: function(rotation) { │ │ │ │ + this.rotation = rotation; │ │ │ │ + this.updateGrid(true); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: onMoveEnd │ │ │ │ + * Listener for map "moveend" events. │ │ │ │ + */ │ │ │ │ + onMoveEnd: function() { │ │ │ │ + this.updateGrid(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getViewBounds │ │ │ │ + * Gets the (potentially rotated) view bounds for grid calculations. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} │ │ │ │ + */ │ │ │ │ + getViewBounds: function() { │ │ │ │ + var bounds = this.map.getExtent(); │ │ │ │ + if (this.rotation) { │ │ │ │ + var origin = this.getOrigin(); │ │ │ │ + var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); │ │ │ │ + var rect = bounds.toGeometry(); │ │ │ │ + rect.rotate(-this.rotation, rotationOrigin); │ │ │ │ + bounds = rect.getBounds(); │ │ │ │ + } │ │ │ │ + return bounds; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: updateGrid │ │ │ │ + * Update the grid. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * force - {Boolean} Update the grid even if the previous bounds are still │ │ │ │ + * valid. │ │ │ │ + */ │ │ │ │ + updateGrid: function(force) { │ │ │ │ + if (force || this.invalidBounds()) { │ │ │ │ + var viewBounds = this.getViewBounds(); │ │ │ │ + var origin = this.getOrigin(); │ │ │ │ + var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); │ │ │ │ + var viewBoundsWidth = viewBounds.getWidth(); │ │ │ │ + var viewBoundsHeight = viewBounds.getHeight(); │ │ │ │ + var aspectRatio = viewBoundsWidth / viewBoundsHeight; │ │ │ │ + var maxHeight = Math.sqrt(this.dx * this.dy * this.maxFeatures / aspectRatio); │ │ │ │ + var maxWidth = maxHeight * aspectRatio; │ │ │ │ + var gridWidth = Math.min(viewBoundsWidth * this.ratio, maxWidth); │ │ │ │ + var gridHeight = Math.min(viewBoundsHeight * this.ratio, maxHeight); │ │ │ │ + var center = viewBounds.getCenterLonLat(); │ │ │ │ + this.gridBounds = new OpenLayers.Bounds( │ │ │ │ + center.lon - (gridWidth / 2), │ │ │ │ + center.lat - (gridHeight / 2), │ │ │ │ + center.lon + (gridWidth / 2), │ │ │ │ + center.lat + (gridHeight / 2) │ │ │ │ + ); │ │ │ │ + var rows = Math.floor(gridHeight / this.dy); │ │ │ │ + var cols = Math.floor(gridWidth / this.dx); │ │ │ │ + var gridLeft = origin.lon + (this.dx * Math.ceil((this.gridBounds.left - origin.lon) / this.dx)); │ │ │ │ + var gridBottom = origin.lat + (this.dy * Math.ceil((this.gridBounds.bottom - origin.lat) / this.dy)); │ │ │ │ + var features = new Array(rows * cols); │ │ │ │ + var x, y, point; │ │ │ │ + for (var i = 0; i < cols; ++i) { │ │ │ │ + x = gridLeft + (i * this.dx); │ │ │ │ + for (var j = 0; j < rows; ++j) { │ │ │ │ + y = gridBottom + (j * this.dy); │ │ │ │ + point = new OpenLayers.Geometry.Point(x, y); │ │ │ │ + if (this.rotation) { │ │ │ │ + point.rotate(this.rotation, rotationOrigin); │ │ │ │ + } │ │ │ │ + features[(i * rows) + j] = new OpenLayers.Feature.Vector(point); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.destroyFeatures(this.features, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + this.addFeatures(features, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: invalidBounds │ │ │ │ + * Determine whether the previously generated point grid is invalid. │ │ │ │ + * This occurs when the map bounds extends beyond the previously │ │ │ │ + * generated grid bounds. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} │ │ │ │ + */ │ │ │ │ + invalidBounds: function() { │ │ │ │ + return !this.gridBounds || !this.gridBounds.containsBounds(this.getViewBounds()); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.PointGrid" │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/ArcGISCache.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.ArcGISCache │ │ │ │ + * Layer for accessing cached map tiles from an ArcGIS Server style mapcache. │ │ │ │ + * Tile must already be cached for this layer to access it. This does not require │ │ │ │ + * ArcGIS Server itself. │ │ │ │ + * │ │ │ │ + * A few attempts have been made at this kind of layer before. See │ │ │ │ + * http://trac.osgeo.org/openlayers/ticket/1967 │ │ │ │ + * and │ │ │ │ + * http://trac.osgeo.org/openlayers/browser/sandbox/tschaub/arcgiscache/lib/OpenLayers/Layer/ArcGISCache.js │ │ │ │ + * │ │ │ │ + * Typically the problem encountered is that the tiles seem to "jump around". │ │ │ │ + * This is due to the fact that the actual max extent for the tiles on AGS layers │ │ │ │ + * changes at each zoom level due to the way these caches are constructed. │ │ │ │ + * We have attempted to use the resolutions, tile size, and tile origin │ │ │ │ + * from the cache meta data to make the appropriate changes to the max extent │ │ │ │ + * of the tile to compensate for this behavior. This must be done as zoom levels change │ │ │ │ + * and before tiles are requested, which is why methods from base classes are overridden. │ │ │ │ + * │ │ │ │ + * For reference, you can access mapcache meta data in two ways. For accessing a │ │ │ │ + * mapcache through ArcGIS Server, you can simply go to the landing page for the │ │ │ │ + * layer. (ie. http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer) │ │ │ │ + * For accessing it directly through HTTP, there should always be a conf.xml file │ │ │ │ + * in the root directory. │ │ │ │ + * (ie. http://serverx.esri.com/arcgiscache/DG_County_roads_yesA_backgroundDark/Layers/conf.xml) │ │ │ │ + * │ │ │ │ + *Inherits from: │ │ │ │ + * - <OpenLayers.Layer.XYZ> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.ArcGISCache = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: url │ │ │ │ + * {String | Array} The base URL for the layer cache. You can also │ │ │ │ + * provide a list of URL strings for the layer if your cache is │ │ │ │ + * available from multiple origins. This must be set before the layer │ │ │ │ + * is drawn. │ │ │ │ + */ │ │ │ │ + url: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: tileOrigin │ │ │ │ + * {<OpenLayers.LonLat>} The location of the tile origin for the cache. │ │ │ │ + * An ArcGIS cache has it's origin at the upper-left (lowest x value │ │ │ │ + * and highest y value of the coordinate system). The units for the │ │ │ │ + * tile origin should be the same as the units for the cached data. │ │ │ │ + */ │ │ │ │ + tileOrigin: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: tileSize │ │ │ │ + * {<OpenLayers.Size>} This size of each tile. Defaults to 256 by 256 pixels. │ │ │ │ + */ │ │ │ │ + tileSize: new OpenLayers.Size(256, 256), │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: useAGS │ │ │ │ + * {Boolean} Indicates if we are going to be accessing the ArcGIS Server (AGS) │ │ │ │ + * cache via an AGS MapServer or directly through HTTP. When accessing via │ │ │ │ + * AGS the path structure uses a standard z/y/x structure. But AGS actually │ │ │ │ + * stores the tile images on disk using a hex based folder structure that looks │ │ │ │ + * like "http://example.com/mylayer/L00/R00000000/C00000000.png". Learn more │ │ │ │ + * about this here: │ │ │ │ + * http://blogs.esri.com/Support/blogs/mappingcenter/archive/2010/08/20/Checking-Your-Local-Cache-Folders.aspx │ │ │ │ + * Defaults to true; │ │ │ │ + */ │ │ │ │ + useArcGISServer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: type │ │ │ │ + * {String} Image type for the layer. This becomes the filename extension │ │ │ │ + * in tile requests. Default is "png" (generating a url like │ │ │ │ + * "http://example.com/mylayer/L00/R00000000/C00000000.png"). │ │ │ │ + */ │ │ │ │ + type: 'png', │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: useScales │ │ │ │ + * {Boolean} Optional override to indicate that the layer should use 'scale' information │ │ │ │ + * returned from the server capabilities object instead of 'resolution' information. │ │ │ │ + * This can be important if your tile server uses an unusual DPI for the tiles. │ │ │ │ + */ │ │ │ │ + useScales: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: overrideDPI │ │ │ │ + * {Boolean} Optional override to change the OpenLayers.DOTS_PER_INCH setting based │ │ │ │ + * on the tile information in the server capabilities object. This can be useful │ │ │ │ + * if your server has a non-standard DPI setting on its tiles, and you're only using │ │ │ │ + * tiles with that DPI. This value is used while OpenLayers is calculating resolution │ │ │ │ + * using scales, and is not necessary if you have resolution information. (This is │ │ │ │ + * typically the case) Regardless, this setting can be useful, but is dangerous │ │ │ │ + * because it will impact other layers while calculating resolution. Only use this │ │ │ │ + * if you know what you are doing. (See OpenLayers.Util.getResolutionFromScale) │ │ │ │ + */ │ │ │ │ + overrideDPI: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.ArcGISCache │ │ │ │ + * Creates a new instance of this class │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} │ │ │ │ + * url - {String} │ │ │ │ + * options - {Object} extra layer options │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, options) { │ │ │ │ + OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments); │ │ │ │ + │ │ │ │ + if (this.resolutions) { │ │ │ │ + this.serverResolutions = this.resolutions; │ │ │ │ + this.maxExtent = this.getMaxExtentForResolution(this.resolutions[0]); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // this block steps through translating the values from the server layer JSON │ │ │ │ + // capabilities object into values that we can use. This is also a helpful │ │ │ │ + // reference when configuring this layer directly. │ │ │ │ + if (this.layerInfo) { │ │ │ │ + // alias the object │ │ │ │ + var info = this.layerInfo; │ │ │ │ + │ │ │ │ + // build our extents │ │ │ │ + var startingTileExtent = new OpenLayers.Bounds( │ │ │ │ + info.fullExtent.xmin, │ │ │ │ + info.fullExtent.ymin, │ │ │ │ + info.fullExtent.xmax, │ │ │ │ + info.fullExtent.ymax │ │ │ │ + ); │ │ │ │ + │ │ │ │ + // set our projection based on the given spatial reference. │ │ │ │ + // esri uses slightly different IDs, so this may not be comprehensive │ │ │ │ + this.projection = 'EPSG:' + info.spatialReference.wkid; │ │ │ │ + this.sphericalMercator = (info.spatialReference.wkid == 102100); │ │ │ │ + │ │ │ │ + // convert esri units into openlayers units (basic feet or meters only) │ │ │ │ + this.units = (info.units == "esriFeet") ? 'ft' : 'm'; │ │ │ │ + │ │ │ │ + // optional extended section based on whether or not the server returned │ │ │ │ + // specific tile information │ │ │ │ + if (!!info.tileInfo) { │ │ │ │ + // either set the tiles based on rows/columns, or specific width/height │ │ │ │ + this.tileSize = new OpenLayers.Size( │ │ │ │ + info.tileInfo.width || info.tileInfo.cols, │ │ │ │ + info.tileInfo.height || info.tileInfo.rows │ │ │ │ + ); │ │ │ │ + │ │ │ │ + // this must be set when manually configuring this layer │ │ │ │ + this.tileOrigin = new OpenLayers.LonLat( │ │ │ │ + info.tileInfo.origin.x, │ │ │ │ + info.tileInfo.origin.y │ │ │ │ + ); │ │ │ │ + │ │ │ │ + var upperLeft = new OpenLayers.Geometry.Point( │ │ │ │ + startingTileExtent.left, │ │ │ │ + startingTileExtent.top │ │ │ │ + ); │ │ │ │ + │ │ │ │ + var bottomRight = new OpenLayers.Geometry.Point( │ │ │ │ + startingTileExtent.right, │ │ │ │ + startingTileExtent.bottom │ │ │ │ + ); │ │ │ │ + │ │ │ │ + if (this.useScales) { │ │ │ │ + this.scales = []; │ │ │ │ + } else { │ │ │ │ + this.resolutions = []; │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.lods = []; │ │ │ │ + for (var key in info.tileInfo.lods) { │ │ │ │ + if (info.tileInfo.lods.hasOwnProperty(key)) { │ │ │ │ + var lod = info.tileInfo.lods[key]; │ │ │ │ + if (this.useScales) { │ │ │ │ + this.scales.push(lod.scale); │ │ │ │ + } else { │ │ │ │ + this.resolutions.push(lod.resolution); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var start = this.getContainingTileCoords(upperLeft, lod.resolution); │ │ │ │ + lod.startTileCol = start.x; │ │ │ │ + lod.startTileRow = start.y; │ │ │ │ + │ │ │ │ + var end = this.getContainingTileCoords(bottomRight, lod.resolution); │ │ │ │ + lod.endTileCol = end.x; │ │ │ │ + lod.endTileRow = end.y; │ │ │ │ + this.lods.push(lod); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.maxExtent = this.calculateMaxExtentWithLOD(this.lods[0]); │ │ │ │ + this.serverResolutions = this.resolutions; │ │ │ │ + if (this.overrideDPI && info.tileInfo.dpi) { │ │ │ │ + // see comment above for 'overrideDPI' │ │ │ │ + OpenLayers.DOTS_PER_INCH = info.tileInfo.dpi; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getContainingTileCoords │ │ │ │ + * Calculates the x/y pixel corresponding to the position of the tile │ │ │ │ + * that contains the given point and for the for the given resolution. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} │ │ │ │ + * res - {Float} The resolution for which to compute the extent. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Pixel>} The x/y pixel corresponding to the position │ │ │ │ + * of the upper left tile for the given resolution. │ │ │ │ + */ │ │ │ │ + getContainingTileCoords: function(point, res) { │ │ │ │ + return new OpenLayers.Pixel( │ │ │ │ + Math.max(Math.floor((point.x - this.tileOrigin.lon) / (this.tileSize.w * res)), 0), │ │ │ │ + Math.max(Math.floor((this.tileOrigin.lat - point.y) / (this.tileSize.h * res)), 0) │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: calculateMaxExtentWithLOD │ │ │ │ + * Given a Level of Detail object from the server, this function │ │ │ │ + * calculates the actual max extent │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * lod - {Object} a Level of Detail Object from the server capabilities object │ │ │ │ + representing a particular zoom level │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} The actual extent of the tiles for the given zoom level │ │ │ │ + */ │ │ │ │ + calculateMaxExtentWithLOD: function(lod) { │ │ │ │ + // the max extent we're provided with just overlaps some tiles │ │ │ │ + // our real extent is the bounds of all the tiles we touch │ │ │ │ + │ │ │ │ + var numTileCols = (lod.endTileCol - lod.startTileCol) + 1; │ │ │ │ + var numTileRows = (lod.endTileRow - lod.startTileRow) + 1; │ │ │ │ + │ │ │ │ + var minX = this.tileOrigin.lon + (lod.startTileCol * this.tileSize.w * lod.resolution); │ │ │ │ + var maxX = minX + (numTileCols * this.tileSize.w * lod.resolution); │ │ │ │ + │ │ │ │ + var maxY = this.tileOrigin.lat - (lod.startTileRow * this.tileSize.h * lod.resolution); │ │ │ │ + var minY = maxY - (numTileRows * this.tileSize.h * lod.resolution); │ │ │ │ + return new OpenLayers.Bounds(minX, minY, maxX, maxY); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: calculateMaxExtentWithExtent │ │ │ │ + * Given a 'suggested' max extent from the server, this function uses │ │ │ │ + * information about the actual tile sizes to determine the actual │ │ │ │ + * extent of the layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * extent - {<OpenLayers.Bounds>} The 'suggested' extent for the layer │ │ │ │ + * res - {Float} The resolution for which to compute the extent. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} The actual extent of the tiles for the given zoom level │ │ │ │ + */ │ │ │ │ + calculateMaxExtentWithExtent: function(extent, res) { │ │ │ │ + var upperLeft = new OpenLayers.Geometry.Point(extent.left, extent.top); │ │ │ │ + var bottomRight = new OpenLayers.Geometry.Point(extent.right, extent.bottom); │ │ │ │ + var start = this.getContainingTileCoords(upperLeft, res); │ │ │ │ + var end = this.getContainingTileCoords(bottomRight, res); │ │ │ │ + var lod = { │ │ │ │ + resolution: res, │ │ │ │ + startTileCol: start.x, │ │ │ │ + startTileRow: start.y, │ │ │ │ + endTileCol: end.x, │ │ │ │ + endTileRow: end.y │ │ │ │ + }; │ │ │ │ + return this.calculateMaxExtentWithLOD(lod); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getUpperLeftTileCoord │ │ │ │ + * Calculates the x/y pixel corresponding to the position │ │ │ │ + * of the upper left tile for the given resolution. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * res - {Float} The resolution for which to compute the extent. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Pixel>} The x/y pixel corresponding to the position │ │ │ │ + * of the upper left tile for the given resolution. │ │ │ │ + */ │ │ │ │ + getUpperLeftTileCoord: function(res) { │ │ │ │ + var upperLeft = new OpenLayers.Geometry.Point( │ │ │ │ + this.maxExtent.left, │ │ │ │ + this.maxExtent.top); │ │ │ │ + return this.getContainingTileCoords(upperLeft, res); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getLowerRightTileCoord │ │ │ │ + * Calculates the x/y pixel corresponding to the position │ │ │ │ + * of the lower right tile for the given resolution. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * res - {Float} The resolution for which to compute the extent. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Pixel>} The x/y pixel corresponding to the position │ │ │ │ + * of the lower right tile for the given resolution. │ │ │ │ + */ │ │ │ │ + getLowerRightTileCoord: function(res) { │ │ │ │ + var bottomRight = new OpenLayers.Geometry.Point( │ │ │ │ + this.maxExtent.right, │ │ │ │ + this.maxExtent.bottom); │ │ │ │ + return this.getContainingTileCoords(bottomRight, res); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getMaxExtentForResolution │ │ │ │ + * Since the max extent of a set of tiles can change from zoom level │ │ │ │ + * to zoom level, we need to be able to calculate that max extent │ │ │ │ + * for a given resolution. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * res - {Float} The resolution for which to compute the extent. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} The extent for this resolution │ │ │ │ + */ │ │ │ │ + getMaxExtentForResolution: function(res) { │ │ │ │ + var start = this.getUpperLeftTileCoord(res); │ │ │ │ + var end = this.getLowerRightTileCoord(res); │ │ │ │ + │ │ │ │ + var numTileCols = (end.x - start.x) + 1; │ │ │ │ + var numTileRows = (end.y - start.y) + 1; │ │ │ │ + │ │ │ │ + var minX = this.tileOrigin.lon + (start.x * this.tileSize.w * res); │ │ │ │ + var maxX = minX + (numTileCols * this.tileSize.w * res); │ │ │ │ + │ │ │ │ + var maxY = this.tileOrigin.lat - (start.y * this.tileSize.h * res); │ │ │ │ + var minY = maxY - (numTileRows * this.tileSize.h * res); │ │ │ │ + return new OpenLayers.Bounds(minX, minY, maxX, maxY); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * Returns an exact clone of this OpenLayers.Layer.ArcGISCache │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * [obj] - {Object} optional object to assign the cloned instance to. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.ArcGISCache>} clone of this instance │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.ArcGISCache(this.name, this.url, this.options); │ │ │ │ + } │ │ │ │ + return OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: initGriddedTiles │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + */ │ │ │ │ + initGriddedTiles: function(bounds) { │ │ │ │ + delete this._tileOrigin; │ │ │ │ + OpenLayers.Layer.XYZ.prototype.initGriddedTiles.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getMaxExtent │ │ │ │ + * Get this layer's maximum extent. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} │ │ │ │ + */ │ │ │ │ + getMaxExtent: function() { │ │ │ │ + var resolution = this.map.getResolution(); │ │ │ │ + return this.maxExtent = this.getMaxExtentForResolution(resolution); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getTileOrigin │ │ │ │ + * Determine the origin for aligning the grid of tiles. │ │ │ │ + * The origin will be derived from the layer's <maxExtent> property. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.LonLat>} The tile origin. │ │ │ │ + */ │ │ │ │ + getTileOrigin: function() { │ │ │ │ + if (!this._tileOrigin) { │ │ │ │ + var extent = this.getMaxExtent(); │ │ │ │ + this._tileOrigin = new OpenLayers.LonLat(extent.left, extent.bottom); │ │ │ │ + } │ │ │ │ + return this._tileOrigin; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getURL │ │ │ │ + * Determine the URL for a tile given the tile bounds. This is should support │ │ │ │ + * urls that access tiles through an ArcGIS Server MapServer or directly through │ │ │ │ + * the hex folder structure using HTTP. Just be sure to set the useArcGISServer │ │ │ │ + * property appropriately! This is basically the same as │ │ │ │ + * 'OpenLayers.Layer.TMS.getURL', but with the addition of hex addressing, │ │ │ │ + * and tile rounding. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} The URL for a tile based on given bounds. │ │ │ │ + */ │ │ │ │ + getURL: function(bounds) { │ │ │ │ + var res = this.getResolution(); │ │ │ │ + │ │ │ │ + // tile center │ │ │ │ + var originTileX = (this.tileOrigin.lon + (res * this.tileSize.w / 2)); │ │ │ │ + var originTileY = (this.tileOrigin.lat - (res * this.tileSize.h / 2)); │ │ │ │ + │ │ │ │ + var center = bounds.getCenterLonLat(); │ │ │ │ + var point = { │ │ │ │ + x: center.lon, │ │ │ │ + y: center.lat │ │ │ │ + }; │ │ │ │ + var x = (Math.round(Math.abs((center.lon - originTileX) / (res * this.tileSize.w)))); │ │ │ │ + var y = (Math.round(Math.abs((originTileY - center.lat) / (res * this.tileSize.h)))); │ │ │ │ + var z = this.map.getZoom(); │ │ │ │ + │ │ │ │ + // this prevents us from getting pink tiles (non-existant tiles) │ │ │ │ + if (this.lods) { │ │ │ │ + var lod = this.lods[this.map.getZoom()]; │ │ │ │ + if ((x < lod.startTileCol || x > lod.endTileCol) || │ │ │ │ + (y < lod.startTileRow || y > lod.endTileRow)) { │ │ │ │ + return null; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + var start = this.getUpperLeftTileCoord(res); │ │ │ │ + var end = this.getLowerRightTileCoord(res); │ │ │ │ + if ((x < start.x || x >= end.x) || │ │ │ │ + (y < start.y || y >= end.y)) { │ │ │ │ + return null; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // Construct the url string │ │ │ │ + var url = this.url; │ │ │ │ + var s = '' + x + y + z; │ │ │ │ + │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(s, url); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // Accessing tiles through ArcGIS Server uses a different path │ │ │ │ + // structure than direct access via the folder structure. │ │ │ │ + if (this.useArcGISServer) { │ │ │ │ + // AGS MapServers have pretty url access to tiles │ │ │ │ + url = url + '/tile/${z}/${y}/${x}'; │ │ │ │ + } else { │ │ │ │ + // The tile images are stored using hex values on disk. │ │ │ │ + x = 'C' + OpenLayers.Number.zeroPad(x, 8, 16); │ │ │ │ + y = 'R' + OpenLayers.Number.zeroPad(y, 8, 16); │ │ │ │ + z = 'L' + OpenLayers.Number.zeroPad(z, 2, 10); │ │ │ │ + url = url + '/${z}/${y}/${x}.' + this.type; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // Write the values into our formatted url │ │ │ │ + url = OpenLayers.String.format(url, { │ │ │ │ + 'x': x, │ │ │ │ + 'y': y, │ │ │ │ + 'z': z │ │ │ │ + }); │ │ │ │ + │ │ │ │ + return OpenLayers.Util.urlAppend( │ │ │ │ + url, OpenLayers.Util.getParameterString(this.params) │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: 'OpenLayers.Layer.ArcGISCache' │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/Google.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/SphericalMercator.js │ │ │ │ + * @requires OpenLayers/Layer/EventPane.js │ │ │ │ + * @requires OpenLayers/Layer/FixedZoomLevels.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.Google │ │ │ │ + * │ │ │ │ + * Provides a wrapper for Google's Maps API │ │ │ │ + * Normally the Terms of Use for this API do not allow wrapping, but Google │ │ │ │ + * have provided written consent to OpenLayers for this - see email in │ │ │ │ + * http://osgeo-org.1560.n6.nabble.com/Google-Maps-API-Terms-of-Use-changes-tp4910013p4911981.html │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.SphericalMercator> │ │ │ │ + * - <OpenLayers.Layer.EventPane> │ │ │ │ + * - <OpenLayers.Layer.FixedZoomLevels> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Google = OpenLayers.Class( │ │ │ │ + OpenLayers.Layer.EventPane, │ │ │ │ + OpenLayers.Layer.FixedZoomLevels, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: MIN_ZOOM_LEVEL │ │ │ │ + * {Integer} 0 │ │ │ │ + */ │ │ │ │ + MIN_ZOOM_LEVEL: 0, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: MAX_ZOOM_LEVEL │ │ │ │ + * {Integer} 21 │ │ │ │ + */ │ │ │ │ + MAX_ZOOM_LEVEL: 21, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: RESOLUTIONS │ │ │ │ + * {Array(Float)} Hardcode these resolutions so that they are more closely │ │ │ │ + * tied with the standard wms projection │ │ │ │ + */ │ │ │ │ + RESOLUTIONS: [ │ │ │ │ + 1.40625, │ │ │ │ + 0.703125, │ │ │ │ + 0.3515625, │ │ │ │ + 0.17578125, │ │ │ │ + 0.087890625, │ │ │ │ + 0.0439453125, │ │ │ │ + 0.02197265625, │ │ │ │ + 0.010986328125, │ │ │ │ + 0.0054931640625, │ │ │ │ + 0.00274658203125, │ │ │ │ + 0.001373291015625, │ │ │ │ + 0.0006866455078125, │ │ │ │ + 0.00034332275390625, │ │ │ │ + 0.000171661376953125, │ │ │ │ + 0.0000858306884765625, │ │ │ │ + 0.00004291534423828125, │ │ │ │ + 0.00002145767211914062, │ │ │ │ + 0.00001072883605957031, │ │ │ │ + 0.00000536441802978515, │ │ │ │ + 0.00000268220901489257, │ │ │ │ + 0.0000013411045074462891, │ │ │ │ + 0.00000067055225372314453 │ │ │ │ + ], │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: type │ │ │ │ + * {GMapType} │ │ │ │ + */ │ │ │ │ + type: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: wrapDateLine │ │ │ │ + * {Boolean} Allow user to pan forever east/west. Default is true. │ │ │ │ + * Setting this to false only restricts panning if │ │ │ │ + * <sphericalMercator> is true. │ │ │ │ + */ │ │ │ │ + wrapDateLine: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: sphericalMercator │ │ │ │ + * {Boolean} Should the map act as a mercator-projected map? This will │ │ │ │ + * cause all interactions with the map to be in the actual map │ │ │ │ + * projection, which allows support for vector drawing, overlaying │ │ │ │ + * other maps, etc. │ │ │ │ + */ │ │ │ │ + sphericalMercator: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {Number} The version of the Google Maps API │ │ │ │ + */ │ │ │ │ + version: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.Google │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} A name for the layer. │ │ │ │ + * options - {Object} An optional object whose properties will be set │ │ │ │ + * on the layer. │ │ │ │ + */ │ │ │ │ + initialize: function(name, options) { │ │ │ │ + options = options || {}; │ │ │ │ + if (!options.version) { │ │ │ │ + options.version = typeof GMap2 === "function" ? "2" : "3"; │ │ │ │ + } │ │ │ │ + var mixin = OpenLayers.Layer.Google["v" + │ │ │ │ + options.version.replace(/\./g, "_")]; │ │ │ │ + if (mixin) { │ │ │ │ + OpenLayers.Util.applyDefaults(options, mixin); │ │ │ │ + } else { │ │ │ │ + throw "Unsupported Google Maps API version: " + options.version; │ │ │ │ + } │ │ │ │ + │ │ │ │ + OpenLayers.Util.applyDefaults(options, mixin.DEFAULTS); │ │ │ │ + if (options.maxExtent) { │ │ │ │ + options.maxExtent = options.maxExtent.clone(); │ │ │ │ + } │ │ │ │ + │ │ │ │ + OpenLayers.Layer.EventPane.prototype.initialize.apply(this, │ │ │ │ + [name, options]); │ │ │ │ + OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, │ │ │ │ + [name, options]); │ │ │ │ + │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator); │ │ │ │ + this.initMercatorParameters(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.Google>} An exact clone of this layer │ │ │ │ + */ │ │ │ │ + clone: function() { │ │ │ │ + /** │ │ │ │ + * This method isn't intended to be called by a subclass and it │ │ │ │ + * doesn't call the same method on the superclass. We don't call │ │ │ │ + * the super's clone because we don't want properties that are set │ │ │ │ + * on this layer after initialize (i.e. this.mapObject etc.). │ │ │ │ + */ │ │ │ │ + return new OpenLayers.Layer.Google( │ │ │ │ + this.name, this.getOptions() │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setVisibility │ │ │ │ + * Set the visibility flag for the layer and hide/show & redraw │ │ │ │ + * accordingly. Fire event unless otherwise specified │ │ │ │ + * │ │ │ │ + * Note that visibility is no longer simply whether or not the layer's │ │ │ │ + * style.display is set to "block". Now we store a 'visibility' state │ │ │ │ + * property on the layer class, this allows us to remember whether or │ │ │ │ + * not we *desire* for a layer to be visible. In the case where the │ │ │ │ + * map's resolution is out of the layer's range, this desire may be │ │ │ │ + * subverted. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * visible - {Boolean} Display the layer (if in range) │ │ │ │ + */ │ │ │ │ + setVisibility: function(visible) { │ │ │ │ + // sharing a map container, opacity has to be set per layer │ │ │ │ + var opacity = this.opacity == null ? 1 : this.opacity; │ │ │ │ + OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this, arguments); │ │ │ │ + this.setOpacity(opacity); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: display │ │ │ │ + * Hide or show the Layer │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * visible - {Boolean} │ │ │ │ + */ │ │ │ │ + display: function(visible) { │ │ │ │ + if (!this._dragging) { │ │ │ │ + this.setGMapVisibility(visible); │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.EventPane.prototype.display.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveTo │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to │ │ │ │ + * do some init work in that case. │ │ │ │ + * dragging - {Boolean} │ │ │ │ + */ │ │ │ │ + moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ + this._dragging = dragging; │ │ │ │ + OpenLayers.Layer.EventPane.prototype.moveTo.apply(this, arguments); │ │ │ │ + delete this._dragging; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setOpacity │ │ │ │ + * Sets the opacity for the entire layer (all images) │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * opacity - {Float} │ │ │ │ + */ │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ + if (opacity !== this.opacity) { │ │ │ │ + if (this.map != null) { │ │ │ │ + this.map.events.triggerEvent("changelayer", { │ │ │ │ + layer: this, │ │ │ │ + property: "opacity" │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + this.opacity = opacity; │ │ │ │ + } │ │ │ │ + // Though this layer's opacity may not change, we're sharing a container │ │ │ │ + // and need to update the opacity for the entire container. │ │ │ │ + if (this.getVisibility()) { │ │ │ │ + var container = this.getMapContainer(); │ │ │ │ + OpenLayers.Util.modifyDOMElement( │ │ │ │ + container, null, null, null, null, null, null, opacity │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Clean up this layer. │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + /** │ │ │ │ + * We have to override this method because the event pane destroy │ │ │ │ + * deletes the mapObject reference before removing this layer from │ │ │ │ + * the map. │ │ │ │ + */ │ │ │ │ + if (this.map) { │ │ │ │ + this.setGMapVisibility(false); │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache && cache.count <= 1) { │ │ │ │ + this.removeGMapElements(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.EventPane.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: removeGMapElements │ │ │ │ + * Remove all elements added to the dom. This should only be called if │ │ │ │ + * this is the last of the Google layers for the given map. │ │ │ │ + */ │ │ │ │ + removeGMapElements: function() { │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + // remove shared elements from dom │ │ │ │ + var container = this.mapObject && this.getMapContainer(); │ │ │ │ + if (container && container.parentNode) { │ │ │ │ + container.parentNode.removeChild(container); │ │ │ │ + } │ │ │ │ + var termsOfUse = cache.termsOfUse; │ │ │ │ + if (termsOfUse && termsOfUse.parentNode) { │ │ │ │ + termsOfUse.parentNode.removeChild(termsOfUse); │ │ │ │ + } │ │ │ │ + var poweredBy = cache.poweredBy; │ │ │ │ + if (poweredBy && poweredBy.parentNode) { │ │ │ │ + poweredBy.parentNode.removeChild(poweredBy); │ │ │ │ + } │ │ │ │ + if (this.mapObject && window.google && google.maps && │ │ │ │ + google.maps.event && google.maps.event.clearListeners) { │ │ │ │ + google.maps.event.clearListeners(this.mapObject, 'tilesloaded'); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: removeMap │ │ │ │ + * On being removed from the map, also remove termsOfUse and poweredBy divs │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + removeMap: function(map) { │ │ │ │ + // hide layer before removing │ │ │ │ + if (this.visibility && this.mapObject) { │ │ │ │ + this.setGMapVisibility(false); │ │ │ │ + } │ │ │ │ + // check to see if last Google layer in this map │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[map.id]; │ │ │ │ + if (cache) { │ │ │ │ + if (cache.count <= 1) { │ │ │ │ + this.removeGMapElements(); │ │ │ │ + delete OpenLayers.Layer.Google.cache[map.id]; │ │ │ │ + } else { │ │ │ │ + // decrement the layer count │ │ │ │ + --cache.count; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + // remove references to gmap elements │ │ │ │ + delete this.termsOfUse; │ │ │ │ + delete this.poweredBy; │ │ │ │ + delete this.mapObject; │ │ │ │ + delete this.dragObject; │ │ │ │ + OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + // │ │ │ │ + // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ + // │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getOLBoundsFromMapObjectBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moBounds - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Bounds>} An <OpenLayers.Bounds>, translated from the │ │ │ │ + * passed-in MapObject Bounds. │ │ │ │ + * Returns null if null value is passed in. │ │ │ │ + */ │ │ │ │ + getOLBoundsFromMapObjectBounds: function(moBounds) { │ │ │ │ + var olBounds = null; │ │ │ │ + if (moBounds != null) { │ │ │ │ + var sw = moBounds.getSouthWest(); │ │ │ │ + var ne = moBounds.getNorthEast(); │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + sw = this.forwardMercator(sw.lng(), sw.lat()); │ │ │ │ + ne = this.forwardMercator(ne.lng(), ne.lat()); │ │ │ │ + } else { │ │ │ │ + sw = new OpenLayers.LonLat(sw.lng(), sw.lat()); │ │ │ │ + ne = new OpenLayers.LonLat(ne.lng(), ne.lat()); │ │ │ │ + } │ │ │ │ + olBounds = new OpenLayers.Bounds(sw.lon, │ │ │ │ + sw.lat, │ │ │ │ + ne.lon, │ │ │ │ + ne.lat); │ │ │ │ + } │ │ │ │ + return olBounds; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getWarningHTML │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} String with information on why layer is broken, how to get │ │ │ │ + * it working. │ │ │ │ + */ │ │ │ │ + getWarningHTML: function() { │ │ │ │ + return OpenLayers.i18n("googleWarning"); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Interface Controls * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ + │ │ │ │ + │ │ │ │ + // Get&Set Center, Zoom │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectCenter │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} The mapObject's current center in Map Object format │ │ │ │ + */ │ │ │ │ + getMapObjectCenter: function() { │ │ │ │ + return this.mapObject.getCenter(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectZoom │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} The mapObject's current zoom, in Map Object format │ │ │ │ + */ │ │ │ │ + getMapObjectZoom: function() { │ │ │ │ + return this.mapObject.getZoom(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Primitives * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ + │ │ │ │ + │ │ │ │ + // LonLat │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getLongitudeFromMapObjectLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moLonLat - {Object} MapObject LonLat format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Float} Longitude of the given MapObject LonLat │ │ │ │ + */ │ │ │ │ + getLongitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + return this.sphericalMercator ? │ │ │ │ + this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon : │ │ │ │ + moLonLat.lng(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getLatitudeFromMapObjectLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moLonLat - {Object} MapObject LonLat format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Float} Latitude of the given MapObject LonLat │ │ │ │ + */ │ │ │ │ + getLatitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + var lat = this.sphericalMercator ? │ │ │ │ + this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat : │ │ │ │ + moLonLat.lat(); │ │ │ │ + return lat; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + // Pixel │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getXFromMapObjectPixel │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moPixel - {Object} MapObject Pixel format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} X value of the MapObject Pixel │ │ │ │ + */ │ │ │ │ + getXFromMapObjectPixel: function(moPixel) { │ │ │ │ + return moPixel.x; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getYFromMapObjectPixel │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moPixel - {Object} MapObject Pixel format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Integer} Y value of the MapObject Pixel │ │ │ │ + */ │ │ │ │ + getYFromMapObjectPixel: function(moPixel) { │ │ │ │ + return moPixel.y; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Google" │ │ │ │ + }); │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Property: OpenLayers.Layer.Google.cache │ │ │ │ + * {Object} Cache for elements that should only be created once per map. │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Google.cache = {}; │ │ │ │ + │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Layer.Google.v2 │ │ │ │ + * │ │ │ │ + * Mixin providing functionality specific to the Google Maps API v2. │ │ │ │ + * │ │ │ │ + * This API has been deprecated by Google. │ │ │ │ + * Developers are encouraged to migrate to v3 of the API; support for this │ │ │ │ + * is provided by <OpenLayers.Layer.Google.v3> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Google.v2 = { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: termsOfUse │ │ │ │ + * {DOMElement} Div for Google's copyright and terms of use link │ │ │ │ + */ │ │ │ │ + termsOfUse: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: poweredBy │ │ │ │ + * {DOMElement} Div for Google's powered by logo and link │ │ │ │ + */ │ │ │ │ + poweredBy: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: dragObject │ │ │ │ + * {GDraggableObject} Since 2.93, Google has exposed the ability to get │ │ │ │ + * the maps GDraggableObject. We can now use this for smooth panning │ │ │ │ + */ │ │ │ │ + dragObject: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: loadMapObject │ │ │ │ + * Load the GMap and register appropriate event listeners. If we can't │ │ │ │ + * load GMap2, then display a warning message. │ │ │ │ + */ │ │ │ │ + loadMapObject: function() { │ │ │ │ + if (!this.type) { │ │ │ │ + this.type = G_NORMAL_MAP; │ │ │ │ + } │ │ │ │ + var mapObject, termsOfUse, poweredBy; │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + // there are already Google layers added to this map │ │ │ │ + mapObject = cache.mapObject; │ │ │ │ + termsOfUse = cache.termsOfUse; │ │ │ │ + poweredBy = cache.poweredBy; │ │ │ │ + // increment the layer count │ │ │ │ + ++cache.count; │ │ │ │ + } else { │ │ │ │ + // this is the first Google layer for this map │ │ │ │ + │ │ │ │ + var container = this.map.viewPortDiv; │ │ │ │ + var div = document.createElement("div"); │ │ │ │ + div.id = this.map.id + "_GMap2Container"; │ │ │ │ + div.style.position = "absolute"; │ │ │ │ + div.style.width = "100%"; │ │ │ │ + div.style.height = "100%"; │ │ │ │ + container.appendChild(div); │ │ │ │ + │ │ │ │ + // create GMap and shuffle elements │ │ │ │ + try { │ │ │ │ + mapObject = new GMap2(div); │ │ │ │ + │ │ │ │ + // move the ToS and branding stuff up to the container div │ │ │ │ + termsOfUse = div.lastChild; │ │ │ │ + container.appendChild(termsOfUse); │ │ │ │ + termsOfUse.style.zIndex = "1100"; │ │ │ │ + termsOfUse.style.right = ""; │ │ │ │ + termsOfUse.style.bottom = ""; │ │ │ │ + termsOfUse.className = "olLayerGoogleCopyright"; │ │ │ │ + │ │ │ │ + poweredBy = div.lastChild; │ │ │ │ + container.appendChild(poweredBy); │ │ │ │ + poweredBy.style.zIndex = "1100"; │ │ │ │ + poweredBy.style.right = ""; │ │ │ │ + poweredBy.style.bottom = ""; │ │ │ │ + poweredBy.className = "olLayerGooglePoweredBy gmnoprint"; │ │ │ │ + │ │ │ │ + } catch (e) { │ │ │ │ + throw (e); │ │ │ │ + } │ │ │ │ + // cache elements for use by any other google layers added to │ │ │ │ + // this same map │ │ │ │ + OpenLayers.Layer.Google.cache[this.map.id] = { │ │ │ │ + mapObject: mapObject, │ │ │ │ + termsOfUse: termsOfUse, │ │ │ │ + poweredBy: poweredBy, │ │ │ │ + count: 1 │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.mapObject = mapObject; │ │ │ │ + this.termsOfUse = termsOfUse; │ │ │ │ + this.poweredBy = poweredBy; │ │ │ │ + │ │ │ │ + // ensure this layer type is one of the mapObject types │ │ │ │ + if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(), │ │ │ │ + this.type) === -1) { │ │ │ │ + this.mapObject.addMapType(this.type); │ │ │ │ + } │ │ │ │ + │ │ │ │ + //since v 2.93 getDragObject is now available. │ │ │ │ + if (typeof mapObject.getDragObject == "function") { │ │ │ │ + this.dragObject = mapObject.getDragObject(); │ │ │ │ + } else { │ │ │ │ + this.dragPanMapObject = null; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.isBaseLayer === false) { │ │ │ │ + this.setGMapVisibility(this.div.style.display !== "none"); │ │ │ │ + } │ │ │ │ + │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: onMapResize │ │ │ │ + */ │ │ │ │ + onMapResize: function() { │ │ │ │ + // workaround for resizing of invisible or not yet fully loaded layers │ │ │ │ + // where GMap2.checkResize() does not work. We need to load the GMap │ │ │ │ + // for the old div size, then checkResize(), and then call │ │ │ │ + // layer.moveTo() to trigger GMap.setCenter() (which will finish │ │ │ │ + // the GMap initialization). │ │ │ │ + if (this.visibility && this.mapObject.isLoaded()) { │ │ │ │ + this.mapObject.checkResize(); │ │ │ │ + } else { │ │ │ │ + if (!this._resized) { │ │ │ │ + var layer = this; │ │ │ │ + var handle = GEvent.addListener(this.mapObject, "load", function() { │ │ │ │ + GEvent.removeListener(handle); │ │ │ │ + delete layer._resized; │ │ │ │ + layer.mapObject.checkResize(); │ │ │ │ + layer.moveTo(layer.map.getCenter(), layer.map.getZoom()); │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + this._resized = true; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setGMapVisibility │ │ │ │ + * Display the GMap container and associated elements. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * visible - {Boolean} Display the GMap elements. │ │ │ │ + */ │ │ │ │ + setGMapVisibility: function(visible) { │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + var container = this.mapObject.getContainer(); │ │ │ │ + if (visible === true) { │ │ │ │ + this.mapObject.setMapType(this.type); │ │ │ │ + container.style.display = ""; │ │ │ │ + this.termsOfUse.style.left = ""; │ │ │ │ + this.termsOfUse.style.display = ""; │ │ │ │ + this.poweredBy.style.display = ""; │ │ │ │ + cache.displayed = this.id; │ │ │ │ + } else { │ │ │ │ + if (cache.displayed === this.id) { │ │ │ │ + delete cache.displayed; │ │ │ │ + } │ │ │ │ + if (!cache.displayed) { │ │ │ │ + container.style.display = "none"; │ │ │ │ + this.termsOfUse.style.display = "none"; │ │ │ │ + // move ToU far to the left in addition to setting display │ │ │ │ + // to "none", because at the end of the GMap2 load │ │ │ │ + // sequence, display: none will be unset and ToU would be │ │ │ │ + // visible after loading a map with a google layer that is │ │ │ │ + // initially hidden. │ │ │ │ + this.termsOfUse.style.left = "-9999px"; │ │ │ │ + this.poweredBy.style.display = "none"; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getMapContainer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} the GMap container's div │ │ │ │ + */ │ │ │ │ + getMapContainer: function() { │ │ │ │ + return this.mapObject.getContainer(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + // │ │ │ │ + // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ + // │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectBoundsFromOLBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * olBounds - {<OpenLayers.Bounds>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} A MapObject Bounds, translated from olBounds │ │ │ │ + * Returns null if null value is passed in │ │ │ │ + */ │ │ │ │ + getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ + var moBounds = null; │ │ │ │ + if (olBounds != null) { │ │ │ │ + var sw = this.sphericalMercator ? │ │ │ │ + this.inverseMercator(olBounds.bottom, olBounds.left) : │ │ │ │ + new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ + var ne = this.sphericalMercator ? │ │ │ │ + this.inverseMercator(olBounds.top, olBounds.right) : │ │ │ │ + new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ + moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon), │ │ │ │ + new GLatLng(ne.lat, ne.lon)); │ │ │ │ + } │ │ │ │ + return moBounds; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Interface Controls * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ + │ │ │ │ + │ │ │ │ + // Get&Set Center, Zoom │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setMapObjectCenter │ │ │ │ + * Set the mapObject to the specified center and zoom │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * center - {Object} MapObject LonLat format │ │ │ │ + * zoom - {int} MapObject zoom format │ │ │ │ + */ │ │ │ │ + setMapObjectCenter: function(center, zoom) { │ │ │ │ + this.mapObject.setCenter(center, zoom); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: dragPanMapObject │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * dX - {Integer} │ │ │ │ + * dY - {Integer} │ │ │ │ + */ │ │ │ │ + dragPanMapObject: function(dX, dY) { │ │ │ │ + this.dragObject.moveBy(new GSize(-dX, dY)); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + // LonLat - Pixel Translation │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectLonLatFromMapObjectPixel │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moPixel - {Object} MapObject Pixel format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject LonLat translated from MapObject Pixel │ │ │ │ + */ │ │ │ │ + getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ + return this.mapObject.fromContainerPixelToLatLng(moPixel); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectPixelFromMapObjectLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moLonLat - {Object} MapObject LonLat format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Pixel transtlated from MapObject LonLat │ │ │ │ + */ │ │ │ │ + getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + return this.mapObject.fromLatLngToContainerPixel(moLonLat); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + // Bounds │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectZoomFromMapObjectBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moBounds - {Object} MapObject Bounds format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Zoom for specified MapObject Bounds │ │ │ │ + */ │ │ │ │ + getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ + return this.mapObject.getBoundsZoomLevel(moBounds); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Primitives * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ + │ │ │ │ + │ │ │ │ + // LonLat │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectLonLatFromLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * lon - {Float} │ │ │ │ + * lat - {Float} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject LonLat built from lon and lat params │ │ │ │ + */ │ │ │ │ + getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ + var gLatLng; │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + var lonlat = this.inverseMercator(lon, lat); │ │ │ │ + gLatLng = new GLatLng(lonlat.lat, lonlat.lon); │ │ │ │ + } else { │ │ │ │ + gLatLng = new GLatLng(lat, lon); │ │ │ │ + } │ │ │ │ + return gLatLng; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + // Pixel │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectPixelFromXY │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * x - {Integer} │ │ │ │ + * y - {Integer} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Pixel from x and y parameters │ │ │ │ + */ │ │ │ │ + getMapObjectPixelFromXY: function(x, y) { │ │ │ │ + return new GPoint(x, y); │ │ │ │ + } │ │ │ │ + │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/ArcXML.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/Geometry/Polygon.js │ │ │ │ + * @requires OpenLayers/Geometry/Point.js │ │ │ │ + * @requires OpenLayers/Geometry/MultiPolygon.js │ │ │ │ + * @requires OpenLayers/Geometry/LinearRing.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.ArcXML │ │ │ │ + * Read/Write ArcXML. Create a new instance with the <OpenLayers.Format.ArcXML> │ │ │ │ + * constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.ArcXML = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: fontStyleKeys │ │ │ │ + * {Array} List of keys used in font styling. │ │ │ │ + */ │ │ │ │ + fontStyleKeys: [ │ │ │ │ + 'antialiasing', 'blockout', 'font', 'fontcolor', 'fontsize', 'fontstyle', │ │ │ │ + 'glowing', 'interval', 'outline', 'printmode', 'shadow', 'transparency' │ │ │ │ + ], │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: request │ │ │ │ + * A get_image request destined for an ArcIMS server. │ │ │ │ + */ │ │ │ │ + request: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: response │ │ │ │ + * A parsed response from an ArcIMS server. │ │ │ │ + */ │ │ │ │ + response: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.ArcXML │ │ │ │ + * Create a new parser/writer for ArcXML. Create an instance of this class │ │ │ │ + * to begin authoring a request to an ArcIMS service. This is used │ │ │ │ + * primarily by the ArcIMS layer, but could be used to do other wild │ │ │ │ + * stuff, like geocoding. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + initialize: function(options) { │ │ │ │ + this.request = new OpenLayers.Format.ArcXML.Request(); │ │ │ │ + this.response = new OpenLayers.Format.ArcXML.Response(); │ │ │ │ + │ │ │ │ + if (options) { │ │ │ │ + if (options.requesttype == "feature") { │ │ │ │ + this.request.get_image = null; │ │ │ │ + │ │ │ │ + var qry = this.request.get_feature.query; │ │ │ │ + this.addCoordSys(qry.featurecoordsys, options.featureCoordSys); │ │ │ │ + this.addCoordSys(qry.filtercoordsys, options.filterCoordSys); │ │ │ │ + │ │ │ │ + if (options.polygon) { │ │ │ │ + qry.isspatial = true; │ │ │ │ + qry.spatialfilter.polygon = options.polygon; │ │ │ │ + } else if (options.envelope) { │ │ │ │ + qry.isspatial = true; │ │ │ │ + qry.spatialfilter.envelope = { │ │ │ │ + minx: 0, │ │ │ │ + miny: 0, │ │ │ │ + maxx: 0, │ │ │ │ + maxy: 0 │ │ │ │ + }; │ │ │ │ + this.parseEnvelope(qry.spatialfilter.envelope, options.envelope); │ │ │ │ + } │ │ │ │ + } else if (options.requesttype == "image") { │ │ │ │ + this.request.get_feature = null; │ │ │ │ + │ │ │ │ + var props = this.request.get_image.properties; │ │ │ │ + this.parseEnvelope(props.envelope, options.envelope); │ │ │ │ + │ │ │ │ + this.addLayers(props.layerlist, options.layers); │ │ │ │ + this.addImageSize(props.imagesize, options.tileSize); │ │ │ │ + this.addCoordSys(props.featurecoordsys, options.featureCoordSys); │ │ │ │ + this.addCoordSys(props.filtercoordsys, options.filterCoordSys); │ │ │ │ + } else { │ │ │ │ + // if an arcxml object is being created with no request type, it is │ │ │ │ + // probably going to consume a response, so do not throw an error if │ │ │ │ + // the requesttype is not defined │ │ │ │ + this.request = null; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseEnvelope │ │ │ │ + * Parse an array of coordinates into an ArcXML envelope structure. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * env - {Object} An envelope object that will contain the parsed coordinates. │ │ │ │ + * arr - {Array(double)} An array of coordinates in the order: [ minx, miny, maxx, maxy ] │ │ │ │ + */ │ │ │ │ + parseEnvelope: function(env, arr) { │ │ │ │ + if (arr && arr.length == 4) { │ │ │ │ + env.minx = arr[0]; │ │ │ │ + env.miny = arr[1]; │ │ │ │ + env.maxx = arr[2]; │ │ │ │ + env.maxy = arr[3]; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: addLayers │ │ │ │ + * Add a collection of layers to another collection of layers. Each layer in the list is tuple of │ │ │ │ + * { id, visible }. These layer collections represent the │ │ │ │ + * /ARCXML/REQUEST/get_image/PROPERTIES/LAYERLIST/LAYERDEF items in ArcXML │ │ │ │ + * │ │ │ │ + * TODO: Add support for dynamic layer rendering. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * ll - {Array({id,visible})} A list of layer definitions. │ │ │ │ + * lyrs - {Array({id,visible})} A list of layer definitions. │ │ │ │ + */ │ │ │ │ + addLayers: function(ll, lyrs) { │ │ │ │ + for (var lind = 0, len = lyrs.length; lind < len; lind++) { │ │ │ │ + ll.push(lyrs[lind]); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: addImageSize │ │ │ │ + * Set the size of the requested image. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * imsize - {Object} An ArcXML imagesize object. │ │ │ │ + * olsize - {<OpenLayers.Size>} The image size to set. │ │ │ │ + */ │ │ │ │ + addImageSize: function(imsize, olsize) { │ │ │ │ + if (olsize !== null) { │ │ │ │ + imsize.width = olsize.w; │ │ │ │ + imsize.height = olsize.h; │ │ │ │ + imsize.printwidth = olsize.w; │ │ │ │ + imsize.printheight = olsize.h; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: addCoordSys │ │ │ │ + * Add the coordinate system information to an object. The object may be │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * featOrFilt - {Object} A featurecoordsys or filtercoordsys ArcXML structure. │ │ │ │ + * fsys - {String} or {<OpenLayers.Projection>} or {filtercoordsys} or │ │ │ │ + * {featurecoordsys} A projection representation. If it's a {String}, │ │ │ │ + * the value is assumed to be the SRID. If it's a {OpenLayers.Projection} │ │ │ │ + * AND Proj4js is available, the projection number and name are extracted │ │ │ │ + * from there. If it's a filter or feature ArcXML structure, it is copied. │ │ │ │ + */ │ │ │ │ + addCoordSys: function(featOrFilt, fsys) { │ │ │ │ + if (typeof fsys == "string") { │ │ │ │ + featOrFilt.id = parseInt(fsys); │ │ │ │ + featOrFilt.string = fsys; │ │ │ │ + } │ │ │ │ + // is this a proj4js instance? │ │ │ │ + else if (typeof fsys == "object" && fsys.proj !== null) { │ │ │ │ + featOrFilt.id = fsys.proj.srsProjNumber; │ │ │ │ + featOrFilt.string = fsys.proj.srsCode; │ │ │ │ + } else { │ │ │ │ + featOrFilt = fsys; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: iserror │ │ │ │ + * Check to see if the response from the server was an error. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. If nothing is supplied, │ │ │ │ + * the current response is examined. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} true if the response was an error. │ │ │ │ + */ │ │ │ │ + iserror: function(data) { │ │ │ │ + var ret = null; │ │ │ │ + │ │ │ │ + if (!data) { │ │ │ │ + ret = (this.response.error !== ''); │ │ │ │ + } else { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ + var errorNodes = data.documentElement.getElementsByTagName("ERROR"); │ │ │ │ + ret = (errorNodes !== null && errorNodes.length > 0); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return ret; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read data from a string, and return an response. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Format.ArcXML.Response>} An ArcXML response. Note that this response │ │ │ │ + * data may change in the future. │ │ │ │ + */ │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var arcNode = null; │ │ │ │ + if (data && data.documentElement) { │ │ │ │ + if (data.documentElement.nodeName == "ARCXML") { │ │ │ │ + arcNode = data.documentElement; │ │ │ │ + } else { │ │ │ │ + arcNode = data.documentElement.getElementsByTagName("ARCXML")[0]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // in Safari, arcNode will be there but will have a child named │ │ │ │ + // parsererror │ │ │ │ + if (!arcNode || arcNode.firstChild.nodeName === 'parsererror') { │ │ │ │ + var error, source; │ │ │ │ + try { │ │ │ │ + error = data.firstChild.nodeValue; │ │ │ │ + source = data.firstChild.childNodes[1].firstChild.nodeValue; │ │ │ │ + } catch (err) { │ │ │ │ + // pass │ │ │ │ + } │ │ │ │ + throw { │ │ │ │ + message: "Error parsing the ArcXML request", │ │ │ │ + error: error, │ │ │ │ + source: source │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var response = this.parseResponse(arcNode); │ │ │ │ + return response; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: write │ │ │ │ + * Generate an ArcXml document string for sending to an ArcIMS server. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A string representing the ArcXML document request. │ │ │ │ + */ │ │ │ │ + write: function(request) { │ │ │ │ + if (!request) { │ │ │ │ + request = this.request; │ │ │ │ + } │ │ │ │ + var root = this.createElementNS("", "ARCXML"); │ │ │ │ + root.setAttribute("version", "1.1"); │ │ │ │ + │ │ │ │ + var reqElem = this.createElementNS("", "REQUEST"); │ │ │ │ + │ │ │ │ + if (request.get_image != null) { │ │ │ │ + var getElem = this.createElementNS("", "GET_IMAGE"); │ │ │ │ + reqElem.appendChild(getElem); │ │ │ │ + │ │ │ │ + var propElem = this.createElementNS("", "PROPERTIES"); │ │ │ │ + getElem.appendChild(propElem); │ │ │ │ + │ │ │ │ + var props = request.get_image.properties; │ │ │ │ + if (props.featurecoordsys != null) { │ │ │ │ + var feat = this.createElementNS("", "FEATURECOORDSYS"); │ │ │ │ + propElem.appendChild(feat); │ │ │ │ + │ │ │ │ + if (props.featurecoordsys.id === 0) { │ │ │ │ + feat.setAttribute("string", props.featurecoordsys['string']); │ │ │ │ + } else { │ │ │ │ + feat.setAttribute("id", props.featurecoordsys.id); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (props.filtercoordsys != null) { │ │ │ │ + var filt = this.createElementNS("", "FILTERCOORDSYS"); │ │ │ │ + propElem.appendChild(filt); │ │ │ │ + │ │ │ │ + if (props.filtercoordsys.id === 0) { │ │ │ │ + filt.setAttribute("string", props.filtercoordsys.string); │ │ │ │ + } else { │ │ │ │ + filt.setAttribute("id", props.filtercoordsys.id); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (props.envelope != null) { │ │ │ │ + var env = this.createElementNS("", "ENVELOPE"); │ │ │ │ + propElem.appendChild(env); │ │ │ │ + │ │ │ │ + env.setAttribute("minx", props.envelope.minx); │ │ │ │ + env.setAttribute("miny", props.envelope.miny); │ │ │ │ + env.setAttribute("maxx", props.envelope.maxx); │ │ │ │ + env.setAttribute("maxy", props.envelope.maxy); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var imagesz = this.createElementNS("", "IMAGESIZE"); │ │ │ │ + propElem.appendChild(imagesz); │ │ │ │ + │ │ │ │ + imagesz.setAttribute("height", props.imagesize.height); │ │ │ │ + imagesz.setAttribute("width", props.imagesize.width); │ │ │ │ + │ │ │ │ + if (props.imagesize.height != props.imagesize.printheight || │ │ │ │ + props.imagesize.width != props.imagesize.printwidth) { │ │ │ │ + imagesz.setAttribute("printheight", props.imagesize.printheight); │ │ │ │ + imagesz.setArrtibute("printwidth", props.imagesize.printwidth); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (props.background != null) { │ │ │ │ + var backgrnd = this.createElementNS("", "BACKGROUND"); │ │ │ │ + propElem.appendChild(backgrnd); │ │ │ │ + │ │ │ │ + backgrnd.setAttribute("color", │ │ │ │ + props.background.color.r + "," + │ │ │ │ + props.background.color.g + "," + │ │ │ │ + props.background.color.b); │ │ │ │ + │ │ │ │ + if (props.background.transcolor !== null) { │ │ │ │ + backgrnd.setAttribute("transcolor", │ │ │ │ + props.background.transcolor.r + "," + │ │ │ │ + props.background.transcolor.g + "," + │ │ │ │ + props.background.transcolor.b); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (props.layerlist != null && props.layerlist.length > 0) { │ │ │ │ + var layerlst = this.createElementNS("", "LAYERLIST"); │ │ │ │ + propElem.appendChild(layerlst); │ │ │ │ + │ │ │ │ + for (var ld = 0; ld < props.layerlist.length; ld++) { │ │ │ │ + var ldef = this.createElementNS("", "LAYERDEF"); │ │ │ │ + layerlst.appendChild(ldef); │ │ │ │ + │ │ │ │ + ldef.setAttribute("id", props.layerlist[ld].id); │ │ │ │ + ldef.setAttribute("visible", props.layerlist[ld].visible); │ │ │ │ + │ │ │ │ + if (typeof props.layerlist[ld].query == "object") { │ │ │ │ + var query = props.layerlist[ld].query; │ │ │ │ + │ │ │ │ + if (query.where.length < 0) { │ │ │ │ + continue; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var queryElem = null; │ │ │ │ + if (typeof query.spatialfilter == "boolean" && query.spatialfilter) { │ │ │ │ + // handle spatial filter madness │ │ │ │ + queryElem = this.createElementNS("", "SPATIALQUERY"); │ │ │ │ + } else { │ │ │ │ + queryElem = this.createElementNS("", "QUERY"); │ │ │ │ + } │ │ │ │ + │ │ │ │ + queryElem.setAttribute("where", query.where); │ │ │ │ + │ │ │ │ + if (typeof query.accuracy == "number" && query.accuracy > 0) { │ │ │ │ + queryElem.setAttribute("accuracy", query.accuracy); │ │ │ │ + } │ │ │ │ + if (typeof query.featurelimit == "number" && query.featurelimit < 2000) { │ │ │ │ + queryElem.setAttribute("featurelimit", query.featurelimit); │ │ │ │ + } │ │ │ │ + if (typeof query.subfields == "string" && query.subfields != "#ALL#") { │ │ │ │ + queryElem.setAttribute("subfields", query.subfields); │ │ │ │ + } │ │ │ │ + if (typeof query.joinexpression == "string" && query.joinexpression.length > 0) { │ │ │ │ + queryElem.setAttribute("joinexpression", query.joinexpression); │ │ │ │ + } │ │ │ │ + if (typeof query.jointables == "string" && query.jointables.length > 0) { │ │ │ │ + queryElem.setAttribute("jointables", query.jointables); │ │ │ │ + } │ │ │ │ + │ │ │ │ + ldef.appendChild(queryElem); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (typeof props.layerlist[ld].renderer == "object") { │ │ │ │ + this.addRenderer(ldef, props.layerlist[ld].renderer); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else if (request.get_feature != null) { │ │ │ │ + var getElem = this.createElementNS("", "GET_FEATURES"); │ │ │ │ + getElem.setAttribute("outputmode", "newxml"); │ │ │ │ + getElem.setAttribute("checkesc", "true"); │ │ │ │ + │ │ │ │ + if (request.get_feature.geometry) { │ │ │ │ + getElem.setAttribute("geometry", request.get_feature.geometry); │ │ │ │ + } else { │ │ │ │ + getElem.setAttribute("geometry", "false"); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (request.get_feature.compact) { │ │ │ │ + getElem.setAttribute("compact", request.get_feature.compact); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (request.get_feature.featurelimit == "number") { │ │ │ │ + getElem.setAttribute("featurelimit", request.get_feature.featurelimit); │ │ │ │ + } │ │ │ │ + │ │ │ │ + getElem.setAttribute("globalenvelope", "true"); │ │ │ │ + reqElem.appendChild(getElem); │ │ │ │ + │ │ │ │ + if (request.get_feature.layer != null && request.get_feature.layer.length > 0) { │ │ │ │ + var lyrElem = this.createElementNS("", "LAYER"); │ │ │ │ + lyrElem.setAttribute("id", request.get_feature.layer); │ │ │ │ + getElem.appendChild(lyrElem); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var fquery = request.get_feature.query; │ │ │ │ + if (fquery != null) { │ │ │ │ + var qElem = null; │ │ │ │ + if (fquery.isspatial) { │ │ │ │ + qElem = this.createElementNS("", "SPATIALQUERY"); │ │ │ │ + } else { │ │ │ │ + qElem = this.createElementNS("", "QUERY"); │ │ │ │ + } │ │ │ │ + getElem.appendChild(qElem); │ │ │ │ + │ │ │ │ + if (typeof fquery.accuracy == "number") { │ │ │ │ + qElem.setAttribute("accuracy", fquery.accuracy); │ │ │ │ + } │ │ │ │ + //qElem.setAttribute("featurelimit", "5"); │ │ │ │ + │ │ │ │ + if (fquery.featurecoordsys != null) { │ │ │ │ + var fcsElem1 = this.createElementNS("", "FEATURECOORDSYS"); │ │ │ │ + │ │ │ │ + if (fquery.featurecoordsys.id == 0) { │ │ │ │ + fcsElem1.setAttribute("string", fquery.featurecoordsys.string); │ │ │ │ + } else { │ │ │ │ + fcsElem1.setAttribute("id", fquery.featurecoordsys.id); │ │ │ │ + } │ │ │ │ + qElem.appendChild(fcsElem1); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (fquery.filtercoordsys != null) { │ │ │ │ + var fcsElem2 = this.createElementNS("", "FILTERCOORDSYS"); │ │ │ │ + │ │ │ │ + if (fquery.filtercoordsys.id === 0) { │ │ │ │ + fcsElem2.setAttribute("string", fquery.filtercoordsys.string); │ │ │ │ + } else { │ │ │ │ + fcsElem2.setAttribute("id", fquery.filtercoordsys.id); │ │ │ │ + } │ │ │ │ + qElem.appendChild(fcsElem2); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (fquery.buffer > 0) { │ │ │ │ + var bufElem = this.createElementNS("", "BUFFER"); │ │ │ │ + bufElem.setAttribute("distance", fquery.buffer); │ │ │ │ + qElem.appendChild(bufElem); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (fquery.isspatial) { │ │ │ │ + var spfElem = this.createElementNS("", "SPATIALFILTER"); │ │ │ │ + spfElem.setAttribute("relation", fquery.spatialfilter.relation); │ │ │ │ + qElem.appendChild(spfElem); │ │ │ │ + │ │ │ │ + if (fquery.spatialfilter.envelope) { │ │ │ │ + var envElem = this.createElementNS("", "ENVELOPE"); │ │ │ │ + envElem.setAttribute("minx", fquery.spatialfilter.envelope.minx); │ │ │ │ + envElem.setAttribute("miny", fquery.spatialfilter.envelope.miny); │ │ │ │ + envElem.setAttribute("maxx", fquery.spatialfilter.envelope.maxx); │ │ │ │ + envElem.setAttribute("maxy", fquery.spatialfilter.envelope.maxy); │ │ │ │ + spfElem.appendChild(envElem); │ │ │ │ + } else if (typeof fquery.spatialfilter.polygon == "object") { │ │ │ │ + spfElem.appendChild(this.writePolygonGeometry(fquery.spatialfilter.polygon)); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (fquery.where != null && fquery.where.length > 0) { │ │ │ │ + qElem.setAttribute("where", fquery.where); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + root.appendChild(reqElem); │ │ │ │ + │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [root]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + addGroupRenderer: function(ldef, toprenderer) { │ │ │ │ + var topRelem = this.createElementNS("", "GROUPRENDERER"); │ │ │ │ + ldef.appendChild(topRelem); │ │ │ │ + │ │ │ │ + for (var rind = 0; rind < toprenderer.length; rind++) { │ │ │ │ + var renderer = toprenderer[rind]; │ │ │ │ + this.addRenderer(topRelem, renderer); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + addRenderer: function(topRelem, renderer) { │ │ │ │ + if (OpenLayers.Util.isArray(renderer)) { │ │ │ │ + this.addGroupRenderer(topRelem, renderer); │ │ │ │ + } else { │ │ │ │ + var renderElem = this.createElementNS("", renderer.type.toUpperCase() + "RENDERER"); │ │ │ │ + topRelem.appendChild(renderElem); │ │ │ │ + │ │ │ │ + if (renderElem.tagName == "VALUEMAPRENDERER") { │ │ │ │ + this.addValueMapRenderer(renderElem, renderer); │ │ │ │ + } else if (renderElem.tagName == "VALUEMAPLABELRENDERER") { │ │ │ │ + this.addValueMapLabelRenderer(renderElem, renderer); │ │ │ │ + } else if (renderElem.tagName == "SIMPLELABELRENDERER") { │ │ │ │ + this.addSimpleLabelRenderer(renderElem, renderer); │ │ │ │ + } else if (renderElem.tagName == "SCALEDEPENDENTRENDERER") { │ │ │ │ + this.addScaleDependentRenderer(renderElem, renderer); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + addScaleDependentRenderer: function(renderElem, renderer) { │ │ │ │ + if (typeof renderer.lower == "string" || typeof renderer.lower == "number") { │ │ │ │ + renderElem.setAttribute("lower", renderer.lower); │ │ │ │ + } │ │ │ │ + if (typeof renderer.upper == "string" || typeof renderer.upper == "number") { │ │ │ │ + renderElem.setAttribute("upper", renderer.upper); │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.addRenderer(renderElem, renderer.renderer); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + addValueMapLabelRenderer: function(renderElem, renderer) { │ │ │ │ + renderElem.setAttribute("lookupfield", renderer.lookupfield); │ │ │ │ + renderElem.setAttribute("labelfield", renderer.labelfield); │ │ │ │ + │ │ │ │ + if (typeof renderer.exacts == "object") { │ │ │ │ + for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) { │ │ │ │ + var exact = renderer.exacts[ext]; │ │ │ │ + │ │ │ │ + var eelem = this.createElementNS("", "EXACT"); │ │ │ │ + │ │ │ │ + if (typeof exact.value == "string") { │ │ │ │ + eelem.setAttribute("value", exact.value); │ │ │ │ + } │ │ │ │ + if (typeof exact.label == "string") { │ │ │ │ + eelem.setAttribute("label", exact.label); │ │ │ │ + } │ │ │ │ + if (typeof exact.method == "string") { │ │ │ │ + eelem.setAttribute("method", exact.method); │ │ │ │ + } │ │ │ │ + │ │ │ │ + renderElem.appendChild(eelem); │ │ │ │ + │ │ │ │ + if (typeof exact.symbol == "object") { │ │ │ │ + var selem = null; │ │ │ │ + │ │ │ │ + if (exact.symbol.type == "text") { │ │ │ │ + selem = this.createElementNS("", "TEXTSYMBOL"); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (selem != null) { │ │ │ │ + var keys = this.fontStyleKeys; │ │ │ │ + for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ + var key = keys[i]; │ │ │ │ + if (exact.symbol[key]) { │ │ │ │ + selem.setAttribute(key, exact.symbol[key]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + eelem.appendChild(selem); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } // for each exact │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ + addValueMapRenderer: function(renderElem, renderer) { │ │ │ │ + renderElem.setAttribute("lookupfield", renderer.lookupfield); │ │ │ │ + │ │ │ │ + if (typeof renderer.ranges == "object") { │ │ │ │ + for (var rng = 0, rnglen = renderer.ranges.length; rng < rnglen; rng++) { │ │ │ │ + var range = renderer.ranges[rng]; │ │ │ │ + │ │ │ │ + var relem = this.createElementNS("", "RANGE"); │ │ │ │ + relem.setAttribute("lower", range.lower); │ │ │ │ + relem.setAttribute("upper", range.upper); │ │ │ │ + │ │ │ │ + renderElem.appendChild(relem); │ │ │ │ + │ │ │ │ + if (typeof range.symbol == "object") { │ │ │ │ + var selem = null; │ │ │ │ + │ │ │ │ + if (range.symbol.type == "simplepolygon") { │ │ │ │ + selem = this.createElementNS("", "SIMPLEPOLYGONSYMBOL"); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (selem != null) { │ │ │ │ + if (typeof range.symbol.boundarycolor == "string") { │ │ │ │ + selem.setAttribute("boundarycolor", range.symbol.boundarycolor); │ │ │ │ + } │ │ │ │ + if (typeof range.symbol.fillcolor == "string") { │ │ │ │ + selem.setAttribute("fillcolor", range.symbol.fillcolor); │ │ │ │ + } │ │ │ │ + if (typeof range.symbol.filltransparency == "number") { │ │ │ │ + selem.setAttribute("filltransparency", range.symbol.filltransparency); │ │ │ │ + } │ │ │ │ + relem.appendChild(selem); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } // for each range │ │ │ │ + } else if (typeof renderer.exacts == "object") { │ │ │ │ + for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) { │ │ │ │ + var exact = renderer.exacts[ext]; │ │ │ │ + │ │ │ │ + var eelem = this.createElementNS("", "EXACT"); │ │ │ │ + if (typeof exact.value == "string") { │ │ │ │ + eelem.setAttribute("value", exact.value); │ │ │ │ + } │ │ │ │ + if (typeof exact.label == "string") { │ │ │ │ + eelem.setAttribute("label", exact.label); │ │ │ │ + } │ │ │ │ + if (typeof exact.method == "string") { │ │ │ │ + eelem.setAttribute("method", exact.method); │ │ │ │ + } │ │ │ │ + │ │ │ │ + renderElem.appendChild(eelem); │ │ │ │ + │ │ │ │ + if (typeof exact.symbol == "object") { │ │ │ │ + var selem = null; │ │ │ │ + │ │ │ │ + if (exact.symbol.type == "simplemarker") { │ │ │ │ + selem = this.createElementNS("", "SIMPLEMARKERSYMBOL"); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (selem != null) { │ │ │ │ + if (typeof exact.symbol.antialiasing == "string") { │ │ │ │ + selem.setAttribute("antialiasing", exact.symbol.antialiasing); │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.color == "string") { │ │ │ │ + selem.setAttribute("color", exact.symbol.color); │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.outline == "string") { │ │ │ │ + selem.setAttribute("outline", exact.symbol.outline); │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.overlap == "string") { │ │ │ │ + selem.setAttribute("overlap", exact.symbol.overlap); │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.shadow == "string") { │ │ │ │ + selem.setAttribute("shadow", exact.symbol.shadow); │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.transparency == "number") { │ │ │ │ + selem.setAttribute("transparency", exact.symbol.transparency); │ │ │ │ + } │ │ │ │ + //if (typeof exact.symbol.type == "string") │ │ │ │ + // selem.setAttribute("type", exact.symbol.type); │ │ │ │ + if (typeof exact.symbol.usecentroid == "string") { │ │ │ │ + selem.setAttribute("usecentroid", exact.symbol.usecentroid); │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.width == "number") { │ │ │ │ + selem.setAttribute("width", exact.symbol.width); │ │ │ │ + } │ │ │ │ + │ │ │ │ + eelem.appendChild(selem); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } // for each exact │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + addSimpleLabelRenderer: function(renderElem, renderer) { │ │ │ │ + renderElem.setAttribute("field", renderer.field); │ │ │ │ + var keys = ['featureweight', 'howmanylabels', 'labelbufferratio', │ │ │ │ + 'labelpriorities', 'labelweight', 'linelabelposition', │ │ │ │ + 'rotationalangles' │ │ │ │ + ]; │ │ │ │ + for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ + var key = keys[i]; │ │ │ │ + if (renderer[key]) { │ │ │ │ + renderElem.setAttribute(key, renderer[key]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (renderer.symbol.type == "text") { │ │ │ │ + var symbol = renderer.symbol; │ │ │ │ + var selem = this.createElementNS("", "TEXTSYMBOL"); │ │ │ │ + renderElem.appendChild(selem); │ │ │ │ + │ │ │ │ + var keys = this.fontStyleKeys; │ │ │ │ + for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ + var key = keys[i]; │ │ │ │ + if (symbol[key]) { │ │ │ │ + selem.setAttribute(key, renderer[key]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + writePolygonGeometry: function(polygon) { │ │ │ │ + if (!(polygon instanceof OpenLayers.Geometry.Polygon)) { │ │ │ │ + throw { │ │ │ │ + message: 'Cannot write polygon geometry to ArcXML with an ' + │ │ │ │ + polygon.CLASS_NAME + ' object.', │ │ │ │ + geometry: polygon │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var polyElem = this.createElementNS("", "POLYGON"); │ │ │ │ + │ │ │ │ + for (var ln = 0, lnlen = polygon.components.length; ln < lnlen; ln++) { │ │ │ │ + var ring = polygon.components[ln]; │ │ │ │ + var ringElem = this.createElementNS("", "RING"); │ │ │ │ + │ │ │ │ + for (var rn = 0, rnlen = ring.components.length; rn < rnlen; rn++) { │ │ │ │ + var point = ring.components[rn]; │ │ │ │ + var pointElem = this.createElementNS("", "POINT"); │ │ │ │ + │ │ │ │ + pointElem.setAttribute("x", point.x); │ │ │ │ + pointElem.setAttribute("y", point.y); │ │ │ │ + │ │ │ │ + ringElem.appendChild(pointElem); │ │ │ │ + } │ │ │ │ + │ │ │ │ + polyElem.appendChild(ringElem); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return polyElem; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseResponse │ │ │ │ + * Take an ArcXML response, and parse in into this object's internal properties. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} The ArcXML response, as either a string or the │ │ │ │ + * top level DOMElement of the response. │ │ │ │ + */ │ │ │ │ + parseResponse: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + var newData = new OpenLayers.Format.XML(); │ │ │ │ + data = newData.read(data); │ │ │ │ + } │ │ │ │ + var response = new OpenLayers.Format.ArcXML.Response(); │ │ │ │ + │ │ │ │ + var errorNode = data.getElementsByTagName("ERROR"); │ │ │ │ + │ │ │ │ + if (errorNode != null && errorNode.length > 0) { │ │ │ │ + response.error = this.getChildValue(errorNode, "Unknown error."); │ │ │ │ + } else { │ │ │ │ + var responseNode = data.getElementsByTagName("RESPONSE"); │ │ │ │ + │ │ │ │ + if (responseNode == null || responseNode.length == 0) { │ │ │ │ + response.error = "No RESPONSE tag found in ArcXML response."; │ │ │ │ + return response; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var rtype = responseNode[0].firstChild.nodeName; │ │ │ │ + if (rtype == "#text") { │ │ │ │ + rtype = responseNode[0].firstChild.nextSibling.nodeName; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (rtype == "IMAGE") { │ │ │ │ + var envelopeNode = data.getElementsByTagName("ENVELOPE"); │ │ │ │ + var outputNode = data.getElementsByTagName("OUTPUT"); │ │ │ │ + │ │ │ │ + if (envelopeNode == null || envelopeNode.length == 0) { │ │ │ │ + response.error = "No ENVELOPE tag found in ArcXML response."; │ │ │ │ + } else if (outputNode == null || outputNode.length == 0) { │ │ │ │ + response.error = "No OUTPUT tag found in ArcXML response."; │ │ │ │ + } else { │ │ │ │ + var envAttr = this.parseAttributes(envelopeNode[0]); │ │ │ │ + var outputAttr = this.parseAttributes(outputNode[0]); │ │ │ │ + │ │ │ │ + if (typeof outputAttr.type == "string") { │ │ │ │ + response.image = { │ │ │ │ + envelope: envAttr, │ │ │ │ + output: { │ │ │ │ + type: outputAttr.type, │ │ │ │ + data: this.getChildValue(outputNode[0]) │ │ │ │ + } │ │ │ │ + }; │ │ │ │ + } else { │ │ │ │ + response.image = { │ │ │ │ + envelope: envAttr, │ │ │ │ + output: outputAttr │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else if (rtype == "FEATURES") { │ │ │ │ + var features = responseNode[0].getElementsByTagName("FEATURES"); │ │ │ │ + │ │ │ │ + // get the feature count │ │ │ │ + var featureCount = features[0].getElementsByTagName("FEATURECOUNT"); │ │ │ │ + response.features.featurecount = featureCount[0].getAttribute("count"); │ │ │ │ + │ │ │ │ + if (response.features.featurecount > 0) { │ │ │ │ + // get the feature envelope │ │ │ │ + var envelope = features[0].getElementsByTagName("ENVELOPE"); │ │ │ │ + response.features.envelope = this.parseAttributes(envelope[0], typeof(0)); │ │ │ │ + │ │ │ │ + // get the field values per feature │ │ │ │ + var featureList = features[0].getElementsByTagName("FEATURE"); │ │ │ │ + for (var fn = 0; fn < featureList.length; fn++) { │ │ │ │ + var feature = new OpenLayers.Feature.Vector(); │ │ │ │ + var fields = featureList[fn].getElementsByTagName("FIELD"); │ │ │ │ + │ │ │ │ + for (var fdn = 0; fdn < fields.length; fdn++) { │ │ │ │ + var fieldName = fields[fdn].getAttribute("name"); │ │ │ │ + var fieldValue = fields[fdn].getAttribute("value"); │ │ │ │ + feature.attributes[fieldName] = fieldValue; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var geom = featureList[fn].getElementsByTagName("POLYGON"); │ │ │ │ + │ │ │ │ + if (geom.length > 0) { │ │ │ │ + // if there is a polygon, create an openlayers polygon, and assign │ │ │ │ + // it to the .geometry property of the feature │ │ │ │ + var ring = geom[0].getElementsByTagName("RING"); │ │ │ │ + │ │ │ │ + var polys = []; │ │ │ │ + for (var rn = 0; rn < ring.length; rn++) { │ │ │ │ + var linearRings = []; │ │ │ │ + linearRings.push(this.parsePointGeometry(ring[rn])); │ │ │ │ + │ │ │ │ + var holes = ring[rn].getElementsByTagName("HOLE"); │ │ │ │ + for (var hn = 0; hn < holes.length; hn++) { │ │ │ │ + linearRings.push(this.parsePointGeometry(holes[hn])); │ │ │ │ + } │ │ │ │ + holes = null; │ │ │ │ + polys.push(new OpenLayers.Geometry.Polygon(linearRings)); │ │ │ │ + linearRings = null; │ │ │ │ + } │ │ │ │ + ring = null; │ │ │ │ + │ │ │ │ + if (polys.length == 1) { │ │ │ │ + feature.geometry = polys[0]; │ │ │ │ + } else { │ │ │ │ + feature.geometry = new OpenLayers.Geometry.MultiPolygon(polys); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + response.features.feature.push(feature); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + response.error = "Unidentified response type."; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return response; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseAttributes │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {<DOMElement>} An element to parse attributes from. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} An attributes object, with properties set to attribute values. │ │ │ │ + */ │ │ │ │ + parseAttributes: function(node, type) { │ │ │ │ + var attributes = {}; │ │ │ │ + for (var attr = 0; attr < node.attributes.length; attr++) { │ │ │ │ + if (type == "number") { │ │ │ │ + attributes[node.attributes[attr].nodeName] = parseFloat(node.attributes[attr].nodeValue); │ │ │ │ + } else { │ │ │ │ + attributes[node.attributes[attr].nodeName] = node.attributes[attr].nodeValue; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return attributes; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parsePointGeometry │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {<DOMElement>} An element to parse <COORDS> or <POINT> arcxml data from. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Geometry.LinearRing>} A linear ring represented by the node's points. │ │ │ │ + */ │ │ │ │ + parsePointGeometry: function(node) { │ │ │ │ + var ringPoints = []; │ │ │ │ + var coords = node.getElementsByTagName("COORDS"); │ │ │ │ + │ │ │ │ + if (coords.length > 0) { │ │ │ │ + // if coords is present, it's the only coords item │ │ │ │ + var coordArr = this.getChildValue(coords[0]); │ │ │ │ + coordArr = coordArr.split(/;/); │ │ │ │ + for (var cn = 0; cn < coordArr.length; cn++) { │ │ │ │ + var coordItems = coordArr[cn].split(/ /); │ │ │ │ + ringPoints.push(new OpenLayers.Geometry.Point(coordItems[0], coordItems[1])); │ │ │ │ + } │ │ │ │ + coords = null; │ │ │ │ + } else { │ │ │ │ + var point = node.getElementsByTagName("POINT"); │ │ │ │ + if (point.length > 0) { │ │ │ │ + for (var pn = 0; pn < point.length; pn++) { │ │ │ │ + ringPoints.push( │ │ │ │ + new OpenLayers.Geometry.Point( │ │ │ │ + parseFloat(point[pn].getAttribute("x")), │ │ │ │ + parseFloat(point[pn].getAttribute("y")) │ │ │ │ + ) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + point = null; │ │ │ │ + } │ │ │ │ + │ │ │ │ + return new OpenLayers.Geometry.LinearRing(ringPoints); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.ArcXML" │ │ │ │ +}); │ │ │ │ + │ │ │ │ +OpenLayers.Format.ArcXML.Request = OpenLayers.Class({ │ │ │ │ + initialize: function(params) { │ │ │ │ + var defaults = { │ │ │ │ + get_image: { │ │ │ │ + properties: { │ │ │ │ + background: null, │ │ │ │ + /*{ │ │ │ │ + color: { r:255, g:255, b:255 }, │ │ │ │ + transcolor: null │ │ │ │ + },*/ │ │ │ │ + draw: true, │ │ │ │ + envelope: { │ │ │ │ + minx: 0, │ │ │ │ + miny: 0, │ │ │ │ + maxx: 0, │ │ │ │ + maxy: 0 │ │ │ │ + }, │ │ │ │ + featurecoordsys: { │ │ │ │ + id: 0, │ │ │ │ + string: "", │ │ │ │ + datumtransformid: 0, │ │ │ │ + datumtransformstring: "" │ │ │ │ + }, │ │ │ │ + filtercoordsys: { │ │ │ │ + id: 0, │ │ │ │ + string: "", │ │ │ │ + datumtransformid: 0, │ │ │ │ + datumtransformstring: "" │ │ │ │ + }, │ │ │ │ + imagesize: { │ │ │ │ + height: 0, │ │ │ │ + width: 0, │ │ │ │ + dpi: 96, │ │ │ │ + printheight: 0, │ │ │ │ + printwidth: 0, │ │ │ │ + scalesymbols: false │ │ │ │ + }, │ │ │ │ + layerlist: [], │ │ │ │ + /* no support for legends */ │ │ │ │ + output: { │ │ │ │ + baseurl: "", │ │ │ │ + legendbaseurl: "", │ │ │ │ + legendname: "", │ │ │ │ + legendpath: "", │ │ │ │ + legendurl: "", │ │ │ │ + name: "", │ │ │ │ + path: "", │ │ │ │ + type: "jpg", │ │ │ │ + url: "" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + get_feature: { │ │ │ │ + layer: "", │ │ │ │ + query: { │ │ │ │ + isspatial: false, │ │ │ │ + featurecoordsys: { │ │ │ │ + id: 0, │ │ │ │ + string: "", │ │ │ │ + datumtransformid: 0, │ │ │ │ + datumtransformstring: "" │ │ │ │ + }, │ │ │ │ + filtercoordsys: { │ │ │ │ + id: 0, │ │ │ │ + string: "", │ │ │ │ + datumtransformid: 0, │ │ │ │ + datumtransformstring: "" │ │ │ │ + }, │ │ │ │ + buffer: 0, │ │ │ │ + where: "", │ │ │ │ + spatialfilter: { │ │ │ │ + relation: "envelope_intersection", │ │ │ │ + envelope: null │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + environment: { │ │ │ │ + separators: { │ │ │ │ + cs: " ", │ │ │ │ + ts: ";" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + layer: [], │ │ │ │ + workspaces: [] │ │ │ │ + }; │ │ │ │ + │ │ │ │ + return OpenLayers.Util.extend(this, defaults); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.ArcXML.Request" │ │ │ │ +}); │ │ │ │ + │ │ │ │ +OpenLayers.Format.ArcXML.Response = OpenLayers.Class({ │ │ │ │ + initialize: function(params) { │ │ │ │ + var defaults = { │ │ │ │ + image: { │ │ │ │ + envelope: null, │ │ │ │ + output: '' │ │ │ │ + }, │ │ │ │ + │ │ │ │ + features: { │ │ │ │ + featurecount: 0, │ │ │ │ + envelope: null, │ │ │ │ + feature: [] │ │ │ │ + }, │ │ │ │ + │ │ │ │ + error: '' │ │ │ │ + }; │ │ │ │ + │ │ │ │ + return OpenLayers.Util.extend(this, defaults); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.ArcXML.Response" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/ArcIMS.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 │ │ │ │ + * @requires OpenLayers/Format/ArcXML.js │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.ArcIMS │ │ │ │ + * Instances of OpenLayers.Layer.ArcIMS are used to display data from ESRI ArcIMS │ │ │ │ + * Mapping Services. Create a new ArcIMS layer with the <OpenLayers.Layer.ArcIMS> │ │ │ │ + * constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.ArcIMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: DEFAULT_PARAMS │ │ │ │ + * {Object} Default query string parameters. │ │ │ │ + */ │ │ │ │ + DEFAULT_PARAMS: { │ │ │ │ + ClientVersion: "9.2", │ │ │ │ + ServiceName: '' │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: featureCoordSys │ │ │ │ + * {String} Code for feature coordinate system. Default is "4326". │ │ │ │ + */ │ │ │ │ + featureCoordSys: "4326", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: filterCoordSys │ │ │ │ + * {String} Code for filter coordinate system. Default is "4326". │ │ │ │ + */ │ │ │ │ + filterCoordSys: "4326", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: layers │ │ │ │ + * {Array} An array of objects with layer properties. │ │ │ │ + */ │ │ │ │ + layers: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: async │ │ │ │ + * {Boolean} Request images asynchronously. Default is true. │ │ │ │ + */ │ │ │ │ + async: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: name │ │ │ │ + * {String} Layer name. Default is "ArcIMS". │ │ │ │ + */ │ │ │ │ + name: "ArcIMS", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} The layer is a base layer. Default is true. │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: DEFAULT_OPTIONS │ │ │ │ + * {Object} Default layers properties. │ │ │ │ + */ │ │ │ │ + DEFAULT_OPTIONS: { │ │ │ │ + tileSize: new OpenLayers.Size(512, 512), │ │ │ │ + featureCoordSys: "4326", │ │ │ │ + filterCoordSys: "4326", │ │ │ │ + layers: null, │ │ │ │ + isBaseLayer: true, │ │ │ │ + async: true, │ │ │ │ + name: "ArcIMS" │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.ArcIMS │ │ │ │ + * Create a new ArcIMS layer object. │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * (code) │ │ │ │ + * var arcims = new OpenLayers.Layer.ArcIMS( │ │ │ │ + * "Global Sample", │ │ │ │ + * "http://sample.avencia.com/servlet/com.esri.esrimap.Esrimap", │ │ │ │ + * { │ │ │ │ + * service: "OpenLayers_Sample", │ │ │ │ + * layers: [ │ │ │ │ + * // layers to manipulate │ │ │ │ + * {id: "1", visible: true} │ │ │ │ + * ] │ │ │ │ + * } │ │ │ │ + * ); │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} A name for the layer │ │ │ │ + * url - {String} Base url for the ArcIMS server │ │ │ │ + * options - {Object} Optional object with properties to be set on the │ │ │ │ + * layer. │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, options) { │ │ │ │ + │ │ │ │ + this.tileSize = new OpenLayers.Size(512, 512); │ │ │ │ + │ │ │ │ + // parameters │ │ │ │ + this.params = OpenLayers.Util.applyDefaults({ │ │ │ │ + ServiceName: options.serviceName │ │ │ │ + }, │ │ │ │ + this.DEFAULT_PARAMS │ │ │ │ + ); │ │ │ │ + this.options = OpenLayers.Util.applyDefaults( │ │ │ │ + options, this.DEFAULT_OPTIONS │ │ │ │ + ); │ │ │ │ + │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply( │ │ │ │ + this, [name, url, this.params, options] │ │ │ │ + ); │ │ │ │ + │ │ │ │ + //layer is transparent │ │ │ │ + if (this.transparent) { │ │ │ │ + │ │ │ │ + // unless explicitly set in options, make layer an overlay │ │ │ │ + if (!this.isBaseLayer) { │ │ │ │ + this.isBaseLayer = false; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // jpegs can never be transparent, so intelligently switch the │ │ │ │ + // format, depending on the browser's capabilities │ │ │ │ + if (this.format == "image/jpeg") { │ │ │ │ + this.format = OpenLayers.Util.alphaHack() ? "image/gif" : "image/png"; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // create an empty layer list if no layers specified in the options │ │ │ │ + if (this.options.layers === null) { │ │ │ │ + this.options.layers = []; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getURL │ │ │ │ + * Return an image url this layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the │ │ │ │ + * request. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A string with the map image's url. │ │ │ │ + */ │ │ │ │ + getURL: function(bounds) { │ │ │ │ + var url = ""; │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + │ │ │ │ + // create an arcxml request to generate the image │ │ │ │ + var axlReq = new OpenLayers.Format.ArcXML( │ │ │ │ + OpenLayers.Util.extend(this.options, { │ │ │ │ + requesttype: "image", │ │ │ │ + envelope: bounds.toArray(), │ │ │ │ + tileSize: this.tileSize │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + │ │ │ │ + // create a synchronous ajax request to get an arcims image │ │ │ │ + var req = new OpenLayers.Request.POST({ │ │ │ │ + url: this.getFullRequestString(), │ │ │ │ + data: axlReq.write(), │ │ │ │ + async: false │ │ │ │ + }); │ │ │ │ + │ │ │ │ + // if the response exists │ │ │ │ + if (req != null) { │ │ │ │ + var doc = req.responseXML; │ │ │ │ + │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = req.responseText; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // create a new arcxml format to read the response │ │ │ │ + var axlResp = new OpenLayers.Format.ArcXML(); │ │ │ │ + var arcxml = axlResp.read(doc); │ │ │ │ + url = this.getUrlOrImage(arcxml.image.output); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return url; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getURLasync │ │ │ │ + * Get an image url this layer asynchronously, and execute a callback │ │ │ │ + * when the image url is generated. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the │ │ │ │ + * request. │ │ │ │ + * callback - {Function} Function to call when image url is retrieved. │ │ │ │ + * scope - {Object} The scope of the callback method. │ │ │ │ + */ │ │ │ │ + getURLasync: function(bounds, callback, scope) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + │ │ │ │ + // create an arcxml request to generate the image │ │ │ │ + var axlReq = new OpenLayers.Format.ArcXML( │ │ │ │ + OpenLayers.Util.extend(this.options, { │ │ │ │ + requesttype: "image", │ │ │ │ + envelope: bounds.toArray(), │ │ │ │ + tileSize: this.tileSize │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + │ │ │ │ + // create an asynchronous ajax request to get an arcims image │ │ │ │ + OpenLayers.Request.POST({ │ │ │ │ + url: this.getFullRequestString(), │ │ │ │ + async: true, │ │ │ │ + data: axlReq.write(), │ │ │ │ + callback: function(req) { │ │ │ │ + // process the response from ArcIMS, and call the callback function │ │ │ │ + // to set the image URL │ │ │ │ + var doc = req.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = req.responseText; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // create a new arcxml format to read the response │ │ │ │ + var axlResp = new OpenLayers.Format.ArcXML(); │ │ │ │ + var arcxml = axlResp.read(doc); │ │ │ │ + │ │ │ │ + callback.call(scope, this.getUrlOrImage(arcxml.image.output)); │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getUrlOrImage │ │ │ │ + * Extract a url or image from the ArcXML image output. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * output - {Object} The image.output property of the object returned from │ │ │ │ + * the ArcXML format read method. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A URL for an image (potentially with the data protocol). │ │ │ │ + */ │ │ │ │ + getUrlOrImage: function(output) { │ │ │ │ + var ret = ""; │ │ │ │ + if (output.url) { │ │ │ │ + // If the image response output url is a string, then the image │ │ │ │ + // data is not inline. │ │ │ │ + ret = output.url; │ │ │ │ + } else if (output.data) { │ │ │ │ + // The image data is inline and base64 encoded, create a data │ │ │ │ + // url for the image. This will only work for small images, │ │ │ │ + // due to browser url length limits. │ │ │ │ + ret = "data:image/" + output.type + │ │ │ │ + ";base64," + output.data; │ │ │ │ + } │ │ │ │ + return ret; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setLayerQuery │ │ │ │ + * Set the query definition on this layer. Query definitions are used to │ │ │ │ + * render parts of the spatial data in an image, and can be used to │ │ │ │ + * filter features or layers in the ArcIMS service. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * id - {String} The ArcIMS layer ID. │ │ │ │ + * querydef - {Object} The query definition to apply to this layer. │ │ │ │ + */ │ │ │ │ + setLayerQuery: function(id, querydef) { │ │ │ │ + // find the matching layer, if it exists │ │ │ │ + for (var lyr = 0; lyr < this.options.layers.length; lyr++) { │ │ │ │ + if (id == this.options.layers[lyr].id) { │ │ │ │ + // replace this layer definition │ │ │ │ + this.options.layers[lyr].query = querydef; │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // no layer found, create a new definition │ │ │ │ + this.options.layers.push({ │ │ │ │ + id: id, │ │ │ │ + visible: true, │ │ │ │ + query: querydef │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getFeatureInfo │ │ │ │ + * Get feature information from ArcIMS. Using the applied geometry, apply │ │ │ │ + * the options to the query (buffer, area/envelope intersection), and │ │ │ │ + * query the ArcIMS service. │ │ │ │ + * │ │ │ │ + * A note about accuracy: │ │ │ │ + * ArcIMS interprets the accuracy attribute in feature requests to be │ │ │ │ + * something like the 'modulus' operator on feature coordinates, │ │ │ │ + * applied to the database geometry of the feature. It doesn't round, │ │ │ │ + * so your feature coordinates may be up to (1 x accuracy) offset from │ │ │ │ + * the actual feature coordinates. If the accuracy of the layer is not │ │ │ │ + * specified, the accuracy will be computed to be approximately 1 │ │ │ │ + * feature coordinate per screen pixel. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.LonLat>} or {<OpenLayers.Geometry.Polygon>} The │ │ │ │ + * geometry to use when making the query. This should be a closed │ │ │ │ + * polygon for behavior approximating a free selection. │ │ │ │ + * layer - {Object} The ArcIMS layer definition. This is an anonymous object │ │ │ │ + * that looks like: │ │ │ │ + * (code) │ │ │ │ + * { │ │ │ │ + * id: "ArcXML layer ID", // the ArcXML layer ID │ │ │ │ + * query: { │ │ │ │ + * where: "STATE = 'PA'", // the where clause of the query │ │ │ │ + * accuracy: 100 // the accuracy of the returned feature │ │ │ │ + * } │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ + * options - {Object} Object with non-default properties to set on the layer. │ │ │ │ + * Supported properties are buffer, callback, scope, and any other │ │ │ │ + * properties applicable to the ArcXML format. Set the 'callback' and │ │ │ │ + * 'scope' for an object and function to recieve the parsed features │ │ │ │ + * from ArcIMS. │ │ │ │ + */ │ │ │ │ + getFeatureInfo: function(geometry, layer, options) { │ │ │ │ + // set the buffer to 1 unit (dd/m/ft?) by default │ │ │ │ + var buffer = options.buffer || 1; │ │ │ │ + // empty callback by default │ │ │ │ + var callback = options.callback || function() {}; │ │ │ │ + // default scope is window (global) │ │ │ │ + var scope = options.scope || window; │ │ │ │ + │ │ │ │ + // apply these option to the request options │ │ │ │ + var requestOptions = {}; │ │ │ │ + OpenLayers.Util.extend(requestOptions, this.options); │ │ │ │ + │ │ │ │ + // this is a feature request │ │ │ │ + requestOptions.requesttype = "feature"; │ │ │ │ + │ │ │ │ + if (geometry instanceof OpenLayers.LonLat) { │ │ │ │ + // create an envelope if the geometry is really a lon/lat │ │ │ │ + requestOptions.polygon = null; │ │ │ │ + requestOptions.envelope = [ │ │ │ │ + geometry.lon - buffer, │ │ │ │ + geometry.lat - buffer, │ │ │ │ + geometry.lon + buffer, │ │ │ │ + geometry.lat + buffer │ │ │ │ + ]; │ │ │ │ + } else if (geometry instanceof OpenLayers.Geometry.Polygon) { │ │ │ │ + // use the polygon assigned, and empty the envelope │ │ │ │ + requestOptions.envelope = null; │ │ │ │ + requestOptions.polygon = geometry; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // create an arcxml request to get feature requests │ │ │ │ + var arcxml = new OpenLayers.Format.ArcXML(requestOptions); │ │ │ │ + │ │ │ │ + // apply any get feature options to the arcxml request │ │ │ │ + OpenLayers.Util.extend(arcxml.request.get_feature, options); │ │ │ │ + │ │ │ │ + arcxml.request.get_feature.layer = layer.id; │ │ │ │ + if (typeof layer.query.accuracy == "number") { │ │ │ │ + // set the accuracy if it was specified │ │ │ │ + arcxml.request.get_feature.query.accuracy = layer.query.accuracy; │ │ │ │ + } else { │ │ │ │ + // guess that the accuracy is 1 per screen pixel │ │ │ │ + var mapCenter = this.map.getCenter(); │ │ │ │ + var viewPx = this.map.getViewPortPxFromLonLat(mapCenter); │ │ │ │ + viewPx.x++; │ │ │ │ + var mapOffCenter = this.map.getLonLatFromPixel(viewPx); │ │ │ │ + arcxml.request.get_feature.query.accuracy = mapOffCenter.lon - mapCenter.lon; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // set the get_feature query to be the same as the layer passed in │ │ │ │ + arcxml.request.get_feature.query.where = layer.query.where; │ │ │ │ + │ │ │ │ + // use area_intersection │ │ │ │ + arcxml.request.get_feature.query.spatialfilter.relation = "area_intersection"; │ │ │ │ + │ │ │ │ + // create a new asynchronous request to get the feature info │ │ │ │ + OpenLayers.Request.POST({ │ │ │ │ + url: this.getFullRequestString({ │ │ │ │ + 'CustomService': 'Query' │ │ │ │ + }), │ │ │ │ + data: arcxml.write(), │ │ │ │ + callback: function(request) { │ │ │ │ + // parse the arcxml response │ │ │ │ + var response = arcxml.parseResponse(request.responseText); │ │ │ │ + │ │ │ │ + if (!arcxml.iserror()) { │ │ │ │ + // if the arcxml is not an error, call the callback with the features parsed │ │ │ │ + callback.call(scope, response.features); │ │ │ │ + } else { │ │ │ │ + // if the arcxml is an error, return null features selected │ │ │ │ + callback.call(scope, null); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.ArcIMS>} An exact clone of this layer │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.ArcIMS(this.name, │ │ │ │ + this.url, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.ArcIMS" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/TMS.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.TMS │ │ │ │ + * Create a layer for accessing tiles from services that conform with the │ │ │ │ + * Tile Map Service Specification │ │ │ │ + * (http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification). │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * (code) │ │ │ │ + * var layer = new OpenLayers.Layer.TMS( │ │ │ │ + * "My Layer", // name for display in LayerSwitcher │ │ │ │ + * "http://tilecache.osgeo.org/wms-c/Basic.py/", // service endpoint │ │ │ │ + * {layername: "basic", type: "png"} // required properties │ │ │ │ + * ); │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.TMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: serviceVersion │ │ │ │ + * {String} Service version for tile requests. Default is "1.0.0". │ │ │ │ + */ │ │ │ │ + serviceVersion: "1.0.0", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: layername │ │ │ │ + * {String} The identifier for the <TileMap> as advertised by the service. │ │ │ │ + * For example, if the service advertises a <TileMap> with │ │ │ │ + * 'href="http://tms.osgeo.org/1.0.0/vmap0"', the <layername> property │ │ │ │ + * would be set to "vmap0". │ │ │ │ + */ │ │ │ │ + layername: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: type │ │ │ │ + * {String} The format extension corresponding to the requested tile image │ │ │ │ + * type. This is advertised in a <TileFormat> element as the │ │ │ │ + * "extension" attribute. For example, if the service advertises a │ │ │ │ + * <TileMap> with <TileFormat width="256" height="256" mime-type="image/jpeg" extension="jpg" />, │ │ │ │ + * the <type> property would be set to "jpg". │ │ │ │ + */ │ │ │ │ + type: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} Make this layer a base layer. Default is true. Set false to │ │ │ │ + * use the layer as an overlay. │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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 bottom-left │ │ │ │ + * corner of the map's <maxExtent>. Default is ``null``. │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * (code) │ │ │ │ + * var layer = new OpenLayers.Layer.TMS( │ │ │ │ + * "My Layer", │ │ │ │ + * "http://tilecache.osgeo.org/wms-c/Basic.py/", │ │ │ │ + * { │ │ │ │ + * layername: "basic", │ │ │ │ + * type: "png", │ │ │ │ + * // set if different than the bottom left of map.maxExtent │ │ │ │ + * tileOrigin: new OpenLayers.LonLat(-180, -90) │ │ │ │ + * } │ │ │ │ + * ); │ │ │ │ + * (end) │ │ │ │ + */ │ │ │ │ + tileOrigin: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.TMS │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} Title to be displayed in a <OpenLayers.Control.LayerSwitcher> │ │ │ │ + * url - {String} Service endpoint (without the version number). E.g. │ │ │ │ + * "http://tms.osgeo.org/". │ │ │ │ + * options - {Object} Additional properties to be set on the layer. The │ │ │ │ + * <layername> and <type> properties must be set here. │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, options) { │ │ │ │ + var newArguments = []; │ │ │ │ + newArguments.push(name, url, {}, options); │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * Create a complete copy of this layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {Object} Should only be provided by subclasses that call this │ │ │ │ + * method. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.TMS>} An exact clone of this <OpenLayers.Layer.TMS> │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.TMS(this.name, │ │ │ │ + this.url, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ + var y = Math.round((bounds.bottom - this.tileOrigin.lat) / (res * this.tileSize.h)); │ │ │ │ + var z = this.getServerZoom(); │ │ │ │ + var path = this.serviceVersion + "/" + this.layername + "/" + z + "/" + x + "/" + y + "." + this.type; │ │ │ │ + var url = this.url; │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(path, url); │ │ │ │ + } │ │ │ │ + return url + path; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: 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.map.maxExtent.left, │ │ │ │ + this.map.maxExtent.bottom); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.TMS" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/KaMapCache.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 │ │ │ │ + * @requires OpenLayers/Layer/KaMap.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.KaMapCache │ │ │ │ + * │ │ │ │ + * This class is designed to talk directly to a web-accessible ka-Map │ │ │ │ + * cache generated by the precache2.php script. │ │ │ │ + * │ │ │ │ + * To create a a new KaMapCache layer, you must indicate also the "i" parameter │ │ │ │ + * (that will be used to calculate the file extension), and another special │ │ │ │ + * parameter, object names "metaTileSize", with "h" (height) and "w" (width) │ │ │ │ + * properties. │ │ │ │ + * │ │ │ │ + * // Create a new kaMapCache layer. │ │ │ │ + * var kamap_base = new OpenLayers.Layer.KaMapCache( │ │ │ │ + * "Satellite", │ │ │ │ + * "http://www.example.org/web/acessible/cache", │ │ │ │ + * {g: "satellite", map: "world", i: 'png24', metaTileSize: {w: 5, h: 5} } │ │ │ │ + * ); │ │ │ │ + * │ │ │ │ + * // Create an kaMapCache overlay layer (using "isBaseLayer: false"). │ │ │ │ + * // Forces the output to be a "gif", using the "i" parameter. │ │ │ │ + * var kamap_overlay = new OpenLayers.Layer.KaMapCache( │ │ │ │ + * "Streets", │ │ │ │ + * "http://www.example.org/web/acessible/cache", │ │ │ │ + * {g: "streets", map: "world", i: "gif", metaTileSize: {w: 5, h: 5} }, │ │ │ │ + * {isBaseLayer: false} │ │ │ │ + * ); │ │ │ │ + * │ │ │ │ + * The cache URLs must look like: │ │ │ │ + * var/cache/World/50000/Group_Name/def/t-440320/l20480 │ │ │ │ + * │ │ │ │ + * This means that the cache generated via tile.php will *not* work with │ │ │ │ + * this class, and should instead use the KaMap layer. │ │ │ │ + * │ │ │ │ + * More information is available in Ticket #1518. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.KaMap> │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.KaMapCache = OpenLayers.Class(OpenLayers.Layer.KaMap, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: IMAGE_EXTENSIONS │ │ │ │ + * {Object} Simple hash map to convert format to extension. │ │ │ │ + */ │ │ │ │ + IMAGE_EXTENSIONS: { │ │ │ │ + 'jpeg': 'jpg', │ │ │ │ + 'gif': 'gif', │ │ │ │ + 'png': 'png', │ │ │ │ + 'png8': 'png', │ │ │ │ + 'png24': 'png', │ │ │ │ + 'dithered': 'png' │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: DEFAULT_FORMAT │ │ │ │ + * {Object} Simple hash map to convert format to extension. │ │ │ │ + */ │ │ │ │ + DEFAULT_FORMAT: 'jpeg', │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.KaMapCache │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} │ │ │ │ + * url - {String} │ │ │ │ + * params - {Object} Parameters to be sent to the HTTP server in the │ │ │ │ + * query string for the tile. The format can be set via the 'i' │ │ │ │ + * parameter (defaults to jpg) , and the map should be set via │ │ │ │ + * the 'map' parameter. It has been reported that ka-Map may behave │ │ │ │ + * inconsistently if your format parameter does not match the format │ │ │ │ + * parameter configured in your config.php. (See ticket #327 for more │ │ │ │ + * information.) │ │ │ │ + * options - {Object} Additional options for the layer. Any of the │ │ │ │ + * APIProperties listed on this layer, and any layer types it │ │ │ │ + * extends, can be overridden through the options parameter. │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + OpenLayers.Layer.KaMap.prototype.initialize.apply(this, arguments); │ │ │ │ + this.extension = this.IMAGE_EXTENSIONS[this.params.i.toLowerCase() || this.DEFAULT_FORMAT]; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ + var scale = Math.round((this.map.getScale() * 10000)) / 10000; │ │ │ │ + var pX = Math.round(bounds.left / mapRes); │ │ │ │ + var pY = -Math.round(bounds.top / mapRes); │ │ │ │ + │ │ │ │ + var metaX = Math.floor(pX / this.tileSize.w / this.params.metaTileSize.w) * this.tileSize.w * this.params.metaTileSize.w; │ │ │ │ + var metaY = Math.floor(pY / this.tileSize.h / this.params.metaTileSize.h) * this.tileSize.h * this.params.metaTileSize.h; │ │ │ │ + │ │ │ │ + var components = [ │ │ │ │ + "/", │ │ │ │ + this.params.map, │ │ │ │ + "/", │ │ │ │ + scale, │ │ │ │ + "/", │ │ │ │ + this.params.g.replace(/\s/g, '_'), │ │ │ │ + "/def/t", │ │ │ │ + metaY, │ │ │ │ + "/l", │ │ │ │ + metaX, │ │ │ │ + "/t", │ │ │ │ + pY, │ │ │ │ + "l", │ │ │ │ + pX, │ │ │ │ + ".", │ │ │ │ + this.extension │ │ │ │ + ]; │ │ │ │ + │ │ │ │ + var url = this.url; │ │ │ │ + │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(components.join(''), url); │ │ │ │ + } │ │ │ │ + return url + components.join(""); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.KaMapCache" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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: "© <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/Format/Text.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/Feature/Vector.js │ │ │ │ + * @requires OpenLayers/Geometry/Point.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.Text │ │ │ │ + * Read Text format. Create a new instance with the <OpenLayers.Format.Text> │ │ │ │ + * constructor. This reads text which is formatted like CSV text, using │ │ │ │ + * tabs as the seperator by default. It provides parsing of data originally │ │ │ │ + * used in the MapViewerService, described on the wiki. This Format is used │ │ │ │ + * by the <OpenLayers.Layer.Text> class. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.Text = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: defaultStyle │ │ │ │ + * defaultStyle allows one to control the default styling of the features. │ │ │ │ + * It should be a symbolizer hash. By default, this is set to match the │ │ │ │ + * Layer.Text behavior, which is to use the default OpenLayers Icon. │ │ │ │ + */ │ │ │ │ + defaultStyle: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: extractStyles │ │ │ │ + * set to true to extract styles from the TSV files, using information │ │ │ │ + * from the image or icon, iconSize and iconOffset fields. This will result │ │ │ │ + * in features with a symbolizer (style) property set, using the │ │ │ │ + * default symbolizer specified in <defaultStyle>. Set to false if you │ │ │ │ + * wish to use a styleMap or OpenLayers.Style options to style your │ │ │ │ + * layer instead. │ │ │ │ + */ │ │ │ │ + extractStyles: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.Text │ │ │ │ + * Create a new parser for TSV Text. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + │ │ │ │ + if (options.extractStyles !== false) { │ │ │ │ + options.defaultStyle = { │ │ │ │ + 'externalGraphic': OpenLayers.Util.getImageLocation("marker.png"), │ │ │ │ + 'graphicWidth': 21, │ │ │ │ + 'graphicHeight': 25, │ │ │ │ + 'graphicXOffset': -10.5, │ │ │ │ + 'graphicYOffset': -12.5 │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + │ │ │ │ + OpenLayers.Format.prototype.initialize.apply(this, [options]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Return a list of features from a Tab Seperated Values text string. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * text - {String} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ + */ │ │ │ │ + read: function(text) { │ │ │ │ + var lines = text.split('\n'); │ │ │ │ + var columns; │ │ │ │ + var features = []; │ │ │ │ + // length - 1 to allow for trailing new line │ │ │ │ + for (var lcv = 0; lcv < (lines.length - 1); lcv++) { │ │ │ │ + var currLine = lines[lcv].replace(/^\s*/, '').replace(/\s*$/, ''); │ │ │ │ + │ │ │ │ + if (currLine.charAt(0) != '#') { │ │ │ │ + /* not a comment */ │ │ │ │ + │ │ │ │ + if (!columns) { │ │ │ │ + //First line is columns │ │ │ │ + columns = currLine.split('\t'); │ │ │ │ + } else { │ │ │ │ + var vals = currLine.split('\t'); │ │ │ │ + var geometry = new OpenLayers.Geometry.Point(0, 0); │ │ │ │ + var attributes = {}; │ │ │ │ + var style = this.defaultStyle ? │ │ │ │ + OpenLayers.Util.applyDefaults({}, this.defaultStyle) : │ │ │ │ + null; │ │ │ │ + var icon, iconSize, iconOffset, overflow; │ │ │ │ + var set = false; │ │ │ │ + for (var valIndex = 0; valIndex < vals.length; valIndex++) { │ │ │ │ + if (vals[valIndex]) { │ │ │ │ + if (columns[valIndex] == 'point') { │ │ │ │ + var coords = vals[valIndex].split(','); │ │ │ │ + geometry.y = parseFloat(coords[0]); │ │ │ │ + geometry.x = parseFloat(coords[1]); │ │ │ │ + set = true; │ │ │ │ + } else if (columns[valIndex] == 'lat') { │ │ │ │ + geometry.y = parseFloat(vals[valIndex]); │ │ │ │ + set = true; │ │ │ │ + } else if (columns[valIndex] == 'lon') { │ │ │ │ + geometry.x = parseFloat(vals[valIndex]); │ │ │ │ + set = true; │ │ │ │ + } else if (columns[valIndex] == 'title') │ │ │ │ + attributes['title'] = vals[valIndex]; │ │ │ │ + else if (columns[valIndex] == 'image' || │ │ │ │ + columns[valIndex] == 'icon' && style) { │ │ │ │ + style['externalGraphic'] = vals[valIndex]; │ │ │ │ + } else if (columns[valIndex] == 'iconSize' && style) { │ │ │ │ + var size = vals[valIndex].split(','); │ │ │ │ + style['graphicWidth'] = parseFloat(size[0]); │ │ │ │ + style['graphicHeight'] = parseFloat(size[1]); │ │ │ │ + } else if (columns[valIndex] == 'iconOffset' && style) { │ │ │ │ + var offset = vals[valIndex].split(','); │ │ │ │ + style['graphicXOffset'] = parseFloat(offset[0]); │ │ │ │ + style['graphicYOffset'] = parseFloat(offset[1]); │ │ │ │ + } else if (columns[valIndex] == 'description') { │ │ │ │ + attributes['description'] = vals[valIndex]; │ │ │ │ + } else if (columns[valIndex] == 'overflow') { │ │ │ │ + attributes['overflow'] = vals[valIndex]; │ │ │ │ + } else { │ │ │ │ + // For StyleMap filtering, allow additional │ │ │ │ + // columns to be stored as attributes. │ │ │ │ + attributes[columns[valIndex]] = vals[valIndex]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (set) { │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + geometry.transform(this.externalProjection, │ │ │ │ + this.internalProjection); │ │ │ │ + } │ │ │ │ + var feature = new OpenLayers.Feature.Vector(geometry, attributes, style); │ │ │ │ + features.push(feature); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return features; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.Text" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/Text.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/Markers.js │ │ │ │ + * @requires OpenLayers/Format/Text.js │ │ │ │ + * @requires OpenLayers/Request/XMLHttpRequest.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.Text │ │ │ │ + * This layer creates markers given data in a text file. The <location> │ │ │ │ + * property of the layer (specified as a property of the options argument │ │ │ │ + * in the <OpenLayers.Layer.Text> constructor) points to a tab delimited │ │ │ │ + * file with data used to create markers. │ │ │ │ + * │ │ │ │ + * The first row of the data file should be a header line with the column names │ │ │ │ + * of the data. Each column should be delimited by a tab space. The │ │ │ │ + * possible columns are: │ │ │ │ + * - *point* lat,lon of the point where a marker is to be placed │ │ │ │ + * - *lat* Latitude of the point where a marker is to be placed │ │ │ │ + * - *lon* Longitude of the point where a marker is to be placed │ │ │ │ + * - *icon* or *image* URL of marker icon to use. │ │ │ │ + * - *iconSize* Size of Icon to use. │ │ │ │ + * - *iconOffset* Where the top-left corner of the icon is to be placed │ │ │ │ + * relative to the latitude and longitude of the point. │ │ │ │ + * - *title* The text of the 'title' is placed inside an 'h2' marker │ │ │ │ + * inside a popup, which opens when the marker is clicked. │ │ │ │ + * - *description* The text of the 'description' is placed below the h2 │ │ │ │ + * in the popup. this can be plain text or HTML. │ │ │ │ + * │ │ │ │ + * Example text file: │ │ │ │ + * (code) │ │ │ │ + * lat lon title description iconSize iconOffset icon │ │ │ │ + * 10 20 title description 21,25 -10,-25 http://www.openlayers.org/dev/img/marker.png │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Markers> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Text = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: location │ │ │ │ + * {String} URL of text file. Must be specified in the "options" argument │ │ │ │ + * of the constructor. Can not be changed once passed in. │ │ │ │ + */ │ │ │ │ + location: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: features │ │ │ │ + * {Array(<OpenLayers.Feature>)} │ │ │ │ + */ │ │ │ │ + features: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: formatOptions │ │ │ │ + * {Object} Hash of options which should be passed to the format when it is │ │ │ │ + * created. Must be passed in the constructor. │ │ │ │ + */ │ │ │ │ + formatOptions: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: selectedFeature │ │ │ │ + * {<OpenLayers.Feature>} │ │ │ │ + */ │ │ │ │ + selectedFeature: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.Text │ │ │ │ + * Create a text layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} │ │ │ │ + * options - {Object} Object with properties to be set on the layer. │ │ │ │ + * Must include <location> property. │ │ │ │ + */ │ │ │ │ + initialize: function(name, options) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.initialize.apply(this, arguments); │ │ │ │ + this.features = []; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + // Warning: Layer.Markers.destroy() must be called prior to calling │ │ │ │ + // clearFeatures() here, otherwise we leak memory. Indeed, if │ │ │ │ + // Layer.Markers.destroy() is called after clearFeatures(), it won't be │ │ │ │ + // able to remove the marker image elements from the layer's div since │ │ │ │ + // the markers will have been destroyed by clearFeatures(). │ │ │ │ + OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ + this.clearFeatures(); │ │ │ │ + this.features = null; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: loadText │ │ │ │ + * Start the load of the Text data. Don't do this when we first add the layer, │ │ │ │ + * since we may not be visible at any point, and it would therefore be a waste. │ │ │ │ + */ │ │ │ │ + loadText: function() { │ │ │ │ + if (!this.loaded) { │ │ │ │ + if (this.location != null) { │ │ │ │ + │ │ │ │ + var onFail = function(e) { │ │ │ │ + this.events.triggerEvent("loadend"); │ │ │ │ + }; │ │ │ │ + │ │ │ │ + this.events.triggerEvent("loadstart"); │ │ │ │ + OpenLayers.Request.GET({ │ │ │ │ + url: this.location, │ │ │ │ + success: this.parseData, │ │ │ │ + failure: onFail, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.loaded = true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveTo │ │ │ │ + * If layer is visible and Text has not been loaded, load Text. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {Object} │ │ │ │ + * zoomChanged - {Object} │ │ │ │ + * minor - {Object} │ │ │ │ + */ │ │ │ │ + moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ + if (this.visibility && !this.loaded) { │ │ │ │ + this.loadText(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseData │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * ajaxRequest - {<OpenLayers.Request.XMLHttpRequest>} │ │ │ │ + */ │ │ │ │ + parseData: function(ajaxRequest) { │ │ │ │ + var text = ajaxRequest.responseText; │ │ │ │ + │ │ │ │ + var options = {}; │ │ │ │ + │ │ │ │ + OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ + │ │ │ │ + if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ + options.externalProjection = this.projection; │ │ │ │ + options.internalProjection = this.map.getProjectionObject(); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var parser = new OpenLayers.Format.Text(options); │ │ │ │ + var features = parser.read(text); │ │ │ │ + for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ + var data = {}; │ │ │ │ + var feature = features[i]; │ │ │ │ + var location; │ │ │ │ + var iconSize, iconOffset; │ │ │ │ + │ │ │ │ + location = new OpenLayers.LonLat(feature.geometry.x, │ │ │ │ + feature.geometry.y); │ │ │ │ + │ │ │ │ + if (feature.style.graphicWidth && │ │ │ │ + feature.style.graphicHeight) { │ │ │ │ + iconSize = new OpenLayers.Size( │ │ │ │ + feature.style.graphicWidth, │ │ │ │ + feature.style.graphicHeight); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // FIXME: At the moment, we only use this if we have an │ │ │ │ + // externalGraphic, because icon has no setOffset API Method. │ │ │ │ + /** │ │ │ │ + * FIXME FIRST!! │ │ │ │ + * The Text format does all sorts of parseFloating │ │ │ │ + * The result of a parseFloat for a bogus string is NaN. That │ │ │ │ + * means the three possible values here are undefined, NaN, or a │ │ │ │ + * number. The previous check was an identity check for null. This │ │ │ │ + * means it was failing for all undefined or NaN. A slightly better │ │ │ │ + * check is for undefined. An even better check is to see if the │ │ │ │ + * value is a number (see #1441). │ │ │ │ + */ │ │ │ │ + if (feature.style.graphicXOffset !== undefined && │ │ │ │ + feature.style.graphicYOffset !== undefined) { │ │ │ │ + iconOffset = new OpenLayers.Pixel( │ │ │ │ + feature.style.graphicXOffset, │ │ │ │ + feature.style.graphicYOffset); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (feature.style.externalGraphic != null) { │ │ │ │ + data.icon = new OpenLayers.Icon(feature.style.externalGraphic, │ │ │ │ + iconSize, │ │ │ │ + iconOffset); │ │ │ │ + } else { │ │ │ │ + data.icon = OpenLayers.Marker.defaultIcon(); │ │ │ │ + │ │ │ │ + //allows for the case where the image url is not │ │ │ │ + // specified but the size is. use a default icon │ │ │ │ + // but change the size │ │ │ │ + if (iconSize != null) { │ │ │ │ + data.icon.setSize(iconSize); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + if ((feature.attributes.title != null) && │ │ │ │ + (feature.attributes.description != null)) { │ │ │ │ + data['popupContentHTML'] = │ │ │ │ + '<h2>' + feature.attributes.title + '</h2>' + │ │ │ │ + '<p>' + feature.attributes.description + '</p>'; │ │ │ │ + } │ │ │ │ + │ │ │ │ + data['overflow'] = feature.attributes.overflow || "auto"; │ │ │ │ + │ │ │ │ + var markerFeature = new OpenLayers.Feature(this, location, data); │ │ │ │ + this.features.push(markerFeature); │ │ │ │ + var marker = markerFeature.createMarker(); │ │ │ │ + if ((feature.attributes.title != null) && │ │ │ │ + (feature.attributes.description != null)) { │ │ │ │ + marker.events.register('click', markerFeature, this.markerClick); │ │ │ │ + } │ │ │ │ + this.addMarker(marker); │ │ │ │ + } │ │ │ │ + this.events.triggerEvent("loadend"); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: markerClick │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + * │ │ │ │ + * Context: │ │ │ │ + * - {<OpenLayers.Feature>} │ │ │ │ + */ │ │ │ │ + markerClick: function(evt) { │ │ │ │ + var sameMarkerClicked = (this == this.layer.selectedFeature); │ │ │ │ + this.layer.selectedFeature = (!sameMarkerClicked) ? this : null; │ │ │ │ + for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ + this.layer.map.removePopup(this.layer.map.popups[i]); │ │ │ │ + } │ │ │ │ + if (!sameMarkerClicked) { │ │ │ │ + this.layer.map.addPopup(this.createPopup()); │ │ │ │ + } │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clearFeatures │ │ │ │ + */ │ │ │ │ + clearFeatures: function() { │ │ │ │ + if (this.features != null) { │ │ │ │ + while (this.features.length > 0) { │ │ │ │ + var feature = this.features[0]; │ │ │ │ + OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ + feature.destroy(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Text" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/MapGuide.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/Request/XMLHttpRequest.js │ │ │ │ + * @requires OpenLayers/Layer/Grid.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.MapGuide │ │ │ │ + * Instances of OpenLayers.Layer.MapGuide are used to display │ │ │ │ + * data from a MapGuide OS instance. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} Treat this layer as a base layer. Default is true. │ │ │ │ + **/ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: useHttpTile │ │ │ │ + * {Boolean} use a tile cache exposed directly via a webserver rather than the │ │ │ │ + * via mapguide server. This does require extra configuration on the Mapguide Server, │ │ │ │ + * and will only work when singleTile is false. The url for the layer must be set to the │ │ │ │ + * webserver path rather than the Mapguide mapagent. │ │ │ │ + * See http://trac.osgeo.org/mapguide/wiki/CodeSamples/Tiles/ServingTilesViaHttp │ │ │ │ + **/ │ │ │ │ + useHttpTile: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: singleTile │ │ │ │ + * {Boolean} use tile server or request single tile image. │ │ │ │ + **/ │ │ │ │ + singleTile: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: useOverlay │ │ │ │ + * {Boolean} flag to indicate if the layer should be retrieved using │ │ │ │ + * GETMAPIMAGE (default) or using GETDYNAMICOVERLAY requests. │ │ │ │ + **/ │ │ │ │ + useOverlay: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: useAsyncOverlay │ │ │ │ + * {Boolean} indicates if the MapGuide site supports the asynchronous │ │ │ │ + * GETDYNAMICOVERLAY requests which is available in MapGuide Enterprise 2010 │ │ │ │ + * and MapGuide Open Source v2.0.3 or higher. The newer versions of MG │ │ │ │ + * is called asynchronously, allows selections to be drawn separately from │ │ │ │ + * the map and offers styling options. │ │ │ │ + * │ │ │ │ + * With older versions of MapGuide, set useAsyncOverlay=false. Note that in │ │ │ │ + * this case a synchronous AJAX call is issued and the mapname and session │ │ │ │ + * parameters must be used to initialize the layer, not the mapdefinition │ │ │ │ + * parameter. Also note that this will issue a synchronous AJAX request │ │ │ │ + * before the image request can be issued so the users browser may lock │ │ │ │ + * up if the MG Web tier does not respond in a timely fashion. │ │ │ │ + **/ │ │ │ │ + useAsyncOverlay: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: TILE_PARAMS │ │ │ │ + * {Object} Hashtable of default parameter key/value pairs for tiled layer │ │ │ │ + */ │ │ │ │ + TILE_PARAMS: { │ │ │ │ + operation: 'GETTILEIMAGE', │ │ │ │ + version: '1.2.0' │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: SINGLE_TILE_PARAMS │ │ │ │ + * {Object} Hashtable of default parameter key/value pairs for untiled layer │ │ │ │ + */ │ │ │ │ + SINGLE_TILE_PARAMS: { │ │ │ │ + operation: 'GETMAPIMAGE', │ │ │ │ + format: 'PNG', │ │ │ │ + locale: 'en', │ │ │ │ + clip: '1', │ │ │ │ + version: '1.0.0' │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: OVERLAY_PARAMS │ │ │ │ + * {Object} Hashtable of default parameter key/value pairs for untiled layer │ │ │ │ + */ │ │ │ │ + OVERLAY_PARAMS: { │ │ │ │ + operation: 'GETDYNAMICMAPOVERLAYIMAGE', │ │ │ │ + format: 'PNG', │ │ │ │ + locale: 'en', │ │ │ │ + clip: '1', │ │ │ │ + version: '2.0.0' │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: FOLDER_PARAMS │ │ │ │ + * {Object} Hashtable of parameter key/value pairs which describe │ │ │ │ + * the folder structure for tiles as configured in the mapguide │ │ │ │ + * serverconfig.ini section [TileServiceProperties] │ │ │ │ + */ │ │ │ │ + FOLDER_PARAMS: { │ │ │ │ + tileColumnsPerFolder: 30, │ │ │ │ + tileRowsPerFolder: 30, │ │ │ │ + format: 'png', │ │ │ │ + querystring: null │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: defaultSize │ │ │ │ + * {<OpenLayers.Size>} Tile size as produced by MapGuide server │ │ │ │ + **/ │ │ │ │ + defaultSize: new OpenLayers.Size(300, 300), │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: tileOriginCorner │ │ │ │ + * {String} MapGuide tile server uses top-left as tile origin │ │ │ │ + **/ │ │ │ │ + tileOriginCorner: "tl", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.MapGuide │ │ │ │ + * Create a new Mapguide layer, either tiled or untiled. │ │ │ │ + * │ │ │ │ + * For tiled layers, the 'groupName' and 'mapDefinition' values │ │ │ │ + * must be specified as parameters in the constructor. │ │ │ │ + * │ │ │ │ + * For untiled base layers, specify either combination of 'mapName' and │ │ │ │ + * 'session', or 'mapDefinition' and 'locale'. │ │ │ │ + * │ │ │ │ + * For older versions of MapGuide and overlay layers, set useAsyncOverlay │ │ │ │ + * to false and in this case mapName and session are required parameters │ │ │ │ + * for the constructor. │ │ │ │ + * │ │ │ │ + * NOTE: MapGuide OS uses a DPI value and degrees to meters conversion │ │ │ │ + * factor that are different than the defaults used in OpenLayers, │ │ │ │ + * so these must be adjusted accordingly in your application. │ │ │ │ + * See the MapGuide example for how to set these values for MGOS. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} Name of the layer displayed in the interface │ │ │ │ + * url - {String} Location of the MapGuide mapagent executable │ │ │ │ + * (e.g. http://localhost:8008/mapguide/mapagent/mapagent.fcgi) │ │ │ │ + * params - {Object} hashtable of additional parameters to use. Some │ │ │ │ + * parameters may require additional code on the server. The ones that │ │ │ │ + * you may want to use are: │ │ │ │ + * - mapDefinition - {String} The MapGuide resource definition │ │ │ │ + * (e.g. Library://Samples/Gmap/Maps/gmapTiled.MapDefinition) │ │ │ │ + * - locale - Locale setting │ │ │ │ + * (for untiled overlays layers only) │ │ │ │ + * - mapName - {String} Name of the map as stored in the MapGuide session. │ │ │ │ + * (for untiled layers with a session parameter only) │ │ │ │ + * - session - { String} MapGuide session ID │ │ │ │ + * (for untiled overlays layers only) │ │ │ │ + * - basemaplayergroupname - {String} GroupName for tiled MapGuide layers only │ │ │ │ + * - format - Image format to be returned (for untiled overlay layers only) │ │ │ │ + * - showLayers - {String} A comma separated list of GUID's for the │ │ │ │ + * layers to display eg: 'cvc-xcv34,453-345-345sdf'. │ │ │ │ + * - hideLayers - {String} A comma separated list of GUID's for the │ │ │ │ + * layers to hide eg: 'cvc-xcv34,453-345-345sdf'. │ │ │ │ + * - showGroups - {String} A comma separated list of GUID's for the │ │ │ │ + * groups to display eg: 'cvc-xcv34,453-345-345sdf'. │ │ │ │ + * - hideGroups - {String} A comma separated list of GUID's for the │ │ │ │ + * groups to hide eg: 'cvc-xcv34,453-345-345sdf' │ │ │ │ + * - selectionXml - {String} A selection xml string Some server plumbing │ │ │ │ + * is required to read such a value. │ │ │ │ + * options - {Object} Hashtable of extra options to tag onto the layer; │ │ │ │ + * will vary depending if tiled or untiled maps are being requested │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ + │ │ │ │ + // unless explicitly set in options, if the layer is transparent, │ │ │ │ + // it will be an overlay │ │ │ │ + if (options == null || options.isBaseLayer == null) { │ │ │ │ + this.isBaseLayer = ((this.transparent != "true") && │ │ │ │ + (this.transparent != true)); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (options && options.useOverlay != null) { │ │ │ │ + this.useOverlay = options.useOverlay; │ │ │ │ + } │ │ │ │ + │ │ │ │ + //initialize for untiled layers │ │ │ │ + if (this.singleTile) { │ │ │ │ + if (this.useOverlay) { │ │ │ │ + OpenLayers.Util.applyDefaults( │ │ │ │ + this.params, │ │ │ │ + this.OVERLAY_PARAMS │ │ │ │ + ); │ │ │ │ + if (!this.useAsyncOverlay) { │ │ │ │ + this.params.version = "1.0.0"; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Util.applyDefaults( │ │ │ │ + this.params, │ │ │ │ + this.SINGLE_TILE_PARAMS │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + //initialize for tiled layers │ │ │ │ + if (this.useHttpTile) { │ │ │ │ + OpenLayers.Util.applyDefaults( │ │ │ │ + this.params, │ │ │ │ + this.FOLDER_PARAMS │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + OpenLayers.Util.applyDefaults( │ │ │ │ + this.params, │ │ │ │ + this.TILE_PARAMS │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + this.setTileSize(this.defaultSize); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.MapGuide>} An exact clone of this layer │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.MapGuide(this.name, │ │ │ │ + this.url, │ │ │ │ + this.params, │ │ │ │ + this.getOptions()); │ │ │ │ + } │ │ │ │ + //get all additions from superclasses │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + │ │ │ │ + return obj; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getURL │ │ │ │ + * Return a 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) { │ │ │ │ + var url; │ │ │ │ + var center = bounds.getCenterLonLat(); │ │ │ │ + var mapSize = this.map.getSize(); │ │ │ │ + │ │ │ │ + if (this.singleTile) { │ │ │ │ + //set up the call for GETMAPIMAGE or GETDYNAMICMAPOVERLAY with │ │ │ │ + //dynamic map parameters │ │ │ │ + var params = { │ │ │ │ + setdisplaydpi: OpenLayers.DOTS_PER_INCH, │ │ │ │ + setdisplayheight: mapSize.h * this.ratio, │ │ │ │ + setdisplaywidth: mapSize.w * this.ratio, │ │ │ │ + setviewcenterx: center.lon, │ │ │ │ + setviewcentery: center.lat, │ │ │ │ + setviewscale: this.map.getScale() │ │ │ │ + }; │ │ │ │ + │ │ │ │ + if (this.useOverlay && !this.useAsyncOverlay) { │ │ │ │ + //first we need to call GETVISIBLEMAPEXTENT to set the extent │ │ │ │ + var getVisParams = {}; │ │ │ │ + getVisParams = OpenLayers.Util.extend(getVisParams, params); │ │ │ │ + getVisParams.operation = "GETVISIBLEMAPEXTENT"; │ │ │ │ + getVisParams.version = "1.0.0"; │ │ │ │ + getVisParams.session = this.params.session; │ │ │ │ + getVisParams.mapName = this.params.mapName; │ │ │ │ + getVisParams.format = 'text/xml'; │ │ │ │ + url = this.getFullRequestString(getVisParams); │ │ │ │ + │ │ │ │ + OpenLayers.Request.GET({ │ │ │ │ + url: url, │ │ │ │ + async: false │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + //construct the full URL │ │ │ │ + url = this.getFullRequestString(params); │ │ │ │ + } else { │ │ │ │ + │ │ │ │ + //tiled version │ │ │ │ + var currentRes = this.map.getResolution(); │ │ │ │ + var colidx = Math.floor((bounds.left - this.maxExtent.left) / currentRes); │ │ │ │ + colidx = Math.round(colidx / this.tileSize.w); │ │ │ │ + var rowidx = Math.floor((this.maxExtent.top - bounds.top) / currentRes); │ │ │ │ + rowidx = Math.round(rowidx / this.tileSize.h); │ │ │ │ + │ │ │ │ + if (this.useHttpTile) { │ │ │ │ + url = this.getImageFilePath({ │ │ │ │ + tilecol: colidx, │ │ │ │ + tilerow: rowidx, │ │ │ │ + scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ + }); │ │ │ │ + │ │ │ │ + } else { │ │ │ │ + url = this.getFullRequestString({ │ │ │ │ + tilecol: colidx, │ │ │ │ + tilerow: rowidx, │ │ │ │ + scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return url; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getFullRequestString │ │ │ │ + * getFullRequestString on MapGuide layers is special, because we │ │ │ │ + * do a regular expression replace on ',' in parameters to '+'. │ │ │ │ + * This is why it is subclassed here. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * altUrl - {String} Alternative base URL to use. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A string with the layer's url appropriately encoded for MapGuide │ │ │ │ + */ │ │ │ │ + getFullRequestString: function(newParams, altUrl) { │ │ │ │ + // use layer's url unless altUrl passed in │ │ │ │ + var url = (altUrl == null) ? this.url : altUrl; │ │ │ │ + │ │ │ │ + // if url is not a string, it should be an array of strings, │ │ │ │ + // in which case we will randomly select one of them in order │ │ │ │ + // to evenly distribute requests to different urls. │ │ │ │ + if (typeof url == "object") { │ │ │ │ + url = url[Math.floor(Math.random() * url.length)]; │ │ │ │ + } │ │ │ │ + // requestString always starts with url │ │ │ │ + var requestString = 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); │ │ │ │ + // 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]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ + │ │ │ │ + /* MapGuide needs '+' seperating things like bounds/height/width. │ │ │ │ + Since typically this is URL encoded, we use a slight hack: we │ │ │ │ + depend on the list-like functionality of getParameterString to │ │ │ │ + leave ',' only in the case of list items (since otherwise it is │ │ │ │ + encoded) then do a regular expression replace on the , characters │ │ │ │ + to '+' */ │ │ │ │ + paramsString = paramsString.replace(/,/g, "+"); │ │ │ │ + │ │ │ │ + if (paramsString != "") { │ │ │ │ + var lastServerChar = url.charAt(url.length - 1); │ │ │ │ + if ((lastServerChar == "&") || (lastServerChar == "?")) { │ │ │ │ + requestString += paramsString; │ │ │ │ + } else { │ │ │ │ + if (url.indexOf('?') == -1) { │ │ │ │ + //serverPath has no ? -- add one │ │ │ │ + requestString += '?' + paramsString; │ │ │ │ + } else { │ │ │ │ + //serverPath contains ?, so must already have paramsString at the end │ │ │ │ + requestString += '&' + paramsString; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return requestString; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getImageFilePath │ │ │ │ + * special handler to request mapguide tiles from an http exposed tilecache │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * altUrl - {String} Alternative base URL to use. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A string with the url for the tile image │ │ │ │ + */ │ │ │ │ + getImageFilePath: function(newParams, altUrl) { │ │ │ │ + // use layer's url unless altUrl passed in │ │ │ │ + var url = (altUrl == null) ? this.url : altUrl; │ │ │ │ + │ │ │ │ + // if url is not a string, it should be an array of strings, │ │ │ │ + // in which case we will randomly select one of them in order │ │ │ │ + // to evenly distribute requests to different urls. │ │ │ │ + if (typeof url == "object") { │ │ │ │ + url = url[Math.floor(Math.random() * url.length)]; │ │ │ │ + } │ │ │ │ + // requestString always starts with url │ │ │ │ + var requestString = url; │ │ │ │ + │ │ │ │ + var tileRowGroup = ""; │ │ │ │ + var tileColGroup = ""; │ │ │ │ + │ │ │ │ + if (newParams.tilerow < 0) { │ │ │ │ + tileRowGroup = '-'; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (newParams.tilerow == 0) { │ │ │ │ + tileRowGroup += '0'; │ │ │ │ + } else { │ │ │ │ + tileRowGroup += Math.floor(Math.abs(newParams.tilerow / this.params.tileRowsPerFolder)) * this.params.tileRowsPerFolder; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (newParams.tilecol < 0) { │ │ │ │ + tileColGroup = '-'; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (newParams.tilecol == 0) { │ │ │ │ + tileColGroup += '0'; │ │ │ │ + } else { │ │ │ │ + tileColGroup += Math.floor(Math.abs(newParams.tilecol / this.params.tileColumnsPerFolder)) * this.params.tileColumnsPerFolder; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var tilePath = '/S' + Math.floor(newParams.scaleindex) + │ │ │ │ + '/' + this.params.basemaplayergroupname + │ │ │ │ + '/R' + tileRowGroup + │ │ │ │ + '/C' + tileColGroup + │ │ │ │ + '/' + (newParams.tilerow % this.params.tileRowsPerFolder) + │ │ │ │ + '_' + (newParams.tilecol % this.params.tileColumnsPerFolder) + │ │ │ │ + '.' + this.params.format; │ │ │ │ + │ │ │ │ + if (this.params.querystring) { │ │ │ │ + tilePath += "?" + this.params.querystring; │ │ │ │ + } │ │ │ │ + │ │ │ │ + requestString += tilePath; │ │ │ │ + return requestString; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.MapGuide" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/Zoomify.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. */ │ │ │ │ + │ │ │ │ +/* │ │ │ │ + * Development supported by a R&D grant DC08P02OUK006 - Old Maps Online │ │ │ │ + * (www.oldmapsonline.org) from Ministry of Culture of the Czech Republic. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Layer/Grid.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.Zoomify │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Zoomify = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: size │ │ │ │ + * {<OpenLayers.Size>} The Zoomify image size in pixels. │ │ │ │ + */ │ │ │ │ + size: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: standardTileSize │ │ │ │ + * {Integer} The size of a standard (non-border) square tile in pixels. │ │ │ │ + */ │ │ │ │ + standardTileSize: 256, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: tileOriginCorner │ │ │ │ + * {String} This layer uses top-left as tile origin │ │ │ │ + **/ │ │ │ │ + tileOriginCorner: "tl", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: numberOfTiers │ │ │ │ + * {Integer} Depth of the Zoomify pyramid, number of tiers (zoom levels) │ │ │ │ + * - filled during Zoomify pyramid initialization. │ │ │ │ + */ │ │ │ │ + numberOfTiers: 0, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: tileCountUpToTier │ │ │ │ + * {Array(Integer)} Number of tiles up to the given tier of pyramid. │ │ │ │ + * - filled during Zoomify pyramid initialization. │ │ │ │ + */ │ │ │ │ + tileCountUpToTier: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: tierSizeInTiles │ │ │ │ + * {Array(<OpenLayers.Size>)} Size (in tiles) for each tier of pyramid. │ │ │ │ + * - filled during Zoomify pyramid initialization. │ │ │ │ + */ │ │ │ │ + tierSizeInTiles: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: tierImageSize │ │ │ │ + * {Array(<OpenLayers.Size>)} Image size in pixels for each pyramid tier. │ │ │ │ + * - filled during Zoomify pyramid initialization. │ │ │ │ + */ │ │ │ │ + tierImageSize: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.Zoomify │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} A name for the layer. │ │ │ │ + * url - {String} - Relative or absolute path to the image or more │ │ │ │ + * precisly to the TileGroup[X] directories root. │ │ │ │ + * Flash plugin use the variable name "zoomifyImagePath" for this. │ │ │ │ + * size - {<OpenLayers.Size>} The size (in pixels) of the image. │ │ │ │ + * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, size, options) { │ │ │ │ + │ │ │ │ + // initilize the Zoomify pyramid for given size │ │ │ │ + this.initializeZoomify(size); │ │ │ │ + │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, [ │ │ │ │ + name, url, size, {}, │ │ │ │ + options │ │ │ │ + ]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: initializeZoomify │ │ │ │ + * It generates constants for all tiers of the Zoomify pyramid │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * size - {<OpenLayers.Size>} The size of the image in pixels │ │ │ │ + * │ │ │ │ + */ │ │ │ │ + initializeZoomify: function(size) { │ │ │ │ + │ │ │ │ + var imageSize = size.clone(); │ │ │ │ + this.size = size.clone(); │ │ │ │ + var tiles = new OpenLayers.Size( │ │ │ │ + Math.ceil(imageSize.w / this.standardTileSize), │ │ │ │ + Math.ceil(imageSize.h / this.standardTileSize) │ │ │ │ + ); │ │ │ │ + │ │ │ │ + this.tierSizeInTiles = [tiles]; │ │ │ │ + this.tierImageSize = [imageSize]; │ │ │ │ + │ │ │ │ + while (imageSize.w > this.standardTileSize || │ │ │ │ + imageSize.h > this.standardTileSize) { │ │ │ │ + │ │ │ │ + imageSize = new OpenLayers.Size( │ │ │ │ + Math.floor(imageSize.w / 2), │ │ │ │ + Math.floor(imageSize.h / 2) │ │ │ │ + ); │ │ │ │ + tiles = new OpenLayers.Size( │ │ │ │ + Math.ceil(imageSize.w / this.standardTileSize), │ │ │ │ + Math.ceil(imageSize.h / this.standardTileSize) │ │ │ │ + ); │ │ │ │ + this.tierSizeInTiles.push(tiles); │ │ │ │ + this.tierImageSize.push(imageSize); │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.tierSizeInTiles.reverse(); │ │ │ │ + this.tierImageSize.reverse(); │ │ │ │ + │ │ │ │ + this.numberOfTiers = this.tierSizeInTiles.length; │ │ │ │ + var resolutions = [1]; │ │ │ │ + this.tileCountUpToTier = [0]; │ │ │ │ + for (var i = 1; i < this.numberOfTiers; i++) { │ │ │ │ + resolutions.unshift(Math.pow(2, i)); │ │ │ │ + this.tileCountUpToTier.push( │ │ │ │ + this.tierSizeInTiles[i - 1].w * this.tierSizeInTiles[i - 1].h + │ │ │ │ + this.tileCountUpToTier[i - 1] │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (!this.serverResolutions) { │ │ │ │ + this.serverResolutions = resolutions; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod:destroy │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + // for now, nothing special to do here. │ │ │ │ + OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments); │ │ │ │ + │ │ │ │ + // Remove from memory the Zoomify pyramid - is that enough? │ │ │ │ + this.tileCountUpToTier.length = 0; │ │ │ │ + this.tierSizeInTiles.length = 0; │ │ │ │ + this.tierImageSize.length = 0; │ │ │ │ + │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.Zoomify>} An exact clone of this <OpenLayers.Layer.Zoomify> │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.Zoomify(this.name, │ │ │ │ + this.url, │ │ │ │ + this.size, │ │ │ │ + this.options); │ │ │ │ + } │ │ │ │ + │ │ │ │ + //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; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ + var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ + var z = this.getZoomForResolution(res); │ │ │ │ + │ │ │ │ + var tileIndex = x + y * this.tierSizeInTiles[z].w + this.tileCountUpToTier[z]; │ │ │ │ + var path = "TileGroup" + Math.floor((tileIndex) / 256) + │ │ │ │ + "/" + z + "-" + x + "-" + y + ".jpg"; │ │ │ │ + var url = this.url; │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(path, url); │ │ │ │ + } │ │ │ │ + return url + path; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getImageSize │ │ │ │ + * getImageSize returns size for a particular tile. If bounds are given as │ │ │ │ + * first argument, size is calculated (bottom-right tiles are non square). │ │ │ │ + * │ │ │ │ + */ │ │ │ │ + getImageSize: function() { │ │ │ │ + if (arguments.length > 0) { │ │ │ │ + var bounds = this.adjustBounds(arguments[0]); │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ + var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ + var z = this.getZoomForResolution(res); │ │ │ │ + var w = this.standardTileSize; │ │ │ │ + var h = this.standardTileSize; │ │ │ │ + if (x == this.tierSizeInTiles[z].w - 1) { │ │ │ │ + var w = this.tierImageSize[z].w % this.standardTileSize; │ │ │ │ + } │ │ │ │ + if (y == this.tierSizeInTiles[z].h - 1) { │ │ │ │ + var h = this.tierImageSize[z].h % this.standardTileSize; │ │ │ │ + } │ │ │ │ + return (new OpenLayers.Size(w, h)); │ │ │ │ + } else { │ │ │ │ + return this.tileSize; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ + this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left, │ │ │ │ + this.map.maxExtent.top); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Zoomify" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/TileCache.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.TileCache │ │ │ │ + * A read only TileCache layer. Used to requests tiles cached by TileCache in │ │ │ │ + * a web accessible cache. This means that you have to pre-populate your │ │ │ │ + * cache before this layer can be used. It is meant only to read tiles │ │ │ │ + * created by TileCache, and not to make calls to TileCache for tile │ │ │ │ + * creation. Create a new instance with the │ │ │ │ + * <OpenLayers.Layer.TileCache> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.TileCache = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} Treat this layer as a base layer. Default is true. │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: format │ │ │ │ + * {String} Mime type of the images returned. Default is image/png. │ │ │ │ + */ │ │ │ │ + format: 'image/png', │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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. (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.TileCache │ │ │ │ + * Create a new read only TileCache layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} Name of the layer displayed in the interface │ │ │ │ + * url - {String} Location of the web accessible cache (not the location of │ │ │ │ + * your tilecache script!) │ │ │ │ + * layername - {String} Layer name as defined in the TileCache │ │ │ │ + * configuration │ │ │ │ + * options - {Object} Optional object with properties to be set on the │ │ │ │ + * layer. Note that you should speficy your resolutions to match │ │ │ │ + * your TileCache configuration. This can be done by setting │ │ │ │ + * the resolutions array directly (here or on the map), by setting │ │ │ │ + * maxResolution and numZoomLevels, or by using scale based properties. │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, layername, options) { │ │ │ │ + this.layername = layername; │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, │ │ │ │ + [name, url, {}, options]); │ │ │ │ + this.extension = this.format.split('/')[1].toLowerCase(); │ │ │ │ + this.extension = (this.extension == 'jpg') ? 'jpeg' : this.extension; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * obj - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.TileCache>} An exact clone of this │ │ │ │ + * <OpenLayers.Layer.TileCache> │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.TileCache(this.name, │ │ │ │ + this.url, │ │ │ │ + this.layername, │ │ │ │ + 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; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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 res = this.getServerResolution(); │ │ │ │ + var bbox = this.maxExtent; │ │ │ │ + var size = this.tileSize; │ │ │ │ + var tileX = Math.round((bounds.left - bbox.left) / (res * size.w)); │ │ │ │ + var tileY = Math.round((bounds.bottom - bbox.bottom) / (res * size.h)); │ │ │ │ + var tileZ = this.serverResolutions != null ? │ │ │ │ + OpenLayers.Util.indexOf(this.serverResolutions, res) : │ │ │ │ + this.map.getZoom(); │ │ │ │ + │ │ │ │ + var components = [ │ │ │ │ + this.layername, │ │ │ │ + OpenLayers.Number.zeroPad(tileZ, 2), │ │ │ │ + OpenLayers.Number.zeroPad(parseInt(tileX / 1000000), 3), │ │ │ │ + OpenLayers.Number.zeroPad((parseInt(tileX / 1000) % 1000), 3), │ │ │ │ + OpenLayers.Number.zeroPad((parseInt(tileX) % 1000), 3), │ │ │ │ + OpenLayers.Number.zeroPad(parseInt(tileY / 1000000), 3), │ │ │ │ + OpenLayers.Number.zeroPad((parseInt(tileY / 1000) % 1000), 3), │ │ │ │ + OpenLayers.Number.zeroPad((parseInt(tileY) % 1000), 3) + '.' + this.extension │ │ │ │ + ]; │ │ │ │ + var path = components.join('/'); │ │ │ │ + var url = this.url; │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(path, url); │ │ │ │ + } │ │ │ │ + url = (url.charAt(url.length - 1) == '/') ? url : url + '/'; │ │ │ │ + return url + path; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.TileCache" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/WMTS.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.WMTS │ │ │ │ + * Instances of the WMTS class allow viewing of tiles from a service that │ │ │ │ + * implements the OGC WMTS specification version 1.0.0. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.WMTS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} The layer will be considered a base layer. Default is true. │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} WMTS version. Default is "1.0.0". │ │ │ │ + */ │ │ │ │ + version: "1.0.0", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: requestEncoding │ │ │ │ + * {String} Request encoding. Can be "REST" or "KVP". Default is "KVP". │ │ │ │ + */ │ │ │ │ + requestEncoding: "KVP", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: url │ │ │ │ + * {String|Array(String)} The base URL or request URL template for the WMTS │ │ │ │ + * service. Must be provided. Array is only supported for base URLs, not │ │ │ │ + * for request URL templates. URL templates are only supported for │ │ │ │ + * REST <requestEncoding>. │ │ │ │ + */ │ │ │ │ + url: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: layer │ │ │ │ + * {String} The layer identifier advertised by the WMTS service. Must be │ │ │ │ + * provided. │ │ │ │ + */ │ │ │ │ + layer: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: matrixSet │ │ │ │ + * {String} One of the advertised matrix set identifiers. Must be provided. │ │ │ │ + */ │ │ │ │ + matrixSet: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: style │ │ │ │ + * {String} One of the advertised layer styles. Must be provided. │ │ │ │ + */ │ │ │ │ + style: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: format │ │ │ │ + * {String} The image MIME type. Default is "image/jpeg". │ │ │ │ + */ │ │ │ │ + format: "image/jpeg", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: tileOrigin │ │ │ │ + * {<OpenLayers.LonLat>} The top-left corner of the tile matrix in map │ │ │ │ + * units. If the tile origin for each matrix in a set is different, │ │ │ │ + * the <matrixIds> should include a topLeftCorner property. If │ │ │ │ + * not provided, the tile origin will default to the top left corner │ │ │ │ + * of the layer <maxExtent>. │ │ │ │ + */ │ │ │ │ + tileOrigin: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: tileFullExtent │ │ │ │ + * {<OpenLayers.Bounds>} The full extent of the tile set. If not supplied, │ │ │ │ + * the layer's <maxExtent> property will be used. │ │ │ │ + */ │ │ │ │ + tileFullExtent: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: formatSuffix │ │ │ │ + * {String} For REST request encoding, an image format suffix must be │ │ │ │ + * included in the request. If not provided, the suffix will be derived │ │ │ │ + * from the <format> property. │ │ │ │ + */ │ │ │ │ + formatSuffix: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: matrixIds │ │ │ │ + * {Array} A list of tile matrix identifiers. If not provided, the matrix │ │ │ │ + * identifiers will be assumed to be integers corresponding to the │ │ │ │ + * map zoom level. If a list of strings is provided, each item should │ │ │ │ + * be the matrix identifier that corresponds to the map zoom level. │ │ │ │ + * Additionally, a list of objects can be provided. Each object should │ │ │ │ + * describe the matrix as presented in the WMTS capabilities. These │ │ │ │ + * objects should have the propertes shown below. │ │ │ │ + * │ │ │ │ + * Matrix properties: │ │ │ │ + * identifier - {String} The matrix identifier (required). │ │ │ │ + * scaleDenominator - {Number} The matrix scale denominator. │ │ │ │ + * topLeftCorner - {<OpenLayers.LonLat>} The top left corner of the │ │ │ │ + * matrix. Must be provided if different than the layer <tileOrigin>. │ │ │ │ + * tileWidth - {Number} The tile width for the matrix. Must be provided │ │ │ │ + * if different than the width given in the layer <tileSize>. │ │ │ │ + * tileHeight - {Number} The tile height for the matrix. Must be provided │ │ │ │ + * if different than the height given in the layer <tileSize>. │ │ │ │ + */ │ │ │ │ + matrixIds: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: dimensions │ │ │ │ + * {Array} For RESTful request encoding, extra dimensions may be specified. │ │ │ │ + * Items in this list should be property names in the <params> object. │ │ │ │ + * Values of extra dimensions will be determined from the corresponding │ │ │ │ + * values in the <params> object. │ │ │ │ + */ │ │ │ │ + dimensions: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: params │ │ │ │ + * {Object} Extra parameters to include in tile requests. For KVP │ │ │ │ + * <requestEncoding>, these properties will be encoded in the request │ │ │ │ + * query string. For REST <requestEncoding>, these properties will │ │ │ │ + * become part of the request path, with order determined by the │ │ │ │ + * <dimensions> list. │ │ │ │ + */ │ │ │ │ + params: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: zoomOffset │ │ │ │ + * {Number} If your cache has more 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). Additionally, if this layer is to be used │ │ │ │ + * as an overlay and the cache has fewer zoom levels than the base │ │ │ │ + * layer, you can supply a negative zoomOffset. For example, if a │ │ │ │ + * map zoom level of 1 corresponds to your cache level zero, you would │ │ │ │ + * supply a -1 zoomOffset (and set the maxResolution of the layer │ │ │ │ + * appropriately). The zoomOffset value has no effect if complete │ │ │ │ + * matrix definitions (including scaleDenominator) are supplied in │ │ │ │ + * the <matrixIds> property. Defaults to 0 (no zoom offset). │ │ │ │ + */ │ │ │ │ + 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, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: formatSuffixMap │ │ │ │ + * {Object} a map between WMTS 'format' request parameter and tile image file suffix │ │ │ │ + */ │ │ │ │ + formatSuffixMap: { │ │ │ │ + "image/png": "png", │ │ │ │ + "image/png8": "png", │ │ │ │ + "image/png24": "png", │ │ │ │ + "image/png32": "png", │ │ │ │ + "png": "png", │ │ │ │ + "image/jpeg": "jpg", │ │ │ │ + "image/jpg": "jpg", │ │ │ │ + "jpeg": "jpg", │ │ │ │ + "jpg": "jpg" │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: matrix │ │ │ │ + * {Object} Matrix definition for the current map resolution. Updated by │ │ │ │ + * the <updateMatrixProperties> method. │ │ │ │ + */ │ │ │ │ + matrix: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.WMTS │ │ │ │ + * Create a new WMTS layer. │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * (code) │ │ │ │ + * var wmts = new OpenLayers.Layer.WMTS({ │ │ │ │ + * name: "My WMTS Layer", │ │ │ │ + * url: "http://example.com/wmts", │ │ │ │ + * layer: "layer_id", │ │ │ │ + * style: "default", │ │ │ │ + * matrixSet: "matrix_id" │ │ │ │ + * }); │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * config - {Object} Configuration properties for the layer. │ │ │ │ + * │ │ │ │ + * Required configuration properties: │ │ │ │ + * url - {String} The base url for the service. See the <url> property. │ │ │ │ + * layer - {String} The layer identifier. See the <layer> property. │ │ │ │ + * style - {String} The layer style identifier. See the <style> property. │ │ │ │ + * matrixSet - {String} The tile matrix set identifier. See the <matrixSet> │ │ │ │ + * property. │ │ │ │ + * │ │ │ │ + * Any other documented layer properties can be provided in the config object. │ │ │ │ + */ │ │ │ │ + initialize: function(config) { │ │ │ │ + │ │ │ │ + // confirm required properties are supplied │ │ │ │ + var required = { │ │ │ │ + url: true, │ │ │ │ + layer: true, │ │ │ │ + style: true, │ │ │ │ + matrixSet: true │ │ │ │ + }; │ │ │ │ + for (var prop in required) { │ │ │ │ + if (!(prop in config)) { │ │ │ │ + throw new Error("Missing property '" + prop + "' in layer configuration."); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + config.params = OpenLayers.Util.upperCaseObject(config.params); │ │ │ │ + var args = [config.name, config.url, config.params, config]; │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, args); │ │ │ │ + │ │ │ │ + │ │ │ │ + // determine format suffix (for REST) │ │ │ │ + if (!this.formatSuffix) { │ │ │ │ + this.formatSuffix = this.formatSuffixMap[this.format] || this.format.split("/").pop(); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // expand matrixIds (may be array of string or array of object) │ │ │ │ + if (this.matrixIds) { │ │ │ │ + var len = this.matrixIds.length; │ │ │ │ + if (len && typeof this.matrixIds[0] === "string") { │ │ │ │ + var ids = this.matrixIds; │ │ │ │ + this.matrixIds = new Array(len); │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ + this.matrixIds[i] = { │ │ │ │ + identifier: ids[i] │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ + */ │ │ │ │ + setMap: function() { │ │ │ │ + OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: updateMatrixProperties │ │ │ │ + * Called when map resolution changes to update matrix related properties. │ │ │ │ + */ │ │ │ │ + updateMatrixProperties: function() { │ │ │ │ + this.matrix = this.getMatrix(); │ │ │ │ + if (this.matrix) { │ │ │ │ + if (this.matrix.topLeftCorner) { │ │ │ │ + this.tileOrigin = this.matrix.topLeftCorner; │ │ │ │ + } │ │ │ │ + if (this.matrix.tileWidth && this.matrix.tileHeight) { │ │ │ │ + this.tileSize = new OpenLayers.Size( │ │ │ │ + this.matrix.tileWidth, this.matrix.tileHeight │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (!this.tileOrigin) { │ │ │ │ + this.tileOrigin = new OpenLayers.LonLat( │ │ │ │ + this.maxExtent.left, this.maxExtent.top │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (!this.tileFullExtent) { │ │ │ │ + this.tileFullExtent = this.maxExtent; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ + if (zoomChanged || !this.matrix) { │ │ │ │ + this.updateMatrixProperties(); │ │ │ │ + } │ │ │ │ + return OpenLayers.Layer.Grid.prototype.moveTo.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: clone │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.WMTS>} An exact clone of this <OpenLayers.Layer.WMTS> │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.WMTS(this.options); │ │ │ │ + } │ │ │ │ + //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; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getIdentifier │ │ │ │ + * Get the current index in the matrixIds array. │ │ │ │ + */ │ │ │ │ + getIdentifier: function() { │ │ │ │ + return this.getServerZoom(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getMatrix │ │ │ │ + * Get the appropriate matrix definition for the current map resolution. │ │ │ │ + */ │ │ │ │ + getMatrix: function() { │ │ │ │ + var matrix; │ │ │ │ + if (!this.matrixIds || this.matrixIds.length === 0) { │ │ │ │ + matrix = { │ │ │ │ + identifier: this.getIdentifier() │ │ │ │ + }; │ │ │ │ + } else { │ │ │ │ + // get appropriate matrix given the map scale if possible │ │ │ │ + if ("scaleDenominator" in this.matrixIds[0]) { │ │ │ │ + // scale denominator calculation based on WMTS spec │ │ │ │ + var denom = │ │ │ │ + OpenLayers.METERS_PER_INCH * │ │ │ │ + OpenLayers.INCHES_PER_UNIT[this.units] * │ │ │ │ + this.getServerResolution() / 0.28E-3; │ │ │ │ + var diff = Number.POSITIVE_INFINITY; │ │ │ │ + var delta; │ │ │ │ + for (var i = 0, ii = this.matrixIds.length; i < ii; ++i) { │ │ │ │ + delta = Math.abs(1 - (this.matrixIds[i].scaleDenominator / denom)); │ │ │ │ + if (delta < diff) { │ │ │ │ + diff = delta; │ │ │ │ + matrix = this.matrixIds[i]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + // fall back on zoom as index │ │ │ │ + matrix = this.matrixIds[this.getIdentifier()]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return matrix; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getTileInfo │ │ │ │ + * Get tile information for a given location at the current map resolution. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * loc - {<OpenLayers.LonLat} A location in map coordinates. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} An object with "col", "row", "i", and "j" properties. The col │ │ │ │ + * and row values are zero based tile indexes from the top left. The │ │ │ │ + * i and j values are the number of pixels to the left and top │ │ │ │ + * (respectively) of the given location within the target tile. │ │ │ │ + */ │ │ │ │ + getTileInfo: function(loc) { │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + │ │ │ │ + var fx = (loc.lon - this.tileOrigin.lon) / (res * this.tileSize.w); │ │ │ │ + var fy = (this.tileOrigin.lat - loc.lat) / (res * this.tileSize.h); │ │ │ │ + │ │ │ │ + var col = Math.floor(fx); │ │ │ │ + var row = Math.floor(fy); │ │ │ │ + │ │ │ │ + return { │ │ │ │ + col: col, │ │ │ │ + row: row, │ │ │ │ + i: Math.floor((fx - col) * this.tileSize.w), │ │ │ │ + j: Math.floor((fy - row) * this.tileSize.h) │ │ │ │ + }; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getURL │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * bounds - {<OpenLayers.Bounds>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A URL for the tile corresponding to the given bounds. │ │ │ │ + */ │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var url = ""; │ │ │ │ + if (!this.tileFullExtent || this.tileFullExtent.intersectsBounds(bounds)) { │ │ │ │ + │ │ │ │ + var center = bounds.getCenterLonLat(); │ │ │ │ + var info = this.getTileInfo(center); │ │ │ │ + var matrixId = this.matrix.identifier; │ │ │ │ + var dimensions = this.dimensions, │ │ │ │ + params; │ │ │ │ + │ │ │ │ + if (OpenLayers.Util.isArray(this.url)) { │ │ │ │ + url = this.selectUrl([ │ │ │ │ + this.version, this.style, this.matrixSet, │ │ │ │ + this.matrix.identifier, info.row, info.col │ │ │ │ + ].join(","), this.url); │ │ │ │ + } else { │ │ │ │ + url = this.url; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.requestEncoding.toUpperCase() === "REST") { │ │ │ │ + params = this.params; │ │ │ │ + if (url.indexOf("{") !== -1) { │ │ │ │ + var template = url.replace(/\{/g, "${"); │ │ │ │ + var context = { │ │ │ │ + // spec does not make clear if capital S or not │ │ │ │ + style: this.style, │ │ │ │ + Style: this.style, │ │ │ │ + TileMatrixSet: this.matrixSet, │ │ │ │ + TileMatrix: this.matrix.identifier, │ │ │ │ + TileRow: info.row, │ │ │ │ + TileCol: info.col │ │ │ │ + }; │ │ │ │ + if (dimensions) { │ │ │ │ + var dimension, i; │ │ │ │ + for (i = dimensions.length - 1; i >= 0; --i) { │ │ │ │ + dimension = dimensions[i]; │ │ │ │ + context[dimension] = params[dimension.toUpperCase()]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + url = OpenLayers.String.format(template, context); │ │ │ │ + } else { │ │ │ │ + // include 'version', 'layer' and 'style' in tile resource url │ │ │ │ + var path = this.version + "/" + this.layer + "/" + this.style + "/"; │ │ │ │ + │ │ │ │ + // append optional dimension path elements │ │ │ │ + if (dimensions) { │ │ │ │ + for (var i = 0; i < dimensions.length; i++) { │ │ │ │ + if (params[dimensions[i]]) { │ │ │ │ + path = path + params[dimensions[i]] + "/"; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // append other required path elements │ │ │ │ + path = path + this.matrixSet + "/" + this.matrix.identifier + │ │ │ │ + "/" + info.row + "/" + info.col + "." + this.formatSuffix; │ │ │ │ + │ │ │ │ + if (!url.match(/\/$/)) { │ │ │ │ + url = url + "/"; │ │ │ │ + } │ │ │ │ + url = url + path; │ │ │ │ + } │ │ │ │ + } else if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ + │ │ │ │ + // assemble all required parameters │ │ │ │ + params = { │ │ │ │ + SERVICE: "WMTS", │ │ │ │ + REQUEST: "GetTile", │ │ │ │ + VERSION: this.version, │ │ │ │ + LAYER: this.layer, │ │ │ │ + STYLE: this.style, │ │ │ │ + TILEMATRIXSET: this.matrixSet, │ │ │ │ + TILEMATRIX: this.matrix.identifier, │ │ │ │ + TILEROW: info.row, │ │ │ │ + TILECOL: info.col, │ │ │ │ + FORMAT: this.format │ │ │ │ + }; │ │ │ │ + url = OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this, [params]); │ │ │ │ + │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return url; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: mergeNewParams │ │ │ │ + * Extend the existing layer <params> with new properties. Tiles will be │ │ │ │ + * reloaded with updated params in the request. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * newParams - {Object} Properties to extend to existing <params>. │ │ │ │ + */ │ │ │ │ + mergeNewParams: function(newParams) { │ │ │ │ + if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ + return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply( │ │ │ │ + this, [OpenLayers.Util.upperCaseObject(newParams)] │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.WMTS" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/GeoRSS.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/Markers.js │ │ │ │ + * @requires OpenLayers/Request/XMLHttpRequest.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.GeoRSS │ │ │ │ + * Add GeoRSS Point features to your map. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Markers> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.GeoRSS = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: location │ │ │ │ + * {String} store url of text file │ │ │ │ + */ │ │ │ │ + location: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: features │ │ │ │ + * {Array(<OpenLayers.Feature>)} │ │ │ │ + */ │ │ │ │ + features: null, │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.SLD.v1 │ │ │ │ - * Instances of this class are not created directly. Use the │ │ │ │ - * <OpenLayers.Format.SLD> constructor instead. │ │ │ │ + * APIProperty: formatOptions │ │ │ │ + * {Object} Hash of options which should be passed to the format when it is │ │ │ │ + * created. Must be passed in the constructor. │ │ │ │ + */ │ │ │ │ + formatOptions: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: selectedFeature │ │ │ │ + * {<OpenLayers.Feature>} │ │ │ │ + */ │ │ │ │ + selectedFeature: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: icon │ │ │ │ + * {<OpenLayers.Icon>}. This determines the Icon to be used on the map │ │ │ │ + * for this GeoRSS layer. │ │ │ │ + */ │ │ │ │ + icon: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: popupSize │ │ │ │ + * {<OpenLayers.Size>} This determines the size of GeoRSS popups. If │ │ │ │ + * not provided, defaults to 250px by 120px. │ │ │ │ + */ │ │ │ │ + popupSize: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: useFeedTitle │ │ │ │ + * {Boolean} Set layer.name to the first <title> element in the feed. Default is true. │ │ │ │ + */ │ │ │ │ + useFeedTitle: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.GeoRSS │ │ │ │ + * Create a GeoRSS Layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * name - {String} │ │ │ │ + * location - {String} │ │ │ │ + * options - {Object} │ │ │ │ + */ │ │ │ │ + initialize: function(name, location, options) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.initialize.apply(this, [name, options]); │ │ │ │ + this.location = location; │ │ │ │ + this.features = []; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ + destroy: function() { │ │ │ │ + // Warning: Layer.Markers.destroy() must be called prior to calling │ │ │ │ + // clearFeatures() here, otherwise we leak memory. Indeed, if │ │ │ │ + // Layer.Markers.destroy() is called after clearFeatures(), it won't be │ │ │ │ + // able to remove the marker image elements from the layer's div since │ │ │ │ + // the markers will have been destroyed by clearFeatures(). │ │ │ │ + OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ + this.clearFeatures(); │ │ │ │ + this.features = null; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: read │ │ │ │ - * │ │ │ │ + * Method: loadRSS │ │ │ │ + * Start the load of the RSS data. Don't do this when we first add the layer, │ │ │ │ + * since we may not be visible at any point, and it would therefore be a waste. │ │ │ │ + */ │ │ │ │ + loadRSS: function() { │ │ │ │ + if (!this.loaded) { │ │ │ │ + this.events.triggerEvent("loadstart"); │ │ │ │ + OpenLayers.Request.GET({ │ │ │ │ + url: this.location, │ │ │ │ + success: this.parseData, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.loaded = true; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveTo │ │ │ │ + * If layer is visible and RSS has not been loaded, load RSS. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * data - {DOMElement} An SLD document element. │ │ │ │ - * options - {Object} Options for the reader. │ │ │ │ - * │ │ │ │ - * Valid options: │ │ │ │ - * namedLayersAsArray - {Boolean} Generate a namedLayers array. If false, │ │ │ │ - * the namedLayers property value will be an object keyed by layer name. │ │ │ │ - * Default is false. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An object representing the SLD. │ │ │ │ + * bounds - {Object} │ │ │ │ + * zoomChanged - {Object} │ │ │ │ + * minor - {Object} │ │ │ │ */ │ │ │ │ - read: function(data, options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ - var sld = { │ │ │ │ - namedLayers: options.namedLayersAsArray === true ? [] : {} │ │ │ │ - }; │ │ │ │ - this.readChildNodes(data, sld); │ │ │ │ - return sld; │ │ │ │ + moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ + if (this.visibility && !this.loaded) { │ │ │ │ + this.loadRSS(); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: parseData │ │ │ │ + * Parse the data returned from the Events call. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * ajaxRequest - {<OpenLayers.Request.XMLHttpRequest>} │ │ │ │ */ │ │ │ │ - readers: OpenLayers.Util.applyDefaults({ │ │ │ │ - "sld": { │ │ │ │ - "StyledLayerDescriptor": function(node, sld) { │ │ │ │ - sld.version = node.getAttribute("version"); │ │ │ │ - this.readChildNodes(node, sld); │ │ │ │ - }, │ │ │ │ - "Name": function(node, obj) { │ │ │ │ - obj.name = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Title": function(node, obj) { │ │ │ │ - obj.title = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Abstract": function(node, obj) { │ │ │ │ - obj.description = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "NamedLayer": function(node, sld) { │ │ │ │ - var layer = { │ │ │ │ - userStyles: [], │ │ │ │ - namedStyles: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, layer); │ │ │ │ - // give each of the user styles this layer name │ │ │ │ - for (var i = 0, len = layer.userStyles.length; i < len; ++i) { │ │ │ │ - layer.userStyles[i].layerName = layer.name; │ │ │ │ - } │ │ │ │ - if (OpenLayers.Util.isArray(sld.namedLayers)) { │ │ │ │ - sld.namedLayers.push(layer); │ │ │ │ - } else { │ │ │ │ - sld.namedLayers[layer.name] = layer; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "NamedStyle": function(node, layer) { │ │ │ │ - layer.namedStyles.push( │ │ │ │ - this.getChildName(node.firstChild) │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "UserStyle": function(node, layer) { │ │ │ │ - var obj = { │ │ │ │ - defaultsPerSymbolizer: true, │ │ │ │ - rules: [] │ │ │ │ - }; │ │ │ │ - this.featureTypeCounter = -1; │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - var style; │ │ │ │ - if (this.multipleSymbolizers) { │ │ │ │ - delete obj.defaultsPerSymbolizer; │ │ │ │ - style = new OpenLayers.Style2(obj); │ │ │ │ - } else { │ │ │ │ - style = new OpenLayers.Style(this.defaultSymbolizer, obj); │ │ │ │ - } │ │ │ │ - layer.userStyles.push(style); │ │ │ │ - }, │ │ │ │ - "IsDefault": function(node, style) { │ │ │ │ - if (this.getChildValue(node) == "1") { │ │ │ │ - style.isDefault = true; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "FeatureTypeStyle": function(node, style) { │ │ │ │ - ++this.featureTypeCounter; │ │ │ │ - var obj = { │ │ │ │ - rules: this.multipleSymbolizers ? style.rules : [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - if (!this.multipleSymbolizers) { │ │ │ │ - style.rules = obj.rules; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Rule": function(node, obj) { │ │ │ │ - var config; │ │ │ │ - if (this.multipleSymbolizers) { │ │ │ │ - config = { │ │ │ │ - symbolizers: [] │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - var rule = new OpenLayers.Rule(config); │ │ │ │ - this.readChildNodes(node, rule); │ │ │ │ - obj.rules.push(rule); │ │ │ │ - }, │ │ │ │ - "ElseFilter": function(node, rule) { │ │ │ │ - rule.elseFilter = true; │ │ │ │ - }, │ │ │ │ - "MinScaleDenominator": function(node, rule) { │ │ │ │ - rule.minScaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "MaxScaleDenominator": function(node, rule) { │ │ │ │ - rule.maxScaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "TextSymbolizer": function(node, rule) { │ │ │ │ - var config = {}; │ │ │ │ - this.readChildNodes(node, config); │ │ │ │ - if (this.multipleSymbolizers) { │ │ │ │ - config.zIndex = this.featureTypeCounter; │ │ │ │ - rule.symbolizers.push( │ │ │ │ - new OpenLayers.Symbolizer.Text(config) │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - rule.symbolizer["Text"] = OpenLayers.Util.applyDefaults( │ │ │ │ - config, rule.symbolizer["Text"] │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "LabelPlacement": function(node, symbolizer) { │ │ │ │ - this.readChildNodes(node, symbolizer); │ │ │ │ - }, │ │ │ │ - "PointPlacement": function(node, symbolizer) { │ │ │ │ - var config = {}; │ │ │ │ - this.readChildNodes(node, config); │ │ │ │ - config.labelRotation = config.rotation; │ │ │ │ - delete config.rotation; │ │ │ │ - var labelAlign, │ │ │ │ - x = symbolizer.labelAnchorPointX, │ │ │ │ - y = symbolizer.labelAnchorPointY; │ │ │ │ - if (x <= 1 / 3) { │ │ │ │ - labelAlign = 'l'; │ │ │ │ - } else if (x > 1 / 3 && x < 2 / 3) { │ │ │ │ - labelAlign = 'c'; │ │ │ │ - } else if (x >= 2 / 3) { │ │ │ │ - labelAlign = 'r'; │ │ │ │ - } │ │ │ │ - if (y <= 1 / 3) { │ │ │ │ - labelAlign += 'b'; │ │ │ │ - } else if (y > 1 / 3 && y < 2 / 3) { │ │ │ │ - labelAlign += 'm'; │ │ │ │ - } else if (y >= 2 / 3) { │ │ │ │ - labelAlign += 't'; │ │ │ │ - } │ │ │ │ - config.labelAlign = labelAlign; │ │ │ │ - OpenLayers.Util.applyDefaults(symbolizer, config); │ │ │ │ - }, │ │ │ │ - "AnchorPoint": function(node, symbolizer) { │ │ │ │ - this.readChildNodes(node, symbolizer); │ │ │ │ - }, │ │ │ │ - "AnchorPointX": function(node, symbolizer) { │ │ │ │ - var labelAnchorPointX = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (labelAnchorPointX) { │ │ │ │ - symbolizer.labelAnchorPointX = labelAnchorPointX; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "AnchorPointY": function(node, symbolizer) { │ │ │ │ - var labelAnchorPointY = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (labelAnchorPointY) { │ │ │ │ - symbolizer.labelAnchorPointY = labelAnchorPointY; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Displacement": function(node, symbolizer) { │ │ │ │ - this.readChildNodes(node, symbolizer); │ │ │ │ - }, │ │ │ │ - "DisplacementX": function(node, symbolizer) { │ │ │ │ - var labelXOffset = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (labelXOffset) { │ │ │ │ - symbolizer.labelXOffset = labelXOffset; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "DisplacementY": function(node, symbolizer) { │ │ │ │ - var labelYOffset = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (labelYOffset) { │ │ │ │ - symbolizer.labelYOffset = labelYOffset; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "LinePlacement": function(node, symbolizer) { │ │ │ │ - this.readChildNodes(node, symbolizer); │ │ │ │ - }, │ │ │ │ - "PerpendicularOffset": function(node, symbolizer) { │ │ │ │ - var labelPerpendicularOffset = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (labelPerpendicularOffset) { │ │ │ │ - symbolizer.labelPerpendicularOffset = labelPerpendicularOffset; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Label": function(node, symbolizer) { │ │ │ │ - var value = this.readers.ogc._expression.call(this, node); │ │ │ │ - if (value) { │ │ │ │ - symbolizer.label = value; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Font": function(node, symbolizer) { │ │ │ │ - this.readChildNodes(node, symbolizer); │ │ │ │ - }, │ │ │ │ - "Halo": function(node, symbolizer) { │ │ │ │ - // halo has a fill, so send fresh object │ │ │ │ - var obj = {}; │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - symbolizer.haloRadius = obj.haloRadius; │ │ │ │ - symbolizer.haloColor = obj.fillColor; │ │ │ │ - symbolizer.haloOpacity = obj.fillOpacity; │ │ │ │ - }, │ │ │ │ - "Radius": function(node, symbolizer) { │ │ │ │ - var radius = this.readers.ogc._expression.call(this, node); │ │ │ │ - if (radius != null) { │ │ │ │ - // radius is only used for halo │ │ │ │ - symbolizer.haloRadius = radius; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "RasterSymbolizer": function(node, rule) { │ │ │ │ - var config = {}; │ │ │ │ - this.readChildNodes(node, config); │ │ │ │ - if (this.multipleSymbolizers) { │ │ │ │ - config.zIndex = this.featureTypeCounter; │ │ │ │ - rule.symbolizers.push( │ │ │ │ - new OpenLayers.Symbolizer.Raster(config) │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - rule.symbolizer["Raster"] = OpenLayers.Util.applyDefaults( │ │ │ │ - config, rule.symbolizer["Raster"] │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Geometry": function(node, obj) { │ │ │ │ - obj.geometry = {}; │ │ │ │ - this.readChildNodes(node, obj.geometry); │ │ │ │ - }, │ │ │ │ - "ColorMap": function(node, symbolizer) { │ │ │ │ - symbolizer.colorMap = []; │ │ │ │ - this.readChildNodes(node, symbolizer.colorMap); │ │ │ │ - }, │ │ │ │ - "ColorMapEntry": function(node, colorMap) { │ │ │ │ - var q = node.getAttribute("quantity"); │ │ │ │ - var o = node.getAttribute("opacity"); │ │ │ │ - colorMap.push({ │ │ │ │ - color: node.getAttribute("color"), │ │ │ │ - quantity: q !== null ? parseFloat(q) : undefined, │ │ │ │ - label: node.getAttribute("label") || undefined, │ │ │ │ - opacity: o !== null ? parseFloat(o) : undefined │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "LineSymbolizer": function(node, rule) { │ │ │ │ - var config = {}; │ │ │ │ - this.readChildNodes(node, config); │ │ │ │ - if (this.multipleSymbolizers) { │ │ │ │ - config.zIndex = this.featureTypeCounter; │ │ │ │ - rule.symbolizers.push( │ │ │ │ - new OpenLayers.Symbolizer.Line(config) │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - rule.symbolizer["Line"] = OpenLayers.Util.applyDefaults( │ │ │ │ - config, rule.symbolizer["Line"] │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "PolygonSymbolizer": function(node, rule) { │ │ │ │ - var config = { │ │ │ │ - fill: false, │ │ │ │ - stroke: false │ │ │ │ - }; │ │ │ │ - if (!this.multipleSymbolizers) { │ │ │ │ - config = rule.symbolizer["Polygon"] || config; │ │ │ │ - } │ │ │ │ - this.readChildNodes(node, config); │ │ │ │ - if (this.multipleSymbolizers) { │ │ │ │ - config.zIndex = this.featureTypeCounter; │ │ │ │ - rule.symbolizers.push( │ │ │ │ - new OpenLayers.Symbolizer.Polygon(config) │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - rule.symbolizer["Polygon"] = config; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "PointSymbolizer": function(node, rule) { │ │ │ │ - var config = { │ │ │ │ - fill: false, │ │ │ │ - stroke: false, │ │ │ │ - graphic: false │ │ │ │ - }; │ │ │ │ - if (!this.multipleSymbolizers) { │ │ │ │ - config = rule.symbolizer["Point"] || config; │ │ │ │ - } │ │ │ │ - this.readChildNodes(node, config); │ │ │ │ - if (this.multipleSymbolizers) { │ │ │ │ - config.zIndex = this.featureTypeCounter; │ │ │ │ - rule.symbolizers.push( │ │ │ │ - new OpenLayers.Symbolizer.Point(config) │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - rule.symbolizer["Point"] = config; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Stroke": function(node, symbolizer) { │ │ │ │ - symbolizer.stroke = true; │ │ │ │ - this.readChildNodes(node, symbolizer); │ │ │ │ - }, │ │ │ │ - "Fill": function(node, symbolizer) { │ │ │ │ - symbolizer.fill = true; │ │ │ │ - this.readChildNodes(node, symbolizer); │ │ │ │ - }, │ │ │ │ - "CssParameter": function(node, symbolizer) { │ │ │ │ - var cssProperty = node.getAttribute("name"); │ │ │ │ - var symProperty = this.cssMap[cssProperty]; │ │ │ │ - // for labels, fill should map to fontColor and fill-opacity │ │ │ │ - // to fontOpacity │ │ │ │ - if (symbolizer.label) { │ │ │ │ - if (cssProperty === 'fill') { │ │ │ │ - symProperty = "fontColor"; │ │ │ │ - } else if (cssProperty === 'fill-opacity') { │ │ │ │ - symProperty = "fontOpacity"; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (symProperty) { │ │ │ │ - // Limited support for parsing of OGC expressions │ │ │ │ - var value = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be an empty string │ │ │ │ - if (value) { │ │ │ │ - symbolizer[symProperty] = value; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Graphic": function(node, symbolizer) { │ │ │ │ - symbolizer.graphic = true; │ │ │ │ - var graphic = {}; │ │ │ │ - // painter's order not respected here, clobber previous with next │ │ │ │ - this.readChildNodes(node, graphic); │ │ │ │ - // directly properties with names that match symbolizer properties │ │ │ │ - var properties = [ │ │ │ │ - "stroke", "strokeColor", "strokeWidth", "strokeOpacity", │ │ │ │ - "strokeLinecap", "fill", "fillColor", "fillOpacity", │ │ │ │ - "graphicName", "rotation", "graphicFormat" │ │ │ │ - ]; │ │ │ │ - var prop, value; │ │ │ │ - for (var i = 0, len = properties.length; i < len; ++i) { │ │ │ │ - prop = properties[i]; │ │ │ │ - value = graphic[prop]; │ │ │ │ - if (value != undefined) { │ │ │ │ - symbolizer[prop] = value; │ │ │ │ - } │ │ │ │ + parseData: function(ajaxRequest) { │ │ │ │ + var doc = ajaxRequest.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = OpenLayers.Format.XML.prototype.read(ajaxRequest.responseText); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.useFeedTitle) { │ │ │ │ + var name = null; │ │ │ │ + try { │ │ │ │ + name = doc.getElementsByTagNameNS('*', 'title')[0].firstChild.nodeValue; │ │ │ │ + } catch (e) { │ │ │ │ + try { │ │ │ │ + name = doc.getElementsByTagName('title')[0].firstChild.nodeValue; │ │ │ │ + } catch (e) {} │ │ │ │ + } │ │ │ │ + if (name) { │ │ │ │ + this.setName(name); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + var options = {}; │ │ │ │ + │ │ │ │ + OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ + │ │ │ │ + if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ + options.externalProjection = this.projection; │ │ │ │ + options.internalProjection = this.map.getProjectionObject(); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var format = new OpenLayers.Format.GeoRSS(options); │ │ │ │ + var features = format.read(doc); │ │ │ │ + │ │ │ │ + for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ + var data = {}; │ │ │ │ + var feature = features[i]; │ │ │ │ + │ │ │ │ + // we don't support features with no geometry in the GeoRSS │ │ │ │ + // layer at this time. │ │ │ │ + if (!feature.geometry) { │ │ │ │ + continue; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var title = feature.attributes.title ? │ │ │ │ + feature.attributes.title : "Untitled"; │ │ │ │ + │ │ │ │ + var description = feature.attributes.description ? │ │ │ │ + feature.attributes.description : "No description."; │ │ │ │ + │ │ │ │ + var link = feature.attributes.link ? feature.attributes.link : ""; │ │ │ │ + │ │ │ │ + var location = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ + │ │ │ │ + │ │ │ │ + data.icon = this.icon == null ? │ │ │ │ + OpenLayers.Marker.defaultIcon() : │ │ │ │ + this.icon.clone(); │ │ │ │ + │ │ │ │ + data.popupSize = this.popupSize ? │ │ │ │ + this.popupSize.clone() : │ │ │ │ + new OpenLayers.Size(250, 120); │ │ │ │ + │ │ │ │ + if (title || description) { │ │ │ │ + // we have supplemental data, store them. │ │ │ │ + data.title = title; │ │ │ │ + data.description = description; │ │ │ │ + │ │ │ │ + var contentHTML = '<div class="olLayerGeoRSSClose">[x]</div>'; │ │ │ │ + contentHTML += '<div class="olLayerGeoRSSTitle">'; │ │ │ │ + if (link) { │ │ │ │ + contentHTML += '<a class="link" href="' + link + '" target="_blank">'; │ │ │ │ } │ │ │ │ - // set other generic properties with specific graphic property names │ │ │ │ - if (graphic.opacity != undefined) { │ │ │ │ - symbolizer.graphicOpacity = graphic.opacity; │ │ │ │ + contentHTML += title; │ │ │ │ + if (link) { │ │ │ │ + contentHTML += '</a>'; │ │ │ │ } │ │ │ │ - if (graphic.size != undefined) { │ │ │ │ - var pointRadius = graphic.size / 2; │ │ │ │ - if (isNaN(pointRadius)) { │ │ │ │ - // likely a property name │ │ │ │ - symbolizer.graphicWidth = graphic.size; │ │ │ │ - } else { │ │ │ │ - symbolizer.pointRadius = graphic.size / 2; │ │ │ │ + contentHTML += '</div>'; │ │ │ │ + contentHTML += '<div style="" class="olLayerGeoRSSDescription">'; │ │ │ │ + contentHTML += description; │ │ │ │ + contentHTML += '</div>'; │ │ │ │ + data['popupContentHTML'] = contentHTML; │ │ │ │ + } │ │ │ │ + var feature = new OpenLayers.Feature(this, location, data); │ │ │ │ + this.features.push(feature); │ │ │ │ + var marker = feature.createMarker(); │ │ │ │ + marker.events.register('click', feature, this.markerClick); │ │ │ │ + this.addMarker(marker); │ │ │ │ + } │ │ │ │ + this.events.triggerEvent("loadend"); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: markerClick │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + */ │ │ │ │ + markerClick: function(evt) { │ │ │ │ + var sameMarkerClicked = (this == this.layer.selectedFeature); │ │ │ │ + this.layer.selectedFeature = (!sameMarkerClicked) ? this : null; │ │ │ │ + for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ + this.layer.map.removePopup(this.layer.map.popups[i]); │ │ │ │ + } │ │ │ │ + if (!sameMarkerClicked) { │ │ │ │ + var popup = this.createPopup(); │ │ │ │ + OpenLayers.Event.observe(popup.div, "click", │ │ │ │ + OpenLayers.Function.bind(function() { │ │ │ │ + for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ + this.layer.map.removePopup(this.layer.map.popups[i]); │ │ │ │ } │ │ │ │ - } │ │ │ │ - if (graphic.href != undefined) { │ │ │ │ - symbolizer.externalGraphic = graphic.href; │ │ │ │ - } │ │ │ │ - if (graphic.rotation != undefined) { │ │ │ │ - symbolizer.rotation = graphic.rotation; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "ExternalGraphic": function(node, graphic) { │ │ │ │ - this.readChildNodes(node, graphic); │ │ │ │ - }, │ │ │ │ - "Mark": function(node, graphic) { │ │ │ │ - this.readChildNodes(node, graphic); │ │ │ │ - }, │ │ │ │ - "WellKnownName": function(node, graphic) { │ │ │ │ - graphic.graphicName = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Opacity": function(node, obj) { │ │ │ │ - var opacity = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (opacity) { │ │ │ │ - obj.opacity = opacity; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Size": function(node, obj) { │ │ │ │ - var size = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (size) { │ │ │ │ - obj.size = size; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Rotation": function(node, obj) { │ │ │ │ - var rotation = this.readers.ogc._expression.call(this, node); │ │ │ │ - // always string, could be empty string │ │ │ │ - if (rotation) { │ │ │ │ - obj.rotation = rotation; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "OnlineResource": function(node, obj) { │ │ │ │ - obj.href = this.getAttributeNS( │ │ │ │ - node, this.namespaces.xlink, "href" │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "Format": function(node, graphic) { │ │ │ │ - graphic.graphicFormat = this.getChildValue(node); │ │ │ │ + }, this) │ │ │ │ + ); │ │ │ │ + this.layer.map.addPopup(popup); │ │ │ │ + } │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clearFeatures │ │ │ │ + * Destroy all features in this layer. │ │ │ │ + */ │ │ │ │ + clearFeatures: function() { │ │ │ │ + if (this.features != null) { │ │ │ │ + while (this.features.length > 0) { │ │ │ │ + var feature = this.features[0]; │ │ │ │ + OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ + feature.destroy(); │ │ │ │ } │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.Filter.v1_0_0.prototype.readers), │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.GeoRSS" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/ArcGIS93Rest.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.ArcGIS93Rest │ │ │ │ + * Instances of OpenLayers.Layer.ArcGIS93Rest are used to display data from │ │ │ │ + * ESRI ArcGIS Server 9.3 (and up?) Mapping Services using the REST API. │ │ │ │ + * Create a new ArcGIS93Rest layer with the <OpenLayers.Layer.ArcGIS93Rest> │ │ │ │ + * constructor. More detail on the REST API is available at │ │ │ │ + * http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/index.html ; │ │ │ │ + * specifically, the URL provided to this layer should be an export service │ │ │ │ + * URL: http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/export.html │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.ArcGIS93Rest = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: cssMap │ │ │ │ - * {Object} Object mapping supported css property names to OpenLayers │ │ │ │ - * symbolizer property names. │ │ │ │ + * Constant: DEFAULT_PARAMS │ │ │ │ + * {Object} Hashtable of default parameter key/value pairs │ │ │ │ */ │ │ │ │ - cssMap: { │ │ │ │ - "stroke": "strokeColor", │ │ │ │ - "stroke-opacity": "strokeOpacity", │ │ │ │ - "stroke-width": "strokeWidth", │ │ │ │ - "stroke-linecap": "strokeLinecap", │ │ │ │ - "stroke-dasharray": "strokeDashstyle", │ │ │ │ - "fill": "fillColor", │ │ │ │ - "fill-opacity": "fillOpacity", │ │ │ │ - "font-family": "fontFamily", │ │ │ │ - "font-size": "fontSize", │ │ │ │ - "font-weight": "fontWeight", │ │ │ │ - "font-style": "fontStyle" │ │ │ │ + DEFAULT_PARAMS: { │ │ │ │ + format: "png" │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getCssProperty │ │ │ │ - * Given a symbolizer property, get the corresponding CSS property │ │ │ │ - * from the <cssMap>. │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} Default is true for ArcGIS93Rest layer │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.ArcGIS93Rest │ │ │ │ + * Create a new ArcGIS93Rest layer object. │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * (code) │ │ │ │ + * var arcims = new OpenLayers.Layer.ArcGIS93Rest("MyName", │ │ │ │ + * "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/export", │ │ │ │ + * { │ │ │ │ + * layers: "0,1,2" │ │ │ │ + * }); │ │ │ │ + * (end) │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * sym - {String} A symbolizer property name. │ │ │ │ + * name - {String} A name for the layer │ │ │ │ + * url - {String} Base url for the ArcGIS server REST service │ │ │ │ + * options - {Object} An object with key/value pairs representing the │ │ │ │ + * options and option values. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {String} A CSS property name or null if none found. │ │ │ │ + * Valid Options: │ │ │ │ + * format - {String} MIME type of desired image type. │ │ │ │ + * layers - {String} Comma-separated list of layers to display. │ │ │ │ + * srs - {String} Projection ID. │ │ │ │ */ │ │ │ │ - getCssProperty: function(sym) { │ │ │ │ - var css = null; │ │ │ │ - for (var prop in this.cssMap) { │ │ │ │ - if (this.cssMap[prop] == sym) { │ │ │ │ - css = prop; │ │ │ │ - break; │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + var newArguments = []; │ │ │ │ + //uppercase params │ │ │ │ + params = OpenLayers.Util.upperCaseObject(params); │ │ │ │ + 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.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 == "jpg") { │ │ │ │ + this.params.FORMAT = OpenLayers.Util.alphaHack() ? "gif" : │ │ │ │ + "png"; │ │ │ │ } │ │ │ │ } │ │ │ │ - return css; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getGraphicFormat │ │ │ │ - * Given a href for an external graphic, try to determine the mime-type. │ │ │ │ - * This method doesn't try too hard, and will fall back to │ │ │ │ - * <defaultGraphicFormat> if one of the known <graphicFormats> is not │ │ │ │ - * the file extension of the provided href. │ │ │ │ + * Method: clone │ │ │ │ + * Create a clone of this layer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.ArcGIS93Rest>} An exact clone of this layer │ │ │ │ + */ │ │ │ │ + clone: function(obj) { │ │ │ │ + │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.ArcGIS93Rest(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; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getURL │ │ │ │ + * Return an image url this layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * href - {String} │ │ │ │ + * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the │ │ │ │ + * request. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} The graphic format. │ │ │ │ + * {String} A string with the map image's url. │ │ │ │ */ │ │ │ │ - getGraphicFormat: function(href) { │ │ │ │ - var format, regex; │ │ │ │ - for (var key in this.graphicFormats) { │ │ │ │ - if (this.graphicFormats[key].test(href)) { │ │ │ │ - format = key; │ │ │ │ - break; │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + │ │ │ │ + // ArcGIS Server only wants the numeric portion of the projection ID. │ │ │ │ + var projWords = this.projection.getCode().split(":"); │ │ │ │ + var srid = projWords[projWords.length - 1]; │ │ │ │ + │ │ │ │ + var imageSize = this.getImageSize(); │ │ │ │ + var newParams = { │ │ │ │ + 'BBOX': bounds.toBBOX(), │ │ │ │ + 'SIZE': imageSize.w + "," + imageSize.h, │ │ │ │ + // We always want image, the other options were json, image with a whole lotta html around it, etc. │ │ │ │ + 'F': "image", │ │ │ │ + 'BBOXSR': srid, │ │ │ │ + 'IMAGESR': srid │ │ │ │ + }; │ │ │ │ + │ │ │ │ + // Now add the filter parameters. │ │ │ │ + if (this.layerDefs) { │ │ │ │ + var layerDefStrList = []; │ │ │ │ + var layerID; │ │ │ │ + for (layerID in this.layerDefs) { │ │ │ │ + if (this.layerDefs.hasOwnProperty(layerID)) { │ │ │ │ + if (this.layerDefs[layerID]) { │ │ │ │ + layerDefStrList.push(layerID); │ │ │ │ + layerDefStrList.push(":"); │ │ │ │ + layerDefStrList.push(this.layerDefs[layerID]); │ │ │ │ + layerDefStrList.push(";"); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (layerDefStrList.length > 0) { │ │ │ │ + newParams['LAYERDEFS'] = layerDefStrList.join(""); │ │ │ │ } │ │ │ │ } │ │ │ │ - return format || this.defaultGraphicFormat; │ │ │ │ + var requestString = this.getFullRequestString(newParams); │ │ │ │ + return requestString; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: defaultGraphicFormat │ │ │ │ - * {String} If none other can be determined from <getGraphicFormat>, this │ │ │ │ - * default will be returned. │ │ │ │ + * Method: setLayerFilter │ │ │ │ + * addTile creates a tile, initializes it, and adds it to the layer div. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * id - {String} The id of the layer to which the filter applies. │ │ │ │ + * queryDef - {String} A sql-ish query filter, for more detail see the ESRI │ │ │ │ + * documentation at http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/export.html │ │ │ │ */ │ │ │ │ - defaultGraphicFormat: "image/png", │ │ │ │ + setLayerFilter: function(id, queryDef) { │ │ │ │ + if (!this.layerDefs) { │ │ │ │ + this.layerDefs = {}; │ │ │ │ + } │ │ │ │ + if (queryDef) { │ │ │ │ + this.layerDefs[id] = queryDef; │ │ │ │ + } else { │ │ │ │ + delete this.layerDefs[id]; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: graphicFormats │ │ │ │ - * {Object} Mapping of image mime-types to regular extensions matching │ │ │ │ - * well-known file extensions. │ │ │ │ + * Method: clearLayerFilter │ │ │ │ + * Clears layer filters, either from a specific layer, │ │ │ │ + * or all of them. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * id - {String} The id of the layer from which to remove any │ │ │ │ + * filter. If unspecified/blank, all filters │ │ │ │ + * will be removed. │ │ │ │ */ │ │ │ │ - graphicFormats: { │ │ │ │ - "image/jpeg": /\.jpe?g$/i, │ │ │ │ - "image/gif": /\.gif$/i, │ │ │ │ - "image/png": /\.png$/i │ │ │ │ + clearLayerFilter: function(id) { │ │ │ │ + if (id) { │ │ │ │ + delete this.layerDefs[id]; │ │ │ │ + } else { │ │ │ │ + delete this.layerDefs; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: write │ │ │ │ + * 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); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.ArcGIS93Rest" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/Boxes.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/Layer/Markers.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.Boxes │ │ │ │ + * Draw divs as 'boxes' on the layer. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Markers> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.Boxes = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.Boxes │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * sld - {Object} An object representing the SLD. │ │ │ │ + * name - {String} │ │ │ │ + * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: drawMarker │ │ │ │ + * Calculate the pixel location for the marker, create it, and │ │ │ │ + * add it to the layer's div │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} The root of an SLD document. │ │ │ │ + * Parameters: │ │ │ │ + * marker - {<OpenLayers.Marker.Box>} │ │ │ │ */ │ │ │ │ - write: function(sld) { │ │ │ │ - return this.writers.sld.StyledLayerDescriptor.apply(this, [sld]); │ │ │ │ + drawMarker: function(marker) { │ │ │ │ + var topleft = this.map.getLayerPxFromLonLat({ │ │ │ │ + lon: marker.bounds.left, │ │ │ │ + lat: marker.bounds.top │ │ │ │ + }); │ │ │ │ + var botright = this.map.getLayerPxFromLonLat({ │ │ │ │ + lon: marker.bounds.right, │ │ │ │ + lat: marker.bounds.bottom │ │ │ │ + }); │ │ │ │ + if (botright == null || topleft == null) { │ │ │ │ + marker.display(false); │ │ │ │ + } else { │ │ │ │ + var markerDiv = marker.draw(topleft, { │ │ │ │ + w: Math.max(1, botright.x - topleft.x), │ │ │ │ + h: Math.max(1, botright.y - topleft.y) │ │ │ │ + }); │ │ │ │ + if (!marker.drawn) { │ │ │ │ + this.div.appendChild(markerDiv); │ │ │ │ + marker.drawn = true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: removeMarker │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * marker - {<OpenLayers.Marker.Box>} │ │ │ │ */ │ │ │ │ - writers: OpenLayers.Util.applyDefaults({ │ │ │ │ - "sld": { │ │ │ │ - "_OGCExpression": function(nodeName, value) { │ │ │ │ - // only the simplest of ogc:expression handled │ │ │ │ - // {label: "some text and a ${propertyName}"} │ │ │ │ - var node = this.createElementNSPlus(nodeName); │ │ │ │ - var tokens = typeof value == "string" ? │ │ │ │ - value.split("${") : [value]; │ │ │ │ - node.appendChild(this.createTextNode(tokens[0])); │ │ │ │ - var item, last; │ │ │ │ - for (var i = 1, len = tokens.length; i < len; i++) { │ │ │ │ - item = tokens[i]; │ │ │ │ - last = item.indexOf("}"); │ │ │ │ - if (last > 0) { │ │ │ │ - this.writeNode( │ │ │ │ - "ogc:PropertyName", { │ │ │ │ - property: item.substring(0, last) │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - node.appendChild( │ │ │ │ - this.createTextNode(item.substring(++last)) │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - // no ending }, so this is a literal ${ │ │ │ │ - node.appendChild( │ │ │ │ - this.createTextNode("${" + item) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "StyledLayerDescriptor": function(sld) { │ │ │ │ - var root = this.createElementNSPlus( │ │ │ │ - "sld:StyledLayerDescriptor", { │ │ │ │ - attributes: { │ │ │ │ - "version": this.VERSION, │ │ │ │ - "xsi:schemaLocation": this.schemaLocation │ │ │ │ - } │ │ │ │ - } │ │ │ │ - ); │ │ │ │ + removeMarker: function(marker) { │ │ │ │ + OpenLayers.Util.removeItem(this.markers, marker); │ │ │ │ + if ((marker.div != null) && │ │ │ │ + (marker.div.parentNode == this.div)) { │ │ │ │ + this.div.removeChild(marker.div); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - // For ArcGIS Server it is necessary to define this │ │ │ │ - // at the root level (see ticket:2166). │ │ │ │ - root.setAttribute("xmlns:ogc", this.namespaces.ogc); │ │ │ │ - root.setAttribute("xmlns:gml", this.namespaces.gml); │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Boxes" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/WorldWind.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - // add in optional name │ │ │ │ - if (sld.name) { │ │ │ │ - this.writeNode("Name", sld.name, root); │ │ │ │ - } │ │ │ │ - // add in optional title │ │ │ │ - if (sld.title) { │ │ │ │ - this.writeNode("Title", sld.title, root); │ │ │ │ - } │ │ │ │ - // add in optional description │ │ │ │ - if (sld.description) { │ │ │ │ - this.writeNode("Abstract", sld.description, root); │ │ │ │ - } │ │ │ │ - // add in named layers │ │ │ │ - // allow namedLayers to be an array │ │ │ │ - if (OpenLayers.Util.isArray(sld.namedLayers)) { │ │ │ │ - for (var i = 0, len = sld.namedLayers.length; i < len; ++i) { │ │ │ │ - this.writeNode("NamedLayer", sld.namedLayers[i], root); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - for (var name in sld.namedLayers) { │ │ │ │ - this.writeNode("NamedLayer", sld.namedLayers[name], root); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return root; │ │ │ │ - }, │ │ │ │ - "Name": function(name) { │ │ │ │ - return this.createElementNSPlus("sld:Name", { │ │ │ │ - value: name │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Title": function(title) { │ │ │ │ - return this.createElementNSPlus("sld:Title", { │ │ │ │ - value: title │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Abstract": function(description) { │ │ │ │ - return this.createElementNSPlus( │ │ │ │ - "sld:Abstract", { │ │ │ │ - value: description │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "NamedLayer": function(layer) { │ │ │ │ - var node = this.createElementNSPlus("sld:NamedLayer"); │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - // add in required name │ │ │ │ - this.writeNode("Name", layer.name, node); │ │ │ │ │ │ │ │ - // optional sld:LayerFeatureConstraints here │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Layer/Grid.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - // add in named styles │ │ │ │ - if (layer.namedStyles) { │ │ │ │ - for (var i = 0, len = layer.namedStyles.length; i < len; ++i) { │ │ │ │ - this.writeNode( │ │ │ │ - "NamedStyle", layer.namedStyles[i], node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.WorldWind │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Grid> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.WorldWind = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ │ │ │ │ - // add in user styles │ │ │ │ - if (layer.userStyles) { │ │ │ │ - for (var i = 0, len = layer.userStyles.length; i < len; ++i) { │ │ │ │ - this.writeNode( │ │ │ │ - "UserStyle", layer.userStyles[i], node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + DEFAULT_PARAMS: {}, │ │ │ │ │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "NamedStyle": function(name) { │ │ │ │ - var node = this.createElementNSPlus("sld:NamedStyle"); │ │ │ │ - this.writeNode("Name", name, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "UserStyle": function(style) { │ │ │ │ - var node = this.createElementNSPlus("sld:UserStyle"); │ │ │ │ + /** │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ + * {Boolean} WorldWind layer is a base layer by default. │ │ │ │ + */ │ │ │ │ + isBaseLayer: true, │ │ │ │ │ │ │ │ - // add in optional name │ │ │ │ - if (style.name) { │ │ │ │ - this.writeNode("Name", style.name, node); │ │ │ │ - } │ │ │ │ - // add in optional title │ │ │ │ - if (style.title) { │ │ │ │ - this.writeNode("Title", style.title, node); │ │ │ │ - } │ │ │ │ - // add in optional description │ │ │ │ - if (style.description) { │ │ │ │ - this.writeNode("Abstract", style.description, node); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: lzd │ │ │ │ + * {Float} LevelZeroTileSizeDegrees │ │ │ │ + */ │ │ │ │ + lzd: null, │ │ │ │ │ │ │ │ - // add isdefault │ │ │ │ - if (style.isDefault) { │ │ │ │ - this.writeNode("IsDefault", style.isDefault, node); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: zoomLevels │ │ │ │ + * {Integer} Number of zoom levels. │ │ │ │ + */ │ │ │ │ + zoomLevels: null, │ │ │ │ │ │ │ │ - // add FeatureTypeStyles │ │ │ │ - if (this.multipleSymbolizers && style.rules) { │ │ │ │ - // group style objects by symbolizer zIndex │ │ │ │ - var rulesByZ = { │ │ │ │ - 0: [] │ │ │ │ - }; │ │ │ │ - var zValues = [0]; │ │ │ │ - var rule, ruleMap, symbolizer, zIndex, clone; │ │ │ │ - for (var i = 0, ii = style.rules.length; i < ii; ++i) { │ │ │ │ - rule = style.rules[i]; │ │ │ │ - if (rule.symbolizers) { │ │ │ │ - ruleMap = {}; │ │ │ │ - for (var j = 0, jj = rule.symbolizers.length; j < jj; ++j) { │ │ │ │ - symbolizer = rule.symbolizers[j]; │ │ │ │ - zIndex = symbolizer.zIndex; │ │ │ │ - if (!(zIndex in ruleMap)) { │ │ │ │ - clone = rule.clone(); │ │ │ │ - clone.symbolizers = []; │ │ │ │ - ruleMap[zIndex] = clone; │ │ │ │ - } │ │ │ │ - ruleMap[zIndex].symbolizers.push(symbolizer.clone()); │ │ │ │ - } │ │ │ │ - for (zIndex in ruleMap) { │ │ │ │ - if (!(zIndex in rulesByZ)) { │ │ │ │ - zValues.push(zIndex); │ │ │ │ - rulesByZ[zIndex] = []; │ │ │ │ - } │ │ │ │ - rulesByZ[zIndex].push(ruleMap[zIndex]); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - // no symbolizers in rule │ │ │ │ - rulesByZ[0].push(rule.clone()); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - // write one FeatureTypeStyle per zIndex │ │ │ │ - zValues.sort(); │ │ │ │ - var rules; │ │ │ │ - for (var i = 0, ii = zValues.length; i < ii; ++i) { │ │ │ │ - rules = rulesByZ[zValues[i]]; │ │ │ │ - if (rules.length > 0) { │ │ │ │ - clone = style.clone(); │ │ │ │ - clone.rules = rulesByZ[zValues[i]]; │ │ │ │ - this.writeNode("FeatureTypeStyle", clone, node); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.writeNode("FeatureTypeStyle", style, node); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Layer.WorldWind │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} Name of Layer │ │ │ │ + * url - {String} Base URL │ │ │ │ + * lzd - {Float} Level zero tile size degrees │ │ │ │ + * zoomLevels - {Integer} number of zoom levels │ │ │ │ + * params - {Object} additional parameters │ │ │ │ + * options - {Object} additional options │ │ │ │ + */ │ │ │ │ + initialize: function(name, url, lzd, zoomLevels, params, options) { │ │ │ │ + this.lzd = lzd; │ │ │ │ + this.zoomLevels = zoomLevels; │ │ │ │ + var newArguments = []; │ │ │ │ + newArguments.push(name, url, params, options); │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments); │ │ │ │ + this.params = OpenLayers.Util.applyDefaults( │ │ │ │ + this.params, this.DEFAULT_PARAMS │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "IsDefault": function(bool) { │ │ │ │ - return this.createElementNSPlus( │ │ │ │ - "sld:IsDefault", { │ │ │ │ - value: (bool) ? "1" : "0" │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "FeatureTypeStyle": function(style) { │ │ │ │ - var node = this.createElementNSPlus("sld:FeatureTypeStyle"); │ │ │ │ + /** │ │ │ │ + * Method: getZoom │ │ │ │ + * Convert map zoom to WW zoom. │ │ │ │ + */ │ │ │ │ + getZoom: function() { │ │ │ │ + var zoom = this.map.getZoom(); │ │ │ │ + var extent = this.map.getMaxExtent(); │ │ │ │ + zoom = zoom - Math.log(this.maxResolution / (this.lzd / 512)) / Math.log(2); │ │ │ │ + return zoom; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // OpenLayers currently stores no Name, Title, Abstract, │ │ │ │ - // FeatureTypeName, or SemanticTypeIdentifier information │ │ │ │ - // related to FeatureTypeStyle │ │ │ │ + /** │ │ │ │ + * 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) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var zoom = this.getZoom(); │ │ │ │ + var extent = this.map.getMaxExtent(); │ │ │ │ + var deg = this.lzd / Math.pow(2, this.getZoom()); │ │ │ │ + var x = Math.floor((bounds.left - extent.left) / deg); │ │ │ │ + var y = Math.floor((bounds.bottom - extent.bottom) / deg); │ │ │ │ + if (this.map.getResolution() <= (this.lzd / 512) && │ │ │ │ + this.getZoom() <= this.zoomLevels) { │ │ │ │ + return this.getFullRequestString({ │ │ │ │ + L: zoom, │ │ │ │ + X: x, │ │ │ │ + Y: y │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + return OpenLayers.Util.getImageLocation("blank.gif"); │ │ │ │ + } │ │ │ │ │ │ │ │ - // add in rules │ │ │ │ - for (var i = 0, len = style.rules.length; i < len; ++i) { │ │ │ │ - this.writeNode("Rule", style.rules[i], node); │ │ │ │ - } │ │ │ │ + }, │ │ │ │ │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Rule": function(rule) { │ │ │ │ - var node = this.createElementNSPlus("sld:Rule"); │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.WorldWind" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Layer/PointTrack.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - // add in optional name │ │ │ │ - if (rule.name) { │ │ │ │ - this.writeNode("Name", rule.name, node); │ │ │ │ - } │ │ │ │ - // add in optional title │ │ │ │ - if (rule.title) { │ │ │ │ - this.writeNode("Title", rule.title, node); │ │ │ │ - } │ │ │ │ - // add in optional description │ │ │ │ - if (rule.description) { │ │ │ │ - this.writeNode("Abstract", rule.description, node); │ │ │ │ - } │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - // add in LegendGraphic here │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Layer/Vector.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - // add in optional filters │ │ │ │ - if (rule.elseFilter) { │ │ │ │ - this.writeNode("ElseFilter", null, node); │ │ │ │ - } else if (rule.filter) { │ │ │ │ - this.writeNode("ogc:Filter", rule.filter, node); │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Layer.PointTrack │ │ │ │ + * Vector layer to display ordered point features as a line, creating one │ │ │ │ + * LineString feature for each pair of two points. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Layer.Vector> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.PointTrack = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ │ │ │ │ - // add in scale limits │ │ │ │ - if (rule.minScaleDenominator != undefined) { │ │ │ │ - this.writeNode( │ │ │ │ - "MinScaleDenominator", rule.minScaleDenominator, node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (rule.maxScaleDenominator != undefined) { │ │ │ │ - this.writeNode( │ │ │ │ - "MaxScaleDenominator", rule.maxScaleDenominator, node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: dataFrom │ │ │ │ + * {<OpenLayers.Layer.PointTrack.TARGET_NODE>} or │ │ │ │ + * {<OpenLayers.Layer.PointTrack.SOURCE_NODE>} optional. If the lines │ │ │ │ + * should get the data/attributes from one of the two points it is │ │ │ │ + * composed of, which one should it be? │ │ │ │ + */ │ │ │ │ + dataFrom: null, │ │ │ │ │ │ │ │ - var type, symbolizer; │ │ │ │ - if (this.multipleSymbolizers && rule.symbolizers) { │ │ │ │ - var symbolizer; │ │ │ │ - for (var i = 0, ii = rule.symbolizers.length; i < ii; ++i) { │ │ │ │ - symbolizer = rule.symbolizers[i]; │ │ │ │ - type = symbolizer.CLASS_NAME.split(".").pop(); │ │ │ │ - this.writeNode( │ │ │ │ - type + "Symbolizer", symbolizer, node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - // add in symbolizers (relies on geometry type keys) │ │ │ │ - var types = OpenLayers.Style.SYMBOLIZER_PREFIXES; │ │ │ │ - for (var i = 0, len = types.length; i < len; ++i) { │ │ │ │ - type = types[i]; │ │ │ │ - symbolizer = rule.symbolizer[type]; │ │ │ │ - if (symbolizer) { │ │ │ │ - this.writeNode( │ │ │ │ - type + "Symbolizer", symbolizer, node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ + /** │ │ │ │ + * APIProperty: styleFrom │ │ │ │ + * {<OpenLayers.Layer.PointTrack.TARGET_NODE>} or │ │ │ │ + * {<OpenLayers.Layer.PointTrack.SOURCE_NODE>} optional. If the lines │ │ │ │ + * should get the style from one of the two points it is composed of, │ │ │ │ + * which one should it be? │ │ │ │ + */ │ │ │ │ + styleFrom: null, │ │ │ │ │ │ │ │ - }, │ │ │ │ - "ElseFilter": function() { │ │ │ │ - return this.createElementNSPlus("sld:ElseFilter"); │ │ │ │ - }, │ │ │ │ - "MinScaleDenominator": function(scale) { │ │ │ │ - return this.createElementNSPlus( │ │ │ │ - "sld:MinScaleDenominator", { │ │ │ │ - value: scale │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "MaxScaleDenominator": function(scale) { │ │ │ │ - return this.createElementNSPlus( │ │ │ │ - "sld:MaxScaleDenominator", { │ │ │ │ - value: scale │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "LineSymbolizer": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:LineSymbolizer"); │ │ │ │ - this.writeNode("Stroke", symbolizer, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Stroke": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:Stroke"); │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.PointTrack │ │ │ │ + * Constructor for a new OpenLayers.PointTrack instance. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * name - {String} name of the layer │ │ │ │ + * options - {Object} Optional object with properties to tag onto the │ │ │ │ + * instance. │ │ │ │ + */ │ │ │ │ │ │ │ │ - // GraphicFill here │ │ │ │ - // GraphicStroke here │ │ │ │ + /** │ │ │ │ + * APIMethod: addNodes │ │ │ │ + * Adds point features that will be used to create lines from, using point │ │ │ │ + * pairs. The first point of a pair will be the source node, the second │ │ │ │ + * will be the target node. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * pointFeatures - {Array(<OpenLayers.Feature>)} │ │ │ │ + * options - {Object} │ │ │ │ + * │ │ │ │ + * Supported options: │ │ │ │ + * silent - {Boolean} true to suppress (before)feature(s)added events │ │ │ │ + */ │ │ │ │ + addNodes: function(pointFeatures, options) { │ │ │ │ + if (pointFeatures.length < 2) { │ │ │ │ + throw new Error("At least two point features have to be added to " + │ │ │ │ + "create a line from"); │ │ │ │ + } │ │ │ │ │ │ │ │ - // add in CssParameters │ │ │ │ - if (symbolizer.strokeColor != undefined) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "strokeColor" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.strokeOpacity != undefined) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "strokeOpacity" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.strokeWidth != undefined) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "strokeWidth" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.strokeDashstyle != undefined && symbolizer.strokeDashstyle !== "solid") { │ │ │ │ - // assumes valid stroke-dasharray value │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "strokeDashstyle" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.strokeLinecap != undefined) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "strokeLinecap" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "CssParameter": function(obj) { │ │ │ │ - // not handling ogc:expressions for now │ │ │ │ - return this.createElementNSPlus("sld:CssParameter", { │ │ │ │ - attributes: { │ │ │ │ - name: this.getCssProperty(obj.key) │ │ │ │ - }, │ │ │ │ - value: obj.symbolizer[obj.key] │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "TextSymbolizer": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:TextSymbolizer"); │ │ │ │ - // add in optional Label │ │ │ │ - if (symbolizer.label != null) { │ │ │ │ - this.writeNode("Label", symbolizer.label, node); │ │ │ │ - } │ │ │ │ - // add in optional Font │ │ │ │ - if (symbolizer.fontFamily != null || │ │ │ │ - symbolizer.fontSize != null || │ │ │ │ - symbolizer.fontWeight != null || │ │ │ │ - symbolizer.fontStyle != null) { │ │ │ │ - this.writeNode("Font", symbolizer, node); │ │ │ │ - } │ │ │ │ - // add in optional LabelPlacement │ │ │ │ - if (symbolizer.labelAnchorPointX != null || │ │ │ │ - symbolizer.labelAnchorPointY != null || │ │ │ │ - symbolizer.labelAlign != null || │ │ │ │ - symbolizer.labelXOffset != null || │ │ │ │ - symbolizer.labelYOffset != null || │ │ │ │ - symbolizer.labelRotation != null || │ │ │ │ - symbolizer.labelPerpendicularOffset != null) { │ │ │ │ - this.writeNode("LabelPlacement", symbolizer, node); │ │ │ │ - } │ │ │ │ - // add in optional Halo │ │ │ │ - if (symbolizer.haloRadius != null || │ │ │ │ - symbolizer.haloColor != null || │ │ │ │ - symbolizer.haloOpacity != null) { │ │ │ │ - this.writeNode("Halo", symbolizer, node); │ │ │ │ - } │ │ │ │ - // add in optional Fill │ │ │ │ - if (symbolizer.fontColor != null || │ │ │ │ - symbolizer.fontOpacity != null) { │ │ │ │ - this.writeNode("Fill", { │ │ │ │ - fillColor: symbolizer.fontColor, │ │ │ │ - fillOpacity: symbolizer.fontOpacity │ │ │ │ - }, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "LabelPlacement": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:LabelPlacement"); │ │ │ │ - // PointPlacement and LinePlacement are choices, so don't output both │ │ │ │ - if ((symbolizer.labelAnchorPointX != null || │ │ │ │ - symbolizer.labelAnchorPointY != null || │ │ │ │ - symbolizer.labelAlign != null || │ │ │ │ - symbolizer.labelXOffset != null || │ │ │ │ - symbolizer.labelYOffset != null || │ │ │ │ - symbolizer.labelRotation != null) && │ │ │ │ - symbolizer.labelPerpendicularOffset == null) { │ │ │ │ - this.writeNode("PointPlacement", symbolizer, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.labelPerpendicularOffset != null) { │ │ │ │ - this.writeNode("LinePlacement", symbolizer, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "LinePlacement": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:LinePlacement"); │ │ │ │ - this.writeNode("PerpendicularOffset", symbolizer.labelPerpendicularOffset, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "PerpendicularOffset": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:PerpendicularOffset", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "PointPlacement": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:PointPlacement"); │ │ │ │ - if (symbolizer.labelAnchorPointX != null || │ │ │ │ - symbolizer.labelAnchorPointY != null || │ │ │ │ - symbolizer.labelAlign != null) { │ │ │ │ - this.writeNode("AnchorPoint", symbolizer, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.labelXOffset != null || │ │ │ │ - symbolizer.labelYOffset != null) { │ │ │ │ - this.writeNode("Displacement", symbolizer, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.labelRotation != null) { │ │ │ │ - this.writeNode("Rotation", symbolizer.labelRotation, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "AnchorPoint": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:AnchorPoint"); │ │ │ │ - var x = symbolizer.labelAnchorPointX, │ │ │ │ - y = symbolizer.labelAnchorPointY; │ │ │ │ - if (x != null) { │ │ │ │ - this.writeNode("AnchorPointX", x, node); │ │ │ │ - } │ │ │ │ - if (y != null) { │ │ │ │ - this.writeNode("AnchorPointY", y, node); │ │ │ │ - } │ │ │ │ - if (x == null && y == null) { │ │ │ │ - var xAlign = symbolizer.labelAlign.substr(0, 1), │ │ │ │ - yAlign = symbolizer.labelAlign.substr(1, 1); │ │ │ │ - if (xAlign === "l") { │ │ │ │ - x = 0; │ │ │ │ - } else if (xAlign === "c") { │ │ │ │ - x = 0.5; │ │ │ │ - } else if (xAlign === "r") { │ │ │ │ - x = 1; │ │ │ │ - } │ │ │ │ - if (yAlign === "b") { │ │ │ │ - y = 0; │ │ │ │ - } else if (yAlign === "m") { │ │ │ │ - y = 0.5; │ │ │ │ - } else if (yAlign === "t") { │ │ │ │ - y = 1; │ │ │ │ - } │ │ │ │ - this.writeNode("AnchorPointX", x, node); │ │ │ │ - this.writeNode("AnchorPointY", y, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "AnchorPointX": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:AnchorPointX", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "AnchorPointY": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:AnchorPointY", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Displacement": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:Displacement"); │ │ │ │ - if (symbolizer.labelXOffset != null) { │ │ │ │ - this.writeNode("DisplacementX", symbolizer.labelXOffset, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.labelYOffset != null) { │ │ │ │ - this.writeNode("DisplacementY", symbolizer.labelYOffset, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "DisplacementX": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:DisplacementX", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "DisplacementY": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:DisplacementY", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Font": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:Font"); │ │ │ │ - // add in CssParameters │ │ │ │ - if (symbolizer.fontFamily) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "fontFamily" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.fontSize) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "fontSize" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.fontWeight) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "fontWeight" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.fontStyle) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "fontStyle" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Label": function(label) { │ │ │ │ - return this.writers.sld._OGCExpression.call( │ │ │ │ - this, "sld:Label", label │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "Halo": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:Halo"); │ │ │ │ - if (symbolizer.haloRadius) { │ │ │ │ - this.writeNode("Radius", symbolizer.haloRadius, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.haloColor || symbolizer.haloOpacity) { │ │ │ │ - this.writeNode("Fill", { │ │ │ │ - fillColor: symbolizer.haloColor, │ │ │ │ - fillOpacity: symbolizer.haloOpacity │ │ │ │ - }, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Radius": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:Radius", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "RasterSymbolizer": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:RasterSymbolizer"); │ │ │ │ - if (symbolizer.geometry) { │ │ │ │ - this.writeNode("Geometry", symbolizer.geometry, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.opacity) { │ │ │ │ - this.writeNode("Opacity", symbolizer.opacity, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.colorMap) { │ │ │ │ - this.writeNode("ColorMap", symbolizer.colorMap, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Geometry": function(geometry) { │ │ │ │ - var node = this.createElementNSPlus("sld:Geometry"); │ │ │ │ - if (geometry.property) { │ │ │ │ - this.writeNode("ogc:PropertyName", geometry, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ColorMap": function(colorMap) { │ │ │ │ - var node = this.createElementNSPlus("sld:ColorMap"); │ │ │ │ - for (var i = 0, len = colorMap.length; i < len; ++i) { │ │ │ │ - this.writeNode("ColorMapEntry", colorMap[i], node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ColorMapEntry": function(colorMapEntry) { │ │ │ │ - var node = this.createElementNSPlus("sld:ColorMapEntry"); │ │ │ │ - var a = colorMapEntry; │ │ │ │ - node.setAttribute("color", a.color); │ │ │ │ - a.opacity !== undefined && node.setAttribute("opacity", │ │ │ │ - parseFloat(a.opacity)); │ │ │ │ - a.quantity !== undefined && node.setAttribute("quantity", │ │ │ │ - parseFloat(a.quantity)); │ │ │ │ - a.label !== undefined && node.setAttribute("label", a.label); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "PolygonSymbolizer": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:PolygonSymbolizer"); │ │ │ │ - if (symbolizer.fill !== false) { │ │ │ │ - this.writeNode("Fill", symbolizer, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.stroke !== false) { │ │ │ │ - this.writeNode("Stroke", symbolizer, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Fill": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:Fill"); │ │ │ │ + var lines = new Array(pointFeatures.length - 1); │ │ │ │ │ │ │ │ - // GraphicFill here │ │ │ │ + var pointFeature, startPoint, endPoint; │ │ │ │ + for (var i = 0, len = pointFeatures.length; i < len; i++) { │ │ │ │ + pointFeature = pointFeatures[i]; │ │ │ │ + endPoint = pointFeature.geometry; │ │ │ │ │ │ │ │ - // add in CssParameters │ │ │ │ - if (symbolizer.fillColor) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "fillColor" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (symbolizer.fillOpacity != null) { │ │ │ │ - this.writeNode( │ │ │ │ - "CssParameter", { │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - key: "fillOpacity" │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "PointSymbolizer": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:PointSymbolizer"); │ │ │ │ - this.writeNode("Graphic", symbolizer, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Graphic": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:Graphic"); │ │ │ │ - if (symbolizer.externalGraphic != undefined) { │ │ │ │ - this.writeNode("ExternalGraphic", symbolizer, node); │ │ │ │ - } else { │ │ │ │ - this.writeNode("Mark", symbolizer, node); │ │ │ │ - } │ │ │ │ + if (!endPoint) { │ │ │ │ + var lonlat = pointFeature.lonlat; │ │ │ │ + endPoint = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat); │ │ │ │ + } else if (endPoint.CLASS_NAME != "OpenLayers.Geometry.Point") { │ │ │ │ + throw new TypeError("Only features with point geometries are supported."); │ │ │ │ + } │ │ │ │ │ │ │ │ - if (symbolizer.graphicOpacity != undefined) { │ │ │ │ - this.writeNode("Opacity", symbolizer.graphicOpacity, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.pointRadius != undefined) { │ │ │ │ - this.writeNode("Size", symbolizer.pointRadius * 2, node); │ │ │ │ - } else if (symbolizer.graphicWidth != undefined) { │ │ │ │ - this.writeNode("Size", symbolizer.graphicWidth, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.rotation != undefined) { │ │ │ │ - this.writeNode("Rotation", symbolizer.rotation, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ExternalGraphic": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:ExternalGraphic"); │ │ │ │ - this.writeNode( │ │ │ │ - "OnlineResource", symbolizer.externalGraphic, node │ │ │ │ - ); │ │ │ │ - var format = symbolizer.graphicFormat || │ │ │ │ - this.getGraphicFormat(symbolizer.externalGraphic); │ │ │ │ - this.writeNode("Format", format, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Mark": function(symbolizer) { │ │ │ │ - var node = this.createElementNSPlus("sld:Mark"); │ │ │ │ - if (symbolizer.graphicName) { │ │ │ │ - this.writeNode("WellKnownName", symbolizer.graphicName, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.fill !== false) { │ │ │ │ - this.writeNode("Fill", symbolizer, node); │ │ │ │ - } │ │ │ │ - if (symbolizer.stroke !== false) { │ │ │ │ - this.writeNode("Stroke", symbolizer, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "WellKnownName": function(name) { │ │ │ │ - return this.createElementNSPlus("sld:WellKnownName", { │ │ │ │ - value: name │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Opacity": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:Opacity", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Size": function(value) { │ │ │ │ - return this.writers.sld._OGCExpression.call( │ │ │ │ - this, "sld:Size", value │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - "Rotation": function(value) { │ │ │ │ - return this.createElementNSPlus("sld:Rotation", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "OnlineResource": function(href) { │ │ │ │ - return this.createElementNSPlus("sld:OnlineResource", { │ │ │ │ - attributes: { │ │ │ │ - "xlink:type": "simple", │ │ │ │ - "xlink:href": href │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Format": function(format) { │ │ │ │ - return this.createElementNSPlus("sld:Format", { │ │ │ │ - value: format │ │ │ │ - }); │ │ │ │ + if (i > 0) { │ │ │ │ + var attributes = (this.dataFrom != null) ? │ │ │ │ + (pointFeatures[i + this.dataFrom].data || │ │ │ │ + pointFeatures[i + this.dataFrom].attributes) : │ │ │ │ + null; │ │ │ │ + var style = (this.styleFrom != null) ? │ │ │ │ + (pointFeatures[i + this.styleFrom].style) : │ │ │ │ + null; │ │ │ │ + var line = new OpenLayers.Geometry.LineString([startPoint, │ │ │ │ + endPoint │ │ │ │ + ]); │ │ │ │ + │ │ │ │ + lines[i - 1] = new OpenLayers.Feature.Vector(line, attributes, │ │ │ │ + style); │ │ │ │ } │ │ │ │ + │ │ │ │ + startPoint = endPoint; │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.Filter.v1_0_0.prototype.writers), │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SLD.v1" │ │ │ │ + this.addFeatures(lines, options); │ │ │ │ + }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.PointTrack" │ │ │ │ }); │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Layer.PointTrack.SOURCE_NODE │ │ │ │ + * {Number} value for <OpenLayers.Layer.PointTrack.dataFrom> and │ │ │ │ + * <OpenLayers.Layer.PointTrack.styleFrom> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.PointTrack.SOURCE_NODE = -1; │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Layer.PointTrack.TARGET_NODE │ │ │ │ + * {Number} value for <OpenLayers.Layer.PointTrack.dataFrom> and │ │ │ │ + * <OpenLayers.Layer.PointTrack.styleFrom> │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.PointTrack.TARGET_NODE = 0; │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Layer.PointTrack.dataFrom │ │ │ │ + * {Object} with the following keys - *deprecated* │ │ │ │ + * - SOURCE_NODE: take data/attributes from the source node of the line │ │ │ │ + * - TARGET_NODE: take data/attributes from the target node of the line │ │ │ │ + */ │ │ │ │ +OpenLayers.Layer.PointTrack.dataFrom = { │ │ │ │ + 'SOURCE_NODE': -1, │ │ │ │ + 'TARGET_NODE': 0 │ │ │ │ +}; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/SLD/v1_0_0.js │ │ │ │ + OpenLayers/Layer/Google/v3.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/SLD/v1.js │ │ │ │ - * @requires OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ + * @requires OpenLayers/Layer/Google.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.SLD.v1_0_0 │ │ │ │ - * Write SLD version 1.0.0. │ │ │ │ + * Constant: OpenLayers.Layer.Google.v3 │ │ │ │ * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.SLD.v1> │ │ │ │ + * Mixin providing functionality specific to the Google Maps API v3. │ │ │ │ + * │ │ │ │ + * To use this layer, you must include the GMaps v3 API in your html. │ │ │ │ + * │ │ │ │ + * Note that this layer configures the google.maps.map object with the │ │ │ │ + * "disableDefaultUI" option set to true. Using UI controls that the Google │ │ │ │ + * Maps API provides is not supported by the OpenLayers API. │ │ │ │ */ │ │ │ │ -OpenLayers.Format.SLD.v1_0_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.SLD.v1, { │ │ │ │ +OpenLayers.Layer.Google.v3 = { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: VERSION │ │ │ │ - * {String} 1.0.0 │ │ │ │ - */ │ │ │ │ - VERSION: "1.0.0", │ │ │ │ + /** │ │ │ │ + * Constant: DEFAULTS │ │ │ │ + * {Object} It is not recommended to change the properties set here. Note │ │ │ │ + * that Google.v3 layers only work when sphericalMercator is set to true. │ │ │ │ + * │ │ │ │ + * (code) │ │ │ │ + * { │ │ │ │ + * sphericalMercator: true, │ │ │ │ + * projection: "EPSG:900913" │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ + */ │ │ │ │ + DEFAULTS: { │ │ │ │ + sphericalMercator: true, │ │ │ │ + projection: "EPSG:900913" │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} http://www.opengis.net/sld │ │ │ │ - * http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd │ │ │ │ - */ │ │ │ │ - schemaLocation: "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd", │ │ │ │ + /** │ │ │ │ + * APIProperty: animationEnabled │ │ │ │ + * {Boolean} If set to true, the transition between zoom levels will be │ │ │ │ + * animated (if supported by the GMaps API for the device used). Set to │ │ │ │ + * false to match the zooming experience of other layer types. Default │ │ │ │ + * is true. Note that the GMaps API does not give us control over zoom │ │ │ │ + * animation, so if set to false, when zooming, this will make the │ │ │ │ + * layer temporarily invisible, wait until GMaps reports the map being │ │ │ │ + * idle, and make it visible again. The result will be a blank layer │ │ │ │ + * for a few moments while zooming. │ │ │ │ + */ │ │ │ │ + animationEnabled: true, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.SLD.v1_0_0 │ │ │ │ - * Instances of this class are not created directly. Use the │ │ │ │ - * <OpenLayers.Format.SLD> constructor instead. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ + /** │ │ │ │ + * Method: loadMapObject │ │ │ │ + * Load the GMap and register appropriate event listeners. │ │ │ │ + */ │ │ │ │ + loadMapObject: function() { │ │ │ │ + if (!this.type) { │ │ │ │ + this.type = google.maps.MapTypeId.ROADMAP; │ │ │ │ + } │ │ │ │ + var mapObject; │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + // there are already Google layers added to this map │ │ │ │ + mapObject = cache.mapObject; │ │ │ │ + // increment the layer count │ │ │ │ + ++cache.count; │ │ │ │ + } else { │ │ │ │ + // this is the first Google layer for this map │ │ │ │ + // create GMap │ │ │ │ + var center = this.map.getCenter(); │ │ │ │ + var container = document.createElement('div'); │ │ │ │ + container.className = "olForeignContainer"; │ │ │ │ + container.style.width = '100%'; │ │ │ │ + container.style.height = '100%'; │ │ │ │ + mapObject = new google.maps.Map(container, { │ │ │ │ + center: center ? │ │ │ │ + new google.maps.LatLng(center.lat, center.lon) : new google.maps.LatLng(0, 0), │ │ │ │ + zoom: this.map.getZoom() || 0, │ │ │ │ + mapTypeId: this.type, │ │ │ │ + disableDefaultUI: true, │ │ │ │ + keyboardShortcuts: false, │ │ │ │ + draggable: false, │ │ │ │ + disableDoubleClickZoom: true, │ │ │ │ + scrollwheel: false, │ │ │ │ + streetViewControl: false │ │ │ │ + }); │ │ │ │ + var googleControl = document.createElement('div'); │ │ │ │ + googleControl.style.width = '100%'; │ │ │ │ + googleControl.style.height = '100%'; │ │ │ │ + mapObject.controls[google.maps.ControlPosition.TOP_LEFT].push(googleControl); │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0" │ │ │ │ + // cache elements for use by any other google layers added to │ │ │ │ + // this same map │ │ │ │ + cache = { │ │ │ │ + googleControl: googleControl, │ │ │ │ + mapObject: mapObject, │ │ │ │ + count: 1 │ │ │ │ + }; │ │ │ │ + OpenLayers.Layer.Google.cache[this.map.id] = cache; │ │ │ │ + } │ │ │ │ + this.mapObject = mapObject; │ │ │ │ + this.setGMapVisibility(this.visibility); │ │ │ │ + }, │ │ │ │ │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * APIMethod: onMapResize │ │ │ │ + */ │ │ │ │ + onMapResize: function() { │ │ │ │ + if (this.visibility) { │ │ │ │ + google.maps.event.trigger(this.mapObject, "resize"); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setGMapVisibility │ │ │ │ + * Display the GMap container and associated elements. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * visible - {Boolean} Display the GMap elements. │ │ │ │ + */ │ │ │ │ + setGMapVisibility: function(visible) { │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + var map = this.map; │ │ │ │ + if (cache) { │ │ │ │ + var type = this.type; │ │ │ │ + var layers = map.layers; │ │ │ │ + var layer; │ │ │ │ + for (var i = layers.length - 1; i >= 0; --i) { │ │ │ │ + layer = layers[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.Google && │ │ │ │ + layer.visibility === true && layer.inRange === true) { │ │ │ │ + type = layer.type; │ │ │ │ + visible = true; │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var container = this.mapObject.getDiv(); │ │ │ │ + if (visible === true) { │ │ │ │ + if (container.parentNode !== map.div) { │ │ │ │ + if (!cache.rendered) { │ │ │ │ + var me = this; │ │ │ │ + google.maps.event.addListenerOnce(this.mapObject, 'tilesloaded', function() { │ │ │ │ + cache.rendered = true; │ │ │ │ + me.setGMapVisibility(me.getVisibility()); │ │ │ │ + me.moveTo(me.map.getCenter()); │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + map.div.appendChild(container); │ │ │ │ + cache.googleControl.appendChild(map.viewPortDiv); │ │ │ │ + google.maps.event.trigger(this.mapObject, 'resize'); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.mapObject.setMapTypeId(type); │ │ │ │ + } else if (cache.googleControl.hasChildNodes()) { │ │ │ │ + map.div.appendChild(map.viewPortDiv); │ │ │ │ + map.div.removeChild(container); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getMapContainer │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} the GMap container's div │ │ │ │ + */ │ │ │ │ + getMapContainer: function() { │ │ │ │ + return this.mapObject.getDiv(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + // │ │ │ │ + // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds │ │ │ │ + // │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectBoundsFromOLBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * olBounds - {<OpenLayers.Bounds>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} A MapObject Bounds, translated from olBounds │ │ │ │ + * Returns null if null value is passed in │ │ │ │ + */ │ │ │ │ + getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ + var moBounds = null; │ │ │ │ + if (olBounds != null) { │ │ │ │ + var sw = this.sphericalMercator ? │ │ │ │ + this.inverseMercator(olBounds.bottom, olBounds.left) : │ │ │ │ + new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ + var ne = this.sphericalMercator ? │ │ │ │ + this.inverseMercator(olBounds.top, olBounds.right) : │ │ │ │ + new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ + moBounds = new google.maps.LatLngBounds( │ │ │ │ + new google.maps.LatLng(sw.lat, sw.lon), │ │ │ │ + new google.maps.LatLng(ne.lat, ne.lon) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return moBounds; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Interface Controls * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ + │ │ │ │ + │ │ │ │ + // LonLat - Pixel Translation │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectLonLatFromMapObjectPixel │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moPixel - {Object} MapObject Pixel format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject LonLat translated from MapObject Pixel │ │ │ │ + */ │ │ │ │ + getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ + var size = this.map.getSize(); │ │ │ │ + var lon = this.getLongitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ + var lat = this.getLatitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ + │ │ │ │ + var delta_x = moPixel.x - (size.w / 2); │ │ │ │ + var delta_y = moPixel.y - (size.h / 2); │ │ │ │ + │ │ │ │ + var lonlat = new OpenLayers.LonLat( │ │ │ │ + lon + delta_x * res, │ │ │ │ + lat - delta_y * res │ │ │ │ + ); │ │ │ │ + │ │ │ │ + if (this.wrapDateLine) { │ │ │ │ + lonlat = lonlat.wrapDateLine(this.maxExtent); │ │ │ │ + } │ │ │ │ + return this.getMapObjectLonLatFromLonLat(lonlat.lon, lonlat.lat); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectPixelFromMapObjectLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moLonLat - {Object} MapObject LonLat format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Pixel transtlated from MapObject LonLat │ │ │ │ + */ │ │ │ │ + getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); │ │ │ │ + var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ + var extent = this.map.getExtent(); │ │ │ │ + return this.getMapObjectPixelFromXY((1 / res * (lon - extent.left)), │ │ │ │ + (1 / res * (extent.top - lat))); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setMapObjectCenter │ │ │ │ + * Set the mapObject to the specified center and zoom │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * center - {Object} MapObject LonLat format │ │ │ │ + * zoom - {int} MapObject zoom format │ │ │ │ + */ │ │ │ │ + setMapObjectCenter: function(center, zoom) { │ │ │ │ + if (this.animationEnabled === false && zoom != this.mapObject.zoom) { │ │ │ │ + var mapContainer = this.getMapContainer(); │ │ │ │ + google.maps.event.addListenerOnce( │ │ │ │ + this.mapObject, │ │ │ │ + "idle", │ │ │ │ + function() { │ │ │ │ + mapContainer.style.visibility = ""; │ │ │ │ + } │ │ │ │ + ); │ │ │ │ + mapContainer.style.visibility = "hidden"; │ │ │ │ + } │ │ │ │ + this.mapObject.setOptions({ │ │ │ │ + center: center, │ │ │ │ + zoom: zoom │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + // Bounds │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectZoomFromMapObjectBounds │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * moBounds - {Object} MapObject Bounds format │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Zoom for specified MapObject Bounds │ │ │ │ + */ │ │ │ │ + getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ + return this.mapObject.getBoundsZoomLevel(moBounds); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /************************************ │ │ │ │ + * * │ │ │ │ + * MapObject Primitives * │ │ │ │ + * * │ │ │ │ + ************************************/ │ │ │ │ + │ │ │ │ + │ │ │ │ + // LonLat │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectLonLatFromLonLat │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * lon - {Float} │ │ │ │ + * lat - {Float} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject LonLat built from lon and lat params │ │ │ │ + */ │ │ │ │ + getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ + var gLatLng; │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + var lonlat = this.inverseMercator(lon, lat); │ │ │ │ + gLatLng = new google.maps.LatLng(lonlat.lat, lonlat.lon); │ │ │ │ + } else { │ │ │ │ + gLatLng = new google.maps.LatLng(lat, lon); │ │ │ │ + } │ │ │ │ + return gLatLng; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + // Pixel │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: getMapObjectPixelFromXY │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * x - {Integer} │ │ │ │ + * y - {Integer} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} MapObject Pixel from x and y parameters │ │ │ │ + */ │ │ │ │ + getMapObjectPixelFromXY: function(x, y) { │ │ │ │ + return new google.maps.Point(x, y); │ │ │ │ + } │ │ │ │ + │ │ │ │ +}; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/SLDSelect.js │ │ │ │ + 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/Control.js │ │ │ │ - * @requires OpenLayers/Layer/WMS.js │ │ │ │ - * @requires OpenLayers/Handler/RegularPolygon.js │ │ │ │ - * @requires OpenLayers/Handler/Polygon.js │ │ │ │ - * @requires OpenLayers/Handler/Path.js │ │ │ │ - * @requires OpenLayers/Handler/Click.js │ │ │ │ - * @requires OpenLayers/Filter/Spatial.js │ │ │ │ - * @requires OpenLayers/Format/SLD/v1_0_0.js │ │ │ │ + * @requires OpenLayers/Layer/Vector.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.SLDSelect │ │ │ │ - * Perform selections on WMS layers using Styled Layer Descriptor (SLD) │ │ │ │ + * 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.Control> │ │ │ │ + * - <OpenLayers.Layer.Vector> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.SLDSelect = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: events │ │ │ │ - * {<OpenLayers.Events>} Events instance for listeners and triggering │ │ │ │ - * control specific events. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Register a listener for a particular event with the following syntax: │ │ │ │ - * (code) │ │ │ │ - * control.events.register(type, obj, listener); │ │ │ │ - * (end) │ │ │ │ + * 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 │ │ │ │ * │ │ │ │ - * Supported event types (in addition to those from <OpenLayers.Control.events>): │ │ │ │ - * selected - Triggered when a selection occurs. Listeners receive an │ │ │ │ - * event with *filters* and *layer* properties. Filters will be an │ │ │ │ - * array of OpenLayers.Filter objects created in order to perform │ │ │ │ - * the particular selection. │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.Vector.RootContainer>} A new vector layer root │ │ │ │ + * container │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: clearOnDeactivate │ │ │ │ - * {Boolean} Should the selection be cleared when the control is │ │ │ │ - * deactivated. Default value is false. │ │ │ │ + * Method: display │ │ │ │ */ │ │ │ │ - clearOnDeactivate: false, │ │ │ │ + display: function() {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layers │ │ │ │ - * {Array(<OpenLayers.Layer.WMS>)} The WMS layers this control will work │ │ │ │ - * on. │ │ │ │ + * 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>} │ │ │ │ */ │ │ │ │ - layers: null, │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: callbacks │ │ │ │ - * {Object} The functions that are sent to the handler for callback │ │ │ │ + * Method: setMap │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - callbacks: null, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ + this.collectRoots(); │ │ │ │ + map.events.register("changelayer", this, this.handleChangeLayer); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: selectionSymbolizer │ │ │ │ - * {Object} Determines the styling of the selected objects. Default is │ │ │ │ - * a selection in red. │ │ │ │ + * Method: removeMap │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - selectionSymbolizer: { │ │ │ │ - 'Polygon': { │ │ │ │ - fillColor: '#FF0000', │ │ │ │ - stroke: false │ │ │ │ - }, │ │ │ │ - 'Line': { │ │ │ │ - strokeColor: '#FF0000', │ │ │ │ - strokeWidth: 2 │ │ │ │ - }, │ │ │ │ - 'Point': { │ │ │ │ - graphicName: 'square', │ │ │ │ - fillColor: '#FF0000', │ │ │ │ - pointRadius: 5 │ │ │ │ - } │ │ │ │ + removeMap: function(map) { │ │ │ │ + map.events.unregister("changelayer", this, this.handleChangeLayer); │ │ │ │ + this.resetRoots(); │ │ │ │ + OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layerOptions │ │ │ │ - * {Object} The options to apply to the selection layer, by default the │ │ │ │ - * selection layer will be kept out of the layer switcher. │ │ │ │ + * Method: collectRoots │ │ │ │ + * Collects the root nodes of all layers this control is configured with │ │ │ │ + * and moveswien the nodes to this control's layer │ │ │ │ */ │ │ │ │ - layerOptions: null, │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: handlerOptions │ │ │ │ - * {Object} Used to set non-default properties on the control's handler │ │ │ │ + * 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: sketchStyle │ │ │ │ - * {<OpenLayers.Style>|Object} Style or symbolizer to use for the sketch │ │ │ │ - * handler. The recommended way of styling the sketch layer, however, is │ │ │ │ - * to configure an <OpenLayers.StyleMap> in the layerOptions of the │ │ │ │ - * <handlerOptions>: │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * (code) │ │ │ │ - * new OpenLayers.Control.SLDSelect(OpenLayers.Handler.Path, { │ │ │ │ - * handlerOptions: { │ │ │ │ - * layerOptions: { │ │ │ │ - * styleMap: new OpenLayers.StyleMap({ │ │ │ │ - * "default": {strokeColor: "yellow"} │ │ │ │ - * }) │ │ │ │ - * } │ │ │ │ - * } │ │ │ │ - * }); │ │ │ │ - * (end) │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Object} │ │ │ │ */ │ │ │ │ - sketchStyle: null, │ │ │ │ + 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/Protocol/SOS.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 │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Function: OpenLayers.Protocol.SOS │ │ │ │ + * Used to create a versioned SOS protocol. Default version is 1.0.0. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Protocol>} An SOS protocol for the given version. │ │ │ │ + */ │ │ │ │ +OpenLayers.Protocol.SOS = function(options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults( │ │ │ │ + options, OpenLayers.Protocol.SOS.DEFAULTS │ │ │ │ + ); │ │ │ │ + var cls = OpenLayers.Protocol.SOS["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (!cls) { │ │ │ │ + throw "Unsupported SOS version: " + options.version; │ │ │ │ + } │ │ │ │ + return new cls(options); │ │ │ │ +}; │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Protocol.SOS.DEFAULTS │ │ │ │ + */ │ │ │ │ +OpenLayers.Protocol.SOS.DEFAULTS = { │ │ │ │ + "version": "1.0.0" │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + 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, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: wfsCache │ │ │ │ - * {Object} Cache to use for storing parsed results from │ │ │ │ - * <OpenLayers.Format.WFSDescribeFeatureType.read>. If not provided, │ │ │ │ - * these will be cached on the prototype. │ │ │ │ + * Property: url │ │ │ │ + * {String} Service URL, read-only, set through the options │ │ │ │ + * passed to constructor. │ │ │ │ */ │ │ │ │ - wfsCache: {}, │ │ │ │ + url: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layerCache │ │ │ │ - * {Object} Cache to use for storing references to the selection layers. │ │ │ │ - * Normally each source layer will have exactly 1 selection layer of │ │ │ │ - * type OpenLayers.Layer.WMS. If not provided, layers will │ │ │ │ - * be cached on the prototype. Note that if <clearOnDeactivate> is │ │ │ │ - * true, the layer will no longer be cached after deactivating the │ │ │ │ - * control. │ │ │ │ + * Property: headers │ │ │ │ + * {Object} HTTP request headers, read-only, set through the options │ │ │ │ + * passed to the constructor, │ │ │ │ + * Example: {'Content-Type': 'plain/text'} │ │ │ │ */ │ │ │ │ - layerCache: {}, │ │ │ │ + headers: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.SLDSelect │ │ │ │ - * Create a new control for selecting features in WMS layers using │ │ │ │ - * Styled Layer Descriptor (SLD). │ │ │ │ + * 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: │ │ │ │ - * handler - {<OpenLayers.Class>} A sketch handler class. This determines │ │ │ │ - * the type of selection, e.g. box (<OpenLayers.Handler.Box>), point │ │ │ │ - * (<OpenLayers.Handler.Point>), path (<OpenLayers.Handler.Path>) or │ │ │ │ - * polygon (<OpenLayers.Handler.Polygon>) selection. To use circle │ │ │ │ - * type selection, use <OpenLayers.Handler.RegularPolygon> and pass │ │ │ │ - * the number of desired sides (e.g. 40) as "sides" property to the │ │ │ │ - * <handlerOptions>. │ │ │ │ - * options - {Object} An object containing all configuration properties for │ │ │ │ - * the control. │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ * │ │ │ │ - * Valid options: │ │ │ │ - * layers - Array({<OpenLayers.Layer.WMS>}) The layers to perform the │ │ │ │ - * selection on. │ │ │ │ + * Valid options include: │ │ │ │ + * url - {String} │ │ │ │ + * headers - {Object} │ │ │ │ + * params - {Object} URL parameters for GET requests │ │ │ │ + * format - {<OpenLayers.Format>} │ │ │ │ + * callback - {Function} │ │ │ │ + * scope - {Object} │ │ │ │ */ │ │ │ │ - initialize: function(handler, options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + this.params = {}; │ │ │ │ + this.headers = {}; │ │ │ │ + OpenLayers.Protocol.prototype.initialize.apply(this, arguments); │ │ │ │ │ │ │ │ - this.callbacks = OpenLayers.Util.extend({ │ │ │ │ - done: this.select, │ │ │ │ - click: this.select │ │ │ │ - }, this.callbacks); │ │ │ │ - this.handlerOptions = this.handlerOptions || {}; │ │ │ │ - this.layerOptions = OpenLayers.Util.applyDefaults(this.layerOptions, { │ │ │ │ - displayInLayerSwitcher: false, │ │ │ │ - tileOptions: { │ │ │ │ - maxGetUrlLength: 2048 │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (this.sketchStyle) { │ │ │ │ - this.handlerOptions.layerOptions = OpenLayers.Util.applyDefaults( │ │ │ │ - this.handlerOptions.layerOptions, { │ │ │ │ - styleMap: new OpenLayers.StyleMap({ │ │ │ │ - "default": this.sketchStyle │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - ); │ │ │ │ + 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); │ │ │ │ + }; │ │ │ │ } │ │ │ │ - this.handler = new handler(this, this.callbacks, this.handlerOptions); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: destroy │ │ │ │ - * Take care of things that are not handled in superclass. │ │ │ │ + * Clean up the protocol. │ │ │ │ */ │ │ │ │ destroy: function() { │ │ │ │ - for (var key in this.layerCache) { │ │ │ │ - delete this.layerCache[key]; │ │ │ │ + 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 │ │ │ │ + ); │ │ │ │ } │ │ │ │ - for (var key in this.wfsCache) { │ │ │ │ - delete this.wfsCache[key]; │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ } │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + return resp; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: coupleLayerVisiblity │ │ │ │ - * Couple the selection layer and the source layer with respect to │ │ │ │ - * layer visibility. So if the source layer is turned off, the │ │ │ │ - * selection layer is also turned off. │ │ │ │ + * Method: handleRead │ │ │ │ + * Individual callbacks are created for read, create and update, should │ │ │ │ + * a subclass need to override each one separately. │ │ │ │ * │ │ │ │ - * Context: │ │ │ │ - * - {<OpenLayers.Layer>} │ │ │ │ + * 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: │ │ │ │ - * evt - {Object} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - coupleLayerVisiblity: function(evt) { │ │ │ │ - this.setVisibility(evt.object.getVisibility()); │ │ │ │ + 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: createSelectionLayer │ │ │ │ - * Creates a "clone" from the source layer in which the selection can │ │ │ │ - * be drawn. This ensures both the source layer and the selection are │ │ │ │ - * visible and not only the selection. │ │ │ │ + * Method: handleCreate │ │ │ │ + * Called the the request issued by <create> is complete. May be overridden │ │ │ │ + * by subclasses. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * source - {<OpenLayers.Layer.WMS>} The source layer on which the selection │ │ │ │ - * is performed. │ │ │ │ + * 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.Layer.WMS>} A WMS layer with maxGetUrlLength configured to 2048 │ │ │ │ - * since SLD selections can easily get quite long. │ │ │ │ + * {<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. │ │ │ │ */ │ │ │ │ - createSelectionLayer: function(source) { │ │ │ │ - // check if we already have a selection layer for the source layer │ │ │ │ - var selectionLayer; │ │ │ │ - if (!this.layerCache[source.id]) { │ │ │ │ - selectionLayer = new OpenLayers.Layer.WMS(source.name, │ │ │ │ - source.url, source.params, │ │ │ │ - OpenLayers.Util.applyDefaults( │ │ │ │ - this.layerOptions, │ │ │ │ - source.getOptions()) │ │ │ │ - ); │ │ │ │ - this.layerCache[source.id] = selectionLayer; │ │ │ │ - // make sure the layers are coupled wrt visibility, but only │ │ │ │ - // if they are not displayed in the layer switcher, because in │ │ │ │ - // that case the user cannot control visibility. │ │ │ │ - if (this.layerOptions.displayInLayerSwitcher === false) { │ │ │ │ - source.events.on({ │ │ │ │ - "visibilitychanged": this.coupleLayerVisiblity, │ │ │ │ - scope: selectionLayer │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - this.map.addLayer(selectionLayer); │ │ │ │ - } else { │ │ │ │ - selectionLayer = this.layerCache[source.id]; │ │ │ │ - } │ │ │ │ - return selectionLayer; │ │ │ │ + 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: createSLD │ │ │ │ - * Create the SLD document for the layer using the supplied filters. │ │ │ │ + * Method: handleUpdate │ │ │ │ + * Called the the request issued by <update> is complete. May be overridden │ │ │ │ + * by subclasses. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.WMS>} │ │ │ │ - * filters - Array({<OpenLayers.Filter>}) The filters to be applied. │ │ │ │ - * geometryAttributes - Array({Object}) The geometry attributes of the │ │ │ │ - * layer. │ │ │ │ + * 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: │ │ │ │ - * {String} The SLD document generated as a string. │ │ │ │ + * {<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. │ │ │ │ */ │ │ │ │ - createSLD: function(layer, filters, geometryAttributes) { │ │ │ │ - var sld = { │ │ │ │ - version: "1.0.0", │ │ │ │ - namedLayers: {} │ │ │ │ + "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 │ │ │ │ }; │ │ │ │ - var layerNames = [layer.params.LAYERS].join(",").split(","); │ │ │ │ - for (var i = 0, len = layerNames.length; i < len; i++) { │ │ │ │ - var name = layerNames[i]; │ │ │ │ - sld.namedLayers[name] = { │ │ │ │ - name: name, │ │ │ │ - userStyles: [] │ │ │ │ - }; │ │ │ │ - var symbolizer = this.selectionSymbolizer; │ │ │ │ - var geometryAttribute = geometryAttributes[i]; │ │ │ │ - if (geometryAttribute.type.indexOf('Polygon') >= 0) { │ │ │ │ - symbolizer = { │ │ │ │ - Polygon: this.selectionSymbolizer['Polygon'] │ │ │ │ - }; │ │ │ │ - } else if (geometryAttribute.type.indexOf('LineString') >= 0) { │ │ │ │ - symbolizer = { │ │ │ │ - Line: this.selectionSymbolizer['Line'] │ │ │ │ - }; │ │ │ │ - } else if (geometryAttribute.type.indexOf('Point') >= 0) { │ │ │ │ - symbolizer = { │ │ │ │ - Point: this.selectionSymbolizer['Point'] │ │ │ │ - }; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - var filter = filters[i]; │ │ │ │ - sld.namedLayers[name].userStyles.push({ │ │ │ │ - name: 'default', │ │ │ │ - rules: [ │ │ │ │ - new OpenLayers.Rule({ │ │ │ │ - symbolizer: symbolizer, │ │ │ │ - filter: filter, │ │ │ │ - maxScaleDenominator: layer.options.minScale │ │ │ │ - }) │ │ │ │ - ] │ │ │ │ - }); │ │ │ │ + options.callback.call(options.scope, resp); │ │ │ │ } │ │ │ │ - return new OpenLayers.Format.SLD({ │ │ │ │ - srsName: this.map.getProjection() │ │ │ │ - }).write(sld); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseDescribeLayer │ │ │ │ - * Parse the SLD WMS DescribeLayer response and issue the corresponding │ │ │ │ - * WFS DescribeFeatureType request │ │ │ │ + * Method: parseFeatures │ │ │ │ + * Read HTTP response body and return features. │ │ │ │ * │ │ │ │ - * request - {XMLHttpRequest} The request object. │ │ │ │ + * Parameters: │ │ │ │ + * request - {XMLHttpRequest} The request object │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array({<OpenLayers.Feature.Vector>})} or │ │ │ │ + * {<OpenLayers.Feature.Vector>} Array of features or a single feature. │ │ │ │ */ │ │ │ │ - parseDescribeLayer: function(request) { │ │ │ │ - var format = new OpenLayers.Format.WMSDescribeLayer(); │ │ │ │ + parseFeatures: function(request) { │ │ │ │ var doc = request.responseXML; │ │ │ │ if (!doc || !doc.documentElement) { │ │ │ │ doc = request.responseText; │ │ │ │ } │ │ │ │ - var describeLayer = format.read(doc); │ │ │ │ - var typeNames = []; │ │ │ │ - var url = null; │ │ │ │ - for (var i = 0, len = describeLayer.length; i < len; i++) { │ │ │ │ - // perform a WFS DescribeFeatureType request │ │ │ │ - if (describeLayer[i].owsType == "WFS") { │ │ │ │ - typeNames.push(describeLayer[i].typeName); │ │ │ │ - url = describeLayer[i].owsURL; │ │ │ │ - } │ │ │ │ + if (!doc || doc.length <= 0) { │ │ │ │ + return null; │ │ │ │ } │ │ │ │ - var options = { │ │ │ │ - url: url, │ │ │ │ - params: { │ │ │ │ - SERVICE: "WFS", │ │ │ │ - TYPENAME: typeNames.toString(), │ │ │ │ - REQUEST: "DescribeFeatureType", │ │ │ │ - VERSION: "1.0.0" │ │ │ │ - }, │ │ │ │ - callback: function(request) { │ │ │ │ - var format = new OpenLayers.Format.WFSDescribeFeatureType(); │ │ │ │ - var doc = request.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = request.responseText; │ │ │ │ - } │ │ │ │ - var describeFeatureType = format.read(doc); │ │ │ │ - this.control.wfsCache[this.layer.id] = describeFeatureType; │ │ │ │ - this.control._queue && this.control.applySelection(); │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }; │ │ │ │ - OpenLayers.Request.GET(options); │ │ │ │ + return this.format.read(doc); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getGeometryAttributes │ │ │ │ - * Look up the geometry attributes from the WFS DescribeFeatureType response │ │ │ │ + * APIMethod: commit │ │ │ │ + * Iterate over each feature and take action based on the feature state. │ │ │ │ + * Possible actions are create, update and delete. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.WMS>} The layer for which to look up the │ │ │ │ - * geometry attributes. │ │ │ │ + * 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({Object}) Array of geometry attributes │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - getGeometryAttributes: function(layer) { │ │ │ │ - var result = []; │ │ │ │ - var cache = this.wfsCache[layer.id]; │ │ │ │ - for (var i = 0, len = cache.featureTypes.length; i < len; i++) { │ │ │ │ - var typeName = cache.featureTypes[i]; │ │ │ │ - var properties = typeName.properties; │ │ │ │ - for (var j = 0, lenj = properties.length; j < lenj; j++) { │ │ │ │ - var property = properties[j]; │ │ │ │ - var type = property.type; │ │ │ │ - if ((type.indexOf('LineString') >= 0) || │ │ │ │ - (type.indexOf('GeometryAssociationType') >= 0) || │ │ │ │ - (type.indexOf('GeometryPropertyType') >= 0) || │ │ │ │ - (type.indexOf('Point') >= 0) || │ │ │ │ - (type.indexOf('Polygon') >= 0)) { │ │ │ │ - result.push(property); │ │ │ │ + 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]); │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ - return result; │ │ │ │ + │ │ │ │ + // 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: activate │ │ │ │ - * Activate the control. Activating the control will perform a SLD WMS │ │ │ │ - * DescribeLayer request followed by a WFS DescribeFeatureType request │ │ │ │ - * so that the proper symbolizers can be chosen based on the geometry │ │ │ │ - * type. │ │ │ │ + * 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>} │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ - var layer = this.layers[i]; │ │ │ │ - if (layer && !this.wfsCache[layer.id]) { │ │ │ │ - var options = { │ │ │ │ - url: layer.url, │ │ │ │ - params: { │ │ │ │ - SERVICE: "WMS", │ │ │ │ - VERSION: layer.params.VERSION, │ │ │ │ - LAYERS: layer.params.LAYERS, │ │ │ │ - REQUEST: "DescribeLayer" │ │ │ │ - }, │ │ │ │ - callback: this.parseDescribeLayer, │ │ │ │ - scope: { │ │ │ │ - layer: layer, │ │ │ │ - control: this │ │ │ │ - } │ │ │ │ - }; │ │ │ │ - OpenLayers.Request.GET(options); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + response.priv.abort(); │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the control. If clearOnDeactivate is true, remove the │ │ │ │ - * selection layer(s). │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ - var layer = this.layers[i]; │ │ │ │ - if (layer && this.clearOnDeactivate === true) { │ │ │ │ - var layerCache = this.layerCache; │ │ │ │ - var selectionLayer = layerCache[layer.id]; │ │ │ │ - if (selectionLayer) { │ │ │ │ - layer.events.un({ │ │ │ │ - "visibilitychanged": this.coupleLayerVisiblity, │ │ │ │ - scope: selectionLayer │ │ │ │ - }); │ │ │ │ - selectionLayer.destroy(); │ │ │ │ - delete layerCache[layer.id]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + callUserCallback: function(resp, options) { │ │ │ │ + var opt = options[resp.requestType]; │ │ │ │ + if (opt && opt.callback) { │ │ │ │ + opt.callback.call(opt.scope, resp); │ │ │ │ } │ │ │ │ - return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.HTTP" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Protocol/CSW.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.CSW │ │ │ │ + * Used to create a versioned CSW protocol. Default version is 2.0.2. │ │ │ │ + */ │ │ │ │ +OpenLayers.Protocol.CSW = function(options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults( │ │ │ │ + options, OpenLayers.Protocol.CSW.DEFAULTS │ │ │ │ + ); │ │ │ │ + var cls = OpenLayers.Protocol.CSW["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (!cls) { │ │ │ │ + throw "Unsupported CSW version: " + options.version; │ │ │ │ + } │ │ │ │ + return new cls(options); │ │ │ │ +}; │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: OpenLayers.Protocol.CSW.DEFAULTS │ │ │ │ + */ │ │ │ │ +OpenLayers.Protocol.CSW.DEFAULTS = { │ │ │ │ + "version": "2.0.2" │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Protocol/Script.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/Feature/Vector.js │ │ │ │ + * @requires OpenLayers/Format/GeoJSON.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.Script │ │ │ │ + * A basic Script protocol for vector layers. Create a new instance with the │ │ │ │ + * <OpenLayers.Protocol.Script> constructor. A script protocol is used to │ │ │ │ + * get around the same origin policy. It works with services that return │ │ │ │ + * JSONP - that is, JSON wrapped in a client-specified callback. The │ │ │ │ + * protocol handles fetching and parsing of feature data and sends parsed │ │ │ │ + * features to the <callback> configured with the protocol. The protocol │ │ │ │ + * expects features serialized as GeoJSON by default, but can be configured │ │ │ │ + * to work with other formats by setting the <format> property. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Protocol> │ │ │ │ + */ │ │ │ │ +OpenLayers.Protocol.Script = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * APIMethod: setLayers │ │ │ │ - * Set the layers on which the selection should be performed. Call the │ │ │ │ - * setLayers method if the layer(s) to be used change and the same │ │ │ │ - * control should be used on a new set of layers. │ │ │ │ - * If the control is already active, it will be active after the new │ │ │ │ - * set of layers is set. │ │ │ │ + * APIProperty: url │ │ │ │ + * {String} Service URL. The service is expected to return serialized │ │ │ │ + * features wrapped in a named callback (where the callback name is │ │ │ │ + * generated by this protocol). │ │ │ │ + * Read-only, set through the options passed to the constructor. │ │ │ │ + */ │ │ │ │ + url: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: params │ │ │ │ + * {Object} Query string parameters to be appended to the URL. │ │ │ │ + * Read-only, set through the options passed to the constructor. │ │ │ │ + * Example: {maxFeatures: 50} │ │ │ │ + */ │ │ │ │ + params: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: callback │ │ │ │ + * {Object} Function to be called when the <read> operation completes. │ │ │ │ + */ │ │ │ │ + callback: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: callbackTemplate │ │ │ │ + * {String} Template for creating a unique callback function name │ │ │ │ + * for the registry. Should include ${id}. The ${id} variable will be │ │ │ │ + * replaced with a string identifier prefixed with a "c" (e.g. c1, c2). │ │ │ │ + * Default is "OpenLayers.Protocol.Script.registry.${id}". │ │ │ │ + */ │ │ │ │ + callbackTemplate: "OpenLayers.Protocol.Script.registry.${id}", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: callbackKey │ │ │ │ + * {String} The name of the query string parameter that the service │ │ │ │ + * recognizes as the callback identifier. Default is "callback". │ │ │ │ + * This key is used to generate the URL for the script. For example │ │ │ │ + * setting <callbackKey> to "myCallback" would result in a URL like │ │ │ │ + * http://example.com/?myCallback=... │ │ │ │ + */ │ │ │ │ + callbackKey: "callback", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: callbackPrefix │ │ │ │ + * {String} Where a service requires that the callback query string │ │ │ │ + * parameter value is prefixed by some string, this value may be set. │ │ │ │ + * For example, setting <callbackPrefix> to "foo:" would result in a │ │ │ │ + * URL like http://example.com/?callback=foo:... Default is "". │ │ │ │ + */ │ │ │ │ + callbackPrefix: "", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: scope │ │ │ │ + * {Object} Optional ``this`` object for the callback. Read-only, set │ │ │ │ + * through the options passed to the constructor. │ │ │ │ + */ │ │ │ │ + scope: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: format │ │ │ │ + * {<OpenLayers.Format>} Format for parsing features. Default is an │ │ │ │ + * <OpenLayers.Format.GeoJSON> format. If an alternative is provided, │ │ │ │ + * the format's read method must take an object and return an array │ │ │ │ + * of features. │ │ │ │ + */ │ │ │ │ + format: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: pendingRequests │ │ │ │ + * {Object} References all pending requests. Property names are script │ │ │ │ + * identifiers and property values are script elements. │ │ │ │ + */ │ │ │ │ + pendingRequests: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: srsInBBOX │ │ │ │ + * {Boolean} Include the SRS identifier in BBOX query string parameter. │ │ │ │ + * Setting this property has no effect if a custom filterToParams method │ │ │ │ + * is provided. 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.Script │ │ │ │ + * A class for giving layers generic Script protocol. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * layers - {Array(<OpenLayers.Layer.WMS>)} The new set of layers on which │ │ │ │ - * the selection should be performed. │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ + * │ │ │ │ + * Valid options include: │ │ │ │ + * url - {String} │ │ │ │ + * params - {Object} │ │ │ │ + * callback - {Function} │ │ │ │ + * scope - {Object} │ │ │ │ */ │ │ │ │ - setLayers: function(layers) { │ │ │ │ - if (this.active) { │ │ │ │ - this.deactivate(); │ │ │ │ - this.layers = layers; │ │ │ │ - this.activate(); │ │ │ │ - } else { │ │ │ │ - this.layers = layers; │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + this.params = {}; │ │ │ │ + this.pendingRequests = {}; │ │ │ │ + OpenLayers.Protocol.prototype.initialize.apply(this, arguments); │ │ │ │ + if (!this.format) { │ │ │ │ + this.format = new OpenLayers.Format.GeoJSON(); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (!this.filterToParams && OpenLayers.Format.QueryStringFilter) { │ │ │ │ + var format = new OpenLayers.Format.QueryStringFilter({ │ │ │ │ + srsInBBOX: this.srsInBBOX │ │ │ │ + }); │ │ │ │ + this.filterToParams = function(filter, params) { │ │ │ │ + return format.write(filter, params); │ │ │ │ + }; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Function: createFilter │ │ │ │ - * Create the filter to be used in the SLD. │ │ │ │ + * APIMethod: read │ │ │ │ + * Construct a request for reading new features. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * geometryAttribute - {Object} Used to get the name of the geometry │ │ │ │ - * attribute which is needed for constructing the spatial filter. │ │ │ │ - * geometry - {<OpenLayers.Geometry>} The geometry to use. │ │ │ │ + * 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. │ │ │ │ + * filter - {<OpenLayers.Filter>} Filter to get serialized as a │ │ │ │ + * query string. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Filter.Spatial>} The spatial filter created. │ │ │ │ + * {<OpenLayers.Protocol.Response>} A response object, whose "priv" property │ │ │ │ + * references the injected script. 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. │ │ │ │ */ │ │ │ │ - createFilter: function(geometryAttribute, geometry) { │ │ │ │ - var filter = null; │ │ │ │ - if (this.handler instanceof OpenLayers.Handler.RegularPolygon) { │ │ │ │ - // box │ │ │ │ - if (this.handler.irregular === true) { │ │ │ │ - filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ - property: geometryAttribute.name, │ │ │ │ - value: geometry.getBounds() │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ - property: geometryAttribute.name, │ │ │ │ - value: geometry │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } else if (this.handler instanceof OpenLayers.Handler.Polygon) { │ │ │ │ - filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ - property: geometryAttribute.name, │ │ │ │ - value: geometry │ │ │ │ - }); │ │ │ │ - } else if (this.handler instanceof OpenLayers.Handler.Path) { │ │ │ │ - // if source layer is point based, use DWITHIN instead │ │ │ │ - if (geometryAttribute.type.indexOf('Point') >= 0) { │ │ │ │ - filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.DWITHIN, │ │ │ │ - property: geometryAttribute.name, │ │ │ │ - distance: this.map.getExtent().getWidth() * 0.01, │ │ │ │ - distanceUnits: this.map.getUnits(), │ │ │ │ - value: geometry │ │ │ │ - }); │ │ │ │ + read: function(options) { │ │ │ │ + OpenLayers.Protocol.prototype.read.apply(this, arguments); │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ + options.params = OpenLayers.Util.applyDefaults( │ │ │ │ + options.params, this.options.params │ │ │ │ + ); │ │ │ │ + if (options.filter && this.filterToParams) { │ │ │ │ + options.params = this.filterToParams( │ │ │ │ + options.filter, options.params │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + var response = new OpenLayers.Protocol.Response({ │ │ │ │ + requestType: "read" │ │ │ │ + }); │ │ │ │ + var request = this.createRequest( │ │ │ │ + options.url, │ │ │ │ + options.params, │ │ │ │ + OpenLayers.Function.bind(function(data) { │ │ │ │ + response.data = data; │ │ │ │ + this.handleRead(response, options); │ │ │ │ + }, this) │ │ │ │ + ); │ │ │ │ + response.priv = request; │ │ │ │ + return response; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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, any filter will not be serialized. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * filter - {<OpenLayers.Filter>} filter to convert. │ │ │ │ + * params - {Object} The parameters object. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} The resulting parameters object. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: createRequest │ │ │ │ + * Issues a request for features by creating injecting a script in the │ │ │ │ + * document head. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * url - {String} Service URL. │ │ │ │ + * params - {Object} Query string parameters. │ │ │ │ + * callback - {Function} Callback to be called with resulting data. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {HTMLScriptElement} The script pending execution. │ │ │ │ + */ │ │ │ │ + createRequest: function(url, params, callback) { │ │ │ │ + var id = OpenLayers.Protocol.Script.register(callback); │ │ │ │ + var name = OpenLayers.String.format(this.callbackTemplate, { │ │ │ │ + id: id │ │ │ │ + }); │ │ │ │ + params = OpenLayers.Util.extend({}, params); │ │ │ │ + params[this.callbackKey] = this.callbackPrefix + name; │ │ │ │ + url = OpenLayers.Util.urlAppend( │ │ │ │ + url, OpenLayers.Util.getParameterString(params) │ │ │ │ + ); │ │ │ │ + var script = document.createElement("script"); │ │ │ │ + script.type = "text/javascript"; │ │ │ │ + script.src = url; │ │ │ │ + script.id = "OpenLayers_Protocol_Script_" + id; │ │ │ │ + this.pendingRequests[script.id] = script; │ │ │ │ + var head = document.getElementsByTagName("head")[0]; │ │ │ │ + head.appendChild(script); │ │ │ │ + return script; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: destroyRequest │ │ │ │ + * Remove a script node associated with a response from the document. Also │ │ │ │ + * unregisters the callback and removes the script from the │ │ │ │ + * <pendingRequests> object. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * script - {HTMLScriptElement} │ │ │ │ + */ │ │ │ │ + destroyRequest: function(script) { │ │ │ │ + OpenLayers.Protocol.Script.unregister(script.id.split("_").pop()); │ │ │ │ + delete this.pendingRequests[script.id]; │ │ │ │ + if (script.parentNode) { │ │ │ │ + script.parentNode.removeChild(script); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: handleRead │ │ │ │ + * Individual callbacks are created for read, create and update, should │ │ │ │ + * a subclass need to override each one separately. │ │ │ │ + * │ │ │ │ + * 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) { │ │ │ │ + this.handleResponse(response, options); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: handleResponse │ │ │ │ + * Called by CRUD specific handlers. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * response - {<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(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + if (response.data) { │ │ │ │ + response.features = this.parseFeatures(response.data); │ │ │ │ + response.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ } else { │ │ │ │ - filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ - property: geometryAttribute.name, │ │ │ │ - value: geometry │ │ │ │ - }); │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ } │ │ │ │ - } else if (this.handler instanceof OpenLayers.Handler.Click) { │ │ │ │ - if (geometryAttribute.type.indexOf('Polygon') >= 0) { │ │ │ │ - filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ - property: geometryAttribute.name, │ │ │ │ - value: geometry │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.DWITHIN, │ │ │ │ - property: geometryAttribute.name, │ │ │ │ - distance: this.map.getExtent().getWidth() * 0.01, │ │ │ │ - distanceUnits: this.map.getUnits(), │ │ │ │ - value: geometry │ │ │ │ - }); │ │ │ │ + this.destroyRequest(response.priv); │ │ │ │ + options.callback.call(options.scope, response); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseFeatures │ │ │ │ + * Read Script response body and return features. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {Object} The data sent to the callback function by the server. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array({<OpenLayers.Feature.Vector>})} or │ │ │ │ + * {<OpenLayers.Feature.Vector>} Array of features or a single feature. │ │ │ │ + */ │ │ │ │ + parseFeatures: function(data) { │ │ │ │ + return this.format.read(data); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: abort │ │ │ │ + * Abort an ongoing request. If no response is provided, all pending │ │ │ │ + * requests will be aborted. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} The response object returned │ │ │ │ + * from a <read> request. │ │ │ │ + */ │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + this.destroyRequest(response.priv); │ │ │ │ + } else { │ │ │ │ + for (var key in this.pendingRequests) { │ │ │ │ + this.destroyRequest(this.pendingRequests[key]); │ │ │ │ } │ │ │ │ } │ │ │ │ - return filter; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: select │ │ │ │ - * When the handler is done, use SLD_BODY on the selection layer to │ │ │ │ - * display the selection in the map. │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Clean up the protocol. │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + this.abort(); │ │ │ │ + delete this.params; │ │ │ │ + delete this.format; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.Script" │ │ │ │ +}); │ │ │ │ + │ │ │ │ +(function() { │ │ │ │ + var o = OpenLayers.Protocol.Script; │ │ │ │ + var counter = 0; │ │ │ │ + o.registry = {}; │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Function: OpenLayers.Protocol.Script.register │ │ │ │ + * Register a callback for a newly created script. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * geometry - {Object} or {<OpenLayers.Geometry>} │ │ │ │ + * callback - {Function} The callback to be executed when the newly added │ │ │ │ + * script loads. This callback will be called with a single argument │ │ │ │ + * that is the JSON returned by the service. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Number} An identifier for retrieving the registered callback. │ │ │ │ */ │ │ │ │ - select: function(geometry) { │ │ │ │ - this._queue = function() { │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ - var layer = this.layers[i]; │ │ │ │ - var geometryAttributes = this.getGeometryAttributes(layer); │ │ │ │ - var filters = []; │ │ │ │ - for (var j = 0, lenj = geometryAttributes.length; j < lenj; j++) { │ │ │ │ - var geometryAttribute = geometryAttributes[j]; │ │ │ │ - if (geometryAttribute !== null) { │ │ │ │ - // from the click handler we will not get an actual │ │ │ │ - // geometry so transform │ │ │ │ - if (!(geometry instanceof OpenLayers.Geometry)) { │ │ │ │ - var point = this.map.getLonLatFromPixel( │ │ │ │ - geometry.xy); │ │ │ │ - geometry = new OpenLayers.Geometry.Point( │ │ │ │ - point.lon, point.lat); │ │ │ │ - } │ │ │ │ - var filter = this.createFilter(geometryAttribute, │ │ │ │ - geometry); │ │ │ │ - if (filter !== null) { │ │ │ │ - filters.push(filter); │ │ │ │ + o.register = function(callback) { │ │ │ │ + var id = "c" + (++counter); │ │ │ │ + o.registry[id] = function() { │ │ │ │ + callback.apply(this, arguments); │ │ │ │ + }; │ │ │ │ + return id; │ │ │ │ + }; │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Function: OpenLayers.Protocol.Script.unregister │ │ │ │ + * Unregister a callback previously registered with the register function. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * id - {Number} The identifer returned by the register function. │ │ │ │ + */ │ │ │ │ + o.unregister = function(id) { │ │ │ │ + delete o.registry[id]; │ │ │ │ + }; │ │ │ │ +})(); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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/Format/SOSGetFeatureOfInterest.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/v3.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.SOSGetFeatureOfInterest │ │ │ │ + * Read and write SOS GetFeatureOfInterest. This is used to get to │ │ │ │ + * the location of the features (stations). The stations can have 1 or more │ │ │ │ + * sensors. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.SOSGetFeatureOfInterest = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.XML, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: VERSION │ │ │ │ + * {String} 1.0.0 │ │ │ │ + */ │ │ │ │ + VERSION: "1.0.0", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + */ │ │ │ │ + namespaces: { │ │ │ │ + sos: "http://www.opengis.net/sos/1.0", │ │ │ │ + gml: "http://www.opengis.net/gml", │ │ │ │ + sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} Schema location │ │ │ │ + */ │ │ │ │ + schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosAll.xsd", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: defaultPrefix │ │ │ │ + */ │ │ │ │ + defaultPrefix: "sos", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ + */ │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.SOSGetFeatureOfInterest │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Parse a GetFeatureOfInterest response and return an array 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]); │ │ │ │ + } │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement; │ │ │ │ + } │ │ │ │ + │ │ │ │ + var info = { │ │ │ │ + features: [] │ │ │ │ + }; │ │ │ │ + this.readNode(data, info); │ │ │ │ + │ │ │ │ + var features = []; │ │ │ │ + for (var i = 0, len = info.features.length; i < len; i++) { │ │ │ │ + var container = info.features[i]; │ │ │ │ + // reproject features if needed │ │ │ │ + if (this.internalProjection && this.externalProjection && │ │ │ │ + container.components[0]) { │ │ │ │ + container.components[0].transform( │ │ │ │ + this.externalProjection, this.internalProjection │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + var feature = new OpenLayers.Feature.Vector( │ │ │ │ + container.components[0], container.attributes); │ │ │ │ + features.push(feature); │ │ │ │ + } │ │ │ │ + return 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: { │ │ │ │ + "sa": { │ │ │ │ + "SamplingPoint": function(node, obj) { │ │ │ │ + // sampling point can also be without a featureMember if │ │ │ │ + // there is only 1 │ │ │ │ + if (!obj.attributes) { │ │ │ │ + var feature = { │ │ │ │ + attributes: {} │ │ │ │ + }; │ │ │ │ + obj.features.push(feature); │ │ │ │ + obj = feature; │ │ │ │ + } │ │ │ │ + obj.attributes.id = this.getAttributeNS(node, │ │ │ │ + this.namespaces.gml, "id"); │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "position": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "gml": OpenLayers.Util.applyDefaults({ │ │ │ │ + "FeatureCollection": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "featureMember": function(node, obj) { │ │ │ │ + var feature = { │ │ │ │ + attributes: {} │ │ │ │ + }; │ │ │ │ + obj.features.push(feature); │ │ │ │ + this.readChildNodes(node, feature); │ │ │ │ + }, │ │ │ │ + "name": function(node, obj) { │ │ │ │ + obj.attributes.name = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "pos": function(node, obj) { │ │ │ │ + // we need to parse the srsName to get to the │ │ │ │ + // externalProjection, that's why we cannot use │ │ │ │ + // GML v3 for this │ │ │ │ + if (!this.externalProjection) { │ │ │ │ + this.externalProjection = new OpenLayers.Projection( │ │ │ │ + node.getAttribute("srsName")); │ │ │ │ + } │ │ │ │ + OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply( │ │ │ │ + this, [node, obj]); │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.GML.v3.prototype.readers.gml) │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "sos": { │ │ │ │ + "GetFeatureOfInterest": function(options) { │ │ │ │ + var node = this.createElementNSPlus("GetFeatureOfInterest", { │ │ │ │ + attributes: { │ │ │ │ + version: this.VERSION, │ │ │ │ + service: 'SOS', │ │ │ │ + "xsi:schemaLocation": this.schemaLocation │ │ │ │ } │ │ │ │ + }); │ │ │ │ + for (var i = 0, len = options.fois.length; i < len; i++) { │ │ │ │ + this.writeNode("FeatureOfInterestId", { │ │ │ │ + foi: options.fois[i] │ │ │ │ + }, node); │ │ │ │ } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "FeatureOfInterestId": function(options) { │ │ │ │ + var node = this.createElementNSPlus("FeatureOfInterestId", { │ │ │ │ + value: options.foi │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - var selectionLayer = this.createSelectionLayer(layer); │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SOSGetFeatureOfInterest" │ │ │ │ │ │ │ │ - this.events.triggerEvent("selected", { │ │ │ │ - layer: layer, │ │ │ │ - filters: filters │ │ │ │ - }); │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Protocol/SOS/v1_0_0.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - var sld = this.createSLD(layer, filters, geometryAttributes); │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - selectionLayer.mergeNewParams({ │ │ │ │ - SLD_BODY: sld │ │ │ │ - }); │ │ │ │ - delete this._queue; │ │ │ │ - } │ │ │ │ - }; │ │ │ │ - this.applySelection(); │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Protocol/SOS.js │ │ │ │ + * @requires OpenLayers/Format/SOSGetFeatureOfInterest.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Protocol.SOS.v1_0_0 │ │ │ │ + * An SOS v1.0.0 Protocol for vector layers. Create a new instance with the │ │ │ │ + * <OpenLayers.Protocol.SOS.v1_0_0> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Protocol> │ │ │ │ + */ │ │ │ │ +OpenLayers.Protocol.SOS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: fois │ │ │ │ + * {Array(String)} Array of features of interest (foi) │ │ │ │ + */ │ │ │ │ + fois: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: applySelection │ │ │ │ - * Checks if all required wfs data is cached, and applies the selection │ │ │ │ + * Constructor: OpenLayers.Protocol.SOS │ │ │ │ + * A class for giving layers an SOS 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). │ │ │ │ + * fois - {Array} The features of interest (required). │ │ │ │ */ │ │ │ │ - applySelection: function() { │ │ │ │ - var canApply = true; │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ - if (!this.wfsCache[this.layers[i].id]) { │ │ │ │ - canApply = false; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ + if (!options.format) { │ │ │ │ + this.format = new OpenLayers.Format.SOSGetFeatureOfInterest( │ │ │ │ + this.formatOptions); │ │ │ │ } │ │ │ │ - canApply && this._queue.call(this); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.SLDSelect" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/Button.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. */ │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ + }, │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Control.js │ │ │ │ - */ │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Construct a request for reading new sensor positions. This is done by │ │ │ │ + * issuing one GetFeatureOfInterest request. │ │ │ │ + */ │ │ │ │ + read: function(options) { │ │ │ │ + options = OpenLayers.Util.extend({}, options); │ │ │ │ + OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ + var response = new OpenLayers.Protocol.Response({ │ │ │ │ + requestType: "read" │ │ │ │ + }); │ │ │ │ + var format = this.format; │ │ │ │ + var data = OpenLayers.Format.XML.prototype.write.apply(format, │ │ │ │ + [format.writeNode("sos:GetFeatureOfInterest", { │ │ │ │ + fois: this.fois │ │ │ │ + })] │ │ │ │ + ); │ │ │ │ + response.priv = OpenLayers.Request.POST({ │ │ │ │ + url: options.url, │ │ │ │ + callback: this.createCallback(this.handleRead, response, options), │ │ │ │ + data: data │ │ │ │ + }); │ │ │ │ + return response; │ │ │ │ + }, │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.Button │ │ │ │ - * The Button control is a very simple push-button, for use with │ │ │ │ - * <OpenLayers.Control.Panel>. │ │ │ │ - * When clicked, the function trigger() is executed. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - * │ │ │ │ - * Use: │ │ │ │ - * (code) │ │ │ │ - * var button = new OpenLayers.Control.Button({ │ │ │ │ - * displayClass: "MyButton", trigger: myFunction │ │ │ │ - * }); │ │ │ │ - * panel.addControls([button]); │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * Will create a button with CSS class MyButtonItemInactive, that │ │ │ │ - * will call the function MyFunction() when clicked. │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.Button = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ /** │ │ │ │ - * Property: type │ │ │ │ - * {Integer} OpenLayers.Control.TYPE_BUTTON. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - type: OpenLayers.Control.TYPE_BUTTON, │ │ │ │ + handleRead: function(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + var request = response.priv; │ │ │ │ + if (request.status >= 200 && request.status < 300) { │ │ │ │ + // success │ │ │ │ + response.features = this.parseFeatures(request); │ │ │ │ + response.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ + } else { │ │ │ │ + // failure │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ + } │ │ │ │ + options.callback.call(options.scope, response); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: trigger │ │ │ │ - * Called by a control panel when the button is clicked. │ │ │ │ + * Method: parseFeatures │ │ │ │ + * Read HTTP response body and return features │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * request - {XMLHttpRequest} The request object │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array({<OpenLayers.Feature.Vector>})} Array of features │ │ │ │ */ │ │ │ │ - trigger: function() {}, │ │ │ │ + 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); │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Button" │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.SOS.v1_0_0" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/NavigationHistory.js │ │ │ │ + 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/Control.js │ │ │ │ - * @requires OpenLayers/Control/Button.js │ │ │ │ + * @requires OpenLayers/Protocol/WFS.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.NavigationHistory │ │ │ │ - * A navigation history control. This is a meta-control, that creates two │ │ │ │ - * dependent controls: <previous> and <next>. Call the trigger method │ │ │ │ - * on the <previous> and <next> controls to restore previous and next │ │ │ │ - * history states. The previous and next controls will become active │ │ │ │ - * when there are available states to restore and will become deactive │ │ │ │ - * when there are no states to restore. │ │ │ │ + * Class: OpenLayers.Protocol.WFS.v1 │ │ │ │ + * Abstract class for for v1.0.0 and v1.1.0 protocol. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * - <OpenLayers.Protocol> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.NavigationHistory = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: type │ │ │ │ - * {String} Note that this control is not intended to be added directly │ │ │ │ - * to a control panel. Instead, add the sub-controls previous and │ │ │ │ - * next. These sub-controls are button type controls that activate │ │ │ │ - * and deactivate themselves. If this parent control is added to │ │ │ │ - * a panel, it will act as a toggle. │ │ │ │ + * Property: version │ │ │ │ + * {String} WFS version number. │ │ │ │ */ │ │ │ │ - type: OpenLayers.Control.TYPE_TOGGLE, │ │ │ │ + version: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: previous │ │ │ │ - * {<OpenLayers.Control>} A button type control whose trigger method restores │ │ │ │ - * the previous state managed by this control. │ │ │ │ + * Property: srsName │ │ │ │ + * {String} Name of spatial reference system. Default is "EPSG:4326". │ │ │ │ */ │ │ │ │ - previous: null, │ │ │ │ + srsName: "EPSG:4326", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: previousOptions │ │ │ │ - * {Object} Set this property on the options argument of the constructor │ │ │ │ - * to set optional properties on the <previous> control. │ │ │ │ + * Property: featureType │ │ │ │ + * {String} Local feature typeName. │ │ │ │ */ │ │ │ │ - previousOptions: null, │ │ │ │ + featureType: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: next │ │ │ │ - * {<OpenLayers.Control>} A button type control whose trigger method restores │ │ │ │ - * the next state managed by this control. │ │ │ │ + * Property: featureNS │ │ │ │ + * {String} Feature namespace. │ │ │ │ */ │ │ │ │ - next: null, │ │ │ │ + featureNS: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: nextOptions │ │ │ │ - * {Object} Set this property on the options argument of the constructor │ │ │ │ - * to set optional properties on the <next> control. │ │ │ │ + * Property: geometryName │ │ │ │ + * {String} Name of the geometry attribute for features. Default is │ │ │ │ + * "the_geom" for WFS <version> 1.0, and null for higher versions. │ │ │ │ */ │ │ │ │ - nextOptions: null, │ │ │ │ + geometryName: "the_geom", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: limit │ │ │ │ - * {Integer} Optional limit on the number of history items to retain. If │ │ │ │ - * null, there is no limit. Default is 50. │ │ │ │ + * Property: maxFeatures │ │ │ │ + * {Integer} Optional maximum number of features to retrieve. │ │ │ │ */ │ │ │ │ - limit: 50, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ + * 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). │ │ │ │ */ │ │ │ │ - autoActivate: true, │ │ │ │ + schema: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: clearOnDeactivate │ │ │ │ - * {Boolean} Clear the history when the control is deactivated. Default │ │ │ │ - * is false. │ │ │ │ + * Property: featurePrefix │ │ │ │ + * {String} Namespace alias for feature type. Default is "feature". │ │ │ │ */ │ │ │ │ - clearOnDeactivate: false, │ │ │ │ + featurePrefix: "feature", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: registry │ │ │ │ - * {Object} An object with keys corresponding to event types. Values │ │ │ │ - * are functions that return an object representing the current state. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - registry: null, │ │ │ │ + formatOptions: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: nextStack │ │ │ │ - * {Array} Array of items in the history. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - nextStack: null, │ │ │ │ + readFormat: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: previousStack │ │ │ │ - * {Array} List of items in the history. First item represents the current │ │ │ │ - * state. │ │ │ │ + * Property: readOptions │ │ │ │ + * {Object} Optional object to pass to format's read. │ │ │ │ */ │ │ │ │ - previousStack: null, │ │ │ │ + readOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: listeners │ │ │ │ - * {Object} An object containing properties corresponding to event types. │ │ │ │ - * This object is used to configure the control and is modified on │ │ │ │ - * construction. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - listeners: null, │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: restoring │ │ │ │ - * {Boolean} Currently restoring a history state. This is set to true │ │ │ │ - * before calling restore and set to false after restore returns. │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Clean up the protocol. │ │ │ │ */ │ │ │ │ - restoring: false, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.options && !this.options.format) { │ │ │ │ + this.format.destroy(); │ │ │ │ + } │ │ │ │ + this.format = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.NavigationHistory │ │ │ │ - * │ │ │ │ + * 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} An optional object whose properties will be used │ │ │ │ - * to extend the control. │ │ │ │ + * 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) │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - │ │ │ │ - this.registry = OpenLayers.Util.extend({ │ │ │ │ - "moveend": this.getState │ │ │ │ - }, this.registry); │ │ │ │ + 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 previousOptions = { │ │ │ │ - trigger: OpenLayers.Function.bind(this.previousTrigger, this), │ │ │ │ - displayClass: this.displayClass + " " + this.displayClass + "Previous" │ │ │ │ - }; │ │ │ │ - OpenLayers.Util.extend(previousOptions, this.previousOptions); │ │ │ │ - this.previous = new OpenLayers.Control.Button(previousOptions); │ │ │ │ + var data = OpenLayers.Format.XML.prototype.write.apply( │ │ │ │ + this.format, [this.format.writeNode("wfs:GetFeature", options)] │ │ │ │ + ); │ │ │ │ │ │ │ │ - var nextOptions = { │ │ │ │ - trigger: OpenLayers.Function.bind(this.nextTrigger, this), │ │ │ │ - displayClass: this.displayClass + " " + this.displayClass + "Next" │ │ │ │ - }; │ │ │ │ - OpenLayers.Util.extend(nextOptions, this.nextOptions); │ │ │ │ - this.next = new OpenLayers.Control.Button(nextOptions); │ │ │ │ + response.priv = OpenLayers.Request.POST({ │ │ │ │ + url: options.url, │ │ │ │ + callback: this.createCallback(this.handleRead, response, options), │ │ │ │ + params: options.params, │ │ │ │ + headers: options.headers, │ │ │ │ + data: data │ │ │ │ + }); │ │ │ │ │ │ │ │ - this.clear(); │ │ │ │ + return response; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onPreviousChange │ │ │ │ - * Called when the previous history stack changes. │ │ │ │ + * APIMethod: setFeatureType │ │ │ │ + * Change the feature type on the fly. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * state - {Object} An object representing the state to be restored │ │ │ │ - * if previous is triggered again or null if no previous states remain. │ │ │ │ - * length - {Integer} The number of remaining previous states that can │ │ │ │ - * be restored. │ │ │ │ + * featureType - {String} Local (without prefix) feature typeName. │ │ │ │ */ │ │ │ │ - onPreviousChange: function(state, length) { │ │ │ │ - if (state && !this.previous.active) { │ │ │ │ - this.previous.activate(); │ │ │ │ - } else if (!state && this.previous.active) { │ │ │ │ - this.previous.deactivate(); │ │ │ │ - } │ │ │ │ + setFeatureType: function(featureType) { │ │ │ │ + this.featureType = featureType; │ │ │ │ + this.format.featureType = featureType; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onNextChange │ │ │ │ - * Called when the next history stack changes. │ │ │ │ + * APIMethod: setGeometryName │ │ │ │ + * Sets the geometryName option after instantiation. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * state - {Object} An object representing the state to be restored │ │ │ │ - * if next is triggered again or null if no next states remain. │ │ │ │ - * length - {Integer} The number of remaining next states that can │ │ │ │ - * be restored. │ │ │ │ + * geometryName - {String} Name of geometry attribute. │ │ │ │ */ │ │ │ │ - onNextChange: function(state, length) { │ │ │ │ - if (state && !this.next.active) { │ │ │ │ - this.next.activate(); │ │ │ │ - } else if (!state && this.next.active) { │ │ │ │ - this.next.deactivate(); │ │ │ │ - } │ │ │ │ + setGeometryName: function(geometryName) { │ │ │ │ + this.geometryName = geometryName; │ │ │ │ + this.format.geometryName = geometryName; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Destroy the control. │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this); │ │ │ │ - this.previous.destroy(); │ │ │ │ - this.next.destroy(); │ │ │ │ - this.deactivate(); │ │ │ │ - for (var prop in this) { │ │ │ │ - this[prop] = null; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * Set the map property for the control and <previous> and <next> child │ │ │ │ - * controls. │ │ │ │ + * Method: handleRead │ │ │ │ + * Deal with response from the read request. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} The response object to pass │ │ │ │ + * to the user callback. │ │ │ │ + * options - {Object} The user options passed to the read call. │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - this.map = map; │ │ │ │ - this.next.setMap(map); │ │ │ │ - this.previous.setMap(map); │ │ │ │ - }, │ │ │ │ + handleRead: function(response, options) { │ │ │ │ + options = OpenLayers.Util.extend({}, options); │ │ │ │ + OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * Called when the control is added to the map. │ │ │ │ - */ │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - this.next.draw(); │ │ │ │ - this.previous.draw(); │ │ │ │ + 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: previousTrigger │ │ │ │ - * Restore the previous state. If no items are in the previous history │ │ │ │ - * stack, this has no effect. │ │ │ │ + * 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} Item representing state that was restored. Undefined if no │ │ │ │ - * items are in the previous history stack. │ │ │ │ + * {Object} or {Array({<OpenLayers.Feature.Vector>})} or │ │ │ │ + * {<OpenLayers.Feature.Vector>} │ │ │ │ + * An object with a features property, an array of features or a single │ │ │ │ + * feature. │ │ │ │ */ │ │ │ │ - previousTrigger: function() { │ │ │ │ - var current = this.previousStack.shift(); │ │ │ │ - var state = this.previousStack.shift(); │ │ │ │ - if (state != undefined) { │ │ │ │ - this.nextStack.unshift(current); │ │ │ │ - this.previousStack.unshift(state); │ │ │ │ - this.restoring = true; │ │ │ │ - this.restore(state); │ │ │ │ - this.restoring = false; │ │ │ │ - this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ - this.onPreviousChange( │ │ │ │ - this.previousStack[1], this.previousStack.length - 1 │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - this.previousStack.unshift(current); │ │ │ │ + parseResponse: function(request, options) { │ │ │ │ + var doc = request.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = request.responseText; │ │ │ │ } │ │ │ │ - return state; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: nextTrigger │ │ │ │ - * Restore the next state. If no items are in the next history │ │ │ │ - * stack, this has no effect. The next history stack is populated │ │ │ │ - * as states are restored from the previous history stack. │ │ │ │ + * 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: │ │ │ │ - * {Object} Item representing state that was restored. Undefined if no │ │ │ │ - * items are in the next history stack. │ │ │ │ + * {<OpenLayers.Protocol.Response>} A response object with a features │ │ │ │ + * property containing any insertIds and a priv property referencing │ │ │ │ + * the XMLHttpRequest object. │ │ │ │ */ │ │ │ │ - nextTrigger: function() { │ │ │ │ - var state = this.nextStack.shift(); │ │ │ │ - if (state != undefined) { │ │ │ │ - this.previousStack.unshift(state); │ │ │ │ - this.restoring = true; │ │ │ │ - this.restore(state); │ │ │ │ - this.restoring = false; │ │ │ │ - this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ - this.onPreviousChange( │ │ │ │ - this.previousStack[1], this.previousStack.length - 1 │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return state; │ │ │ │ - }, │ │ │ │ + commit: function(features, options) { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: clear │ │ │ │ - * Clear history. │ │ │ │ - */ │ │ │ │ - clear: function() { │ │ │ │ - this.previousStack = []; │ │ │ │ - this.previous.deactivate(); │ │ │ │ - this.nextStack = []; │ │ │ │ - this.next.deactivate(); │ │ │ │ - }, │ │ │ │ + options = OpenLayers.Util.extend({}, options); │ │ │ │ + OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getState │ │ │ │ - * Get the current state and return it. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An object representing the current state. │ │ │ │ - */ │ │ │ │ - getState: function() { │ │ │ │ - return { │ │ │ │ - center: this.map.getCenter(), │ │ │ │ - resolution: this.map.getResolution(), │ │ │ │ - projection: this.map.getProjectionObject(), │ │ │ │ - units: this.map.getProjectionObject().getUnits() || │ │ │ │ - this.map.units || this.map.baseLayer.units │ │ │ │ - }; │ │ │ │ + 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: restore │ │ │ │ - * Update the state with the given object. │ │ │ │ - * │ │ │ │ + * Method: handleCommit │ │ │ │ + * Called when the commit request returns. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * state - {Object} An object representing the state to restore. │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} The response object to pass │ │ │ │ + * to the user callback. │ │ │ │ + * options - {Object} The user options passed to the commit call. │ │ │ │ */ │ │ │ │ - restore: function(state) { │ │ │ │ - var center, zoom; │ │ │ │ - if (this.map.getProjectionObject() == state.projection) { │ │ │ │ - zoom = this.map.getZoomForResolution(state.resolution); │ │ │ │ - center = state.center; │ │ │ │ - } else { │ │ │ │ - center = state.center.clone(); │ │ │ │ - center.transform(state.projection, this.map.getProjectionObject()); │ │ │ │ - var sourceUnits = state.units; │ │ │ │ - var targetUnits = this.map.getProjectionObject().getUnits() || │ │ │ │ - this.map.units || this.map.baseLayer.units; │ │ │ │ - var resolutionFactor = sourceUnits && targetUnits ? │ │ │ │ - OpenLayers.INCHES_PER_UNIT[sourceUnits] / OpenLayers.INCHES_PER_UNIT[targetUnits] : 1; │ │ │ │ - zoom = this.map.getZoomForResolution(resolutionFactor * state.resolution); │ │ │ │ - } │ │ │ │ - this.map.setCenter(center, zoom); │ │ │ │ - }, │ │ │ │ + handleCommit: function(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + var request = response.priv; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setListeners │ │ │ │ - * Sets functions to be registered in the listeners object. │ │ │ │ - */ │ │ │ │ - setListeners: function() { │ │ │ │ - this.listeners = {}; │ │ │ │ - for (var type in this.registry) { │ │ │ │ - this.listeners[type] = OpenLayers.Function.bind(function() { │ │ │ │ - if (!this.restoring) { │ │ │ │ - var state = this.registry[type].apply(this, arguments); │ │ │ │ - this.previousStack.unshift(state); │ │ │ │ - if (this.previousStack.length > 1) { │ │ │ │ - this.onPreviousChange( │ │ │ │ - this.previousStack[1], this.previousStack.length - 1 │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (this.previousStack.length > (this.limit + 1)) { │ │ │ │ - this.previousStack.pop(); │ │ │ │ - } │ │ │ │ - if (this.nextStack.length > 0) { │ │ │ │ - this.nextStack = []; │ │ │ │ - this.onNextChange(null, 0); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return true; │ │ │ │ - }, this); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + // ensure that we have an xml doc │ │ │ │ + var data = request.responseXML; │ │ │ │ + if (!data || !data.documentElement) { │ │ │ │ + data = request.responseText; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the control. This registers any listeners. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Control successfully activated. │ │ │ │ - */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (this.map) { │ │ │ │ - if (OpenLayers.Control.prototype.activate.apply(this)) { │ │ │ │ - if (this.listeners == null) { │ │ │ │ - this.setListeners(); │ │ │ │ - } │ │ │ │ - for (var type in this.listeners) { │ │ │ │ - this.map.events.register(type, this, this.listeners[type]); │ │ │ │ - } │ │ │ │ - activated = true; │ │ │ │ - if (this.previousStack.length == 0) { │ │ │ │ - this.initStack(); │ │ │ │ - } │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: initStack │ │ │ │ - * Called after the control is activated if the previous history stack is │ │ │ │ - * empty. │ │ │ │ + * Method: filterDelete │ │ │ │ + * Send a request that deletes all features by their filter. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * filter - {<OpenLayers.Filter>} filter │ │ │ │ */ │ │ │ │ - initStack: function() { │ │ │ │ - if (this.map.getCenter()) { │ │ │ │ - this.listeners.moveend(); │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ + │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the control. This unregisters any listeners. │ │ │ │ + * 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). │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Control successfully deactivated. │ │ │ │ + * Parameters: │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = false; │ │ │ │ - if (this.map) { │ │ │ │ - if (OpenLayers.Control.prototype.deactivate.apply(this)) { │ │ │ │ - for (var type in this.listeners) { │ │ │ │ - this.map.events.unregister( │ │ │ │ - type, this, this.listeners[type] │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (this.clearOnDeactivate) { │ │ │ │ - this.clear(); │ │ │ │ - } │ │ │ │ - deactivated = true; │ │ │ │ - } │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + response.priv.abort(); │ │ │ │ } │ │ │ │ - return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.NavigationHistory" │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.WFS.v1" │ │ │ │ }); │ │ │ │ - │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Geolocate.js │ │ │ │ + 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/Control.js │ │ │ │ - * @requires OpenLayers/Geometry/Point.js │ │ │ │ - * @requires OpenLayers/Projection.js │ │ │ │ + * @requires OpenLayers/Format/GML/Base.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. │ │ │ │ + * Class: OpenLayers.Format.GML.v2 │ │ │ │ + * Parses GML version 2. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * - <OpenLayers.Format.GML.Base> │ │ │ │ */ │ │ │ │ -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, │ │ │ │ +OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} Schema location for a particular minor version. │ │ │ │ */ │ │ │ │ - geolocationOptions: null, │ │ │ │ + schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.Geolocate │ │ │ │ - * Create a new control to deal with browser geolocation API │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ - * Activates the control. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The control was effectively activated. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + 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) │ │ │ │ ); │ │ │ │ - } else { │ │ │ │ - this.getCurrentLocation(); │ │ │ │ } │ │ │ │ - return true; │ │ │ │ - } │ │ │ │ - return false; │ │ │ │ + }, OpenLayers.Format.GML.Base.prototype.readers["gml"]), │ │ │ │ + "feature": OpenLayers.Format.GML.Base.prototype.readers["feature"], │ │ │ │ + "wfs": OpenLayers.Format.GML.Base.prototype.readers["wfs"] │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Deactivates the control. │ │ │ │ + * Method: write │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector} │ │ │ │ + * An array of features or a single feature. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} The control was effectively deactivated. │ │ │ │ + * {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. │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - if (this.active && this.watchId !== null) { │ │ │ │ - this.geolocation.clearWatch(this.watchId); │ │ │ │ + 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"; │ │ │ │ } │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply( │ │ │ │ - this, arguments │ │ │ │ + var root = this.writeNode(name, features); │ │ │ │ + this.setAttributeNS( │ │ │ │ + root, this.namespaces["xsi"], │ │ │ │ + "xsi:schemaLocation", this.schemaLocation │ │ │ │ ); │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 │ │ │ │ - ) │ │ │ │ - }); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [root]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: getCurrentLocation │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Returns true if a event will be fired (successfull │ │ │ │ - * registration) │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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"] │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: failure │ │ │ │ - * method called on browser's geolocation failure │ │ │ │ - * │ │ │ │ - */ │ │ │ │ - failure: function(error) { │ │ │ │ - this.events.triggerEvent("locationfailed", { │ │ │ │ - error: error │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.GML.v2" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Geolocate" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/PanZoom.js │ │ │ │ + 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/Control.js │ │ │ │ - * @requires OpenLayers/Events/buttonclick.js │ │ │ │ + * @requires OpenLayers/Format/GML/v2.js │ │ │ │ + * @requires OpenLayers/Format/Filter/v1.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.PanZoom │ │ │ │ - * The PanZoom is a visible control, composed of a │ │ │ │ - * <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomPanel>. By │ │ │ │ - * default it is drawn in the upper left corner of the map. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.Filter.v1_0_0 │ │ │ │ + * Write ogc:Filter version 1.0.0. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * - <OpenLayers.Format.GML.v2> │ │ │ │ + * - <OpenLayers.Format.Filter.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: slideFactor │ │ │ │ - * {Integer} Number of pixels by which we'll pan the map in any direction │ │ │ │ - * on clicking the arrow buttons. If you want to pan by some ratio │ │ │ │ - * of the map dimensions, use <slideRatio> instead. │ │ │ │ - */ │ │ │ │ - slideFactor: 50, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: slideRatio │ │ │ │ - * {Number} The fraction of map width/height by which we'll pan the map │ │ │ │ - * on clicking the arrow buttons. Default is null. If set, will │ │ │ │ - * override <slideFactor>. E.g. if slideRatio is .5, then the Pan Up │ │ │ │ - * button will pan up half the map height. │ │ │ │ - */ │ │ │ │ - slideRatio: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: buttons │ │ │ │ - * {Array(DOMElement)} Array of Button Divs │ │ │ │ - */ │ │ │ │ - buttons: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: position │ │ │ │ - * {<OpenLayers.Pixel>} │ │ │ │ - */ │ │ │ │ - position: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.PanZoom │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X, │ │ │ │ - OpenLayers.Control.PanZoom.Y); │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ - } │ │ │ │ - this.removeButtons(); │ │ │ │ - this.buttons = null; │ │ │ │ - this.position = null; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * │ │ │ │ - * Properties: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ - */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - this.map.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * px - {<OpenLayers.Pixel>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A reference to the container div for the PanZoom control. │ │ │ │ - */ │ │ │ │ - draw: function(px) { │ │ │ │ - // initialize our internal div │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - px = this.position; │ │ │ │ - │ │ │ │ - // place the controls │ │ │ │ - this.buttons = []; │ │ │ │ - │ │ │ │ - var sz = { │ │ │ │ - w: 18, │ │ │ │ - h: 18 │ │ │ │ - }; │ │ │ │ - var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ - │ │ │ │ - this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ - px.y = centered.y + sz.h; │ │ │ │ - this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ - this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz); │ │ │ │ - this._addButton("pandown", "south-mini.png", │ │ │ │ - centered.add(0, sz.h * 2), sz); │ │ │ │ - this._addButton("zoomin", "zoom-plus-mini.png", │ │ │ │ - centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ - this._addButton("zoomworld", "zoom-world-mini.png", │ │ │ │ - centered.add(0, sz.h * 4 + 5), sz); │ │ │ │ - this._addButton("zoomout", "zoom-minus-mini.png", │ │ │ │ - centered.add(0, sz.h * 5 + 5), sz); │ │ │ │ - return this.div; │ │ │ │ - }, │ │ │ │ +OpenLayers.Format.Filter.v1_0_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.GML.v2, OpenLayers.Format.Filter.v1, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: _addButton │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * id - {String} │ │ │ │ - * img - {String} │ │ │ │ - * xy - {<OpenLayers.Pixel>} │ │ │ │ - * sz - {<OpenLayers.Size>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A Div (an alphaImageDiv, to be precise) that contains the │ │ │ │ - * image of the button, and has all the proper event handlers set. │ │ │ │ - */ │ │ │ │ - _addButton: function(id, img, xy, sz) { │ │ │ │ - var imgLocation = OpenLayers.Util.getImageLocation(img); │ │ │ │ - var btn = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ - this.id + "_" + id, │ │ │ │ - xy, sz, imgLocation, "absolute"); │ │ │ │ - btn.style.cursor = "pointer"; │ │ │ │ - //we want to add the outer div │ │ │ │ - this.div.appendChild(btn); │ │ │ │ - btn.action = id; │ │ │ │ - btn.className = "olButton"; │ │ │ │ + /** │ │ │ │ + * Constant: VERSION │ │ │ │ + * {String} 1.0.0 │ │ │ │ + */ │ │ │ │ + VERSION: "1.0.0", │ │ │ │ │ │ │ │ - //we want to remember/reference the outer div │ │ │ │ - this.buttons.push(btn); │ │ │ │ - return btn; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: _removeButton │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * btn - {Object} │ │ │ │ - */ │ │ │ │ - _removeButton: function(btn) { │ │ │ │ - this.div.removeChild(btn); │ │ │ │ - OpenLayers.Util.removeItem(this.buttons, btn); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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] │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: removeButtons │ │ │ │ - */ │ │ │ │ - removeButtons: function() { │ │ │ │ - for (var i = this.buttons.length - 1; i >= 0; --i) { │ │ │ │ - this._removeButton(this.buttons[i]); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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"] │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: onButtonClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - */ │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - var btn = evt.buttonElement; │ │ │ │ - switch (btn.action) { │ │ │ │ - case "panup": │ │ │ │ - this.map.pan(0, -this.getSlideFactor("h")); │ │ │ │ - break; │ │ │ │ - case "pandown": │ │ │ │ - this.map.pan(0, this.getSlideFactor("h")); │ │ │ │ - break; │ │ │ │ - case "panleft": │ │ │ │ - this.map.pan(-this.getSlideFactor("w"), 0); │ │ │ │ - break; │ │ │ │ - case "panright": │ │ │ │ - this.map.pan(this.getSlideFactor("w"), 0); │ │ │ │ - break; │ │ │ │ - case "zoomin": │ │ │ │ - this.map.zoomIn(); │ │ │ │ - break; │ │ │ │ - case "zoomout": │ │ │ │ - this.map.zoomOut(); │ │ │ │ - break; │ │ │ │ - case "zoomworld": │ │ │ │ - this.map.zoomToMaxExtent(); │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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: getSlideFactor │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * dim - {String} "w" or "h" (for width or height). │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Number} The slide factor for panning in the requested direction. │ │ │ │ - */ │ │ │ │ - getSlideFactor: function(dim) { │ │ │ │ - return this.slideRatio ? │ │ │ │ - this.map.getSize()[dim] * this.slideRatio : │ │ │ │ - this.slideFactor; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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.Control.PanZoom" │ │ │ │ -}); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: X │ │ │ │ - * {Integer} │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.PanZoom.X = 4; │ │ │ │ + CLASS_NAME: "OpenLayers.Format.Filter.v1_0_0" │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: Y │ │ │ │ - * {Integer} │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.PanZoom.Y = 4; │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/PanZoomBar.js │ │ │ │ + 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/Control/PanZoom.js │ │ │ │ + * @requires OpenLayers/Format/WFST/v1.js │ │ │ │ + * @requires OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.PanZoomBar │ │ │ │ - * The PanZoomBar is a visible control composed of a │ │ │ │ - * <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomBar>. │ │ │ │ - * By default it is displayed in the upper left corner of the map as 4 │ │ │ │ - * directional arrows above a vertical slider. │ │ │ │ + * 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.Control.PanZoom> │ │ │ │ + * - <OpenLayers.Format.Filter.v1_0_0> │ │ │ │ + * - <OpenLayers.Format.WFST.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.PanZoomBar = OpenLayers.Class(OpenLayers.Control.PanZoom, { │ │ │ │ +OpenLayers.Format.WFST.v1_0_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.Filter.v1_0_0, OpenLayers.Format.WFST.v1, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: zoomStopWidth │ │ │ │ - */ │ │ │ │ - zoomStopWidth: 18, │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} WFS version number. │ │ │ │ + */ │ │ │ │ + version: "1.0.0", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: zoomStopHeight │ │ │ │ - */ │ │ │ │ - zoomStopHeight: 11, │ │ │ │ + /** │ │ │ │ + * 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: slider │ │ │ │ - */ │ │ │ │ - slider: null, │ │ │ │ + /** │ │ │ │ + * Property: schemaLocations │ │ │ │ + * {Object} Properties are namespace aliases, values are schema locations. │ │ │ │ + */ │ │ │ │ + schemaLocations: { │ │ │ │ + "wfs": "http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd" │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: sliderEvents │ │ │ │ - * {<OpenLayers.Events>} │ │ │ │ - */ │ │ │ │ - sliderEvents: null, │ │ │ │ + /** │ │ │ │ + * 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]); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: zoombarDiv │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - zoombarDiv: null, │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: zoomWorldIcon │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - zoomWorldIcon: false, │ │ │ │ + /** │ │ │ │ + * 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"] │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: panIcons │ │ │ │ - * {Boolean} Set this property to false not to display the pan icons. If │ │ │ │ - * false the zoom world icon is placed under the zoom bar. Defaults to │ │ │ │ - * true. │ │ │ │ - */ │ │ │ │ - panIcons: true, │ │ │ │ + /** │ │ │ │ + * 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"] │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: forceFixedZoomLevel │ │ │ │ - * {Boolean} Force a fixed zoom level even though the map has │ │ │ │ - * fractionalZoom │ │ │ │ - */ │ │ │ │ - forceFixedZoomLevel: false, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFST.v1_0_0" │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Protocol/WFS/v1_0_0.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: mouseDragStart │ │ │ │ - * {<OpenLayers.Pixel>} │ │ │ │ - */ │ │ │ │ - mouseDragStart: null, │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: deltaY │ │ │ │ - * {Number} The cumulative vertical pixel offset during a zoom bar drag. │ │ │ │ - */ │ │ │ │ - deltaY: null, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Protocol/WFS/v1.js │ │ │ │ + * @requires OpenLayers/Format/WFST/v1_0_0.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: zoomStart │ │ │ │ - * {<OpenLayers.Pixel>} │ │ │ │ - */ │ │ │ │ - zoomStart: null, │ │ │ │ +/** │ │ │ │ + * 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, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.PanZoomBar │ │ │ │ + * Property: version │ │ │ │ + * {String} WFS version number. │ │ │ │ */ │ │ │ │ + version: "1.0.0", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: destroy │ │ │ │ + * 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'. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ │ │ │ │ - this._removeZoomBar(); │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.WFS.v1_0_0" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Protocol/WFS/v1_1_0.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - this.map.events.un({ │ │ │ │ - "changebaselayer": this.redraw, │ │ │ │ - "updatesize": this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Protocol/WFS/v1.js │ │ │ │ + * @requires OpenLayers/Format/WFST/v1_1_0.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - delete this.mouseDragStart; │ │ │ │ - delete this.zoomStart; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Protocol.WFS.v1_1_0 │ │ │ │ + * A WFS v1.1.0 protocol for vector layers. Create a new instance with the │ │ │ │ + * <OpenLayers.Protocol.WFS.v1_1_0> constructor. │ │ │ │ + * │ │ │ │ + * Differences from the v1.0.0 protocol: │ │ │ │ + * - uses Filter Encoding 1.1.0 instead of 1.0.0 │ │ │ │ + * - uses GML 3 instead of 2 if no format is provided │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Protocol.WFS.v1> │ │ │ │ + */ │ │ │ │ +OpenLayers.Protocol.WFS.v1_1_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setMap │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ - */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments); │ │ │ │ - this.map.events.on({ │ │ │ │ - "changebaselayer": this.redraw, │ │ │ │ - "updatesize": this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: redraw │ │ │ │ - * clear the div and start over. │ │ │ │ + * Property: version │ │ │ │ + * {String} WFS version number. │ │ │ │ */ │ │ │ │ - redraw: function() { │ │ │ │ - if (this.div != null) { │ │ │ │ - this.removeButtons(); │ │ │ │ - this._removeZoomBar(); │ │ │ │ - } │ │ │ │ - this.draw(); │ │ │ │ - }, │ │ │ │ + version: "1.1.0", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: draw │ │ │ │ + * Constructor: OpenLayers.Protocol.WFS.v1_1_0 │ │ │ │ + * A class for giving layers WFS v1.1.0 protocol. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * px - {<OpenLayers.Pixel>} │ │ │ │ + * 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'. │ │ │ │ + * outputFormat - {String} Optional output format to use for WFS GetFeature │ │ │ │ + * requests. This can be any format advertized by the WFS's │ │ │ │ + * GetCapabilities response. If set, an appropriate readFormat also │ │ │ │ + * has to be provided, unless outputFormat is GML3, GML2 or JSON. │ │ │ │ + * readFormat - {<OpenLayers.Format>} An appropriate format parser if │ │ │ │ + * outputFormat is none of GML3, GML2 or JSON. │ │ │ │ */ │ │ │ │ - draw: function(px) { │ │ │ │ - // initialize our internal div │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - px = this.position.clone(); │ │ │ │ - │ │ │ │ - // place the controls │ │ │ │ - this.buttons = []; │ │ │ │ - │ │ │ │ - var sz = { │ │ │ │ - w: 18, │ │ │ │ - h: 18 │ │ │ │ - }; │ │ │ │ - if (this.panIcons) { │ │ │ │ - var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ - var wposition = sz.w; │ │ │ │ - │ │ │ │ - if (this.zoomWorldIcon) { │ │ │ │ - centered = new OpenLayers.Pixel(px.x + sz.w, px.y); │ │ │ │ - } │ │ │ │ - │ │ │ │ - this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ - px.y = centered.y + sz.h; │ │ │ │ - this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ - if (this.zoomWorldIcon) { │ │ │ │ - this._addButton("zoomworld", "zoom-world-mini.png", px.add(sz.w, 0), sz); │ │ │ │ - │ │ │ │ - wposition *= 2; │ │ │ │ - } │ │ │ │ - this._addButton("panright", "east-mini.png", px.add(wposition, 0), sz); │ │ │ │ - this._addButton("pandown", "south-mini.png", centered.add(0, sz.h * 2), sz); │ │ │ │ - this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ - centered = this._addZoomBar(centered.add(0, sz.h * 4 + 5)); │ │ │ │ - this._addButton("zoomout", "zoom-minus-mini.png", centered, sz); │ │ │ │ - } else { │ │ │ │ - this._addButton("zoomin", "zoom-plus-mini.png", px, sz); │ │ │ │ - centered = this._addZoomBar(px.add(0, sz.h)); │ │ │ │ - this._addButton("zoomout", "zoom-minus-mini.png", centered, sz); │ │ │ │ - if (this.zoomWorldIcon) { │ │ │ │ - centered = centered.add(0, sz.h + 3); │ │ │ │ - this._addButton("zoomworld", "zoom-world-mini.png", centered, sz); │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Protocol.WFS.v1.prototype.initialize.apply(this, arguments); │ │ │ │ + if (this.outputFormat && !this.readFormat) { │ │ │ │ + if (this.outputFormat.toLowerCase() == "gml2") { │ │ │ │ + this.readFormat = new OpenLayers.Format.GML.v2({ │ │ │ │ + featureType: this.featureType, │ │ │ │ + featureNS: this.featureNS, │ │ │ │ + geometryName: this.geometryName │ │ │ │ + }); │ │ │ │ + } else if (this.outputFormat.toLowerCase() == "json") { │ │ │ │ + this.readFormat = new OpenLayers.Format.GeoJSON(); │ │ │ │ } │ │ │ │ } │ │ │ │ - return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: _addZoomBar │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * centered - {<OpenLayers.Pixel>} where zoombar drawing is to start. │ │ │ │ - */ │ │ │ │ - _addZoomBar: function(centered) { │ │ │ │ - var imgLocation = OpenLayers.Util.getImageLocation("slider.png"); │ │ │ │ - var id = this.id + "_" + this.map.id; │ │ │ │ - var minZoom = this.map.getMinZoom(); │ │ │ │ - var zoomsToEnd = this.map.getNumZoomLevels() - 1 - this.map.getZoom(); │ │ │ │ - var slider = OpenLayers.Util.createAlphaImageDiv(id, │ │ │ │ - centered.add(-1, zoomsToEnd * this.zoomStopHeight), { │ │ │ │ - w: 20, │ │ │ │ - h: 9 │ │ │ │ - }, │ │ │ │ - imgLocation, │ │ │ │ - "absolute"); │ │ │ │ - slider.style.cursor = "move"; │ │ │ │ - this.slider = slider; │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.WFS.v1_1_0" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/CSWGetRecords.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - this.sliderEvents = new OpenLayers.Events(this, slider, null, true, { │ │ │ │ - includeXY: true │ │ │ │ - }); │ │ │ │ - this.sliderEvents.on({ │ │ │ │ - "touchstart": this.zoomBarDown, │ │ │ │ - "touchmove": this.zoomBarDrag, │ │ │ │ - "touchend": this.zoomBarUp, │ │ │ │ - "mousedown": this.zoomBarDown, │ │ │ │ - "mousemove": this.zoomBarDrag, │ │ │ │ - "mouseup": this.zoomBarUp │ │ │ │ - }); │ │ │ │ +/* 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 sz = { │ │ │ │ - w: this.zoomStopWidth, │ │ │ │ - h: this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom) │ │ │ │ - }; │ │ │ │ - var imgLocation = OpenLayers.Util.getImageLocation("zoombar.png"); │ │ │ │ - var div = null; │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (OpenLayers.Util.alphaHack()) { │ │ │ │ - var id = this.id + "_" + this.map.id; │ │ │ │ - div = OpenLayers.Util.createAlphaImageDiv(id, centered, { │ │ │ │ - w: sz.w, │ │ │ │ - h: this.zoomStopHeight │ │ │ │ - }, │ │ │ │ - imgLocation, │ │ │ │ - "absolute", null, "crop"); │ │ │ │ - div.style.height = sz.h + "px"; │ │ │ │ - } else { │ │ │ │ - div = OpenLayers.Util.createDiv( │ │ │ │ - 'OpenLayers_Control_PanZoomBar_Zoombar' + this.map.id, │ │ │ │ - centered, │ │ │ │ - sz, │ │ │ │ - imgLocation); │ │ │ │ - } │ │ │ │ - div.style.cursor = "pointer"; │ │ │ │ - div.className = "olButton"; │ │ │ │ - this.zoombarDiv = div; │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.CSWGetRecords │ │ │ │ + * Default version is 2.0.2. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Format>} A CSWGetRecords format of the given version. │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.CSWGetRecords = function(options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults( │ │ │ │ + options, OpenLayers.Format.CSWGetRecords.DEFAULTS │ │ │ │ + ); │ │ │ │ + var cls = OpenLayers.Format.CSWGetRecords["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (!cls) { │ │ │ │ + throw "Unsupported CSWGetRecords version: " + options.version; │ │ │ │ + } │ │ │ │ + return new cls(options); │ │ │ │ +}; │ │ │ │ │ │ │ │ - this.div.appendChild(div); │ │ │ │ +/** │ │ │ │ + * Constant: DEFAULTS │ │ │ │ + * {Object} Default properties for the CSWGetRecords format. │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.CSWGetRecords.DEFAULTS = { │ │ │ │ + "version": "2.0.2" │ │ │ │ +}; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/CSWGetRecords/v2_0_2.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - this.startTop = parseInt(div.style.top); │ │ │ │ - this.div.appendChild(slider); │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - this.map.events.register("zoomend", this, this.moveZoomBar); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/XML.js │ │ │ │ + * @requires OpenLayers/Format/CSWGetRecords.js │ │ │ │ + * @requires OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ + * @requires OpenLayers/Format/Filter/v1_1_0.js │ │ │ │ + * @requires OpenLayers/Format/OWSCommon/v1_0_0.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - centered = centered.add(0, │ │ │ │ - this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom)); │ │ │ │ - return centered; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.CSWGetRecords.v2_0_2 │ │ │ │ + * A format for creating CSWGetRecords v2.0.2 transactions. │ │ │ │ + * Create a new instance with the │ │ │ │ + * <OpenLayers.Format.CSWGetRecords.v2_0_2> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.CSWGetRecords.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: _removeZoomBar │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ - _removeZoomBar: function() { │ │ │ │ - this.sliderEvents.un({ │ │ │ │ - "touchstart": this.zoomBarDown, │ │ │ │ - "touchmove": this.zoomBarDrag, │ │ │ │ - "touchend": this.zoomBarUp, │ │ │ │ - "mousedown": this.zoomBarDown, │ │ │ │ - "mousemove": this.zoomBarDrag, │ │ │ │ - "mouseup": this.zoomBarUp │ │ │ │ - }); │ │ │ │ - this.sliderEvents.destroy(); │ │ │ │ - │ │ │ │ - this.div.removeChild(this.zoombarDiv); │ │ │ │ - this.zoombarDiv = null; │ │ │ │ - this.div.removeChild(this.slider); │ │ │ │ - this.slider = null; │ │ │ │ - │ │ │ │ - this.map.events.unregister("zoomend", this, this.moveZoomBar); │ │ │ │ + namespaces: { │ │ │ │ + csw: "http://www.opengis.net/cat/csw/2.0.2", │ │ │ │ + dc: "http://purl.org/dc/elements/1.1/", │ │ │ │ + dct: "http://purl.org/dc/terms/", │ │ │ │ + gmd: "http://www.isotc211.org/2005/gmd", │ │ │ │ + geonet: "http://www.fao.org/geonetwork", │ │ │ │ + ogc: "http://www.opengis.net/ogc", │ │ │ │ + ows: "http://www.opengis.net/ows", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onButtonClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * Property: defaultPrefix │ │ │ │ + * {String} The default prefix (used by Format.XML). │ │ │ │ */ │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this, arguments); │ │ │ │ - if (evt.buttonElement === this.zoombarDiv) { │ │ │ │ - var levels = evt.buttonXY.y / this.zoomStopHeight; │ │ │ │ - if (this.forceFixedZoomLevel || !this.map.fractionalZoom) { │ │ │ │ - levels = Math.floor(levels); │ │ │ │ - } │ │ │ │ - var zoom = (this.map.getNumZoomLevels() - 1) - levels; │ │ │ │ - zoom = Math.min(Math.max(zoom, 0), this.map.getNumZoomLevels() - 1); │ │ │ │ - this.map.zoomTo(zoom); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + defaultPrefix: "csw", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: passEventToSlider │ │ │ │ - * This function is used to pass events that happen on the div, or the map, │ │ │ │ - * through to the slider, which then does its moving thing. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ - */ │ │ │ │ - passEventToSlider: function(evt) { │ │ │ │ - this.sliderEvents.handleBrowserEvent(evt); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /* │ │ │ │ - * Method: zoomBarDown │ │ │ │ - * event listener for clicks on the slider │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ + * Property: version │ │ │ │ + * {String} CSW version number. │ │ │ │ */ │ │ │ │ - zoomBarDown: function(evt) { │ │ │ │ - if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - this.map.events.on({ │ │ │ │ - "touchmove": this.passEventToSlider, │ │ │ │ - "mousemove": this.passEventToSlider, │ │ │ │ - "mouseup": this.passEventToSlider, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.mouseDragStart = evt.xy.clone(); │ │ │ │ - this.zoomStart = evt.xy.clone(); │ │ │ │ - this.div.style.cursor = "move"; │ │ │ │ - // reset the div offsets just in case the div moved │ │ │ │ - this.zoombarDiv.offsets = null; │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - }, │ │ │ │ + version: "2.0.2", │ │ │ │ │ │ │ │ - /* │ │ │ │ - * Method: zoomBarDrag │ │ │ │ - * This is what happens when a click has occurred, and the client is │ │ │ │ - * dragging. Here we must ensure that the slider doesn't go beyond the │ │ │ │ - * bottom/top of the zoombar div, as well as moving the slider to its new │ │ │ │ - * visual location │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ + /** │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} http://www.opengis.net/cat/csw/2.0.2 │ │ │ │ + * http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd │ │ │ │ */ │ │ │ │ - zoomBarDrag: function(evt) { │ │ │ │ - if (this.mouseDragStart != null) { │ │ │ │ - var deltaY = this.mouseDragStart.y - evt.xy.y; │ │ │ │ - var offsets = OpenLayers.Util.pagePosition(this.zoombarDiv); │ │ │ │ - if ((evt.clientY - offsets[1]) > 0 && │ │ │ │ - (evt.clientY - offsets[1]) < parseInt(this.zoombarDiv.style.height) - 2) { │ │ │ │ - var newTop = parseInt(this.slider.style.top) - deltaY; │ │ │ │ - this.slider.style.top = newTop + "px"; │ │ │ │ - this.mouseDragStart = evt.xy.clone(); │ │ │ │ - } │ │ │ │ - // set cumulative displacement │ │ │ │ - this.deltaY = this.zoomStart.y - evt.xy.y; │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ │ │ │ │ - /* │ │ │ │ - * Method: zoomBarUp │ │ │ │ - * Perform cleanup when a mouseup event is received -- discover new zoom │ │ │ │ - * level and switch to it. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ + /** │ │ │ │ + * APIProperty: requestId │ │ │ │ + * {String} Value of the requestId attribute of the GetRecords element. │ │ │ │ */ │ │ │ │ - zoomBarUp: function(evt) { │ │ │ │ - if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - if (this.mouseDragStart) { │ │ │ │ - this.div.style.cursor = ""; │ │ │ │ - this.map.events.un({ │ │ │ │ - "touchmove": this.passEventToSlider, │ │ │ │ - "mouseup": this.passEventToSlider, │ │ │ │ - "mousemove": this.passEventToSlider, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - var zoomLevel = this.map.zoom; │ │ │ │ - if (!this.forceFixedZoomLevel && this.map.fractionalZoom) { │ │ │ │ - zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ - zoomLevel = Math.min(Math.max(zoomLevel, 0), │ │ │ │ - this.map.getNumZoomLevels() - 1); │ │ │ │ - } else { │ │ │ │ - zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ - zoomLevel = Math.max(Math.round(zoomLevel), 0); │ │ │ │ - } │ │ │ │ - this.map.zoomTo(zoomLevel); │ │ │ │ - this.mouseDragStart = null; │ │ │ │ - this.zoomStart = null; │ │ │ │ - this.deltaY = 0; │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + requestId: null, │ │ │ │ │ │ │ │ - /* │ │ │ │ - * Method: moveZoomBar │ │ │ │ - * Change the location of the slider to match the current zoom level. │ │ │ │ + /** │ │ │ │ + * APIProperty: resultType │ │ │ │ + * {String} Value of the resultType attribute of the GetRecords element, │ │ │ │ + * specifies the result type in the GetRecords response, "hits" is │ │ │ │ + * the default. │ │ │ │ */ │ │ │ │ - moveZoomBar: function() { │ │ │ │ - var newTop = │ │ │ │ - ((this.map.getNumZoomLevels() - 1) - this.map.getZoom()) * │ │ │ │ - this.zoomStopHeight + this.startTop + 1; │ │ │ │ - this.slider.style.top = newTop + "px"; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.PanZoomBar" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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, { │ │ │ │ + resultType: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: outputFormat │ │ │ │ + * {String} Value of the outputFormat attribute of the GetRecords element, │ │ │ │ + * specifies the format of the GetRecords response, │ │ │ │ + * "application/xml" is the default. │ │ │ │ */ │ │ │ │ - started: false, │ │ │ │ + outputFormat: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: stopDown │ │ │ │ - * {Boolean} Stop propagation of touchstart events from getting to │ │ │ │ - * listeners on the same element. Default is false. │ │ │ │ + * APIProperty: outputSchema │ │ │ │ + * {String} Value of the outputSchema attribute of the GetRecords element, │ │ │ │ + * specifies the schema of the GetRecords response. │ │ │ │ */ │ │ │ │ - stopDown: false, │ │ │ │ + outputSchema: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: pinching │ │ │ │ - * {Boolean} │ │ │ │ + * APIProperty: startPosition │ │ │ │ + * {String} Value of the startPosition attribute of the GetRecords element, │ │ │ │ + * specifies the start position (offset+1) for the GetRecords response, │ │ │ │ + * 1 is the default. │ │ │ │ */ │ │ │ │ - pinching: false, │ │ │ │ + startPosition: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: last │ │ │ │ - * {Object} Object that store informations related to pinch last touch. │ │ │ │ + * APIProperty: maxRecords │ │ │ │ + * {String} Value of the maxRecords attribute of the GetRecords element, │ │ │ │ + * specifies the maximum number of records in the GetRecords response, │ │ │ │ + * 10 is the default. │ │ │ │ */ │ │ │ │ - last: null, │ │ │ │ + maxRecords: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: start │ │ │ │ - * {Object} Object that store informations related to pinch touchstart. │ │ │ │ + * APIProperty: DistributedSearch │ │ │ │ + * {String} Value of the csw:DistributedSearch element, used when writing │ │ │ │ + * a csw:GetRecords document. │ │ │ │ */ │ │ │ │ - start: null, │ │ │ │ + DistributedSearch: 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} │ │ │ │ + * APIProperty: ResponseHandler │ │ │ │ + * {Array({String})} Values of the csw:ResponseHandler elements, used when │ │ │ │ + * writting a csw:GetRecords document. │ │ │ │ */ │ │ │ │ + ResponseHandler: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: touchstart │ │ │ │ - * Handle touchstart events │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * APIProperty: Query │ │ │ │ + * {String} Value of the csw:Query element, used when writing a csw:GetRecords │ │ │ │ + * document. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - }, │ │ │ │ + Query: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: touchmove │ │ │ │ - * Handle touchmove events │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: touchend │ │ │ │ - * Handle touchend events │ │ │ │ + * Constructor: OpenLayers.Format.CSWGetRecords.v2_0_2 │ │ │ │ + * A class for parsing and generating CSWGetRecords v2.0.2 transactions. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ + * Valid options properties (documented as class properties): │ │ │ │ + * - requestId │ │ │ │ + * - resultType │ │ │ │ + * - outputFormat │ │ │ │ + * - outputSchema │ │ │ │ + * - startPosition │ │ │ │ + * - maxRecords │ │ │ │ + * - DistributedSearch │ │ │ │ + * - ResponseHandler │ │ │ │ + * - Query │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ - * Activate the handler. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The handler was successfully activated. │ │ │ │ + * APIMethod: read │ │ │ │ + * Parse the response from a GetRecords request. │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.pinching = false; │ │ │ │ - activated = true; │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement; │ │ │ │ + } │ │ │ │ + var obj = {}; │ │ │ │ + this.readNode(data, obj); │ │ │ │ + return obj; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Deactivate the handler. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The handler was successfully deactivated. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + readers: { │ │ │ │ + "csw": { │ │ │ │ + "GetRecordsResponse": function(node, obj) { │ │ │ │ + obj.records = []; │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + var version = this.getAttributeNS(node, "", 'version'); │ │ │ │ + if (version != "") { │ │ │ │ + obj.version = version; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "RequestId": function(node, obj) { │ │ │ │ + obj.RequestId = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "SearchStatus": function(node, obj) { │ │ │ │ + obj.SearchStatus = {}; │ │ │ │ + var timestamp = this.getAttributeNS(node, "", 'timestamp'); │ │ │ │ + if (timestamp != "") { │ │ │ │ + obj.SearchStatus.timestamp = timestamp; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "SearchResults": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var SearchResults = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + if ((attrs[i].name == "numberOfRecordsMatched") || │ │ │ │ + (attrs[i].name == "numberOfRecordsReturned") || │ │ │ │ + (attrs[i].name == "nextRecord")) { │ │ │ │ + SearchResults[attrs[i].name] = parseInt(attrs[i].nodeValue); │ │ │ │ + } else { │ │ │ │ + SearchResults[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + obj.SearchResults = SearchResults; │ │ │ │ + }, │ │ │ │ + "SummaryRecord": function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "SummaryRecord" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record); │ │ │ │ + }, │ │ │ │ + "BriefRecord": function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "BriefRecord" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record); │ │ │ │ + }, │ │ │ │ + "DCMIRecord": function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "DCMIRecord" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record); │ │ │ │ + }, │ │ │ │ + "Record": function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "Record" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record); │ │ │ │ + }, │ │ │ │ + "*": function(node, obj) { │ │ │ │ + var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ + obj[name] = this.getChildValue(node); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "geonet": { │ │ │ │ + "info": function(node, obj) { │ │ │ │ + var gninfo = {}; │ │ │ │ + this.readChildNodes(node, gninfo); │ │ │ │ + obj.gninfo = gninfo; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "dc": { │ │ │ │ + // audience, contributor, coverage, creator, date, description, format, │ │ │ │ + // identifier, language, provenance, publisher, relation, rights, │ │ │ │ + // rightsHolder, source, subject, title, type, URI │ │ │ │ + "*": function(node, obj) { │ │ │ │ + var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ + if (!(OpenLayers.Util.isArray(obj[name]))) { │ │ │ │ + obj[name] = []; │ │ │ │ + } │ │ │ │ + var dc_element = {}; │ │ │ │ + var attrs = node.attributes; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + dc_element[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ + } │ │ │ │ + dc_element.value = this.getChildValue(node); │ │ │ │ + if (dc_element.value != "") { │ │ │ │ + obj[name].push(dc_element); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "dct": { │ │ │ │ + // abstract, modified, spatial │ │ │ │ + "*": function(node, obj) { │ │ │ │ + var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ + if (!(OpenLayers.Util.isArray(obj[name]))) { │ │ │ │ + obj[name] = []; │ │ │ │ + } │ │ │ │ + obj[name].push(this.getChildValue(node)); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "ows": OpenLayers.Util.applyDefaults({ │ │ │ │ + "BoundingBox": function(node, obj) { │ │ │ │ + if (obj.bounds) { │ │ │ │ + obj.BoundingBox = [{ │ │ │ │ + crs: obj.projection, │ │ │ │ + value: [ │ │ │ │ + obj.bounds.left, │ │ │ │ + obj.bounds.bottom, │ │ │ │ + obj.bounds.right, │ │ │ │ + obj.bounds.top │ │ │ │ + ] │ │ │ │ + }]; │ │ │ │ + delete obj.projection; │ │ │ │ + delete obj.bounds; │ │ │ │ + } │ │ │ │ + OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]["BoundingBox"].apply( │ │ │ │ + this, arguments); │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]) │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getDistance │ │ │ │ - * Get the distance in pixels between two touches. │ │ │ │ + * Method: write │ │ │ │ + * Given an configuration js object, write a CSWGetRecords request. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * touches - {Array(Object)} │ │ │ │ + * options - {Object} A object mapping the request. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Number} The distance in pixels. │ │ │ │ + * {String} A serialized CSWGetRecords request. │ │ │ │ */ │ │ │ │ - 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) │ │ │ │ - ); │ │ │ │ + write: function(options) { │ │ │ │ + var node = this.writeNode("csw:GetRecords", options); │ │ │ │ + node.setAttribute("xmlns:gmd", this.namespaces.gmd); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [node]); │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: getPinchData │ │ │ │ - * Get informations about the pinch event. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} Object that contains data about the current pinch. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }; │ │ │ │ + writers: { │ │ │ │ + "csw": { │ │ │ │ + "GetRecords": function(options) { │ │ │ │ + if (!options) { │ │ │ │ + options = {}; │ │ │ │ + } │ │ │ │ + var node = this.createElementNSPlus("csw:GetRecords", { │ │ │ │ + attributes: { │ │ │ │ + service: "CSW", │ │ │ │ + version: this.version, │ │ │ │ + requestId: options.requestId || this.requestId, │ │ │ │ + resultType: options.resultType || this.resultType, │ │ │ │ + outputFormat: options.outputFormat || this.outputFormat, │ │ │ │ + outputSchema: options.outputSchema || this.outputSchema, │ │ │ │ + startPosition: options.startPosition || this.startPosition, │ │ │ │ + maxRecords: options.maxRecords || this.maxRecords │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (options.DistributedSearch || this.DistributedSearch) { │ │ │ │ + this.writeNode( │ │ │ │ + "csw:DistributedSearch", │ │ │ │ + options.DistributedSearch || this.DistributedSearch, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + var ResponseHandler = options.ResponseHandler || this.ResponseHandler; │ │ │ │ + if (OpenLayers.Util.isArray(ResponseHandler) && ResponseHandler.length > 0) { │ │ │ │ + // ResponseHandler must be a non-empty array │ │ │ │ + for (var i = 0, len = ResponseHandler.length; i < len; i++) { │ │ │ │ + this.writeNode( │ │ │ │ + "csw:ResponseHandler", │ │ │ │ + ResponseHandler[i], │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.writeNode("Query", options.Query || this.Query, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "DistributedSearch": function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:DistributedSearch", { │ │ │ │ + attributes: { │ │ │ │ + hopCount: options.hopCount │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ResponseHandler": function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:ResponseHandler", { │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Query": function(options) { │ │ │ │ + if (!options) { │ │ │ │ + options = {}; │ │ │ │ + } │ │ │ │ + var node = this.createElementNSPlus("csw:Query", { │ │ │ │ + attributes: { │ │ │ │ + typeNames: options.typeNames || "csw:Record" │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + var ElementName = options.ElementName; │ │ │ │ + if (OpenLayers.Util.isArray(ElementName) && ElementName.length > 0) { │ │ │ │ + // ElementName must be a non-empty array │ │ │ │ + for (var i = 0, len = ElementName.length; i < len; i++) { │ │ │ │ + this.writeNode( │ │ │ │ + "csw:ElementName", │ │ │ │ + ElementName[i], │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.writeNode( │ │ │ │ + "csw:ElementSetName", │ │ │ │ + options.ElementSetName || { │ │ │ │ + value: 'summary' │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (options.Constraint) { │ │ │ │ + this.writeNode( │ │ │ │ + "csw:Constraint", │ │ │ │ + options.Constraint, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (options.SortBy) { │ │ │ │ + this.writeNode( │ │ │ │ + "ogc:SortBy", │ │ │ │ + options.SortBy, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ElementName": function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:ElementName", { │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ElementSetName": function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:ElementSetName", { │ │ │ │ + attributes: { │ │ │ │ + typeNames: options.typeNames │ │ │ │ + }, │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Constraint": function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:Constraint", { │ │ │ │ + attributes: { │ │ │ │ + version: options.version │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (options.Filter) { │ │ │ │ + var format = new OpenLayers.Format.Filter({ │ │ │ │ + version: options.version │ │ │ │ + }); │ │ │ │ + node.appendChild(format.write(options.Filter)); │ │ │ │ + } else if (options.CqlText) { │ │ │ │ + var child = this.createElementNSPlus("CqlText", { │ │ │ │ + value: options.CqlText.value │ │ │ │ + }); │ │ │ │ + node.appendChild(child); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "ogc": OpenLayers.Format.Filter.v1_1_0.prototype.writers["ogc"] │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Pinch" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.CSWGetRecords.v2_0_2" │ │ │ │ }); │ │ │ │ - │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/PinchZoom.js │ │ │ │ + OpenLayers/Protocol/CSW/v2_0_2.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 │ │ │ │ + * @requires OpenLayers/Protocol/CSW.js │ │ │ │ + * @requires OpenLayers/Format/CSWGetRecords/v2_0_2.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.PinchZoom │ │ │ │ + * Class: OpenLayers.Protocol.CSW.v2_0_2 │ │ │ │ + * CS-W (Catalogue services for the Web) version 2.0.2 protocol. │ │ │ │ * │ │ │ │ - * Inherits: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Protocol> │ │ │ │ */ │ │ │ │ -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, │ │ │ │ +OpenLayers.Protocol.CSW.v2_0_2 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: handlerOptions │ │ │ │ - * {Object} Used to set non-default properties on the pinch handler │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.PinchZoom │ │ │ │ - * Create a control for zooming with pinch gestures. This works on devices │ │ │ │ - * with multi-touch support. │ │ │ │ + * Constructor: OpenLayers.Protocol.CSW.v2_0_2 │ │ │ │ + * A class for CSW version 2.0.2 protocol management. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * the control │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ */ │ │ │ │ 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); │ │ │ │ + OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ + if (!options.format) { │ │ │ │ + this.format = new OpenLayers.Format.CSWGetRecords.v2_0_2(OpenLayers.Util.extend({}, this.formatOptions)); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Clean up the protocol. │ │ │ │ */ │ │ │ │ - pinchStart: function(evt, pinchData) { │ │ │ │ - var xy = (this.preserveCenter) ? │ │ │ │ - this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; │ │ │ │ - this.pinchOrigin = xy; │ │ │ │ - this.currentCenter = xy; │ │ │ │ + destroy: function() { │ │ │ │ + if (this.options && !this.options.format) { │ │ │ │ + this.format.destroy(); │ │ │ │ + } │ │ │ │ + this.format = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: read │ │ │ │ + * Construct a request for reading new records from the Catalogue. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + read: function(options) { │ │ │ │ + options = OpenLayers.Util.extend({}, options); │ │ │ │ + OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ + var response = new OpenLayers.Protocol.Response({ │ │ │ │ + requestType: "read" │ │ │ │ + }); │ │ │ │ │ │ │ │ - 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)); │ │ │ │ + var data = this.format.write(options.params || options); │ │ │ │ │ │ │ │ - this.map.applyTransform(dx, dy, scale); │ │ │ │ - this.currentCenter = current; │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: pinchDone │ │ │ │ + * Method: handleRead │ │ │ │ + * Deal with response from the read request. │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * response - {<OpenLayers.Protocol.Response>} The response object to pass │ │ │ │ + * to the user callback. │ │ │ │ + * This response is given a code property, and optionally a data property. │ │ │ │ + * The latter represents the CSW records as returned by the call to │ │ │ │ + * the CSW format read method. │ │ │ │ + * options - {Object} The user options passed to the read call. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + handleRead: function(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + var request = response.priv; │ │ │ │ + if (request.status >= 200 && request.status < 300) { │ │ │ │ + // success │ │ │ │ + response.data = this.parseData(request); │ │ │ │ + response.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ + } else { │ │ │ │ + // failure │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ + } │ │ │ │ + options.callback.call(options.scope, response); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.PinchZoom" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/ZoomIn.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/Button.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.ZoomIn │ │ │ │ - * The ZoomIn control is a button to increase the zoom level of a map. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.ZoomIn = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: trigger │ │ │ │ + * Method: parseData │ │ │ │ + * Read HTTP response body and return records │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * request - {XMLHttpRequest} The request object │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} The CSW records as returned by the call to the format read method. │ │ │ │ */ │ │ │ │ - trigger: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.zoomIn(); │ │ │ │ + parseData: 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); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomIn" │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.CSW.v2_0_2" │ │ │ │ + │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Control/ScaleLine.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ @@ -61250,3398 +66731,4261 @@ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Control.ScaleLine" │ │ │ │ }); │ │ │ │ │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Handler/Hover.js │ │ │ │ + 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/Handler.js │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Handler/Drag.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Handler.Hover │ │ │ │ - * The hover handler is to be used to emulate mouseovers on objects │ │ │ │ - * on the map that aren't DOM elements. For example one can use │ │ │ │ - * this handler to send WMS/GetFeatureInfo requests as the user │ │ │ │ - * moves the mouve over the map. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Control.DragPan │ │ │ │ + * The DragPan control pans the map with a drag of the mouse. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Handler> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ +OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: delay │ │ │ │ - * {Integer} - Number of milliseconds between mousemoves before │ │ │ │ - * the event is considered a hover. Default is 500. │ │ │ │ + /** │ │ │ │ + * Property: type │ │ │ │ + * {OpenLayers.Control.TYPES} │ │ │ │ */ │ │ │ │ - delay: 500, │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: pixelTolerance │ │ │ │ - * {Integer} - Maximum number of pixels between mousemoves for │ │ │ │ - * an event to be considered a hover. Default is null. │ │ │ │ + * Property: panned │ │ │ │ + * {Boolean} The map moved. │ │ │ │ */ │ │ │ │ - pixelTolerance: null, │ │ │ │ + panned: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: stopMove │ │ │ │ - * {Boolean} - Stop other listeners from being notified on mousemoves. │ │ │ │ - * Default is 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. │ │ │ │ */ │ │ │ │ - stopMove: false, │ │ │ │ + interval: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: px │ │ │ │ - * {<OpenLayers.Pixel>} - The location of the last mousemove, expressed │ │ │ │ - * in pixels. │ │ │ │ + * APIProperty: documentDrag │ │ │ │ + * {Boolean} If set to true, mouse dragging will continue even if the │ │ │ │ + * mouse cursor leaves the map viewport. Default is false. │ │ │ │ */ │ │ │ │ - px: null, │ │ │ │ + documentDrag: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: timerId │ │ │ │ - * {Number} - The id of the timer. │ │ │ │ + * Property: kinetic │ │ │ │ + * {<OpenLayers.Kinetic>} The OpenLayers.Kinetic object. │ │ │ │ */ │ │ │ │ - timerId: null, │ │ │ │ + kinetic: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Handler.Hover │ │ │ │ - * Construct a hover 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. │ │ │ │ - * callbacks - {Object} An object with keys corresponding to callbacks │ │ │ │ - * that will be called by the handler. The callbacks should │ │ │ │ - * expect to receive a single argument, the event. Callbacks for │ │ │ │ - * 'move', the mouse is moving, and 'pause', the mouse is pausing, │ │ │ │ - * are supported. │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * the handler. │ │ │ │ + * 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, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: mousemove │ │ │ │ - * Called when the mouse moves on the map. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Continue propagating this event. │ │ │ │ + * APIProperty: kineticInterval │ │ │ │ + * {Integer} Interval in milliseconds between 2 steps in the "kinetic │ │ │ │ + * scrolling". Applies only if enableKinetic is set. Defaults │ │ │ │ + * to 10 milliseconds. │ │ │ │ */ │ │ │ │ - mousemove: function(evt) { │ │ │ │ - if (this.passesTolerance(evt.xy)) { │ │ │ │ - this.clearTimer(); │ │ │ │ - this.callback('move', [evt]); │ │ │ │ - this.px = evt.xy; │ │ │ │ - // clone the evt so original properties can be accessed even │ │ │ │ - // if the browser deletes them during the delay │ │ │ │ - evt = OpenLayers.Util.extend({}, evt); │ │ │ │ - this.timerId = window.setTimeout( │ │ │ │ - OpenLayers.Function.bind(this.delayedCall, this, evt), │ │ │ │ - this.delay │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return !this.stopMove; │ │ │ │ - }, │ │ │ │ + kineticInterval: 10, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: mouseout │ │ │ │ - * Called when the mouse goes out of the map. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Continue propagating this event. │ │ │ │ - */ │ │ │ │ - mouseout: function(evt) { │ │ │ │ - if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ - this.clearTimer(); │ │ │ │ - this.callback('move', [evt]); │ │ │ │ - } │ │ │ │ - return true; │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: passesTolerance │ │ │ │ - * Determine whether the mouse move is within the optional pixel tolerance. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * px - {<OpenLayers.Pixel>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The mouse move is within the pixel tolerance. │ │ │ │ + * Method: draw │ │ │ │ + * Creates a Drag handler, using <panMap> and │ │ │ │ + * <panMapDone> as callbacks. │ │ │ │ */ │ │ │ │ - passesTolerance: function(px) { │ │ │ │ - var passes = true; │ │ │ │ - if (this.pixelTolerance && this.px) { │ │ │ │ - var dpx = Math.sqrt( │ │ │ │ - Math.pow(this.px.x - px.x, 2) + │ │ │ │ - Math.pow(this.px.y - px.y, 2) │ │ │ │ - ); │ │ │ │ - if (dpx < this.pixelTolerance) { │ │ │ │ - passes = false; │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - return passes; │ │ │ │ + this.handler = new OpenLayers.Handler.Drag(this, { │ │ │ │ + "move": this.panMap, │ │ │ │ + "done": this.panMapDone, │ │ │ │ + "down": this.panMapStart │ │ │ │ + }, { │ │ │ │ + interval: this.interval, │ │ │ │ + documentDrag: this.documentDrag │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clearTimer │ │ │ │ - * Clear the timer and set <timerId> to null. │ │ │ │ + * Method: panMapStart │ │ │ │ */ │ │ │ │ - clearTimer: function() { │ │ │ │ - if (this.timerId != null) { │ │ │ │ - window.clearTimeout(this.timerId); │ │ │ │ - this.timerId = null; │ │ │ │ + panMapStart: function() { │ │ │ │ + if (this.kinetic) { │ │ │ │ + this.kinetic.begin(); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: delayedCall │ │ │ │ - * Triggers pause callback. │ │ │ │ + * Method: panMap │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ + * xy - {<OpenLayers.Pixel>} Pixel of the mouse position │ │ │ │ */ │ │ │ │ - delayedCall: function(evt) { │ │ │ │ - this.callback('pause', [evt]); │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the handler. │ │ │ │ + * Method: panMapDone │ │ │ │ + * Finish the panning operation. Only call setCenter (through <panMap>) │ │ │ │ + * if the map has actually been moved. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The handler was successfully deactivated. │ │ │ │ + * Parameters: │ │ │ │ + * xy - {<OpenLayers.Pixel>} Pixel of the mouse position │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = false; │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - this.clearTimer(); │ │ │ │ - deactivated = true; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Hover" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.DragPan" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSGetFeatureInfo.js │ │ │ │ + OpenLayers/Control/Button.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/Control.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WMSGetFeatureInfo │ │ │ │ - * Class to read GetFeatureInfo responses from Web Mapping Services │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Control.Button │ │ │ │ + * The Button control is a very simple push-button, for use with │ │ │ │ + * <OpenLayers.Control.Panel>. │ │ │ │ + * When clicked, the function trigger() is executed. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + * │ │ │ │ + * Use: │ │ │ │ + * (code) │ │ │ │ + * var button = new OpenLayers.Control.Button({ │ │ │ │ + * displayClass: "MyButton", trigger: myFunction │ │ │ │ + * }); │ │ │ │ + * panel.addControls([button]); │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Will create a button with CSS class MyButtonItemInactive, that │ │ │ │ + * will call the function MyFunction() when clicked. │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: layerIdentifier │ │ │ │ - * {String} All xml nodes containing this search criteria will populate an │ │ │ │ - * internal array of layer nodes. │ │ │ │ - */ │ │ │ │ - layerIdentifier: '_layer', │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: featureIdentifier │ │ │ │ - * {String} All xml nodes containing this search criteria will populate an │ │ │ │ - * internal array of feature nodes for each layer node found. │ │ │ │ - */ │ │ │ │ - featureIdentifier: '_feature', │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ - */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: gmlFormat │ │ │ │ - * {<OpenLayers.Format.GML>} internal GML format for parsing geometries │ │ │ │ - * in msGMLOutput │ │ │ │ - */ │ │ │ │ - gmlFormat: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WMSGetFeatureInfo │ │ │ │ - * Create a new parser for WMS GetFeatureInfo responses │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read WMS GetFeatureInfo data from a string, and return an array of features │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} An array of features. │ │ │ │ - */ │ │ │ │ - read: function(data) { │ │ │ │ - var result; │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - } │ │ │ │ - var root = data.documentElement; │ │ │ │ - if (root) { │ │ │ │ - var scope = this; │ │ │ │ - var read = this["read_" + root.nodeName]; │ │ │ │ - if (read) { │ │ │ │ - result = read.call(this, root); │ │ │ │ - } else { │ │ │ │ - // fall-back to GML since this is a common output format for WMS │ │ │ │ - // GetFeatureInfo responses │ │ │ │ - result = new OpenLayers.Format.GML((this.options ? this.options : {})).read(data); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - result = data; │ │ │ │ - } │ │ │ │ - return result; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: read_msGMLOutput │ │ │ │ - * Parse msGMLOutput nodes. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {DOMElement} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} │ │ │ │ - */ │ │ │ │ - read_msGMLOutput: function(data) { │ │ │ │ - var response = []; │ │ │ │ - var layerNodes = this.getSiblingNodesByTagCriteria(data, │ │ │ │ - this.layerIdentifier); │ │ │ │ - if (layerNodes) { │ │ │ │ - for (var i = 0, len = layerNodes.length; i < len; ++i) { │ │ │ │ - var node = layerNodes[i]; │ │ │ │ - var layerName = node.nodeName; │ │ │ │ - if (node.prefix) { │ │ │ │ - layerName = layerName.split(':')[1]; │ │ │ │ - } │ │ │ │ - var layerName = layerName.replace(this.layerIdentifier, ''); │ │ │ │ - var featureNodes = this.getSiblingNodesByTagCriteria(node, │ │ │ │ - this.featureIdentifier); │ │ │ │ - if (featureNodes) { │ │ │ │ - for (var j = 0; j < featureNodes.length; j++) { │ │ │ │ - var featureNode = featureNodes[j]; │ │ │ │ - var geomInfo = this.parseGeometry(featureNode); │ │ │ │ - var attributes = this.parseAttributes(featureNode); │ │ │ │ - var feature = new OpenLayers.Feature.Vector(geomInfo.geometry, │ │ │ │ - attributes, null); │ │ │ │ - feature.bounds = geomInfo.bounds; │ │ │ │ - feature.type = layerName; │ │ │ │ - response.push(feature); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return response; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: read_FeatureInfoResponse │ │ │ │ - * Parse FeatureInfoResponse nodes. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {DOMElement} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} │ │ │ │ - */ │ │ │ │ - read_FeatureInfoResponse: function(data) { │ │ │ │ - var response = []; │ │ │ │ - var featureNodes = this.getElementsByTagNameNS(data, '*', │ │ │ │ - 'FIELDS'); │ │ │ │ - │ │ │ │ - for (var i = 0, len = featureNodes.length; i < len; i++) { │ │ │ │ - var featureNode = featureNodes[i]; │ │ │ │ - var geom = null; │ │ │ │ - │ │ │ │ - // attributes can be actual attributes on the FIELDS tag, │ │ │ │ - // or FIELD children │ │ │ │ - var attributes = {}; │ │ │ │ - var j; │ │ │ │ - var jlen = featureNode.attributes.length; │ │ │ │ - if (jlen > 0) { │ │ │ │ - for (j = 0; j < jlen; j++) { │ │ │ │ - var attribute = featureNode.attributes[j]; │ │ │ │ - attributes[attribute.nodeName] = attribute.nodeValue; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - var nodes = featureNode.childNodes; │ │ │ │ - for (j = 0, jlen = nodes.length; j < jlen; ++j) { │ │ │ │ - var node = nodes[j]; │ │ │ │ - if (node.nodeType != 3) { │ │ │ │ - attributes[node.getAttribute("name")] = │ │ │ │ - node.getAttribute("value"); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - response.push( │ │ │ │ - new OpenLayers.Feature.Vector(geom, attributes, null) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return response; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getSiblingNodesByTagCriteria │ │ │ │ - * Recursively searches passed xml node and all it's descendant levels for │ │ │ │ - * nodes whose tagName contains the passed search string. This returns an │ │ │ │ - * array of all sibling nodes which match the criteria from the highest │ │ │ │ - * hierarchial level from which a match is found. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} An xml node │ │ │ │ - * criteria - {String} Search string which will match some part of a tagName │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * Array({DOMElement}) An array of sibling xml nodes │ │ │ │ - */ │ │ │ │ - getSiblingNodesByTagCriteria: function(node, criteria) { │ │ │ │ - var nodes = []; │ │ │ │ - var children, tagName, n, matchNodes, child; │ │ │ │ - if (node && node.hasChildNodes()) { │ │ │ │ - children = node.childNodes; │ │ │ │ - n = children.length; │ │ │ │ - │ │ │ │ - for (var k = 0; k < n; k++) { │ │ │ │ - child = children[k]; │ │ │ │ - while (child && child.nodeType != 1) { │ │ │ │ - child = child.nextSibling; │ │ │ │ - k++; │ │ │ │ - } │ │ │ │ - tagName = (child ? child.nodeName : ''); │ │ │ │ - if (tagName.length > 0 && tagName.indexOf(criteria) > -1) { │ │ │ │ - nodes.push(child); │ │ │ │ - } else { │ │ │ │ - matchNodes = this.getSiblingNodesByTagCriteria( │ │ │ │ - child, criteria); │ │ │ │ - │ │ │ │ - if (matchNodes.length > 0) { │ │ │ │ - (nodes.length == 0) ? │ │ │ │ - nodes = matchNodes: nodes.push(matchNodes); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - } │ │ │ │ - return nodes; │ │ │ │ - }, │ │ │ │ - │ │ │ │ +OpenLayers.Control.Button = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ /** │ │ │ │ - * Method: parseAttributes │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {<DOMElement>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An attributes object. │ │ │ │ - * │ │ │ │ - * Notes: │ │ │ │ - * Assumes that attributes are direct child xml nodes of the passed node │ │ │ │ - * and contain only a single text node. │ │ │ │ + * Property: type │ │ │ │ + * {Integer} OpenLayers.Control.TYPE_BUTTON. │ │ │ │ */ │ │ │ │ - parseAttributes: function(node) { │ │ │ │ - var attributes = {}; │ │ │ │ - if (node.nodeType == 1) { │ │ │ │ - var children = node.childNodes; │ │ │ │ - var n = children.length; │ │ │ │ - for (var i = 0; i < n; ++i) { │ │ │ │ - var child = children[i]; │ │ │ │ - if (child.nodeType == 1) { │ │ │ │ - var grandchildren = child.childNodes; │ │ │ │ - var name = (child.prefix) ? │ │ │ │ - child.nodeName.split(":")[1] : child.nodeName; │ │ │ │ - if (grandchildren.length == 0) { │ │ │ │ - attributes[name] = null; │ │ │ │ - } else if (grandchildren.length == 1) { │ │ │ │ - var grandchild = grandchildren[0]; │ │ │ │ - if (grandchild.nodeType == 3 || │ │ │ │ - grandchild.nodeType == 4) { │ │ │ │ - var value = grandchild.nodeValue.replace( │ │ │ │ - this.regExes.trimSpace, ""); │ │ │ │ - attributes[name] = value; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return attributes; │ │ │ │ - }, │ │ │ │ + type: OpenLayers.Control.TYPE_BUTTON, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseGeometry │ │ │ │ - * Parse the geometry and the feature bounds out of the node using │ │ │ │ - * Format.GML │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {<DOMElement>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An object containing the geometry and the feature bounds │ │ │ │ + * Method: trigger │ │ │ │ + * Called by a control panel when the button is clicked. │ │ │ │ */ │ │ │ │ - parseGeometry: function(node) { │ │ │ │ - // we need to use the old Format.GML parser since we do not know the │ │ │ │ - // geometry name │ │ │ │ - if (!this.gmlFormat) { │ │ │ │ - this.gmlFormat = new OpenLayers.Format.GML(); │ │ │ │ - } │ │ │ │ - var feature = this.gmlFormat.parseFeature(node); │ │ │ │ - var geometry, bounds = null; │ │ │ │ - if (feature) { │ │ │ │ - geometry = feature.geometry && feature.geometry.clone(); │ │ │ │ - bounds = feature.bounds && feature.bounds.clone(); │ │ │ │ - feature.destroy(); │ │ │ │ - } │ │ │ │ - return { │ │ │ │ - geometry: geometry, │ │ │ │ - bounds: bounds │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSGetFeatureInfo" │ │ │ │ + trigger: function() {}, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Button" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/WMSGetFeatureInfo.js │ │ │ │ + OpenLayers/Control/ZoomIn.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/Click.js │ │ │ │ - * @requires OpenLayers/Handler/Hover.js │ │ │ │ - * @requires OpenLayers/Request.js │ │ │ │ - * @requires OpenLayers/Format/WMSGetFeatureInfo.js │ │ │ │ + * @requires OpenLayers/Control/Button.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.WMSGetFeatureInfo │ │ │ │ - * The WMSGetFeatureInfo control uses a WMS query to get information about a point on the map. The │ │ │ │ - * information may be in a display-friendly format such as HTML, or a machine-friendly format such │ │ │ │ - * as GML, depending on the server's capabilities and the client's configuration. This control │ │ │ │ - * handles click or hover events, attempts to parse the results using an OpenLayers.Format, and │ │ │ │ - * fires a 'getfeatureinfo' event with the click position, the raw body of the response, and an │ │ │ │ - * array of features if it successfully read the response. │ │ │ │ + * Class: OpenLayers.Control.ZoomIn │ │ │ │ + * The ZoomIn control is a button to increase the zoom level of a map. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: hover │ │ │ │ - * {Boolean} Send GetFeatureInfo requests when mouse stops moving. │ │ │ │ - * Default is false. │ │ │ │ - */ │ │ │ │ - hover: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: drillDown │ │ │ │ - * {Boolean} Drill down over all WMS layers in the map. When │ │ │ │ - * using drillDown mode, hover is not possible, and an infoFormat that │ │ │ │ - * returns parseable features is required. Default is false. │ │ │ │ - */ │ │ │ │ - drillDown: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: maxFeatures │ │ │ │ - * {Integer} Maximum number of features to return from a WMS query. This │ │ │ │ - * sets the feature_count parameter on WMS GetFeatureInfo │ │ │ │ - * requests. │ │ │ │ - */ │ │ │ │ - maxFeatures: 10, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: clickCallback │ │ │ │ - * {String} The click callback to register in the │ │ │ │ - * {<OpenLayers.Handler.Click>} object created when the hover │ │ │ │ - * option is set to false. Default is "click". │ │ │ │ - */ │ │ │ │ - clickCallback: "click", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: output │ │ │ │ - * {String} Either "features" or "object". When triggering a getfeatureinfo │ │ │ │ - * request should we pass on an array of features or an object with with │ │ │ │ - * a "features" property and other properties (such as the url of the │ │ │ │ - * WMS). Default is "features". │ │ │ │ - */ │ │ │ │ - output: "features", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: layers │ │ │ │ - * {Array(<OpenLayers.Layer.WMS>)} The layers to query for feature info. │ │ │ │ - * If omitted, all map WMS layers with a url that matches this <url> or │ │ │ │ - * <layerUrls> will be considered. │ │ │ │ - */ │ │ │ │ - layers: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: queryVisible │ │ │ │ - * {Boolean} If true, filter out hidden layers when searching the map for │ │ │ │ - * layers to query. Default is false. │ │ │ │ - */ │ │ │ │ - queryVisible: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: url │ │ │ │ - * {String} The URL of the WMS service to use. If not provided, the url │ │ │ │ - * of the first eligible layer will be used. │ │ │ │ - */ │ │ │ │ - url: null, │ │ │ │ +OpenLayers.Control.ZoomIn = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layerUrls │ │ │ │ - * {Array(String)} Optional list of urls for layers that should be queried. │ │ │ │ - * This can be used when the layer url differs from the url used for │ │ │ │ - * making GetFeatureInfo requests (in the case of a layer using cached │ │ │ │ - * tiles). │ │ │ │ + * Method: trigger │ │ │ │ */ │ │ │ │ - layerUrls: null, │ │ │ │ + trigger: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.zoomIn(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: infoFormat │ │ │ │ - * {String} The mimetype to request from the server. If you are using │ │ │ │ - * drillDown mode and have multiple servers that do not share a common │ │ │ │ - * infoFormat, you can override the control's infoFormat by providing an │ │ │ │ - * INFO_FORMAT parameter in your <OpenLayers.Layer.WMS> instance(s). │ │ │ │ - */ │ │ │ │ - infoFormat: 'text/html', │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomIn" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Events/buttonclick.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: vendorParams │ │ │ │ - * {Object} Additional parameters that will be added to the request, for │ │ │ │ - * WMS implementations that support them. This could e.g. look like │ │ │ │ - * (start code) │ │ │ │ - * { │ │ │ │ - * radius: 5 │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ - */ │ │ │ │ - vendorParams: {}, │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: format │ │ │ │ - * {<OpenLayers.Format>} A format for parsing GetFeatureInfo responses. │ │ │ │ - * Default is <OpenLayers.Format.WMSGetFeatureInfo>. │ │ │ │ - */ │ │ │ │ - format: null, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: formatOptions │ │ │ │ - * {Object} Optional properties to set on the format (if one is not provided │ │ │ │ - * in the <format> property. │ │ │ │ - */ │ │ │ │ - formatOptions: null, │ │ │ │ +/** │ │ │ │ + * 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({ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: handlerOptions │ │ │ │ - * {Object} Additional options for the handlers used by this control, e.g. │ │ │ │ - * (start code) │ │ │ │ - * { │ │ │ │ - * "click": {delay: 100}, │ │ │ │ - * "hover": {delay: 300} │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ + * Property: target │ │ │ │ + * {<OpenLayers.Events>} The events instance that the buttonclick event will │ │ │ │ + * be triggered on. │ │ │ │ */ │ │ │ │ + target: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: handler │ │ │ │ - * {Object} Reference to the <OpenLayers.Handler> for this control │ │ │ │ + * Property: events │ │ │ │ + * {Array} Events to observe and conditionally stop from propagating when │ │ │ │ + * an element with the olButton class (or its olAlphaImg child) is │ │ │ │ + * clicked. │ │ │ │ */ │ │ │ │ - handler: null, │ │ │ │ + events: [ │ │ │ │ + 'mousedown', 'mouseup', 'click', 'dblclick', │ │ │ │ + 'touchstart', 'touchmove', 'touchend', 'keydown' │ │ │ │ + ], │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: hoverRequest │ │ │ │ - * {<OpenLayers.Request>} contains the currently running hover request │ │ │ │ - * (if any). │ │ │ │ + * Property: startRegEx │ │ │ │ + * {RegExp} Regular expression to test Event.type for events that start │ │ │ │ + * a buttonclick sequence. │ │ │ │ */ │ │ │ │ - hoverRequest: null, │ │ │ │ + startRegEx: /^mousedown|touchstart$/, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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>): │ │ │ │ - * beforegetfeatureinfo - Triggered before the request is sent. │ │ │ │ - * The event object has an *xy* property with the position of the │ │ │ │ - * mouse click or hover event that triggers the request. │ │ │ │ - * nogetfeatureinfo - no queryable layers were found. │ │ │ │ - * getfeatureinfo - Triggered when a GetFeatureInfo response is received. │ │ │ │ - * The event object has a *text* property with the body of the │ │ │ │ - * response (String), a *features* property with an array of the │ │ │ │ - * parsed features, an *xy* property with the position of the mouse │ │ │ │ - * click or hover event that triggered the request, and a *request* │ │ │ │ - * property with the request itself. If drillDown is set to true and │ │ │ │ - * multiple requests were issued to collect feature info from all │ │ │ │ - * layers, *text* and *request* will only contain the response body │ │ │ │ - * and request object of the last request. │ │ │ │ + * Property: cancelRegEx │ │ │ │ + * {RegExp} Regular expression to test Event.type for events that cancel │ │ │ │ + * a buttonclick sequence. │ │ │ │ */ │ │ │ │ + cancelRegEx: /^touchmove$/, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: <OpenLayers.Control.WMSGetFeatureInfo> │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ + * Property: completeRegEx │ │ │ │ + * {RegExp} Regular expression to test Event.type for events that complete │ │ │ │ + * a buttonclick sequence. │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.handlerOptions = options.handlerOptions || {}; │ │ │ │ - │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - │ │ │ │ - if (!this.format) { │ │ │ │ - this.format = new OpenLayers.Format.WMSGetFeatureInfo( │ │ │ │ - options.formatOptions │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.drillDown === true) { │ │ │ │ - this.hover = false; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.hover) { │ │ │ │ - this.handler = new OpenLayers.Handler.Hover( │ │ │ │ - this, { │ │ │ │ - 'move': this.cancelHover, │ │ │ │ - 'pause': this.getInfoForHover │ │ │ │ - }, │ │ │ │ - OpenLayers.Util.extend(this.handlerOptions.hover || {}, { │ │ │ │ - 'delay': 250 │ │ │ │ - })); │ │ │ │ - } else { │ │ │ │ - var callbacks = {}; │ │ │ │ - callbacks[this.clickCallback] = this.getInfoForClick; │ │ │ │ - this.handler = new OpenLayers.Handler.Click( │ │ │ │ - this, callbacks, this.handlerOptions.click || {}); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + completeRegEx: /^mouseup|touchend$/, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getInfoForClick │ │ │ │ - * Called on click │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ + * Property: startEvt │ │ │ │ + * {Event} The event that started the click sequence │ │ │ │ */ │ │ │ │ - getInfoForClick: function(evt) { │ │ │ │ - this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ - xy: evt.xy │ │ │ │ - }); │ │ │ │ - // Set the cursor to "wait" to tell the user we're working on their │ │ │ │ - // click. │ │ │ │ - OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - this.request(evt.xy, {}); │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getInfoForHover │ │ │ │ - * Pause callback for the hover handler │ │ │ │ + * 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: │ │ │ │ - * evt - {Object} │ │ │ │ - */ │ │ │ │ - getInfoForHover: function(evt) { │ │ │ │ - this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ - xy: evt.xy │ │ │ │ - }); │ │ │ │ - this.request(evt.xy, { │ │ │ │ - hover: true │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: cancelHover │ │ │ │ - * Cancel callback for the hover handler │ │ │ │ + * target - {<OpenLayers.Events>} The events instance that the buttonclick │ │ │ │ + * event will be triggered on. │ │ │ │ */ │ │ │ │ - cancelHover: function() { │ │ │ │ - if (this.hoverRequest) { │ │ │ │ - this.hoverRequest.abort(); │ │ │ │ - this.hoverRequest = null; │ │ │ │ + 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: findLayers │ │ │ │ - * Internal method to get the layers, independent of whether we are │ │ │ │ - * inspecting the map or using a client-provided array │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - findLayers: function() { │ │ │ │ - │ │ │ │ - var candidates = this.layers || this.map.layers; │ │ │ │ - var layers = []; │ │ │ │ - var layer, url; │ │ │ │ - for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ - layer = candidates[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.WMS && │ │ │ │ - (!this.queryVisible || layer.getVisibility())) { │ │ │ │ - url = OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url; │ │ │ │ - // if the control was not configured with a url, set it │ │ │ │ - // to the first layer url │ │ │ │ - if (this.drillDown === false && !this.url) { │ │ │ │ - this.url = url; │ │ │ │ - } │ │ │ │ - if (this.drillDown === true || this.urlMatches(url)) { │ │ │ │ - layers.push(layer); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + destroy: function() { │ │ │ │ + for (var i = this.events.length - 1; i >= 0; --i) { │ │ │ │ + this.target.unregister(this.events[i], this, this.buttonClick); │ │ │ │ } │ │ │ │ - return layers; │ │ │ │ + delete this.target; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: urlMatches │ │ │ │ - * Test to see if the provided url matches either the control <url> or one │ │ │ │ - * of the <layerUrls>. │ │ │ │ + * Method: getPressedButton │ │ │ │ + * Get the pressed button, if any. Returns undefined if no button │ │ │ │ + * was pressed. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * url - {String} The url to test. │ │ │ │ + * Arguments: │ │ │ │ + * element - {DOMElement} The event target. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} The provided url matches the control <url> or one of the │ │ │ │ - * <layerUrls>. │ │ │ │ - */ │ │ │ │ - urlMatches: function(url) { │ │ │ │ - var matches = OpenLayers.Util.isEquivalentUrl(this.url, url); │ │ │ │ - if (!matches && this.layerUrls) { │ │ │ │ - for (var i = 0, len = this.layerUrls.length; i < len; ++i) { │ │ │ │ - if (OpenLayers.Util.isEquivalentUrl(this.layerUrls[i], url)) { │ │ │ │ - matches = true; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return matches; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: buildWMSOptions │ │ │ │ - * Build an object with the relevant WMS options for the GetFeatureInfo request │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * url - {String} The url to be used for sending the request │ │ │ │ - * layers - {Array(<OpenLayers.Layer.WMS)} An array of layers │ │ │ │ - * clickPosition - {<OpenLayers.Pixel>} The position on the map where the mouse │ │ │ │ - * event occurred. │ │ │ │ - * format - {String} The format from the corresponding GetMap request │ │ │ │ + * {DOMElement} The button element, or undefined. │ │ │ │ */ │ │ │ │ - buildWMSOptions: function(url, layers, clickPosition, format) { │ │ │ │ - var layerNames = [], │ │ │ │ - styleNames = []; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - if (layers[i].params.LAYERS != null) { │ │ │ │ - layerNames = layerNames.concat(layers[i].params.LAYERS); │ │ │ │ - styleNames = styleNames.concat(this.getStyleNames(layers[i])); │ │ │ │ + getPressedButton: function(element) { │ │ │ │ + var depth = 3, // limit the search depth │ │ │ │ + button; │ │ │ │ + do { │ │ │ │ + if (OpenLayers.Element.hasClass(element, "olButton")) { │ │ │ │ + // hit! │ │ │ │ + button = element; │ │ │ │ + break; │ │ │ │ } │ │ │ │ - } │ │ │ │ - var firstLayer = layers[0]; │ │ │ │ - // use the firstLayer's projection if it matches the map projection - │ │ │ │ - // this assumes that all layers will be available in this projection │ │ │ │ - var projection = this.map.getProjection(); │ │ │ │ - var layerProj = firstLayer.projection; │ │ │ │ - if (layerProj && layerProj.equals(this.map.getProjectionObject())) { │ │ │ │ - projection = layerProj.getCode(); │ │ │ │ - } │ │ │ │ - var params = OpenLayers.Util.extend({ │ │ │ │ - service: "WMS", │ │ │ │ - version: firstLayer.params.VERSION, │ │ │ │ - request: "GetFeatureInfo", │ │ │ │ - exceptions: firstLayer.params.EXCEPTIONS, │ │ │ │ - bbox: this.map.getExtent().toBBOX(null, │ │ │ │ - firstLayer.reverseAxisOrder()), │ │ │ │ - feature_count: this.maxFeatures, │ │ │ │ - height: this.map.getSize().h, │ │ │ │ - width: this.map.getSize().w, │ │ │ │ - format: format, │ │ │ │ - info_format: firstLayer.params.INFO_FORMAT || this.infoFormat │ │ │ │ - }, (parseFloat(firstLayer.params.VERSION) >= 1.3) ? { │ │ │ │ - crs: projection, │ │ │ │ - i: parseInt(clickPosition.x), │ │ │ │ - j: parseInt(clickPosition.y) │ │ │ │ - } : { │ │ │ │ - srs: projection, │ │ │ │ - x: parseInt(clickPosition.x), │ │ │ │ - y: parseInt(clickPosition.y) │ │ │ │ - }); │ │ │ │ - if (layerNames.length != 0) { │ │ │ │ - params = OpenLayers.Util.extend({ │ │ │ │ - layers: layerNames, │ │ │ │ - query_layers: layerNames, │ │ │ │ - styles: styleNames │ │ │ │ - }, params); │ │ │ │ - } │ │ │ │ - OpenLayers.Util.applyDefaults(params, this.vendorParams); │ │ │ │ - return { │ │ │ │ - url: url, │ │ │ │ - params: OpenLayers.Util.upperCaseObject(params), │ │ │ │ - callback: function(request) { │ │ │ │ - this.handleResponse(clickPosition, request, url); │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }; │ │ │ │ + element = element.parentNode; │ │ │ │ + } while (--depth > 0 && element); │ │ │ │ + return button; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getStyleNames │ │ │ │ - * Gets the STYLES parameter for the layer. Make sure the STYLES parameter │ │ │ │ - * matches the LAYERS parameter │ │ │ │ + * Method: ignore │ │ │ │ + * Check for event target elements that should be ignored by OpenLayers. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.WMS>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array(String)} The STYLES parameter │ │ │ │ + * element - {DOMElement} The event target. │ │ │ │ */ │ │ │ │ - getStyleNames: function(layer) { │ │ │ │ - // in the event of a WMS layer bundling multiple layers but not │ │ │ │ - // specifying styles,we need the same number of commas to specify │ │ │ │ - // the default style for each of the layers. We can't just leave it │ │ │ │ - // blank as we may be including other layers that do specify styles. │ │ │ │ - var styleNames; │ │ │ │ - if (layer.params.STYLES) { │ │ │ │ - styleNames = layer.params.STYLES; │ │ │ │ - } else { │ │ │ │ - if (OpenLayers.Util.isArray(layer.params.LAYERS)) { │ │ │ │ - styleNames = new Array(layer.params.LAYERS.length); │ │ │ │ - } else { // Assume it's a String │ │ │ │ - styleNames = layer.params.LAYERS.replace(/[^,]/g, ""); │ │ │ │ + ignore: function(element) { │ │ │ │ + var depth = 3, │ │ │ │ + ignore = false; │ │ │ │ + do { │ │ │ │ + if (element.nodeName.toLowerCase() === 'a') { │ │ │ │ + ignore = true; │ │ │ │ + break; │ │ │ │ } │ │ │ │ - } │ │ │ │ - return styleNames; │ │ │ │ + element = element.parentNode; │ │ │ │ + } while (--depth > 0 && element); │ │ │ │ + return ignore; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: request │ │ │ │ - * Sends a GetFeatureInfo request to the WMS │ │ │ │ + * Method: buttonClick │ │ │ │ + * Check if a button was clicked, and fire the buttonclick event │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * clickPosition - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ - * mouse event occurred. │ │ │ │ - * options - {Object} additional options for this method. │ │ │ │ - * │ │ │ │ - * Valid options: │ │ │ │ - * - *hover* {Boolean} true if we do the request for the hover handler │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - request: function(clickPosition, options) { │ │ │ │ - var layers = this.findLayers(); │ │ │ │ - if (layers.length == 0) { │ │ │ │ - this.events.triggerEvent("nogetfeatureinfo"); │ │ │ │ - // Reset the cursor. │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - │ │ │ │ - options = options || {}; │ │ │ │ - if (this.drillDown === false) { │ │ │ │ - var wmsOptions = this.buildWMSOptions(this.url, layers, │ │ │ │ - clickPosition, layers[0].params.FORMAT); │ │ │ │ - var request = OpenLayers.Request.GET(wmsOptions); │ │ │ │ + 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; │ │ │ │ │ │ │ │ - if (options.hover === true) { │ │ │ │ - this.hoverRequest = request; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this._requestCount = 0; │ │ │ │ - this._numRequests = 0; │ │ │ │ - this.features = []; │ │ │ │ - // group according to service url to combine requests │ │ │ │ - var services = {}, │ │ │ │ - url; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - var layer = layers[i]; │ │ │ │ - var service, found = false; │ │ │ │ - url = OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url; │ │ │ │ - if (url in services) { │ │ │ │ - services[url].push(layer); │ │ │ │ - } else { │ │ │ │ - this._numRequests++; │ │ │ │ - services[url] = [layer]; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - } │ │ │ │ - var layers; │ │ │ │ - for (var url in services) { │ │ │ │ - layers = services[url]; │ │ │ │ - var wmsOptions = this.buildWMSOptions(url, layers, │ │ │ │ - clickPosition, layers[0].params.FORMAT); │ │ │ │ - OpenLayers.Request.GET(wmsOptions); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: triggerGetFeatureInfo │ │ │ │ - * Trigger the getfeatureinfo event when all is done │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * request - {XMLHttpRequest} The request object │ │ │ │ - * xy - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ - * mouse event occurred. │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} or │ │ │ │ - * {Array({Object}) when output is "object". The object has a url and a │ │ │ │ - * features property which contains an array of features. │ │ │ │ - */ │ │ │ │ - triggerGetFeatureInfo: function(request, xy, features) { │ │ │ │ - this.events.triggerEvent("getfeatureinfo", { │ │ │ │ - text: request.responseText, │ │ │ │ - features: features, │ │ │ │ - request: request, │ │ │ │ - xy: xy │ │ │ │ - }); │ │ │ │ - │ │ │ │ - // Reset the cursor. │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: handleResponse │ │ │ │ - * Handler for the GetFeatureInfo response. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * xy - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ - * mouse event occurred. │ │ │ │ - * request - {XMLHttpRequest} The request object. │ │ │ │ - * url - {String} The url which was used for this request. │ │ │ │ - */ │ │ │ │ - handleResponse: function(xy, request, url) { │ │ │ │ - │ │ │ │ - var doc = request.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = request.responseText; │ │ │ │ - } │ │ │ │ - var features = this.format.read(doc); │ │ │ │ - if (this.drillDown === false) { │ │ │ │ - this.triggerGetFeatureInfo(request, xy, features); │ │ │ │ - } else { │ │ │ │ - this._requestCount++; │ │ │ │ - if (this.output === "object") { │ │ │ │ - this._features = (this._features || []).concat({ │ │ │ │ - url: url, │ │ │ │ - features: features │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - this._features = (this._features || []).concat(features); │ │ │ │ - } │ │ │ │ - if (this._requestCount === this._numRequests) { │ │ │ │ - this.triggerGetFeatureInfo(request, xy, this._features.concat()); │ │ │ │ - delete this._features; │ │ │ │ - delete this._requestCount; │ │ │ │ - delete this._numRequests; │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.WMSGetFeatureInfo" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/OverviewMap.js │ │ │ │ + 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/BaseTypes.js │ │ │ │ * @requires OpenLayers/Events/buttonclick.js │ │ │ │ - * @requires OpenLayers/Map.js │ │ │ │ - * @requires OpenLayers/Handler/Click.js │ │ │ │ - * @requires OpenLayers/Handler/Drag.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.OverviewMap │ │ │ │ - * The OverMap control creates a small overview map, useful to display the │ │ │ │ - * extent of a zoomed map and your main map and provide additional │ │ │ │ - * navigation options to the User. By default the overview map is drawn in │ │ │ │ - * the lower right corner of the main map. Create a new overview map with the │ │ │ │ - * <OpenLayers.Control.OverviewMap> constructor. │ │ │ │ + * 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.OverviewMap = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: element │ │ │ │ - * {DOMElement} The DOM element that contains the overview map │ │ │ │ - */ │ │ │ │ - element: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: ovmap │ │ │ │ - * {<OpenLayers.Map>} A reference to the overview map itself. │ │ │ │ - */ │ │ │ │ - ovmap: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: size │ │ │ │ - * {<OpenLayers.Size>} The overvew map size in pixels. Note that this is │ │ │ │ - * the size of the map itself - the element that contains the map (default │ │ │ │ - * class name olControlOverviewMapElement) may have padding or other style │ │ │ │ - * attributes added via CSS. │ │ │ │ - */ │ │ │ │ - size: { │ │ │ │ - w: 180, │ │ │ │ - h: 90 │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: layers │ │ │ │ - * {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map. │ │ │ │ - * If none are sent at construction, the base layer for the main map is used. │ │ │ │ - */ │ │ │ │ - layers: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: minRectSize │ │ │ │ - * {Integer} The minimum width or height (in pixels) of the extent │ │ │ │ - * rectangle on the overview map. When the extent rectangle reaches │ │ │ │ - * this size, it will be replaced depending on the value of the │ │ │ │ - * <minRectDisplayClass> property. Default is 15 pixels. │ │ │ │ - */ │ │ │ │ - minRectSize: 15, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: minRectDisplayClass │ │ │ │ - * {String} Replacement style class name for the extent rectangle when │ │ │ │ - * <minRectSize> is reached. This string will be suffixed on to the │ │ │ │ - * displayClass. Default is "RectReplacement". │ │ │ │ - * │ │ │ │ - * Example CSS declaration: │ │ │ │ - * (code) │ │ │ │ - * .olControlOverviewMapRectReplacement { │ │ │ │ - * overflow: hidden; │ │ │ │ - * cursor: move; │ │ │ │ - * background-image: url("img/overview_replacement.gif"); │ │ │ │ - * background-repeat: no-repeat; │ │ │ │ - * background-position: center; │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ - */ │ │ │ │ - minRectDisplayClass: "RectReplacement", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: minRatio │ │ │ │ - * {Float} The ratio of the overview map resolution to the main map │ │ │ │ - * resolution at which to zoom farther out on the overview map. │ │ │ │ - */ │ │ │ │ - minRatio: 8, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: maxRatio │ │ │ │ - * {Float} The ratio of the overview map resolution to the main map │ │ │ │ - * resolution at which to zoom farther in on the overview map. │ │ │ │ - */ │ │ │ │ - maxRatio: 32, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: mapOptions │ │ │ │ - * {Object} An object containing any non-default properties to be sent to │ │ │ │ - * the overview map's map constructor. These should include any │ │ │ │ - * non-default options that the main map was constructed with. │ │ │ │ - */ │ │ │ │ - mapOptions: null, │ │ │ │ - │ │ │ │ +OpenLayers.Control.Panel = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ /** │ │ │ │ - * APIProperty: autoPan │ │ │ │ - * {Boolean} Always pan the overview map, so the extent marker remains in │ │ │ │ - * the center. Default is false. If true, when you drag the extent │ │ │ │ - * marker, the overview map will update itself so the marker returns │ │ │ │ - * to the center. │ │ │ │ + * Property: controls │ │ │ │ + * {Array(<OpenLayers.Control>)} │ │ │ │ */ │ │ │ │ - autoPan: false, │ │ │ │ + controls: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: handlers │ │ │ │ - * {Object} │ │ │ │ + * APIProperty: autoActivate │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * true. │ │ │ │ */ │ │ │ │ - handlers: null, │ │ │ │ + autoActivate: true, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: resolutionFactor │ │ │ │ - * {Object} │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - resolutionFactor: 1, │ │ │ │ + defaultControl: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: maximized │ │ │ │ - * {Boolean} Start as maximized (visible). Defaults to false. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - maximized: false, │ │ │ │ + saveState: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: maximizeTitle │ │ │ │ - * {String} This property is used for showing a tooltip over the │ │ │ │ - * maximize div. Defaults to "" (no title). │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - maximizeTitle: "", │ │ │ │ + allowDepress: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: minimizeTitle │ │ │ │ - * {String} This property is used for showing a tooltip over the │ │ │ │ - * minimize div. Defaults to "" (no title). │ │ │ │ + * Property: activeState │ │ │ │ + * {Object} stores the active state of this panel's controls. │ │ │ │ */ │ │ │ │ - minimizeTitle: "", │ │ │ │ + activeState: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.OverviewMap │ │ │ │ - * Create a new overview map │ │ │ │ + * 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} Properties of this object will be set on the overview │ │ │ │ - * map object. Note, to set options on the map object contained in this │ │ │ │ - * control, set <mapOptions> as one of the options properties. │ │ │ │ + * options - {Object} An optional object whose properties will be used │ │ │ │ + * to extend the control. │ │ │ │ */ │ │ │ │ initialize: function(options) { │ │ │ │ - this.layers = []; │ │ │ │ - this.handlers = {}; │ │ │ │ OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.controls = []; │ │ │ │ + this.activeState = {}; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: destroy │ │ │ │ - * Deconstruct the control │ │ │ │ */ │ │ │ │ destroy: function() { │ │ │ │ - if (!this.mapDiv) { // we've already been destroyed │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - if (this.handlers.click) { │ │ │ │ - this.handlers.click.destroy(); │ │ │ │ - } │ │ │ │ - if (this.handlers.drag) { │ │ │ │ - this.handlers.drag.destroy(); │ │ │ │ - } │ │ │ │ - │ │ │ │ - this.ovmap && this.ovmap.viewPortDiv.removeChild(this.extentRectangle); │ │ │ │ - this.extentRectangle = null; │ │ │ │ - │ │ │ │ - if (this.rectEvents) { │ │ │ │ - this.rectEvents.destroy(); │ │ │ │ - this.rectEvents = null; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.ovmap) { │ │ │ │ - this.ovmap.destroy(); │ │ │ │ - this.ovmap = null; │ │ │ │ - } │ │ │ │ - │ │ │ │ - this.element.removeChild(this.mapDiv); │ │ │ │ - this.mapDiv = null; │ │ │ │ - │ │ │ │ - this.div.removeChild(this.element); │ │ │ │ - this.element = null; │ │ │ │ - │ │ │ │ - if (this.maximizeDiv) { │ │ │ │ - this.div.removeChild(this.maximizeDiv); │ │ │ │ - this.maximizeDiv = null; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.minimizeDiv) { │ │ │ │ - this.div.removeChild(this.minimizeDiv); │ │ │ │ - this.minimizeDiv = null; │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ } │ │ │ │ - │ │ │ │ - this.map.events.un({ │ │ │ │ - buttonclick: this.onButtonClick, │ │ │ │ - moveend: this.update, │ │ │ │ - changebaselayer: this.baseLayerDraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - │ │ │ │ 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: draw │ │ │ │ - * Render the control in the browser. │ │ │ │ + * APIMethod: activate │ │ │ │ */ │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (this.layers.length === 0) { │ │ │ │ - if (this.map.baseLayer) { │ │ │ │ - var layer = this.map.baseLayer.clone(); │ │ │ │ - this.layers = [layer]; │ │ │ │ - } else { │ │ │ │ - this.map.events.register("changebaselayer", this, this.baseLayerDraw); │ │ │ │ - return this.div; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // create overview map DOM elements │ │ │ │ - this.element = document.createElement('div'); │ │ │ │ - this.element.className = this.displayClass + 'Element'; │ │ │ │ - this.element.style.display = 'none'; │ │ │ │ - │ │ │ │ - this.mapDiv = document.createElement('div'); │ │ │ │ - this.mapDiv.style.width = this.size.w + 'px'; │ │ │ │ - this.mapDiv.style.height = this.size.h + 'px'; │ │ │ │ - this.mapDiv.style.position = 'relative'; │ │ │ │ - this.mapDiv.style.overflow = 'hidden'; │ │ │ │ - this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap'); │ │ │ │ - │ │ │ │ - this.extentRectangle = document.createElement('div'); │ │ │ │ - this.extentRectangle.style.position = 'absolute'; │ │ │ │ - this.extentRectangle.style.zIndex = 1000; //HACK │ │ │ │ - this.extentRectangle.className = this.displayClass + 'ExtentRectangle'; │ │ │ │ - │ │ │ │ - this.element.appendChild(this.mapDiv); │ │ │ │ - │ │ │ │ - this.div.appendChild(this.element); │ │ │ │ - │ │ │ │ - // Optionally add min/max buttons if the control will go in the │ │ │ │ - // map viewport. │ │ │ │ - if (!this.outsideViewport) { │ │ │ │ - this.div.className += " " + this.displayClass + 'Container'; │ │ │ │ - // maximize button div │ │ │ │ - var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png'); │ │ │ │ - this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ - this.displayClass + 'MaximizeButton', │ │ │ │ - null, │ │ │ │ - null, │ │ │ │ - img, │ │ │ │ - 'absolute'); │ │ │ │ - this.maximizeDiv.style.display = 'none'; │ │ │ │ - this.maximizeDiv.className = this.displayClass + 'MaximizeButton olButton'; │ │ │ │ - if (this.maximizeTitle) { │ │ │ │ - this.maximizeDiv.title = this.maximizeTitle; │ │ │ │ + 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(); │ │ │ │ + } │ │ │ │ } │ │ │ │ - this.div.appendChild(this.maximizeDiv); │ │ │ │ - │ │ │ │ - // minimize button div │ │ │ │ - var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png'); │ │ │ │ - this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ - 'OpenLayers_Control_minimizeDiv', │ │ │ │ - null, │ │ │ │ - null, │ │ │ │ - img, │ │ │ │ - 'absolute'); │ │ │ │ - this.minimizeDiv.style.display = 'none'; │ │ │ │ - this.minimizeDiv.className = this.displayClass + 'MinimizeButton olButton'; │ │ │ │ - if (this.minimizeTitle) { │ │ │ │ - this.minimizeDiv.title = this.minimizeTitle; │ │ │ │ + if (this.saveState === true) { │ │ │ │ + this.defaultControl = null; │ │ │ │ } │ │ │ │ - this.div.appendChild(this.minimizeDiv); │ │ │ │ - this.minimizeControl(); │ │ │ │ + this.redraw(); │ │ │ │ + return true; │ │ │ │ } else { │ │ │ │ - // show the overview map │ │ │ │ - this.element.style.display = ''; │ │ │ │ - } │ │ │ │ - if (this.map.getExtent()) { │ │ │ │ - this.update(); │ │ │ │ - } │ │ │ │ - │ │ │ │ - this.map.events.on({ │ │ │ │ - buttonclick: this.onButtonClick, │ │ │ │ - moveend: this.update, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - │ │ │ │ - if (this.maximized) { │ │ │ │ - this.maximizeControl(); │ │ │ │ + return false; │ │ │ │ } │ │ │ │ - return this.div; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: baseLayerDraw │ │ │ │ - * Draw the base layer - called if unable to complete in the initial draw │ │ │ │ - */ │ │ │ │ - baseLayerDraw: function() { │ │ │ │ - this.draw(); │ │ │ │ - this.map.events.unregister("changebaselayer", this, this.baseLayerDraw); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: rectDrag │ │ │ │ - * Handle extent rectangle drag │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * px - {<OpenLayers.Pixel>} The pixel location of the drag. │ │ │ │ + * APIMethod: deactivate │ │ │ │ */ │ │ │ │ - rectDrag: function(px) { │ │ │ │ - var deltaX = this.handlers.drag.last.x - px.x; │ │ │ │ - var deltaY = this.handlers.drag.last.y - px.y; │ │ │ │ - if (deltaX != 0 || deltaY != 0) { │ │ │ │ - var rectTop = this.rectPxBounds.top; │ │ │ │ - var rectLeft = this.rectPxBounds.left; │ │ │ │ - var rectHeight = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ - var rectWidth = this.rectPxBounds.getWidth(); │ │ │ │ - // don't allow dragging off of parent element │ │ │ │ - var newTop = Math.max(0, (rectTop - deltaY)); │ │ │ │ - newTop = Math.min(newTop, │ │ │ │ - this.ovmap.size.h - this.hComp - rectHeight); │ │ │ │ - var newLeft = Math.max(0, (rectLeft - deltaX)); │ │ │ │ - newLeft = Math.min(newLeft, │ │ │ │ - this.ovmap.size.w - this.wComp - rectWidth); │ │ │ │ - this.setRectPxBounds(new OpenLayers.Bounds(newLeft, │ │ │ │ - newTop + rectHeight, │ │ │ │ - newLeft + rectWidth, │ │ │ │ - newTop)); │ │ │ │ + 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: mapDivClick │ │ │ │ - * Handle browser events │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} evt │ │ │ │ - */ │ │ │ │ - mapDivClick: function(evt) { │ │ │ │ - var pxCenter = this.rectPxBounds.getCenterPixel(); │ │ │ │ - var deltaX = evt.xy.x - pxCenter.x; │ │ │ │ - var deltaY = evt.xy.y - pxCenter.y; │ │ │ │ - var top = this.rectPxBounds.top; │ │ │ │ - var left = this.rectPxBounds.left; │ │ │ │ - var height = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ - var width = this.rectPxBounds.getWidth(); │ │ │ │ - var newTop = Math.max(0, (top + deltaY)); │ │ │ │ - newTop = Math.min(newTop, this.ovmap.size.h - height); │ │ │ │ - var newLeft = Math.max(0, (left + deltaX)); │ │ │ │ - newLeft = Math.min(newLeft, this.ovmap.size.w - width); │ │ │ │ - this.setRectPxBounds(new OpenLayers.Bounds(newLeft, │ │ │ │ - newTop + height, │ │ │ │ - newLeft + width, │ │ │ │ - newTop)); │ │ │ │ - this.updateMapToRect(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: onButtonClick │ │ │ │ + * Method: draw │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - if (evt.buttonElement === this.minimizeDiv) { │ │ │ │ - this.minimizeControl(); │ │ │ │ - } else if (evt.buttonElement === this.maximizeDiv) { │ │ │ │ - this.maximizeControl(); │ │ │ │ + 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: maximizeControl │ │ │ │ - * Unhide the control. Called when the control is in the map viewport. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {<OpenLayers.Event>} │ │ │ │ + * Method: redraw │ │ │ │ */ │ │ │ │ - maximizeControl: function(e) { │ │ │ │ - this.element.style.display = ''; │ │ │ │ - this.showToggle(false); │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e); │ │ │ │ + redraw: function() { │ │ │ │ + for (var l = this.div.childNodes.length, i = l - 1; i >= 0; i--) { │ │ │ │ + this.div.removeChild(this.div.childNodes[i]); │ │ │ │ } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: minimizeControl │ │ │ │ - * Hide all the contents of the control, shrink the size, │ │ │ │ - * add the maximize icon │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {<OpenLayers.Event>} │ │ │ │ - */ │ │ │ │ - minimizeControl: function(e) { │ │ │ │ - this.element.style.display = 'none'; │ │ │ │ - this.showToggle(true); │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e); │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: showToggle │ │ │ │ - * Hide/Show the toggle depending on whether the control is minimized │ │ │ │ + * APIMethod: activateControl │ │ │ │ + * This method is called when the user click on the icon representing a │ │ │ │ + * control in the panel. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * minimize - {Boolean} │ │ │ │ + * control - {<OpenLayers.Control>} │ │ │ │ */ │ │ │ │ - showToggle: function(minimize) { │ │ │ │ - if (this.maximizeDiv) { │ │ │ │ - this.maximizeDiv.style.display = minimize ? '' : 'none'; │ │ │ │ + activateControl: function(control) { │ │ │ │ + if (!this.active) { │ │ │ │ + return false; │ │ │ │ } │ │ │ │ - if (this.minimizeDiv) { │ │ │ │ - this.minimizeDiv.style.display = minimize ? 'none' : ''; │ │ │ │ + if (control.type == OpenLayers.Control.TYPE_BUTTON) { │ │ │ │ + control.trigger(); │ │ │ │ + return; │ │ │ │ } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: update │ │ │ │ - * Update the overview map after layers move. │ │ │ │ - */ │ │ │ │ - update: function() { │ │ │ │ - if (this.ovmap == null) { │ │ │ │ - this.createMap(); │ │ │ │ + if (control.type == OpenLayers.Control.TYPE_TOGGLE) { │ │ │ │ + if (control.active) { │ │ │ │ + control.deactivate(); │ │ │ │ + } else { │ │ │ │ + control.activate(); │ │ │ │ + } │ │ │ │ + return; │ │ │ │ } │ │ │ │ - │ │ │ │ - if (this.autoPan || !this.isSuitableOverview()) { │ │ │ │ - this.updateOverview(); │ │ │ │ + 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(); │ │ │ │ } │ │ │ │ - │ │ │ │ - // update extent rectangle │ │ │ │ - this.updateRectToMap(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: isSuitableOverview │ │ │ │ - * Determines if the overview map is suitable given the extent and │ │ │ │ - * resolution of the main map. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - isSuitableOverview: function() { │ │ │ │ - var mapExtent = this.map.getExtent(); │ │ │ │ - var maxExtent = this.map.getMaxExtent(); │ │ │ │ - var testExtent = new OpenLayers.Bounds( │ │ │ │ - Math.max(mapExtent.left, maxExtent.left), │ │ │ │ - Math.max(mapExtent.bottom, maxExtent.bottom), │ │ │ │ - Math.min(mapExtent.right, maxExtent.right), │ │ │ │ - Math.min(mapExtent.top, maxExtent.top)); │ │ │ │ - │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - testExtent = testExtent.transform( │ │ │ │ - this.map.getProjectionObject(), │ │ │ │ - this.ovmap.getProjectionObject()); │ │ │ │ + addControls: function(controls) { │ │ │ │ + if (!(OpenLayers.Util.isArray(controls))) { │ │ │ │ + controls = [controls]; │ │ │ │ } │ │ │ │ + this.controls = this.controls.concat(controls); │ │ │ │ │ │ │ │ - var resRatio = this.ovmap.getResolution() / this.map.getResolution(); │ │ │ │ - return ((resRatio > this.minRatio) && │ │ │ │ - (resRatio <= this.maxRatio) && │ │ │ │ - (this.ovmap.getExtent().containsBounds(testExtent))); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method updateOverview │ │ │ │ - * Called by <update> if <isSuitableOverview> returns true │ │ │ │ - */ │ │ │ │ - updateOverview: function() { │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ - var targetRes = this.ovmap.getResolution(); │ │ │ │ - var resRatio = targetRes / mapRes; │ │ │ │ - if (resRatio > this.maxRatio) { │ │ │ │ - // zoom in overview map │ │ │ │ - targetRes = this.minRatio * mapRes; │ │ │ │ - } else if (resRatio <= this.minRatio) { │ │ │ │ - // zoom out overview map │ │ │ │ - targetRes = this.maxRatio * mapRes; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - var center; │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - center = this.map.center.clone(); │ │ │ │ - center.transform(this.map.getProjectionObject(), │ │ │ │ - this.ovmap.getProjectionObject()); │ │ │ │ - } else { │ │ │ │ - center = this.map.center; │ │ │ │ + │ │ │ │ + if (this.map) { // map.addControl() has already been called on the panel │ │ │ │ + this.addControlsToMap(controls); │ │ │ │ + this.redraw(); │ │ │ │ } │ │ │ │ - this.ovmap.setCenter(center, this.ovmap.getZoomForResolution( │ │ │ │ - targetRes * this.resolutionFactor)); │ │ │ │ - this.updateRectToMap(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createMap │ │ │ │ - * Construct the map that this control contains │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - createMap: function() { │ │ │ │ - // create the overview map │ │ │ │ - var options = OpenLayers.Util.extend({ │ │ │ │ - controls: [], │ │ │ │ - maxResolution: 'auto', │ │ │ │ - fallThrough: false │ │ │ │ - }, this.mapOptions); │ │ │ │ - this.ovmap = new OpenLayers.Map(this.mapDiv, options); │ │ │ │ - this.ovmap.viewPortDiv.appendChild(this.extentRectangle); │ │ │ │ - │ │ │ │ - // prevent ovmap from being destroyed when the page unloads, because │ │ │ │ - // the OverviewMap control has to do this (and does it). │ │ │ │ - OpenLayers.Event.stopObserving(window, 'unload', this.ovmap.unloadDestroy); │ │ │ │ - │ │ │ │ - this.ovmap.addLayers(this.layers); │ │ │ │ - this.ovmap.zoomToMaxExtent(); │ │ │ │ - // check extent rectangle border width │ │ │ │ - this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ - 'border-left-width')) + │ │ │ │ - parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ - 'border-right-width')); │ │ │ │ - this.wComp = (this.wComp) ? this.wComp : 2; │ │ │ │ - this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ - 'border-top-width')) + │ │ │ │ - parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ - 'border-bottom-width')); │ │ │ │ - this.hComp = (this.hComp) ? this.hComp : 2; │ │ │ │ - │ │ │ │ - this.handlers.drag = new OpenLayers.Handler.Drag( │ │ │ │ - this, { │ │ │ │ - move: this.rectDrag, │ │ │ │ - done: this.updateMapToRect │ │ │ │ - }, { │ │ │ │ - map: this.ovmap │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - this.handlers.click = new OpenLayers.Handler.Click( │ │ │ │ - this, { │ │ │ │ - "click": this.mapDivClick │ │ │ │ - }, { │ │ │ │ - "single": true, │ │ │ │ - "double": false, │ │ │ │ - "stopSingle": true, │ │ │ │ - "stopDouble": true, │ │ │ │ - "pixelTolerance": 1, │ │ │ │ - map: this.ovmap │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - this.handlers.click.activate(); │ │ │ │ - │ │ │ │ - this.rectEvents = new OpenLayers.Events(this, this.extentRectangle, │ │ │ │ - null, true); │ │ │ │ - this.rectEvents.register("mouseover", this, function(e) { │ │ │ │ - if (!this.handlers.drag.active && !this.map.dragging) { │ │ │ │ - this.handlers.drag.activate(); │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.rectEvents.register("mouseout", this, function(e) { │ │ │ │ - if (!this.handlers.drag.dragging) { │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - var sourceUnits = this.map.getProjectionObject().getUnits() || │ │ │ │ - this.map.units || this.map.baseLayer.units; │ │ │ │ - var targetUnits = this.ovmap.getProjectionObject().getUnits() || │ │ │ │ - this.ovmap.units || this.ovmap.baseLayer.units; │ │ │ │ - this.resolutionFactor = sourceUnits && targetUnits ? │ │ │ │ - OpenLayers.INCHES_PER_UNIT[sourceUnits] / │ │ │ │ - OpenLayers.INCHES_PER_UNIT[targetUnits] : 1; │ │ │ │ - } │ │ │ │ + createControlMarkup: function(control) { │ │ │ │ + return document.createElement("div"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: updateRectToMap │ │ │ │ - * Updates the extent rectangle position and size to match the map extent │ │ │ │ + * Method: addControlsToMap │ │ │ │ + * Only for internal use in draw() and addControls() methods. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * controls - {Array(<OpenLayers.Control>)} Controls to add into map. │ │ │ │ */ │ │ │ │ - updateRectToMap: function() { │ │ │ │ - // If the projections differ we need to reproject │ │ │ │ - var bounds; │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - bounds = this.map.getExtent().transform( │ │ │ │ - this.map.getProjectionObject(), │ │ │ │ - this.ovmap.getProjectionObject()); │ │ │ │ - } else { │ │ │ │ - bounds = this.map.getExtent(); │ │ │ │ - } │ │ │ │ - var pxBounds = this.getRectBoundsFromMapBounds(bounds); │ │ │ │ - if (pxBounds) { │ │ │ │ - this.setRectPxBounds(pxBounds); │ │ │ │ + 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: updateMapToRect │ │ │ │ - * Updates the map extent to match the extent rectangle position and size │ │ │ │ + * Method: iconOn │ │ │ │ + * Internal use, for use only with "controls[i].events.on/un". │ │ │ │ */ │ │ │ │ - updateMapToRect: function() { │ │ │ │ - var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds); │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - lonLatBounds = lonLatBounds.transform( │ │ │ │ - this.ovmap.getProjectionObject(), │ │ │ │ - this.map.getProjectionObject()); │ │ │ │ - } │ │ │ │ - this.map.panTo(lonLatBounds.getCenterLonLat()); │ │ │ │ + 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: setRectPxBounds │ │ │ │ - * Set extent rectangle pixel bounds. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * pxBounds - {<OpenLayers.Bounds>} │ │ │ │ + * Method: iconOff │ │ │ │ + * Internal use, for use only with "controls[i].events.on/un". │ │ │ │ */ │ │ │ │ - setRectPxBounds: function(pxBounds) { │ │ │ │ - var top = Math.max(pxBounds.top, 0); │ │ │ │ - var left = Math.max(pxBounds.left, 0); │ │ │ │ - var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()), │ │ │ │ - this.ovmap.size.h - this.hComp); │ │ │ │ - var right = Math.min(pxBounds.left + pxBounds.getWidth(), │ │ │ │ - this.ovmap.size.w - this.wComp); │ │ │ │ - var width = Math.max(right - left, 0); │ │ │ │ - var height = Math.max(bottom - top, 0); │ │ │ │ - if (width < this.minRectSize || height < this.minRectSize) { │ │ │ │ - this.extentRectangle.className = this.displayClass + │ │ │ │ - this.minRectDisplayClass; │ │ │ │ - var rLeft = left + (width / 2) - (this.minRectSize / 2); │ │ │ │ - var rTop = top + (height / 2) - (this.minRectSize / 2); │ │ │ │ - this.extentRectangle.style.top = Math.round(rTop) + 'px'; │ │ │ │ - this.extentRectangle.style.left = Math.round(rLeft) + 'px'; │ │ │ │ - this.extentRectangle.style.height = this.minRectSize + 'px'; │ │ │ │ - this.extentRectangle.style.width = this.minRectSize + 'px'; │ │ │ │ - } else { │ │ │ │ - this.extentRectangle.className = this.displayClass + │ │ │ │ - 'ExtentRectangle'; │ │ │ │ - this.extentRectangle.style.top = Math.round(top) + 'px'; │ │ │ │ - this.extentRectangle.style.left = Math.round(left) + 'px'; │ │ │ │ - this.extentRectangle.style.height = Math.round(height) + 'px'; │ │ │ │ - this.extentRectangle.style.width = Math.round(width) + 'px'; │ │ │ │ - } │ │ │ │ - this.rectPxBounds = new OpenLayers.Bounds( │ │ │ │ - Math.round(left), Math.round(bottom), │ │ │ │ - Math.round(right), Math.round(top) │ │ │ │ - ); │ │ │ │ + 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: getRectBoundsFromMapBounds │ │ │ │ - * Get the rect bounds from the map bounds. │ │ │ │ + * Method: onButtonClick │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * lonLatBounds - {<OpenLayers.Bounds>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent │ │ │ │ - * translated into pixel bounds for the overview map │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - getRectBoundsFromMapBounds: function(lonLatBounds) { │ │ │ │ - var leftBottomPx = this.getOverviewPxFromLonLat({ │ │ │ │ - lon: lonLatBounds.left, │ │ │ │ - lat: lonLatBounds.bottom │ │ │ │ - }); │ │ │ │ - var rightTopPx = this.getOverviewPxFromLonLat({ │ │ │ │ - lon: lonLatBounds.right, │ │ │ │ - lat: lonLatBounds.top │ │ │ │ - }); │ │ │ │ - var bounds = null; │ │ │ │ - if (leftBottomPx && rightTopPx) { │ │ │ │ - bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y, │ │ │ │ - rightTopPx.x, rightTopPx.y); │ │ │ │ + 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; │ │ │ │ + } │ │ │ │ } │ │ │ │ - return bounds; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getMapBoundsFromRectBounds │ │ │ │ - * Get the map bounds from the rect bounds. │ │ │ │ + * APIMethod: getControlsBy │ │ │ │ + * Get a list of controls with properties matching the given criteria. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * pxBounds - {<OpenLayers.Bounds>} │ │ │ │ + * 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: │ │ │ │ - * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds │ │ │ │ - * translated into lon/lat bounds for the overview map │ │ │ │ + * {Array(<OpenLayers.Control>)} A list of controls matching the given criteria. │ │ │ │ + * An empty array is returned if no matches are found. │ │ │ │ */ │ │ │ │ - getMapBoundsFromRectBounds: function(pxBounds) { │ │ │ │ - var leftBottomLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ - x: pxBounds.left, │ │ │ │ - y: pxBounds.bottom │ │ │ │ - }); │ │ │ │ - var rightTopLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ - x: pxBounds.right, │ │ │ │ - y: pxBounds.top │ │ │ │ + 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 new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat, │ │ │ │ - rightTopLonLat.lon, rightTopLonLat.lat); │ │ │ │ + return found; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getLonLatFromOverviewPx │ │ │ │ - * Get a map location from a pixel location │ │ │ │ + * APIMethod: getControlsByName │ │ │ │ + * Get a list of contorls with names matching the given name. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * overviewMapPx - {<OpenLayers.Pixel>|Object} OpenLayers.Pixel or │ │ │ │ - * an object with a │ │ │ │ - * 'x' and 'y' properties. │ │ │ │ + * 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: │ │ │ │ - * {Object} Location which is the passed-in overview map │ │ │ │ - * OpenLayers.Pixel, translated into lon/lat by the overview │ │ │ │ - * map. An object with a 'lon' and 'lat' properties. │ │ │ │ + * {Array(<OpenLayers.Control>)} A list of controls matching the given name. │ │ │ │ + * An empty array is returned if no matches are found. │ │ │ │ */ │ │ │ │ - getLonLatFromOverviewPx: function(overviewMapPx) { │ │ │ │ - var size = this.ovmap.size; │ │ │ │ - var res = this.ovmap.getResolution(); │ │ │ │ - var center = this.ovmap.getExtent().getCenterLonLat(); │ │ │ │ - │ │ │ │ - var deltaX = overviewMapPx.x - (size.w / 2); │ │ │ │ - var deltaY = overviewMapPx.y - (size.h / 2); │ │ │ │ - │ │ │ │ - return { │ │ │ │ - lon: center.lon + deltaX * res, │ │ │ │ - lat: center.lat - deltaY * res │ │ │ │ - }; │ │ │ │ + getControlsByName: function(match) { │ │ │ │ + return this.getControlsBy("name", match); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getOverviewPxFromLonLat │ │ │ │ - * Get a pixel location from a map location │ │ │ │ + * APIMethod: getControlsByClass │ │ │ │ + * Get a list of controls of a given type (CLASS_NAME). │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * lonlat - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an │ │ │ │ - * object with a 'lon' and 'lat' properties. │ │ │ │ + * 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: │ │ │ │ - * {Object} Location which is the passed-in OpenLayers.LonLat, │ │ │ │ - * translated into overview map pixels │ │ │ │ + * {Array(<OpenLayers.Control>)} A list of controls matching the given type. │ │ │ │ + * An empty array is returned if no matches are found. │ │ │ │ */ │ │ │ │ - getOverviewPxFromLonLat: function(lonlat) { │ │ │ │ - var res = this.ovmap.getResolution(); │ │ │ │ - var extent = this.ovmap.getExtent(); │ │ │ │ - if (extent) { │ │ │ │ - return { │ │ │ │ - x: Math.round(1 / res * (lonlat.lon - extent.left)), │ │ │ │ - y: Math.round(1 / res * (extent.top - lonlat.lat)) │ │ │ │ - }; │ │ │ │ - } │ │ │ │ + getControlsByClass: function(match) { │ │ │ │ + return this.getControlsBy("CLASS_NAME", match); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: 'OpenLayers.Control.OverviewMap' │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Panel" │ │ │ │ }); │ │ │ │ + │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Scale.js │ │ │ │ + OpenLayers/Control/PanZoom.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/Lang.js │ │ │ │ + * @requires OpenLayers/Events/buttonclick.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Scale │ │ │ │ - * The Scale control displays the current map scale as a ratio (e.g. Scale = │ │ │ │ - * 1:1M). By default it is displayed in the lower right corner of the map. │ │ │ │ + * Class: OpenLayers.Control.PanZoom │ │ │ │ + * The PanZoom is a visible control, composed of a │ │ │ │ + * <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomPanel>. By │ │ │ │ + * default it is drawn in the upper left corner of the map. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.Scale = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: element │ │ │ │ - * {DOMElement} │ │ │ │ + /** │ │ │ │ + * APIProperty: slideFactor │ │ │ │ + * {Integer} Number of pixels by which we'll pan the map in any direction │ │ │ │ + * on clicking the arrow buttons. If you want to pan by some ratio │ │ │ │ + * of the map dimensions, use <slideRatio> instead. │ │ │ │ */ │ │ │ │ - element: null, │ │ │ │ + slideFactor: 50, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: geodesic │ │ │ │ - * {Boolean} Use geodesic measurement. Default is false. The recommended │ │ │ │ - * setting for maps in EPSG:4326 is false, and true EPSG:900913. If set to │ │ │ │ - * true, the scale will be calculated based on the horizontal size of the │ │ │ │ - * pixel in the center of the map viewport. │ │ │ │ + /** │ │ │ │ + * APIProperty: slideRatio │ │ │ │ + * {Number} The fraction of map width/height by which we'll pan the map │ │ │ │ + * on clicking the arrow buttons. Default is null. If set, will │ │ │ │ + * override <slideFactor>. E.g. if slideRatio is .5, then the Pan Up │ │ │ │ + * button will pan up half the map height. │ │ │ │ */ │ │ │ │ - geodesic: false, │ │ │ │ + slideRatio: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: buttons │ │ │ │ + * {Array(DOMElement)} Array of Button Divs │ │ │ │ + */ │ │ │ │ + buttons: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: position │ │ │ │ + * {<OpenLayers.Pixel>} │ │ │ │ + */ │ │ │ │ + position: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.Scale │ │ │ │ + * Constructor: OpenLayers.Control.PanZoom │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * element - {DOMElement} │ │ │ │ - * options - {Object} │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ - initialize: function(element, options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.element = OpenLayers.Util.getElement(element); │ │ │ │ + initialize: function(options) { │ │ │ │ + this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X, │ │ │ │ + OpenLayers.Control.PanZoom.Y); │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ + } │ │ │ │ + this.removeButtons(); │ │ │ │ + this.buttons = null; │ │ │ │ + this.position = null; │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ + * │ │ │ │ + * Properties: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + this.map.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * Method: draw │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * px - {<OpenLayers.Pixel>} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * {DOMElement} A reference to the container div for the PanZoom control. │ │ │ │ */ │ │ │ │ - draw: function() { │ │ │ │ + draw: function(px) { │ │ │ │ + // initialize our internal div │ │ │ │ OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (!this.element) { │ │ │ │ - this.element = document.createElement("div"); │ │ │ │ - this.div.appendChild(this.element); │ │ │ │ - } │ │ │ │ - this.map.events.register('moveend', this, this.updateScale); │ │ │ │ - this.updateScale(); │ │ │ │ + px = this.position; │ │ │ │ + │ │ │ │ + // place the controls │ │ │ │ + this.buttons = []; │ │ │ │ + │ │ │ │ + var sz = { │ │ │ │ + w: 18, │ │ │ │ + h: 18 │ │ │ │ + }; │ │ │ │ + var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ + │ │ │ │ + this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ + px.y = centered.y + sz.h; │ │ │ │ + this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ + this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz); │ │ │ │ + this._addButton("pandown", "south-mini.png", │ │ │ │ + centered.add(0, sz.h * 2), sz); │ │ │ │ + this._addButton("zoomin", "zoom-plus-mini.png", │ │ │ │ + centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ + this._addButton("zoomworld", "zoom-world-mini.png", │ │ │ │ + centered.add(0, sz.h * 4 + 5), sz); │ │ │ │ + this._addButton("zoomout", "zoom-minus-mini.png", │ │ │ │ + centered.add(0, sz.h * 5 + 5), sz); │ │ │ │ return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: updateScale │ │ │ │ + * Method: _addButton │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * id - {String} │ │ │ │ + * img - {String} │ │ │ │ + * xy - {<OpenLayers.Pixel>} │ │ │ │ + * sz - {<OpenLayers.Size>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A Div (an alphaImageDiv, to be precise) that contains the │ │ │ │ + * image of the button, and has all the proper event handlers set. │ │ │ │ */ │ │ │ │ - updateScale: function() { │ │ │ │ - var scale; │ │ │ │ - if (this.geodesic === true) { │ │ │ │ - var units = this.map.getUnits(); │ │ │ │ - if (!units) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - var inches = OpenLayers.INCHES_PER_UNIT; │ │ │ │ - scale = (this.map.getGeodesicPixelSize().w || 0.000001) * │ │ │ │ - inches["km"] * OpenLayers.DOTS_PER_INCH; │ │ │ │ - } else { │ │ │ │ - scale = this.map.getScale(); │ │ │ │ - } │ │ │ │ + _addButton: function(id, img, xy, sz) { │ │ │ │ + var imgLocation = OpenLayers.Util.getImageLocation(img); │ │ │ │ + var btn = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ + this.id + "_" + id, │ │ │ │ + xy, sz, imgLocation, "absolute"); │ │ │ │ + btn.style.cursor = "pointer"; │ │ │ │ + //we want to add the outer div │ │ │ │ + this.div.appendChild(btn); │ │ │ │ + btn.action = id; │ │ │ │ + btn.className = "olButton"; │ │ │ │ │ │ │ │ - if (!scale) { │ │ │ │ - return; │ │ │ │ + //we want to remember/reference the outer div │ │ │ │ + this.buttons.push(btn); │ │ │ │ + return btn; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: _removeButton │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * btn - {Object} │ │ │ │ + */ │ │ │ │ + _removeButton: function(btn) { │ │ │ │ + this.div.removeChild(btn); │ │ │ │ + OpenLayers.Util.removeItem(this.buttons, btn); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: removeButtons │ │ │ │ + */ │ │ │ │ + removeButtons: function() { │ │ │ │ + for (var i = this.buttons.length - 1; i >= 0; --i) { │ │ │ │ + this._removeButton(this.buttons[i]); │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (scale >= 9500 && scale <= 950000) { │ │ │ │ - scale = Math.round(scale / 1000) + "K"; │ │ │ │ - } else if (scale >= 950000) { │ │ │ │ - scale = Math.round(scale / 1000000) + "M"; │ │ │ │ - } else { │ │ │ │ - scale = Math.round(scale); │ │ │ │ + /** │ │ │ │ + * Method: onButtonClick │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ + */ │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + var btn = evt.buttonElement; │ │ │ │ + switch (btn.action) { │ │ │ │ + case "panup": │ │ │ │ + this.map.pan(0, -this.getSlideFactor("h")); │ │ │ │ + break; │ │ │ │ + case "pandown": │ │ │ │ + this.map.pan(0, this.getSlideFactor("h")); │ │ │ │ + break; │ │ │ │ + case "panleft": │ │ │ │ + this.map.pan(-this.getSlideFactor("w"), 0); │ │ │ │ + break; │ │ │ │ + case "panright": │ │ │ │ + this.map.pan(this.getSlideFactor("w"), 0); │ │ │ │ + break; │ │ │ │ + case "zoomin": │ │ │ │ + this.map.zoomIn(); │ │ │ │ + break; │ │ │ │ + case "zoomout": │ │ │ │ + this.map.zoomOut(); │ │ │ │ + break; │ │ │ │ + case "zoomworld": │ │ │ │ + this.map.zoomToMaxExtent(); │ │ │ │ + break; │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - this.element.innerHTML = OpenLayers.i18n("Scale = 1 : ${scaleDenom}", { │ │ │ │ - 'scaleDenom': scale │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * Method: getSlideFactor │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * dim - {String} "w" or "h" (for width or height). │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Number} The slide factor for panning in the requested direction. │ │ │ │ + */ │ │ │ │ + getSlideFactor: function(dim) { │ │ │ │ + return this.slideRatio ? │ │ │ │ + this.map.getSize()[dim] * this.slideRatio : │ │ │ │ + this.slideFactor; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Scale" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.PanZoom" │ │ │ │ }); │ │ │ │ │ │ │ │ +/** │ │ │ │ + * Constant: X │ │ │ │ + * {Integer} │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.PanZoom.X = 4; │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Constant: Y │ │ │ │ + * {Integer} │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.PanZoom.Y = 4; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Graticule.js │ │ │ │ + OpenLayers/Control/PanZoomBar.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/Lang.js │ │ │ │ - * @requires OpenLayers/Rule.js │ │ │ │ - * @requires OpenLayers/StyleMap.js │ │ │ │ - * @requires OpenLayers/Layer/Vector.js │ │ │ │ + * @requires OpenLayers/Control/PanZoom.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Graticule │ │ │ │ - * The Graticule displays a grid of latitude/longitude lines reprojected on │ │ │ │ - * the map. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Control.PanZoomBar │ │ │ │ + * The PanZoomBar is a visible control composed of a │ │ │ │ + * <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomBar>. │ │ │ │ + * By default it is displayed in the upper left corner of the map as 4 │ │ │ │ + * directional arrows above a vertical slider. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - * │ │ │ │ + * - <OpenLayers.Control.PanZoom> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.Graticule = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Control.PanZoomBar = OpenLayers.Class(OpenLayers.Control.PanZoom, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ + /** │ │ │ │ + * APIProperty: zoomStopWidth │ │ │ │ */ │ │ │ │ - autoActivate: true, │ │ │ │ + zoomStopWidth: 18, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: intervals │ │ │ │ - * {Array(Float)} A list of possible graticule widths in degrees. │ │ │ │ + /** │ │ │ │ + * APIProperty: zoomStopHeight │ │ │ │ */ │ │ │ │ - intervals: [45, 30, 20, 10, 5, 2, 1, │ │ │ │ - 0.5, 0.2, 0.1, 0.05, 0.01, │ │ │ │ - 0.005, 0.002, 0.001 │ │ │ │ - ], │ │ │ │ + zoomStopHeight: 11, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: displayInLayerSwitcher │ │ │ │ - * {Boolean} Allows the Graticule control to be switched on and off by │ │ │ │ - * LayerSwitcher control. Defaults is true. │ │ │ │ + /** │ │ │ │ + * Property: slider │ │ │ │ */ │ │ │ │ - displayInLayerSwitcher: true, │ │ │ │ + slider: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: visible │ │ │ │ - * {Boolean} should the graticule be initially visible (default=true) │ │ │ │ + /** │ │ │ │ + * Property: sliderEvents │ │ │ │ + * {<OpenLayers.Events>} │ │ │ │ */ │ │ │ │ - visible: true, │ │ │ │ + sliderEvents: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: numPoints │ │ │ │ - * {Integer} The number of points to use in each graticule line. Higher │ │ │ │ - * numbers result in a smoother curve for projected maps │ │ │ │ + /** │ │ │ │ + * Property: zoombarDiv │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - numPoints: 50, │ │ │ │ + zoombarDiv: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: zoomWorldIcon │ │ │ │ + * {Boolean} │ │ │ │ + */ │ │ │ │ + zoomWorldIcon: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: targetSize │ │ │ │ - * {Integer} The maximum size of the grid in pixels on the map │ │ │ │ + * APIProperty: panIcons │ │ │ │ + * {Boolean} Set this property to false not to display the pan icons. If │ │ │ │ + * false the zoom world icon is placed under the zoom bar. Defaults to │ │ │ │ + * true. │ │ │ │ */ │ │ │ │ - targetSize: 200, │ │ │ │ + panIcons: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: layerName │ │ │ │ - * {String} The name to be displayed in the layer switcher, default is set │ │ │ │ - * by {<OpenLayers.Lang>}. │ │ │ │ + * APIProperty: forceFixedZoomLevel │ │ │ │ + * {Boolean} Force a fixed zoom level even though the map has │ │ │ │ + * fractionalZoom │ │ │ │ */ │ │ │ │ - layerName: null, │ │ │ │ + forceFixedZoomLevel: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: labelled │ │ │ │ - * {Boolean} Should the graticule lines be labelled?. default=true │ │ │ │ + * Property: mouseDragStart │ │ │ │ + * {<OpenLayers.Pixel>} │ │ │ │ */ │ │ │ │ - labelled: true, │ │ │ │ + mouseDragStart: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: labelFormat │ │ │ │ - * {String} the format of the labels, default = 'dm'. See │ │ │ │ - * <OpenLayers.Util.getFormattedLonLat> for other options. │ │ │ │ + * Property: deltaY │ │ │ │ + * {Number} The cumulative vertical pixel offset during a zoom bar drag. │ │ │ │ */ │ │ │ │ - labelFormat: 'dm', │ │ │ │ + deltaY: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: lineSymbolizer │ │ │ │ - * {symbolizer} the symbolizer used to render lines │ │ │ │ + * Property: zoomStart │ │ │ │ + * {<OpenLayers.Pixel>} │ │ │ │ */ │ │ │ │ - lineSymbolizer: { │ │ │ │ - strokeColor: "#333", │ │ │ │ - strokeWidth: 1, │ │ │ │ - strokeOpacity: 0.5 │ │ │ │ - }, │ │ │ │ + zoomStart: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: labelSymbolizer │ │ │ │ - * {symbolizer} the symbolizer used to render labels │ │ │ │ + * Constructor: OpenLayers.Control.PanZoomBar │ │ │ │ */ │ │ │ │ - labelSymbolizer: {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: gratLayer │ │ │ │ - * {<OpenLayers.Layer.Vector>} vector layer used to draw the graticule on │ │ │ │ + * APIMethod: destroy │ │ │ │ */ │ │ │ │ - gratLayer: null, │ │ │ │ + destroy: function() { │ │ │ │ + │ │ │ │ + this._removeZoomBar(); │ │ │ │ + │ │ │ │ + this.map.events.un({ │ │ │ │ + "changebaselayer": this.redraw, │ │ │ │ + "updatesize": this.redraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + │ │ │ │ + OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments); │ │ │ │ + │ │ │ │ + delete this.mouseDragStart; │ │ │ │ + delete this.zoomStart; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.Graticule │ │ │ │ - * Create a new graticule control to display a grid of latitude longitude │ │ │ │ - * lines. │ │ │ │ + * Method: setMap │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be used │ │ │ │ - * to extend the control. │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.layerName = options.layerName || OpenLayers.i18n("Graticule"); │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - │ │ │ │ - this.labelSymbolizer.stroke = false; │ │ │ │ - this.labelSymbolizer.fill = false; │ │ │ │ - this.labelSymbolizer.label = "${label}"; │ │ │ │ - this.labelSymbolizer.labelAlign = "${labelAlign}"; │ │ │ │ - this.labelSymbolizer.labelXOffset = "${xOffset}"; │ │ │ │ - this.labelSymbolizer.labelYOffset = "${yOffset}"; │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments); │ │ │ │ + this.map.events.on({ │ │ │ │ + "changebaselayer": this.redraw, │ │ │ │ + "updatesize": this.redraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ + /** │ │ │ │ + * Method: redraw │ │ │ │ + * clear the div and start over. │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - if (this.gratLayer) { │ │ │ │ - this.gratLayer.destroy(); │ │ │ │ - this.gratLayer = null; │ │ │ │ + redraw: function() { │ │ │ │ + if (this.div != null) { │ │ │ │ + this.removeButtons(); │ │ │ │ + this._removeZoomBar(); │ │ │ │ } │ │ │ │ + this.draw(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: draw │ │ │ │ + * Method: draw │ │ │ │ * │ │ │ │ - * initializes the graticule layer and does the initial update │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * Parameters: │ │ │ │ + * px - {<OpenLayers.Pixel>} │ │ │ │ */ │ │ │ │ - draw: function() { │ │ │ │ + draw: function(px) { │ │ │ │ + // initialize our internal div │ │ │ │ OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (!this.gratLayer) { │ │ │ │ - var gratStyle = new OpenLayers.Style({}, { │ │ │ │ - rules: [new OpenLayers.Rule({ │ │ │ │ - 'symbolizer': { │ │ │ │ - "Point": this.labelSymbolizer, │ │ │ │ - "Line": this.lineSymbolizer │ │ │ │ - } │ │ │ │ - })] │ │ │ │ - }); │ │ │ │ - this.gratLayer = new OpenLayers.Layer.Vector(this.layerName, { │ │ │ │ - styleMap: new OpenLayers.StyleMap({ │ │ │ │ - 'default': gratStyle │ │ │ │ - }), │ │ │ │ - visibility: this.visible, │ │ │ │ - displayInLayerSwitcher: this.displayInLayerSwitcher │ │ │ │ - }); │ │ │ │ + px = this.position.clone(); │ │ │ │ + │ │ │ │ + // place the controls │ │ │ │ + this.buttons = []; │ │ │ │ + │ │ │ │ + var sz = { │ │ │ │ + w: 18, │ │ │ │ + h: 18 │ │ │ │ + }; │ │ │ │ + if (this.panIcons) { │ │ │ │ + var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ + var wposition = sz.w; │ │ │ │ + │ │ │ │ + if (this.zoomWorldIcon) { │ │ │ │ + centered = new OpenLayers.Pixel(px.x + sz.w, px.y); │ │ │ │ + } │ │ │ │ + │ │ │ │ + this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ + px.y = centered.y + sz.h; │ │ │ │ + this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ + if (this.zoomWorldIcon) { │ │ │ │ + this._addButton("zoomworld", "zoom-world-mini.png", px.add(sz.w, 0), sz); │ │ │ │ + │ │ │ │ + wposition *= 2; │ │ │ │ + } │ │ │ │ + this._addButton("panright", "east-mini.png", px.add(wposition, 0), sz); │ │ │ │ + this._addButton("pandown", "south-mini.png", centered.add(0, sz.h * 2), sz); │ │ │ │ + this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ + centered = this._addZoomBar(centered.add(0, sz.h * 4 + 5)); │ │ │ │ + this._addButton("zoomout", "zoom-minus-mini.png", centered, sz); │ │ │ │ + } else { │ │ │ │ + this._addButton("zoomin", "zoom-plus-mini.png", px, sz); │ │ │ │ + centered = this._addZoomBar(px.add(0, sz.h)); │ │ │ │ + this._addButton("zoomout", "zoom-minus-mini.png", centered, sz); │ │ │ │ + if (this.zoomWorldIcon) { │ │ │ │ + centered = centered.add(0, sz.h + 3); │ │ │ │ + this._addButton("zoomworld", "zoom-world-mini.png", centered, sz); │ │ │ │ + } │ │ │ │ } │ │ │ │ return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ + /** │ │ │ │ + * Method: _addZoomBar │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * centered - {<OpenLayers.Pixel>} where zoombar drawing is to start. │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.map.addLayer(this.gratLayer); │ │ │ │ - this.map.events.register('moveend', this, this.update); │ │ │ │ - this.update(); │ │ │ │ - return true; │ │ │ │ + _addZoomBar: function(centered) { │ │ │ │ + var imgLocation = OpenLayers.Util.getImageLocation("slider.png"); │ │ │ │ + var id = this.id + "_" + this.map.id; │ │ │ │ + var minZoom = this.map.getMinZoom(); │ │ │ │ + var zoomsToEnd = this.map.getNumZoomLevels() - 1 - this.map.getZoom(); │ │ │ │ + var slider = OpenLayers.Util.createAlphaImageDiv(id, │ │ │ │ + centered.add(-1, zoomsToEnd * this.zoomStopHeight), { │ │ │ │ + w: 20, │ │ │ │ + h: 9 │ │ │ │ + }, │ │ │ │ + imgLocation, │ │ │ │ + "absolute"); │ │ │ │ + slider.style.cursor = "move"; │ │ │ │ + this.slider = slider; │ │ │ │ + │ │ │ │ + this.sliderEvents = new OpenLayers.Events(this, slider, null, true, { │ │ │ │ + includeXY: true │ │ │ │ + }); │ │ │ │ + this.sliderEvents.on({ │ │ │ │ + "touchstart": this.zoomBarDown, │ │ │ │ + "touchmove": this.zoomBarDrag, │ │ │ │ + "touchend": this.zoomBarUp, │ │ │ │ + "mousedown": this.zoomBarDown, │ │ │ │ + "mousemove": this.zoomBarDrag, │ │ │ │ + "mouseup": this.zoomBarUp │ │ │ │ + }); │ │ │ │ + │ │ │ │ + var sz = { │ │ │ │ + w: this.zoomStopWidth, │ │ │ │ + h: this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom) │ │ │ │ + }; │ │ │ │ + var imgLocation = OpenLayers.Util.getImageLocation("zoombar.png"); │ │ │ │ + var div = null; │ │ │ │ + │ │ │ │ + if (OpenLayers.Util.alphaHack()) { │ │ │ │ + var id = this.id + "_" + this.map.id; │ │ │ │ + div = OpenLayers.Util.createAlphaImageDiv(id, centered, { │ │ │ │ + w: sz.w, │ │ │ │ + h: this.zoomStopHeight │ │ │ │ + }, │ │ │ │ + imgLocation, │ │ │ │ + "absolute", null, "crop"); │ │ │ │ + div.style.height = sz.h + "px"; │ │ │ │ } else { │ │ │ │ - return false; │ │ │ │ + div = OpenLayers.Util.createDiv( │ │ │ │ + 'OpenLayers_Control_PanZoomBar_Zoombar' + this.map.id, │ │ │ │ + centered, │ │ │ │ + sz, │ │ │ │ + imgLocation); │ │ │ │ } │ │ │ │ + div.style.cursor = "pointer"; │ │ │ │ + div.className = "olButton"; │ │ │ │ + this.zoombarDiv = div; │ │ │ │ + │ │ │ │ + this.div.appendChild(div); │ │ │ │ + │ │ │ │ + this.startTop = parseInt(div.style.top); │ │ │ │ + this.div.appendChild(slider); │ │ │ │ + │ │ │ │ + this.map.events.register("zoomend", this, this.moveZoomBar); │ │ │ │ + │ │ │ │ + centered = centered.add(0, │ │ │ │ + this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom)); │ │ │ │ + return centered; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ + * Method: _removeZoomBar │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - this.map.events.unregister('moveend', this, this.update); │ │ │ │ - this.map.removeLayer(this.gratLayer); │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ + _removeZoomBar: function() { │ │ │ │ + this.sliderEvents.un({ │ │ │ │ + "touchstart": this.zoomBarDown, │ │ │ │ + "touchmove": this.zoomBarDrag, │ │ │ │ + "touchend": this.zoomBarUp, │ │ │ │ + "mousedown": this.zoomBarDown, │ │ │ │ + "mousemove": this.zoomBarDrag, │ │ │ │ + "mouseup": this.zoomBarUp │ │ │ │ + }); │ │ │ │ + this.sliderEvents.destroy(); │ │ │ │ + │ │ │ │ + this.div.removeChild(this.zoombarDiv); │ │ │ │ + this.zoombarDiv = null; │ │ │ │ + this.div.removeChild(this.slider); │ │ │ │ + this.slider = null; │ │ │ │ + │ │ │ │ + this.map.events.unregister("zoomend", this, this.moveZoomBar); │ │ │ │ }, │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: update │ │ │ │ + * Method: onButtonClick │ │ │ │ * │ │ │ │ - * calculates the grid to be displayed and actually draws it │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - update: function() { │ │ │ │ - //wait for the map to be initialized before proceeding │ │ │ │ - var mapBounds = this.map.getExtent(); │ │ │ │ - if (!mapBounds) { │ │ │ │ - return; │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this, arguments); │ │ │ │ + if (evt.buttonElement === this.zoombarDiv) { │ │ │ │ + var levels = evt.buttonXY.y / this.zoomStopHeight; │ │ │ │ + if (this.forceFixedZoomLevel || !this.map.fractionalZoom) { │ │ │ │ + levels = Math.floor(levels); │ │ │ │ + } │ │ │ │ + var zoom = (this.map.getNumZoomLevels() - 1) - levels; │ │ │ │ + zoom = Math.min(Math.max(zoom, 0), this.map.getNumZoomLevels() - 1); │ │ │ │ + this.map.zoomTo(zoom); │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - //clear out the old grid │ │ │ │ - this.gratLayer.destroyFeatures(); │ │ │ │ - │ │ │ │ - //get the projection objects required │ │ │ │ - var llProj = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ - var mapProj = this.map.getProjectionObject(); │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ + /** │ │ │ │ + * Method: passEventToSlider │ │ │ │ + * This function is used to pass events that happen on the div, or the map, │ │ │ │ + * through to the slider, which then does its moving thing. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ + */ │ │ │ │ + passEventToSlider: function(evt) { │ │ │ │ + this.sliderEvents.handleBrowserEvent(evt); │ │ │ │ + }, │ │ │ │ │ │ │ │ - //if the map is in lon/lat, then the lines are straight and only one │ │ │ │ - //point is required │ │ │ │ - if (mapProj.proj && mapProj.proj.projName == "longlat") { │ │ │ │ - this.numPoints = 1; │ │ │ │ + /* │ │ │ │ + * Method: zoomBarDown │ │ │ │ + * event listener for clicks on the slider │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ + */ │ │ │ │ + zoomBarDown: function(evt) { │ │ │ │ + if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ + return; │ │ │ │ } │ │ │ │ + this.map.events.on({ │ │ │ │ + "touchmove": this.passEventToSlider, │ │ │ │ + "mousemove": this.passEventToSlider, │ │ │ │ + "mouseup": this.passEventToSlider, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.mouseDragStart = evt.xy.clone(); │ │ │ │ + this.zoomStart = evt.xy.clone(); │ │ │ │ + this.div.style.cursor = "move"; │ │ │ │ + // reset the div offsets just in case the div moved │ │ │ │ + this.zoombarDiv.offsets = null; │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ + }, │ │ │ │ │ │ │ │ - //get the map center in EPSG:4326 │ │ │ │ - var mapCenter = this.map.getCenter(); //lon and lat here are really map x and y │ │ │ │ - var mapCenterLL = new OpenLayers.Pixel(mapCenter.lon, mapCenter.lat); │ │ │ │ - OpenLayers.Projection.transform(mapCenterLL, mapProj, llProj); │ │ │ │ - │ │ │ │ - /* This block of code determines the lon/lat interval to use for the │ │ │ │ - * grid by calculating the diagonal size of one grid cell at the map │ │ │ │ - * center. Iterates through the intervals array until the diagonal │ │ │ │ - * length is less than the targetSize option. │ │ │ │ - */ │ │ │ │ - //find lat/lon interval that results in a grid of less than the target size │ │ │ │ - var testSq = this.targetSize * mapRes; │ │ │ │ - testSq *= testSq; //compare squares rather than doing a square root to save time │ │ │ │ - var llInterval; │ │ │ │ - for (var i = 0; i < this.intervals.length; ++i) { │ │ │ │ - llInterval = this.intervals[i]; //could do this for both x and y?? │ │ │ │ - var delta = llInterval / 2; │ │ │ │ - var p1 = mapCenterLL.offset({ │ │ │ │ - x: -delta, │ │ │ │ - y: -delta │ │ │ │ - }); //test coords in EPSG:4326 space │ │ │ │ - var p2 = mapCenterLL.offset({ │ │ │ │ - x: delta, │ │ │ │ - y: delta │ │ │ │ - }); │ │ │ │ - OpenLayers.Projection.transform(p1, llProj, mapProj); // convert them back to map projection │ │ │ │ - OpenLayers.Projection.transform(p2, llProj, mapProj); │ │ │ │ - var distSq = (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y); │ │ │ │ - if (distSq <= testSq) { │ │ │ │ - break; │ │ │ │ + /* │ │ │ │ + * Method: zoomBarDrag │ │ │ │ + * This is what happens when a click has occurred, and the client is │ │ │ │ + * dragging. Here we must ensure that the slider doesn't go beyond the │ │ │ │ + * bottom/top of the zoombar div, as well as moving the slider to its new │ │ │ │ + * visual location │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ + */ │ │ │ │ + zoomBarDrag: function(evt) { │ │ │ │ + if (this.mouseDragStart != null) { │ │ │ │ + var deltaY = this.mouseDragStart.y - evt.xy.y; │ │ │ │ + var offsets = OpenLayers.Util.pagePosition(this.zoombarDiv); │ │ │ │ + if ((evt.clientY - offsets[1]) > 0 && │ │ │ │ + (evt.clientY - offsets[1]) < parseInt(this.zoombarDiv.style.height) - 2) { │ │ │ │ + var newTop = parseInt(this.slider.style.top) - deltaY; │ │ │ │ + this.slider.style.top = newTop + "px"; │ │ │ │ + this.mouseDragStart = evt.xy.clone(); │ │ │ │ } │ │ │ │ + // set cumulative displacement │ │ │ │ + this.deltaY = this.zoomStart.y - evt.xy.y; │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ } │ │ │ │ - //alert(llInterval); │ │ │ │ - │ │ │ │ - //round the LL center to an even number based on the interval │ │ │ │ - mapCenterLL.x = Math.floor(mapCenterLL.x / llInterval) * llInterval; │ │ │ │ - mapCenterLL.y = Math.floor(mapCenterLL.y / llInterval) * llInterval; │ │ │ │ - //TODO adjust for minutses/seconds? │ │ │ │ - │ │ │ │ - /* The following 2 blocks calculate the nodes of the grid along a │ │ │ │ - * line of constant longitude (then latitiude) running through the │ │ │ │ - * center of the map until it reaches the map edge. The calculation │ │ │ │ - * goes from the center in both directions to the edge. │ │ │ │ - */ │ │ │ │ - //get the central longitude line, increment the latitude │ │ │ │ - var iter = 0; │ │ │ │ - var centerLonPoints = [mapCenterLL.clone()]; │ │ │ │ - var newPoint = mapCenterLL.clone(); │ │ │ │ - var mapXY; │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: 0, │ │ │ │ - y: llInterval │ │ │ │ - }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLonPoints.unshift(newPoint); │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ - newPoint = mapCenterLL.clone(); │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: 0, │ │ │ │ - y: -llInterval │ │ │ │ - }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLonPoints.push(newPoint); │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ + }, │ │ │ │ │ │ │ │ - //get the central latitude line, increment the longitude │ │ │ │ - iter = 0; │ │ │ │ - var centerLatPoints = [mapCenterLL.clone()]; │ │ │ │ - newPoint = mapCenterLL.clone(); │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: -llInterval, │ │ │ │ - y: 0 │ │ │ │ - }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLatPoints.unshift(newPoint); │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ - newPoint = mapCenterLL.clone(); │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: llInterval, │ │ │ │ - y: 0 │ │ │ │ + /* │ │ │ │ + * Method: zoomBarUp │ │ │ │ + * Perform cleanup when a mouseup event is received -- discover new zoom │ │ │ │ + * level and switch to it. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ + */ │ │ │ │ + zoomBarUp: function(evt) { │ │ │ │ + if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + if (this.mouseDragStart) { │ │ │ │ + this.div.style.cursor = ""; │ │ │ │ + this.map.events.un({ │ │ │ │ + "touchmove": this.passEventToSlider, │ │ │ │ + "mouseup": this.passEventToSlider, │ │ │ │ + "mousemove": this.passEventToSlider, │ │ │ │ + scope: this │ │ │ │ }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLatPoints.push(newPoint); │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ - │ │ │ │ - //now generate a line for each node in the central lat and lon lines │ │ │ │ - //first loop over constant longitude │ │ │ │ - var lines = []; │ │ │ │ - for (var i = 0; i < centerLatPoints.length; ++i) { │ │ │ │ - var lon = centerLatPoints[i].x; │ │ │ │ - var pointList = []; │ │ │ │ - var labelPoint = null; │ │ │ │ - var latEnd = Math.min(centerLonPoints[0].y, 90); │ │ │ │ - var latStart = Math.max(centerLonPoints[centerLonPoints.length - 1].y, -90); │ │ │ │ - var latDelta = (latEnd - latStart) / this.numPoints; │ │ │ │ - var lat = latStart; │ │ │ │ - for (var j = 0; j <= this.numPoints; ++j) { │ │ │ │ - var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ - gridPoint.transform(llProj, mapProj); │ │ │ │ - pointList.push(gridPoint); │ │ │ │ - lat += latDelta; │ │ │ │ - if (gridPoint.y >= mapBounds.bottom && !labelPoint) { │ │ │ │ - labelPoint = gridPoint; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.labelled) { │ │ │ │ - //keep track of when this grid line crosses the map bounds to set │ │ │ │ - //the label position │ │ │ │ - //labels along the bottom, add 10 pixel offset up into the map │ │ │ │ - //TODO add option for labels on top │ │ │ │ - var labelPos = new OpenLayers.Geometry.Point(labelPoint.x, mapBounds.bottom); │ │ │ │ - var labelAttrs = { │ │ │ │ - value: lon, │ │ │ │ - label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lon, "lon", this.labelFormat) : "", │ │ │ │ - labelAlign: "cb", │ │ │ │ - xOffset: 0, │ │ │ │ - yOffset: 2 │ │ │ │ - }; │ │ │ │ - this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)); │ │ │ │ + var zoomLevel = this.map.zoom; │ │ │ │ + if (!this.forceFixedZoomLevel && this.map.fractionalZoom) { │ │ │ │ + zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ + zoomLevel = Math.min(Math.max(zoomLevel, 0), │ │ │ │ + this.map.getNumZoomLevels() - 1); │ │ │ │ + } else { │ │ │ │ + zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ + zoomLevel = Math.max(Math.round(zoomLevel), 0); │ │ │ │ } │ │ │ │ - var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ - lines.push(new OpenLayers.Feature.Vector(geom)); │ │ │ │ + this.map.zoomTo(zoomLevel); │ │ │ │ + this.mouseDragStart = null; │ │ │ │ + this.zoomStart = null; │ │ │ │ + this.deltaY = 0; │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - //now draw the lines of constant latitude │ │ │ │ - for (var j = 0; j < centerLonPoints.length; ++j) { │ │ │ │ - lat = centerLonPoints[j].y; │ │ │ │ - if (lat < -90 || lat > 90) { //latitudes only valid between -90 and 90 │ │ │ │ - continue; │ │ │ │ - } │ │ │ │ - var pointList = []; │ │ │ │ - var lonStart = centerLatPoints[0].x; │ │ │ │ - var lonEnd = centerLatPoints[centerLatPoints.length - 1].x; │ │ │ │ - var lonDelta = (lonEnd - lonStart) / this.numPoints; │ │ │ │ - var lon = lonStart; │ │ │ │ - var labelPoint = null; │ │ │ │ - for (var i = 0; i <= this.numPoints; ++i) { │ │ │ │ - var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ - gridPoint.transform(llProj, mapProj); │ │ │ │ - pointList.push(gridPoint); │ │ │ │ - lon += lonDelta; │ │ │ │ - if (gridPoint.x < mapBounds.right) { │ │ │ │ - labelPoint = gridPoint; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.labelled) { │ │ │ │ - //keep track of when this grid line crosses the map bounds to set │ │ │ │ - //the label position │ │ │ │ - //labels along the right, 30 pixel offset left into the map │ │ │ │ - //TODO add option for labels on left │ │ │ │ - var labelPos = new OpenLayers.Geometry.Point(mapBounds.right, labelPoint.y); │ │ │ │ - var labelAttrs = { │ │ │ │ - value: lat, │ │ │ │ - label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lat, "lat", this.labelFormat) : "", │ │ │ │ - labelAlign: "rb", │ │ │ │ - xOffset: -2, │ │ │ │ - yOffset: 2 │ │ │ │ - }; │ │ │ │ - this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)); │ │ │ │ - } │ │ │ │ - var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ - lines.push(new OpenLayers.Feature.Vector(geom)); │ │ │ │ - } │ │ │ │ - this.gratLayer.addFeatures(lines); │ │ │ │ + /* │ │ │ │ + * Method: moveZoomBar │ │ │ │ + * Change the location of the slider to match the current zoom level. │ │ │ │ + */ │ │ │ │ + moveZoomBar: function() { │ │ │ │ + var newTop = │ │ │ │ + ((this.map.getNumZoomLevels() - 1) - this.map.getZoom()) * │ │ │ │ + this.zoomStopHeight + this.startTop + 1; │ │ │ │ + this.slider.style.top = newTop + "px"; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Graticule" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.PanZoomBar" │ │ │ │ }); │ │ │ │ - │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/ArgParser.js │ │ │ │ + OpenLayers/Format/SLD.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/Format/XML/VersionedOGC.js │ │ │ │ + * @requires OpenLayers/Style.js │ │ │ │ + * @requires OpenLayers/Rule.js │ │ │ │ + * @requires OpenLayers/Filter/FeatureId.js │ │ │ │ + * @requires OpenLayers/Filter/Logical.js │ │ │ │ + * @requires OpenLayers/Filter/Comparison.js │ │ │ │ + * @requires OpenLayers/Filter/Spatial.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.ArgParser │ │ │ │ - * The ArgParser control adds location bar query string parsing functionality │ │ │ │ - * to an OpenLayers Map. │ │ │ │ - * When added to a Map control, on a page load/refresh, the Map will │ │ │ │ - * automatically take the href string and parse it for lon, lat, zoom, and │ │ │ │ - * layers information. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.SLD │ │ │ │ + * Read/Write SLD. Create a new instance with the <OpenLayers.Format.SLD> │ │ │ │ + * constructor. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Format.SLD = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: center │ │ │ │ - * {<OpenLayers.LonLat>} │ │ │ │ + * APIProperty: profile │ │ │ │ + * {String} If provided, use a custom profile. │ │ │ │ + * │ │ │ │ + * Currently supported profiles: │ │ │ │ + * - GeoServer - parses GeoServer vendor specific capabilities for SLD. │ │ │ │ */ │ │ │ │ - center: null, │ │ │ │ + profile: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: zoom │ │ │ │ - * {int} │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "1.0.0". │ │ │ │ */ │ │ │ │ - zoom: null, │ │ │ │ + defaultVersion: "1.0.0", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: layers │ │ │ │ - * {String} Each character represents the state of the corresponding layer │ │ │ │ - * on the map. │ │ │ │ + * APIProperty: stringifyOutput │ │ │ │ + * {Boolean} If true, write will return a string otherwise a DOMElement. │ │ │ │ + * Default is true. │ │ │ │ */ │ │ │ │ - layers: null, │ │ │ │ + stringifyOutput: true, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: displayProjection │ │ │ │ - * {<OpenLayers.Projection>} Requires proj4js support. │ │ │ │ - * Projection used when reading the coordinates from the URL. This will │ │ │ │ - * reproject the map coordinates from the URL into the map's │ │ │ │ - * projection. │ │ │ │ + /** │ │ │ │ + * APIProperty: namedLayersAsArray │ │ │ │ + * {Boolean} Generate a namedLayers array. If false, the namedLayers │ │ │ │ + * property value will be an object keyed by layer name. Default is │ │ │ │ + * false. │ │ │ │ + */ │ │ │ │ + namedLayersAsArray: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: write │ │ │ │ + * Write a SLD document given a list of styles. │ │ │ │ * │ │ │ │ - * If you are using this functionality, be aware that any permalink │ │ │ │ - * which is added to the map will determine the coordinate type which │ │ │ │ - * is read from the URL, which means you should not add permalinks with │ │ │ │ - * different displayProjections to the same map. │ │ │ │ + * Parameters: │ │ │ │ + * sld - {Object} An object representing the SLD. │ │ │ │ + * options - {Object} Optional configuration object. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} An SLD document string. │ │ │ │ */ │ │ │ │ - displayProjection: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.ArgParser │ │ │ │ + * APIMethod: read │ │ │ │ + * Read and SLD doc and return an object representing the SLD. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ + * data - {String | DOMElement} Data to read. │ │ │ │ + * options - {Object} Options for the reader. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} An object representing the SLD. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SLD" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/SLD/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/Rule.js │ │ │ │ + * @requires OpenLayers/Format/SLD.js │ │ │ │ + * @requires OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Point.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Line.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Polygon.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Text.js │ │ │ │ + * @requires OpenLayers/Symbolizer/Raster.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.SLD.v1 │ │ │ │ + * Superclass for SLD version 1 parsers. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.Filter.v1_0_0> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ + namespaces: { │ │ │ │ + sld: "http://www.opengis.net/sld", │ │ │ │ + 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" │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getParameters │ │ │ │ + * Property: defaultPrefix │ │ │ │ */ │ │ │ │ - getParameters: function(url) { │ │ │ │ - url = url || window.location.href; │ │ │ │ - var parameters = OpenLayers.Util.getParameters(url); │ │ │ │ + defaultPrefix: "sld", │ │ │ │ │ │ │ │ - // If we have an anchor in the url use it to split the url │ │ │ │ - var index = url.indexOf('#'); │ │ │ │ - if (index > 0) { │ │ │ │ - // create an url to parse on the getParameters │ │ │ │ - url = '?' + url.substring(index + 1, url.length); │ │ │ │ + /** │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} Schema location for a particular minor version. │ │ │ │ + */ │ │ │ │ + schemaLocation: null, │ │ │ │ │ │ │ │ - OpenLayers.Util.extend(parameters, │ │ │ │ - OpenLayers.Util.getParameters(url)); │ │ │ │ - } │ │ │ │ - return parameters; │ │ │ │ + /** │ │ │ │ + * APIProperty: multipleSymbolizers │ │ │ │ + * {Boolean} Support multiple symbolizers per rule. Default is false. if │ │ │ │ + * true, an OpenLayers.Style2 instance will be created to represent │ │ │ │ + * user styles instead of an OpenLayers.Style instace. The │ │ │ │ + * OpenLayers.Style2 class allows collections of rules with multiple │ │ │ │ + * symbolizers, but is not currently useful for client side rendering. │ │ │ │ + * If multiple symbolizers is true, multiple FeatureTypeStyle elements │ │ │ │ + * are preserved in reading/writing by setting symbolizer zIndex values. │ │ │ │ + * In addition, the <defaultSymbolizer> property is ignored if │ │ │ │ + * multiple symbolizers are supported (defaults should be applied │ │ │ │ + * when rendering). │ │ │ │ + */ │ │ │ │ + multipleSymbolizers: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: featureTypeCounter │ │ │ │ + * {Number} Private counter for multiple feature type styles. │ │ │ │ + */ │ │ │ │ + featureTypeCounter: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: defaultSymbolizer. │ │ │ │ + * {Object} A symbolizer with the SLD defaults. │ │ │ │ + */ │ │ │ │ + defaultSymbolizer: { │ │ │ │ + fillColor: "#808080", │ │ │ │ + fillOpacity: 1, │ │ │ │ + strokeColor: "#000000", │ │ │ │ + strokeOpacity: 1, │ │ │ │ + strokeWidth: 1, │ │ │ │ + strokeDashstyle: "solid", │ │ │ │ + pointRadius: 3, │ │ │ │ + graphicName: "square" │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setMap │ │ │ │ - * Set the map property for the control. │ │ │ │ - * │ │ │ │ + * Constructor: OpenLayers.Format.SLD.v1 │ │ │ │ + * Instances of this class are not created directly. Use the │ │ │ │ + * <OpenLayers.Format.SLD> constructor instead. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ │ │ │ │ - //make sure we dont already have an arg parser attached │ │ │ │ - for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ - var control = this.map.controls[i]; │ │ │ │ - if ((control != this) && │ │ │ │ - (control.CLASS_NAME == "OpenLayers.Control.ArgParser")) { │ │ │ │ + /** │ │ │ │ + * Method: read │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {DOMElement} An SLD document element. │ │ │ │ + * options - {Object} Options for the reader. │ │ │ │ + * │ │ │ │ + * Valid options: │ │ │ │ + * namedLayersAsArray - {Boolean} Generate a namedLayers array. If false, │ │ │ │ + * the namedLayers property value will be an object keyed by layer name. │ │ │ │ + * Default is false. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} An object representing the SLD. │ │ │ │ + */ │ │ │ │ + read: function(data, options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ + var sld = { │ │ │ │ + namedLayers: options.namedLayersAsArray === true ? [] : {} │ │ │ │ + }; │ │ │ │ + this.readChildNodes(data, sld); │ │ │ │ + return sld; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // If a second argparser is added to the map, then we │ │ │ │ - // override the displayProjection to be the one added to the │ │ │ │ - // map. │ │ │ │ - if (control.displayProjection != this.displayProjection) { │ │ │ │ - this.displayProjection = control.displayProjection; │ │ │ │ + /** │ │ │ │ + * 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: OpenLayers.Util.applyDefaults({ │ │ │ │ + "sld": { │ │ │ │ + "StyledLayerDescriptor": function(node, sld) { │ │ │ │ + sld.version = node.getAttribute("version"); │ │ │ │ + this.readChildNodes(node, sld); │ │ │ │ + }, │ │ │ │ + "Name": function(node, obj) { │ │ │ │ + obj.name = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Title": function(node, obj) { │ │ │ │ + obj.title = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Abstract": function(node, obj) { │ │ │ │ + obj.description = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "NamedLayer": function(node, sld) { │ │ │ │ + var layer = { │ │ │ │ + userStyles: [], │ │ │ │ + namedStyles: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, layer); │ │ │ │ + // give each of the user styles this layer name │ │ │ │ + for (var i = 0, len = layer.userStyles.length; i < len; ++i) { │ │ │ │ + layer.userStyles[i].layerName = layer.name; │ │ │ │ } │ │ │ │ - │ │ │ │ - break; │ │ │ │ + if (OpenLayers.Util.isArray(sld.namedLayers)) { │ │ │ │ + sld.namedLayers.push(layer); │ │ │ │ + } else { │ │ │ │ + sld.namedLayers[layer.name] = layer; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "NamedStyle": function(node, layer) { │ │ │ │ + layer.namedStyles.push( │ │ │ │ + this.getChildName(node.firstChild) │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "UserStyle": function(node, layer) { │ │ │ │ + var obj = { │ │ │ │ + defaultsPerSymbolizer: true, │ │ │ │ + rules: [] │ │ │ │ + }; │ │ │ │ + this.featureTypeCounter = -1; │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + var style; │ │ │ │ + if (this.multipleSymbolizers) { │ │ │ │ + delete obj.defaultsPerSymbolizer; │ │ │ │ + style = new OpenLayers.Style2(obj); │ │ │ │ + } else { │ │ │ │ + style = new OpenLayers.Style(this.defaultSymbolizer, obj); │ │ │ │ + } │ │ │ │ + layer.userStyles.push(style); │ │ │ │ + }, │ │ │ │ + "IsDefault": function(node, style) { │ │ │ │ + if (this.getChildValue(node) == "1") { │ │ │ │ + style.isDefault = true; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "FeatureTypeStyle": function(node, style) { │ │ │ │ + ++this.featureTypeCounter; │ │ │ │ + var obj = { │ │ │ │ + rules: this.multipleSymbolizers ? style.rules : [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + if (!this.multipleSymbolizers) { │ │ │ │ + style.rules = obj.rules; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Rule": function(node, obj) { │ │ │ │ + var config; │ │ │ │ + if (this.multipleSymbolizers) { │ │ │ │ + config = { │ │ │ │ + symbolizers: [] │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + var rule = new OpenLayers.Rule(config); │ │ │ │ + this.readChildNodes(node, rule); │ │ │ │ + obj.rules.push(rule); │ │ │ │ + }, │ │ │ │ + "ElseFilter": function(node, rule) { │ │ │ │ + rule.elseFilter = true; │ │ │ │ + }, │ │ │ │ + "MinScaleDenominator": function(node, rule) { │ │ │ │ + rule.minScaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "MaxScaleDenominator": function(node, rule) { │ │ │ │ + rule.maxScaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "TextSymbolizer": function(node, rule) { │ │ │ │ + var config = {}; │ │ │ │ + this.readChildNodes(node, config); │ │ │ │ + if (this.multipleSymbolizers) { │ │ │ │ + config.zIndex = this.featureTypeCounter; │ │ │ │ + rule.symbolizers.push( │ │ │ │ + new OpenLayers.Symbolizer.Text(config) │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + rule.symbolizer["Text"] = OpenLayers.Util.applyDefaults( │ │ │ │ + config, rule.symbolizer["Text"] │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "LabelPlacement": function(node, symbolizer) { │ │ │ │ + this.readChildNodes(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "PointPlacement": function(node, symbolizer) { │ │ │ │ + var config = {}; │ │ │ │ + this.readChildNodes(node, config); │ │ │ │ + config.labelRotation = config.rotation; │ │ │ │ + delete config.rotation; │ │ │ │ + var labelAlign, │ │ │ │ + x = symbolizer.labelAnchorPointX, │ │ │ │ + y = symbolizer.labelAnchorPointY; │ │ │ │ + if (x <= 1 / 3) { │ │ │ │ + labelAlign = 'l'; │ │ │ │ + } else if (x > 1 / 3 && x < 2 / 3) { │ │ │ │ + labelAlign = 'c'; │ │ │ │ + } else if (x >= 2 / 3) { │ │ │ │ + labelAlign = 'r'; │ │ │ │ + } │ │ │ │ + if (y <= 1 / 3) { │ │ │ │ + labelAlign += 'b'; │ │ │ │ + } else if (y > 1 / 3 && y < 2 / 3) { │ │ │ │ + labelAlign += 'm'; │ │ │ │ + } else if (y >= 2 / 3) { │ │ │ │ + labelAlign += 't'; │ │ │ │ + } │ │ │ │ + config.labelAlign = labelAlign; │ │ │ │ + OpenLayers.Util.applyDefaults(symbolizer, config); │ │ │ │ + }, │ │ │ │ + "AnchorPoint": function(node, symbolizer) { │ │ │ │ + this.readChildNodes(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "AnchorPointX": function(node, symbolizer) { │ │ │ │ + var labelAnchorPointX = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (labelAnchorPointX) { │ │ │ │ + symbolizer.labelAnchorPointX = labelAnchorPointX; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "AnchorPointY": function(node, symbolizer) { │ │ │ │ + var labelAnchorPointY = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (labelAnchorPointY) { │ │ │ │ + symbolizer.labelAnchorPointY = labelAnchorPointY; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Displacement": function(node, symbolizer) { │ │ │ │ + this.readChildNodes(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "DisplacementX": function(node, symbolizer) { │ │ │ │ + var labelXOffset = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (labelXOffset) { │ │ │ │ + symbolizer.labelXOffset = labelXOffset; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "DisplacementY": function(node, symbolizer) { │ │ │ │ + var labelYOffset = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (labelYOffset) { │ │ │ │ + symbolizer.labelYOffset = labelYOffset; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "LinePlacement": function(node, symbolizer) { │ │ │ │ + this.readChildNodes(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "PerpendicularOffset": function(node, symbolizer) { │ │ │ │ + var labelPerpendicularOffset = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (labelPerpendicularOffset) { │ │ │ │ + symbolizer.labelPerpendicularOffset = labelPerpendicularOffset; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Label": function(node, symbolizer) { │ │ │ │ + var value = this.readers.ogc._expression.call(this, node); │ │ │ │ + if (value) { │ │ │ │ + symbolizer.label = value; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Font": function(node, symbolizer) { │ │ │ │ + this.readChildNodes(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "Halo": function(node, symbolizer) { │ │ │ │ + // halo has a fill, so send fresh object │ │ │ │ + var obj = {}; │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + symbolizer.haloRadius = obj.haloRadius; │ │ │ │ + symbolizer.haloColor = obj.fillColor; │ │ │ │ + symbolizer.haloOpacity = obj.fillOpacity; │ │ │ │ + }, │ │ │ │ + "Radius": function(node, symbolizer) { │ │ │ │ + var radius = this.readers.ogc._expression.call(this, node); │ │ │ │ + if (radius != null) { │ │ │ │ + // radius is only used for halo │ │ │ │ + symbolizer.haloRadius = radius; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "RasterSymbolizer": function(node, rule) { │ │ │ │ + var config = {}; │ │ │ │ + this.readChildNodes(node, config); │ │ │ │ + if (this.multipleSymbolizers) { │ │ │ │ + config.zIndex = this.featureTypeCounter; │ │ │ │ + rule.symbolizers.push( │ │ │ │ + new OpenLayers.Symbolizer.Raster(config) │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + rule.symbolizer["Raster"] = OpenLayers.Util.applyDefaults( │ │ │ │ + config, rule.symbolizer["Raster"] │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Geometry": function(node, obj) { │ │ │ │ + obj.geometry = {}; │ │ │ │ + this.readChildNodes(node, obj.geometry); │ │ │ │ + }, │ │ │ │ + "ColorMap": function(node, symbolizer) { │ │ │ │ + symbolizer.colorMap = []; │ │ │ │ + this.readChildNodes(node, symbolizer.colorMap); │ │ │ │ + }, │ │ │ │ + "ColorMapEntry": function(node, colorMap) { │ │ │ │ + var q = node.getAttribute("quantity"); │ │ │ │ + var o = node.getAttribute("opacity"); │ │ │ │ + colorMap.push({ │ │ │ │ + color: node.getAttribute("color"), │ │ │ │ + quantity: q !== null ? parseFloat(q) : undefined, │ │ │ │ + label: node.getAttribute("label") || undefined, │ │ │ │ + opacity: o !== null ? parseFloat(o) : undefined │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "LineSymbolizer": function(node, rule) { │ │ │ │ + var config = {}; │ │ │ │ + this.readChildNodes(node, config); │ │ │ │ + if (this.multipleSymbolizers) { │ │ │ │ + config.zIndex = this.featureTypeCounter; │ │ │ │ + rule.symbolizers.push( │ │ │ │ + new OpenLayers.Symbolizer.Line(config) │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + rule.symbolizer["Line"] = OpenLayers.Util.applyDefaults( │ │ │ │ + config, rule.symbolizer["Line"] │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "PolygonSymbolizer": function(node, rule) { │ │ │ │ + var config = { │ │ │ │ + fill: false, │ │ │ │ + stroke: false │ │ │ │ + }; │ │ │ │ + if (!this.multipleSymbolizers) { │ │ │ │ + config = rule.symbolizer["Polygon"] || config; │ │ │ │ + } │ │ │ │ + this.readChildNodes(node, config); │ │ │ │ + if (this.multipleSymbolizers) { │ │ │ │ + config.zIndex = this.featureTypeCounter; │ │ │ │ + rule.symbolizers.push( │ │ │ │ + new OpenLayers.Symbolizer.Polygon(config) │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + rule.symbolizer["Polygon"] = config; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "PointSymbolizer": function(node, rule) { │ │ │ │ + var config = { │ │ │ │ + fill: false, │ │ │ │ + stroke: false, │ │ │ │ + graphic: false │ │ │ │ + }; │ │ │ │ + if (!this.multipleSymbolizers) { │ │ │ │ + config = rule.symbolizer["Point"] || config; │ │ │ │ + } │ │ │ │ + this.readChildNodes(node, config); │ │ │ │ + if (this.multipleSymbolizers) { │ │ │ │ + config.zIndex = this.featureTypeCounter; │ │ │ │ + rule.symbolizers.push( │ │ │ │ + new OpenLayers.Symbolizer.Point(config) │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + rule.symbolizer["Point"] = config; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Stroke": function(node, symbolizer) { │ │ │ │ + symbolizer.stroke = true; │ │ │ │ + this.readChildNodes(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "Fill": function(node, symbolizer) { │ │ │ │ + symbolizer.fill = true; │ │ │ │ + this.readChildNodes(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "CssParameter": function(node, symbolizer) { │ │ │ │ + var cssProperty = node.getAttribute("name"); │ │ │ │ + var symProperty = this.cssMap[cssProperty]; │ │ │ │ + // for labels, fill should map to fontColor and fill-opacity │ │ │ │ + // to fontOpacity │ │ │ │ + if (symbolizer.label) { │ │ │ │ + if (cssProperty === 'fill') { │ │ │ │ + symProperty = "fontColor"; │ │ │ │ + } else if (cssProperty === 'fill-opacity') { │ │ │ │ + symProperty = "fontOpacity"; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (symProperty) { │ │ │ │ + // Limited support for parsing of OGC expressions │ │ │ │ + var value = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be an empty string │ │ │ │ + if (value) { │ │ │ │ + symbolizer[symProperty] = value; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Graphic": function(node, symbolizer) { │ │ │ │ + symbolizer.graphic = true; │ │ │ │ + var graphic = {}; │ │ │ │ + // painter's order not respected here, clobber previous with next │ │ │ │ + this.readChildNodes(node, graphic); │ │ │ │ + // directly properties with names that match symbolizer properties │ │ │ │ + var properties = [ │ │ │ │ + "stroke", "strokeColor", "strokeWidth", "strokeOpacity", │ │ │ │ + "strokeLinecap", "fill", "fillColor", "fillOpacity", │ │ │ │ + "graphicName", "rotation", "graphicFormat" │ │ │ │ + ]; │ │ │ │ + var prop, value; │ │ │ │ + for (var i = 0, len = properties.length; i < len; ++i) { │ │ │ │ + prop = properties[i]; │ │ │ │ + value = graphic[prop]; │ │ │ │ + if (value != undefined) { │ │ │ │ + symbolizer[prop] = value; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + // set other generic properties with specific graphic property names │ │ │ │ + if (graphic.opacity != undefined) { │ │ │ │ + symbolizer.graphicOpacity = graphic.opacity; │ │ │ │ + } │ │ │ │ + if (graphic.size != undefined) { │ │ │ │ + var pointRadius = graphic.size / 2; │ │ │ │ + if (isNaN(pointRadius)) { │ │ │ │ + // likely a property name │ │ │ │ + symbolizer.graphicWidth = graphic.size; │ │ │ │ + } else { │ │ │ │ + symbolizer.pointRadius = graphic.size / 2; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (graphic.href != undefined) { │ │ │ │ + symbolizer.externalGraphic = graphic.href; │ │ │ │ + } │ │ │ │ + if (graphic.rotation != undefined) { │ │ │ │ + symbolizer.rotation = graphic.rotation; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "ExternalGraphic": function(node, graphic) { │ │ │ │ + this.readChildNodes(node, graphic); │ │ │ │ + }, │ │ │ │ + "Mark": function(node, graphic) { │ │ │ │ + this.readChildNodes(node, graphic); │ │ │ │ + }, │ │ │ │ + "WellKnownName": function(node, graphic) { │ │ │ │ + graphic.graphicName = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Opacity": function(node, obj) { │ │ │ │ + var opacity = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (opacity) { │ │ │ │ + obj.opacity = opacity; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Size": function(node, obj) { │ │ │ │ + var size = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (size) { │ │ │ │ + obj.size = size; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Rotation": function(node, obj) { │ │ │ │ + var rotation = this.readers.ogc._expression.call(this, node); │ │ │ │ + // always string, could be empty string │ │ │ │ + if (rotation) { │ │ │ │ + obj.rotation = rotation; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "OnlineResource": function(node, obj) { │ │ │ │ + obj.href = this.getAttributeNS( │ │ │ │ + node, this.namespaces.xlink, "href" │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "Format": function(node, graphic) { │ │ │ │ + graphic.graphicFormat = this.getChildValue(node); │ │ │ │ } │ │ │ │ } │ │ │ │ - if (i == this.map.controls.length) { │ │ │ │ + }, OpenLayers.Format.Filter.v1_0_0.prototype.readers), │ │ │ │ │ │ │ │ - var args = this.getParameters(); │ │ │ │ - // Be careful to set layer first, to not trigger unnecessary layer loads │ │ │ │ - if (args.layers) { │ │ │ │ - this.layers = args.layers; │ │ │ │ + /** │ │ │ │ + * Property: cssMap │ │ │ │ + * {Object} Object mapping supported css property names to OpenLayers │ │ │ │ + * symbolizer property names. │ │ │ │ + */ │ │ │ │ + cssMap: { │ │ │ │ + "stroke": "strokeColor", │ │ │ │ + "stroke-opacity": "strokeOpacity", │ │ │ │ + "stroke-width": "strokeWidth", │ │ │ │ + "stroke-linecap": "strokeLinecap", │ │ │ │ + "stroke-dasharray": "strokeDashstyle", │ │ │ │ + "fill": "fillColor", │ │ │ │ + "fill-opacity": "fillOpacity", │ │ │ │ + "font-family": "fontFamily", │ │ │ │ + "font-size": "fontSize", │ │ │ │ + "font-weight": "fontWeight", │ │ │ │ + "font-style": "fontStyle" │ │ │ │ + }, │ │ │ │ │ │ │ │ - // when we add a new layer, set its visibility │ │ │ │ - this.map.events.register('addlayer', this, │ │ │ │ - this.configureLayers); │ │ │ │ - this.configureLayers(); │ │ │ │ + /** │ │ │ │ + * Method: getCssProperty │ │ │ │ + * Given a symbolizer property, get the corresponding CSS property │ │ │ │ + * from the <cssMap>. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * sym - {String} A symbolizer property name. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A CSS property name or null if none found. │ │ │ │ + */ │ │ │ │ + getCssProperty: function(sym) { │ │ │ │ + var css = null; │ │ │ │ + for (var prop in this.cssMap) { │ │ │ │ + if (this.cssMap[prop] == sym) { │ │ │ │ + css = prop; │ │ │ │ + break; │ │ │ │ } │ │ │ │ - if (args.lat && args.lon) { │ │ │ │ - this.center = new OpenLayers.LonLat(parseFloat(args.lon), │ │ │ │ - parseFloat(args.lat)); │ │ │ │ - if (args.zoom) { │ │ │ │ - this.zoom = parseFloat(args.zoom); │ │ │ │ - } │ │ │ │ + } │ │ │ │ + return css; │ │ │ │ + }, │ │ │ │ │ │ │ │ - // when we add a new baselayer to see when we can set the center │ │ │ │ - this.map.events.register('changebaselayer', this, │ │ │ │ - this.setCenter); │ │ │ │ - this.setCenter(); │ │ │ │ + /** │ │ │ │ + * Method: getGraphicFormat │ │ │ │ + * Given a href for an external graphic, try to determine the mime-type. │ │ │ │ + * This method doesn't try too hard, and will fall back to │ │ │ │ + * <defaultGraphicFormat> if one of the known <graphicFormats> is not │ │ │ │ + * the file extension of the provided href. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * href - {String} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} The graphic format. │ │ │ │ + */ │ │ │ │ + getGraphicFormat: function(href) { │ │ │ │ + var format, regex; │ │ │ │ + for (var key in this.graphicFormats) { │ │ │ │ + if (this.graphicFormats[key].test(href)) { │ │ │ │ + format = key; │ │ │ │ + break; │ │ │ │ } │ │ │ │ } │ │ │ │ + return format || this.defaultGraphicFormat; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setCenter │ │ │ │ - * As soon as a baseLayer has been loaded, we center and zoom │ │ │ │ - * ...and remove the handler. │ │ │ │ + /** │ │ │ │ + * Property: defaultGraphicFormat │ │ │ │ + * {String} If none other can be determined from <getGraphicFormat>, this │ │ │ │ + * default will be returned. │ │ │ │ */ │ │ │ │ - setCenter: function() { │ │ │ │ - │ │ │ │ - if (this.map.baseLayer) { │ │ │ │ - //dont need to listen for this one anymore │ │ │ │ - this.map.events.unregister('changebaselayer', this, │ │ │ │ - this.setCenter); │ │ │ │ + defaultGraphicFormat: "image/png", │ │ │ │ │ │ │ │ - if (this.displayProjection) { │ │ │ │ - this.center.transform(this.displayProjection, │ │ │ │ - this.map.getProjectionObject()); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: graphicFormats │ │ │ │ + * {Object} Mapping of image mime-types to regular extensions matching │ │ │ │ + * well-known file extensions. │ │ │ │ + */ │ │ │ │ + graphicFormats: { │ │ │ │ + "image/jpeg": /\.jpe?g$/i, │ │ │ │ + "image/gif": /\.gif$/i, │ │ │ │ + "image/png": /\.png$/i │ │ │ │ + }, │ │ │ │ │ │ │ │ - this.map.setCenter(this.center, this.zoom); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Method: write │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * sld - {Object} An object representing the SLD. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} The root of an SLD document. │ │ │ │ + */ │ │ │ │ + write: function(sld) { │ │ │ │ + return this.writers.sld.StyledLayerDescriptor.apply(this, [sld]); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: configureLayers │ │ │ │ - * As soon as all the layers are loaded, cycle through them and │ │ │ │ - * hide or show them. │ │ │ │ + /** │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - configureLayers: function() { │ │ │ │ + writers: OpenLayers.Util.applyDefaults({ │ │ │ │ + "sld": { │ │ │ │ + "_OGCExpression": function(nodeName, value) { │ │ │ │ + // only the simplest of ogc:expression handled │ │ │ │ + // {label: "some text and a ${propertyName}"} │ │ │ │ + var node = this.createElementNSPlus(nodeName); │ │ │ │ + var tokens = typeof value == "string" ? │ │ │ │ + value.split("${") : [value]; │ │ │ │ + node.appendChild(this.createTextNode(tokens[0])); │ │ │ │ + var item, last; │ │ │ │ + for (var i = 1, len = tokens.length; i < len; i++) { │ │ │ │ + item = tokens[i]; │ │ │ │ + last = item.indexOf("}"); │ │ │ │ + if (last > 0) { │ │ │ │ + this.writeNode( │ │ │ │ + "ogc:PropertyName", { │ │ │ │ + property: item.substring(0, last) │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + node.appendChild( │ │ │ │ + this.createTextNode(item.substring(++last)) │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + // no ending }, so this is a literal ${ │ │ │ │ + node.appendChild( │ │ │ │ + this.createTextNode("${" + item) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "StyledLayerDescriptor": function(sld) { │ │ │ │ + var root = this.createElementNSPlus( │ │ │ │ + "sld:StyledLayerDescriptor", { │ │ │ │ + attributes: { │ │ │ │ + "version": this.VERSION, │ │ │ │ + "xsi:schemaLocation": this.schemaLocation │ │ │ │ + } │ │ │ │ + } │ │ │ │ + ); │ │ │ │ │ │ │ │ - if (this.layers.length == this.map.layers.length) { │ │ │ │ - this.map.events.unregister('addlayer', this, this.configureLayers); │ │ │ │ + // For ArcGIS Server it is necessary to define this │ │ │ │ + // at the root level (see ticket:2166). │ │ │ │ + root.setAttribute("xmlns:ogc", this.namespaces.ogc); │ │ │ │ + root.setAttribute("xmlns:gml", this.namespaces.gml); │ │ │ │ │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ + // add in optional name │ │ │ │ + if (sld.name) { │ │ │ │ + this.writeNode("Name", sld.name, root); │ │ │ │ + } │ │ │ │ + // add in optional title │ │ │ │ + if (sld.title) { │ │ │ │ + this.writeNode("Title", sld.title, root); │ │ │ │ + } │ │ │ │ + // add in optional description │ │ │ │ + if (sld.description) { │ │ │ │ + this.writeNode("Abstract", sld.description, root); │ │ │ │ + } │ │ │ │ + // add in named layers │ │ │ │ + // allow namedLayers to be an array │ │ │ │ + if (OpenLayers.Util.isArray(sld.namedLayers)) { │ │ │ │ + for (var i = 0, len = sld.namedLayers.length; i < len; ++i) { │ │ │ │ + this.writeNode("NamedLayer", sld.namedLayers[i], root); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + for (var name in sld.namedLayers) { │ │ │ │ + this.writeNode("NamedLayer", sld.namedLayers[name], root); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return root; │ │ │ │ + }, │ │ │ │ + "Name": function(name) { │ │ │ │ + return this.createElementNSPlus("sld:Name", { │ │ │ │ + value: name │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Title": function(title) { │ │ │ │ + return this.createElementNSPlus("sld:Title", { │ │ │ │ + value: title │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Abstract": function(description) { │ │ │ │ + return this.createElementNSPlus( │ │ │ │ + "sld:Abstract", { │ │ │ │ + value: description │ │ │ │ + } │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "NamedLayer": function(layer) { │ │ │ │ + var node = this.createElementNSPlus("sld:NamedLayer"); │ │ │ │ │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - var c = this.layers.charAt(i); │ │ │ │ + // add in required name │ │ │ │ + this.writeNode("Name", layer.name, node); │ │ │ │ │ │ │ │ - if (c == "B") { │ │ │ │ - this.map.setBaseLayer(layer); │ │ │ │ - } else if ((c == "T") || (c == "F")) { │ │ │ │ - layer.setVisibility(c == "T"); │ │ │ │ + // optional sld:LayerFeatureConstraints here │ │ │ │ + │ │ │ │ + // add in named styles │ │ │ │ + if (layer.namedStyles) { │ │ │ │ + for (var i = 0, len = layer.namedStyles.length; i < len; ++i) { │ │ │ │ + this.writeNode( │ │ │ │ + "NamedStyle", layer.namedStyles[i], node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + // add in user styles │ │ │ │ + if (layer.userStyles) { │ │ │ │ + for (var i = 0, len = layer.userStyles.length; i < len; ++i) { │ │ │ │ + this.writeNode( │ │ │ │ + "UserStyle", layer.userStyles[i], node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "NamedStyle": function(name) { │ │ │ │ + var node = this.createElementNSPlus("sld:NamedStyle"); │ │ │ │ + this.writeNode("Name", name, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "UserStyle": function(style) { │ │ │ │ + var node = this.createElementNSPlus("sld:UserStyle"); │ │ │ │ + │ │ │ │ + // add in optional name │ │ │ │ + if (style.name) { │ │ │ │ + this.writeNode("Name", style.name, node); │ │ │ │ + } │ │ │ │ + // add in optional title │ │ │ │ + if (style.title) { │ │ │ │ + this.writeNode("Title", style.title, node); │ │ │ │ + } │ │ │ │ + // add in optional description │ │ │ │ + if (style.description) { │ │ │ │ + this.writeNode("Abstract", style.description, node); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // add isdefault │ │ │ │ + if (style.isDefault) { │ │ │ │ + this.writeNode("IsDefault", style.isDefault, node); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // add FeatureTypeStyles │ │ │ │ + if (this.multipleSymbolizers && style.rules) { │ │ │ │ + // group style objects by symbolizer zIndex │ │ │ │ + var rulesByZ = { │ │ │ │ + 0: [] │ │ │ │ + }; │ │ │ │ + var zValues = [0]; │ │ │ │ + var rule, ruleMap, symbolizer, zIndex, clone; │ │ │ │ + for (var i = 0, ii = style.rules.length; i < ii; ++i) { │ │ │ │ + rule = style.rules[i]; │ │ │ │ + if (rule.symbolizers) { │ │ │ │ + ruleMap = {}; │ │ │ │ + for (var j = 0, jj = rule.symbolizers.length; j < jj; ++j) { │ │ │ │ + symbolizer = rule.symbolizers[j]; │ │ │ │ + zIndex = symbolizer.zIndex; │ │ │ │ + if (!(zIndex in ruleMap)) { │ │ │ │ + clone = rule.clone(); │ │ │ │ + clone.symbolizers = []; │ │ │ │ + ruleMap[zIndex] = clone; │ │ │ │ + } │ │ │ │ + ruleMap[zIndex].symbolizers.push(symbolizer.clone()); │ │ │ │ + } │ │ │ │ + for (zIndex in ruleMap) { │ │ │ │ + if (!(zIndex in rulesByZ)) { │ │ │ │ + zValues.push(zIndex); │ │ │ │ + rulesByZ[zIndex] = []; │ │ │ │ + } │ │ │ │ + rulesByZ[zIndex].push(ruleMap[zIndex]); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + // no symbolizers in rule │ │ │ │ + rulesByZ[0].push(rule.clone()); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + // write one FeatureTypeStyle per zIndex │ │ │ │ + zValues.sort(); │ │ │ │ + var rules; │ │ │ │ + for (var i = 0, ii = zValues.length; i < ii; ++i) { │ │ │ │ + rules = rulesByZ[zValues[i]]; │ │ │ │ + if (rules.length > 0) { │ │ │ │ + clone = style.clone(); │ │ │ │ + clone.rules = rulesByZ[zValues[i]]; │ │ │ │ + this.writeNode("FeatureTypeStyle", clone, node); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.writeNode("FeatureTypeStyle", style, node); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "IsDefault": function(bool) { │ │ │ │ + return this.createElementNSPlus( │ │ │ │ + "sld:IsDefault", { │ │ │ │ + value: (bool) ? "1" : "0" │ │ │ │ + } │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "FeatureTypeStyle": function(style) { │ │ │ │ + var node = this.createElementNSPlus("sld:FeatureTypeStyle"); │ │ │ │ + │ │ │ │ + // OpenLayers currently stores no Name, Title, Abstract, │ │ │ │ + // FeatureTypeName, or SemanticTypeIdentifier information │ │ │ │ + // related to FeatureTypeStyle │ │ │ │ + │ │ │ │ + // add in rules │ │ │ │ + for (var i = 0, len = style.rules.length; i < len; ++i) { │ │ │ │ + this.writeNode("Rule", style.rules[i], node); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Rule": function(rule) { │ │ │ │ + var node = this.createElementNSPlus("sld:Rule"); │ │ │ │ + │ │ │ │ + // add in optional name │ │ │ │ + if (rule.name) { │ │ │ │ + this.writeNode("Name", rule.name, node); │ │ │ │ + } │ │ │ │ + // add in optional title │ │ │ │ + if (rule.title) { │ │ │ │ + this.writeNode("Title", rule.title, node); │ │ │ │ + } │ │ │ │ + // add in optional description │ │ │ │ + if (rule.description) { │ │ │ │ + this.writeNode("Abstract", rule.description, node); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // add in LegendGraphic here │ │ │ │ + │ │ │ │ + // add in optional filters │ │ │ │ + if (rule.elseFilter) { │ │ │ │ + this.writeNode("ElseFilter", null, node); │ │ │ │ + } else if (rule.filter) { │ │ │ │ + this.writeNode("ogc:Filter", rule.filter, node); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // add in scale limits │ │ │ │ + if (rule.minScaleDenominator != undefined) { │ │ │ │ + this.writeNode( │ │ │ │ + "MinScaleDenominator", rule.minScaleDenominator, node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (rule.maxScaleDenominator != undefined) { │ │ │ │ + this.writeNode( │ │ │ │ + "MaxScaleDenominator", rule.maxScaleDenominator, node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var type, symbolizer; │ │ │ │ + if (this.multipleSymbolizers && rule.symbolizers) { │ │ │ │ + var symbolizer; │ │ │ │ + for (var i = 0, ii = rule.symbolizers.length; i < ii; ++i) { │ │ │ │ + symbolizer = rule.symbolizers[i]; │ │ │ │ + type = symbolizer.CLASS_NAME.split(".").pop(); │ │ │ │ + this.writeNode( │ │ │ │ + type + "Symbolizer", symbolizer, node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + // add in symbolizers (relies on geometry type keys) │ │ │ │ + var types = OpenLayers.Style.SYMBOLIZER_PREFIXES; │ │ │ │ + for (var i = 0, len = types.length; i < len; ++i) { │ │ │ │ + type = types[i]; │ │ │ │ + symbolizer = rule.symbolizer[type]; │ │ │ │ + if (symbolizer) { │ │ │ │ + this.writeNode( │ │ │ │ + type + "Symbolizer", symbolizer, node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + │ │ │ │ + }, │ │ │ │ + "ElseFilter": function() { │ │ │ │ + return this.createElementNSPlus("sld:ElseFilter"); │ │ │ │ + }, │ │ │ │ + "MinScaleDenominator": function(scale) { │ │ │ │ + return this.createElementNSPlus( │ │ │ │ + "sld:MinScaleDenominator", { │ │ │ │ + value: scale │ │ │ │ + } │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "MaxScaleDenominator": function(scale) { │ │ │ │ + return this.createElementNSPlus( │ │ │ │ + "sld:MaxScaleDenominator", { │ │ │ │ + value: scale │ │ │ │ + } │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "LineSymbolizer": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:LineSymbolizer"); │ │ │ │ + this.writeNode("Stroke", symbolizer, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Stroke": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:Stroke"); │ │ │ │ + │ │ │ │ + // GraphicFill here │ │ │ │ + // GraphicStroke here │ │ │ │ + │ │ │ │ + // add in CssParameters │ │ │ │ + if (symbolizer.strokeColor != undefined) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "strokeColor" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (symbolizer.strokeOpacity != undefined) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "strokeOpacity" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (symbolizer.strokeWidth != undefined) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "strokeWidth" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (symbolizer.strokeDashstyle != undefined && symbolizer.strokeDashstyle !== "solid") { │ │ │ │ + // assumes valid stroke-dasharray value │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "strokeDashstyle" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (symbolizer.strokeLinecap != undefined) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "strokeLinecap" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "CssParameter": function(obj) { │ │ │ │ + // not handling ogc:expressions for now │ │ │ │ + return this.createElementNSPlus("sld:CssParameter", { │ │ │ │ + attributes: { │ │ │ │ + name: this.getCssProperty(obj.key) │ │ │ │ + }, │ │ │ │ + value: obj.symbolizer[obj.key] │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "TextSymbolizer": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:TextSymbolizer"); │ │ │ │ + // add in optional Label │ │ │ │ + if (symbolizer.label != null) { │ │ │ │ + this.writeNode("Label", symbolizer.label, node); │ │ │ │ + } │ │ │ │ + // add in optional Font │ │ │ │ + if (symbolizer.fontFamily != null || │ │ │ │ + symbolizer.fontSize != null || │ │ │ │ + symbolizer.fontWeight != null || │ │ │ │ + symbolizer.fontStyle != null) { │ │ │ │ + this.writeNode("Font", symbolizer, node); │ │ │ │ + } │ │ │ │ + // add in optional LabelPlacement │ │ │ │ + if (symbolizer.labelAnchorPointX != null || │ │ │ │ + symbolizer.labelAnchorPointY != null || │ │ │ │ + symbolizer.labelAlign != null || │ │ │ │ + symbolizer.labelXOffset != null || │ │ │ │ + symbolizer.labelYOffset != null || │ │ │ │ + symbolizer.labelRotation != null || │ │ │ │ + symbolizer.labelPerpendicularOffset != null) { │ │ │ │ + this.writeNode("LabelPlacement", symbolizer, node); │ │ │ │ + } │ │ │ │ + // add in optional Halo │ │ │ │ + if (symbolizer.haloRadius != null || │ │ │ │ + symbolizer.haloColor != null || │ │ │ │ + symbolizer.haloOpacity != null) { │ │ │ │ + this.writeNode("Halo", symbolizer, node); │ │ │ │ + } │ │ │ │ + // add in optional Fill │ │ │ │ + if (symbolizer.fontColor != null || │ │ │ │ + symbolizer.fontOpacity != null) { │ │ │ │ + this.writeNode("Fill", { │ │ │ │ + fillColor: symbolizer.fontColor, │ │ │ │ + fillOpacity: symbolizer.fontOpacity │ │ │ │ + }, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "LabelPlacement": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:LabelPlacement"); │ │ │ │ + // PointPlacement and LinePlacement are choices, so don't output both │ │ │ │ + if ((symbolizer.labelAnchorPointX != null || │ │ │ │ + symbolizer.labelAnchorPointY != null || │ │ │ │ + symbolizer.labelAlign != null || │ │ │ │ + symbolizer.labelXOffset != null || │ │ │ │ + symbolizer.labelYOffset != null || │ │ │ │ + symbolizer.labelRotation != null) && │ │ │ │ + symbolizer.labelPerpendicularOffset == null) { │ │ │ │ + this.writeNode("PointPlacement", symbolizer, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.labelPerpendicularOffset != null) { │ │ │ │ + this.writeNode("LinePlacement", symbolizer, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "LinePlacement": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:LinePlacement"); │ │ │ │ + this.writeNode("PerpendicularOffset", symbolizer.labelPerpendicularOffset, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "PerpendicularOffset": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:PerpendicularOffset", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "PointPlacement": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:PointPlacement"); │ │ │ │ + if (symbolizer.labelAnchorPointX != null || │ │ │ │ + symbolizer.labelAnchorPointY != null || │ │ │ │ + symbolizer.labelAlign != null) { │ │ │ │ + this.writeNode("AnchorPoint", symbolizer, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.labelXOffset != null || │ │ │ │ + symbolizer.labelYOffset != null) { │ │ │ │ + this.writeNode("Displacement", symbolizer, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.labelRotation != null) { │ │ │ │ + this.writeNode("Rotation", symbolizer.labelRotation, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "AnchorPoint": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:AnchorPoint"); │ │ │ │ + var x = symbolizer.labelAnchorPointX, │ │ │ │ + y = symbolizer.labelAnchorPointY; │ │ │ │ + if (x != null) { │ │ │ │ + this.writeNode("AnchorPointX", x, node); │ │ │ │ + } │ │ │ │ + if (y != null) { │ │ │ │ + this.writeNode("AnchorPointY", y, node); │ │ │ │ + } │ │ │ │ + if (x == null && y == null) { │ │ │ │ + var xAlign = symbolizer.labelAlign.substr(0, 1), │ │ │ │ + yAlign = symbolizer.labelAlign.substr(1, 1); │ │ │ │ + if (xAlign === "l") { │ │ │ │ + x = 0; │ │ │ │ + } else if (xAlign === "c") { │ │ │ │ + x = 0.5; │ │ │ │ + } else if (xAlign === "r") { │ │ │ │ + x = 1; │ │ │ │ + } │ │ │ │ + if (yAlign === "b") { │ │ │ │ + y = 0; │ │ │ │ + } else if (yAlign === "m") { │ │ │ │ + y = 0.5; │ │ │ │ + } else if (yAlign === "t") { │ │ │ │ + y = 1; │ │ │ │ + } │ │ │ │ + this.writeNode("AnchorPointX", x, node); │ │ │ │ + this.writeNode("AnchorPointY", y, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "AnchorPointX": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:AnchorPointX", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "AnchorPointY": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:AnchorPointY", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Displacement": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:Displacement"); │ │ │ │ + if (symbolizer.labelXOffset != null) { │ │ │ │ + this.writeNode("DisplacementX", symbolizer.labelXOffset, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.labelYOffset != null) { │ │ │ │ + this.writeNode("DisplacementY", symbolizer.labelYOffset, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "DisplacementX": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:DisplacementX", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "DisplacementY": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:DisplacementY", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Font": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:Font"); │ │ │ │ + // add in CssParameters │ │ │ │ + if (symbolizer.fontFamily) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "fontFamily" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (symbolizer.fontSize) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "fontSize" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (symbolizer.fontWeight) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "fontWeight" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (symbolizer.fontStyle) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "fontStyle" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Label": function(label) { │ │ │ │ + return this.writers.sld._OGCExpression.call( │ │ │ │ + this, "sld:Label", label │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "Halo": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:Halo"); │ │ │ │ + if (symbolizer.haloRadius) { │ │ │ │ + this.writeNode("Radius", symbolizer.haloRadius, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.haloColor || symbolizer.haloOpacity) { │ │ │ │ + this.writeNode("Fill", { │ │ │ │ + fillColor: symbolizer.haloColor, │ │ │ │ + fillOpacity: symbolizer.haloOpacity │ │ │ │ + }, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Radius": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:Radius", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "RasterSymbolizer": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:RasterSymbolizer"); │ │ │ │ + if (symbolizer.geometry) { │ │ │ │ + this.writeNode("Geometry", symbolizer.geometry, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.opacity) { │ │ │ │ + this.writeNode("Opacity", symbolizer.opacity, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.colorMap) { │ │ │ │ + this.writeNode("ColorMap", symbolizer.colorMap, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Geometry": function(geometry) { │ │ │ │ + var node = this.createElementNSPlus("sld:Geometry"); │ │ │ │ + if (geometry.property) { │ │ │ │ + this.writeNode("ogc:PropertyName", geometry, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ColorMap": function(colorMap) { │ │ │ │ + var node = this.createElementNSPlus("sld:ColorMap"); │ │ │ │ + for (var i = 0, len = colorMap.length; i < len; ++i) { │ │ │ │ + this.writeNode("ColorMapEntry", colorMap[i], node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ColorMapEntry": function(colorMapEntry) { │ │ │ │ + var node = this.createElementNSPlus("sld:ColorMapEntry"); │ │ │ │ + var a = colorMapEntry; │ │ │ │ + node.setAttribute("color", a.color); │ │ │ │ + a.opacity !== undefined && node.setAttribute("opacity", │ │ │ │ + parseFloat(a.opacity)); │ │ │ │ + a.quantity !== undefined && node.setAttribute("quantity", │ │ │ │ + parseFloat(a.quantity)); │ │ │ │ + a.label !== undefined && node.setAttribute("label", a.label); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "PolygonSymbolizer": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:PolygonSymbolizer"); │ │ │ │ + if (symbolizer.fill !== false) { │ │ │ │ + this.writeNode("Fill", symbolizer, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.stroke !== false) { │ │ │ │ + this.writeNode("Stroke", symbolizer, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Fill": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:Fill"); │ │ │ │ + │ │ │ │ + // GraphicFill here │ │ │ │ + │ │ │ │ + // add in CssParameters │ │ │ │ + if (symbolizer.fillColor) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "fillColor" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (symbolizer.fillOpacity != null) { │ │ │ │ + this.writeNode( │ │ │ │ + "CssParameter", { │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + key: "fillOpacity" │ │ │ │ + }, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "PointSymbolizer": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:PointSymbolizer"); │ │ │ │ + this.writeNode("Graphic", symbolizer, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Graphic": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:Graphic"); │ │ │ │ + if (symbolizer.externalGraphic != undefined) { │ │ │ │ + this.writeNode("ExternalGraphic", symbolizer, node); │ │ │ │ + } else { │ │ │ │ + this.writeNode("Mark", symbolizer, node); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (symbolizer.graphicOpacity != undefined) { │ │ │ │ + this.writeNode("Opacity", symbolizer.graphicOpacity, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.pointRadius != undefined) { │ │ │ │ + this.writeNode("Size", symbolizer.pointRadius * 2, node); │ │ │ │ + } else if (symbolizer.graphicWidth != undefined) { │ │ │ │ + this.writeNode("Size", symbolizer.graphicWidth, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.rotation != undefined) { │ │ │ │ + this.writeNode("Rotation", symbolizer.rotation, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ExternalGraphic": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:ExternalGraphic"); │ │ │ │ + this.writeNode( │ │ │ │ + "OnlineResource", symbolizer.externalGraphic, node │ │ │ │ + ); │ │ │ │ + var format = symbolizer.graphicFormat || │ │ │ │ + this.getGraphicFormat(symbolizer.externalGraphic); │ │ │ │ + this.writeNode("Format", format, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Mark": function(symbolizer) { │ │ │ │ + var node = this.createElementNSPlus("sld:Mark"); │ │ │ │ + if (symbolizer.graphicName) { │ │ │ │ + this.writeNode("WellKnownName", symbolizer.graphicName, node); │ │ │ │ + } │ │ │ │ + if (symbolizer.fill !== false) { │ │ │ │ + this.writeNode("Fill", symbolizer, node); │ │ │ │ } │ │ │ │ + if (symbolizer.stroke !== false) { │ │ │ │ + this.writeNode("Stroke", symbolizer, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "WellKnownName": function(name) { │ │ │ │ + return this.createElementNSPlus("sld:WellKnownName", { │ │ │ │ + value: name │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Opacity": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:Opacity", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Size": function(value) { │ │ │ │ + return this.writers.sld._OGCExpression.call( │ │ │ │ + this, "sld:Size", value │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "Rotation": function(value) { │ │ │ │ + return this.createElementNSPlus("sld:Rotation", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "OnlineResource": function(href) { │ │ │ │ + return this.createElementNSPlus("sld:OnlineResource", { │ │ │ │ + attributes: { │ │ │ │ + "xlink:type": "simple", │ │ │ │ + "xlink:href": href │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Format": function(format) { │ │ │ │ + return this.createElementNSPlus("sld:Format", { │ │ │ │ + value: format │ │ │ │ + }); │ │ │ │ } │ │ │ │ } │ │ │ │ - }, │ │ │ │ + }, OpenLayers.Format.Filter.v1_0_0.prototype.writers), │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SLD.v1" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ArgParser" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Permalink.js │ │ │ │ + OpenLayers/Format/SLD/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/SLD/v1.js │ │ │ │ + * @requires OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.SLD.v1_0_0 │ │ │ │ + * Write SLD version 1.0.0. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.SLD.v1> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.SLD.v1_0_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.SLD.v1, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: VERSION │ │ │ │ + * {String} 1.0.0 │ │ │ │ + */ │ │ │ │ + VERSION: "1.0.0", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} http://www.opengis.net/sld │ │ │ │ + * http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd │ │ │ │ + */ │ │ │ │ + schemaLocation: "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.SLD.v1_0_0 │ │ │ │ + * Instances of this class are not created directly. Use the │ │ │ │ + * <OpenLayers.Format.SLD> constructor instead. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0" │ │ │ │ + │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/SLDSelect.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/Control/ArgParser.js │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ + * @requires OpenLayers/Layer/WMS.js │ │ │ │ + * @requires OpenLayers/Handler/RegularPolygon.js │ │ │ │ + * @requires OpenLayers/Handler/Polygon.js │ │ │ │ + * @requires OpenLayers/Handler/Path.js │ │ │ │ + * @requires OpenLayers/Handler/Click.js │ │ │ │ + * @requires OpenLayers/Filter/Spatial.js │ │ │ │ + * @requires OpenLayers/Format/SLD/v1_0_0.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Permalink │ │ │ │ - * The Permalink control is hyperlink that will return the user to the │ │ │ │ - * current map view. By default it is drawn in the lower right corner of the │ │ │ │ - * map. The href is updated as the map is zoomed, panned and whilst layers │ │ │ │ - * are switched. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Control.SLDSelect │ │ │ │ + * Perform selections on WMS layers using Styled Layer Descriptor (SLD) │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Control.SLDSelect = 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>): │ │ │ │ + * selected - Triggered when a selection occurs. Listeners receive an │ │ │ │ + * event with *filters* and *layer* properties. Filters will be an │ │ │ │ + * array of OpenLayers.Filter objects created in order to perform │ │ │ │ + * the particular selection. │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: argParserClass │ │ │ │ - * {Class} The ArgParser control class (not instance) to use with this │ │ │ │ - * control. │ │ │ │ + * APIProperty: clearOnDeactivate │ │ │ │ + * {Boolean} Should the selection be cleared when the control is │ │ │ │ + * deactivated. Default value is false. │ │ │ │ */ │ │ │ │ - argParserClass: OpenLayers.Control.ArgParser, │ │ │ │ + clearOnDeactivate: false, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: element │ │ │ │ - * {DOMElement} │ │ │ │ + /** │ │ │ │ + * APIProperty: layers │ │ │ │ + * {Array(<OpenLayers.Layer.WMS>)} The WMS layers this control will work │ │ │ │ + * on. │ │ │ │ */ │ │ │ │ - element: null, │ │ │ │ + layers: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: anchor │ │ │ │ - * {Boolean} This option changes 3 things: │ │ │ │ - * the character '#' is used in place of the character '?', │ │ │ │ - * the window.href is updated if no element is provided. │ │ │ │ - * When this option is set to true it's not recommend to provide │ │ │ │ - * a base without provide an element. │ │ │ │ + /** │ │ │ │ + * Property: callbacks │ │ │ │ + * {Object} The functions that are sent to the handler for callback │ │ │ │ */ │ │ │ │ - anchor: false, │ │ │ │ + callbacks: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: base │ │ │ │ - * {String} │ │ │ │ + /** │ │ │ │ + * APIProperty: selectionSymbolizer │ │ │ │ + * {Object} Determines the styling of the selected objects. Default is │ │ │ │ + * a selection in red. │ │ │ │ */ │ │ │ │ - base: '', │ │ │ │ + selectionSymbolizer: { │ │ │ │ + 'Polygon': { │ │ │ │ + fillColor: '#FF0000', │ │ │ │ + stroke: false │ │ │ │ + }, │ │ │ │ + 'Line': { │ │ │ │ + strokeColor: '#FF0000', │ │ │ │ + strokeWidth: 2 │ │ │ │ + }, │ │ │ │ + 'Point': { │ │ │ │ + graphicName: 'square', │ │ │ │ + fillColor: '#FF0000', │ │ │ │ + pointRadius: 5 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: displayProjection │ │ │ │ - * {<OpenLayers.Projection>} Requires proj4js support. Projection used │ │ │ │ - * when creating the coordinates in the link. This will reproject the │ │ │ │ - * map coordinates into display coordinates. If you are using this │ │ │ │ - * functionality, the permalink which is last added to the map will │ │ │ │ - * determine the coordinate type which is read from the URL, which │ │ │ │ - * means you should not add permalinks with different │ │ │ │ - * displayProjections to the same map. │ │ │ │ + /** │ │ │ │ + * APIProperty: layerOptions │ │ │ │ + * {Object} The options to apply to the selection layer, by default the │ │ │ │ + * selection layer will be kept out of the layer switcher. │ │ │ │ */ │ │ │ │ - displayProjection: null, │ │ │ │ + layerOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.Permalink │ │ │ │ + * APIProperty: handlerOptions │ │ │ │ + * {Object} Used to set non-default properties on the control's handler │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: sketchStyle │ │ │ │ + * {<OpenLayers.Style>|Object} Style or symbolizer to use for the sketch │ │ │ │ + * handler. The recommended way of styling the sketch layer, however, is │ │ │ │ + * to configure an <OpenLayers.StyleMap> in the layerOptions of the │ │ │ │ + * <handlerOptions>: │ │ │ │ + * │ │ │ │ + * (code) │ │ │ │ + * new OpenLayers.Control.SLDSelect(OpenLayers.Handler.Path, { │ │ │ │ + * handlerOptions: { │ │ │ │ + * layerOptions: { │ │ │ │ + * styleMap: new OpenLayers.StyleMap({ │ │ │ │ + * "default": {strokeColor: "yellow"} │ │ │ │ + * }) │ │ │ │ + * } │ │ │ │ + * } │ │ │ │ + * }); │ │ │ │ + * (end) │ │ │ │ + */ │ │ │ │ + sketchStyle: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: wfsCache │ │ │ │ + * {Object} Cache to use for storing parsed results from │ │ │ │ + * <OpenLayers.Format.WFSDescribeFeatureType.read>. If not provided, │ │ │ │ + * these will be cached on the prototype. │ │ │ │ + */ │ │ │ │ + wfsCache: {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: layerCache │ │ │ │ + * {Object} Cache to use for storing references to the selection layers. │ │ │ │ + * Normally each source layer will have exactly 1 selection layer of │ │ │ │ + * type OpenLayers.Layer.WMS. If not provided, layers will │ │ │ │ + * be cached on the prototype. Note that if <clearOnDeactivate> is │ │ │ │ + * true, the layer will no longer be cached after deactivating the │ │ │ │ + * control. │ │ │ │ + */ │ │ │ │ + layerCache: {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.SLDSelect │ │ │ │ + * Create a new control for selecting features in WMS layers using │ │ │ │ + * Styled Layer Descriptor (SLD). │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * element - {DOMElement} │ │ │ │ - * base - {String} │ │ │ │ - * options - {Object} options to the control. │ │ │ │ + * Parameters: │ │ │ │ + * handler - {<OpenLayers.Class>} A sketch handler class. This determines │ │ │ │ + * the type of selection, e.g. box (<OpenLayers.Handler.Box>), point │ │ │ │ + * (<OpenLayers.Handler.Point>), path (<OpenLayers.Handler.Path>) or │ │ │ │ + * polygon (<OpenLayers.Handler.Polygon>) selection. To use circle │ │ │ │ + * type selection, use <OpenLayers.Handler.RegularPolygon> and pass │ │ │ │ + * the number of desired sides (e.g. 40) as "sides" property to the │ │ │ │ + * <handlerOptions>. │ │ │ │ + * options - {Object} An object containing all configuration properties for │ │ │ │ + * the control. │ │ │ │ * │ │ │ │ - * Or for anchor: │ │ │ │ - * options - {Object} options to the control. │ │ │ │ + * Valid options: │ │ │ │ + * layers - Array({<OpenLayers.Layer.WMS>}) The layers to perform the │ │ │ │ + * selection on. │ │ │ │ */ │ │ │ │ - initialize: function(element, base, options) { │ │ │ │ - if (element !== null && typeof element == 'object' && !OpenLayers.Util.isElement(element)) { │ │ │ │ - options = element; │ │ │ │ - this.base = document.location.href; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - if (this.element != null) { │ │ │ │ - this.element = OpenLayers.Util.getElement(this.element); │ │ │ │ + initialize: function(handler, options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + │ │ │ │ + this.callbacks = OpenLayers.Util.extend({ │ │ │ │ + done: this.select, │ │ │ │ + click: this.select │ │ │ │ + }, this.callbacks); │ │ │ │ + this.handlerOptions = this.handlerOptions || {}; │ │ │ │ + this.layerOptions = OpenLayers.Util.applyDefaults(this.layerOptions, { │ │ │ │ + displayInLayerSwitcher: false, │ │ │ │ + tileOptions: { │ │ │ │ + maxGetUrlLength: 2048 │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.element = OpenLayers.Util.getElement(element); │ │ │ │ - this.base = base || document.location.href; │ │ │ │ + }); │ │ │ │ + if (this.sketchStyle) { │ │ │ │ + this.handlerOptions.layerOptions = OpenLayers.Util.applyDefaults( │ │ │ │ + this.handlerOptions.layerOptions, { │ │ │ │ + styleMap: new OpenLayers.StyleMap({ │ │ │ │ + "default": this.sketchStyle │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + ); │ │ │ │ } │ │ │ │ + this.handler = new handler(this, this.callbacks, this.handlerOptions); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: destroy │ │ │ │ + * Take care of things that are not handled in superclass. │ │ │ │ */ │ │ │ │ destroy: function() { │ │ │ │ - if (this.element && this.element.parentNode == this.div) { │ │ │ │ - this.div.removeChild(this.element); │ │ │ │ - this.element = null; │ │ │ │ + for (var key in this.layerCache) { │ │ │ │ + delete this.layerCache[key]; │ │ │ │ } │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.unregister('moveend', this, this.updateLink); │ │ │ │ + for (var key in this.wfsCache) { │ │ │ │ + delete this.wfsCache[key]; │ │ │ │ } │ │ │ │ - │ │ │ │ OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setMap │ │ │ │ - * Set the map property for the control. │ │ │ │ - * │ │ │ │ + * Method: coupleLayerVisiblity │ │ │ │ + * Couple the selection layer and the source layer with respect to │ │ │ │ + * layer visibility. So if the source layer is turned off, the │ │ │ │ + * selection layer is also turned off. │ │ │ │ + * │ │ │ │ + * Context: │ │ │ │ + * - {<OpenLayers.Layer>} │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * evt - {Object} │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - │ │ │ │ - //make sure we have an arg parser attached │ │ │ │ - for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ - var control = this.map.controls[i]; │ │ │ │ - if (control.CLASS_NAME == this.argParserClass.CLASS_NAME) { │ │ │ │ - │ │ │ │ - // If a permalink is added to the map, and an ArgParser already │ │ │ │ - // exists, we override the displayProjection to be the one │ │ │ │ - // on the permalink. │ │ │ │ - if (control.displayProjection != this.displayProjection) { │ │ │ │ - this.displayProjection = control.displayProjection; │ │ │ │ - } │ │ │ │ + coupleLayerVisiblity: function(evt) { │ │ │ │ + this.setVisibility(evt.object.getVisibility()); │ │ │ │ + }, │ │ │ │ │ │ │ │ - break; │ │ │ │ + /** │ │ │ │ + * Method: createSelectionLayer │ │ │ │ + * Creates a "clone" from the source layer in which the selection can │ │ │ │ + * be drawn. This ensures both the source layer and the selection are │ │ │ │ + * visible and not only the selection. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * source - {<OpenLayers.Layer.WMS>} The source layer on which the selection │ │ │ │ + * is performed. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Layer.WMS>} A WMS layer with maxGetUrlLength configured to 2048 │ │ │ │ + * since SLD selections can easily get quite long. │ │ │ │ + */ │ │ │ │ + createSelectionLayer: function(source) { │ │ │ │ + // check if we already have a selection layer for the source layer │ │ │ │ + var selectionLayer; │ │ │ │ + if (!this.layerCache[source.id]) { │ │ │ │ + selectionLayer = new OpenLayers.Layer.WMS(source.name, │ │ │ │ + source.url, source.params, │ │ │ │ + OpenLayers.Util.applyDefaults( │ │ │ │ + this.layerOptions, │ │ │ │ + source.getOptions()) │ │ │ │ + ); │ │ │ │ + this.layerCache[source.id] = selectionLayer; │ │ │ │ + // make sure the layers are coupled wrt visibility, but only │ │ │ │ + // if they are not displayed in the layer switcher, because in │ │ │ │ + // that case the user cannot control visibility. │ │ │ │ + if (this.layerOptions.displayInLayerSwitcher === false) { │ │ │ │ + source.events.on({ │ │ │ │ + "visibilitychanged": this.coupleLayerVisiblity, │ │ │ │ + scope: selectionLayer │ │ │ │ + }); │ │ │ │ } │ │ │ │ + this.map.addLayer(selectionLayer); │ │ │ │ + } else { │ │ │ │ + selectionLayer = this.layerCache[source.id]; │ │ │ │ } │ │ │ │ - if (i == this.map.controls.length) { │ │ │ │ - this.map.addControl(new this.argParserClass({ │ │ │ │ - 'displayProjection': this.displayProjection │ │ │ │ - })); │ │ │ │ - } │ │ │ │ - │ │ │ │ + return selectionLayer; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: draw │ │ │ │ + * Method: createSLD │ │ │ │ + * Create the SLD document for the layer using the supplied filters. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.WMS>} │ │ │ │ + * filters - Array({<OpenLayers.Filter>}) The filters to be applied. │ │ │ │ + * geometryAttributes - Array({Object}) The geometry attributes of the │ │ │ │ + * layer. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * {String} The SLD document generated as a string. │ │ │ │ */ │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + createSLD: function(layer, filters, geometryAttributes) { │ │ │ │ + var sld = { │ │ │ │ + version: "1.0.0", │ │ │ │ + namedLayers: {} │ │ │ │ + }; │ │ │ │ + var layerNames = [layer.params.LAYERS].join(",").split(","); │ │ │ │ + for (var i = 0, len = layerNames.length; i < len; i++) { │ │ │ │ + var name = layerNames[i]; │ │ │ │ + sld.namedLayers[name] = { │ │ │ │ + name: name, │ │ │ │ + userStyles: [] │ │ │ │ + }; │ │ │ │ + var symbolizer = this.selectionSymbolizer; │ │ │ │ + var geometryAttribute = geometryAttributes[i]; │ │ │ │ + if (geometryAttribute.type.indexOf('Polygon') >= 0) { │ │ │ │ + symbolizer = { │ │ │ │ + Polygon: this.selectionSymbolizer['Polygon'] │ │ │ │ + }; │ │ │ │ + } else if (geometryAttribute.type.indexOf('LineString') >= 0) { │ │ │ │ + symbolizer = { │ │ │ │ + Line: this.selectionSymbolizer['Line'] │ │ │ │ + }; │ │ │ │ + } else if (geometryAttribute.type.indexOf('Point') >= 0) { │ │ │ │ + symbolizer = { │ │ │ │ + Point: this.selectionSymbolizer['Point'] │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + var filter = filters[i]; │ │ │ │ + sld.namedLayers[name].userStyles.push({ │ │ │ │ + name: 'default', │ │ │ │ + rules: [ │ │ │ │ + new OpenLayers.Rule({ │ │ │ │ + symbolizer: symbolizer, │ │ │ │ + filter: filter, │ │ │ │ + maxScaleDenominator: layer.options.minScale │ │ │ │ + }) │ │ │ │ + ] │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + return new OpenLayers.Format.SLD({ │ │ │ │ + srsName: this.map.getProjection() │ │ │ │ + }).write(sld); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (!this.element && !this.anchor) { │ │ │ │ - this.element = document.createElement("a"); │ │ │ │ - this.element.innerHTML = OpenLayers.i18n("Permalink"); │ │ │ │ - this.element.href = ""; │ │ │ │ - this.div.appendChild(this.element); │ │ │ │ + /** │ │ │ │ + * Method: parseDescribeLayer │ │ │ │ + * Parse the SLD WMS DescribeLayer response and issue the corresponding │ │ │ │ + * WFS DescribeFeatureType request │ │ │ │ + * │ │ │ │ + * request - {XMLHttpRequest} The request object. │ │ │ │ + */ │ │ │ │ + parseDescribeLayer: function(request) { │ │ │ │ + var format = new OpenLayers.Format.WMSDescribeLayer(); │ │ │ │ + var doc = request.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = request.responseText; │ │ │ │ } │ │ │ │ - this.map.events.on({ │ │ │ │ - 'moveend': this.updateLink, │ │ │ │ - 'changelayer': this.updateLink, │ │ │ │ - 'changebaselayer': this.updateLink, │ │ │ │ + var describeLayer = format.read(doc); │ │ │ │ + var typeNames = []; │ │ │ │ + var url = null; │ │ │ │ + for (var i = 0, len = describeLayer.length; i < len; i++) { │ │ │ │ + // perform a WFS DescribeFeatureType request │ │ │ │ + if (describeLayer[i].owsType == "WFS") { │ │ │ │ + typeNames.push(describeLayer[i].typeName); │ │ │ │ + url = describeLayer[i].owsURL; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var options = { │ │ │ │ + url: url, │ │ │ │ + params: { │ │ │ │ + SERVICE: "WFS", │ │ │ │ + TYPENAME: typeNames.toString(), │ │ │ │ + REQUEST: "DescribeFeatureType", │ │ │ │ + VERSION: "1.0.0" │ │ │ │ + }, │ │ │ │ + callback: function(request) { │ │ │ │ + var format = new OpenLayers.Format.WFSDescribeFeatureType(); │ │ │ │ + var doc = request.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = request.responseText; │ │ │ │ + } │ │ │ │ + var describeFeatureType = format.read(doc); │ │ │ │ + this.control.wfsCache[this.layer.id] = describeFeatureType; │ │ │ │ + this.control._queue && this.control.applySelection(); │ │ │ │ + }, │ │ │ │ scope: this │ │ │ │ - }); │ │ │ │ - │ │ │ │ - // Make it so there is at least a link even though the map may not have │ │ │ │ - // moved yet. │ │ │ │ - this.updateLink(); │ │ │ │ - │ │ │ │ - return this.div; │ │ │ │ + }; │ │ │ │ + OpenLayers.Request.GET(options); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: updateLink │ │ │ │ + * Method: getGeometryAttributes │ │ │ │ + * Look up the geometry attributes from the WFS DescribeFeatureType response │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.WMS>} The layer for which to look up the │ │ │ │ + * geometry attributes. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * Array({Object}) Array of geometry attributes │ │ │ │ */ │ │ │ │ - updateLink: function() { │ │ │ │ - var separator = this.anchor ? '#' : '?'; │ │ │ │ - var href = this.base; │ │ │ │ - var anchor = null; │ │ │ │ - if (href.indexOf("#") != -1 && this.anchor == false) { │ │ │ │ - anchor = href.substring(href.indexOf("#"), href.length); │ │ │ │ + getGeometryAttributes: function(layer) { │ │ │ │ + var result = []; │ │ │ │ + var cache = this.wfsCache[layer.id]; │ │ │ │ + for (var i = 0, len = cache.featureTypes.length; i < len; i++) { │ │ │ │ + var typeName = cache.featureTypes[i]; │ │ │ │ + var properties = typeName.properties; │ │ │ │ + for (var j = 0, lenj = properties.length; j < lenj; j++) { │ │ │ │ + var property = properties[j]; │ │ │ │ + var type = property.type; │ │ │ │ + if ((type.indexOf('LineString') >= 0) || │ │ │ │ + (type.indexOf('GeometryAssociationType') >= 0) || │ │ │ │ + (type.indexOf('GeometryPropertyType') >= 0) || │ │ │ │ + (type.indexOf('Point') >= 0) || │ │ │ │ + (type.indexOf('Polygon') >= 0)) { │ │ │ │ + result.push(property); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - if (href.indexOf(separator) != -1) { │ │ │ │ - href = href.substring(0, href.indexOf(separator)); │ │ │ │ + return result; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the control. Activating the control will perform a SLD WMS │ │ │ │ + * DescribeLayer request followed by a WFS DescribeFeatureType request │ │ │ │ + * so that the proper symbolizers can be chosen based on the geometry │ │ │ │ + * type. │ │ │ │ + */ │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ + var layer = this.layers[i]; │ │ │ │ + if (layer && !this.wfsCache[layer.id]) { │ │ │ │ + var options = { │ │ │ │ + url: layer.url, │ │ │ │ + params: { │ │ │ │ + SERVICE: "WMS", │ │ │ │ + VERSION: layer.params.VERSION, │ │ │ │ + LAYERS: layer.params.LAYERS, │ │ │ │ + REQUEST: "DescribeLayer" │ │ │ │ + }, │ │ │ │ + callback: this.parseDescribeLayer, │ │ │ │ + scope: { │ │ │ │ + layer: layer, │ │ │ │ + control: this │ │ │ │ + } │ │ │ │ + }; │ │ │ │ + OpenLayers.Request.GET(options); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - var splits = href.split("#"); │ │ │ │ - href = splits[0] + separator + OpenLayers.Util.getParameterString(this.createParams()); │ │ │ │ - if (anchor) { │ │ │ │ - href += anchor; │ │ │ │ + return activated; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the control. If clearOnDeactivate is true, remove the │ │ │ │ + * selection layer(s). │ │ │ │ + */ │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ + var layer = this.layers[i]; │ │ │ │ + if (layer && this.clearOnDeactivate === true) { │ │ │ │ + var layerCache = this.layerCache; │ │ │ │ + var selectionLayer = layerCache[layer.id]; │ │ │ │ + if (selectionLayer) { │ │ │ │ + layer.events.un({ │ │ │ │ + "visibilitychanged": this.coupleLayerVisiblity, │ │ │ │ + scope: selectionLayer │ │ │ │ + }); │ │ │ │ + selectionLayer.destroy(); │ │ │ │ + delete layerCache[layer.id]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - if (this.anchor && !this.element) { │ │ │ │ - window.location.href = href; │ │ │ │ + return deactivated; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setLayers │ │ │ │ + * Set the layers on which the selection should be performed. Call the │ │ │ │ + * setLayers method if the layer(s) to be used change and the same │ │ │ │ + * control should be used on a new set of layers. │ │ │ │ + * If the control is already active, it will be active after the new │ │ │ │ + * set of layers is set. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layers - {Array(<OpenLayers.Layer.WMS>)} The new set of layers on which │ │ │ │ + * the selection should be performed. │ │ │ │ + */ │ │ │ │ + setLayers: function(layers) { │ │ │ │ + if (this.active) { │ │ │ │ + this.deactivate(); │ │ │ │ + this.layers = layers; │ │ │ │ + this.activate(); │ │ │ │ } else { │ │ │ │ - this.element.href = href; │ │ │ │ + this.layers = layers; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: createParams │ │ │ │ - * Creates the parameters that need to be encoded into the permalink url. │ │ │ │ - * │ │ │ │ + * Function: createFilter │ │ │ │ + * Create the filter to be used in the SLD. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * center - {<OpenLayers.LonLat>} center to encode in the permalink. │ │ │ │ - * Defaults to the current map center. │ │ │ │ - * zoom - {Integer} zoom level to encode in the permalink. Defaults to the │ │ │ │ - * current map zoom level. │ │ │ │ - * layers - {Array(<OpenLayers.Layer>)} layers to encode in the permalink. │ │ │ │ - * Defaults to the current map layers. │ │ │ │ - * │ │ │ │ + * geometryAttribute - {Object} Used to get the name of the geometry │ │ │ │ + * attribute which is needed for constructing the spatial filter. │ │ │ │ + * geometry - {<OpenLayers.Geometry>} The geometry to use. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} Hash of parameters that will be url-encoded into the │ │ │ │ - * permalink. │ │ │ │ + * {<OpenLayers.Filter.Spatial>} The spatial filter created. │ │ │ │ */ │ │ │ │ - createParams: function(center, zoom, layers) { │ │ │ │ - center = center || this.map.getCenter(); │ │ │ │ + createFilter: function(geometryAttribute, geometry) { │ │ │ │ + var filter = null; │ │ │ │ + if (this.handler instanceof OpenLayers.Handler.RegularPolygon) { │ │ │ │ + // box │ │ │ │ + if (this.handler.irregular === true) { │ │ │ │ + filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ + property: geometryAttribute.name, │ │ │ │ + value: geometry.getBounds() │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ + property: geometryAttribute.name, │ │ │ │ + value: geometry │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } else if (this.handler instanceof OpenLayers.Handler.Polygon) { │ │ │ │ + filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ + property: geometryAttribute.name, │ │ │ │ + value: geometry │ │ │ │ + }); │ │ │ │ + } else if (this.handler instanceof OpenLayers.Handler.Path) { │ │ │ │ + // if source layer is point based, use DWITHIN instead │ │ │ │ + if (geometryAttribute.type.indexOf('Point') >= 0) { │ │ │ │ + filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.DWITHIN, │ │ │ │ + property: geometryAttribute.name, │ │ │ │ + distance: this.map.getExtent().getWidth() * 0.01, │ │ │ │ + distanceUnits: this.map.getUnits(), │ │ │ │ + value: geometry │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ + property: geometryAttribute.name, │ │ │ │ + value: geometry │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } else if (this.handler instanceof OpenLayers.Handler.Click) { │ │ │ │ + if (geometryAttribute.type.indexOf('Polygon') >= 0) { │ │ │ │ + filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ + property: geometryAttribute.name, │ │ │ │ + value: geometry │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.DWITHIN, │ │ │ │ + property: geometryAttribute.name, │ │ │ │ + distance: this.map.getExtent().getWidth() * 0.01, │ │ │ │ + distanceUnits: this.map.getUnits(), │ │ │ │ + value: geometry │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return filter; │ │ │ │ + }, │ │ │ │ │ │ │ │ - var params = OpenLayers.Util.getParameters(this.base); │ │ │ │ + /** │ │ │ │ + * Method: select │ │ │ │ + * When the handler is done, use SLD_BODY on the selection layer to │ │ │ │ + * display the selection in the map. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {Object} or {<OpenLayers.Geometry>} │ │ │ │ + */ │ │ │ │ + select: function(geometry) { │ │ │ │ + this._queue = function() { │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ + var layer = this.layers[i]; │ │ │ │ + var geometryAttributes = this.getGeometryAttributes(layer); │ │ │ │ + var filters = []; │ │ │ │ + for (var j = 0, lenj = geometryAttributes.length; j < lenj; j++) { │ │ │ │ + var geometryAttribute = geometryAttributes[j]; │ │ │ │ + if (geometryAttribute !== null) { │ │ │ │ + // from the click handler we will not get an actual │ │ │ │ + // geometry so transform │ │ │ │ + if (!(geometry instanceof OpenLayers.Geometry)) { │ │ │ │ + var point = this.map.getLonLatFromPixel( │ │ │ │ + geometry.xy); │ │ │ │ + geometry = new OpenLayers.Geometry.Point( │ │ │ │ + point.lon, point.lat); │ │ │ │ + } │ │ │ │ + var filter = this.createFilter(geometryAttribute, │ │ │ │ + geometry); │ │ │ │ + if (filter !== null) { │ │ │ │ + filters.push(filter); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ - // If there's still no center, map is not initialized yet. │ │ │ │ - // Break out of this function, and simply return the params from the │ │ │ │ - // base link. │ │ │ │ - if (center) { │ │ │ │ + var selectionLayer = this.createSelectionLayer(layer); │ │ │ │ │ │ │ │ - //zoom │ │ │ │ - params.zoom = zoom || this.map.getZoom(); │ │ │ │ + this.events.triggerEvent("selected", { │ │ │ │ + layer: layer, │ │ │ │ + filters: filters │ │ │ │ + }); │ │ │ │ │ │ │ │ - //lon,lat │ │ │ │ - var lat = center.lat; │ │ │ │ - var lon = center.lon; │ │ │ │ + var sld = this.createSLD(layer, filters, geometryAttributes); │ │ │ │ │ │ │ │ - if (this.displayProjection) { │ │ │ │ - var mapPosition = OpenLayers.Projection.transform({ │ │ │ │ - x: lon, │ │ │ │ - y: lat │ │ │ │ - }, │ │ │ │ - this.map.getProjectionObject(), │ │ │ │ - this.displayProjection); │ │ │ │ - lon = mapPosition.x; │ │ │ │ - lat = mapPosition.y; │ │ │ │ + selectionLayer.mergeNewParams({ │ │ │ │ + SLD_BODY: sld │ │ │ │ + }); │ │ │ │ + delete this._queue; │ │ │ │ } │ │ │ │ - params.lat = Math.round(lat * 100000) / 100000; │ │ │ │ - params.lon = Math.round(lon * 100000) / 100000; │ │ │ │ - │ │ │ │ - //layers │ │ │ │ - layers = layers || this.map.layers; │ │ │ │ - params.layers = ''; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - var layer = layers[i]; │ │ │ │ + }; │ │ │ │ + this.applySelection(); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (layer.isBaseLayer) { │ │ │ │ - params.layers += (layer == this.map.baseLayer) ? "B" : "0"; │ │ │ │ - } else { │ │ │ │ - params.layers += (layer.getVisibility()) ? "T" : "F"; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Method: applySelection │ │ │ │ + * Checks if all required wfs data is cached, and applies the selection │ │ │ │ + */ │ │ │ │ + applySelection: function() { │ │ │ │ + var canApply = true; │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ + if (!this.wfsCache[this.layers[i].id]) { │ │ │ │ + canApply = false; │ │ │ │ + break; │ │ │ │ } │ │ │ │ } │ │ │ │ - │ │ │ │ - return params; │ │ │ │ + canApply && this._queue.call(this); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Permalink" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.SLDSelect" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/Measure.js │ │ │ │ + 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/Feature/Vector.js │ │ │ │ + * @requires OpenLayers/Geometry/Point.js │ │ │ │ + * @requires OpenLayers/Projection.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Measure │ │ │ │ - * Allows for drawing of features for measurements. │ │ │ │ + * 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.Measure = OpenLayers.Class(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>): │ │ │ │ - * measure - Triggered when a measurement sketch is complete. Listeners │ │ │ │ - * will receive an event with measure, units, order, and geometry │ │ │ │ - * properties. │ │ │ │ - * measurepartial - Triggered when a new point is added to the │ │ │ │ - * measurement sketch or if the <immediate> property is true and the │ │ │ │ - * measurement sketch is modified. Listeners receive an event with measure, │ │ │ │ - * units, order, and geometry. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: handlerOptions │ │ │ │ - * {Object} Used to set non-default properties on the control's handler │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: callbacks │ │ │ │ - * {Object} The functions that are sent to the handler for callback │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - callbacks: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: displaySystem │ │ │ │ - * {String} Display system for output measurements. Supported values │ │ │ │ - * are 'english', 'metric', and 'geographic'. Default is 'metric'. │ │ │ │ + * Property: geolocation │ │ │ │ + * {Object} The geolocation engine, as a property to be possibly mocked. │ │ │ │ + * This is set lazily to avoid a memory leak in IE9. │ │ │ │ */ │ │ │ │ - displaySystem: 'metric', │ │ │ │ + geolocation: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: geodesic │ │ │ │ - * {Boolean} Calculate geodesic metrics instead of planar metrics. This │ │ │ │ - * requires that geometries can be transformed into Geographic/WGS84 │ │ │ │ - * (if that is not already the map projection). Default is false. │ │ │ │ + * Property: available │ │ │ │ + * {Boolean} The navigator.geolocation object is available. │ │ │ │ */ │ │ │ │ - geodesic: false, │ │ │ │ + available: ('geolocation' in navigator), │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: displaySystemUnits │ │ │ │ - * {Object} Units for various measurement systems. Values are arrays │ │ │ │ - * of unit abbreviations (from OpenLayers.INCHES_PER_UNIT) in decreasing │ │ │ │ - * order of length. │ │ │ │ + * APIProperty: bind │ │ │ │ + * {Boolean} If true, map center will be set on location update. │ │ │ │ */ │ │ │ │ - displaySystemUnits: { │ │ │ │ - geographic: ['dd'], │ │ │ │ - english: ['mi', 'ft', 'in'], │ │ │ │ - metric: ['km', 'm'] │ │ │ │ - }, │ │ │ │ + bind: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: delay │ │ │ │ - * {Number} Number of milliseconds between clicks before the event is │ │ │ │ - * considered a double-click. The "measurepartial" event will not │ │ │ │ - * be triggered if the sketch is completed within this time. This │ │ │ │ - * is required for IE where creating a browser reflow (if a listener │ │ │ │ - * is modifying the DOM by displaying the measurement values) messes │ │ │ │ - * with the dblclick listener in the sketch handler. │ │ │ │ + * APIProperty: watch │ │ │ │ + * {Boolean} If true, position will be update regularly. │ │ │ │ */ │ │ │ │ - partialDelay: 300, │ │ │ │ + watch: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: delayedTrigger │ │ │ │ - * {Number} Timeout id of trigger for measurepartial. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - delayedTrigger: null, │ │ │ │ + geolocationOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: persist │ │ │ │ - * {Boolean} Keep the temporary measurement sketch drawn after the │ │ │ │ - * measurement is complete. The geometry will persist until a new │ │ │ │ - * measurement is started, the control is deactivated, or <cancel> is │ │ │ │ - * called. │ │ │ │ + * Constructor: OpenLayers.Control.Geolocate │ │ │ │ + * Create a new control to deal with browser geolocation API │ │ │ │ + * │ │ │ │ */ │ │ │ │ - persist: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: immediate │ │ │ │ - * {Boolean} Activates the immediate measurement so that the "measurepartial" │ │ │ │ - * event is also fired once the measurement sketch is modified. │ │ │ │ - * Default is false. │ │ │ │ + * Method: destroy │ │ │ │ */ │ │ │ │ - immediate: false, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.Measure │ │ │ │ + * Method: activate │ │ │ │ + * Activates the control. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * handler - {<OpenLayers.Handler>} │ │ │ │ - * options - {Object} │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The control was effectively activated. │ │ │ │ */ │ │ │ │ - initialize: function(handler, options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - var callbacks = { │ │ │ │ - done: this.measureComplete, │ │ │ │ - point: this.measurePartial │ │ │ │ - }; │ │ │ │ - if (this.immediate) { │ │ │ │ - callbacks.modify = this.measureImmediate; │ │ │ │ + activate: function() { │ │ │ │ + if (this.available && !this.geolocation) { │ │ │ │ + // set lazily to avoid IE9 memory leak │ │ │ │ + this.geolocation = navigator.geolocation; │ │ │ │ } │ │ │ │ - this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks); │ │ │ │ - │ │ │ │ - // let the handler options override, so old code that passes 'persist' │ │ │ │ - // directly to the handler does not need an update │ │ │ │ - this.handlerOptions = OpenLayers.Util.extend({ │ │ │ │ - persist: this.persist │ │ │ │ - }, this.handlerOptions); │ │ │ │ - this.handler = new handler(this, this.callbacks, this.handlerOptions); │ │ │ │ + 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; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ + * Method: deactivate │ │ │ │ + * Deactivates the control. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The control was effectively deactivated. │ │ │ │ */ │ │ │ │ deactivate: function() { │ │ │ │ - this.cancelDelay(); │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: cancel │ │ │ │ - * Stop the control from measuring. If <persist> is true, the temporary │ │ │ │ - * sketch will be erased. │ │ │ │ - */ │ │ │ │ - cancel: function() { │ │ │ │ - this.cancelDelay(); │ │ │ │ - this.handler.cancel(); │ │ │ │ + if (this.active && this.watchId !== null) { │ │ │ │ + this.geolocation.clearWatch(this.watchId); │ │ │ │ + } │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply( │ │ │ │ + this, arguments │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: setImmediate │ │ │ │ - * Sets the <immediate> property. Changes the activity of immediate │ │ │ │ - * measurement. │ │ │ │ + * Method: geolocate │ │ │ │ + * Activates the control. │ │ │ │ + * │ │ │ │ */ │ │ │ │ - setImmediate: function(immediate) { │ │ │ │ - this.immediate = immediate; │ │ │ │ - if (this.immediate) { │ │ │ │ - this.callbacks.modify = this.measureImmediate; │ │ │ │ - } else { │ │ │ │ - delete this.callbacks.modify; │ │ │ │ + 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 │ │ │ │ + ) │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: updateHandler │ │ │ │ + * APIMethod: getCurrentLocation │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * handler - {Function} One of the sketch handler constructors. │ │ │ │ - * options - {Object} Options for the handler. │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Returns true if a event will be fired (successfull │ │ │ │ + * registration) │ │ │ │ */ │ │ │ │ - updateHandler: function(handler, options) { │ │ │ │ - var active = this.active; │ │ │ │ - if (active) { │ │ │ │ - this.deactivate(); │ │ │ │ - } │ │ │ │ - this.handler = new handler(this, this.callbacks, options); │ │ │ │ - if (active) { │ │ │ │ - this.activate(); │ │ │ │ + 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: measureComplete │ │ │ │ - * Called when the measurement sketch is done. │ │ │ │ + * Method: failure │ │ │ │ + * method called on browser's geolocation failure │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ */ │ │ │ │ - measureComplete: function(geometry) { │ │ │ │ - this.cancelDelay(); │ │ │ │ - this.measure(geometry, "measure"); │ │ │ │ + failure: function(error) { │ │ │ │ + this.events.triggerEvent("locationfailed", { │ │ │ │ + error: error │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Geolocate" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + 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, { │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: measurePartial │ │ │ │ - * Called each time a new point is added to the measurement sketch. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * point - {<OpenLayers.Geometry.Point>} The last point added. │ │ │ │ - * geometry - {<OpenLayers.Geometry>} The sketch geometry. │ │ │ │ + * APIProperty: zoomInText │ │ │ │ + * {String} │ │ │ │ + * Text for zoom-in link. Default is "+". │ │ │ │ */ │ │ │ │ - measurePartial: function(point, geometry) { │ │ │ │ - this.cancelDelay(); │ │ │ │ - geometry = geometry.clone(); │ │ │ │ - // when we're wating for a dblclick, we have to trigger measurepartial │ │ │ │ - // after some delay to deal with reflow issues in IE │ │ │ │ - if (this.handler.freehandMode(this.handler.evt)) { │ │ │ │ - // no dblclick in freehand mode │ │ │ │ - this.measure(geometry, "measurepartial"); │ │ │ │ - } else { │ │ │ │ - this.delayedTrigger = window.setTimeout( │ │ │ │ - OpenLayers.Function.bind(function() { │ │ │ │ - this.delayedTrigger = null; │ │ │ │ - this.measure(geometry, "measurepartial"); │ │ │ │ - }, this), │ │ │ │ - this.partialDelay │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + zoomInText: "+", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: measureImmediate │ │ │ │ - * Called each time the measurement sketch is modified. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * point - {<OpenLayers.Geometry.Point>} The point at the mouse position. │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The sketch feature. │ │ │ │ - * drawing - {Boolean} Indicates whether we're currently drawing. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - measureImmediate: function(point, feature, drawing) { │ │ │ │ - if (drawing && !this.handler.freehandMode(this.handler.evt)) { │ │ │ │ - this.cancelDelay(); │ │ │ │ - this.measure(feature.geometry, "measurepartial"); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + zoomInId: "olZoomInLink", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: cancelDelay │ │ │ │ - * Cancels the delay measurement that measurePartial began. │ │ │ │ + * APIProperty: zoomOutText │ │ │ │ + * {String} │ │ │ │ + * Text for zoom-out link. Default is "\u2212". │ │ │ │ */ │ │ │ │ - cancelDelay: function() { │ │ │ │ - if (this.delayedTrigger !== null) { │ │ │ │ - window.clearTimeout(this.delayedTrigger); │ │ │ │ - this.delayedTrigger = null; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + zoomOutText: "\u2212", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: measure │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * eventType - {String} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - measure: function(geometry, eventType) { │ │ │ │ - var stat, order; │ │ │ │ - if (geometry.CLASS_NAME.indexOf('LineString') > -1) { │ │ │ │ - stat = this.getBestLength(geometry); │ │ │ │ - order = 1; │ │ │ │ - } else { │ │ │ │ - stat = this.getBestArea(geometry); │ │ │ │ - order = 2; │ │ │ │ - } │ │ │ │ - this.events.triggerEvent(eventType, { │ │ │ │ - measure: stat[0], │ │ │ │ - units: stat[1], │ │ │ │ - order: order, │ │ │ │ - geometry: geometry │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ + zoomOutId: "olZoomOutLink", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getBestArea │ │ │ │ - * Based on the <displaySystem> returns the area of a geometry. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * Method: draw │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Array([Float, String])} Returns a two item array containing the │ │ │ │ - * area and the units abbreviation. │ │ │ │ + * {DOMElement} A reference to the DOMElement containing the zoom links. │ │ │ │ */ │ │ │ │ - getBestArea: function(geometry) { │ │ │ │ - var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ - var unit, area; │ │ │ │ - for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ - unit = units[i]; │ │ │ │ - area = this.getArea(geometry, unit); │ │ │ │ - if (area > 1) { │ │ │ │ - break; │ │ │ │ - } │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - return [area, unit]; │ │ │ │ + eventsInstance.register("buttonclick", this, this.onZoomClick); │ │ │ │ + │ │ │ │ + this.zoomInLink = zoomIn; │ │ │ │ + this.zoomOutLink = zoomOut; │ │ │ │ + return div; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getArea │ │ │ │ - * │ │ │ │ + * Method: getOrCreateLinks │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * units - {String} Unit abbreviation │ │ │ │ + * el - {DOMElement} │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Float} The geometry area in the given units. │ │ │ │ + * Return: │ │ │ │ + * {Object} Object with zoomIn and zoomOut properties referencing links. │ │ │ │ */ │ │ │ │ - getArea: function(geometry, units) { │ │ │ │ - var area, geomUnits; │ │ │ │ - if (this.geodesic) { │ │ │ │ - area = geometry.getGeodesicArea(this.map.getProjectionObject()); │ │ │ │ - geomUnits = "m"; │ │ │ │ - } else { │ │ │ │ - area = geometry.getArea(); │ │ │ │ - geomUnits = this.map.getUnits(); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ - if (inPerDisplayUnit) { │ │ │ │ - var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ - area *= Math.pow((inPerMapUnit / inPerDisplayUnit), 2); │ │ │ │ + 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); │ │ │ │ } │ │ │ │ - return area; │ │ │ │ + OpenLayers.Element.addClass(zoomOut, "olButton"); │ │ │ │ + return { │ │ │ │ + zoomIn: zoomIn, │ │ │ │ + zoomOut: zoomOut │ │ │ │ + }; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getBestLength │ │ │ │ - * Based on the <displaySystem> returns the length of a geometry. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array([Float, String])} Returns a two item array containing the │ │ │ │ - * length and the units abbreviation. │ │ │ │ + * Method: onZoomClick │ │ │ │ + * Called when zoomin/out link is clicked. │ │ │ │ */ │ │ │ │ - getBestLength: function(geometry) { │ │ │ │ - var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ - var unit, length; │ │ │ │ - for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ - unit = units[i]; │ │ │ │ - length = this.getLength(geometry, unit); │ │ │ │ - if (length > 1) { │ │ │ │ - break; │ │ │ │ - } │ │ │ │ + onZoomClick: function(evt) { │ │ │ │ + var button = evt.buttonElement; │ │ │ │ + if (button === this.zoomInLink) { │ │ │ │ + this.map.zoomIn(); │ │ │ │ + } else if (button === this.zoomOutLink) { │ │ │ │ + this.map.zoomOut(); │ │ │ │ } │ │ │ │ - return [length, unit]; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getLength │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * units - {String} Unit abbreviation │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Float} The geometry length in the given units. │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + * Clean up. │ │ │ │ */ │ │ │ │ - getLength: function(geometry, units) { │ │ │ │ - var length, geomUnits; │ │ │ │ - if (this.geodesic) { │ │ │ │ - length = geometry.getGeodesicLength(this.map.getProjectionObject()); │ │ │ │ - geomUnits = "m"; │ │ │ │ - } else { │ │ │ │ - length = geometry.getLength(); │ │ │ │ - geomUnits = this.map.getUnits(); │ │ │ │ - } │ │ │ │ - var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ - if (inPerDisplayUnit) { │ │ │ │ - var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ - length *= (inPerMapUnit / inPerDisplayUnit); │ │ │ │ + destroy: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.unregister("buttonclick", this, this.onZoomClick); │ │ │ │ } │ │ │ │ - return length; │ │ │ │ + delete this.zoomInLink; │ │ │ │ + delete this.zoomOutLink; │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Measure" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Zoom" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Handler/Box.js │ │ │ │ + OpenLayers/Control/UTFGrid.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/Handler/Drag.js │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Handler/Hover.js │ │ │ │ + * @requires OpenLayers/Handler/Click.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Handler.Box │ │ │ │ - * Handler for dragging a rectangle across the map. Box is displayed │ │ │ │ - * on mouse down, moves on mouse move, and is finished on mouse up. │ │ │ │ + * Class: OpenLayers.Control.UTFGrid │ │ │ │ + * │ │ │ │ + * This Control provides behavior associated with UTFGrid Layers. │ │ │ │ + * These 'hit grids' provide underlying feature attributes without │ │ │ │ + * calling the server (again). This control allows Mousemove, Hovering │ │ │ │ + * and Click events to trigger callbacks that use the attributes in │ │ │ │ + * whatever way you need. │ │ │ │ + * │ │ │ │ + * The most common example may be a UTFGrid layer containing feature │ │ │ │ + * attributes that are displayed in a div as you mouseover. │ │ │ │ + * │ │ │ │ + * Example Code: │ │ │ │ + * │ │ │ │ + * (start code) │ │ │ │ + * var world_utfgrid = new OpenLayers.Layer.UTFGrid( │ │ │ │ + * 'UTFGrid Layer', │ │ │ │ + * "http://tiles/world_utfgrid/${z}/${x}/${y}.json" │ │ │ │ + * ); │ │ │ │ + * map.addLayer(world_utfgrid); │ │ │ │ + * │ │ │ │ + * var control = new OpenLayers.Control.UTFGrid({ │ │ │ │ + * layers: [world_utfgrid], │ │ │ │ + * handlerMode: 'move', │ │ │ │ + * callback: function(infoLookup) { │ │ │ │ + * // do something with returned data │ │ │ │ + * │ │ │ │ + * } │ │ │ │ + * }) │ │ │ │ + * (end code) │ │ │ │ + * │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Handler> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ +OpenLayers.Control.UTFGrid = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: autoActivate │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * true. │ │ │ │ + */ │ │ │ │ + autoActivate: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: dragHandler │ │ │ │ - * {<OpenLayers.Handler.Drag>} │ │ │ │ + * APIProperty: Layers │ │ │ │ + * List of layers to consider. Must be Layer.UTFGrids │ │ │ │ + * `null` is the default indicating all UTFGrid Layers are queried. │ │ │ │ + * {Array} <OpenLayers.Layer.UTFGrid> │ │ │ │ */ │ │ │ │ - dragHandler: null, │ │ │ │ + layers: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: boxDivClassName │ │ │ │ - * {String} The CSS class to use for drawing the box. Default is │ │ │ │ - * olHandlerBoxZoomBox │ │ │ │ + /* Property: defaultHandlerOptions │ │ │ │ + * The default opts passed to the handler constructors │ │ │ │ */ │ │ │ │ - boxDivClassName: 'olHandlerBoxZoomBox', │ │ │ │ + defaultHandlerOptions: { │ │ │ │ + 'delay': 300, │ │ │ │ + 'pixelTolerance': 4, │ │ │ │ + 'stopMove': false, │ │ │ │ + 'single': true, │ │ │ │ + 'double': false, │ │ │ │ + 'stopSingle': false, │ │ │ │ + 'stopDouble': false │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: boxOffsets │ │ │ │ - * {Object} Caches box offsets from css. This is used by the getBoxOffsets │ │ │ │ - * method. │ │ │ │ + /* APIProperty: handlerMode │ │ │ │ + * Defaults to 'click'. Can be 'hover' or 'move'. │ │ │ │ */ │ │ │ │ - boxOffsets: null, │ │ │ │ + handlerMode: 'click', │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Handler.Box │ │ │ │ + * APIMethod: setHandler │ │ │ │ + * sets this.handlerMode and calls resetHandler() │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * control - {<OpenLayers.Control>} │ │ │ │ - * callbacks - {Object} An object with a properties whose values are │ │ │ │ - * functions. Various callbacks described below. │ │ │ │ - * options - {Object} │ │ │ │ - * │ │ │ │ - * Named callbacks: │ │ │ │ - * start - Called when the box drag operation starts. │ │ │ │ - * done - Called when the box drag operation is finished. │ │ │ │ - * The callback should expect to receive a single argument, the box │ │ │ │ - * bounds or a pixel. If the box dragging didn't span more than a 5 │ │ │ │ - * pixel distance, a pixel will be returned instead of a bounds object. │ │ │ │ + * hm - {String} Handler Mode string; 'click', 'hover' or 'move'. │ │ │ │ */ │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ - this.dragHandler = new OpenLayers.Handler.Drag( │ │ │ │ - this, { │ │ │ │ - down: this.startBox, │ │ │ │ - move: this.moveBox, │ │ │ │ - out: this.removeBox, │ │ │ │ - up: this.endBox │ │ │ │ - }, { │ │ │ │ - keyMask: this.keyMask │ │ │ │ - } │ │ │ │ - ); │ │ │ │ + setHandler: function(hm) { │ │ │ │ + this.handlerMode = hm; │ │ │ │ + this.resetHandler(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroy │ │ │ │ + * Method: resetHandler │ │ │ │ + * Deactivates the old hanlder and creates a new │ │ │ │ + * <OpenLayers.Handler> based on the mode specified in │ │ │ │ + * this.handlerMode │ │ │ │ + * │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ - if (this.dragHandler) { │ │ │ │ - this.dragHandler.destroy(); │ │ │ │ - this.dragHandler = null; │ │ │ │ + resetHandler: function() { │ │ │ │ + if (this.handler) { │ │ │ │ + this.handler.deactivate(); │ │ │ │ + this.handler.destroy(); │ │ │ │ + this.handler = null; │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Handler.prototype.setMap.apply(this, arguments); │ │ │ │ - if (this.dragHandler) { │ │ │ │ - this.dragHandler.setMap(map); │ │ │ │ + if (this.handlerMode == 'hover') { │ │ │ │ + // Handle this event on hover │ │ │ │ + this.handler = new OpenLayers.Handler.Hover( │ │ │ │ + this, { │ │ │ │ + 'pause': this.handleEvent, │ │ │ │ + 'move': this.reset │ │ │ │ + }, │ │ │ │ + this.handlerOptions │ │ │ │ + ); │ │ │ │ + } else if (this.handlerMode == 'click') { │ │ │ │ + // Handle this event on click │ │ │ │ + this.handler = new OpenLayers.Handler.Click( │ │ │ │ + this, { │ │ │ │ + 'click': this.handleEvent │ │ │ │ + }, this.handlerOptions │ │ │ │ + ); │ │ │ │ + } else if (this.handlerMode == 'move') { │ │ │ │ + this.handler = new OpenLayers.Handler.Hover( │ │ │ │ + this, │ │ │ │ + // Handle this event while hovering OR moving │ │ │ │ + { │ │ │ │ + 'pause': this.handleEvent, │ │ │ │ + 'move': this.handleEvent │ │ │ │ + }, │ │ │ │ + this.handlerOptions │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (this.handler) { │ │ │ │ + return true; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: startBox │ │ │ │ + * Constructor: <OpenLayers.Control.UTFGrid> │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * xy - {<OpenLayers.Pixel>} │ │ │ │ - */ │ │ │ │ - startBox: function(xy) { │ │ │ │ - this.callback("start", []); │ │ │ │ - this.zoomBox = OpenLayers.Util.createDiv('zoomBox', { │ │ │ │ - x: -9999, │ │ │ │ - y: -9999 │ │ │ │ - }); │ │ │ │ - this.zoomBox.className = this.boxDivClassName; │ │ │ │ - this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1; │ │ │ │ - │ │ │ │ - this.map.viewPortDiv.appendChild(this.zoomBox); │ │ │ │ - │ │ │ │ - OpenLayers.Element.addClass( │ │ │ │ - this.map.viewPortDiv, "olDrawBox" │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: moveBox │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ - moveBox: function(xy) { │ │ │ │ - var startX = this.dragHandler.start.x; │ │ │ │ - var startY = this.dragHandler.start.y; │ │ │ │ - var deltaX = Math.abs(startX - xy.x); │ │ │ │ - var deltaY = Math.abs(startY - xy.y); │ │ │ │ - │ │ │ │ - var offset = this.getBoxOffsets(); │ │ │ │ - this.zoomBox.style.width = (deltaX + offset.width + 1) + "px"; │ │ │ │ - this.zoomBox.style.height = (deltaY + offset.height + 1) + "px"; │ │ │ │ - this.zoomBox.style.left = (xy.x < startX ? │ │ │ │ - startX - deltaX - offset.left : startX - offset.left) + "px"; │ │ │ │ - this.zoomBox.style.top = (xy.y < startY ? │ │ │ │ - startY - deltaY - offset.top : startY - offset.top) + "px"; │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + options.handlerOptions = options.handlerOptions || this.defaultHandlerOptions; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.resetHandler(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: endBox │ │ │ │ + * Method: handleEvent │ │ │ │ + * Internal method called when specified event is triggered. │ │ │ │ + * │ │ │ │ + * This method does several things: │ │ │ │ + * │ │ │ │ + * Gets the lonLat of the event. │ │ │ │ + * │ │ │ │ + * Loops through the appropriate hit grid layers and gathers the attributes. │ │ │ │ + * │ │ │ │ + * Passes the attributes to the callback │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ */ │ │ │ │ - endBox: function(end) { │ │ │ │ - var result; │ │ │ │ - if (Math.abs(this.dragHandler.start.x - end.x) > 5 || │ │ │ │ - Math.abs(this.dragHandler.start.y - end.y) > 5) { │ │ │ │ - var start = this.dragHandler.start; │ │ │ │ - var top = Math.min(start.y, end.y); │ │ │ │ - var bottom = Math.max(start.y, end.y); │ │ │ │ - var left = Math.min(start.x, end.x); │ │ │ │ - var right = Math.max(start.x, end.x); │ │ │ │ - result = new OpenLayers.Bounds(left, bottom, right, top); │ │ │ │ - } else { │ │ │ │ - result = this.dragHandler.start.clone(); // i.e. OL.Pixel │ │ │ │ + handleEvent: function(evt) { │ │ │ │ + if (evt == null) { │ │ │ │ + this.reset(); │ │ │ │ + return; │ │ │ │ } │ │ │ │ - this.removeBox(); │ │ │ │ │ │ │ │ - this.callback("done", [result]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: removeBox │ │ │ │ - * Remove the zoombox from the screen and nullify our reference to it. │ │ │ │ - */ │ │ │ │ - removeBox: function() { │ │ │ │ - this.map.viewPortDiv.removeChild(this.zoomBox); │ │ │ │ - this.zoomBox = null; │ │ │ │ - this.boxOffsets = null; │ │ │ │ - OpenLayers.Element.removeClass( │ │ │ │ - this.map.viewPortDiv, "olDrawBox" │ │ │ │ - ); │ │ │ │ + var lonLat = this.map.getLonLatFromPixel(evt.xy); │ │ │ │ + if (!lonLat) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ │ │ │ │ + var layers = this.findLayers(); │ │ │ │ + if (layers.length > 0) { │ │ │ │ + var infoLookup = {}; │ │ │ │ + var layer, idx; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + layer = layers[i]; │ │ │ │ + idx = OpenLayers.Util.indexOf(this.map.layers, layer); │ │ │ │ + infoLookup[idx] = layer.getFeatureInfo(lonLat); │ │ │ │ + } │ │ │ │ + this.callback(infoLookup, lonLat, evt.xy); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ + * APIMethod: callback │ │ │ │ + * Function to be called when a mouse event corresponds with a location that │ │ │ │ + * includes data in one of the configured UTFGrid layers. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * infoLookup - {Object} Keys of this object are layer indexes and can be │ │ │ │ + * used to resolve a layer in the map.layers array. The structure of │ │ │ │ + * the property values depend on the data included in the underlying │ │ │ │ + * UTFGrid and may be any valid JSON type. │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.dragHandler.activate(); │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ + callback: function(infoLookup) { │ │ │ │ + // to be provided in the constructor │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ + * Method: reset │ │ │ │ + * Calls the callback with null. │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - if (this.dragHandler.deactivate()) { │ │ │ │ - if (this.zoomBox) { │ │ │ │ - this.removeBox(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ + reset: function(evt) { │ │ │ │ + this.callback(null); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getBoxOffsets │ │ │ │ - * Determines border offsets for a box, according to the box model. │ │ │ │ - * │ │ │ │ + * Method: findLayers │ │ │ │ + * Internal method to get the layers, independent of whether we are │ │ │ │ + * inspecting the map or using a client-provided array │ │ │ │ + * │ │ │ │ + * The default value of this.layers is null; this causes the │ │ │ │ + * findLayers method to return ALL UTFGrid layers encountered. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * None │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} an object with the following offsets: │ │ │ │ - * - left │ │ │ │ - * - right │ │ │ │ - * - top │ │ │ │ - * - bottom │ │ │ │ - * - width │ │ │ │ - * - height │ │ │ │ + * {Array} Layers to handle on each event │ │ │ │ */ │ │ │ │ - getBoxOffsets: function() { │ │ │ │ - if (!this.boxOffsets) { │ │ │ │ - // Determine the box model. If the testDiv's clientWidth is 3, then │ │ │ │ - // the borders are outside and we are dealing with the w3c box │ │ │ │ - // model. Otherwise, the browser uses the traditional box model and │ │ │ │ - // the borders are inside the box bounds, leaving us with a │ │ │ │ - // clientWidth of 1. │ │ │ │ - var testDiv = document.createElement("div"); │ │ │ │ - //testDiv.style.visibility = "hidden"; │ │ │ │ - testDiv.style.position = "absolute"; │ │ │ │ - testDiv.style.border = "1px solid black"; │ │ │ │ - testDiv.style.width = "3px"; │ │ │ │ - document.body.appendChild(testDiv); │ │ │ │ - var w3cBoxModel = testDiv.clientWidth == 3; │ │ │ │ - document.body.removeChild(testDiv); │ │ │ │ - │ │ │ │ - var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ - "border-left-width")); │ │ │ │ - var right = parseInt(OpenLayers.Element.getStyle( │ │ │ │ - this.zoomBox, "border-right-width")); │ │ │ │ - var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ - "border-top-width")); │ │ │ │ - var bottom = parseInt(OpenLayers.Element.getStyle( │ │ │ │ - this.zoomBox, "border-bottom-width")); │ │ │ │ - this.boxOffsets = { │ │ │ │ - left: left, │ │ │ │ - right: right, │ │ │ │ - top: top, │ │ │ │ - bottom: bottom, │ │ │ │ - width: w3cBoxModel === false ? left + right : 0, │ │ │ │ - height: w3cBoxModel === false ? top + bottom : 0 │ │ │ │ - }; │ │ │ │ + findLayers: function() { │ │ │ │ + var candidates = this.layers || this.map.layers; │ │ │ │ + var layers = []; │ │ │ │ + var layer; │ │ │ │ + for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ + layer = candidates[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.UTFGrid) { │ │ │ │ + layers.push(layer); │ │ │ │ + } │ │ │ │ } │ │ │ │ - return this.boxOffsets; │ │ │ │ + return layers; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Box" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.UTFGrid" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Control/ZoomBox.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ @@ -64775,450 +71119,14 @@ │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Control.ZoomBox" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - 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/Handler/MouseWheel.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.MouseWheel │ │ │ │ - * Handler for wheel up/down events. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Handler> │ │ │ │ - */ │ │ │ │ -OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - /** │ │ │ │ - * Property: wheelListener │ │ │ │ - * {function} │ │ │ │ - */ │ │ │ │ - wheelListener: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: interval │ │ │ │ - * {Integer} In order to increase server performance, an interval (in │ │ │ │ - * milliseconds) can be set to reduce the number of up/down events │ │ │ │ - * called. If set, a new up/down event will not be set until the │ │ │ │ - * interval has passed. │ │ │ │ - * Defaults to 0, meaning no interval. │ │ │ │ - */ │ │ │ │ - interval: 0, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: maxDelta │ │ │ │ - * {Integer} Maximum delta to collect before breaking from the current │ │ │ │ - * interval. In cumulative mode, this also limits the maximum delta │ │ │ │ - * returned from the handler. Default is Number.POSITIVE_INFINITY. │ │ │ │ - */ │ │ │ │ - maxDelta: Number.POSITIVE_INFINITY, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: delta │ │ │ │ - * {Integer} When interval is set, delta collects the mousewheel z-deltas │ │ │ │ - * of the events that occur within the interval. │ │ │ │ - * See also the cumulative option │ │ │ │ - */ │ │ │ │ - delta: 0, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: cumulative │ │ │ │ - * {Boolean} When interval is set: true to collect all the mousewheel │ │ │ │ - * z-deltas, false to only record the delta direction (positive or │ │ │ │ - * negative) │ │ │ │ - */ │ │ │ │ - cumulative: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Handler.MouseWheel │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * control - {<OpenLayers.Control>} │ │ │ │ - * 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 point geometry. │ │ │ │ - * options - {Object} │ │ │ │ - */ │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ - this.wheelListener = OpenLayers.Function.bindAsEventListener( │ │ │ │ - this.onWheelEvent, this │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ - this.wheelListener = null; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/ │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: onWheelEvent │ │ │ │ - * Catch the wheel event and handle it xbrowserly │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {Event} │ │ │ │ - */ │ │ │ │ - onWheelEvent: function(e) { │ │ │ │ - │ │ │ │ - // make sure we have a map and check keyboard modifiers │ │ │ │ - if (!this.map || !this.checkModifiers(e)) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // Ride up the element's DOM hierarchy to determine if it or any of │ │ │ │ - // its ancestors was: │ │ │ │ - // * specifically marked as scrollable (CSS overflow property) │ │ │ │ - // * one of our layer divs or a div marked as scrollable │ │ │ │ - // ('olScrollable' CSS class) │ │ │ │ - // * the map div │ │ │ │ - // │ │ │ │ - var overScrollableDiv = false; │ │ │ │ - var allowScroll = false; │ │ │ │ - var overMapDiv = false; │ │ │ │ - │ │ │ │ - var elem = OpenLayers.Event.element(e); │ │ │ │ - while ((elem != null) && !overMapDiv && !overScrollableDiv) { │ │ │ │ - │ │ │ │ - if (!overScrollableDiv) { │ │ │ │ - try { │ │ │ │ - var overflow; │ │ │ │ - if (elem.currentStyle) { │ │ │ │ - overflow = elem.currentStyle["overflow"]; │ │ │ │ - } else { │ │ │ │ - var style = │ │ │ │ - document.defaultView.getComputedStyle(elem, null); │ │ │ │ - overflow = style.getPropertyValue("overflow"); │ │ │ │ - } │ │ │ │ - overScrollableDiv = (overflow && │ │ │ │ - (overflow == "auto") || (overflow == "scroll")); │ │ │ │ - } catch (err) { │ │ │ │ - //sometimes when scrolling in a popup, this causes │ │ │ │ - // obscure browser error │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (!allowScroll) { │ │ │ │ - allowScroll = OpenLayers.Element.hasClass(elem, 'olScrollable'); │ │ │ │ - if (!allowScroll) { │ │ │ │ - for (var i = 0, len = this.map.layers.length; i < len; i++) { │ │ │ │ - // Are we in the layer div? Note that we have two cases │ │ │ │ - // here: one is to catch EventPane layers, which have a │ │ │ │ - // pane above the layer (layer.pane) │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - if (elem == layer.div || elem == layer.pane) { │ │ │ │ - allowScroll = true; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - overMapDiv = (elem == this.map.div); │ │ │ │ - │ │ │ │ - elem = elem.parentNode; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // Logic below is the following: │ │ │ │ - // │ │ │ │ - // If we are over a scrollable div or not over the map div: │ │ │ │ - // * do nothing (let the browser handle scrolling) │ │ │ │ - // │ │ │ │ - // otherwise │ │ │ │ - // │ │ │ │ - // If we are over the layer div or a 'olScrollable' div: │ │ │ │ - // * zoom/in out │ │ │ │ - // then │ │ │ │ - // * kill event (so as not to also scroll the page after zooming) │ │ │ │ - // │ │ │ │ - // otherwise │ │ │ │ - // │ │ │ │ - // Kill the event (dont scroll the page if we wheel over the │ │ │ │ - // layerswitcher or the pan/zoom control) │ │ │ │ - // │ │ │ │ - if (!overScrollableDiv && overMapDiv) { │ │ │ │ - if (allowScroll) { │ │ │ │ - var delta = 0; │ │ │ │ - │ │ │ │ - if (e.wheelDelta) { │ │ │ │ - delta = e.wheelDelta; │ │ │ │ - if (delta % 160 === 0) { │ │ │ │ - // opera have steps of 160 instead of 120 │ │ │ │ - delta = delta * 0.75; │ │ │ │ - } │ │ │ │ - delta = delta / 120; │ │ │ │ - } else if (e.detail) { │ │ │ │ - // detail in Firefox on OS X is 1/3 of Windows │ │ │ │ - // so force delta 1 / -1 │ │ │ │ - delta = -(e.detail / Math.abs(e.detail)); │ │ │ │ - } │ │ │ │ - this.delta += delta; │ │ │ │ - │ │ │ │ - window.clearTimeout(this._timeoutId); │ │ │ │ - if (this.interval && Math.abs(this.delta) < this.maxDelta) { │ │ │ │ - // store e because window.event might change during delay │ │ │ │ - var evt = OpenLayers.Util.extend({}, e); │ │ │ │ - this._timeoutId = window.setTimeout( │ │ │ │ - OpenLayers.Function.bind(function() { │ │ │ │ - this.wheelZoom(evt); │ │ │ │ - }, this), │ │ │ │ - this.interval │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - this.wheelZoom(e); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - OpenLayers.Event.stop(e); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: wheelZoom │ │ │ │ - * Given the wheel event, we carry out the appropriate zooming in or out, │ │ │ │ - * based on the 'wheelDelta' or 'detail' property of the event. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {Event} │ │ │ │ - */ │ │ │ │ - wheelZoom: function(e) { │ │ │ │ - var delta = this.delta; │ │ │ │ - this.delta = 0; │ │ │ │ - │ │ │ │ - if (delta) { │ │ │ │ - e.xy = this.map.events.getMousePosition(e); │ │ │ │ - if (delta < 0) { │ │ │ │ - this.callback("down", │ │ │ │ - [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]); │ │ │ │ - } else { │ │ │ │ - this.callback("up", │ │ │ │ - [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: activate │ │ │ │ - */ │ │ │ │ - activate: function(evt) { │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - //register mousewheel events specifically on the window and document │ │ │ │ - var wheelListener = this.wheelListener; │ │ │ │ - OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener); │ │ │ │ - OpenLayers.Event.observe(window, "mousewheel", wheelListener); │ │ │ │ - OpenLayers.Event.observe(document, "mousewheel", wheelListener); │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: deactivate │ │ │ │ - */ │ │ │ │ - deactivate: function(evt) { │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - // unregister mousewheel events specifically on the window and document │ │ │ │ - var wheelListener = this.wheelListener; │ │ │ │ - OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener); │ │ │ │ - OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener); │ │ │ │ - OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener); │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.MouseWheel" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ OpenLayers/Control/Navigation.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. */ │ │ │ │ @@ -65627,14 +71535,2352 @@ │ │ │ │ } │ │ │ │ return div; │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Control.NavToolbar" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ + OpenLayers/Format/WMSGetFeatureInfo.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.WMSGetFeatureInfo │ │ │ │ + * Class to read GetFeatureInfo responses from Web Mapping Services │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: layerIdentifier │ │ │ │ + * {String} All xml nodes containing this search criteria will populate an │ │ │ │ + * internal array of layer nodes. │ │ │ │ + */ │ │ │ │ + layerIdentifier: '_layer', │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: featureIdentifier │ │ │ │ + * {String} All xml nodes containing this search criteria will populate an │ │ │ │ + * internal array of feature nodes for each layer node found. │ │ │ │ + */ │ │ │ │ + featureIdentifier: '_feature', │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ + */ │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: gmlFormat │ │ │ │ + * {<OpenLayers.Format.GML>} internal GML format for parsing geometries │ │ │ │ + * in msGMLOutput │ │ │ │ + */ │ │ │ │ + gmlFormat: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMSGetFeatureInfo │ │ │ │ + * Create a new parser for WMS GetFeatureInfo responses │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read WMS GetFeatureInfo data from a string, and return an array of features │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} An array of features. │ │ │ │ + */ │ │ │ │ + read: function(data) { │ │ │ │ + var result; │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ + } │ │ │ │ + var root = data.documentElement; │ │ │ │ + if (root) { │ │ │ │ + var scope = this; │ │ │ │ + var read = this["read_" + root.nodeName]; │ │ │ │ + if (read) { │ │ │ │ + result = read.call(this, root); │ │ │ │ + } else { │ │ │ │ + // fall-back to GML since this is a common output format for WMS │ │ │ │ + // GetFeatureInfo responses │ │ │ │ + result = new OpenLayers.Format.GML((this.options ? this.options : {})).read(data); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + result = data; │ │ │ │ + } │ │ │ │ + return result; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: read_msGMLOutput │ │ │ │ + * Parse msGMLOutput nodes. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {DOMElement} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array} │ │ │ │ + */ │ │ │ │ + read_msGMLOutput: function(data) { │ │ │ │ + var response = []; │ │ │ │ + var layerNodes = this.getSiblingNodesByTagCriteria(data, │ │ │ │ + this.layerIdentifier); │ │ │ │ + if (layerNodes) { │ │ │ │ + for (var i = 0, len = layerNodes.length; i < len; ++i) { │ │ │ │ + var node = layerNodes[i]; │ │ │ │ + var layerName = node.nodeName; │ │ │ │ + if (node.prefix) { │ │ │ │ + layerName = layerName.split(':')[1]; │ │ │ │ + } │ │ │ │ + var layerName = layerName.replace(this.layerIdentifier, ''); │ │ │ │ + var featureNodes = this.getSiblingNodesByTagCriteria(node, │ │ │ │ + this.featureIdentifier); │ │ │ │ + if (featureNodes) { │ │ │ │ + for (var j = 0; j < featureNodes.length; j++) { │ │ │ │ + var featureNode = featureNodes[j]; │ │ │ │ + var geomInfo = this.parseGeometry(featureNode); │ │ │ │ + var attributes = this.parseAttributes(featureNode); │ │ │ │ + var feature = new OpenLayers.Feature.Vector(geomInfo.geometry, │ │ │ │ + attributes, null); │ │ │ │ + feature.bounds = geomInfo.bounds; │ │ │ │ + feature.type = layerName; │ │ │ │ + response.push(feature); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return response; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: read_FeatureInfoResponse │ │ │ │ + * Parse FeatureInfoResponse nodes. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {DOMElement} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array} │ │ │ │ + */ │ │ │ │ + read_FeatureInfoResponse: function(data) { │ │ │ │ + var response = []; │ │ │ │ + var featureNodes = this.getElementsByTagNameNS(data, '*', │ │ │ │ + 'FIELDS'); │ │ │ │ + │ │ │ │ + for (var i = 0, len = featureNodes.length; i < len; i++) { │ │ │ │ + var featureNode = featureNodes[i]; │ │ │ │ + var geom = null; │ │ │ │ + │ │ │ │ + // attributes can be actual attributes on the FIELDS tag, │ │ │ │ + // or FIELD children │ │ │ │ + var attributes = {}; │ │ │ │ + var j; │ │ │ │ + var jlen = featureNode.attributes.length; │ │ │ │ + if (jlen > 0) { │ │ │ │ + for (j = 0; j < jlen; j++) { │ │ │ │ + var attribute = featureNode.attributes[j]; │ │ │ │ + attributes[attribute.nodeName] = attribute.nodeValue; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + var nodes = featureNode.childNodes; │ │ │ │ + for (j = 0, jlen = nodes.length; j < jlen; ++j) { │ │ │ │ + var node = nodes[j]; │ │ │ │ + if (node.nodeType != 3) { │ │ │ │ + attributes[node.getAttribute("name")] = │ │ │ │ + node.getAttribute("value"); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + response.push( │ │ │ │ + new OpenLayers.Feature.Vector(geom, attributes, null) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + return response; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getSiblingNodesByTagCriteria │ │ │ │ + * Recursively searches passed xml node and all it's descendant levels for │ │ │ │ + * nodes whose tagName contains the passed search string. This returns an │ │ │ │ + * array of all sibling nodes which match the criteria from the highest │ │ │ │ + * hierarchial level from which a match is found. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} An xml node │ │ │ │ + * criteria - {String} Search string which will match some part of a tagName │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * Array({DOMElement}) An array of sibling xml nodes │ │ │ │ + */ │ │ │ │ + getSiblingNodesByTagCriteria: function(node, criteria) { │ │ │ │ + var nodes = []; │ │ │ │ + var children, tagName, n, matchNodes, child; │ │ │ │ + if (node && node.hasChildNodes()) { │ │ │ │ + children = node.childNodes; │ │ │ │ + n = children.length; │ │ │ │ + │ │ │ │ + for (var k = 0; k < n; k++) { │ │ │ │ + child = children[k]; │ │ │ │ + while (child && child.nodeType != 1) { │ │ │ │ + child = child.nextSibling; │ │ │ │ + k++; │ │ │ │ + } │ │ │ │ + tagName = (child ? child.nodeName : ''); │ │ │ │ + if (tagName.length > 0 && tagName.indexOf(criteria) > -1) { │ │ │ │ + nodes.push(child); │ │ │ │ + } else { │ │ │ │ + matchNodes = this.getSiblingNodesByTagCriteria( │ │ │ │ + child, criteria); │ │ │ │ + │ │ │ │ + if (matchNodes.length > 0) { │ │ │ │ + (nodes.length == 0) ? │ │ │ │ + nodes = matchNodes: nodes.push(matchNodes); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + } │ │ │ │ + return nodes; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseAttributes │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {<DOMElement>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} An attributes object. │ │ │ │ + * │ │ │ │ + * Notes: │ │ │ │ + * Assumes that attributes are direct child xml nodes of the passed node │ │ │ │ + * and contain only a single text node. │ │ │ │ + */ │ │ │ │ + parseAttributes: function(node) { │ │ │ │ + var attributes = {}; │ │ │ │ + if (node.nodeType == 1) { │ │ │ │ + var children = node.childNodes; │ │ │ │ + var n = children.length; │ │ │ │ + for (var i = 0; i < n; ++i) { │ │ │ │ + var child = children[i]; │ │ │ │ + if (child.nodeType == 1) { │ │ │ │ + var grandchildren = child.childNodes; │ │ │ │ + var name = (child.prefix) ? │ │ │ │ + child.nodeName.split(":")[1] : child.nodeName; │ │ │ │ + if (grandchildren.length == 0) { │ │ │ │ + attributes[name] = null; │ │ │ │ + } else if (grandchildren.length == 1) { │ │ │ │ + var grandchild = grandchildren[0]; │ │ │ │ + if (grandchild.nodeType == 3 || │ │ │ │ + grandchild.nodeType == 4) { │ │ │ │ + var value = grandchild.nodeValue.replace( │ │ │ │ + this.regExes.trimSpace, ""); │ │ │ │ + attributes[name] = value; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return attributes; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: parseGeometry │ │ │ │ + * Parse the geometry and the feature bounds out of the node using │ │ │ │ + * Format.GML │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {<DOMElement>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} An object containing the geometry and the feature bounds │ │ │ │ + */ │ │ │ │ + parseGeometry: function(node) { │ │ │ │ + // we need to use the old Format.GML parser since we do not know the │ │ │ │ + // geometry name │ │ │ │ + if (!this.gmlFormat) { │ │ │ │ + this.gmlFormat = new OpenLayers.Format.GML(); │ │ │ │ + } │ │ │ │ + var feature = this.gmlFormat.parseFeature(node); │ │ │ │ + var geometry, bounds = null; │ │ │ │ + if (feature) { │ │ │ │ + geometry = feature.geometry && feature.geometry.clone(); │ │ │ │ + bounds = feature.bounds && feature.bounds.clone(); │ │ │ │ + feature.destroy(); │ │ │ │ + } │ │ │ │ + return { │ │ │ │ + geometry: geometry, │ │ │ │ + bounds: bounds │ │ │ │ + }; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSGetFeatureInfo" │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/WMSGetFeatureInfo.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/Click.js │ │ │ │ + * @requires OpenLayers/Handler/Hover.js │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ + * @requires OpenLayers/Format/WMSGetFeatureInfo.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.WMSGetFeatureInfo │ │ │ │ + * The WMSGetFeatureInfo control uses a WMS query to get information about a point on the map. The │ │ │ │ + * information may be in a display-friendly format such as HTML, or a machine-friendly format such │ │ │ │ + * as GML, depending on the server's capabilities and the client's configuration. This control │ │ │ │ + * handles click or hover events, attempts to parse the results using an OpenLayers.Format, and │ │ │ │ + * fires a 'getfeatureinfo' event with the click position, the raw body of the response, and an │ │ │ │ + * array of features if it successfully read the response. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: hover │ │ │ │ + * {Boolean} Send GetFeatureInfo requests when mouse stops moving. │ │ │ │ + * Default is false. │ │ │ │ + */ │ │ │ │ + hover: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: drillDown │ │ │ │ + * {Boolean} Drill down over all WMS layers in the map. When │ │ │ │ + * using drillDown mode, hover is not possible, and an infoFormat that │ │ │ │ + * returns parseable features is required. Default is false. │ │ │ │ + */ │ │ │ │ + drillDown: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: maxFeatures │ │ │ │ + * {Integer} Maximum number of features to return from a WMS query. This │ │ │ │ + * sets the feature_count parameter on WMS GetFeatureInfo │ │ │ │ + * requests. │ │ │ │ + */ │ │ │ │ + maxFeatures: 10, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: clickCallback │ │ │ │ + * {String} The click callback to register in the │ │ │ │ + * {<OpenLayers.Handler.Click>} object created when the hover │ │ │ │ + * option is set to false. Default is "click". │ │ │ │ + */ │ │ │ │ + clickCallback: "click", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: output │ │ │ │ + * {String} Either "features" or "object". When triggering a getfeatureinfo │ │ │ │ + * request should we pass on an array of features or an object with with │ │ │ │ + * a "features" property and other properties (such as the url of the │ │ │ │ + * WMS). Default is "features". │ │ │ │ + */ │ │ │ │ + output: "features", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: layers │ │ │ │ + * {Array(<OpenLayers.Layer.WMS>)} The layers to query for feature info. │ │ │ │ + * If omitted, all map WMS layers with a url that matches this <url> or │ │ │ │ + * <layerUrls> will be considered. │ │ │ │ + */ │ │ │ │ + layers: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: queryVisible │ │ │ │ + * {Boolean} If true, filter out hidden layers when searching the map for │ │ │ │ + * layers to query. Default is false. │ │ │ │ + */ │ │ │ │ + queryVisible: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: url │ │ │ │ + * {String} The URL of the WMS service to use. If not provided, the url │ │ │ │ + * of the first eligible layer will be used. │ │ │ │ + */ │ │ │ │ + url: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: layerUrls │ │ │ │ + * {Array(String)} Optional list of urls for layers that should be queried. │ │ │ │ + * This can be used when the layer url differs from the url used for │ │ │ │ + * making GetFeatureInfo requests (in the case of a layer using cached │ │ │ │ + * tiles). │ │ │ │ + */ │ │ │ │ + layerUrls: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: infoFormat │ │ │ │ + * {String} The mimetype to request from the server. If you are using │ │ │ │ + * drillDown mode and have multiple servers that do not share a common │ │ │ │ + * infoFormat, you can override the control's infoFormat by providing an │ │ │ │ + * INFO_FORMAT parameter in your <OpenLayers.Layer.WMS> instance(s). │ │ │ │ + */ │ │ │ │ + infoFormat: 'text/html', │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: vendorParams │ │ │ │ + * {Object} Additional parameters that will be added to the request, for │ │ │ │ + * WMS implementations that support them. This could e.g. look like │ │ │ │ + * (start code) │ │ │ │ + * { │ │ │ │ + * radius: 5 │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ + */ │ │ │ │ + vendorParams: {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: format │ │ │ │ + * {<OpenLayers.Format>} A format for parsing GetFeatureInfo responses. │ │ │ │ + * Default is <OpenLayers.Format.WMSGetFeatureInfo>. │ │ │ │ + */ │ │ │ │ + format: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: formatOptions │ │ │ │ + * {Object} Optional properties to set on the format (if one is not provided │ │ │ │ + * in the <format> property. │ │ │ │ + */ │ │ │ │ + formatOptions: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: handlerOptions │ │ │ │ + * {Object} Additional options for the handlers used by this control, e.g. │ │ │ │ + * (start code) │ │ │ │ + * { │ │ │ │ + * "click": {delay: 100}, │ │ │ │ + * "hover": {delay: 300} │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: handler │ │ │ │ + * {Object} Reference to the <OpenLayers.Handler> for this control │ │ │ │ + */ │ │ │ │ + handler: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: hoverRequest │ │ │ │ + * {<OpenLayers.Request>} contains the currently running hover request │ │ │ │ + * (if any). │ │ │ │ + */ │ │ │ │ + hoverRequest: 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>): │ │ │ │ + * beforegetfeatureinfo - Triggered before the request is sent. │ │ │ │ + * The event object has an *xy* property with the position of the │ │ │ │ + * mouse click or hover event that triggers the request. │ │ │ │ + * nogetfeatureinfo - no queryable layers were found. │ │ │ │ + * getfeatureinfo - Triggered when a GetFeatureInfo response is received. │ │ │ │ + * The event object has a *text* property with the body of the │ │ │ │ + * response (String), a *features* property with an array of the │ │ │ │ + * parsed features, an *xy* property with the position of the mouse │ │ │ │ + * click or hover event that triggered the request, and a *request* │ │ │ │ + * property with the request itself. If drillDown is set to true and │ │ │ │ + * multiple requests were issued to collect feature info from all │ │ │ │ + * layers, *text* and *request* will only contain the response body │ │ │ │ + * and request object of the last request. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: <OpenLayers.Control.WMSGetFeatureInfo> │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} │ │ │ │ + */ │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + options.handlerOptions = options.handlerOptions || {}; │ │ │ │ + │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + │ │ │ │ + if (!this.format) { │ │ │ │ + this.format = new OpenLayers.Format.WMSGetFeatureInfo( │ │ │ │ + options.formatOptions │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.drillDown === true) { │ │ │ │ + this.hover = false; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.hover) { │ │ │ │ + this.handler = new OpenLayers.Handler.Hover( │ │ │ │ + this, { │ │ │ │ + 'move': this.cancelHover, │ │ │ │ + 'pause': this.getInfoForHover │ │ │ │ + }, │ │ │ │ + OpenLayers.Util.extend(this.handlerOptions.hover || {}, { │ │ │ │ + 'delay': 250 │ │ │ │ + })); │ │ │ │ + } else { │ │ │ │ + var callbacks = {}; │ │ │ │ + callbacks[this.clickCallback] = this.getInfoForClick; │ │ │ │ + this.handler = new OpenLayers.Handler.Click( │ │ │ │ + this, callbacks, this.handlerOptions.click || {}); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getInfoForClick │ │ │ │ + * Called on click │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ + */ │ │ │ │ + getInfoForClick: function(evt) { │ │ │ │ + this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ + xy: evt.xy │ │ │ │ + }); │ │ │ │ + // Set the cursor to "wait" to tell the user we're working on their │ │ │ │ + // click. │ │ │ │ + OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + this.request(evt.xy, {}); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getInfoForHover │ │ │ │ + * Pause callback for the hover handler │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Object} │ │ │ │ + */ │ │ │ │ + getInfoForHover: function(evt) { │ │ │ │ + this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ + xy: evt.xy │ │ │ │ + }); │ │ │ │ + this.request(evt.xy, { │ │ │ │ + hover: true │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: cancelHover │ │ │ │ + * Cancel callback for the hover handler │ │ │ │ + */ │ │ │ │ + cancelHover: function() { │ │ │ │ + if (this.hoverRequest) { │ │ │ │ + this.hoverRequest.abort(); │ │ │ │ + this.hoverRequest = null; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: findLayers │ │ │ │ + * Internal method to get the layers, independent of whether we are │ │ │ │ + * inspecting the map or using a client-provided array │ │ │ │ + */ │ │ │ │ + findLayers: function() { │ │ │ │ + │ │ │ │ + var candidates = this.layers || this.map.layers; │ │ │ │ + var layers = []; │ │ │ │ + var layer, url; │ │ │ │ + for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ + layer = candidates[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.WMS && │ │ │ │ + (!this.queryVisible || layer.getVisibility())) { │ │ │ │ + url = OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url; │ │ │ │ + // if the control was not configured with a url, set it │ │ │ │ + // to the first layer url │ │ │ │ + if (this.drillDown === false && !this.url) { │ │ │ │ + this.url = url; │ │ │ │ + } │ │ │ │ + if (this.drillDown === true || this.urlMatches(url)) { │ │ │ │ + layers.push(layer); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return layers; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: urlMatches │ │ │ │ + * Test to see if the provided url matches either the control <url> or one │ │ │ │ + * of the <layerUrls>. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * url - {String} The url to test. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The provided url matches the control <url> or one of the │ │ │ │ + * <layerUrls>. │ │ │ │ + */ │ │ │ │ + urlMatches: function(url) { │ │ │ │ + var matches = OpenLayers.Util.isEquivalentUrl(this.url, url); │ │ │ │ + if (!matches && this.layerUrls) { │ │ │ │ + for (var i = 0, len = this.layerUrls.length; i < len; ++i) { │ │ │ │ + if (OpenLayers.Util.isEquivalentUrl(this.layerUrls[i], url)) { │ │ │ │ + matches = true; │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return matches; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: buildWMSOptions │ │ │ │ + * Build an object with the relevant WMS options for the GetFeatureInfo request │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * url - {String} The url to be used for sending the request │ │ │ │ + * layers - {Array(<OpenLayers.Layer.WMS)} An array of layers │ │ │ │ + * clickPosition - {<OpenLayers.Pixel>} The position on the map where the mouse │ │ │ │ + * event occurred. │ │ │ │ + * format - {String} The format from the corresponding GetMap request │ │ │ │ + */ │ │ │ │ + buildWMSOptions: function(url, layers, clickPosition, format) { │ │ │ │ + var layerNames = [], │ │ │ │ + styleNames = []; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + if (layers[i].params.LAYERS != null) { │ │ │ │ + layerNames = layerNames.concat(layers[i].params.LAYERS); │ │ │ │ + styleNames = styleNames.concat(this.getStyleNames(layers[i])); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var firstLayer = layers[0]; │ │ │ │ + // use the firstLayer's projection if it matches the map projection - │ │ │ │ + // this assumes that all layers will be available in this projection │ │ │ │ + var projection = this.map.getProjection(); │ │ │ │ + var layerProj = firstLayer.projection; │ │ │ │ + if (layerProj && layerProj.equals(this.map.getProjectionObject())) { │ │ │ │ + projection = layerProj.getCode(); │ │ │ │ + } │ │ │ │ + var params = OpenLayers.Util.extend({ │ │ │ │ + service: "WMS", │ │ │ │ + version: firstLayer.params.VERSION, │ │ │ │ + request: "GetFeatureInfo", │ │ │ │ + exceptions: firstLayer.params.EXCEPTIONS, │ │ │ │ + bbox: this.map.getExtent().toBBOX(null, │ │ │ │ + firstLayer.reverseAxisOrder()), │ │ │ │ + feature_count: this.maxFeatures, │ │ │ │ + height: this.map.getSize().h, │ │ │ │ + width: this.map.getSize().w, │ │ │ │ + format: format, │ │ │ │ + info_format: firstLayer.params.INFO_FORMAT || this.infoFormat │ │ │ │ + }, (parseFloat(firstLayer.params.VERSION) >= 1.3) ? { │ │ │ │ + crs: projection, │ │ │ │ + i: parseInt(clickPosition.x), │ │ │ │ + j: parseInt(clickPosition.y) │ │ │ │ + } : { │ │ │ │ + srs: projection, │ │ │ │ + x: parseInt(clickPosition.x), │ │ │ │ + y: parseInt(clickPosition.y) │ │ │ │ + }); │ │ │ │ + if (layerNames.length != 0) { │ │ │ │ + params = OpenLayers.Util.extend({ │ │ │ │ + layers: layerNames, │ │ │ │ + query_layers: layerNames, │ │ │ │ + styles: styleNames │ │ │ │ + }, params); │ │ │ │ + } │ │ │ │ + OpenLayers.Util.applyDefaults(params, this.vendorParams); │ │ │ │ + return { │ │ │ │ + url: url, │ │ │ │ + params: OpenLayers.Util.upperCaseObject(params), │ │ │ │ + callback: function(request) { │ │ │ │ + this.handleResponse(clickPosition, request, url); │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getStyleNames │ │ │ │ + * Gets the STYLES parameter for the layer. Make sure the STYLES parameter │ │ │ │ + * matches the LAYERS parameter │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.WMS>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array(String)} The STYLES parameter │ │ │ │ + */ │ │ │ │ + getStyleNames: function(layer) { │ │ │ │ + // in the event of a WMS layer bundling multiple layers but not │ │ │ │ + // specifying styles,we need the same number of commas to specify │ │ │ │ + // the default style for each of the layers. We can't just leave it │ │ │ │ + // blank as we may be including other layers that do specify styles. │ │ │ │ + var styleNames; │ │ │ │ + if (layer.params.STYLES) { │ │ │ │ + styleNames = layer.params.STYLES; │ │ │ │ + } else { │ │ │ │ + if (OpenLayers.Util.isArray(layer.params.LAYERS)) { │ │ │ │ + styleNames = new Array(layer.params.LAYERS.length); │ │ │ │ + } else { // Assume it's a String │ │ │ │ + styleNames = layer.params.LAYERS.replace(/[^,]/g, ""); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return styleNames; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: request │ │ │ │ + * Sends a GetFeatureInfo request to the WMS │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * clickPosition - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ + * mouse event occurred. │ │ │ │ + * options - {Object} additional options for this method. │ │ │ │ + * │ │ │ │ + * Valid options: │ │ │ │ + * - *hover* {Boolean} true if we do the request for the hover handler │ │ │ │ + */ │ │ │ │ + request: function(clickPosition, options) { │ │ │ │ + var layers = this.findLayers(); │ │ │ │ + if (layers.length == 0) { │ │ │ │ + this.events.triggerEvent("nogetfeatureinfo"); │ │ │ │ + // Reset the cursor. │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + │ │ │ │ + options = options || {}; │ │ │ │ + if (this.drillDown === false) { │ │ │ │ + var wmsOptions = this.buildWMSOptions(this.url, layers, │ │ │ │ + clickPosition, layers[0].params.FORMAT); │ │ │ │ + var request = OpenLayers.Request.GET(wmsOptions); │ │ │ │ + │ │ │ │ + if (options.hover === true) { │ │ │ │ + this.hoverRequest = request; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this._requestCount = 0; │ │ │ │ + this._numRequests = 0; │ │ │ │ + this.features = []; │ │ │ │ + // group according to service url to combine requests │ │ │ │ + var services = {}, │ │ │ │ + url; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + var layer = layers[i]; │ │ │ │ + var service, found = false; │ │ │ │ + url = OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url; │ │ │ │ + if (url in services) { │ │ │ │ + services[url].push(layer); │ │ │ │ + } else { │ │ │ │ + this._numRequests++; │ │ │ │ + services[url] = [layer]; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var layers; │ │ │ │ + for (var url in services) { │ │ │ │ + layers = services[url]; │ │ │ │ + var wmsOptions = this.buildWMSOptions(url, layers, │ │ │ │ + clickPosition, layers[0].params.FORMAT); │ │ │ │ + OpenLayers.Request.GET(wmsOptions); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: triggerGetFeatureInfo │ │ │ │ + * Trigger the getfeatureinfo event when all is done │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * request - {XMLHttpRequest} The request object │ │ │ │ + * xy - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ + * mouse event occurred. │ │ │ │ + * features - {Array(<OpenLayers.Feature.Vector>)} or │ │ │ │ + * {Array({Object}) when output is "object". The object has a url and a │ │ │ │ + * features property which contains an array of features. │ │ │ │ + */ │ │ │ │ + triggerGetFeatureInfo: function(request, xy, features) { │ │ │ │ + this.events.triggerEvent("getfeatureinfo", { │ │ │ │ + text: request.responseText, │ │ │ │ + features: features, │ │ │ │ + request: request, │ │ │ │ + xy: xy │ │ │ │ + }); │ │ │ │ + │ │ │ │ + // Reset the cursor. │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: handleResponse │ │ │ │ + * Handler for the GetFeatureInfo response. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * xy - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ + * mouse event occurred. │ │ │ │ + * request - {XMLHttpRequest} The request object. │ │ │ │ + * url - {String} The url which was used for this request. │ │ │ │ + */ │ │ │ │ + handleResponse: function(xy, request, url) { │ │ │ │ + │ │ │ │ + var doc = request.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = request.responseText; │ │ │ │ + } │ │ │ │ + var features = this.format.read(doc); │ │ │ │ + if (this.drillDown === false) { │ │ │ │ + this.triggerGetFeatureInfo(request, xy, features); │ │ │ │ + } else { │ │ │ │ + this._requestCount++; │ │ │ │ + if (this.output === "object") { │ │ │ │ + this._features = (this._features || []).concat({ │ │ │ │ + url: url, │ │ │ │ + features: features │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + this._features = (this._features || []).concat(features); │ │ │ │ + } │ │ │ │ + if (this._requestCount === this._numRequests) { │ │ │ │ + this.triggerGetFeatureInfo(request, xy, this._features.concat()); │ │ │ │ + delete this._features; │ │ │ │ + delete this._requestCount; │ │ │ │ + delete this._numRequests; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Control.WMSGetFeatureInfo" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/DragFeature.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/Feature.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.DragFeature │ │ │ │ + * The DragFeature control moves a feature with a drag of the mouse. Create a │ │ │ │ + * new control with the <OpenLayers.Control.DragFeature> constructor. │ │ │ │ + * │ │ │ │ + * Inherits From: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.DragFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: geometryTypes │ │ │ │ + * {Array(String)} To restrict dragging to a limited set of geometry types, │ │ │ │ + * send a list of strings corresponding to the geometry class names. │ │ │ │ + */ │ │ │ │ + geometryTypes: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: onStart │ │ │ │ + * {Function} Define this function if you want to know when a drag starts. │ │ │ │ + * The function should expect to receive two arguments: the feature │ │ │ │ + * that is about to be dragged and the pixel location of the mouse. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature that is about to be │ │ │ │ + * dragged. │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. │ │ │ │ + */ │ │ │ │ + onStart: function(feature, pixel) {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: onDrag │ │ │ │ + * {Function} Define this function if you want to know about each move of a │ │ │ │ + * feature. The function should expect to receive two arguments: the │ │ │ │ + * feature that is being dragged and the pixel location of the mouse. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. │ │ │ │ + */ │ │ │ │ + onDrag: function(feature, pixel) {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: onComplete │ │ │ │ + * {Function} Define this function if you want to know when a feature is │ │ │ │ + * done dragging. The function should expect to receive two arguments: │ │ │ │ + * the feature that is being dragged and the pixel location of the │ │ │ │ + * mouse. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse. │ │ │ │ + */ │ │ │ │ + onComplete: function(feature, pixel) {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: onEnter │ │ │ │ + * {Function} Define this function if you want to know when the mouse │ │ │ │ + * goes over a feature and thereby makes this feature a candidate │ │ │ │ + * for dragging. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature that is ready │ │ │ │ + * to be dragged. │ │ │ │ + */ │ │ │ │ + onEnter: function(feature) {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: onLeave │ │ │ │ + * {Function} Define this function if you want to know when the mouse │ │ │ │ + * goes out of the feature that was dragged. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged. │ │ │ │ + */ │ │ │ │ + onLeave: function(feature) {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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: layer │ │ │ │ + * {<OpenLayers.Layer.Vector>} │ │ │ │ + */ │ │ │ │ + layer: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: feature │ │ │ │ + * {<OpenLayers.Feature.Vector>} │ │ │ │ + */ │ │ │ │ + feature: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: dragCallbacks │ │ │ │ + * {Object} The functions that are sent to the drag handler for callback. │ │ │ │ + */ │ │ │ │ + dragCallbacks: {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: featureCallbacks │ │ │ │ + * {Object} The functions that are sent to the feature handler for callback. │ │ │ │ + */ │ │ │ │ + featureCallbacks: {}, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: lastPixel │ │ │ │ + * {<OpenLayers.Pixel>} │ │ │ │ + */ │ │ │ │ + lastPixel: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.DragFeature │ │ │ │ + * Create a new control to drag features. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} The layer containing features to be │ │ │ │ + * dragged. │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * control. │ │ │ │ + */ │ │ │ │ + initialize: function(layer, options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.layer = layer; │ │ │ │ + this.handlers = { │ │ │ │ + drag: new OpenLayers.Handler.Drag( │ │ │ │ + this, OpenLayers.Util.extend({ │ │ │ │ + down: this.downFeature, │ │ │ │ + move: this.moveFeature, │ │ │ │ + up: this.upFeature, │ │ │ │ + out: this.cancel, │ │ │ │ + done: this.doneDragging │ │ │ │ + }, this.dragCallbacks), { │ │ │ │ + documentDrag: this.documentDrag │ │ │ │ + } │ │ │ │ + ), │ │ │ │ + feature: new OpenLayers.Handler.Feature( │ │ │ │ + this, this.layer, OpenLayers.Util.extend({ │ │ │ │ + // 'click' and 'clickout' callback are for the mobile │ │ │ │ + // support: no 'over' or 'out' in touch based browsers. │ │ │ │ + click: this.clickFeature, │ │ │ │ + clickout: this.clickoutFeature, │ │ │ │ + over: this.overFeature, │ │ │ │ + out: this.outFeature │ │ │ │ + }, this.featureCallbacks), { │ │ │ │ + geometryTypes: this.geometryTypes │ │ │ │ + } │ │ │ │ + ) │ │ │ │ + }; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clickFeature │ │ │ │ + * Called when the feature handler detects a click-in on a feature. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + */ │ │ │ │ + clickFeature: function(feature) { │ │ │ │ + if (this.handlers.feature.touch && !this.over && this.overFeature(feature)) { │ │ │ │ + this.handlers.drag.dragstart(this.handlers.feature.evt); │ │ │ │ + // to let the events propagate to the feature handler (click callback) │ │ │ │ + this.handlers.drag.stopDown = false; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: clickoutFeature │ │ │ │ + * Called when the feature handler detects a click-out on a feature. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + */ │ │ │ │ + clickoutFeature: function(feature) { │ │ │ │ + if (this.handlers.feature.touch && this.over) { │ │ │ │ + this.outFeature(feature); │ │ │ │ + this.handlers.drag.stopDown = true; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Take care of things that are not handled in superclass │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + this.layer = null; │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, []); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the control and the feature handler. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Successfully activated the control and feature handler. │ │ │ │ + */ │ │ │ │ + activate: function() { │ │ │ │ + return (this.handlers.feature.activate() && │ │ │ │ + OpenLayers.Control.prototype.activate.apply(this, arguments)); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the control and all handlers. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Successfully deactivated the control. │ │ │ │ + */ │ │ │ │ + deactivate: function() { │ │ │ │ + // the return from the handlers is unimportant in this case │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ + this.handlers.feature.deactivate(); │ │ │ │ + this.feature = null; │ │ │ │ + this.dragging = false; │ │ │ │ + this.lastPixel = null; │ │ │ │ + OpenLayers.Element.removeClass( │ │ │ │ + this.map.viewPortDiv, this.displayClass + "Over" │ │ │ │ + ); │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: overFeature │ │ │ │ + * Called when the feature handler detects a mouse-over on a feature. │ │ │ │ + * This activates the drag handler. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The selected feature. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} Successfully activated the drag handler. │ │ │ │ + */ │ │ │ │ + overFeature: function(feature) { │ │ │ │ + var activated = false; │ │ │ │ + if (!this.handlers.drag.dragging) { │ │ │ │ + this.feature = feature; │ │ │ │ + this.handlers.drag.activate(); │ │ │ │ + activated = true; │ │ │ │ + this.over = true; │ │ │ │ + OpenLayers.Element.addClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ + this.onEnter(feature); │ │ │ │ + } else { │ │ │ │ + if (this.feature.id == feature.id) { │ │ │ │ + this.over = true; │ │ │ │ + } else { │ │ │ │ + this.over = false; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return activated; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: downFeature │ │ │ │ + * Called when the drag handler detects a mouse-down. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * pixel - {<OpenLayers.Pixel>} Location of the mouse event. │ │ │ │ + */ │ │ │ │ + downFeature: function(pixel) { │ │ │ │ + this.lastPixel = pixel; │ │ │ │ + this.onStart(this.feature, pixel); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: moveFeature │ │ │ │ + * Called when the drag handler detects a mouse-move. Also calls the │ │ │ │ + * optional onDrag method. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * pixel - {<OpenLayers.Pixel>} Location of the mouse event. │ │ │ │ + */ │ │ │ │ + moveFeature: function(pixel) { │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ + this.feature.geometry.move(res * (pixel.x - this.lastPixel.x), │ │ │ │ + res * (this.lastPixel.y - pixel.y)); │ │ │ │ + this.layer.drawFeature(this.feature); │ │ │ │ + this.lastPixel = pixel; │ │ │ │ + this.onDrag(this.feature, pixel); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: upFeature │ │ │ │ + * Called when the drag handler detects a mouse-up. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * pixel - {<OpenLayers.Pixel>} Location of the mouse event. │ │ │ │ + */ │ │ │ │ + upFeature: function(pixel) { │ │ │ │ + if (!this.over) { │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: doneDragging │ │ │ │ + * Called when the drag handler is done dragging. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * pixel - {<OpenLayers.Pixel>} The last event pixel location. If this event │ │ │ │ + * came from a mouseout, this may not be in the map viewport. │ │ │ │ + */ │ │ │ │ + doneDragging: function(pixel) { │ │ │ │ + this.onComplete(this.feature, pixel); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: outFeature │ │ │ │ + * Called when the feature handler detects a mouse-out on a feature. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature that the mouse left. │ │ │ │ + */ │ │ │ │ + outFeature: function(feature) { │ │ │ │ + if (!this.handlers.drag.dragging) { │ │ │ │ + this.over = false; │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ + OpenLayers.Element.removeClass( │ │ │ │ + this.map.viewPortDiv, this.displayClass + "Over" │ │ │ │ + ); │ │ │ │ + this.onLeave(feature); │ │ │ │ + this.feature = null; │ │ │ │ + } else { │ │ │ │ + if (this.feature.id == feature.id) { │ │ │ │ + this.over = false; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: cancel │ │ │ │ + * Called when the drag handler detects a mouse-out (from the map viewport). │ │ │ │ + */ │ │ │ │ + cancel: function() { │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ + this.over = false; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ + this.handlers.feature.setMap(map); │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Control.DragFeature" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/Scale.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/Lang.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.Scale │ │ │ │ + * The Scale control displays the current map scale as a ratio (e.g. Scale = │ │ │ │ + * 1:1M). By default it is displayed in the lower right corner of the map. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.Scale = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: element │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + element: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: geodesic │ │ │ │ + * {Boolean} Use geodesic measurement. Default is false. The recommended │ │ │ │ + * setting for maps in EPSG:4326 is false, and true EPSG:900913. If set to │ │ │ │ + * true, the scale will be calculated based on the horizontal size of the │ │ │ │ + * pixel in the center of the map viewport. │ │ │ │ + */ │ │ │ │ + geodesic: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.Scale │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * element - {DOMElement} │ │ │ │ + * options - {Object} │ │ │ │ + */ │ │ │ │ + initialize: function(element, options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.element = OpenLayers.Util.getElement(element); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: draw │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (!this.element) { │ │ │ │ + this.element = document.createElement("div"); │ │ │ │ + this.div.appendChild(this.element); │ │ │ │ + } │ │ │ │ + this.map.events.register('moveend', this, this.updateScale); │ │ │ │ + this.updateScale(); │ │ │ │ + return this.div; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: updateScale │ │ │ │ + */ │ │ │ │ + updateScale: function() { │ │ │ │ + var scale; │ │ │ │ + if (this.geodesic === true) { │ │ │ │ + var units = this.map.getUnits(); │ │ │ │ + if (!units) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + var inches = OpenLayers.INCHES_PER_UNIT; │ │ │ │ + scale = (this.map.getGeodesicPixelSize().w || 0.000001) * │ │ │ │ + inches["km"] * OpenLayers.DOTS_PER_INCH; │ │ │ │ + } else { │ │ │ │ + scale = this.map.getScale(); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (!scale) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (scale >= 9500 && scale <= 950000) { │ │ │ │ + scale = Math.round(scale / 1000) + "K"; │ │ │ │ + } else if (scale >= 950000) { │ │ │ │ + scale = Math.round(scale / 1000000) + "M"; │ │ │ │ + } else { │ │ │ │ + scale = Math.round(scale); │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.element.innerHTML = OpenLayers.i18n("Scale = 1 : ${scaleDenom}", { │ │ │ │ + 'scaleDenom': scale │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Scale" │ │ │ │ +}); │ │ │ │ + │ │ │ │ +/* ====================================================================== │ │ │ │ + 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/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/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/Control/TransformFeature.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. */ │ │ │ │ @@ -66109,1934 +74355,767 @@ │ │ │ │ var diff = control.rotation % constrain; │ │ │ │ if (Math.abs(control._angle) >= constrain || diff !== 0) { │ │ │ │ angle = Math.round(control._angle / constrain) * constrain - │ │ │ │ diff; │ │ │ │ control._angle = 0; │ │ │ │ control.box.geometry.rotate(angle, centerGeometry); │ │ │ │ control.transformFeature({ │ │ │ │ - rotation: angle │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }; │ │ │ │ - │ │ │ │ - var handles = new Array(8); │ │ │ │ - var rotationHandles = new Array(4); │ │ │ │ - var geom, handle, rotationHandle; │ │ │ │ - var positions = ["sw", "s", "se", "e", "ne", "n", "nw", "w"]; │ │ │ │ - for (var i = 0; i < 8; ++i) { │ │ │ │ - geom = this.box.geometry.components[i]; │ │ │ │ - handle = new OpenLayers.Feature.Vector(geom.clone(), { │ │ │ │ - role: positions[i] + "-resize" │ │ │ │ - }, typeof this.renderIntent == "string" ? null : │ │ │ │ - this.renderIntent); │ │ │ │ - if (i % 2 == 0) { │ │ │ │ - rotationHandle = new OpenLayers.Feature.Vector(geom.clone(), { │ │ │ │ - role: positions[i] + "-rotate" │ │ │ │ - }, typeof this.rotationHandleSymbolizer == "string" ? │ │ │ │ - null : this.rotationHandleSymbolizer); │ │ │ │ - rotationHandle.geometry.move = rotationHandleMoveFn; │ │ │ │ - geom._rotationHandle = rotationHandle; │ │ │ │ - rotationHandles[i / 2] = rotationHandle; │ │ │ │ - } │ │ │ │ - geom.move = vertexMoveFn; │ │ │ │ - geom.resize = vertexResizeFn; │ │ │ │ - geom.rotate = vertexRotateFn; │ │ │ │ - handle.geometry.move = handleMoveFn; │ │ │ │ - geom._handle = handle; │ │ │ │ - handles[i] = handle; │ │ │ │ - } │ │ │ │ - │ │ │ │ - this.rotationHandles = rotationHandles; │ │ │ │ - this.handles = handles; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: createControl │ │ │ │ - * Creates a DragFeature control for this control. │ │ │ │ - */ │ │ │ │ - createControl: function() { │ │ │ │ - var control = this; │ │ │ │ - this.dragControl = new OpenLayers.Control.DragFeature(this.layer, { │ │ │ │ - documentDrag: true, │ │ │ │ - // avoid moving the feature itself - move the box instead │ │ │ │ - moveFeature: function(pixel) { │ │ │ │ - if (this.feature === control.feature) { │ │ │ │ - this.feature = control.box; │ │ │ │ - } │ │ │ │ - OpenLayers.Control.DragFeature.prototype.moveFeature.apply(this, │ │ │ │ - arguments); │ │ │ │ - }, │ │ │ │ - // transform while dragging │ │ │ │ - onDrag: function(feature, pixel) { │ │ │ │ - if (feature === control.box) { │ │ │ │ - control.transformFeature({ │ │ │ │ - center: control.center │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - // set a new feature │ │ │ │ - onStart: function(feature, pixel) { │ │ │ │ - var eligible = !control.geometryTypes || │ │ │ │ - OpenLayers.Util.indexOf(control.geometryTypes, │ │ │ │ - feature.geometry.CLASS_NAME) !== -1; │ │ │ │ - var i = OpenLayers.Util.indexOf(control.handles, feature); │ │ │ │ - i += OpenLayers.Util.indexOf(control.rotationHandles, │ │ │ │ - feature); │ │ │ │ - if (feature !== control.feature && feature !== control.box && │ │ │ │ - i == -2 && eligible) { │ │ │ │ - control.setFeature(feature); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - onComplete: function(feature, pixel) { │ │ │ │ - control.events.triggerEvent("transformcomplete", { │ │ │ │ - feature: control.feature │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: drawHandles │ │ │ │ - * Draws the handles to match the box. │ │ │ │ - */ │ │ │ │ - drawHandles: function() { │ │ │ │ - var layer = this.layer; │ │ │ │ - for (var i = 0; i < 8; ++i) { │ │ │ │ - if (this.rotate && i % 2 === 0) { │ │ │ │ - layer.drawFeature(this.rotationHandles[i / 2], │ │ │ │ - this.rotationHandleSymbolizer); │ │ │ │ - } │ │ │ │ - layer.drawFeature(this.handles[i], this.renderIntent); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: transformFeature │ │ │ │ - * Transforms the feature. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * mods - {Object} An object with optional scale, ratio, rotation and │ │ │ │ - * center properties. │ │ │ │ - */ │ │ │ │ - transformFeature: function(mods) { │ │ │ │ - if (!this._setfeature) { │ │ │ │ - this.scale *= (mods.scale || 1); │ │ │ │ - this.ratio *= (mods.ratio || 1); │ │ │ │ - var oldRotation = this.rotation; │ │ │ │ - this.rotation = (this.rotation + (mods.rotation || 0)) % 360; │ │ │ │ - │ │ │ │ - if (this.events.triggerEvent("beforetransform", mods) !== false) { │ │ │ │ - var feature = this.feature; │ │ │ │ - var geom = feature.geometry; │ │ │ │ - var center = this.center; │ │ │ │ - geom.rotate(-oldRotation, center); │ │ │ │ - if (mods.scale || mods.ratio) { │ │ │ │ - geom.resize(mods.scale, center, mods.ratio); │ │ │ │ - } else if (mods.center) { │ │ │ │ - feature.move(mods.center.getBounds().getCenterLonLat()); │ │ │ │ - } │ │ │ │ - geom.rotate(this.rotation, center); │ │ │ │ - this.layer.drawFeature(feature); │ │ │ │ - feature.toState(OpenLayers.State.UPDATE); │ │ │ │ - this.events.triggerEvent("transform", mods); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.layer.drawFeature(this.box, this.renderIntent); │ │ │ │ - this.drawHandles(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Take care of things that are not handled in superclass. │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - var geom; │ │ │ │ - for (var i = 0; i < 8; ++i) { │ │ │ │ - geom = this.box.geometry.components[i]; │ │ │ │ - geom._handle.destroy(); │ │ │ │ - geom._handle = null; │ │ │ │ - geom._rotationHandle && geom._rotationHandle.destroy(); │ │ │ │ - geom._rotationHandle = null; │ │ │ │ - } │ │ │ │ - this.center = null; │ │ │ │ - this.feature = null; │ │ │ │ - this.handles = null; │ │ │ │ - this.rotationHandleSymbolizer = null; │ │ │ │ - this.rotationHandles = null; │ │ │ │ - this.box.destroy(); │ │ │ │ - this.box = null; │ │ │ │ - this.layer = null; │ │ │ │ - this.dragControl.destroy(); │ │ │ │ - this.dragControl = null; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.TransformFeature" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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/Control/ZoomOut.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/Button.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.ZoomOut │ │ │ │ - * The ZoomOut control is a button to decrease the zoom level of a map. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.ZoomOut = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: trigger │ │ │ │ - */ │ │ │ │ - trigger: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.zoomOut(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomOut" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/UTFGrid.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/Hover.js │ │ │ │ - * @requires OpenLayers/Handler/Click.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.UTFGrid │ │ │ │ - * │ │ │ │ - * This Control provides behavior associated with UTFGrid Layers. │ │ │ │ - * These 'hit grids' provide underlying feature attributes without │ │ │ │ - * calling the server (again). This control allows Mousemove, Hovering │ │ │ │ - * and Click events to trigger callbacks that use the attributes in │ │ │ │ - * whatever way you need. │ │ │ │ - * │ │ │ │ - * The most common example may be a UTFGrid layer containing feature │ │ │ │ - * attributes that are displayed in a div as you mouseover. │ │ │ │ - * │ │ │ │ - * Example Code: │ │ │ │ - * │ │ │ │ - * (start code) │ │ │ │ - * var world_utfgrid = new OpenLayers.Layer.UTFGrid( │ │ │ │ - * 'UTFGrid Layer', │ │ │ │ - * "http://tiles/world_utfgrid/${z}/${x}/${y}.json" │ │ │ │ - * ); │ │ │ │ - * map.addLayer(world_utfgrid); │ │ │ │ - * │ │ │ │ - * var control = new OpenLayers.Control.UTFGrid({ │ │ │ │ - * layers: [world_utfgrid], │ │ │ │ - * handlerMode: 'move', │ │ │ │ - * callback: function(infoLookup) { │ │ │ │ - * // do something with returned data │ │ │ │ - * │ │ │ │ - * } │ │ │ │ - * }) │ │ │ │ - * (end code) │ │ │ │ - * │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.UTFGrid = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ - */ │ │ │ │ - autoActivate: true, │ │ │ │ + rotation: angle │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + }; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: Layers │ │ │ │ - * List of layers to consider. Must be Layer.UTFGrids │ │ │ │ - * `null` is the default indicating all UTFGrid Layers are queried. │ │ │ │ - * {Array} <OpenLayers.Layer.UTFGrid> │ │ │ │ - */ │ │ │ │ - layers: null, │ │ │ │ + var handles = new Array(8); │ │ │ │ + var rotationHandles = new Array(4); │ │ │ │ + var geom, handle, rotationHandle; │ │ │ │ + var positions = ["sw", "s", "se", "e", "ne", "n", "nw", "w"]; │ │ │ │ + for (var i = 0; i < 8; ++i) { │ │ │ │ + geom = this.box.geometry.components[i]; │ │ │ │ + handle = new OpenLayers.Feature.Vector(geom.clone(), { │ │ │ │ + role: positions[i] + "-resize" │ │ │ │ + }, typeof this.renderIntent == "string" ? null : │ │ │ │ + this.renderIntent); │ │ │ │ + if (i % 2 == 0) { │ │ │ │ + rotationHandle = new OpenLayers.Feature.Vector(geom.clone(), { │ │ │ │ + role: positions[i] + "-rotate" │ │ │ │ + }, typeof this.rotationHandleSymbolizer == "string" ? │ │ │ │ + null : this.rotationHandleSymbolizer); │ │ │ │ + rotationHandle.geometry.move = rotationHandleMoveFn; │ │ │ │ + geom._rotationHandle = rotationHandle; │ │ │ │ + rotationHandles[i / 2] = rotationHandle; │ │ │ │ + } │ │ │ │ + geom.move = vertexMoveFn; │ │ │ │ + geom.resize = vertexResizeFn; │ │ │ │ + geom.rotate = vertexRotateFn; │ │ │ │ + handle.geometry.move = handleMoveFn; │ │ │ │ + geom._handle = handle; │ │ │ │ + handles[i] = handle; │ │ │ │ + } │ │ │ │ │ │ │ │ - /* Property: defaultHandlerOptions │ │ │ │ - * The default opts passed to the handler constructors │ │ │ │ - */ │ │ │ │ - defaultHandlerOptions: { │ │ │ │ - 'delay': 300, │ │ │ │ - 'pixelTolerance': 4, │ │ │ │ - 'stopMove': false, │ │ │ │ - 'single': true, │ │ │ │ - 'double': false, │ │ │ │ - 'stopSingle': false, │ │ │ │ - 'stopDouble': false │ │ │ │ + this.rotationHandles = rotationHandles; │ │ │ │ + this.handles = handles; │ │ │ │ }, │ │ │ │ │ │ │ │ - /* APIProperty: handlerMode │ │ │ │ - * Defaults to 'click'. Can be 'hover' or 'move'. │ │ │ │ - */ │ │ │ │ - handlerMode: 'click', │ │ │ │ - │ │ │ │ /** │ │ │ │ - * APIMethod: setHandler │ │ │ │ - * sets this.handlerMode and calls resetHandler() │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * hm - {String} Handler Mode string; 'click', 'hover' or 'move'. │ │ │ │ + * Method: createControl │ │ │ │ + * Creates a DragFeature control for this control. │ │ │ │ */ │ │ │ │ - setHandler: function(hm) { │ │ │ │ - this.handlerMode = hm; │ │ │ │ - this.resetHandler(); │ │ │ │ + createControl: function() { │ │ │ │ + var control = this; │ │ │ │ + this.dragControl = new OpenLayers.Control.DragFeature(this.layer, { │ │ │ │ + documentDrag: true, │ │ │ │ + // avoid moving the feature itself - move the box instead │ │ │ │ + moveFeature: function(pixel) { │ │ │ │ + if (this.feature === control.feature) { │ │ │ │ + this.feature = control.box; │ │ │ │ + } │ │ │ │ + OpenLayers.Control.DragFeature.prototype.moveFeature.apply(this, │ │ │ │ + arguments); │ │ │ │ + }, │ │ │ │ + // transform while dragging │ │ │ │ + onDrag: function(feature, pixel) { │ │ │ │ + if (feature === control.box) { │ │ │ │ + control.transformFeature({ │ │ │ │ + center: control.center │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + // set a new feature │ │ │ │ + onStart: function(feature, pixel) { │ │ │ │ + var eligible = !control.geometryTypes || │ │ │ │ + OpenLayers.Util.indexOf(control.geometryTypes, │ │ │ │ + feature.geometry.CLASS_NAME) !== -1; │ │ │ │ + var i = OpenLayers.Util.indexOf(control.handles, feature); │ │ │ │ + i += OpenLayers.Util.indexOf(control.rotationHandles, │ │ │ │ + feature); │ │ │ │ + if (feature !== control.feature && feature !== control.box && │ │ │ │ + i == -2 && eligible) { │ │ │ │ + control.setFeature(feature); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + onComplete: function(feature, pixel) { │ │ │ │ + control.events.triggerEvent("transformcomplete", { │ │ │ │ + feature: control.feature │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: resetHandler │ │ │ │ - * Deactivates the old hanlder and creates a new │ │ │ │ - * <OpenLayers.Handler> based on the mode specified in │ │ │ │ - * this.handlerMode │ │ │ │ - * │ │ │ │ + * Method: drawHandles │ │ │ │ + * Draws the handles to match the box. │ │ │ │ */ │ │ │ │ - resetHandler: function() { │ │ │ │ - if (this.handler) { │ │ │ │ - this.handler.deactivate(); │ │ │ │ - this.handler.destroy(); │ │ │ │ - this.handler = null; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.handlerMode == 'hover') { │ │ │ │ - // Handle this event on hover │ │ │ │ - this.handler = new OpenLayers.Handler.Hover( │ │ │ │ - this, { │ │ │ │ - 'pause': this.handleEvent, │ │ │ │ - 'move': this.reset │ │ │ │ - }, │ │ │ │ - this.handlerOptions │ │ │ │ - ); │ │ │ │ - } else if (this.handlerMode == 'click') { │ │ │ │ - // Handle this event on click │ │ │ │ - this.handler = new OpenLayers.Handler.Click( │ │ │ │ - this, { │ │ │ │ - 'click': this.handleEvent │ │ │ │ - }, this.handlerOptions │ │ │ │ - ); │ │ │ │ - } else if (this.handlerMode == 'move') { │ │ │ │ - this.handler = new OpenLayers.Handler.Hover( │ │ │ │ - this, │ │ │ │ - // Handle this event while hovering OR moving │ │ │ │ - { │ │ │ │ - 'pause': this.handleEvent, │ │ │ │ - 'move': this.handleEvent │ │ │ │ - }, │ │ │ │ - this.handlerOptions │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (this.handler) { │ │ │ │ - return true; │ │ │ │ - } else { │ │ │ │ - return false; │ │ │ │ + drawHandles: function() { │ │ │ │ + var layer = this.layer; │ │ │ │ + for (var i = 0; i < 8; ++i) { │ │ │ │ + if (this.rotate && i % 2 === 0) { │ │ │ │ + layer.drawFeature(this.rotationHandles[i / 2], │ │ │ │ + this.rotationHandleSymbolizer); │ │ │ │ + } │ │ │ │ + layer.drawFeature(this.handles[i], this.renderIntent); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: <OpenLayers.Control.UTFGrid> │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.handlerOptions = options.handlerOptions || this.defaultHandlerOptions; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.resetHandler(); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: handleEvent │ │ │ │ - * Internal method called when specified event is triggered. │ │ │ │ + * Method: transformFeature │ │ │ │ + * Transforms the feature. │ │ │ │ * │ │ │ │ - * This method does several things: │ │ │ │ - * │ │ │ │ - * Gets the lonLat of the event. │ │ │ │ - * │ │ │ │ - * Loops through the appropriate hit grid layers and gathers the attributes. │ │ │ │ - * │ │ │ │ - * Passes the attributes to the callback │ │ │ │ - * │ │ │ │ * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ + * mods - {Object} An object with optional scale, ratio, rotation and │ │ │ │ + * center properties. │ │ │ │ */ │ │ │ │ - handleEvent: function(evt) { │ │ │ │ - if (evt == null) { │ │ │ │ - this.reset(); │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var lonLat = this.map.getLonLatFromPixel(evt.xy); │ │ │ │ - if (!lonLat) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ + transformFeature: function(mods) { │ │ │ │ + if (!this._setfeature) { │ │ │ │ + this.scale *= (mods.scale || 1); │ │ │ │ + this.ratio *= (mods.ratio || 1); │ │ │ │ + var oldRotation = this.rotation; │ │ │ │ + this.rotation = (this.rotation + (mods.rotation || 0)) % 360; │ │ │ │ │ │ │ │ - var layers = this.findLayers(); │ │ │ │ - if (layers.length > 0) { │ │ │ │ - var infoLookup = {}; │ │ │ │ - var layer, idx; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - layer = layers[i]; │ │ │ │ - idx = OpenLayers.Util.indexOf(this.map.layers, layer); │ │ │ │ - infoLookup[idx] = layer.getFeatureInfo(lonLat); │ │ │ │ + if (this.events.triggerEvent("beforetransform", mods) !== false) { │ │ │ │ + var feature = this.feature; │ │ │ │ + var geom = feature.geometry; │ │ │ │ + var center = this.center; │ │ │ │ + geom.rotate(-oldRotation, center); │ │ │ │ + if (mods.scale || mods.ratio) { │ │ │ │ + geom.resize(mods.scale, center, mods.ratio); │ │ │ │ + } else if (mods.center) { │ │ │ │ + feature.move(mods.center.getBounds().getCenterLonLat()); │ │ │ │ + } │ │ │ │ + geom.rotate(this.rotation, center); │ │ │ │ + this.layer.drawFeature(feature); │ │ │ │ + feature.toState(OpenLayers.State.UPDATE); │ │ │ │ + this.events.triggerEvent("transform", mods); │ │ │ │ } │ │ │ │ - this.callback(infoLookup, lonLat, evt.xy); │ │ │ │ } │ │ │ │ + this.layer.drawFeature(this.box, this.renderIntent); │ │ │ │ + this.drawHandles(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: callback │ │ │ │ - * Function to be called when a mouse event corresponds with a location that │ │ │ │ - * includes data in one of the configured UTFGrid layers. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * infoLookup - {Object} Keys of this object are layer indexes and can be │ │ │ │ - * used to resolve a layer in the map.layers array. The structure of │ │ │ │ - * the property values depend on the data included in the underlying │ │ │ │ - * UTFGrid and may be any valid JSON type. │ │ │ │ - */ │ │ │ │ - callback: function(infoLookup) { │ │ │ │ - // to be provided in the constructor │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: reset │ │ │ │ - * Calls the callback with null. │ │ │ │ - */ │ │ │ │ - reset: function(evt) { │ │ │ │ - this.callback(null); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: findLayers │ │ │ │ - * Internal method to get the layers, independent of whether we are │ │ │ │ - * inspecting the map or using a client-provided array │ │ │ │ - * │ │ │ │ - * The default value of this.layers is null; this causes the │ │ │ │ - * findLayers method to return ALL UTFGrid layers encountered. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * None │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} Layers to handle on each event │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Take care of things that are not handled in superclass. │ │ │ │ */ │ │ │ │ - findLayers: function() { │ │ │ │ - var candidates = this.layers || this.map.layers; │ │ │ │ - var layers = []; │ │ │ │ - var layer; │ │ │ │ - for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ - layer = candidates[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.UTFGrid) { │ │ │ │ - layers.push(layer); │ │ │ │ - } │ │ │ │ + destroy: function() { │ │ │ │ + var geom; │ │ │ │ + for (var i = 0; i < 8; ++i) { │ │ │ │ + geom = this.box.geometry.components[i]; │ │ │ │ + geom._handle.destroy(); │ │ │ │ + geom._handle = null; │ │ │ │ + geom._rotationHandle && geom._rotationHandle.destroy(); │ │ │ │ + geom._rotationHandle = null; │ │ │ │ } │ │ │ │ - return layers; │ │ │ │ + this.center = null; │ │ │ │ + this.feature = null; │ │ │ │ + this.handles = null; │ │ │ │ + this.rotationHandleSymbolizer = null; │ │ │ │ + this.rotationHandles = null; │ │ │ │ + this.box.destroy(); │ │ │ │ + this.box = null; │ │ │ │ + this.layer = null; │ │ │ │ + this.dragControl.destroy(); │ │ │ │ + this.dragControl = null; │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.UTFGrid" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.TransformFeature" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/EditingToolbar.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/Panel.js │ │ │ │ - * @requires OpenLayers/Control/Navigation.js │ │ │ │ - * @requires OpenLayers/Control/DrawFeature.js │ │ │ │ - * @requires OpenLayers/Handler/Point.js │ │ │ │ - * @requires OpenLayers/Handler/Path.js │ │ │ │ - * @requires OpenLayers/Handler/Polygon.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.EditingToolbar │ │ │ │ - * The EditingToolbar is a panel of 4 controls to draw polygons, lines, │ │ │ │ - * points, or to navigate the map by panning. By default it appears in the │ │ │ │ - * upper right corner of the map. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control.Panel> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.EditingToolbar = OpenLayers.Class( │ │ │ │ - OpenLayers.Control.Panel, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.EditingToolbar │ │ │ │ - * Create an editing toolbar for a given layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} │ │ │ │ - * options - {Object} │ │ │ │ - */ │ │ │ │ - initialize: function(layer, options) { │ │ │ │ - OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ - │ │ │ │ - this.addControls( │ │ │ │ - [new OpenLayers.Control.Navigation()] │ │ │ │ - ); │ │ │ │ - var controls = [ │ │ │ │ - new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Point, { │ │ │ │ - displayClass: 'olControlDrawFeaturePoint', │ │ │ │ - handlerOptions: { │ │ │ │ - citeCompliant: this.citeCompliant │ │ │ │ - } │ │ │ │ - }), │ │ │ │ - new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Path, { │ │ │ │ - displayClass: 'olControlDrawFeaturePath', │ │ │ │ - handlerOptions: { │ │ │ │ - citeCompliant: this.citeCompliant │ │ │ │ - } │ │ │ │ - }), │ │ │ │ - new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Polygon, { │ │ │ │ - displayClass: 'olControlDrawFeaturePolygon', │ │ │ │ - handlerOptions: { │ │ │ │ - citeCompliant: this.citeCompliant │ │ │ │ - } │ │ │ │ - }) │ │ │ │ - ]; │ │ │ │ - this.addControls(controls); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * calls the default draw, and then activates mouse defaults. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - draw: function() { │ │ │ │ - var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments); │ │ │ │ - if (this.defaultControl === null) { │ │ │ │ - this.defaultControl = this.controls[0]; │ │ │ │ - } │ │ │ │ - return div; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.EditingToolbar" │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/Zoom.js │ │ │ │ + OpenLayers/Control/KeyboardDefaults.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 │ │ │ │ + * @requires OpenLayers/Handler/Keyboard.js │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.Zoom │ │ │ │ - * The Zoom control is a pair of +/- links for zooming in and out. │ │ │ │ + * Class: OpenLayers.Control.KeyboardDefaults │ │ │ │ + * The KeyboardDefaults control adds panning and zooming functions, controlled │ │ │ │ + * with the keyboard. By default arrow keys pan, +/- keys zoom & Page Up/Page │ │ │ │ + * Down/Home/End scroll by three quarters of a page. │ │ │ │ + * │ │ │ │ + * This control has no visible appearance. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.Zoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Control.KeyboardDefaults = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: zoomInText │ │ │ │ - * {String} │ │ │ │ - * Text for zoom-in link. Default is "+". │ │ │ │ + * APIProperty: autoActivate │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * true. │ │ │ │ */ │ │ │ │ - zoomInText: "+", │ │ │ │ + autoActivate: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIProperty: slideFactor │ │ │ │ + * Pixels to slide by. │ │ │ │ */ │ │ │ │ - zoomInId: "olZoomInLink", │ │ │ │ + slideFactor: 75, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: zoomOutText │ │ │ │ - * {String} │ │ │ │ - * Text for zoom-out link. Default is "\u2212". │ │ │ │ + * APIProperty: observeElement │ │ │ │ + * {DOMelement|String} The DOM element to handle keys for. You │ │ │ │ + * can use the map div here, to have the navigation keys │ │ │ │ + * work when the map div has the focus. If undefined the │ │ │ │ + * document is used. │ │ │ │ */ │ │ │ │ - zoomOutText: "\u2212", │ │ │ │ + observeElement: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Constructor: OpenLayers.Control.KeyboardDefaults │ │ │ │ */ │ │ │ │ - zoomOutId: "olZoomOutLink", │ │ │ │ │ │ │ │ /** │ │ │ │ * Method: draw │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A reference to the DOMElement containing the zoom links. │ │ │ │ + * Create handler. │ │ │ │ */ │ │ │ │ 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; │ │ │ │ + var observeElement = this.observeElement || document; │ │ │ │ + this.handler = new OpenLayers.Handler.Keyboard(this, { │ │ │ │ + "keydown": this.defaultKeyPress │ │ │ │ + }, { │ │ │ │ + observeElement: observeElement │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getOrCreateLinks │ │ │ │ + * Method: defaultKeyPress │ │ │ │ + * When handling the key event, we only use evt.keyCode. This holds │ │ │ │ + * some drawbacks, though we get around them below. When interpretting │ │ │ │ + * the keycodes below (including the comments associated with them), │ │ │ │ + * consult the URL below. For instance, the Safari browser returns │ │ │ │ + * "IE keycodes", and so is supported by any keycode labeled "IE". │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * el - {DOMElement} │ │ │ │ + * Very informative URL: │ │ │ │ + * http://unixpapa.com/js/key.html │ │ │ │ * │ │ │ │ - * Return: │ │ │ │ - * {Object} Object with zoomIn and zoomOut properties referencing links. │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ + defaultKeyPress: function(evt) { │ │ │ │ + var size, handled = true; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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(); │ │ │ │ + var target = OpenLayers.Event.element(evt); │ │ │ │ + if (target && │ │ │ │ + (target.tagName == 'INPUT' || │ │ │ │ + target.tagName == 'TEXTAREA' || │ │ │ │ + target.tagName == 'SELECT')) { │ │ │ │ + return; │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - * Clean up. │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.unregister("buttonclick", this, this.onZoomClick); │ │ │ │ + switch (evt.keyCode) { │ │ │ │ + case OpenLayers.Event.KEY_LEFT: │ │ │ │ + this.map.pan(-this.slideFactor, 0); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Event.KEY_RIGHT: │ │ │ │ + this.map.pan(this.slideFactor, 0); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Event.KEY_UP: │ │ │ │ + this.map.pan(0, -this.slideFactor); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Event.KEY_DOWN: │ │ │ │ + this.map.pan(0, this.slideFactor); │ │ │ │ + break; │ │ │ │ + │ │ │ │ + case 33: // Page Up. Same in all browsers. │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(0, -0.75 * size.h); │ │ │ │ + break; │ │ │ │ + case 34: // Page Down. Same in all browsers. │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(0, 0.75 * size.h); │ │ │ │ + break; │ │ │ │ + case 35: // End. Same in all browsers. │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(0.75 * size.w, 0); │ │ │ │ + break; │ │ │ │ + case 36: // Home. Same in all browsers. │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(-0.75 * size.w, 0); │ │ │ │ + break; │ │ │ │ + │ │ │ │ + case 43: // +/= (ASCII), keypad + (ASCII, Opera) │ │ │ │ + case 61: // +/= (Mozilla, Opera, some ASCII) │ │ │ │ + case 187: // +/= (IE) │ │ │ │ + case 107: // keypad + (IE, Mozilla) │ │ │ │ + this.map.zoomIn(); │ │ │ │ + break; │ │ │ │ + case 45: // -/_ (ASCII, Opera), keypad - (ASCII, Opera) │ │ │ │ + case 109: // -/_ (Mozilla), keypad - (Mozilla, IE) │ │ │ │ + case 189: // -/_ (IE) │ │ │ │ + case 95: // -/_ (some ASCII) │ │ │ │ + this.map.zoomOut(); │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + handled = false; │ │ │ │ + } │ │ │ │ + if (handled) { │ │ │ │ + // prevent browser default not to move the page │ │ │ │ + // when moving the page with the keyboard │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ } │ │ │ │ - delete this.zoomInLink; │ │ │ │ - delete this.zoomOutLink; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Zoom" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.KeyboardDefaults" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Handler/Keyboard.js │ │ │ │ + OpenLayers/Control/ZoomToMaxExtent.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 │ │ │ │ + * @requires OpenLayers/Control/Button.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.handler.Keyboard │ │ │ │ - * A handler for keyboard events. Create a new instance with the │ │ │ │ - * <OpenLayers.Handler.Keyboard> constructor. │ │ │ │ + * Class: OpenLayers.Control.ZoomToMaxExtent │ │ │ │ + * The ZoomToMaxExtent control is a button that zooms out to the maximum │ │ │ │ + * extent of the map. It is designed to be used with a │ │ │ │ + * <OpenLayers.Control.Panel>. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Handler> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -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, │ │ │ │ +OpenLayers.Control.ZoomToMaxExtent = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Handler.Keyboard │ │ │ │ - * Returns a new keyboard handler. │ │ │ │ + * Method: trigger │ │ │ │ * │ │ │ │ - * 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 │ │ │ │ + * Called whenever this control is being rendered inside of a panel and a │ │ │ │ + * click occurs on this controls element. Actually zooms to the maximum │ │ │ │ + * extent of this controls map. │ │ │ │ */ │ │ │ │ - handleKeyEvent: function(evt) { │ │ │ │ - if (this.checkModifiers(evt)) { │ │ │ │ - this.callback(evt.type, [evt]); │ │ │ │ + trigger: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.zoomToMaxExtent(); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Keyboard" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomToMaxExtent" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/ModifyFeature.js │ │ │ │ + OpenLayers/Control/WMTSGetFeatureInfo.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 │ │ │ │ + * @requires OpenLayers/Handler/Click.js │ │ │ │ + * @requires OpenLayers/Handler/Hover.js │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ + * @requires OpenLayers/Format/WMSGetFeatureInfo.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. │ │ │ │ + * Class: OpenLayers.Control.WMTSGetFeatureInfo │ │ │ │ + * The WMTSGetFeatureInfo control uses a WMTS query to get information about a │ │ │ │ + * point on the map. The information may be in a display-friendly format │ │ │ │ + * such as HTML, or a machine-friendly format such as GML, depending on the │ │ │ │ + * server's capabilities and the client's configuration. This control │ │ │ │ + * handles click or hover events, attempts to parse the results using an │ │ │ │ + * OpenLayers.Format, and fires a 'getfeatureinfo' event for each layer │ │ │ │ + * queried. │ │ │ │ * │ │ │ │ - * Inherits From: │ │ │ │ + * 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, │ │ │ │ +OpenLayers.Control.WMTSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: layer │ │ │ │ - * {<OpenLayers.Layer.Vector>} │ │ │ │ + * APIProperty: hover │ │ │ │ + * {Boolean} Send GetFeatureInfo requests when mouse stops moving. │ │ │ │ + * Default is false. │ │ │ │ */ │ │ │ │ - layer: null, │ │ │ │ + hover: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: feature │ │ │ │ - * {<OpenLayers.Feature.Vector>} Feature currently available for modification. │ │ │ │ + * Property: requestEncoding │ │ │ │ + * {String} One of "KVP" or "REST". Only KVP encoding is supported at this │ │ │ │ + * time. │ │ │ │ */ │ │ │ │ - feature: null, │ │ │ │ + requestEncoding: "KVP", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: vertex │ │ │ │ - * {<OpenLayers.Feature.Vector>} Vertex currently being modified. │ │ │ │ + * APIProperty: drillDown │ │ │ │ + * {Boolean} Drill down over all WMTS layers in the map. When │ │ │ │ + * using drillDown mode, hover is not possible. A getfeatureinfo event │ │ │ │ + * will be fired for each layer queried. │ │ │ │ */ │ │ │ │ - vertex: null, │ │ │ │ + drillDown: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: vertices │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} Verticies currently available │ │ │ │ - * for dragging. │ │ │ │ + * APIProperty: maxFeatures │ │ │ │ + * {Integer} Maximum number of features to return from a WMTS query. This │ │ │ │ + * sets the feature_count parameter on WMTS GetFeatureInfo │ │ │ │ + * requests. │ │ │ │ */ │ │ │ │ - vertices: null, │ │ │ │ + maxFeatures: 10, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: virtualVertices │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} Virtual vertices in the middle │ │ │ │ - * of each edge. │ │ │ │ + /** APIProperty: clickCallback │ │ │ │ + * {String} The click callback to register in the │ │ │ │ + * {<OpenLayers.Handler.Click>} object created when the hover │ │ │ │ + * option is set to false. Default is "click". │ │ │ │ */ │ │ │ │ - virtualVertices: null, │ │ │ │ + clickCallback: "click", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: handlers │ │ │ │ - * {Object} │ │ │ │ + * Property: layers │ │ │ │ + * {Array(<OpenLayers.Layer.WMTS>)} The layers to query for feature info. │ │ │ │ + * If omitted, all map WMTS layers will be considered. │ │ │ │ */ │ │ │ │ - handlers: null, │ │ │ │ + layers: 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. │ │ │ │ + * APIProperty: queryVisible │ │ │ │ + * {Boolean} Filter out hidden layers when searching the map for layers to │ │ │ │ + * query. Default is true. │ │ │ │ */ │ │ │ │ - deleteCodes: null, │ │ │ │ + queryVisible: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: virtualStyle │ │ │ │ - * {Object} A symbolizer to be used for virtual vertices. │ │ │ │ + * Property: infoFormat │ │ │ │ + * {String} The mimetype to request from the server │ │ │ │ */ │ │ │ │ - virtualStyle: null, │ │ │ │ + infoFormat: 'text/html', │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: vendorParams │ │ │ │ + * {Object} Additional parameters that will be added to the request, for │ │ │ │ + * WMTS implementations that support them. This could e.g. look like │ │ │ │ + * (start code) │ │ │ │ + * { │ │ │ │ + * radius: 5 │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ */ │ │ │ │ - vertexRenderIntent: null, │ │ │ │ + vendorParams: {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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) │ │ │ │ + * Property: format │ │ │ │ + * {<OpenLayers.Format>} A format for parsing GetFeatureInfo responses. │ │ │ │ + * Default is <OpenLayers.Format.WMSGetFeatureInfo>. │ │ │ │ */ │ │ │ │ - mode: null, │ │ │ │ + format: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: createVertices │ │ │ │ - * {Boolean} Create new vertices by dragging the virtual vertices │ │ │ │ - * in the middle of each edge. Default is true. │ │ │ │ + * Property: formatOptions │ │ │ │ + * {Object} Optional properties to set on the format (if one is not provided │ │ │ │ + * in the <format> property. │ │ │ │ */ │ │ │ │ - createVertices: true, │ │ │ │ + formatOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: modified │ │ │ │ - * {Boolean} The currently selected feature has been modified. │ │ │ │ + * APIProperty: handlerOptions │ │ │ │ + * {Object} Additional options for the handlers used by this control, e.g. │ │ │ │ + * (start code) │ │ │ │ + * { │ │ │ │ + * "click": {delay: 100}, │ │ │ │ + * "hover": {delay: 300} │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ */ │ │ │ │ - modified: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: radiusHandle │ │ │ │ - * {<OpenLayers.Feature.Vector>} A handle for rotating/resizing a feature. │ │ │ │ + * Property: handler │ │ │ │ + * {Object} Reference to the <OpenLayers.Handler> for this control │ │ │ │ */ │ │ │ │ - radiusHandle: null, │ │ │ │ + handler: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: dragHandle │ │ │ │ - * {<OpenLayers.Feature.Vector>} A handle for dragging a feature. │ │ │ │ + * Property: hoverRequest │ │ │ │ + * {<OpenLayers.Request>} contains the currently running hover request │ │ │ │ + * (if any). │ │ │ │ */ │ │ │ │ - dragHandle: null, │ │ │ │ + hoverRequest: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: onModificationStart │ │ │ │ - * {Function} *Deprecated*. Register for "beforefeaturemodified" instead. │ │ │ │ - * The "beforefeaturemodified" event is triggered on the layer before │ │ │ │ - * any modification begins. │ │ │ │ + /** │ │ │ │ + * APIProperty: events │ │ │ │ + * {<OpenLayers.Events>} Events instance for listeners and triggering │ │ │ │ + * control specific events. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Register a listener for a particular event with the following syntax: │ │ │ │ + * (code) │ │ │ │ + * control.events.register(type, obj, listener); │ │ │ │ + * (end) │ │ │ │ * │ │ │ │ - * Optional function to be called when a feature has been │ │ │ │ - * modified. The function should expect to be called with a feature. │ │ │ │ + * Supported event types (in addition to those from <OpenLayers.Control.events>): │ │ │ │ + * beforegetfeatureinfo - Triggered before each request is sent. │ │ │ │ + * The event object has an *xy* property with the position of the │ │ │ │ + * mouse click or hover event that triggers the request and a *layer* │ │ │ │ + * property referencing the layer about to be queried. If a listener │ │ │ │ + * returns false, the request will not be issued. │ │ │ │ + * getfeatureinfo - Triggered when a GetFeatureInfo response is received. │ │ │ │ + * The event object has a *text* property with the body of the │ │ │ │ + * response (String), a *features* property with an array of the │ │ │ │ + * parsed features, an *xy* property with the position of the mouse │ │ │ │ + * click or hover event that triggered the request, a *layer* property │ │ │ │ + * referencing the layer queried and a *request* property with the │ │ │ │ + * request itself. If drillDown is set to true, one event will be fired │ │ │ │ + * for each layer queried. │ │ │ │ + * exception - Triggered when a GetFeatureInfo request fails (with a │ │ │ │ + * status other than 200) or whenparsing fails. Listeners will receive │ │ │ │ + * an event with *request*, *xy*, and *layer* properties. In the case │ │ │ │ + * of a parsing error, the event will also contain an *error* property. │ │ │ │ */ │ │ │ │ - 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. │ │ │ │ + /** │ │ │ │ + * Property: pending │ │ │ │ + * {Number} The number of pending requests. │ │ │ │ */ │ │ │ │ - onModificationEnd: function() {}, │ │ │ │ + pending: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.ModifyFeature │ │ │ │ - * Create a new modify feature control. │ │ │ │ + * Constructor: <OpenLayers.Control.WMTSGetFeatureInfo> │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ - initialize: function(layer, options) { │ │ │ │ + initialize: function(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 │ │ │ │ - }; │ │ │ │ + options.handlerOptions = options.handlerOptions || {}; │ │ │ │ │ │ │ │ - // 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) │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 │ │ │ │ - }); │ │ │ │ + if (!this.format) { │ │ │ │ + this.format = new OpenLayers.Format.WMSGetFeatureInfo( │ │ │ │ + options.formatOptions │ │ │ │ + ); │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + if (this.drillDown === true) { │ │ │ │ + this.hover = false; │ │ │ │ } │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - ); │ │ │ │ + if (this.hover) { │ │ │ │ + this.handler = new OpenLayers.Handler.Hover( │ │ │ │ + this, { │ │ │ │ + move: this.cancelHover, │ │ │ │ + pause: this.getInfoForHover │ │ │ │ + }, │ │ │ │ + OpenLayers.Util.extend( │ │ │ │ + this.handlerOptions.hover || {}, { │ │ │ │ + delay: 250 │ │ │ │ + } │ │ │ │ + ) │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + var callbacks = {}; │ │ │ │ + callbacks[this.clickCallback] = this.getInfoForClick; │ │ │ │ + this.handler = new OpenLayers.Handler.Click( │ │ │ │ + this, callbacks, this.handlerOptions.click || {} │ │ │ │ + ); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: getInfoForClick │ │ │ │ + * Called on click │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} the selected feature. │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ + getInfoForClick: function(evt) { │ │ │ │ + this.request(evt.xy, {}); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: unselectFeature │ │ │ │ - * Called when the select feature control unselects a feature. │ │ │ │ + * Method: getInfoForHover │ │ │ │ + * Pause callback for the hover handler │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The unselected feature. │ │ │ │ + * evt - {Object} │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + getInfoForHover: function(evt) { │ │ │ │ + this.request(evt.xy, { │ │ │ │ + hover: true │ │ │ │ }); │ │ │ │ - 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. │ │ │ │ + * Method: cancelHover │ │ │ │ + * Cancel callback for the hover handler │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + cancelHover: function() { │ │ │ │ + if (this.hoverRequest) { │ │ │ │ + --this.pending; │ │ │ │ + if (this.pending <= 0) { │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + this.pending = 0; │ │ │ │ } │ │ │ │ - this.selectFeature(feature); │ │ │ │ - } │ │ │ │ - if (feature._sketch || isPoint) { │ │ │ │ - // feature is a drag or virtual handle or point │ │ │ │ - this.vertex = feature; │ │ │ │ - this.handlers.drag.stopDown = true; │ │ │ │ + this.hoverRequest.abort(); │ │ │ │ + this.hoverRequest = null; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: findLayers │ │ │ │ + * Internal method to get the layers, independent of whether we are │ │ │ │ + * inspecting the map or using a client-provided array │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + findLayers: function() { │ │ │ │ + var candidates = this.layers || this.map.layers; │ │ │ │ + var layers = []; │ │ │ │ + var layer; │ │ │ │ + for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ + layer = candidates[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.WMTS && │ │ │ │ + layer.requestEncoding === this.requestEncoding && │ │ │ │ + (!this.queryVisible || layer.getVisibility())) { │ │ │ │ + layers.push(layer); │ │ │ │ + if (!this.drillDown || this.hover) { │ │ │ │ + break; │ │ │ │ } │ │ │ │ - } 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); │ │ │ │ + return layers; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: dragComplete │ │ │ │ - * Called by the drag handler when the feature dragging is complete. │ │ │ │ + * Method: buildRequestOptions │ │ │ │ + * Build an object with the relevant options for the GetFeatureInfo request. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged. │ │ │ │ + * layer - {<OpenLayers.Layer.WMTS>} A WMTS layer. │ │ │ │ + * xy - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ + * mouse event occurred. │ │ │ │ */ │ │ │ │ - dragComplete: function(vertex) { │ │ │ │ - this.resetVertices(); │ │ │ │ - this.setFeatureState(); │ │ │ │ - this.onModification(this.feature); │ │ │ │ - this.layer.events.triggerEvent("featuremodified", { │ │ │ │ - feature: this.feature │ │ │ │ + buildRequestOptions: function(layer, xy) { │ │ │ │ + var loc = this.map.getLonLatFromPixel(xy); │ │ │ │ + var getTileUrl = layer.getURL( │ │ │ │ + new OpenLayers.Bounds(loc.lon, loc.lat, loc.lon, loc.lat) │ │ │ │ + ); │ │ │ │ + var params = OpenLayers.Util.getParameters(getTileUrl); │ │ │ │ + var tileInfo = layer.getTileInfo(loc); │ │ │ │ + OpenLayers.Util.extend(params, { │ │ │ │ + service: "WMTS", │ │ │ │ + version: layer.version, │ │ │ │ + request: "GetFeatureInfo", │ │ │ │ + infoFormat: this.infoFormat, │ │ │ │ + i: tileInfo.i, │ │ │ │ + j: tileInfo.j │ │ │ │ }); │ │ │ │ + OpenLayers.Util.applyDefaults(params, this.vendorParams); │ │ │ │ + return { │ │ │ │ + url: OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url, │ │ │ │ + params: OpenLayers.Util.upperCaseObject(params), │ │ │ │ + callback: function(request) { │ │ │ │ + this.handleResponse(xy, request, layer); │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + * Method: request │ │ │ │ + * Sends a GetFeatureInfo request to the WMTS │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Event} Keypress event. │ │ │ │ + * xy - {<OpenLayers.Pixel>} The position on the map where the mouse event │ │ │ │ + * occurred. │ │ │ │ + * options - {Object} additional options for this method. │ │ │ │ + * │ │ │ │ + * Valid options: │ │ │ │ + * - *hover* {Boolean} true if we do the request for the hover handler │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ + request: function(xy, options) { │ │ │ │ + options = options || {}; │ │ │ │ + var layers = this.findLayers(); │ │ │ │ + if (layers.length > 0) { │ │ │ │ + var issue, layer; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + layer = layers[i]; │ │ │ │ + issue = this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ + xy: xy, │ │ │ │ + layer: layer │ │ │ │ }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - } │ │ │ │ + if (issue !== false) { │ │ │ │ + ++this.pending; │ │ │ │ + var requestOptions = this.buildRequestOptions(layer, xy); │ │ │ │ + var request = OpenLayers.Request.GET(requestOptions); │ │ │ │ + if (options.hover === true) { │ │ │ │ + this.hoverRequest = request; │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ - } │ │ │ │ - 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); │ │ │ │ + if (this.pending > 0) { │ │ │ │ + OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ } │ │ │ │ - }; │ │ │ │ - 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 │ │ │ │ + * Method: handleResponse │ │ │ │ + * Handler for the GetFeatureInfo response. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Object} │ │ │ │ + * xy - {<OpenLayers.Pixel>} The position on the map where the mouse event │ │ │ │ + * occurred. │ │ │ │ + * request - {XMLHttpRequest} The request object. │ │ │ │ + * layer - {<OpenLayers.Layer.WMTS>} The queried layer. │ │ │ │ */ │ │ │ │ - handleMapEvents: function(evt) { │ │ │ │ - if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ - this.moveLayerToTop(); │ │ │ │ + handleResponse: function(xy, request, layer) { │ │ │ │ + --this.pending; │ │ │ │ + if (this.pending <= 0) { │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + this.pending = 0; │ │ │ │ } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + if (request.status && (request.status < 200 || request.status >= 300)) { │ │ │ │ + this.events.triggerEvent("exception", { │ │ │ │ + xy: xy, │ │ │ │ + request: request, │ │ │ │ + layer: layer │ │ │ │ + }); │ │ │ │ } else { │ │ │ │ - this.map.setLayerZIndex(this.layer, │ │ │ │ - this.map.getLayerIndex(this.layer)); │ │ │ │ + var doc = request.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = request.responseText; │ │ │ │ + } │ │ │ │ + var features, except; │ │ │ │ + try { │ │ │ │ + features = this.format.read(doc); │ │ │ │ + } catch (error) { │ │ │ │ + except = true; │ │ │ │ + this.events.triggerEvent("exception", { │ │ │ │ + xy: xy, │ │ │ │ + request: request, │ │ │ │ + error: error, │ │ │ │ + layer: layer │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + if (!except) { │ │ │ │ + this.events.triggerEvent("getfeatureinfo", { │ │ │ │ + text: request.responseText, │ │ │ │ + features: features, │ │ │ │ + request: request, │ │ │ │ + xy: xy, │ │ │ │ + layer: layer │ │ │ │ + }); │ │ │ │ + } │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ModifyFeature" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.WMTSGetFeatureInfo" │ │ │ │ }); │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * 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/Control/Pan.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 │ │ │ │ @@ -68206,14 +75285,462 @@ │ │ │ │ new OpenLayers.Control.Pan(OpenLayers.Control.Pan.WEST, options) │ │ │ │ ]); │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Control.PanPanel" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ + OpenLayers/Control/ArgParser.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.ArgParser │ │ │ │ + * The ArgParser control adds location bar query string parsing functionality │ │ │ │ + * to an OpenLayers Map. │ │ │ │ + * When added to a Map control, on a page load/refresh, the Map will │ │ │ │ + * automatically take the href string and parse it for lon, lat, zoom, and │ │ │ │ + * layers information. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: center │ │ │ │ + * {<OpenLayers.LonLat>} │ │ │ │ + */ │ │ │ │ + center: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: zoom │ │ │ │ + * {int} │ │ │ │ + */ │ │ │ │ + zoom: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: layers │ │ │ │ + * {String} Each character represents the state of the corresponding layer │ │ │ │ + * on the map. │ │ │ │ + */ │ │ │ │ + layers: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: displayProjection │ │ │ │ + * {<OpenLayers.Projection>} Requires proj4js support. │ │ │ │ + * Projection used when reading the coordinates from the URL. This will │ │ │ │ + * reproject the map coordinates from the URL into the map's │ │ │ │ + * projection. │ │ │ │ + * │ │ │ │ + * If you are using this functionality, be aware that any permalink │ │ │ │ + * which is added to the map will determine the coordinate type which │ │ │ │ + * is read from the URL, which means you should not add permalinks with │ │ │ │ + * different displayProjections to the same map. │ │ │ │ + */ │ │ │ │ + displayProjection: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.ArgParser │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getParameters │ │ │ │ + */ │ │ │ │ + getParameters: function(url) { │ │ │ │ + url = url || window.location.href; │ │ │ │ + var parameters = OpenLayers.Util.getParameters(url); │ │ │ │ + │ │ │ │ + // If we have an anchor in the url use it to split the url │ │ │ │ + var index = url.indexOf('#'); │ │ │ │ + if (index > 0) { │ │ │ │ + // create an url to parse on the getParameters │ │ │ │ + url = '?' + url.substring(index + 1, url.length); │ │ │ │ + │ │ │ │ + OpenLayers.Util.extend(parameters, │ │ │ │ + OpenLayers.Util.getParameters(url)); │ │ │ │ + } │ │ │ │ + return parameters; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ + * Set the map property for the control. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + │ │ │ │ + //make sure we dont already have an arg parser attached │ │ │ │ + for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ + var control = this.map.controls[i]; │ │ │ │ + if ((control != this) && │ │ │ │ + (control.CLASS_NAME == "OpenLayers.Control.ArgParser")) { │ │ │ │ + │ │ │ │ + // If a second argparser is added to the map, then we │ │ │ │ + // override the displayProjection to be the one added to the │ │ │ │ + // map. │ │ │ │ + if (control.displayProjection != this.displayProjection) { │ │ │ │ + this.displayProjection = control.displayProjection; │ │ │ │ + } │ │ │ │ + │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (i == this.map.controls.length) { │ │ │ │ + │ │ │ │ + var args = this.getParameters(); │ │ │ │ + // Be careful to set layer first, to not trigger unnecessary layer loads │ │ │ │ + if (args.layers) { │ │ │ │ + this.layers = args.layers; │ │ │ │ + │ │ │ │ + // when we add a new layer, set its visibility │ │ │ │ + this.map.events.register('addlayer', this, │ │ │ │ + this.configureLayers); │ │ │ │ + this.configureLayers(); │ │ │ │ + } │ │ │ │ + if (args.lat && args.lon) { │ │ │ │ + this.center = new OpenLayers.LonLat(parseFloat(args.lon), │ │ │ │ + parseFloat(args.lat)); │ │ │ │ + if (args.zoom) { │ │ │ │ + this.zoom = parseFloat(args.zoom); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // when we add a new baselayer to see when we can set the center │ │ │ │ + this.map.events.register('changebaselayer', this, │ │ │ │ + this.setCenter); │ │ │ │ + this.setCenter(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setCenter │ │ │ │ + * As soon as a baseLayer has been loaded, we center and zoom │ │ │ │ + * ...and remove the handler. │ │ │ │ + */ │ │ │ │ + setCenter: function() { │ │ │ │ + │ │ │ │ + if (this.map.baseLayer) { │ │ │ │ + //dont need to listen for this one anymore │ │ │ │ + this.map.events.unregister('changebaselayer', this, │ │ │ │ + this.setCenter); │ │ │ │ + │ │ │ │ + if (this.displayProjection) { │ │ │ │ + this.center.transform(this.displayProjection, │ │ │ │ + this.map.getProjectionObject()); │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.map.setCenter(this.center, this.zoom); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: configureLayers │ │ │ │ + * As soon as all the layers are loaded, cycle through them and │ │ │ │ + * hide or show them. │ │ │ │ + */ │ │ │ │ + configureLayers: function() { │ │ │ │ + │ │ │ │ + if (this.layers.length == this.map.layers.length) { │ │ │ │ + this.map.events.unregister('addlayer', this, this.configureLayers); │ │ │ │ + │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ + │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + var c = this.layers.charAt(i); │ │ │ │ + │ │ │ │ + if (c == "B") { │ │ │ │ + this.map.setBaseLayer(layer); │ │ │ │ + } else if ((c == "T") || (c == "F")) { │ │ │ │ + layer.setVisibility(c == "T"); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ArgParser" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/Permalink.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/Control/ArgParser.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.Permalink │ │ │ │ + * The Permalink control is hyperlink that will return the user to the │ │ │ │ + * current map view. By default it is drawn in the lower right corner of the │ │ │ │ + * map. The href is updated as the map is zoomed, panned and whilst layers │ │ │ │ + * are switched. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: argParserClass │ │ │ │ + * {Class} The ArgParser control class (not instance) to use with this │ │ │ │ + * control. │ │ │ │ + */ │ │ │ │ + argParserClass: OpenLayers.Control.ArgParser, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: element │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + element: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: anchor │ │ │ │ + * {Boolean} This option changes 3 things: │ │ │ │ + * the character '#' is used in place of the character '?', │ │ │ │ + * the window.href is updated if no element is provided. │ │ │ │ + * When this option is set to true it's not recommend to provide │ │ │ │ + * a base without provide an element. │ │ │ │ + */ │ │ │ │ + anchor: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: base │ │ │ │ + * {String} │ │ │ │ + */ │ │ │ │ + base: '', │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: displayProjection │ │ │ │ + * {<OpenLayers.Projection>} Requires proj4js support. Projection used │ │ │ │ + * when creating the coordinates in the link. This will reproject the │ │ │ │ + * map coordinates into display coordinates. If you are using this │ │ │ │ + * functionality, the permalink which is last added to the map will │ │ │ │ + * determine the coordinate type which is read from the URL, which │ │ │ │ + * means you should not add permalinks with different │ │ │ │ + * displayProjections to the same map. │ │ │ │ + */ │ │ │ │ + displayProjection: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.Permalink │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * element - {DOMElement} │ │ │ │ + * base - {String} │ │ │ │ + * options - {Object} options to the control. │ │ │ │ + * │ │ │ │ + * Or for anchor: │ │ │ │ + * options - {Object} options to the control. │ │ │ │ + */ │ │ │ │ + initialize: function(element, base, options) { │ │ │ │ + if (element !== null && typeof element == 'object' && !OpenLayers.Util.isElement(element)) { │ │ │ │ + options = element; │ │ │ │ + this.base = document.location.href; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + if (this.element != null) { │ │ │ │ + this.element = OpenLayers.Util.getElement(this.element); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.element = OpenLayers.Util.getElement(element); │ │ │ │ + this.base = base || document.location.href; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: destroy │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + if (this.element && this.element.parentNode == this.div) { │ │ │ │ + this.div.removeChild(this.element); │ │ │ │ + this.element = null; │ │ │ │ + } │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.unregister('moveend', this, this.updateLink); │ │ │ │ + } │ │ │ │ + │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ + * Set the map property for the control. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + │ │ │ │ + //make sure we have an arg parser attached │ │ │ │ + for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ + var control = this.map.controls[i]; │ │ │ │ + if (control.CLASS_NAME == this.argParserClass.CLASS_NAME) { │ │ │ │ + │ │ │ │ + // If a permalink is added to the map, and an ArgParser already │ │ │ │ + // exists, we override the displayProjection to be the one │ │ │ │ + // on the permalink. │ │ │ │ + if (control.displayProjection != this.displayProjection) { │ │ │ │ + this.displayProjection = control.displayProjection; │ │ │ │ + } │ │ │ │ + │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (i == this.map.controls.length) { │ │ │ │ + this.map.addControl(new this.argParserClass({ │ │ │ │ + 'displayProjection': this.displayProjection │ │ │ │ + })); │ │ │ │ + } │ │ │ │ + │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: draw │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + │ │ │ │ + if (!this.element && !this.anchor) { │ │ │ │ + this.element = document.createElement("a"); │ │ │ │ + this.element.innerHTML = OpenLayers.i18n("Permalink"); │ │ │ │ + this.element.href = ""; │ │ │ │ + this.div.appendChild(this.element); │ │ │ │ + } │ │ │ │ + this.map.events.on({ │ │ │ │ + 'moveend': this.updateLink, │ │ │ │ + 'changelayer': this.updateLink, │ │ │ │ + 'changebaselayer': this.updateLink, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + │ │ │ │ + // Make it so there is at least a link even though the map may not have │ │ │ │ + // moved yet. │ │ │ │ + this.updateLink(); │ │ │ │ + │ │ │ │ + return this.div; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: updateLink │ │ │ │ + */ │ │ │ │ + updateLink: function() { │ │ │ │ + var separator = this.anchor ? '#' : '?'; │ │ │ │ + var href = this.base; │ │ │ │ + var anchor = null; │ │ │ │ + if (href.indexOf("#") != -1 && this.anchor == false) { │ │ │ │ + anchor = href.substring(href.indexOf("#"), href.length); │ │ │ │ + } │ │ │ │ + if (href.indexOf(separator) != -1) { │ │ │ │ + href = href.substring(0, href.indexOf(separator)); │ │ │ │ + } │ │ │ │ + var splits = href.split("#"); │ │ │ │ + href = splits[0] + separator + OpenLayers.Util.getParameterString(this.createParams()); │ │ │ │ + if (anchor) { │ │ │ │ + href += anchor; │ │ │ │ + } │ │ │ │ + if (this.anchor && !this.element) { │ │ │ │ + window.location.href = href; │ │ │ │ + } else { │ │ │ │ + this.element.href = href; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: createParams │ │ │ │ + * Creates the parameters that need to be encoded into the permalink url. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * center - {<OpenLayers.LonLat>} center to encode in the permalink. │ │ │ │ + * Defaults to the current map center. │ │ │ │ + * zoom - {Integer} zoom level to encode in the permalink. Defaults to the │ │ │ │ + * current map zoom level. │ │ │ │ + * layers - {Array(<OpenLayers.Layer>)} layers to encode in the permalink. │ │ │ │ + * Defaults to the current map layers. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} Hash of parameters that will be url-encoded into the │ │ │ │ + * permalink. │ │ │ │ + */ │ │ │ │ + createParams: function(center, zoom, layers) { │ │ │ │ + center = center || this.map.getCenter(); │ │ │ │ + │ │ │ │ + var params = OpenLayers.Util.getParameters(this.base); │ │ │ │ + │ │ │ │ + // If there's still no center, map is not initialized yet. │ │ │ │ + // Break out of this function, and simply return the params from the │ │ │ │ + // base link. │ │ │ │ + if (center) { │ │ │ │ + │ │ │ │ + //zoom │ │ │ │ + params.zoom = zoom || this.map.getZoom(); │ │ │ │ + │ │ │ │ + //lon,lat │ │ │ │ + var lat = center.lat; │ │ │ │ + var lon = center.lon; │ │ │ │ + │ │ │ │ + if (this.displayProjection) { │ │ │ │ + var mapPosition = OpenLayers.Projection.transform({ │ │ │ │ + x: lon, │ │ │ │ + y: lat │ │ │ │ + }, │ │ │ │ + this.map.getProjectionObject(), │ │ │ │ + this.displayProjection); │ │ │ │ + lon = mapPosition.x; │ │ │ │ + lat = mapPosition.y; │ │ │ │ + } │ │ │ │ + params.lat = Math.round(lat * 100000) / 100000; │ │ │ │ + params.lon = Math.round(lon * 100000) / 100000; │ │ │ │ + │ │ │ │ + //layers │ │ │ │ + layers = layers || this.map.layers; │ │ │ │ + params.layers = ''; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + var layer = layers[i]; │ │ │ │ + │ │ │ │ + if (layer.isBaseLayer) { │ │ │ │ + params.layers += (layer == this.map.baseLayer) ? "B" : "0"; │ │ │ │ + } else { │ │ │ │ + params.layers += (layer.getVisibility()) ? "T" : "F"; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + return params; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Permalink" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ OpenLayers/Control/GetFeature.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. */ │ │ │ │ @@ -68826,2639 +76353,996 @@ │ │ │ │ var ur = this.map.getLonLatFromPixel(urPx); │ │ │ │ return new OpenLayers.Bounds(ll.lon, ll.lat, ur.lon, ur.lat); │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Control.GetFeature" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/ZoomToMaxExtent.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/Button.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.ZoomToMaxExtent │ │ │ │ - * The ZoomToMaxExtent control is a button that zooms out to the maximum │ │ │ │ - * extent of the map. It is designed to be used with a │ │ │ │ - * <OpenLayers.Control.Panel>. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.ZoomToMaxExtent = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: trigger │ │ │ │ - * │ │ │ │ - * Called whenever this control is being rendered inside of a panel and a │ │ │ │ - * click occurs on this controls element. Actually zooms to the maximum │ │ │ │ - * extent of this controls map. │ │ │ │ - */ │ │ │ │ - trigger: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.zoomToMaxExtent(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomToMaxExtent" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/CacheRead.js │ │ │ │ + OpenLayers/Control/Graticule.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/Lang.js │ │ │ │ + * @requires OpenLayers/Rule.js │ │ │ │ + * @requires OpenLayers/StyleMap.js │ │ │ │ + * @requires OpenLayers/Layer/Vector.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.CacheRead │ │ │ │ - * A control for using image tiles cached with <OpenLayers.Control.CacheWrite> │ │ │ │ - * from the browser's local storage. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Control.Graticule │ │ │ │ + * The Graticule displays a grid of latitude/longitude lines reprojected on │ │ │ │ + * the map. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Control> │ │ │ │ + * │ │ │ │ */ │ │ │ │ -OpenLayers.Control.CacheRead = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: fetchEvent │ │ │ │ - * {String} The layer event to listen to for replacing remote resource tile │ │ │ │ - * URLs with cached data URIs. Supported values are "tileerror" (try │ │ │ │ - * remote first, fall back to cached) and "tileloadstart" (try cache │ │ │ │ - * first, fall back to remote). Default is "tileloadstart". │ │ │ │ - * │ │ │ │ - * Note that "tileerror" will not work for CORS enabled images (see │ │ │ │ - * https://developer.mozilla.org/en/CORS_Enabled_Image), i.e. layers │ │ │ │ - * configured with a <OpenLayers.Tile.Image.crossOriginKeyword> in │ │ │ │ - * <OpenLayers.Layer.Grid.tileOptions>. │ │ │ │ - */ │ │ │ │ - fetchEvent: "tileloadstart", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: layers │ │ │ │ - * {Array(<OpenLayers.Layer.Grid>)}. Optional. If provided, only these │ │ │ │ - * layers will receive tiles from the cache. │ │ │ │ - */ │ │ │ │ - layers: null, │ │ │ │ +OpenLayers.Control.Graticule = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * true. │ │ │ │ */ │ │ │ │ autoActivate: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.CacheRead │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Object with API properties for this control │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * Set the map property for the control. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ - */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - var i, layers = this.layers || map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.addLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - if (!this.layers) { │ │ │ │ - map.events.on({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: addLayer │ │ │ │ - * Adds a layer to the control. Once added, tiles requested for this layer │ │ │ │ - * will be cached. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} Object with a layer property referencing an │ │ │ │ - * <OpenLayers.Layer> instance │ │ │ │ - */ │ │ │ │ - addLayer: function(evt) { │ │ │ │ - evt.layer.events.register(this.fetchEvent, this, this.fetch); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: removeLayer │ │ │ │ - * Removes a layer from the control. Once removed, tiles requested for this │ │ │ │ - * layer will no longer be cached. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} Object with a layer property referencing an │ │ │ │ - * <OpenLayers.Layer> instance │ │ │ │ - */ │ │ │ │ - removeLayer: function(evt) { │ │ │ │ - evt.layer.events.unregister(this.fetchEvent, this, this.fetch); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: fetch │ │ │ │ - * Listener to the <fetchEvent> event. Replaces a tile's url with a data │ │ │ │ - * URI from the cache. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} Event object with a tile property. │ │ │ │ - */ │ │ │ │ - fetch: function(evt) { │ │ │ │ - if (this.active && window.localStorage && │ │ │ │ - evt.tile instanceof OpenLayers.Tile.Image) { │ │ │ │ - var tile = evt.tile, │ │ │ │ - url = tile.url; │ │ │ │ - // deal with modified tile urls when both CacheWrite and CacheRead │ │ │ │ - // are active │ │ │ │ - if (!tile.layer.crossOriginKeyword && OpenLayers.ProxyHost && │ │ │ │ - url.indexOf(OpenLayers.ProxyHost) === 0) { │ │ │ │ - url = OpenLayers.Control.CacheWrite.urlMap[url]; │ │ │ │ - } │ │ │ │ - var dataURI = window.localStorage.getItem("olCache_" + url); │ │ │ │ - if (dataURI) { │ │ │ │ - tile.url = dataURI; │ │ │ │ - if (evt.type === "tileerror") { │ │ │ │ - tile.setImgSrc(dataURI); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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.layers || this.map) { │ │ │ │ - var i, layers = this.layers || this.map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.removeLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.un({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.CacheRead" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/LayerSwitcher.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/Lang.js │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ - * @requires OpenLayers/Events/buttonclick.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.LayerSwitcher │ │ │ │ - * The LayerSwitcher control displays a table of contents for the map. This │ │ │ │ - * allows the user interface to switch between BaseLasyers and to show or hide │ │ │ │ - * Overlays. By default the switcher is shown minimized on the right edge of │ │ │ │ - * the map, the user may expand it by clicking on the handle. │ │ │ │ - * │ │ │ │ - * To create the LayerSwitcher outside of the map, pass the Id of a html div │ │ │ │ - * as the first argument to the constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.LayerSwitcher = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: layerStates │ │ │ │ - * {Array(Object)} Basically a copy of the "state" of the map's layers │ │ │ │ - * the last time the control was drawn. We have this in order to avoid │ │ │ │ - * unnecessarily redrawing the control. │ │ │ │ - */ │ │ │ │ - layerStates: null, │ │ │ │ - │ │ │ │ - // DOM Elements │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: layersDiv │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - layersDiv: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: baseLayersDiv │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - baseLayersDiv: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: baseLayers │ │ │ │ - * {Array(Object)} │ │ │ │ - */ │ │ │ │ - baseLayers: null, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: dataLbl │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - dataLbl: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: dataLayersDiv │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - dataLayersDiv: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: dataLayers │ │ │ │ - * {Array(Object)} │ │ │ │ - */ │ │ │ │ - dataLayers: null, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: minimizeDiv │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - minimizeDiv: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: maximizeDiv │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - maximizeDiv: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: ascending │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - ascending: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.LayerSwitcher │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ - this.layerStates = []; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - │ │ │ │ - //clear out layers info and unregister their events │ │ │ │ - this.clearLayersArray("base"); │ │ │ │ - this.clearLayersArray("data"); │ │ │ │ - │ │ │ │ - this.map.events.un({ │ │ │ │ - buttonclick: this.onButtonClick, │ │ │ │ - addlayer: this.redraw, │ │ │ │ - changelayer: this.redraw, │ │ │ │ - removelayer: this.redraw, │ │ │ │ - changebaselayer: this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ - │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * │ │ │ │ - * Properties: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * APIProperty: intervals │ │ │ │ + * {Array(Float)} A list of possible graticule widths in degrees. │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - │ │ │ │ - this.map.events.on({ │ │ │ │ - addlayer: this.redraw, │ │ │ │ - changelayer: this.redraw, │ │ │ │ - removelayer: this.redraw, │ │ │ │ - changebaselayer: this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - if (this.outsideViewport) { │ │ │ │ - this.events.attachToElement(this.div); │ │ │ │ - this.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ - } else { │ │ │ │ - this.map.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + intervals: [45, 30, 20, 10, 5, 2, 1, │ │ │ │ + 0.5, 0.2, 0.1, 0.05, 0.01, │ │ │ │ + 0.005, 0.002, 0.001 │ │ │ │ + ], │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: draw │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A reference to the DIV DOMElement containing the │ │ │ │ - * switcher tabs. │ │ │ │ + * APIProperty: displayInLayerSwitcher │ │ │ │ + * {Boolean} Allows the Graticule control to be switched on and off by │ │ │ │ + * LayerSwitcher control. Defaults is true. │ │ │ │ */ │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this); │ │ │ │ - │ │ │ │ - // create layout divs │ │ │ │ - this.loadContents(); │ │ │ │ - │ │ │ │ - // set mode to minimize │ │ │ │ - if (!this.outsideViewport) { │ │ │ │ - this.minimizeControl(); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // populate div with current info │ │ │ │ - this.redraw(); │ │ │ │ - │ │ │ │ - return this.div; │ │ │ │ - }, │ │ │ │ + displayInLayerSwitcher: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onButtonClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ + * APIProperty: visible │ │ │ │ + * {Boolean} should the graticule be initially visible (default=true) │ │ │ │ */ │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - var button = evt.buttonElement; │ │ │ │ - if (button === this.minimizeDiv) { │ │ │ │ - this.minimizeControl(); │ │ │ │ - } else if (button === this.maximizeDiv) { │ │ │ │ - this.maximizeControl(); │ │ │ │ - } else if (button._layerSwitcher === this.id) { │ │ │ │ - if (button["for"]) { │ │ │ │ - button = document.getElementById(button["for"]); │ │ │ │ - } │ │ │ │ - if (!button.disabled) { │ │ │ │ - if (button.type == "radio") { │ │ │ │ - button.checked = true; │ │ │ │ - this.map.setBaseLayer(this.map.getLayer(button._layer)); │ │ │ │ - } else { │ │ │ │ - button.checked = !button.checked; │ │ │ │ - this.updateMap(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + visible: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clearLayersArray │ │ │ │ - * User specifies either "base" or "data". we then clear all the │ │ │ │ - * corresponding listeners, the div, and reinitialize a new array. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layersType - {String} │ │ │ │ + * APIProperty: numPoints │ │ │ │ + * {Integer} The number of points to use in each graticule line. Higher │ │ │ │ + * numbers result in a smoother curve for projected maps │ │ │ │ */ │ │ │ │ - clearLayersArray: function(layersType) { │ │ │ │ - this[layersType + "LayersDiv"].innerHTML = ""; │ │ │ │ - this[layersType + "Layers"] = []; │ │ │ │ - }, │ │ │ │ - │ │ │ │ + numPoints: 50, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: checkRedraw │ │ │ │ - * Checks if the layer state has changed since the last redraw() call. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The layer state changed since the last redraw() call. │ │ │ │ + * APIProperty: targetSize │ │ │ │ + * {Integer} The maximum size of the grid in pixels on the map │ │ │ │ */ │ │ │ │ - checkRedraw: function() { │ │ │ │ - if (!this.layerStates.length || │ │ │ │ - (this.map.layers.length != this.layerStates.length)) { │ │ │ │ - return true; │ │ │ │ - } │ │ │ │ - │ │ │ │ - for (var i = 0, len = this.layerStates.length; i < len; i++) { │ │ │ │ - var layerState = this.layerStates[i]; │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - if ((layerState.name != layer.name) || │ │ │ │ - (layerState.inRange != layer.inRange) || │ │ │ │ - (layerState.id != layer.id) || │ │ │ │ - (layerState.visibility != layer.visibility)) { │ │ │ │ - return true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return false; │ │ │ │ - }, │ │ │ │ + targetSize: 200, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: redraw │ │ │ │ - * Goes through and takes the current state of the Map and rebuilds the │ │ │ │ - * control to display that state. Groups base layers into a │ │ │ │ - * radio-button group and lists each data layer with a checkbox. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A reference to the DIV DOMElement containing the control │ │ │ │ + * APIProperty: layerName │ │ │ │ + * {String} The name to be displayed in the layer switcher, default is set │ │ │ │ + * by {<OpenLayers.Lang>}. │ │ │ │ */ │ │ │ │ - redraw: function() { │ │ │ │ - //if the state hasn't changed since last redraw, no need │ │ │ │ - // to do anything. Just return the existing div. │ │ │ │ - if (!this.checkRedraw()) { │ │ │ │ - return this.div; │ │ │ │ - } │ │ │ │ - │ │ │ │ - //clear out previous layers │ │ │ │ - this.clearLayersArray("base"); │ │ │ │ - this.clearLayersArray("data"); │ │ │ │ - │ │ │ │ - var containsOverlays = false; │ │ │ │ - var containsBaseLayers = false; │ │ │ │ - │ │ │ │ - // Save state -- for checking layer if the map state changed. │ │ │ │ - // We save this before redrawing, because in the process of redrawing │ │ │ │ - // we will trigger more visibility changes, and we want to not redraw │ │ │ │ - // and enter an infinite loop. │ │ │ │ - var len = this.map.layers.length; │ │ │ │ - this.layerStates = new Array(len); │ │ │ │ - for (var i = 0; i < len; i++) { │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - this.layerStates[i] = { │ │ │ │ - 'name': layer.name, │ │ │ │ - 'visibility': layer.visibility, │ │ │ │ - 'inRange': layer.inRange, │ │ │ │ - 'id': layer.id │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var layers = this.map.layers.slice(); │ │ │ │ - if (!this.ascending) { │ │ │ │ - layers.reverse(); │ │ │ │ - } │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - var layer = layers[i]; │ │ │ │ - var baseLayer = layer.isBaseLayer; │ │ │ │ - │ │ │ │ - if (layer.displayInLayerSwitcher) { │ │ │ │ - │ │ │ │ - if (baseLayer) { │ │ │ │ - containsBaseLayers = true; │ │ │ │ - } else { │ │ │ │ - containsOverlays = true; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // only check a baselayer if it is *the* baselayer, check data │ │ │ │ - // layers if they are visible │ │ │ │ - var checked = (baseLayer) ? (layer == this.map.baseLayer) : │ │ │ │ - layer.getVisibility(); │ │ │ │ - │ │ │ │ - // create input element │ │ │ │ - var inputElem = document.createElement("input"), │ │ │ │ - // The input shall have an id attribute so we can use │ │ │ │ - // labels to interact with them. │ │ │ │ - inputId = OpenLayers.Util.createUniqueID( │ │ │ │ - this.id + "_input_" │ │ │ │ - ); │ │ │ │ - │ │ │ │ - inputElem.id = inputId; │ │ │ │ - inputElem.name = (baseLayer) ? this.id + "_baseLayers" : layer.name; │ │ │ │ - inputElem.type = (baseLayer) ? "radio" : "checkbox"; │ │ │ │ - inputElem.value = layer.name; │ │ │ │ - inputElem.checked = checked; │ │ │ │ - inputElem.defaultChecked = checked; │ │ │ │ - inputElem.className = "olButton"; │ │ │ │ - inputElem._layer = layer.id; │ │ │ │ - inputElem._layerSwitcher = this.id; │ │ │ │ - │ │ │ │ - if (!baseLayer && !layer.inRange) { │ │ │ │ - inputElem.disabled = true; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // create span │ │ │ │ - var labelSpan = document.createElement("label"); │ │ │ │ - // this isn't the DOM attribute 'for', but an arbitrary name we │ │ │ │ - // use to find the appropriate input element in <onButtonClick> │ │ │ │ - labelSpan["for"] = inputElem.id; │ │ │ │ - OpenLayers.Element.addClass(labelSpan, "labelSpan olButton"); │ │ │ │ - labelSpan._layer = layer.id; │ │ │ │ - labelSpan._layerSwitcher = this.id; │ │ │ │ - if (!baseLayer && !layer.inRange) { │ │ │ │ - labelSpan.style.color = "gray"; │ │ │ │ - } │ │ │ │ - labelSpan.innerHTML = layer.name; │ │ │ │ - labelSpan.style.verticalAlign = (baseLayer) ? "bottom" : │ │ │ │ - "baseline"; │ │ │ │ - // create line break │ │ │ │ - var br = document.createElement("br"); │ │ │ │ - │ │ │ │ - │ │ │ │ - var groupArray = (baseLayer) ? this.baseLayers : │ │ │ │ - this.dataLayers; │ │ │ │ - groupArray.push({ │ │ │ │ - 'layer': layer, │ │ │ │ - 'inputElem': inputElem, │ │ │ │ - 'labelSpan': labelSpan │ │ │ │ - }); │ │ │ │ - │ │ │ │ - │ │ │ │ - var groupDiv = (baseLayer) ? this.baseLayersDiv : │ │ │ │ - this.dataLayersDiv; │ │ │ │ - groupDiv.appendChild(inputElem); │ │ │ │ - groupDiv.appendChild(labelSpan); │ │ │ │ - groupDiv.appendChild(br); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // if no overlays, dont display the overlay label │ │ │ │ - this.dataLbl.style.display = (containsOverlays) ? "" : "none"; │ │ │ │ - │ │ │ │ - // if no baselayers, dont display the baselayer label │ │ │ │ - this.baseLbl.style.display = (containsBaseLayers) ? "" : "none"; │ │ │ │ - │ │ │ │ - return this.div; │ │ │ │ - }, │ │ │ │ + layerName: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: updateMap │ │ │ │ - * Cycles through the loaded data and base layer input arrays and makes │ │ │ │ - * the necessary calls to the Map object such that that the map's │ │ │ │ - * visual state corresponds to what the user has selected in │ │ │ │ - * the control. │ │ │ │ + * APIProperty: labelled │ │ │ │ + * {Boolean} Should the graticule lines be labelled?. default=true │ │ │ │ */ │ │ │ │ - updateMap: function() { │ │ │ │ - │ │ │ │ - // set the newly selected base layer │ │ │ │ - for (var i = 0, len = this.baseLayers.length; i < len; i++) { │ │ │ │ - var layerEntry = this.baseLayers[i]; │ │ │ │ - if (layerEntry.inputElem.checked) { │ │ │ │ - this.map.setBaseLayer(layerEntry.layer, false); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // set the correct visibilities for the overlays │ │ │ │ - for (var i = 0, len = this.dataLayers.length; i < len; i++) { │ │ │ │ - var layerEntry = this.dataLayers[i]; │ │ │ │ - layerEntry.layer.setVisibility(layerEntry.inputElem.checked); │ │ │ │ - } │ │ │ │ - │ │ │ │ - }, │ │ │ │ + labelled: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: maximizeControl │ │ │ │ - * Set up the labels and divs for the control │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {Event} │ │ │ │ + * APIProperty: labelFormat │ │ │ │ + * {String} the format of the labels, default = 'dm'. See │ │ │ │ + * <OpenLayers.Util.getFormattedLonLat> for other options. │ │ │ │ */ │ │ │ │ - maximizeControl: function(e) { │ │ │ │ - │ │ │ │ - // set the div's width and height to empty values, so │ │ │ │ - // the div dimensions can be controlled by CSS │ │ │ │ - this.div.style.width = ""; │ │ │ │ - this.div.style.height = ""; │ │ │ │ - │ │ │ │ - this.showControls(false); │ │ │ │ - │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + labelFormat: 'dm', │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: minimizeControl │ │ │ │ - * Hide all the contents of the control, shrink the size, │ │ │ │ - * add the maximize icon │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * e - {Event} │ │ │ │ + * APIProperty: lineSymbolizer │ │ │ │ + * {symbolizer} the symbolizer used to render lines │ │ │ │ */ │ │ │ │ - minimizeControl: function(e) { │ │ │ │ - │ │ │ │ - // to minimize the control we set its div's width │ │ │ │ - // and height to 0px, we cannot just set "display" │ │ │ │ - // to "none" because it would hide the maximize │ │ │ │ - // div │ │ │ │ - this.div.style.width = "0px"; │ │ │ │ - this.div.style.height = "0px"; │ │ │ │ - │ │ │ │ - this.showControls(true); │ │ │ │ - │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e); │ │ │ │ - } │ │ │ │ + lineSymbolizer: { │ │ │ │ + strokeColor: "#333", │ │ │ │ + strokeWidth: 1, │ │ │ │ + strokeOpacity: 0.5 │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: showControls │ │ │ │ - * Hide/Show all LayerSwitcher controls depending on whether we are │ │ │ │ - * minimized or not │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * minimize - {Boolean} │ │ │ │ + * APIProperty: labelSymbolizer │ │ │ │ + * {symbolizer} the symbolizer used to render labels │ │ │ │ */ │ │ │ │ - showControls: function(minimize) { │ │ │ │ - │ │ │ │ - this.maximizeDiv.style.display = minimize ? "" : "none"; │ │ │ │ - this.minimizeDiv.style.display = minimize ? "none" : ""; │ │ │ │ - │ │ │ │ - this.layersDiv.style.display = minimize ? "none" : ""; │ │ │ │ - }, │ │ │ │ + labelSymbolizer: {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: loadContents │ │ │ │ - * Set up the labels and divs for the control │ │ │ │ + * Property: gratLayer │ │ │ │ + * {<OpenLayers.Layer.Vector>} vector layer used to draw the graticule on │ │ │ │ */ │ │ │ │ - loadContents: function() { │ │ │ │ - │ │ │ │ - // layers list div │ │ │ │ - this.layersDiv = document.createElement("div"); │ │ │ │ - this.layersDiv.id = this.id + "_layersDiv"; │ │ │ │ - OpenLayers.Element.addClass(this.layersDiv, "layersDiv"); │ │ │ │ - │ │ │ │ - this.baseLbl = document.createElement("div"); │ │ │ │ - this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer"); │ │ │ │ - OpenLayers.Element.addClass(this.baseLbl, "baseLbl"); │ │ │ │ - │ │ │ │ - this.baseLayersDiv = document.createElement("div"); │ │ │ │ - OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv"); │ │ │ │ - │ │ │ │ - this.dataLbl = document.createElement("div"); │ │ │ │ - this.dataLbl.innerHTML = OpenLayers.i18n("Overlays"); │ │ │ │ - OpenLayers.Element.addClass(this.dataLbl, "dataLbl"); │ │ │ │ - │ │ │ │ - this.dataLayersDiv = document.createElement("div"); │ │ │ │ - OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv"); │ │ │ │ - │ │ │ │ - if (this.ascending) { │ │ │ │ - this.layersDiv.appendChild(this.baseLbl); │ │ │ │ - this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ - this.layersDiv.appendChild(this.dataLbl); │ │ │ │ - this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ - } else { │ │ │ │ - this.layersDiv.appendChild(this.dataLbl); │ │ │ │ - this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ - this.layersDiv.appendChild(this.baseLbl); │ │ │ │ - this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ - } │ │ │ │ - │ │ │ │ - this.div.appendChild(this.layersDiv); │ │ │ │ - │ │ │ │ - // maximize button div │ │ │ │ - var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png'); │ │ │ │ - this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ - "OpenLayers_Control_MaximizeDiv", │ │ │ │ - null, │ │ │ │ - null, │ │ │ │ - img, │ │ │ │ - "absolute"); │ │ │ │ - OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv olButton"); │ │ │ │ - this.maximizeDiv.style.display = "none"; │ │ │ │ - │ │ │ │ - this.div.appendChild(this.maximizeDiv); │ │ │ │ - │ │ │ │ - // minimize button div │ │ │ │ - var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png'); │ │ │ │ - this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ - "OpenLayers_Control_MinimizeDiv", │ │ │ │ - null, │ │ │ │ - null, │ │ │ │ - img, │ │ │ │ - "absolute"); │ │ │ │ - OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton"); │ │ │ │ - this.minimizeDiv.style.display = "none"; │ │ │ │ - │ │ │ │ - this.div.appendChild(this.minimizeDiv); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.LayerSwitcher" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/ZoomPanel.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/Panel.js │ │ │ │ - * @requires OpenLayers/Control/ZoomIn.js │ │ │ │ - * @requires OpenLayers/Control/ZoomOut.js │ │ │ │ - * @requires OpenLayers/Control/ZoomToMaxExtent.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.ZoomPanel │ │ │ │ - * The ZoomPanel control is a compact collecton of 3 zoom controls: a │ │ │ │ - * <OpenLayers.Control.ZoomIn>, a <OpenLayers.Control.ZoomToMaxExtent>, and a │ │ │ │ - * <OpenLayers.Control.ZoomOut>. By default it is drawn in the upper left │ │ │ │ - * corner of the map. │ │ │ │ - * │ │ │ │ - * Note: │ │ │ │ - * If you wish to use this class with the default images and you want │ │ │ │ - * it to look nice in ie6, you should add the following, conditionally │ │ │ │ - * added css stylesheet to your HTML file: │ │ │ │ - * │ │ │ │ - * (code) │ │ │ │ - * <!--[if lte IE 6]> │ │ │ │ - * <link rel="stylesheet" href="../theme/default/ie6-style.css" type="text/css" /> │ │ │ │ - * <![endif]--> │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control.Panel> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.ZoomPanel = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ + gratLayer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.ZoomPanel │ │ │ │ - * Add the three zooming controls. │ │ │ │ - * │ │ │ │ + * Constructor: OpenLayers.Control.Graticule │ │ │ │ + * Create a new graticule control to display a grid of latitude longitude │ │ │ │ + * lines. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be used │ │ │ │ * to extend the control. │ │ │ │ */ │ │ │ │ initialize: function(options) { │ │ │ │ - OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ - this.addControls([ │ │ │ │ - new OpenLayers.Control.ZoomIn(), │ │ │ │ - new OpenLayers.Control.ZoomToMaxExtent(), │ │ │ │ - new OpenLayers.Control.ZoomOut() │ │ │ │ - ]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomPanel" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/WMTSGetFeatureInfo.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/Click.js │ │ │ │ - * @requires OpenLayers/Handler/Hover.js │ │ │ │ - * @requires OpenLayers/Request.js │ │ │ │ - * @requires OpenLayers/Format/WMSGetFeatureInfo.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.WMTSGetFeatureInfo │ │ │ │ - * The WMTSGetFeatureInfo control uses a WMTS query to get information about a │ │ │ │ - * point on the map. The information may be in a display-friendly format │ │ │ │ - * such as HTML, or a machine-friendly format such as GML, depending on the │ │ │ │ - * server's capabilities and the client's configuration. This control │ │ │ │ - * handles click or hover events, attempts to parse the results using an │ │ │ │ - * OpenLayers.Format, and fires a 'getfeatureinfo' event for each layer │ │ │ │ - * queried. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.WMTSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: hover │ │ │ │ - * {Boolean} Send GetFeatureInfo requests when mouse stops moving. │ │ │ │ - * Default is false. │ │ │ │ - */ │ │ │ │ - hover: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: requestEncoding │ │ │ │ - * {String} One of "KVP" or "REST". Only KVP encoding is supported at this │ │ │ │ - * time. │ │ │ │ - */ │ │ │ │ - requestEncoding: "KVP", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: drillDown │ │ │ │ - * {Boolean} Drill down over all WMTS layers in the map. When │ │ │ │ - * using drillDown mode, hover is not possible. A getfeatureinfo event │ │ │ │ - * will be fired for each layer queried. │ │ │ │ - */ │ │ │ │ - drillDown: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: maxFeatures │ │ │ │ - * {Integer} Maximum number of features to return from a WMTS query. This │ │ │ │ - * sets the feature_count parameter on WMTS GetFeatureInfo │ │ │ │ - * requests. │ │ │ │ - */ │ │ │ │ - maxFeatures: 10, │ │ │ │ - │ │ │ │ - /** APIProperty: clickCallback │ │ │ │ - * {String} The click callback to register in the │ │ │ │ - * {<OpenLayers.Handler.Click>} object created when the hover │ │ │ │ - * option is set to false. Default is "click". │ │ │ │ - */ │ │ │ │ - clickCallback: "click", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: layers │ │ │ │ - * {Array(<OpenLayers.Layer.WMTS>)} The layers to query for feature info. │ │ │ │ - * If omitted, all map WMTS layers will be considered. │ │ │ │ - */ │ │ │ │ - layers: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: queryVisible │ │ │ │ - * {Boolean} Filter out hidden layers when searching the map for layers to │ │ │ │ - * query. Default is true. │ │ │ │ - */ │ │ │ │ - queryVisible: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: infoFormat │ │ │ │ - * {String} The mimetype to request from the server │ │ │ │ - */ │ │ │ │ - infoFormat: 'text/html', │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: vendorParams │ │ │ │ - * {Object} Additional parameters that will be added to the request, for │ │ │ │ - * WMTS implementations that support them. This could e.g. look like │ │ │ │ - * (start code) │ │ │ │ - * { │ │ │ │ - * radius: 5 │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ - */ │ │ │ │ - vendorParams: {}, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: format │ │ │ │ - * {<OpenLayers.Format>} A format for parsing GetFeatureInfo responses. │ │ │ │ - * Default is <OpenLayers.Format.WMSGetFeatureInfo>. │ │ │ │ - */ │ │ │ │ - format: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: formatOptions │ │ │ │ - * {Object} Optional properties to set on the format (if one is not provided │ │ │ │ - * in the <format> property. │ │ │ │ - */ │ │ │ │ - formatOptions: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: handlerOptions │ │ │ │ - * {Object} Additional options for the handlers used by this control, e.g. │ │ │ │ - * (start code) │ │ │ │ - * { │ │ │ │ - * "click": {delay: 100}, │ │ │ │ - * "hover": {delay: 300} │ │ │ │ - * } │ │ │ │ - * (end) │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: handler │ │ │ │ - * {Object} Reference to the <OpenLayers.Handler> for this control │ │ │ │ - */ │ │ │ │ - handler: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: hoverRequest │ │ │ │ - * {<OpenLayers.Request>} contains the currently running hover request │ │ │ │ - * (if any). │ │ │ │ - */ │ │ │ │ - hoverRequest: 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>): │ │ │ │ - * beforegetfeatureinfo - Triggered before each request is sent. │ │ │ │ - * The event object has an *xy* property with the position of the │ │ │ │ - * mouse click or hover event that triggers the request and a *layer* │ │ │ │ - * property referencing the layer about to be queried. If a listener │ │ │ │ - * returns false, the request will not be issued. │ │ │ │ - * getfeatureinfo - Triggered when a GetFeatureInfo response is received. │ │ │ │ - * The event object has a *text* property with the body of the │ │ │ │ - * response (String), a *features* property with an array of the │ │ │ │ - * parsed features, an *xy* property with the position of the mouse │ │ │ │ - * click or hover event that triggered the request, a *layer* property │ │ │ │ - * referencing the layer queried and a *request* property with the │ │ │ │ - * request itself. If drillDown is set to true, one event will be fired │ │ │ │ - * for each layer queried. │ │ │ │ - * exception - Triggered when a GetFeatureInfo request fails (with a │ │ │ │ - * status other than 200) or whenparsing fails. Listeners will receive │ │ │ │ - * an event with *request*, *xy*, and *layer* properties. In the case │ │ │ │ - * of a parsing error, the event will also contain an *error* property. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: pending │ │ │ │ - * {Number} The number of pending requests. │ │ │ │ - */ │ │ │ │ - pending: 0, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: <OpenLayers.Control.WMTSGetFeatureInfo> │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ options = options || {}; │ │ │ │ - options.handlerOptions = options.handlerOptions || {}; │ │ │ │ - │ │ │ │ + options.layerName = options.layerName || OpenLayers.i18n("Graticule"); │ │ │ │ OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ │ │ │ │ - if (!this.format) { │ │ │ │ - this.format = new OpenLayers.Format.WMSGetFeatureInfo( │ │ │ │ - options.formatOptions │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.drillDown === true) { │ │ │ │ - this.hover = false; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (this.hover) { │ │ │ │ - this.handler = new OpenLayers.Handler.Hover( │ │ │ │ - this, { │ │ │ │ - move: this.cancelHover, │ │ │ │ - pause: this.getInfoForHover │ │ │ │ - }, │ │ │ │ - OpenLayers.Util.extend( │ │ │ │ - this.handlerOptions.hover || {}, { │ │ │ │ - delay: 250 │ │ │ │ - } │ │ │ │ - ) │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - var callbacks = {}; │ │ │ │ - callbacks[this.clickCallback] = this.getInfoForClick; │ │ │ │ - this.handler = new OpenLayers.Handler.Click( │ │ │ │ - this, callbacks, this.handlerOptions.click || {} │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getInfoForClick │ │ │ │ - * Called on click │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ - */ │ │ │ │ - getInfoForClick: function(evt) { │ │ │ │ - this.request(evt.xy, {}); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getInfoForHover │ │ │ │ - * Pause callback for the hover handler │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Object} │ │ │ │ - */ │ │ │ │ - getInfoForHover: function(evt) { │ │ │ │ - this.request(evt.xy, { │ │ │ │ - hover: true │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: cancelHover │ │ │ │ - * Cancel callback for the hover handler │ │ │ │ - */ │ │ │ │ - cancelHover: function() { │ │ │ │ - if (this.hoverRequest) { │ │ │ │ - --this.pending; │ │ │ │ - if (this.pending <= 0) { │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - this.pending = 0; │ │ │ │ - } │ │ │ │ - this.hoverRequest.abort(); │ │ │ │ - this.hoverRequest = null; │ │ │ │ - } │ │ │ │ + this.labelSymbolizer.stroke = false; │ │ │ │ + this.labelSymbolizer.fill = false; │ │ │ │ + this.labelSymbolizer.label = "${label}"; │ │ │ │ + this.labelSymbolizer.labelAlign = "${labelAlign}"; │ │ │ │ + this.labelSymbolizer.labelXOffset = "${xOffset}"; │ │ │ │ + this.labelSymbolizer.labelYOffset = "${yOffset}"; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: findLayers │ │ │ │ - * Internal method to get the layers, independent of whether we are │ │ │ │ - * inspecting the map or using a client-provided array │ │ │ │ + * APIMethod: destroy │ │ │ │ */ │ │ │ │ - findLayers: function() { │ │ │ │ - var candidates = this.layers || this.map.layers; │ │ │ │ - var layers = []; │ │ │ │ - var layer; │ │ │ │ - for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ - layer = candidates[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.WMTS && │ │ │ │ - layer.requestEncoding === this.requestEncoding && │ │ │ │ - (!this.queryVisible || layer.getVisibility())) { │ │ │ │ - layers.push(layer); │ │ │ │ - if (!this.drillDown || this.hover) { │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + if (this.gratLayer) { │ │ │ │ + this.gratLayer.destroy(); │ │ │ │ + this.gratLayer = null; │ │ │ │ } │ │ │ │ - return layers; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: buildRequestOptions │ │ │ │ - * Build an object with the relevant options for the GetFeatureInfo request. │ │ │ │ + * Method: draw │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.WMTS>} A WMTS layer. │ │ │ │ - * xy - {<OpenLayers.Pixel>} The position on the map where the │ │ │ │ - * mouse event occurred. │ │ │ │ - */ │ │ │ │ - buildRequestOptions: function(layer, xy) { │ │ │ │ - var loc = this.map.getLonLatFromPixel(xy); │ │ │ │ - var getTileUrl = layer.getURL( │ │ │ │ - new OpenLayers.Bounds(loc.lon, loc.lat, loc.lon, loc.lat) │ │ │ │ - ); │ │ │ │ - var params = OpenLayers.Util.getParameters(getTileUrl); │ │ │ │ - var tileInfo = layer.getTileInfo(loc); │ │ │ │ - OpenLayers.Util.extend(params, { │ │ │ │ - service: "WMTS", │ │ │ │ - version: layer.version, │ │ │ │ - request: "GetFeatureInfo", │ │ │ │ - infoFormat: this.infoFormat, │ │ │ │ - i: tileInfo.i, │ │ │ │ - j: tileInfo.j │ │ │ │ - }); │ │ │ │ - OpenLayers.Util.applyDefaults(params, this.vendorParams); │ │ │ │ - return { │ │ │ │ - url: OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url, │ │ │ │ - params: OpenLayers.Util.upperCaseObject(params), │ │ │ │ - callback: function(request) { │ │ │ │ - this.handleResponse(xy, request, layer); │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: request │ │ │ │ - * Sends a GetFeatureInfo request to the WMTS │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * xy - {<OpenLayers.Pixel>} The position on the map where the mouse event │ │ │ │ - * occurred. │ │ │ │ - * options - {Object} additional options for this method. │ │ │ │ + * initializes the graticule layer and does the initial update │ │ │ │ * │ │ │ │ - * Valid options: │ │ │ │ - * - *hover* {Boolean} true if we do the request for the hover handler │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - request: function(xy, options) { │ │ │ │ - options = options || {}; │ │ │ │ - var layers = this.findLayers(); │ │ │ │ - if (layers.length > 0) { │ │ │ │ - var issue, layer; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - layer = layers[i]; │ │ │ │ - issue = this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ - xy: xy, │ │ │ │ - layer: layer │ │ │ │ - }); │ │ │ │ - if (issue !== false) { │ │ │ │ - ++this.pending; │ │ │ │ - var requestOptions = this.buildRequestOptions(layer, xy); │ │ │ │ - var request = OpenLayers.Request.GET(requestOptions); │ │ │ │ - if (options.hover === true) { │ │ │ │ - this.hoverRequest = request; │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (!this.gratLayer) { │ │ │ │ + var gratStyle = new OpenLayers.Style({}, { │ │ │ │ + rules: [new OpenLayers.Rule({ │ │ │ │ + 'symbolizer': { │ │ │ │ + "Point": this.labelSymbolizer, │ │ │ │ + "Line": this.lineSymbolizer │ │ │ │ } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.pending > 0) { │ │ │ │ - OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: handleResponse │ │ │ │ - * Handler for the GetFeatureInfo response. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * xy - {<OpenLayers.Pixel>} The position on the map where the mouse event │ │ │ │ - * occurred. │ │ │ │ - * request - {XMLHttpRequest} The request object. │ │ │ │ - * layer - {<OpenLayers.Layer.WMTS>} The queried layer. │ │ │ │ - */ │ │ │ │ - handleResponse: function(xy, request, layer) { │ │ │ │ - --this.pending; │ │ │ │ - if (this.pending <= 0) { │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - this.pending = 0; │ │ │ │ - } │ │ │ │ - if (request.status && (request.status < 200 || request.status >= 300)) { │ │ │ │ - this.events.triggerEvent("exception", { │ │ │ │ - xy: xy, │ │ │ │ - request: request, │ │ │ │ - layer: layer │ │ │ │ - }); │ │ │ │ - } else { │ │ │ │ - var doc = request.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = request.responseText; │ │ │ │ - } │ │ │ │ - var features, except; │ │ │ │ - try { │ │ │ │ - features = this.format.read(doc); │ │ │ │ - } catch (error) { │ │ │ │ - except = true; │ │ │ │ - this.events.triggerEvent("exception", { │ │ │ │ - xy: xy, │ │ │ │ - request: request, │ │ │ │ - error: error, │ │ │ │ - layer: layer │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - if (!except) { │ │ │ │ - this.events.triggerEvent("getfeatureinfo", { │ │ │ │ - text: request.responseText, │ │ │ │ - features: features, │ │ │ │ - request: request, │ │ │ │ - xy: xy, │ │ │ │ - layer: layer │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.WMTSGetFeatureInfo" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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.gratLayer = new OpenLayers.Layer.Vector(this.layerName, { │ │ │ │ + styleMap: new OpenLayers.StyleMap({ │ │ │ │ + 'default': gratStyle │ │ │ │ + }), │ │ │ │ + visibility: this.visible, │ │ │ │ + displayInLayerSwitcher: this.displayInLayerSwitcher │ │ │ │ }); │ │ │ │ - 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/Control/Split.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/Path.js │ │ │ │ - * @requires OpenLayers/Layer/Vector.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.Split │ │ │ │ - * Acts as a split feature agent while editing vector features. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.Split = 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>): │ │ │ │ - * beforesplit - Triggered before a split occurs. Listeners receive an │ │ │ │ - * event object with *source* and *target* properties. │ │ │ │ - * split - Triggered when a split occurs. Listeners receive an event with │ │ │ │ - * an *original* property and a *features* property. The original │ │ │ │ - * is a reference to the target feature that the sketch or modified │ │ │ │ - * feature intersects. The features property is a list of all features │ │ │ │ - * that result from this single split. This event is triggered before │ │ │ │ - * the resulting features are added to the layer (while the layer still │ │ │ │ - * has a reference to the original). │ │ │ │ - * aftersplit - Triggered after all splits resulting from a single sketch │ │ │ │ - * or feature modification have occurred. The original features │ │ │ │ - * have been destroyed and features that result from the split │ │ │ │ - * have already been added to the layer. Listeners receive an event │ │ │ │ - * with a *source* and *features* property. The source references the │ │ │ │ - * sketch or modified feature used as a splitter. The features │ │ │ │ - * property is a list of all resulting features. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: layer │ │ │ │ - * {<OpenLayers.Layer.Vector>} The target layer with features to be split. │ │ │ │ - * Set at construction or after construction with <setLayer>. │ │ │ │ - */ │ │ │ │ - layer: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: source │ │ │ │ - * {<OpenLayers.Layer.Vector>} Optional source layer. Any newly created │ │ │ │ - * or modified features from this layer will be used to split features │ │ │ │ - * on the target layer. If not provided, a temporary sketch layer will │ │ │ │ - * be created. │ │ │ │ - */ │ │ │ │ - source: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: sourceOptions │ │ │ │ - * {Options} If a temporary sketch layer is created, these layer options │ │ │ │ - * will be applied. │ │ │ │ - */ │ │ │ │ - sourceOptions: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: tolerance │ │ │ │ - * {Number} Distance between the calculated intersection and a vertex on │ │ │ │ - * the source geometry below which the existing vertex will be used │ │ │ │ - * for the split. Default is null. │ │ │ │ - */ │ │ │ │ - tolerance: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: edge │ │ │ │ - * {Boolean} Allow splits given intersection of edges only. Default is │ │ │ │ - * true. If false, a vertex on the source must be within the │ │ │ │ - * <tolerance> distance of the calculated intersection for a split │ │ │ │ - * to occur. │ │ │ │ - */ │ │ │ │ - edge: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: deferDelete │ │ │ │ - * {Boolean} Instead of removing features from the layer, set feature │ │ │ │ - * states of split features to DELETE. This assumes a save strategy │ │ │ │ - * or other component is in charge of removing features from the │ │ │ │ - * layer. Default is false. If false, split features will be │ │ │ │ - * immediately deleted from the layer. │ │ │ │ - */ │ │ │ │ - deferDelete: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: mutual │ │ │ │ - * {Boolean} If source and target layers are the same, split source │ │ │ │ - * features and target features where they intersect. Default is │ │ │ │ - * true. If false, only target features will be split. │ │ │ │ - */ │ │ │ │ - mutual: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: targetFilter │ │ │ │ - * {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ - * to determine if a feature from the target layer is eligible for │ │ │ │ - * splitting. │ │ │ │ - */ │ │ │ │ - targetFilter: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: sourceFilter │ │ │ │ - * {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ - * to determine if a feature from the source layer is eligible for │ │ │ │ - * splitting. │ │ │ │ - */ │ │ │ │ - sourceFilter: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: handler │ │ │ │ - * {<OpenLayers.Handler.Path>} The temporary sketch handler created if │ │ │ │ - * no source layer is provided. │ │ │ │ - */ │ │ │ │ - handler: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.Split │ │ │ │ - * Creates a new split control. A control is constructed with a target │ │ │ │ - * layer and an optional source layer. While the control is active, │ │ │ │ - * creating new features or modifying existing features on the source │ │ │ │ - * layer will result in splitting any eligible features on the target │ │ │ │ - * layer. If no source layer is provided, a temporary sketch layer will │ │ │ │ - * be created to create lines for splitting features on the target. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An object containing all configuration properties for │ │ │ │ - * the control. │ │ │ │ - * │ │ │ │ - * Valid options: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} The target layer. Features from this │ │ │ │ - * layer will be split by new or modified features on the source layer │ │ │ │ - * or temporary sketch layer. │ │ │ │ - * source - {<OpenLayers.Layer.Vector>} Optional source layer. If provided │ │ │ │ - * newly created features or modified features will be used to split │ │ │ │ - * features on the target layer. If not provided, a temporary sketch │ │ │ │ - * layer will be created for drawing lines. │ │ │ │ - * tolerance - {Number} Optional value for the distance between a source │ │ │ │ - * vertex and the calculated intersection below which the split will │ │ │ │ - * occur at the vertex. │ │ │ │ - * edge - {Boolean} Allow splits given intersection of edges only. Default │ │ │ │ - * is true. If false, a vertex on the source must be within the │ │ │ │ - * <tolerance> distance of the calculated intersection for a split │ │ │ │ - * to occur. │ │ │ │ - * mutual - {Boolean} If source and target are the same, split source │ │ │ │ - * features and target features where they intersect. Default is │ │ │ │ - * true. If false, only target features will be split. │ │ │ │ - * targetFilter - {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ - * to determine if a feature from the target layer is eligible for │ │ │ │ - * splitting. │ │ │ │ - * sourceFilter - {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ - * to determine if a feature from the target layer is eligible for │ │ │ │ - * splitting. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.options = options || {}; // TODO: this could be done by the super │ │ │ │ - │ │ │ │ - // set the source layer if provided │ │ │ │ - if (this.options.source) { │ │ │ │ - this.setSource(this.options.source); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: setSource │ │ │ │ - * Set the source layer for edits layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.Vector>} The new source layer layer. If │ │ │ │ - * null, a temporary sketch layer will be created. │ │ │ │ - */ │ │ │ │ - setSource: function(layer) { │ │ │ │ - if (this.active) { │ │ │ │ - this.deactivate(); │ │ │ │ - if (this.handler) { │ │ │ │ - this.handler.destroy(); │ │ │ │ - delete this.handler; │ │ │ │ - } │ │ │ │ - this.source = layer; │ │ │ │ - this.activate(); │ │ │ │ - } else { │ │ │ │ - this.source = layer; │ │ │ │ } │ │ │ │ + return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: activate │ │ │ │ - * Activate the control. Activating the control registers listeners for │ │ │ │ - * editing related events so that during feature creation and │ │ │ │ - * modification, features in the target will be considered for │ │ │ │ - * splitting. │ │ │ │ */ │ │ │ │ activate: function() { │ │ │ │ - var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - if (!this.source) { │ │ │ │ - if (!this.handler) { │ │ │ │ - this.handler = new OpenLayers.Handler.Path(this, { │ │ │ │ - done: function(geometry) { │ │ │ │ - this.onSketchComplete({ │ │ │ │ - feature: new OpenLayers.Feature.Vector(geometry) │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - }, { │ │ │ │ - layerOptions: this.sourceOptions │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - this.handler.activate(); │ │ │ │ - } else if (this.source.events) { │ │ │ │ - this.source.events.on({ │ │ │ │ - sketchcomplete: this.onSketchComplete, │ │ │ │ - afterfeaturemodified: this.afterFeatureModified, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ + if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.map.addLayer(this.gratLayer); │ │ │ │ + this.map.events.register('moveend', this, this.update); │ │ │ │ + this.update(); │ │ │ │ + return true; │ │ │ │ + } else { │ │ │ │ + return false; │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: deactivate │ │ │ │ - * Deactivate the control. Deactivating the control unregisters listeners │ │ │ │ - * so feature editing may proceed without engaging the split agent. │ │ │ │ */ │ │ │ │ deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - if (this.source && this.source.events) { │ │ │ │ - this.source.events.un({ │ │ │ │ - sketchcomplete: this.onSketchComplete, │ │ │ │ - afterfeaturemodified: this.afterFeatureModified, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return deactivated; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: onSketchComplete │ │ │ │ - * Registered as a listener for the sketchcomplete event on the editable │ │ │ │ - * layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * event - {Object} The sketch complete event. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Stop the sketch from being added to the layer (it has been │ │ │ │ - * split). │ │ │ │ - */ │ │ │ │ - onSketchComplete: function(event) { │ │ │ │ - this.feature = null; │ │ │ │ - return !this.considerSplit(event.feature); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: afterFeatureModified │ │ │ │ - * Registered as a listener for the afterfeaturemodified event on the │ │ │ │ - * editable layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * event - {Object} The after feature modified event. │ │ │ │ - */ │ │ │ │ - afterFeatureModified: function(event) { │ │ │ │ - if (event.modified) { │ │ │ │ - var feature = event.feature; │ │ │ │ - if (typeof feature.geometry.split === "function") { │ │ │ │ - this.feature = event.feature; │ │ │ │ - this.considerSplit(event.feature); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: removeByGeometry │ │ │ │ - * Remove a feature from a list based on the given geometry. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} A list of features. │ │ │ │ - * geometry - {<OpenLayers.Geometry>} A geometry. │ │ │ │ - */ │ │ │ │ - removeByGeometry: function(features, geometry) { │ │ │ │ - for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ - if (features[i].geometry === geometry) { │ │ │ │ - features.splice(i, 1); │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: isEligible │ │ │ │ - * Test if a target feature is eligible for splitting. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * target - {<OpenLayers.Feature.Vector>} The target feature. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The target is eligible for splitting. │ │ │ │ - */ │ │ │ │ - isEligible: function(target) { │ │ │ │ - if (!target.geometry) { │ │ │ │ - return false; │ │ │ │ + if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + this.map.events.unregister('moveend', this, this.update); │ │ │ │ + this.map.removeLayer(this.gratLayer); │ │ │ │ + return true; │ │ │ │ } else { │ │ │ │ - return ( │ │ │ │ - target.state !== OpenLayers.State.DELETE │ │ │ │ - ) && ( │ │ │ │ - typeof target.geometry.split === "function" │ │ │ │ - ) && ( │ │ │ │ - this.feature !== target │ │ │ │ - ) && ( │ │ │ │ - !this.targetFilter || │ │ │ │ - this.targetFilter.evaluate(target.attributes) │ │ │ │ - ); │ │ │ │ + return false; │ │ │ │ } │ │ │ │ }, │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: considerSplit │ │ │ │ - * Decide whether or not to split target features with the supplied │ │ │ │ - * feature. If <mutual> is true, both the source and target features │ │ │ │ - * will be split if eligible. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The newly created or modified │ │ │ │ - * feature. │ │ │ │ + * Method: update │ │ │ │ * │ │ │ │ + * calculates the grid to be displayed and actually draws it │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} The supplied feature was split (and destroyed). │ │ │ │ - */ │ │ │ │ - considerSplit: function(feature) { │ │ │ │ - var sourceSplit = false; │ │ │ │ - var targetSplit = false; │ │ │ │ - if (!this.sourceFilter || │ │ │ │ - this.sourceFilter.evaluate(feature.attributes)) { │ │ │ │ - var features = this.layer && this.layer.features || []; │ │ │ │ - var target, results, proceed; │ │ │ │ - var additions = [], │ │ │ │ - removals = []; │ │ │ │ - var mutual = (this.layer === this.source) && this.mutual; │ │ │ │ - var options = { │ │ │ │ - edge: this.edge, │ │ │ │ - tolerance: this.tolerance, │ │ │ │ - mutual: mutual │ │ │ │ - }; │ │ │ │ - var sourceParts = [feature.geometry]; │ │ │ │ - var targetFeature, targetParts; │ │ │ │ - var source, parts; │ │ │ │ - for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ - targetFeature = features[i]; │ │ │ │ - if (this.isEligible(targetFeature)) { │ │ │ │ - targetParts = [targetFeature.geometry]; │ │ │ │ - // work through source geoms - this array may change │ │ │ │ - for (var j = 0; j < sourceParts.length; ++j) { │ │ │ │ - source = sourceParts[j]; │ │ │ │ - // work through target parts - this array may change │ │ │ │ - for (var k = 0; k < targetParts.length; ++k) { │ │ │ │ - target = targetParts[k]; │ │ │ │ - if (source.getBounds().intersectsBounds(target.getBounds())) { │ │ │ │ - results = source.split(target, options); │ │ │ │ - if (results) { │ │ │ │ - proceed = this.events.triggerEvent( │ │ │ │ - "beforesplit", { │ │ │ │ - source: feature, │ │ │ │ - target: targetFeature │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - if (proceed !== false) { │ │ │ │ - if (mutual) { │ │ │ │ - parts = results[0]; │ │ │ │ - // handle parts that result from source splitting │ │ │ │ - if (parts.length > 1) { │ │ │ │ - // splice in new source parts │ │ │ │ - parts.unshift(j, 1); // add args for splice below │ │ │ │ - Array.prototype.splice.apply(sourceParts, parts); │ │ │ │ - j += parts.length - 3; │ │ │ │ - } │ │ │ │ - results = results[1]; │ │ │ │ - } │ │ │ │ - // handle parts that result from target splitting │ │ │ │ - if (results.length > 1) { │ │ │ │ - // splice in new target parts │ │ │ │ - results.unshift(k, 1); // add args for splice below │ │ │ │ - Array.prototype.splice.apply(targetParts, results); │ │ │ │ - k += results.length - 3; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (targetParts && targetParts.length > 1) { │ │ │ │ - this.geomsToFeatures(targetFeature, targetParts); │ │ │ │ - this.events.triggerEvent("split", { │ │ │ │ - original: targetFeature, │ │ │ │ - features: targetParts │ │ │ │ - }); │ │ │ │ - Array.prototype.push.apply(additions, targetParts); │ │ │ │ - removals.push(targetFeature); │ │ │ │ - targetSplit = true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (sourceParts && sourceParts.length > 1) { │ │ │ │ - this.geomsToFeatures(feature, sourceParts); │ │ │ │ - this.events.triggerEvent("split", { │ │ │ │ - original: feature, │ │ │ │ - features: sourceParts │ │ │ │ - }); │ │ │ │ - Array.prototype.push.apply(additions, sourceParts); │ │ │ │ - removals.push(feature); │ │ │ │ - sourceSplit = true; │ │ │ │ - } │ │ │ │ - if (sourceSplit || targetSplit) { │ │ │ │ - // remove and add feature events are suppressed │ │ │ │ - // listen for split event on this control instead │ │ │ │ - if (this.deferDelete) { │ │ │ │ - // Set state instead of removing. Take care to avoid │ │ │ │ - // setting delete for features that have not yet been │ │ │ │ - // inserted - those should be destroyed immediately. │ │ │ │ - var feat, destroys = []; │ │ │ │ - for (var i = 0, len = removals.length; i < len; ++i) { │ │ │ │ - feat = removals[i]; │ │ │ │ - if (feat.state === OpenLayers.State.INSERT) { │ │ │ │ - destroys.push(feat); │ │ │ │ - } else { │ │ │ │ - feat.state = OpenLayers.State.DELETE; │ │ │ │ - this.layer.drawFeature(feat); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.layer.destroyFeatures(destroys, { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ - for (var i = 0, len = additions.length; i < len; ++i) { │ │ │ │ - additions[i].state = OpenLayers.State.INSERT; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.layer.destroyFeatures(removals, { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - this.layer.addFeatures(additions, { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ - this.events.triggerEvent("aftersplit", { │ │ │ │ - source: feature, │ │ │ │ - features: additions │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return sourceSplit; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: geomsToFeatures │ │ │ │ - * Create new features given a template feature and a list of geometries. │ │ │ │ - * The list of geometries is modified in place. The result will be │ │ │ │ - * a list of new features. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} The feature to be cloned. │ │ │ │ - * geoms - {Array(<OpenLayers.Geometry>)} List of goemetries. This will │ │ │ │ - * become a list of new features. │ │ │ │ - */ │ │ │ │ - geomsToFeatures: function(feature, geoms) { │ │ │ │ - var clone = feature.clone(); │ │ │ │ - delete clone.geometry; │ │ │ │ - var newFeature; │ │ │ │ - for (var i = 0, len = geoms.length; i < len; ++i) { │ │ │ │ - // turn results list from geoms to features │ │ │ │ - newFeature = clone.clone(); │ │ │ │ - newFeature.geometry = geoms[i]; │ │ │ │ - newFeature.state = OpenLayers.State.INSERT; │ │ │ │ - geoms[i] = newFeature; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: destroy │ │ │ │ - * Clean up the control. │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - if (this.active) { │ │ │ │ - this.deactivate(); // TODO: this should be handled by the super │ │ │ │ + update: function() { │ │ │ │ + //wait for the map to be initialized before proceeding │ │ │ │ + var mapBounds = this.map.getExtent(); │ │ │ │ + if (!mapBounds) { │ │ │ │ + return; │ │ │ │ } │ │ │ │ - OpenLayers.Control.prototype.destroy.call(this); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Split" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Control/KeyboardDefaults.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/Keyboard.js │ │ │ │ - * @requires OpenLayers/Events.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Control.KeyboardDefaults │ │ │ │ - * The KeyboardDefaults control adds panning and zooming functions, controlled │ │ │ │ - * with the keyboard. By default arrow keys pan, +/- keys zoom & Page Up/Page │ │ │ │ - * Down/Home/End scroll by three quarters of a page. │ │ │ │ - * │ │ │ │ - * This control has no visible appearance. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Control> │ │ │ │ - */ │ │ │ │ -OpenLayers.Control.KeyboardDefaults = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ - */ │ │ │ │ - autoActivate: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: slideFactor │ │ │ │ - * Pixels to slide by. │ │ │ │ - */ │ │ │ │ - slideFactor: 75, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: observeElement │ │ │ │ - * {DOMelement|String} The DOM element to handle keys for. You │ │ │ │ - * can use the map div here, to have the navigation keys │ │ │ │ - * work when the map div has the focus. If undefined the │ │ │ │ - * document is used. │ │ │ │ - */ │ │ │ │ - observeElement: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Control.KeyboardDefaults │ │ │ │ - */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * Create handler. │ │ │ │ - */ │ │ │ │ - draw: function() { │ │ │ │ - var observeElement = this.observeElement || document; │ │ │ │ - this.handler = new OpenLayers.Handler.Keyboard(this, { │ │ │ │ - "keydown": this.defaultKeyPress │ │ │ │ - }, { │ │ │ │ - observeElement: observeElement │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ + //clear out the old grid │ │ │ │ + this.gratLayer.destroyFeatures(); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: defaultKeyPress │ │ │ │ - * When handling the key event, we only use evt.keyCode. This holds │ │ │ │ - * some drawbacks, though we get around them below. When interpretting │ │ │ │ - * the keycodes below (including the comments associated with them), │ │ │ │ - * consult the URL below. For instance, the Safari browser returns │ │ │ │ - * "IE keycodes", and so is supported by any keycode labeled "IE". │ │ │ │ - * │ │ │ │ - * Very informative URL: │ │ │ │ - * http://unixpapa.com/js/key.html │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - */ │ │ │ │ - defaultKeyPress: function(evt) { │ │ │ │ - var size, handled = true; │ │ │ │ + //get the projection objects required │ │ │ │ + var llProj = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ + var mapProj = this.map.getProjectionObject(); │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ │ │ │ │ - var target = OpenLayers.Event.element(evt); │ │ │ │ - if (target && │ │ │ │ - (target.tagName == 'INPUT' || │ │ │ │ - target.tagName == 'TEXTAREA' || │ │ │ │ - target.tagName == 'SELECT')) { │ │ │ │ - return; │ │ │ │ + //if the map is in lon/lat, then the lines are straight and only one │ │ │ │ + //point is required │ │ │ │ + if (mapProj.proj && mapProj.proj.projName == "longlat") { │ │ │ │ + this.numPoints = 1; │ │ │ │ } │ │ │ │ │ │ │ │ - switch (evt.keyCode) { │ │ │ │ - case OpenLayers.Event.KEY_LEFT: │ │ │ │ - this.map.pan(-this.slideFactor, 0); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Event.KEY_RIGHT: │ │ │ │ - this.map.pan(this.slideFactor, 0); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Event.KEY_UP: │ │ │ │ - this.map.pan(0, -this.slideFactor); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Event.KEY_DOWN: │ │ │ │ - this.map.pan(0, this.slideFactor); │ │ │ │ + //get the map center in EPSG:4326 │ │ │ │ + var mapCenter = this.map.getCenter(); //lon and lat here are really map x and y │ │ │ │ + var mapCenterLL = new OpenLayers.Pixel(mapCenter.lon, mapCenter.lat); │ │ │ │ + OpenLayers.Projection.transform(mapCenterLL, mapProj, llProj); │ │ │ │ + │ │ │ │ + /* This block of code determines the lon/lat interval to use for the │ │ │ │ + * grid by calculating the diagonal size of one grid cell at the map │ │ │ │ + * center. Iterates through the intervals array until the diagonal │ │ │ │ + * length is less than the targetSize option. │ │ │ │ + */ │ │ │ │ + //find lat/lon interval that results in a grid of less than the target size │ │ │ │ + var testSq = this.targetSize * mapRes; │ │ │ │ + testSq *= testSq; //compare squares rather than doing a square root to save time │ │ │ │ + var llInterval; │ │ │ │ + for (var i = 0; i < this.intervals.length; ++i) { │ │ │ │ + llInterval = this.intervals[i]; //could do this for both x and y?? │ │ │ │ + var delta = llInterval / 2; │ │ │ │ + var p1 = mapCenterLL.offset({ │ │ │ │ + x: -delta, │ │ │ │ + y: -delta │ │ │ │ + }); //test coords in EPSG:4326 space │ │ │ │ + var p2 = mapCenterLL.offset({ │ │ │ │ + x: delta, │ │ │ │ + y: delta │ │ │ │ + }); │ │ │ │ + OpenLayers.Projection.transform(p1, llProj, mapProj); // convert them back to map projection │ │ │ │ + OpenLayers.Projection.transform(p2, llProj, mapProj); │ │ │ │ + var distSq = (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y); │ │ │ │ + if (distSq <= testSq) { │ │ │ │ break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + //alert(llInterval); │ │ │ │ │ │ │ │ - case 33: // Page Up. Same in all browsers. │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(0, -0.75 * size.h); │ │ │ │ - break; │ │ │ │ - case 34: // Page Down. Same in all browsers. │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(0, 0.75 * size.h); │ │ │ │ - break; │ │ │ │ - case 35: // End. Same in all browsers. │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(0.75 * size.w, 0); │ │ │ │ - break; │ │ │ │ - case 36: // Home. Same in all browsers. │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(-0.75 * size.w, 0); │ │ │ │ - break; │ │ │ │ + //round the LL center to an even number based on the interval │ │ │ │ + mapCenterLL.x = Math.floor(mapCenterLL.x / llInterval) * llInterval; │ │ │ │ + mapCenterLL.y = Math.floor(mapCenterLL.y / llInterval) * llInterval; │ │ │ │ + //TODO adjust for minutses/seconds? │ │ │ │ │ │ │ │ - case 43: // +/= (ASCII), keypad + (ASCII, Opera) │ │ │ │ - case 61: // +/= (Mozilla, Opera, some ASCII) │ │ │ │ - case 187: // +/= (IE) │ │ │ │ - case 107: // keypad + (IE, Mozilla) │ │ │ │ - this.map.zoomIn(); │ │ │ │ - break; │ │ │ │ - case 45: // -/_ (ASCII, Opera), keypad - (ASCII, Opera) │ │ │ │ - case 109: // -/_ (Mozilla), keypad - (Mozilla, IE) │ │ │ │ - case 189: // -/_ (IE) │ │ │ │ - case 95: // -/_ (some ASCII) │ │ │ │ - this.map.zoomOut(); │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - handled = false; │ │ │ │ + /* The following 2 blocks calculate the nodes of the grid along a │ │ │ │ + * line of constant longitude (then latitiude) running through the │ │ │ │ + * center of the map until it reaches the map edge. The calculation │ │ │ │ + * goes from the center in both directions to the edge. │ │ │ │ + */ │ │ │ │ + //get the central longitude line, increment the latitude │ │ │ │ + var iter = 0; │ │ │ │ + var centerLonPoints = [mapCenterLL.clone()]; │ │ │ │ + var newPoint = mapCenterLL.clone(); │ │ │ │ + var mapXY; │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: 0, │ │ │ │ + y: llInterval │ │ │ │ + }); │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLonPoints.unshift(newPoint); │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ + newPoint = mapCenterLL.clone(); │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: 0, │ │ │ │ + y: -llInterval │ │ │ │ + }); │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLonPoints.push(newPoint); │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ + │ │ │ │ + //get the central latitude line, increment the longitude │ │ │ │ + iter = 0; │ │ │ │ + var centerLatPoints = [mapCenterLL.clone()]; │ │ │ │ + newPoint = mapCenterLL.clone(); │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: -llInterval, │ │ │ │ + y: 0 │ │ │ │ + }); │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLatPoints.unshift(newPoint); │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ + newPoint = mapCenterLL.clone(); │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: llInterval, │ │ │ │ + y: 0 │ │ │ │ + }); │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLatPoints.push(newPoint); │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1000); │ │ │ │ + │ │ │ │ + //now generate a line for each node in the central lat and lon lines │ │ │ │ + //first loop over constant longitude │ │ │ │ + var lines = []; │ │ │ │ + for (var i = 0; i < centerLatPoints.length; ++i) { │ │ │ │ + var lon = centerLatPoints[i].x; │ │ │ │ + var pointList = []; │ │ │ │ + var labelPoint = null; │ │ │ │ + var latEnd = Math.min(centerLonPoints[0].y, 90); │ │ │ │ + var latStart = Math.max(centerLonPoints[centerLonPoints.length - 1].y, -90); │ │ │ │ + var latDelta = (latEnd - latStart) / this.numPoints; │ │ │ │ + var lat = latStart; │ │ │ │ + for (var j = 0; j <= this.numPoints; ++j) { │ │ │ │ + var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ + gridPoint.transform(llProj, mapProj); │ │ │ │ + pointList.push(gridPoint); │ │ │ │ + lat += latDelta; │ │ │ │ + if (gridPoint.y >= mapBounds.bottom && !labelPoint) { │ │ │ │ + labelPoint = gridPoint; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.labelled) { │ │ │ │ + //keep track of when this grid line crosses the map bounds to set │ │ │ │ + //the label position │ │ │ │ + //labels along the bottom, add 10 pixel offset up into the map │ │ │ │ + //TODO add option for labels on top │ │ │ │ + var labelPos = new OpenLayers.Geometry.Point(labelPoint.x, mapBounds.bottom); │ │ │ │ + var labelAttrs = { │ │ │ │ + value: lon, │ │ │ │ + label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lon, "lon", this.labelFormat) : "", │ │ │ │ + labelAlign: "cb", │ │ │ │ + xOffset: 0, │ │ │ │ + yOffset: 2 │ │ │ │ + }; │ │ │ │ + this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)); │ │ │ │ + } │ │ │ │ + var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ + lines.push(new OpenLayers.Feature.Vector(geom)); │ │ │ │ } │ │ │ │ - if (handled) { │ │ │ │ - // prevent browser default not to move the page │ │ │ │ - // when moving the page with the keyboard │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ + │ │ │ │ + //now draw the lines of constant latitude │ │ │ │ + for (var j = 0; j < centerLonPoints.length; ++j) { │ │ │ │ + lat = centerLonPoints[j].y; │ │ │ │ + if (lat < -90 || lat > 90) { //latitudes only valid between -90 and 90 │ │ │ │ + continue; │ │ │ │ + } │ │ │ │ + var pointList = []; │ │ │ │ + var lonStart = centerLatPoints[0].x; │ │ │ │ + var lonEnd = centerLatPoints[centerLatPoints.length - 1].x; │ │ │ │ + var lonDelta = (lonEnd - lonStart) / this.numPoints; │ │ │ │ + var lon = lonStart; │ │ │ │ + var labelPoint = null; │ │ │ │ + for (var i = 0; i <= this.numPoints; ++i) { │ │ │ │ + var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ + gridPoint.transform(llProj, mapProj); │ │ │ │ + pointList.push(gridPoint); │ │ │ │ + lon += lonDelta; │ │ │ │ + if (gridPoint.x < mapBounds.right) { │ │ │ │ + labelPoint = gridPoint; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.labelled) { │ │ │ │ + //keep track of when this grid line crosses the map bounds to set │ │ │ │ + //the label position │ │ │ │ + //labels along the right, 30 pixel offset left into the map │ │ │ │ + //TODO add option for labels on left │ │ │ │ + var labelPos = new OpenLayers.Geometry.Point(mapBounds.right, labelPoint.y); │ │ │ │ + var labelAttrs = { │ │ │ │ + value: lat, │ │ │ │ + label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lat, "lat", this.labelFormat) : "", │ │ │ │ + labelAlign: "rb", │ │ │ │ + xOffset: -2, │ │ │ │ + yOffset: 2 │ │ │ │ + }; │ │ │ │ + this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)); │ │ │ │ + } │ │ │ │ + var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ + lines.push(new OpenLayers.Feature.Vector(geom)); │ │ │ │ } │ │ │ │ + this.gratLayer.addFeatures(lines); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.KeyboardDefaults" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Graticule" │ │ │ │ }); │ │ │ │ + │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/SelectFeature.js │ │ │ │ + OpenLayers/Control/Snapping.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 │ │ │ │ + * @requires OpenLayers/Layer/Vector.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Control.SelectFeature │ │ │ │ - * The SelectFeature control selects vector features from a given layer on │ │ │ │ - * click or hover. │ │ │ │ + * Class: OpenLayers.Control.Snapping │ │ │ │ + * Acts as a snapping agent while editing vector features. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Control.Snapping = 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. │ │ │ │ + * beforesnap - Triggered before a snap occurs. Listeners receive an │ │ │ │ + * event object with *point*, *x*, *y*, *distance*, *layer*, and │ │ │ │ + * *snapType* properties. The point property will be original point │ │ │ │ + * geometry considered for snapping. The x and y properties represent │ │ │ │ + * coordinates the point will receive. The distance is the distance │ │ │ │ + * of the snap. The layer is the target layer. The snapType property │ │ │ │ + * will be one of "node", "vertex", or "edge". Return false to stop │ │ │ │ + * snapping from occurring. │ │ │ │ + * snap - Triggered when a snap occurs. Listeners receive an event with │ │ │ │ + * *point*, *snapType*, *layer*, and *distance* properties. The point │ │ │ │ + * will be the location snapped to. The snapType will be one of "node", │ │ │ │ + * "vertex", or "edge". The layer will be the target layer. The │ │ │ │ + * distance will be the distance of the snap in map units. │ │ │ │ + * unsnap - Triggered when a vertex is unsnapped. Listeners receive an │ │ │ │ + * event with a *point* property. │ │ │ │ */ │ │ │ │ - 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. │ │ │ │ + * CONSTANT: DEFAULTS │ │ │ │ + * Default target properties. │ │ │ │ */ │ │ │ │ - onBeforeSelect: function() {}, │ │ │ │ + DEFAULTS: { │ │ │ │ + tolerance: 10, │ │ │ │ + node: true, │ │ │ │ + edge: true, │ │ │ │ + vertex: true │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: onSelect │ │ │ │ - * {Function} Optional function to be called when a feature is selected. │ │ │ │ - * The function should expect to be called with a feature. │ │ │ │ + * Property: greedy │ │ │ │ + * {Boolean} Snap to closest feature in first layer with an eligible │ │ │ │ + * feature. Default is true. │ │ │ │ */ │ │ │ │ - onSelect: function() {}, │ │ │ │ + greedy: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: onUnselect │ │ │ │ - * {Function} Optional function to be called when a feature is unselected. │ │ │ │ - * The function should expect to be called with a feature. │ │ │ │ + * Property: precedence │ │ │ │ + * {Array} List representing precedence of different snapping types. │ │ │ │ + * Default is "node", "vertex", "edge". │ │ │ │ */ │ │ │ │ - onUnselect: function() {}, │ │ │ │ + precedence: ["node", "vertex", "edge"], │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: scope │ │ │ │ - * {Object} The scope to use with the onBeforeSelect, onSelect, onUnselect │ │ │ │ - * callbacks. If null the scope will be this control. │ │ │ │ + * Property: resolution │ │ │ │ + * {Float} The map resolution for the previously considered snap. │ │ │ │ */ │ │ │ │ - scope: null, │ │ │ │ + resolution: 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. │ │ │ │ + * Property: geoToleranceCache │ │ │ │ + * {Object} A cache of geo-tolerances. Tolerance values (in map units) are │ │ │ │ + * calculated when the map resolution changes. │ │ │ │ */ │ │ │ │ - geometryTypes: null, │ │ │ │ + geoToleranceCache: 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). │ │ │ │ + * {<OpenLayers.Layer.Vector>} The current editable layer. Set at │ │ │ │ + * construction or after construction with <setLayer>. │ │ │ │ */ │ │ │ │ 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. │ │ │ │ + * Property: feature │ │ │ │ + * {<OpenLayers.Feature.Vector>} The current editable feature. │ │ │ │ */ │ │ │ │ - renderIntent: "select", │ │ │ │ + feature: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: handlers │ │ │ │ - * {Object} Object with references to multiple <OpenLayers.Handler> │ │ │ │ - * instances. │ │ │ │ + * Property: point │ │ │ │ + * {<OpenLayers.Geometry.Point>} The currently snapped vertex. │ │ │ │ */ │ │ │ │ - handlers: null, │ │ │ │ + point: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Control.SelectFeature │ │ │ │ - * Create a new control for selecting features. │ │ │ │ + * Constructor: OpenLayers.Control.Snapping │ │ │ │ + * Creates a new snapping control. A control is constructed with an editable │ │ │ │ + * layer and a set of configuration objects for target layers. While the │ │ │ │ + * control is active, dragging vertices while drawing new features or │ │ │ │ + * modifying existing features on the editable layer will engage │ │ │ │ + * snapping to features on the target layers. Whether a vertex snaps to │ │ │ │ + * a feature on a target layer depends on the target layer configuration. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * layers - {<OpenLayers.Layer.Vector>}, or an array of vector layers. The │ │ │ │ - * layer(s) this control will select features from. │ │ │ │ - * options - {Object} │ │ │ │ + * options - {Object} An object containing all configuration properties for │ │ │ │ + * the control. │ │ │ │ + * │ │ │ │ + * Valid options: │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} The editable layer. Features from this │ │ │ │ + * layer that are digitized or modified may have vertices snapped to │ │ │ │ + * features from any of the target layers. │ │ │ │ + * targets - {Array(Object | OpenLayers.Layer.Vector)} A list of objects for │ │ │ │ + * configuring target layers. See valid properties of the target │ │ │ │ + * objects below. If the items in the targets list are vector layers │ │ │ │ + * (instead of configuration objects), the defaults from the <defaults> │ │ │ │ + * property will apply. The editable layer itself may be a target │ │ │ │ + * layer, allowing newly created or edited features to be snapped to │ │ │ │ + * existing features from the same layer. If no targets are provided │ │ │ │ + * the layer given in the constructor (as <layer>) will become the │ │ │ │ + * initial target. │ │ │ │ + * defaults - {Object} An object with default properties to be applied │ │ │ │ + * to all target objects. │ │ │ │ + * greedy - {Boolean} Snap to closest feature in first target layer that │ │ │ │ + * applies. Default is true. If false, all features in all target │ │ │ │ + * layers will be checked and the closest feature in all target layers │ │ │ │ + * will be chosen. The greedy property determines if the order of the │ │ │ │ + * target layers is significant. By default, the order of the target │ │ │ │ + * layers is significant where layers earlier in the target layer list │ │ │ │ + * have precedence over layers later in the list. Within a single │ │ │ │ + * layer, the closest feature is always chosen for snapping. This │ │ │ │ + * property only determines whether the search for a closer feature │ │ │ │ + * continues after an eligible feature is found in a target layer. │ │ │ │ + * │ │ │ │ + * Valid target properties: │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} A target layer. Features from this │ │ │ │ + * layer will be eligible to act as snapping target for the editable │ │ │ │ + * layer. │ │ │ │ + * tolerance - {Float} The distance (in pixels) at which snapping may occur. │ │ │ │ + * Default is 10. │ │ │ │ + * node - {Boolean} Snap to nodes (first or last point in a geometry) in │ │ │ │ + * target layer. Default is true. │ │ │ │ + * nodeTolerance - {Float} Optional distance at which snapping may occur │ │ │ │ + * for nodes specifically. If none is provided, <tolerance> will be │ │ │ │ + * used. │ │ │ │ + * vertex - {Boolean} Snap to vertices in target layer. Default is true. │ │ │ │ + * vertexTolerance - {Float} Optional distance at which snapping may occur │ │ │ │ + * for vertices specifically. If none is provided, <tolerance> will be │ │ │ │ + * used. │ │ │ │ + * edge - {Boolean} Snap to edges in target layer. Default is true. │ │ │ │ + * edgeTolerance - {Float} Optional distance at which snapping may occur │ │ │ │ + * for edges specifically. If none is provided, <tolerance> will be │ │ │ │ + * used. │ │ │ │ + * filter - {<OpenLayers.Filter>} Optional filter to evaluate to determine if │ │ │ │ + * feature is eligible for snapping. If filter evaluates to true for a │ │ │ │ + * target feature a vertex may be snapped to the feature. │ │ │ │ + * minResolution - {Number} If a minResolution is provided, snapping to this │ │ │ │ + * target will only be considered if the map resolution is greater than │ │ │ │ + * or equal to this value (the minResolution is inclusive). Default is │ │ │ │ + * no minimum resolution limit. │ │ │ │ + * maxResolution - {Number} If a maxResolution is provided, snapping to this │ │ │ │ + * target will only be considered if the map resolution is strictly │ │ │ │ + * less than this value (the maxResolution is exclusive). Default is │ │ │ │ + * no maximum resolution limit. │ │ │ │ */ │ │ │ │ - initialize: function(layers, options) { │ │ │ │ + initialize: function(options) { │ │ │ │ OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.options = options || {}; // TODO: this could be done by the super │ │ │ │ │ │ │ │ - if (this.scope === null) { │ │ │ │ - this.scope = this; │ │ │ │ + // set the editable layer if provided │ │ │ │ + if (this.options.layer) { │ │ │ │ + this.setLayer(this.options.layer); │ │ │ │ } │ │ │ │ - this.initLayer(layers); │ │ │ │ - var callbacks = { │ │ │ │ - click: this.clickFeature, │ │ │ │ - clickout: this.clickoutFeature │ │ │ │ - }; │ │ │ │ - if (this.hover) { │ │ │ │ - callbacks.over = this.overFeature; │ │ │ │ - callbacks.out = this.outFeature; │ │ │ │ + // configure target layers │ │ │ │ + var defaults = OpenLayers.Util.extend({}, this.options.defaults); │ │ │ │ + this.defaults = OpenLayers.Util.applyDefaults(defaults, this.DEFAULTS); │ │ │ │ + this.setTargets(this.options.targets); │ │ │ │ + if (this.targets.length === 0 && this.layer) { │ │ │ │ + this.addTargetLayer(this.layer); │ │ │ │ } │ │ │ │ │ │ │ │ - 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" │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + this.geoToleranceCache = {}; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: initLayer │ │ │ │ - * Assign the layer property. If layers is an array, we need to use │ │ │ │ - * a RootContainer. │ │ │ │ + * APIMethod: setLayer │ │ │ │ + * Set the editable layer. Call the setLayer method if the editable layer │ │ │ │ + * changes and the same control should be used on a new editable layer. │ │ │ │ + * If the control is already active, it will be active after the new │ │ │ │ + * layer is set. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * layers - {<OpenLayers.Layer.Vector>}, or an array of vector layers. │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} The new editable layer. │ │ │ │ */ │ │ │ │ - initLayer: function(layers) { │ │ │ │ - if (OpenLayers.Util.isArray(layers)) { │ │ │ │ - this.layers = layers; │ │ │ │ - this.layer = new OpenLayers.Layer.Vector.RootContainer( │ │ │ │ - this.id + "_container", { │ │ │ │ - layers: layers │ │ │ │ - } │ │ │ │ - ); │ │ │ │ + setLayer: function(layer) { │ │ │ │ + if (this.active) { │ │ │ │ + this.deactivate(); │ │ │ │ + this.layer = layer; │ │ │ │ + this.activate(); │ │ │ │ } 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(); │ │ │ │ + this.layer = layer; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: activate │ │ │ │ - * Activates the control. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The control was effectively activated. │ │ │ │ + * Method: setTargets │ │ │ │ + * Set the targets for the snapping agent. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * targets - {Array} An array of target configs or target layers. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ + setTargets: function(targets) { │ │ │ │ + this.targets = []; │ │ │ │ + if (targets && targets.length) { │ │ │ │ + var target; │ │ │ │ + for (var i = 0, len = targets.length; i < len; ++i) { │ │ │ │ + target = targets[i]; │ │ │ │ + if (target instanceof OpenLayers.Layer.Vector) { │ │ │ │ + this.addTargetLayer(target); │ │ │ │ + } else { │ │ │ │ + this.addTarget(target); │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ - return OpenLayers.Control.prototype.activate.apply( │ │ │ │ - this, arguments │ │ │ │ - ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Deactivates the control. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The control was effectively deactivated. │ │ │ │ + * Method: addTargetLayer │ │ │ │ + * Add a target layer with the default target config. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} A target layer. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - ); │ │ │ │ + addTargetLayer: function(layer) { │ │ │ │ + this.addTarget({ │ │ │ │ + layer: layer │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: unselectAll │ │ │ │ - * Unselect all selected features. To unselect all except for a single │ │ │ │ - * feature, set the options.except property to the feature. │ │ │ │ + * Method: addTarget │ │ │ │ + * Add a configured target layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional configuration object. │ │ │ │ + * target - {Object} A target config. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + addTarget: function(target) { │ │ │ │ + target = OpenLayers.Util.applyDefaults(target, this.defaults); │ │ │ │ + target.nodeTolerance = target.nodeTolerance || target.tolerance; │ │ │ │ + target.vertexTolerance = target.vertexTolerance || target.tolerance; │ │ │ │ + target.edgeTolerance = target.edgeTolerance || target.tolerance; │ │ │ │ + this.targets.push(target); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clickFeature │ │ │ │ - * Called on click in a feature │ │ │ │ - * Only responds if this.hover is false. │ │ │ │ + * Method: removeTargetLayer │ │ │ │ + * Remove a target layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} The target layer to remove. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + removeTargetLayer: function(layer) { │ │ │ │ + var target; │ │ │ │ + for (var i = this.targets.length - 1; i >= 0; --i) { │ │ │ │ + target = this.targets[i]; │ │ │ │ + if (target.layer === layer) { │ │ │ │ + this.removeTarget(target); │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: multipleSelect │ │ │ │ - * Allow for multiple selected features based on <multiple> property and │ │ │ │ - * <multipleKey> event modifier. │ │ │ │ + * Method: removeTarget │ │ │ │ + * Remove a target. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Parameters: │ │ │ │ + * target - {Object} A target config. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} Toggle the selected state of a feature. │ │ │ │ + * {Array} The targets array. │ │ │ │ */ │ │ │ │ - toggleSelect: function() { │ │ │ │ - return this.toggle || (this.handlers.feature.evt && │ │ │ │ - this.handlers.feature.evt[this.toggleKey]); │ │ │ │ + removeTarget: function(target) { │ │ │ │ + return OpenLayers.Util.removeItem(this.targets, target); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clickoutFeature │ │ │ │ - * Called on click outside a previously clicked (selected) feature. │ │ │ │ - * Only responds if this.hover is false. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Vector.Feature>} │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the control. Activating the control registers listeners for │ │ │ │ + * editing related events so that during feature creation and │ │ │ │ + * modification, moving vertices will trigger snapping. │ │ │ │ */ │ │ │ │ - clickoutFeature: function(feature) { │ │ │ │ - if (!this.hover && this.clickout) { │ │ │ │ - this.unselectAll(); │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + if (this.layer && this.layer.events) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + sketchstarted: this.onSketchModified, │ │ │ │ + sketchmodified: this.onSketchModified, │ │ │ │ + vertexmodified: this.onVertexModified, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ } │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: overFeature │ │ │ │ - * Called on over a feature. │ │ │ │ - * Only responds if this.hover is true. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the control. Deactivating the control unregisters listeners │ │ │ │ + * so feature editing may proceed without engaging the snapping agent. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + if (this.layer && this.layer.events) { │ │ │ │ + this.layer.events.un({ │ │ │ │ + sketchstarted: this.onSketchModified, │ │ │ │ + sketchmodified: this.onSketchModified, │ │ │ │ + vertexmodified: this.onVertexModified, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ } │ │ │ │ } │ │ │ │ + this.feature = null; │ │ │ │ + this.point = null; │ │ │ │ + return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: outFeature │ │ │ │ - * Called on out of a selected feature. │ │ │ │ - * Only responds if this.hover is true. │ │ │ │ + * Method: onSketchModified │ │ │ │ + * Registered as a listener for the sketchmodified event on the editable │ │ │ │ + * layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * event - {Object} The sketch modified event. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + onSketchModified: function(event) { │ │ │ │ + this.feature = event.feature; │ │ │ │ + this.considerSnapping(event.vertex, event.vertex); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: highlight │ │ │ │ - * Redraw feature with the select style. │ │ │ │ + * Method: onVertexModified │ │ │ │ + * Registered as a listener for the vertexmodified event on the editable │ │ │ │ + * layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * event - {Object} The vertex modified event. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ - } │ │ │ │ + onVertexModified: function(event) { │ │ │ │ + this.feature = event.feature; │ │ │ │ + var loc = this.layer.map.getLonLatFromViewPortPx(event.pixel); │ │ │ │ + this.considerSnapping( │ │ │ │ + event.vertex, new OpenLayers.Geometry.Point(loc.lon, loc.lat) │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: unhighlight │ │ │ │ - * Redraw feature with the "default" style │ │ │ │ + * Method: considerSnapping │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} The vertex to be snapped (or │ │ │ │ + * unsnapped). │ │ │ │ + * loc - {<OpenLayers.Geometry.Point>} The location of the mouse in map │ │ │ │ + * coords. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + considerSnapping: function(point, loc) { │ │ │ │ + var best = { │ │ │ │ + rank: Number.POSITIVE_INFINITY, │ │ │ │ + dist: Number.POSITIVE_INFINITY, │ │ │ │ + x: null, │ │ │ │ + y: null │ │ │ │ + }; │ │ │ │ + var snapped = false; │ │ │ │ + var result, target; │ │ │ │ + for (var i = 0, len = this.targets.length; i < len; ++i) { │ │ │ │ + target = this.targets[i]; │ │ │ │ + result = this.testTarget(target, loc); │ │ │ │ + if (result) { │ │ │ │ + if (this.greedy) { │ │ │ │ + best = result; │ │ │ │ + best.target = target; │ │ │ │ + snapped = true; │ │ │ │ + break; │ │ │ │ + } else { │ │ │ │ + if ((result.rank < best.rank) || │ │ │ │ + (result.rank === best.rank && result.dist < best.dist)) { │ │ │ │ + best = result; │ │ │ │ + best.target = target; │ │ │ │ + snapped = true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - 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 (snapped) { │ │ │ │ + var proceed = this.events.triggerEvent("beforesnap", { │ │ │ │ + point: point, │ │ │ │ + x: best.x, │ │ │ │ + y: best.y, │ │ │ │ + distance: best.dist, │ │ │ │ + layer: best.target.layer, │ │ │ │ + snapType: this.precedence[best.rank] │ │ │ │ }); │ │ │ │ - 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 │ │ │ │ + if (proceed !== false) { │ │ │ │ + point.x = best.x; │ │ │ │ + point.y = best.y; │ │ │ │ + this.point = point; │ │ │ │ + this.events.triggerEvent("snap", { │ │ │ │ + point: point, │ │ │ │ + snapType: this.precedence[best.rank], │ │ │ │ + layer: best.target.layer, │ │ │ │ + distance: best.dist │ │ │ │ }); │ │ │ │ - this.onSelect.call(this.scope, feature); │ │ │ │ + } else { │ │ │ │ + snapped = false; │ │ │ │ } │ │ │ │ } │ │ │ │ + if (this.point && !snapped) { │ │ │ │ + point.x = loc.x; │ │ │ │ + point.y = loc.y; │ │ │ │ + this.point = null; │ │ │ │ + this.events.triggerEvent("unsnap", { │ │ │ │ + point: point │ │ │ │ + }); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: unselect │ │ │ │ - * Remove feature from the layer's selectedFeature array, render the feature as │ │ │ │ - * normal, and call the onUnselect function. │ │ │ │ + * Method: testTarget │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * target - {Object} Object with target layer configuration. │ │ │ │ + * loc - {<OpenLayers.Geometry.Point>} The location of the mouse in map │ │ │ │ + * coords. │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * position - {<OpenLayers.Bounds> || <OpenLayers.Pixel> } │ │ │ │ + * Returns: │ │ │ │ + * {Object} A result object with rank, dist, x, and y properties. │ │ │ │ + * Returns null if candidate is not eligible for snapping. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ + testTarget: function(target, loc) { │ │ │ │ + var resolution = this.layer.map.getResolution(); │ │ │ │ + if ("minResolution" in target) { │ │ │ │ + if (resolution < target.minResolution) { │ │ │ │ + return null; │ │ │ │ } │ │ │ │ - │ │ │ │ - // 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); │ │ │ │ + } │ │ │ │ + if ("maxResolution" in target) { │ │ │ │ + if (resolution >= target.maxResolution) { │ │ │ │ + return null; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var tolerance = { │ │ │ │ + node: this.getGeoTolerance(target.nodeTolerance, resolution), │ │ │ │ + vertex: this.getGeoTolerance(target.vertexTolerance, resolution), │ │ │ │ + edge: this.getGeoTolerance(target.edgeTolerance, resolution) │ │ │ │ + }; │ │ │ │ + // this could be cached if we don't support setting tolerance values directly │ │ │ │ + var maxTolerance = Math.max( │ │ │ │ + tolerance.node, tolerance.vertex, tolerance.edge │ │ │ │ + ); │ │ │ │ + var result = { │ │ │ │ + rank: Number.POSITIVE_INFINITY, │ │ │ │ + dist: Number.POSITIVE_INFINITY │ │ │ │ + }; │ │ │ │ + var eligible = false; │ │ │ │ + var features = target.layer.features; │ │ │ │ + var feature, type, vertices, vertex, closest, dist, found; │ │ │ │ + var numTypes = this.precedence.length; │ │ │ │ + var ll = new OpenLayers.LonLat(loc.x, loc.y); │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + if (feature !== this.feature && !feature._sketch && │ │ │ │ + feature.state !== OpenLayers.State.DELETE && │ │ │ │ + (!target.filter || target.filter.evaluate(feature))) { │ │ │ │ + if (feature.atPoint(ll, maxTolerance, maxTolerance)) { │ │ │ │ + for (var j = 0, stop = Math.min(result.rank + 1, numTypes); j < stop; ++j) { │ │ │ │ + type = this.precedence[j]; │ │ │ │ + if (target[type]) { │ │ │ │ + if (type === "edge") { │ │ │ │ + closest = feature.geometry.distanceTo(loc, { │ │ │ │ + details: true │ │ │ │ + }); │ │ │ │ + dist = closest.distance; │ │ │ │ + if (dist <= tolerance[type] && dist < result.dist) { │ │ │ │ + result = { │ │ │ │ + rank: j, │ │ │ │ + dist: dist, │ │ │ │ + x: closest.x0, │ │ │ │ + y: closest.y0 // closest coords on feature │ │ │ │ + }; │ │ │ │ + eligible = true; │ │ │ │ + // don't look for lower precedence types for this feature │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + // look for nodes or vertices │ │ │ │ + vertices = feature.geometry.getVertices(type === "node"); │ │ │ │ + found = false; │ │ │ │ + for (var k = 0, klen = vertices.length; k < klen; ++k) { │ │ │ │ + vertex = vertices[k]; │ │ │ │ + dist = vertex.distanceTo(loc); │ │ │ │ + if (dist <= tolerance[type] && │ │ │ │ + (j < result.rank || (j === result.rank && dist < result.dist))) { │ │ │ │ + result = { │ │ │ │ + rank: j, │ │ │ │ + dist: dist, │ │ │ │ + x: vertex.x, │ │ │ │ + y: vertex.y │ │ │ │ + }; │ │ │ │ + eligible = true; │ │ │ │ + found = true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (found) { │ │ │ │ + // don't look for lower precedence types for this feature │ │ │ │ + break; │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ - this.multiple = prevMultiple; │ │ │ │ - this.events.triggerEvent("boxselectionend", { │ │ │ │ - layers: layers │ │ │ │ - }); │ │ │ │ } │ │ │ │ + return eligible ? result : null; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setMap │ │ │ │ - * Set the map property for the control. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: getGeoTolerance │ │ │ │ + * Calculate a tolerance in map units given a tolerance in pixels. This │ │ │ │ + * takes advantage of the <geoToleranceCache> when the map resolution │ │ │ │ + * has not changed. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * map - {<OpenLayers.Map>} │ │ │ │ + * tolerance - {Number} A tolerance value in pixels. │ │ │ │ + * resolution - {Number} Map resolution. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Number} A tolerance value in map units. │ │ │ │ */ │ │ │ │ - setMap: function(map) { │ │ │ │ - this.handlers.feature.setMap(map); │ │ │ │ - if (this.box) { │ │ │ │ - this.handlers.box.setMap(map); │ │ │ │ + getGeoTolerance: function(tolerance, resolution) { │ │ │ │ + if (resolution !== this.resolution) { │ │ │ │ + this.resolution = resolution; │ │ │ │ + this.geoToleranceCache = {}; │ │ │ │ } │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + var geoTolerance = this.geoToleranceCache[tolerance]; │ │ │ │ + if (geoTolerance === undefined) { │ │ │ │ + geoTolerance = tolerance * resolution; │ │ │ │ + this.geoToleranceCache[tolerance] = geoTolerance; │ │ │ │ + } │ │ │ │ + return geoTolerance; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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>} │ │ │ │ + * Method: destroy │ │ │ │ + * Clean up the control. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ + destroy: function() { │ │ │ │ + if (this.active) { │ │ │ │ + this.deactivate(); // TODO: this should be handled by the super │ │ │ │ } │ │ │ │ + delete this.layer; │ │ │ │ + delete this.targets; │ │ │ │ + OpenLayers.Control.prototype.destroy.call(this); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control.SelectFeature" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Snapping" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Control/MousePosition.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ @@ -71683,4981 +77567,4475 @@ │ │ │ │ this.suffix; │ │ │ │ return newHtml; │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Control.MousePosition" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Control/TouchNavigation.js │ │ │ │ + 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/DragPan.js │ │ │ │ - * @requires OpenLayers/Control/PinchZoom.js │ │ │ │ - * @requires OpenLayers/Handler/Click.js │ │ │ │ + * @requires OpenLayers/Control.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. │ │ │ │ + * Class: OpenLayers.Control.Attribution │ │ │ │ + * The attribution control adds attribution from layers to the map display. │ │ │ │ + * It uses 'attribution' property of each layer. │ │ │ │ * │ │ │ │ - * Inherits: │ │ │ │ + * Inherits from: │ │ │ │ * - <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, │ │ │ │ +OpenLayers.Control.Attribution = │ │ │ │ + OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: documentDrag │ │ │ │ - * {Boolean} Allow panning of the map by dragging outside map viewport. │ │ │ │ - * Default is false. │ │ │ │ - */ │ │ │ │ - documentDrag: false, │ │ │ │ + /** │ │ │ │ + * APIProperty: separator │ │ │ │ + * {String} String used to separate layers. │ │ │ │ + */ │ │ │ │ + separator: ", ", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: autoActivate │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ - * true. │ │ │ │ - */ │ │ │ │ - autoActivate: true, │ │ │ │ + /** │ │ │ │ + * 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.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); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.Attribution │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} Options for control. │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: destroy │ │ │ │ + * Destroy control. │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + this.map.events.un({ │ │ │ │ + "removelayer": this.updateAttribution, │ │ │ │ + "addlayer": this.updateAttribution, │ │ │ │ + "changelayer": this.updateAttribution, │ │ │ │ + "changebaselayer": this.updateAttribution, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - }, │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 │ │ │ │ + * Initialize control. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A reference to the DIV DOMElement containing the control │ │ │ │ + */ │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ + this.map.events.on({ │ │ │ │ + 'changebaselayer': this.updateAttribution, │ │ │ │ + 'changelayer': this.updateAttribution, │ │ │ │ + 'addlayer': this.updateAttribution, │ │ │ │ + 'removelayer': this.updateAttribution, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.updateAttribution(); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: defaultClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - */ │ │ │ │ - defaultClick: function(evt) { │ │ │ │ - if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ - this.map.zoomOut(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + return this.div; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: defaultDblClick │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {Event} │ │ │ │ - */ │ │ │ │ - defaultDblClick: function(evt) { │ │ │ │ - this.map.zoomTo(this.map.zoom + 1, evt.xy); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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.TouchNavigation" │ │ │ │ -}); │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Attribution" │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Strategy/Cluster.js │ │ │ │ + OpenLayers/Control/LayerSwitcher.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 │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ + * @requires OpenLayers/Events/buttonclick.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Strategy.Cluster │ │ │ │ - * Strategy for vector feature clustering. │ │ │ │ + * Class: OpenLayers.Control.LayerSwitcher │ │ │ │ + * The LayerSwitcher control displays a table of contents for the map. This │ │ │ │ + * allows the user interface to switch between BaseLasyers and to show or hide │ │ │ │ + * Overlays. By default the switcher is shown minimized on the right edge of │ │ │ │ + * the map, the user may expand it by clicking on the handle. │ │ │ │ + * │ │ │ │ + * To create the LayerSwitcher outside of the map, pass the Id of a html div │ │ │ │ + * as the first argument to the constructor. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Strategy> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: distance │ │ │ │ - * {Integer} Pixel distance between features that should be considered a │ │ │ │ - * single cluster. Default is 20 pixels. │ │ │ │ - */ │ │ │ │ - distance: 20, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: threshold │ │ │ │ - * {Integer} Optional threshold below which original features will be │ │ │ │ - * added to the layer instead of clusters. For example, a threshold │ │ │ │ - * of 3 would mean that any time there are 2 or fewer features in │ │ │ │ - * a cluster, those features will be added directly to the layer instead │ │ │ │ - * of a cluster representing those features. Default is null (which is │ │ │ │ - * equivalent to 1 - meaning that clusters may contain just one feature). │ │ │ │ - */ │ │ │ │ - threshold: null, │ │ │ │ +OpenLayers.Control.LayerSwitcher = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: features │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} Cached features. │ │ │ │ + /** │ │ │ │ + * Property: layerStates │ │ │ │ + * {Array(Object)} Basically a copy of the "state" of the map's layers │ │ │ │ + * the last time the control was drawn. We have this in order to avoid │ │ │ │ + * unnecessarily redrawing the control. │ │ │ │ */ │ │ │ │ - features: null, │ │ │ │ + layerStates: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: clusters │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} Calculated clusters. │ │ │ │ - */ │ │ │ │ - clusters: null, │ │ │ │ + // DOM Elements │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: clustering │ │ │ │ - * {Boolean} The strategy is currently clustering features. │ │ │ │ + * Property: layersDiv │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - clustering: false, │ │ │ │ + layersDiv: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: resolution │ │ │ │ - * {Float} The resolution (map units per pixel) of the current cluster set. │ │ │ │ + * Property: baseLayersDiv │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - resolution: null, │ │ │ │ + baseLayersDiv: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Strategy.Cluster │ │ │ │ - * Create a new clustering strategy. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * Property: baseLayers │ │ │ │ + * {Array(Object)} │ │ │ │ */ │ │ │ │ + baseLayers: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully activated. │ │ │ │ - */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - "beforefeaturesadded": this.cacheFeatures, │ │ │ │ - "featuresremoved": this.clearCache, │ │ │ │ - "moveend": this.cluster, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - return activated; │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ - * tear-down. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully deactivated. │ │ │ │ + * Property: dataLbl │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.layer.events.un({ │ │ │ │ - "beforefeaturesadded": this.cacheFeatures, │ │ │ │ - "featuresremoved": this.clearCache, │ │ │ │ - "moveend": this.cluster, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - return deactivated; │ │ │ │ - }, │ │ │ │ + dataLbl: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: cacheFeatures │ │ │ │ - * Cache features before they are added to the layer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * event - {Object} The event that this was listening for. This will come │ │ │ │ - * with a batch of features to be clustered. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} False to stop features from being added to the layer. │ │ │ │ + * Property: dataLayersDiv │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - cacheFeatures: function(event) { │ │ │ │ - var propagate = true; │ │ │ │ - if (!this.clustering) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.features = event.features; │ │ │ │ - this.cluster(); │ │ │ │ - propagate = false; │ │ │ │ - } │ │ │ │ - return propagate; │ │ │ │ - }, │ │ │ │ + dataLayersDiv: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clearCache │ │ │ │ - * Clear out the cached features. │ │ │ │ + * Property: dataLayers │ │ │ │ + * {Array(Object)} │ │ │ │ */ │ │ │ │ - clearCache: function() { │ │ │ │ - if (!this.clustering) { │ │ │ │ - this.features = null; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + dataLayers: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: cluster │ │ │ │ - * Cluster features based on some threshold distance. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * event - {Object} The event received when cluster is called as a │ │ │ │ - * result of a moveend event. │ │ │ │ - */ │ │ │ │ - cluster: function(event) { │ │ │ │ - if ((!event || event.zoomChanged) && this.features) { │ │ │ │ - var resolution = this.layer.map.getResolution(); │ │ │ │ - if (resolution != this.resolution || !this.clustersExist()) { │ │ │ │ - this.resolution = resolution; │ │ │ │ - var clusters = []; │ │ │ │ - var feature, clustered, cluster; │ │ │ │ - for (var i = 0; i < this.features.length; ++i) { │ │ │ │ - feature = this.features[i]; │ │ │ │ - if (feature.geometry) { │ │ │ │ - clustered = false; │ │ │ │ - for (var j = clusters.length - 1; j >= 0; --j) { │ │ │ │ - cluster = clusters[j]; │ │ │ │ - if (this.shouldCluster(cluster, feature)) { │ │ │ │ - this.addToCluster(cluster, feature); │ │ │ │ - clustered = true; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (!clustered) { │ │ │ │ - clusters.push(this.createCluster(this.features[i])); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.clustering = true; │ │ │ │ - this.layer.removeAllFeatures(); │ │ │ │ - this.clustering = false; │ │ │ │ - if (clusters.length > 0) { │ │ │ │ - if (this.threshold > 1) { │ │ │ │ - var clone = clusters.slice(); │ │ │ │ - clusters = []; │ │ │ │ - var candidate; │ │ │ │ - for (var i = 0, len = clone.length; i < len; ++i) { │ │ │ │ - candidate = clone[i]; │ │ │ │ - if (candidate.attributes.count < this.threshold) { │ │ │ │ - Array.prototype.push.apply(clusters, candidate.cluster); │ │ │ │ - } else { │ │ │ │ - clusters.push(candidate); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.clustering = true; │ │ │ │ - // A legitimate feature addition could occur during this │ │ │ │ - // addFeatures call. For clustering to behave well, features │ │ │ │ - // should be removed from a layer before requesting a new batch. │ │ │ │ - this.layer.addFeatures(clusters); │ │ │ │ - this.clustering = false; │ │ │ │ - } │ │ │ │ - this.clusters = clusters; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clustersExist │ │ │ │ - * Determine whether calculated clusters are already on the layer. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The calculated clusters are already on the layer. │ │ │ │ + * Property: minimizeDiv │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - clustersExist: function() { │ │ │ │ - var exist = false; │ │ │ │ - if (this.clusters && this.clusters.length > 0 && │ │ │ │ - this.clusters.length == this.layer.features.length) { │ │ │ │ - exist = true; │ │ │ │ - for (var i = 0; i < this.clusters.length; ++i) { │ │ │ │ - if (this.clusters[i] != this.layer.features[i]) { │ │ │ │ - exist = false; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return exist; │ │ │ │ - }, │ │ │ │ + minimizeDiv: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: shouldCluster │ │ │ │ - * Determine whether to include a feature in a given cluster. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * cluster - {<OpenLayers.Feature.Vector>} A cluster. │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} A feature. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The feature should be included in the cluster. │ │ │ │ + * Property: maximizeDiv │ │ │ │ + * {DOMElement} │ │ │ │ */ │ │ │ │ - shouldCluster: function(cluster, feature) { │ │ │ │ - var cc = cluster.geometry.getBounds().getCenterLonLat(); │ │ │ │ - var fc = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ - var distance = ( │ │ │ │ - Math.sqrt( │ │ │ │ - Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2) │ │ │ │ - ) / this.resolution │ │ │ │ - ); │ │ │ │ - return (distance <= this.distance); │ │ │ │ - }, │ │ │ │ + maximizeDiv: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: addToCluster │ │ │ │ - * Add a feature to a cluster. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * cluster - {<OpenLayers.Feature.Vector>} A cluster. │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} A feature. │ │ │ │ + * APIProperty: ascending │ │ │ │ + * {Boolean} │ │ │ │ */ │ │ │ │ - addToCluster: function(cluster, feature) { │ │ │ │ - cluster.cluster.push(feature); │ │ │ │ - cluster.attributes.count += 1; │ │ │ │ - }, │ │ │ │ + ascending: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createCluster │ │ │ │ - * Given a feature, create a cluster. │ │ │ │ + * Constructor: OpenLayers.Control.LayerSwitcher │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} A cluster. │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ - createCluster: function(feature) { │ │ │ │ - var center = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ - var cluster = new OpenLayers.Feature.Vector( │ │ │ │ - new OpenLayers.Geometry.Point(center.lon, center.lat), { │ │ │ │ - count: 1 │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - cluster.cluster = [feature]; │ │ │ │ - return cluster; │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ + this.layerStates = []; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Cluster" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Strategy/BBOX.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 │ │ │ │ - * @requires OpenLayers/Filter/Spatial.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Strategy.BBOX │ │ │ │ - * A simple strategy that reads new features when the viewport invalidates │ │ │ │ - * some bounds. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Strategy> │ │ │ │ - */ │ │ │ │ -OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Property: bounds │ │ │ │ - * {<OpenLayers.Bounds>} The current data bounds (in the same projection │ │ │ │ - * as the layer - not always the same projection as the map). │ │ │ │ - */ │ │ │ │ - bounds: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: resolution │ │ │ │ - * {Float} The current data resolution. │ │ │ │ + * APIMethod: destroy │ │ │ │ */ │ │ │ │ - resolution: null, │ │ │ │ + destroy: function() { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: ratio │ │ │ │ - * {Float} The ratio of the data bounds to the viewport bounds (in each │ │ │ │ - * dimension). Default is 2. │ │ │ │ - */ │ │ │ │ - ratio: 2, │ │ │ │ + //clear out layers info and unregister their events │ │ │ │ + this.clearLayersArray("base"); │ │ │ │ + this.clearLayersArray("data"); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: resFactor │ │ │ │ - * {Float} Optional factor used to determine when previously requested │ │ │ │ - * features are invalid. If set, the resFactor will be compared to the │ │ │ │ - * resolution of the previous request to the current map resolution. │ │ │ │ - * If resFactor > (old / new) and 1/resFactor < (old / new). If you │ │ │ │ - * set a resFactor of 1, data will be requested every time the │ │ │ │ - * resolution changes. If you set a resFactor of 3, data will be │ │ │ │ - * requested if the old resolution is 3 times the new, or if the new is │ │ │ │ - * 3 times the old. If the old bounds do not contain the new bounds │ │ │ │ - * new data will always be requested (with or without considering │ │ │ │ - * resFactor). │ │ │ │ - */ │ │ │ │ - resFactor: null, │ │ │ │ + this.map.events.un({ │ │ │ │ + buttonclick: this.onButtonClick, │ │ │ │ + addlayer: this.redraw, │ │ │ │ + changelayer: this.redraw, │ │ │ │ + removelayer: this.redraw, │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: response │ │ │ │ - * {<OpenLayers.Protocol.Response>} The protocol response object returned │ │ │ │ - * by the layer protocol. │ │ │ │ - */ │ │ │ │ - response: null, │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Strategy.BBOX │ │ │ │ - * Create a new BBOX strategy. │ │ │ │ + * Method: setMap │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * Properties: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: activate │ │ │ │ - * Set up strategy with regard to reading new batches of remote data. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully activated. │ │ │ │ - */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - "moveend": this.update, │ │ │ │ - "refresh": this.update, │ │ │ │ - "visibilitychanged": this.update, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.update(); │ │ │ │ + this.map.events.on({ │ │ │ │ + addlayer: this.redraw, │ │ │ │ + changelayer: this.redraw, │ │ │ │ + removelayer: this.redraw, │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + if (this.outsideViewport) { │ │ │ │ + this.events.attachToElement(this.div); │ │ │ │ + this.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ + } else { │ │ │ │ + this.map.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: deactivate │ │ │ │ - * Tear down strategy with regard to reading new batches of remote data. │ │ │ │ - * │ │ │ │ + * Method: draw │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} The strategy was successfully deactivated. │ │ │ │ + * {DOMElement} A reference to the DIV DOMElement containing the │ │ │ │ + * switcher tabs. │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.layer.events.un({ │ │ │ │ - "moveend": this.update, │ │ │ │ - "refresh": this.update, │ │ │ │ - "visibilitychanged": this.update, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this); │ │ │ │ + │ │ │ │ + // create layout divs │ │ │ │ + this.loadContents(); │ │ │ │ + │ │ │ │ + // set mode to minimize │ │ │ │ + if (!this.outsideViewport) { │ │ │ │ + this.minimizeControl(); │ │ │ │ } │ │ │ │ - return deactivated; │ │ │ │ + │ │ │ │ + // populate div with current info │ │ │ │ + this.redraw(); │ │ │ │ + │ │ │ │ + return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: update │ │ │ │ - * Callback function called on "moveend" or "refresh" layer events. │ │ │ │ + * Method: onButtonClick │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will determine │ │ │ │ - * the behaviour of this Strategy │ │ │ │ - * │ │ │ │ - * Valid options include: │ │ │ │ - * force - {Boolean} if true, new data must be unconditionally read. │ │ │ │ - * noAbort - {Boolean} if true, do not abort previous requests. │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - update: function(options) { │ │ │ │ - var mapBounds = this.getMapBounds(); │ │ │ │ - if (mapBounds !== null && ((options && options.force) || │ │ │ │ - (this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds)))) { │ │ │ │ - this.calculateBounds(mapBounds); │ │ │ │ - this.resolution = this.layer.map.getResolution(); │ │ │ │ - this.triggerRead(options); │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + var button = evt.buttonElement; │ │ │ │ + if (button === this.minimizeDiv) { │ │ │ │ + this.minimizeControl(); │ │ │ │ + } else if (button === this.maximizeDiv) { │ │ │ │ + this.maximizeControl(); │ │ │ │ + } else if (button._layerSwitcher === this.id) { │ │ │ │ + if (button["for"]) { │ │ │ │ + button = document.getElementById(button["for"]); │ │ │ │ + } │ │ │ │ + if (!button.disabled) { │ │ │ │ + if (button.type == "radio") { │ │ │ │ + button.checked = true; │ │ │ │ + this.map.setBaseLayer(this.map.getLayer(button._layer)); │ │ │ │ + } else { │ │ │ │ + button.checked = !button.checked; │ │ │ │ + this.updateMap(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getMapBounds │ │ │ │ - * Get the map bounds expressed in the same projection as this layer. │ │ │ │ + * Method: clearLayersArray │ │ │ │ + * User specifies either "base" or "data". we then clear all the │ │ │ │ + * corresponding listeners, the div, and reinitialize a new array. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Bounds>} Map bounds in the projection of the layer. │ │ │ │ + * Parameters: │ │ │ │ + * layersType - {String} │ │ │ │ */ │ │ │ │ - getMapBounds: function() { │ │ │ │ - if (this.layer.map === null) { │ │ │ │ - return null; │ │ │ │ - } │ │ │ │ - var bounds = this.layer.map.getExtent(); │ │ │ │ - if (bounds && !this.layer.projection.equals( │ │ │ │ - this.layer.map.getProjectionObject())) { │ │ │ │ - bounds = bounds.clone().transform( │ │ │ │ - this.layer.map.getProjectionObject(), this.layer.projection │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return bounds; │ │ │ │ + clearLayersArray: function(layersType) { │ │ │ │ + this[layersType + "LayersDiv"].innerHTML = ""; │ │ │ │ + this[layersType + "Layers"] = []; │ │ │ │ }, │ │ │ │ │ │ │ │ + │ │ │ │ /** │ │ │ │ - * Method: invalidBounds │ │ │ │ - * Determine whether the previously requested set of features is invalid. │ │ │ │ - * This occurs when the new map bounds do not contain the previously │ │ │ │ - * requested bounds. In addition, if <resFactor> is set, it will be │ │ │ │ - * considered. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be │ │ │ │ - * retrieved from the map object if not provided │ │ │ │ + * Method: checkRedraw │ │ │ │ + * Checks if the layer state has changed since the last redraw() call. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Boolean} │ │ │ │ + * {Boolean} The layer state changed since the last redraw() call. │ │ │ │ */ │ │ │ │ - invalidBounds: function(mapBounds) { │ │ │ │ - if (!mapBounds) { │ │ │ │ - mapBounds = this.getMapBounds(); │ │ │ │ - } │ │ │ │ - var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds); │ │ │ │ - if (!invalid && this.resFactor) { │ │ │ │ - var ratio = this.resolution / this.layer.map.getResolution(); │ │ │ │ - invalid = (ratio >= this.resFactor || ratio <= (1 / this.resFactor)); │ │ │ │ + checkRedraw: function() { │ │ │ │ + if (!this.layerStates.length || │ │ │ │ + (this.map.layers.length != this.layerStates.length)) { │ │ │ │ + return true; │ │ │ │ } │ │ │ │ - return invalid; │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: calculateBounds │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be │ │ │ │ - * retrieved from the map object if not provided │ │ │ │ - */ │ │ │ │ - calculateBounds: function(mapBounds) { │ │ │ │ - if (!mapBounds) { │ │ │ │ - mapBounds = this.getMapBounds(); │ │ │ │ + for (var i = 0, len = this.layerStates.length; i < len; i++) { │ │ │ │ + var layerState = this.layerStates[i]; │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + if ((layerState.name != layer.name) || │ │ │ │ + (layerState.inRange != layer.inRange) || │ │ │ │ + (layerState.id != layer.id) || │ │ │ │ + (layerState.visibility != layer.visibility)) { │ │ │ │ + return true; │ │ │ │ + } │ │ │ │ } │ │ │ │ - var center = mapBounds.getCenterLonLat(); │ │ │ │ - var dataWidth = mapBounds.getWidth() * this.ratio; │ │ │ │ - var dataHeight = mapBounds.getHeight() * this.ratio; │ │ │ │ - this.bounds = new OpenLayers.Bounds( │ │ │ │ - center.lon - (dataWidth / 2), │ │ │ │ - center.lat - (dataHeight / 2), │ │ │ │ - center.lon + (dataWidth / 2), │ │ │ │ - center.lat + (dataHeight / 2) │ │ │ │ - ); │ │ │ │ + │ │ │ │ + return false; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: triggerRead │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Additional options for the protocol's read method │ │ │ │ - * (optional) │ │ │ │ + * Method: redraw │ │ │ │ + * Goes through and takes the current state of the Map and rebuilds the │ │ │ │ + * control to display that state. Groups base layers into a │ │ │ │ + * radio-button group and lists each data layer with a checkbox. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Protocol.Response>} The protocol response object │ │ │ │ - * returned by the layer protocol. │ │ │ │ + * {DOMElement} A reference to the DIV DOMElement containing the control │ │ │ │ */ │ │ │ │ - triggerRead: function(options) { │ │ │ │ - if (this.response && !(options && options.noAbort === true)) { │ │ │ │ - this.layer.protocol.abort(this.response); │ │ │ │ - this.layer.events.triggerEvent("loadend"); │ │ │ │ + redraw: function() { │ │ │ │ + //if the state hasn't changed since last redraw, no need │ │ │ │ + // to do anything. Just return the existing div. │ │ │ │ + if (!this.checkRedraw()) { │ │ │ │ + return this.div; │ │ │ │ } │ │ │ │ - var evt = { │ │ │ │ - filter: this.createFilter() │ │ │ │ - }; │ │ │ │ - this.layer.events.triggerEvent("loadstart", evt); │ │ │ │ - this.response = this.layer.protocol.read( │ │ │ │ - OpenLayers.Util.applyDefaults({ │ │ │ │ - filter: evt.filter, │ │ │ │ - callback: this.merge, │ │ │ │ - scope: this │ │ │ │ - }, options)); │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: createFilter │ │ │ │ - * Creates a spatial BBOX filter. If the layer that this strategy belongs │ │ │ │ - * to has a filter property, this filter will be combined with the BBOX │ │ │ │ - * filter. │ │ │ │ - * │ │ │ │ - * Returns │ │ │ │ - * {<OpenLayers.Filter>} The filter object. │ │ │ │ - */ │ │ │ │ - createFilter: function() { │ │ │ │ - var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ - value: this.bounds, │ │ │ │ - projection: this.layer.projection │ │ │ │ - }); │ │ │ │ - if (this.layer.filter) { │ │ │ │ - filter = new OpenLayers.Filter.Logical({ │ │ │ │ - type: OpenLayers.Filter.Logical.AND, │ │ │ │ - filters: [this.layer.filter, filter] │ │ │ │ - }); │ │ │ │ + //clear out previous layers │ │ │ │ + this.clearLayersArray("base"); │ │ │ │ + this.clearLayersArray("data"); │ │ │ │ + │ │ │ │ + var containsOverlays = false; │ │ │ │ + var containsBaseLayers = false; │ │ │ │ + │ │ │ │ + // Save state -- for checking layer if the map state changed. │ │ │ │ + // We save this before redrawing, because in the process of redrawing │ │ │ │ + // we will trigger more visibility changes, and we want to not redraw │ │ │ │ + // and enter an infinite loop. │ │ │ │ + var len = this.map.layers.length; │ │ │ │ + this.layerStates = new Array(len); │ │ │ │ + for (var i = 0; i < len; i++) { │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + this.layerStates[i] = { │ │ │ │ + 'name': layer.name, │ │ │ │ + 'visibility': layer.visibility, │ │ │ │ + 'inRange': layer.inRange, │ │ │ │ + 'id': layer.id │ │ │ │ + }; │ │ │ │ } │ │ │ │ - return filter; │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: merge │ │ │ │ - * Given a list of features, determine which ones to add 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) { │ │ │ │ - this.layer.destroyFeatures(); │ │ │ │ - if (resp.success()) { │ │ │ │ - var features = resp.features; │ │ │ │ - if (features && features.length > 0) { │ │ │ │ - var remote = this.layer.projection; │ │ │ │ - var local = this.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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.layer.addFeatures(features); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.bounds = null; │ │ │ │ + var layers = this.map.layers.slice(); │ │ │ │ + if (!this.ascending) { │ │ │ │ + layers.reverse(); │ │ │ │ } │ │ │ │ - this.response = null; │ │ │ │ - this.layer.events.triggerEvent("loadend", { │ │ │ │ - response: resp │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + var layer = layers[i]; │ │ │ │ + var baseLayer = layer.isBaseLayer; │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.BBOX" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Strategy/Save.js │ │ │ │ - ====================================================================== */ │ │ │ │ + if (layer.displayInLayerSwitcher) { │ │ │ │ │ │ │ │ -/* 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. */ │ │ │ │ + if (baseLayer) { │ │ │ │ + containsBaseLayers = true; │ │ │ │ + } else { │ │ │ │ + containsOverlays = true; │ │ │ │ + } │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Strategy.js │ │ │ │ - */ │ │ │ │ + // only check a baselayer if it is *the* baselayer, check data │ │ │ │ + // layers if they are visible │ │ │ │ + var checked = (baseLayer) ? (layer == this.map.baseLayer) : │ │ │ │ + layer.getVisibility(); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Strategy.Save │ │ │ │ - * A strategy that commits newly created or modified features. By default │ │ │ │ - * the strategy waits for a call to <save> before persisting changes. By │ │ │ │ - * configuring the strategy with the <auto> option, changes can be saved │ │ │ │ - * automatically. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Strategy> │ │ │ │ - */ │ │ │ │ -OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + // create input element │ │ │ │ + var inputElem = document.createElement("input"), │ │ │ │ + // The input shall have an id attribute so we can use │ │ │ │ + // labels to interact with them. │ │ │ │ + inputId = OpenLayers.Util.createUniqueID( │ │ │ │ + this.id + "_input_" │ │ │ │ + ); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: events │ │ │ │ - * {<OpenLayers.Events>} An events object that handles all │ │ │ │ - * events on the strategy object. │ │ │ │ - * │ │ │ │ - * Register a listener for a particular event with the following syntax: │ │ │ │ - * (code) │ │ │ │ - * strategy.events.register(type, obj, listener); │ │ │ │ - * (end) │ │ │ │ - * │ │ │ │ - * Supported event types: │ │ │ │ - * start - Triggered before saving │ │ │ │ - * success - Triggered after a successful transaction │ │ │ │ - * fail - Triggered after a failed transaction │ │ │ │ - * │ │ │ │ - */ │ │ │ │ + inputElem.id = inputId; │ │ │ │ + inputElem.name = (baseLayer) ? this.id + "_baseLayers" : layer.name; │ │ │ │ + inputElem.type = (baseLayer) ? "radio" : "checkbox"; │ │ │ │ + inputElem.value = layer.name; │ │ │ │ + inputElem.checked = checked; │ │ │ │ + inputElem.defaultChecked = checked; │ │ │ │ + inputElem.className = "olButton"; │ │ │ │ + inputElem._layer = layer.id; │ │ │ │ + inputElem._layerSwitcher = this.id; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: events │ │ │ │ - * {<OpenLayers.Events>} Events instance for triggering this protocol │ │ │ │ - * events. │ │ │ │ - */ │ │ │ │ - events: null, │ │ │ │ + if (!baseLayer && !layer.inRange) { │ │ │ │ + inputElem.disabled = true; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: auto │ │ │ │ - * {Boolean | Number} Auto-save. Default is false. If true, features will be │ │ │ │ - * saved immediately after being added to the layer and with each │ │ │ │ - * modification or deletion. If auto is a number, features will be │ │ │ │ - * saved on an interval provided by the value (in seconds). │ │ │ │ - */ │ │ │ │ - auto: false, │ │ │ │ + // create span │ │ │ │ + var labelSpan = document.createElement("label"); │ │ │ │ + // this isn't the DOM attribute 'for', but an arbitrary name we │ │ │ │ + // use to find the appropriate input element in <onButtonClick> │ │ │ │ + labelSpan["for"] = inputElem.id; │ │ │ │ + OpenLayers.Element.addClass(labelSpan, "labelSpan olButton"); │ │ │ │ + labelSpan._layer = layer.id; │ │ │ │ + labelSpan._layerSwitcher = this.id; │ │ │ │ + if (!baseLayer && !layer.inRange) { │ │ │ │ + labelSpan.style.color = "gray"; │ │ │ │ + } │ │ │ │ + labelSpan.innerHTML = layer.name; │ │ │ │ + labelSpan.style.verticalAlign = (baseLayer) ? "bottom" : │ │ │ │ + "baseline"; │ │ │ │ + // create line break │ │ │ │ + var br = document.createElement("br"); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: timer │ │ │ │ - * {Number} The id of the timer. │ │ │ │ - */ │ │ │ │ - timer: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Strategy.Save │ │ │ │ - * Create a new Save strategy. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Strategy.prototype.initialize.apply(this, [options]); │ │ │ │ - this.events = new OpenLayers.Events(this); │ │ │ │ - }, │ │ │ │ + var groupArray = (baseLayer) ? this.baseLayers : │ │ │ │ + this.dataLayers; │ │ │ │ + groupArray.push({ │ │ │ │ + 'layer': layer, │ │ │ │ + 'inputElem': inputElem, │ │ │ │ + 'labelSpan': labelSpan │ │ │ │ + }); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully activated. │ │ │ │ - */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - if (this.auto) { │ │ │ │ - if (typeof this.auto === "number") { │ │ │ │ - this.timer = window.setInterval( │ │ │ │ - OpenLayers.Function.bind(this.save, this), │ │ │ │ - this.auto * 1000 │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - this.layer.events.on({ │ │ │ │ - "featureadded": this.triggerSave, │ │ │ │ - "afterfeaturemodified": this.triggerSave, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ + │ │ │ │ + var groupDiv = (baseLayer) ? this.baseLayersDiv : │ │ │ │ + this.dataLayersDiv; │ │ │ │ + groupDiv.appendChild(inputElem); │ │ │ │ + groupDiv.appendChild(labelSpan); │ │ │ │ + groupDiv.appendChild(br); │ │ │ │ } │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ + │ │ │ │ + // if no overlays, dont display the overlay label │ │ │ │ + this.dataLbl.style.display = (containsOverlays) ? "" : "none"; │ │ │ │ + │ │ │ │ + // if no baselayers, dont display the baselayer label │ │ │ │ + this.baseLbl.style.display = (containsBaseLayers) ? "" : "none"; │ │ │ │ + │ │ │ │ + return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ - * tear-down. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully deactivated. │ │ │ │ + * Method: updateMap │ │ │ │ + * Cycles through the loaded data and base layer input arrays and makes │ │ │ │ + * the necessary calls to the Map object such that that the map's │ │ │ │ + * visual state corresponds to what the user has selected in │ │ │ │ + * the control. │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - if (this.auto) { │ │ │ │ - if (typeof this.auto === "number") { │ │ │ │ - window.clearInterval(this.timer); │ │ │ │ - } else { │ │ │ │ - this.layer.events.un({ │ │ │ │ - "featureadded": this.triggerSave, │ │ │ │ - "afterfeaturemodified": this.triggerSave, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ + updateMap: function() { │ │ │ │ + │ │ │ │ + // set the newly selected base layer │ │ │ │ + for (var i = 0, len = this.baseLayers.length; i < len; i++) { │ │ │ │ + var layerEntry = this.baseLayers[i]; │ │ │ │ + if (layerEntry.inputElem.checked) { │ │ │ │ + this.map.setBaseLayer(layerEntry.layer, false); │ │ │ │ } │ │ │ │ } │ │ │ │ - return deactivated; │ │ │ │ + │ │ │ │ + // set the correct visibilities for the overlays │ │ │ │ + for (var i = 0, len = this.dataLayers.length; i < len; i++) { │ │ │ │ + var layerEntry = this.dataLayers[i]; │ │ │ │ + layerEntry.layer.setVisibility(layerEntry.inputElem.checked); │ │ │ │ + } │ │ │ │ + │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: triggerSave │ │ │ │ - * Registered as a listener. Calls save if a feature has insert, update, │ │ │ │ - * or delete state. │ │ │ │ + * Method: maximizeControl │ │ │ │ + * Set up the labels and divs for the control │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * event - {Object} The event this function is listening for. │ │ │ │ + * e - {Event} │ │ │ │ */ │ │ │ │ - triggerSave: function(event) { │ │ │ │ - var feature = event.feature; │ │ │ │ - if (feature.state === OpenLayers.State.INSERT || │ │ │ │ - feature.state === OpenLayers.State.UPDATE || │ │ │ │ - feature.state === OpenLayers.State.DELETE) { │ │ │ │ - this.save([event.feature]); │ │ │ │ + maximizeControl: function(e) { │ │ │ │ + │ │ │ │ + // set the div's width and height to empty values, so │ │ │ │ + // the div dimensions can be controlled by CSS │ │ │ │ + this.div.style.width = ""; │ │ │ │ + this.div.style.height = ""; │ │ │ │ + │ │ │ │ + this.showControls(false); │ │ │ │ + │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: save │ │ │ │ - * Tell the layer protocol to commit unsaved features. If the layer │ │ │ │ - * projection differs from the map projection, features will be │ │ │ │ - * transformed into the layer projection before being committed. │ │ │ │ + * Method: minimizeControl │ │ │ │ + * Hide all the contents of the control, shrink the size, │ │ │ │ + * add the maximize icon │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * features - {Array} Features to be saved. If null, then default is all │ │ │ │ - * features in the layer. Features are assumed to be in the map │ │ │ │ - * projection. │ │ │ │ + * e - {Event} │ │ │ │ */ │ │ │ │ - save: function(features) { │ │ │ │ - if (!features) { │ │ │ │ - features = this.layer.features; │ │ │ │ - } │ │ │ │ - this.events.triggerEvent("start", { │ │ │ │ - features: features │ │ │ │ - }); │ │ │ │ - var remote = this.layer.projection; │ │ │ │ - var local = this.layer.map.getProjectionObject(); │ │ │ │ - if (!local.equals(remote)) { │ │ │ │ - var len = features.length; │ │ │ │ - var clones = new Array(len); │ │ │ │ - var orig, clone; │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ - orig = features[i]; │ │ │ │ - clone = orig.clone(); │ │ │ │ - clone.fid = orig.fid; │ │ │ │ - clone.state = orig.state; │ │ │ │ - if (orig.url) { │ │ │ │ - clone.url = orig.url; │ │ │ │ - } │ │ │ │ - clone._original = orig; │ │ │ │ - clone.geometry.transform(local, remote); │ │ │ │ - clones[i] = clone; │ │ │ │ - } │ │ │ │ - features = clones; │ │ │ │ + minimizeControl: function(e) { │ │ │ │ + │ │ │ │ + // to minimize the control we set its div's width │ │ │ │ + // and height to 0px, we cannot just set "display" │ │ │ │ + // to "none" because it would hide the maximize │ │ │ │ + // div │ │ │ │ + this.div.style.width = "0px"; │ │ │ │ + this.div.style.height = "0px"; │ │ │ │ + │ │ │ │ + this.showControls(true); │ │ │ │ + │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ } │ │ │ │ - this.layer.protocol.commit(features, { │ │ │ │ - callback: this.onCommit, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onCommit │ │ │ │ - * Called after protocol commit. │ │ │ │ + * Method: showControls │ │ │ │ + * Hide/Show all LayerSwitcher controls depending on whether we are │ │ │ │ + * minimized or not │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * response - {<OpenLayers.Protocol.Response>} A response object. │ │ │ │ + * minimize - {Boolean} │ │ │ │ */ │ │ │ │ - onCommit: function(response) { │ │ │ │ - var evt = { │ │ │ │ - "response": response │ │ │ │ - }; │ │ │ │ - if (response.success()) { │ │ │ │ - var features = response.reqFeatures; │ │ │ │ - // deal with inserts, updates, and deletes │ │ │ │ - var state, feature; │ │ │ │ - var destroys = []; │ │ │ │ - var insertIds = response.insertIds || []; │ │ │ │ - var j = 0; │ │ │ │ - for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - // if projection was different, we may be dealing with clones │ │ │ │ - feature = feature._original || feature; │ │ │ │ - state = feature.state; │ │ │ │ - if (state) { │ │ │ │ - if (state == OpenLayers.State.DELETE) { │ │ │ │ - destroys.push(feature); │ │ │ │ - } else if (state == OpenLayers.State.INSERT) { │ │ │ │ - feature.fid = insertIds[j]; │ │ │ │ - ++j; │ │ │ │ - } │ │ │ │ - feature.state = null; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + showControls: function(minimize) { │ │ │ │ │ │ │ │ - if (destroys.length > 0) { │ │ │ │ - this.layer.destroyFeatures(destroys); │ │ │ │ - } │ │ │ │ + this.maximizeDiv.style.display = minimize ? "" : "none"; │ │ │ │ + this.minimizeDiv.style.display = minimize ? "none" : ""; │ │ │ │ │ │ │ │ - this.events.triggerEvent("success", evt); │ │ │ │ + this.layersDiv.style.display = minimize ? "none" : ""; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: loadContents │ │ │ │ + * Set up the labels and divs for the control │ │ │ │ + */ │ │ │ │ + loadContents: function() { │ │ │ │ + │ │ │ │ + // layers list div │ │ │ │ + this.layersDiv = document.createElement("div"); │ │ │ │ + this.layersDiv.id = this.id + "_layersDiv"; │ │ │ │ + OpenLayers.Element.addClass(this.layersDiv, "layersDiv"); │ │ │ │ + │ │ │ │ + this.baseLbl = document.createElement("div"); │ │ │ │ + this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer"); │ │ │ │ + OpenLayers.Element.addClass(this.baseLbl, "baseLbl"); │ │ │ │ + │ │ │ │ + this.baseLayersDiv = document.createElement("div"); │ │ │ │ + OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv"); │ │ │ │ + │ │ │ │ + this.dataLbl = document.createElement("div"); │ │ │ │ + this.dataLbl.innerHTML = OpenLayers.i18n("Overlays"); │ │ │ │ + OpenLayers.Element.addClass(this.dataLbl, "dataLbl"); │ │ │ │ + │ │ │ │ + this.dataLayersDiv = document.createElement("div"); │ │ │ │ + OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv"); │ │ │ │ │ │ │ │ + if (this.ascending) { │ │ │ │ + this.layersDiv.appendChild(this.baseLbl); │ │ │ │ + this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ + this.layersDiv.appendChild(this.dataLbl); │ │ │ │ + this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ } else { │ │ │ │ - this.events.triggerEvent("fail", evt); │ │ │ │ + this.layersDiv.appendChild(this.dataLbl); │ │ │ │ + this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ + this.layersDiv.appendChild(this.baseLbl); │ │ │ │ + this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ } │ │ │ │ + │ │ │ │ + this.div.appendChild(this.layersDiv); │ │ │ │ + │ │ │ │ + // maximize button div │ │ │ │ + var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png'); │ │ │ │ + this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ + "OpenLayers_Control_MaximizeDiv", │ │ │ │ + null, │ │ │ │ + null, │ │ │ │ + img, │ │ │ │ + "absolute"); │ │ │ │ + OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv olButton"); │ │ │ │ + this.maximizeDiv.style.display = "none"; │ │ │ │ + │ │ │ │ + this.div.appendChild(this.maximizeDiv); │ │ │ │ + │ │ │ │ + // minimize button div │ │ │ │ + var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png'); │ │ │ │ + this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ + "OpenLayers_Control_MinimizeDiv", │ │ │ │ + null, │ │ │ │ + null, │ │ │ │ + img, │ │ │ │ + "absolute"); │ │ │ │ + OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton"); │ │ │ │ + this.minimizeDiv.style.display = "none"; │ │ │ │ + │ │ │ │ + this.div.appendChild(this.minimizeDiv); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Save" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.LayerSwitcher" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Strategy/Fixed.js │ │ │ │ + OpenLayers/Control/ZoomOut.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 │ │ │ │ + * @requires OpenLayers/Control/Button.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Strategy.Fixed │ │ │ │ - * A simple strategy that requests features once and never requests new data. │ │ │ │ + * Class: OpenLayers.Control.ZoomOut │ │ │ │ + * The ZoomOut control is a button to decrease the zoom level of a map. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Strategy> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -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. │ │ │ │ - */ │ │ │ │ +OpenLayers.Control.ZoomOut = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: trigger │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ - } │ │ │ │ + trigger: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.zoomOut(); │ │ │ │ } │ │ │ │ - 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; │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomOut" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/ZoomPanel.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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 │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ +/* 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/Panel.js │ │ │ │ + * @requires OpenLayers/Control/ZoomIn.js │ │ │ │ + * @requires OpenLayers/Control/ZoomOut.js │ │ │ │ + * @requires OpenLayers/Control/ZoomToMaxExtent.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.ZoomPanel │ │ │ │ + * The ZoomPanel control is a compact collecton of 3 zoom controls: a │ │ │ │ + * <OpenLayers.Control.ZoomIn>, a <OpenLayers.Control.ZoomToMaxExtent>, and a │ │ │ │ + * <OpenLayers.Control.ZoomOut>. By default it is drawn in the upper left │ │ │ │ + * corner of the map. │ │ │ │ + * │ │ │ │ + * Note: │ │ │ │ + * If you wish to use this class with the default images and you want │ │ │ │ + * it to look nice in ie6, you should add the following, conditionally │ │ │ │ + * added css stylesheet to your HTML file: │ │ │ │ + * │ │ │ │ + * (code) │ │ │ │ + * <!--[if lte IE 6]> │ │ │ │ + * <link rel="stylesheet" href="../theme/default/ie6-style.css" type="text/css" /> │ │ │ │ + * <![endif]--> │ │ │ │ + * (end) │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control.Panel> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.ZoomPanel = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Constructor: OpenLayers.Control.ZoomPanel │ │ │ │ + * Add the three zooming controls. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * resp - {<OpenLayers.Protocol.Response>} The response object passed │ │ │ │ - * by the protocol. │ │ │ │ + * options - {Object} An optional object whose properties will be used │ │ │ │ + * to extend the control. │ │ │ │ */ │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ + this.addControls([ │ │ │ │ + new OpenLayers.Control.ZoomIn(), │ │ │ │ + new OpenLayers.Control.ZoomToMaxExtent(), │ │ │ │ + new OpenLayers.Control.ZoomOut() │ │ │ │ + ]); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Fixed" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomPanel" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Strategy/Refresh.js │ │ │ │ + OpenLayers/Control/CacheRead.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 │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Strategy.Refresh │ │ │ │ - * A strategy that refreshes the layer. By default the strategy waits for a │ │ │ │ - * call to <refresh> before refreshing. By configuring the strategy with │ │ │ │ - * the <interval> option, refreshing can take place automatically. │ │ │ │ + * Class: OpenLayers.Control.CacheRead │ │ │ │ + * A control for using image tiles cached with <OpenLayers.Control.CacheWrite> │ │ │ │ + * from the browser's local storage. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Strategy> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Strategy.Refresh = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ +OpenLayers.Control.CacheRead = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: force │ │ │ │ - * {Boolean} Force a refresh on the layer. Default is false. │ │ │ │ + * APIProperty: fetchEvent │ │ │ │ + * {String} The layer event to listen to for replacing remote resource tile │ │ │ │ + * URLs with cached data URIs. Supported values are "tileerror" (try │ │ │ │ + * remote first, fall back to cached) and "tileloadstart" (try cache │ │ │ │ + * first, fall back to remote). Default is "tileloadstart". │ │ │ │ + * │ │ │ │ + * Note that "tileerror" will not work for CORS enabled images (see │ │ │ │ + * https://developer.mozilla.org/en/CORS_Enabled_Image), i.e. layers │ │ │ │ + * configured with a <OpenLayers.Tile.Image.crossOriginKeyword> in │ │ │ │ + * <OpenLayers.Layer.Grid.tileOptions>. │ │ │ │ */ │ │ │ │ - force: false, │ │ │ │ + fetchEvent: "tileloadstart", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: interval │ │ │ │ - * {Number} Auto-refresh. Default is 0. If > 0, layer will be refreshed │ │ │ │ - * every N milliseconds. │ │ │ │ + * APIProperty: layers │ │ │ │ + * {Array(<OpenLayers.Layer.Grid>)}. Optional. If provided, only these │ │ │ │ + * layers will receive tiles from the cache. │ │ │ │ */ │ │ │ │ - interval: 0, │ │ │ │ + layers: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: timer │ │ │ │ - * {Number} The id of the timer. │ │ │ │ + * APIProperty: autoActivate │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * true. │ │ │ │ */ │ │ │ │ - timer: null, │ │ │ │ + autoActivate: true, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Strategy.Refresh │ │ │ │ - * Create a new Refresh strategy. │ │ │ │ + * Constructor: OpenLayers.Control.CacheRead │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * options - {Object} Object with API properties for this control │ │ │ │ */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ + * Set the map property for the control. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} True if the strategy was successfully activated. │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - if (this.layer.visibility === true) { │ │ │ │ - this.start(); │ │ │ │ - } │ │ │ │ - this.layer.events.on({ │ │ │ │ - "visibilitychanged": this.reset, │ │ │ │ - scope: this │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + var i, layers = this.layers || map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.addLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ }); │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ - * tear-down. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} True if the strategy was successfully deactivated. │ │ │ │ - */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.stop(); │ │ │ │ - this.layer.events.un({ │ │ │ │ - "visibilitychanged": this.reset, │ │ │ │ + if (!this.layers) { │ │ │ │ + map.events.on({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ scope: this │ │ │ │ }); │ │ │ │ } │ │ │ │ - return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: reset │ │ │ │ - * Start or cancel the refresh interval depending on the visibility of │ │ │ │ - * the layer. │ │ │ │ + * Method: addLayer │ │ │ │ + * Adds a layer to the control. Once added, tiles requested for this layer │ │ │ │ + * will be cached. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Object} Object with a layer property referencing an │ │ │ │ + * <OpenLayers.Layer> instance │ │ │ │ */ │ │ │ │ - reset: function() { │ │ │ │ - if (this.layer.visibility === true) { │ │ │ │ - this.start(); │ │ │ │ - } else { │ │ │ │ - this.stop(); │ │ │ │ - } │ │ │ │ + addLayer: function(evt) { │ │ │ │ + evt.layer.events.register(this.fetchEvent, this, this.fetch); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: start │ │ │ │ - * Start the refresh interval. │ │ │ │ + * Method: removeLayer │ │ │ │ + * Removes a layer from the control. Once removed, tiles requested for this │ │ │ │ + * layer will no longer be cached. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Object} Object with a layer property referencing an │ │ │ │ + * <OpenLayers.Layer> instance │ │ │ │ */ │ │ │ │ - start: function() { │ │ │ │ - if (this.interval && typeof this.interval === "number" && │ │ │ │ - this.interval > 0) { │ │ │ │ - │ │ │ │ - this.timer = window.setInterval( │ │ │ │ - OpenLayers.Function.bind(this.refresh, this), │ │ │ │ - this.interval); │ │ │ │ - } │ │ │ │ + removeLayer: function(evt) { │ │ │ │ + evt.layer.events.unregister(this.fetchEvent, this, this.fetch); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: refresh │ │ │ │ - * Tell the strategy to refresh which will refresh the layer. │ │ │ │ + * Method: fetch │ │ │ │ + * Listener to the <fetchEvent> event. Replaces a tile's url with a data │ │ │ │ + * URI from the cache. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Object} Event object with a tile property. │ │ │ │ */ │ │ │ │ - refresh: function() { │ │ │ │ - if (this.layer && this.layer.refresh && │ │ │ │ - typeof this.layer.refresh == "function") { │ │ │ │ - │ │ │ │ - this.layer.refresh({ │ │ │ │ - force: this.force │ │ │ │ - }); │ │ │ │ + fetch: function(evt) { │ │ │ │ + if (this.active && window.localStorage && │ │ │ │ + evt.tile instanceof OpenLayers.Tile.Image) { │ │ │ │ + var tile = evt.tile, │ │ │ │ + url = tile.url; │ │ │ │ + // deal with modified tile urls when both CacheWrite and CacheRead │ │ │ │ + // are active │ │ │ │ + if (!tile.layer.crossOriginKeyword && OpenLayers.ProxyHost && │ │ │ │ + url.indexOf(OpenLayers.ProxyHost) === 0) { │ │ │ │ + url = OpenLayers.Control.CacheWrite.urlMap[url]; │ │ │ │ + } │ │ │ │ + var dataURI = window.localStorage.getItem("olCache_" + url); │ │ │ │ + if (dataURI) { │ │ │ │ + tile.url = dataURI; │ │ │ │ + if (evt.type === "tileerror") { │ │ │ │ + tile.setImgSrc(dataURI); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: stop │ │ │ │ - * Cancels the refresh interval. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - stop: function() { │ │ │ │ - if (this.timer !== null) { │ │ │ │ - window.clearInterval(this.timer); │ │ │ │ - this.timer = null; │ │ │ │ + destroy: function() { │ │ │ │ + if (this.layers || this.map) { │ │ │ │ + var i, layers = this.layers || this.map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.removeLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.un({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ } │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Refresh" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.CacheRead" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Strategy/Paging.js │ │ │ │ + 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/Strategy.js │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Strategy.Paging │ │ │ │ - * Strategy for vector feature paging │ │ │ │ + * Class: OpenLayers.Control.DrawFeature │ │ │ │ + * The DrawFeature control draws point, line or polygon features on a vector │ │ │ │ + * layer when active. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Strategy> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ +OpenLayers.Control.DrawFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: features │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} Cached features. │ │ │ │ + * Property: layer │ │ │ │ + * {<OpenLayers.Layer.Vector>} │ │ │ │ */ │ │ │ │ - features: null, │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: length │ │ │ │ - * {Integer} Number of features per page. Default is 10. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - length: 10, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: num │ │ │ │ - * {Integer} The currently displayed page number. │ │ │ │ + * APIProperty: multi │ │ │ │ + * {Boolean} Cast features to multi-part geometries before passing to the │ │ │ │ + * layer. Default is false. │ │ │ │ */ │ │ │ │ - num: null, │ │ │ │ + multi: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: paging │ │ │ │ - * {Boolean} The strategy is currently changing pages. │ │ │ │ + * APIProperty: featureAdded │ │ │ │ + * {Function} Called after each feature is added │ │ │ │ */ │ │ │ │ - paging: false, │ │ │ │ + featureAdded: function() {}, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Strategy.Paging │ │ │ │ - * Create a new paging strategy. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * APIProperty: handlerOptions │ │ │ │ + * {Object} Used to set non-default properties on the control's handler │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ + * Constructor: OpenLayers.Control.DrawFeature │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully activated. │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} │ │ │ │ + * handler - {<OpenLayers.Handler>} │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - "beforefeaturesadded": this.cacheFeatures, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - return activated; │ │ │ │ + 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); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ - * tear-down. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The strategy was successfully deactivated. │ │ │ │ + * Method: drawFeature │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.layer.events.un({ │ │ │ │ - "beforefeaturesadded": this.cacheFeatures, │ │ │ │ - scope: this │ │ │ │ + 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 │ │ │ │ }); │ │ │ │ } │ │ │ │ - return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: cacheFeatures │ │ │ │ - * Cache features before they are added to the layer. │ │ │ │ + * APIMethod: insertXY │ │ │ │ + * Insert a point in the current sketch given x & y coordinates. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * event - {Object} The event that this was listening for. This will come │ │ │ │ - * with a batch of features to be paged. │ │ │ │ + * x - {Number} The x-coordinate of the point. │ │ │ │ + * y - {Number} The y-coordinate of the point. │ │ │ │ */ │ │ │ │ - cacheFeatures: function(event) { │ │ │ │ - if (!this.paging) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.features = event.features; │ │ │ │ - this.pageNext(event); │ │ │ │ + insertXY: function(x, y) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertXY(x, y); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: clearCache │ │ │ │ - * Clear out the cached features. This destroys features, assuming │ │ │ │ - * nothing else has a reference. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - clearCache: function() { │ │ │ │ - if (this.features) { │ │ │ │ - for (var i = 0; i < this.features.length; ++i) { │ │ │ │ - this.features[i].destroy(); │ │ │ │ - } │ │ │ │ + insertDeltaXY: function(dx, dy) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertDeltaXY(dx, dy); │ │ │ │ } │ │ │ │ - this.features = null; │ │ │ │ - this.num = null; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: pageCount │ │ │ │ - * Get the total count of pages given the current cache of features. │ │ │ │ + * APIMethod: insertDirectionLength │ │ │ │ + * Insert a point in the current sketch given a direction and a length. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} The page count. │ │ │ │ + * Parameters: │ │ │ │ + * direction - {Number} Degrees clockwise from the positive x-axis. │ │ │ │ + * length - {Number} Distance from the previously drawn point. │ │ │ │ */ │ │ │ │ - pageCount: function() { │ │ │ │ - var numFeatures = this.features ? this.features.length : 0; │ │ │ │ - return Math.ceil(numFeatures / this.length); │ │ │ │ + insertDirectionLength: function(direction, length) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertDirectionLength(direction, length); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: pageNum │ │ │ │ - * Get the zero based page number. │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} The current page number being displayed. │ │ │ │ + * Parameters: │ │ │ │ + * deflection - {Number} Degrees clockwise from the previous segment. │ │ │ │ + * length - {Number} Distance from the previously drawn point. │ │ │ │ */ │ │ │ │ - pageNum: function() { │ │ │ │ - return this.num; │ │ │ │ + insertDeflectionLength: function(deflection, length) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertDeflectionLength(deflection, length); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: pageLength │ │ │ │ - * Gets or sets page length. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * newLength - {Integer} Optional length to be set. │ │ │ │ + * APIMethod: undo │ │ │ │ + * Remove the most recently added point in the current sketch geometry. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Integer} The length of a page (number of features per page). │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} An edit was undone. │ │ │ │ */ │ │ │ │ - pageLength: function(newLength) { │ │ │ │ - if (newLength && newLength > 0) { │ │ │ │ - this.length = newLength; │ │ │ │ - } │ │ │ │ - return this.length; │ │ │ │ + undo: function() { │ │ │ │ + return this.handler.undo && this.handler.undo(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: pageNext │ │ │ │ - * Display the next page of features. │ │ │ │ + * 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} A new page was displayed. │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} An edit was redone. │ │ │ │ */ │ │ │ │ - pageNext: function(event) { │ │ │ │ - var changed = false; │ │ │ │ - if (this.features) { │ │ │ │ - if (this.num === null) { │ │ │ │ - this.num = -1; │ │ │ │ - } │ │ │ │ - var start = (this.num + 1) * this.length; │ │ │ │ - changed = this.page(start, event); │ │ │ │ - } │ │ │ │ - return changed; │ │ │ │ + redo: function() { │ │ │ │ + return this.handler.redo && this.handler.redo(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: pagePrevious │ │ │ │ - * Display the previous page of features. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} A new page was displayed. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - pagePrevious: function() { │ │ │ │ - var changed = false; │ │ │ │ - if (this.features) { │ │ │ │ - if (this.num === null) { │ │ │ │ - this.num = this.pageCount(); │ │ │ │ - } │ │ │ │ - var start = (this.num - 1) * this.length; │ │ │ │ - changed = this.page(start); │ │ │ │ - } │ │ │ │ - return changed; │ │ │ │ + finishSketch: function() { │ │ │ │ + this.handler.finishGeometry(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: page │ │ │ │ - * Display the page starting at the given index from the cache. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} A new page was displayed. │ │ │ │ + * APIMethod: cancel │ │ │ │ + * Cancel the current sketch. This removes the current sketch and keeps │ │ │ │ + * the drawing control active. │ │ │ │ */ │ │ │ │ - page: function(start, event) { │ │ │ │ - var changed = false; │ │ │ │ - if (this.features) { │ │ │ │ - if (start >= 0 && start < this.features.length) { │ │ │ │ - var num = Math.floor(start / this.length); │ │ │ │ - if (num != this.num) { │ │ │ │ - this.paging = true; │ │ │ │ - var features = this.features.slice(start, start + this.length); │ │ │ │ - this.layer.removeFeatures(this.layer.features); │ │ │ │ - this.num = num; │ │ │ │ - // modify the event if any │ │ │ │ - if (event && event.features) { │ │ │ │ - // this.was called by an event listener │ │ │ │ - event.features = features; │ │ │ │ - } else { │ │ │ │ - // this was called directly on the strategy │ │ │ │ - this.layer.addFeatures(features); │ │ │ │ - } │ │ │ │ - this.paging = false; │ │ │ │ - changed = true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return changed; │ │ │ │ + cancel: function() { │ │ │ │ + this.handler.cancel(); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Paging" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.DrawFeature" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Strategy/Filter.js │ │ │ │ + OpenLayers/Control/EditingToolbar.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 │ │ │ │ - * @requires OpenLayers/Filter.js │ │ │ │ + * @requires OpenLayers/Control/Panel.js │ │ │ │ + * @requires OpenLayers/Control/Navigation.js │ │ │ │ + * @requires OpenLayers/Control/DrawFeature.js │ │ │ │ + * @requires OpenLayers/Handler/Point.js │ │ │ │ + * @requires OpenLayers/Handler/Path.js │ │ │ │ + * @requires OpenLayers/Handler/Polygon.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Strategy.Filter │ │ │ │ - * Strategy for limiting features that get added to a layer by │ │ │ │ - * evaluating a filter. The strategy maintains a cache of │ │ │ │ - * all features until removeFeatures is called on the layer. │ │ │ │ + * Class: OpenLayers.Control.EditingToolbar │ │ │ │ + * The EditingToolbar is a panel of 4 controls to draw polygons, lines, │ │ │ │ + * points, or to navigate the map by panning. By default it appears in the │ │ │ │ + * upper right corner of the map. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control.Panel> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.EditingToolbar = OpenLayers.Class( │ │ │ │ + OpenLayers.Control.Panel, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.EditingToolbar │ │ │ │ + * Create an editing toolbar for a given layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} │ │ │ │ + * options - {Object} │ │ │ │ + */ │ │ │ │ + initialize: function(layer, options) { │ │ │ │ + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ + │ │ │ │ + this.addControls( │ │ │ │ + [new OpenLayers.Control.Navigation()] │ │ │ │ + ); │ │ │ │ + var controls = [ │ │ │ │ + new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Point, { │ │ │ │ + displayClass: 'olControlDrawFeaturePoint', │ │ │ │ + handlerOptions: { │ │ │ │ + citeCompliant: this.citeCompliant │ │ │ │ + } │ │ │ │ + }), │ │ │ │ + new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Path, { │ │ │ │ + displayClass: 'olControlDrawFeaturePath', │ │ │ │ + handlerOptions: { │ │ │ │ + citeCompliant: this.citeCompliant │ │ │ │ + } │ │ │ │ + }), │ │ │ │ + new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Polygon, { │ │ │ │ + displayClass: 'olControlDrawFeaturePolygon', │ │ │ │ + handlerOptions: { │ │ │ │ + citeCompliant: this.citeCompliant │ │ │ │ + } │ │ │ │ + }) │ │ │ │ + ]; │ │ │ │ + this.addControls(controls); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: draw │ │ │ │ + * calls the default draw, and then activates mouse defaults. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} │ │ │ │ + */ │ │ │ │ + draw: function() { │ │ │ │ + var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments); │ │ │ │ + if (this.defaultControl === null) { │ │ │ │ + this.defaultControl = this.controls[0]; │ │ │ │ + } │ │ │ │ + return div; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Control.EditingToolbar" │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/OverviewMap.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/BaseTypes.js │ │ │ │ + * @requires OpenLayers/Events/buttonclick.js │ │ │ │ + * @requires OpenLayers/Map.js │ │ │ │ + * @requires OpenLayers/Handler/Click.js │ │ │ │ + * @requires OpenLayers/Handler/Drag.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.OverviewMap │ │ │ │ + * The OverMap control creates a small overview map, useful to display the │ │ │ │ + * extent of a zoomed map and your main map and provide additional │ │ │ │ + * navigation options to the User. By default the overview map is drawn in │ │ │ │ + * the lower right corner of the main map. Create a new overview map with the │ │ │ │ + * <OpenLayers.Control.OverviewMap> constructor. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Strategy> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Strategy.Filter = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ +OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: filter │ │ │ │ - * {<OpenLayers.Filter>} Filter for limiting features sent to the layer. │ │ │ │ - * Use the <setFilter> method to update this filter after construction. │ │ │ │ + * Property: element │ │ │ │ + * {DOMElement} The DOM element that contains the overview map │ │ │ │ */ │ │ │ │ - filter: null, │ │ │ │ + element: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: cache │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} List of currently cached │ │ │ │ - * features. │ │ │ │ + * APIProperty: ovmap │ │ │ │ + * {<OpenLayers.Map>} A reference to the overview map itself. │ │ │ │ */ │ │ │ │ - cache: null, │ │ │ │ + ovmap: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: caching │ │ │ │ - * {Boolean} The filter is currently caching features. │ │ │ │ + * APIProperty: size │ │ │ │ + * {<OpenLayers.Size>} The overvew map size in pixels. Note that this is │ │ │ │ + * the size of the map itself - the element that contains the map (default │ │ │ │ + * class name olControlOverviewMapElement) may have padding or other style │ │ │ │ + * attributes added via CSS. │ │ │ │ */ │ │ │ │ - caching: false, │ │ │ │ + size: { │ │ │ │ + w: 180, │ │ │ │ + h: 90 │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Strategy.Filter │ │ │ │ - * Create a new filter strategy. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * APIProperty: layers │ │ │ │ + * {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map. │ │ │ │ + * If none are sent at construction, the base layer for the main map is used. │ │ │ │ */ │ │ │ │ + layers: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: activate │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ - * By default, this strategy automatically activates itself when a layer │ │ │ │ - * is added to a map. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ - * the strategy was already active. │ │ │ │ + * APIProperty: minRectSize │ │ │ │ + * {Integer} The minimum width or height (in pixels) of the extent │ │ │ │ + * rectangle on the overview map. When the extent rectangle reaches │ │ │ │ + * this size, it will be replaced depending on the value of the │ │ │ │ + * <minRectDisplayClass> property. Default is 15 pixels. │ │ │ │ */ │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments); │ │ │ │ - if (activated) { │ │ │ │ - this.cache = []; │ │ │ │ - this.layer.events.on({ │ │ │ │ - "beforefeaturesadded": this.handleAdd, │ │ │ │ - "beforefeaturesremoved": this.handleRemove, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - return activated; │ │ │ │ - }, │ │ │ │ + minRectSize: 15, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: deactivate │ │ │ │ - * Deactivate the strategy. Clear the feature cache. │ │ │ │ + * APIProperty: minRectDisplayClass │ │ │ │ + * {String} Replacement style class name for the extent rectangle when │ │ │ │ + * <minRectSize> is reached. This string will be suffixed on to the │ │ │ │ + * displayClass. Default is "RectReplacement". │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} True if the strategy was successfully deactivated or false if │ │ │ │ - * the strategy was already inactive. │ │ │ │ + * Example CSS declaration: │ │ │ │ + * (code) │ │ │ │ + * .olControlOverviewMapRectReplacement { │ │ │ │ + * overflow: hidden; │ │ │ │ + * cursor: move; │ │ │ │ + * background-image: url("img/overview_replacement.gif"); │ │ │ │ + * background-repeat: no-repeat; │ │ │ │ + * background-position: center; │ │ │ │ + * } │ │ │ │ + * (end) │ │ │ │ */ │ │ │ │ - deactivate: function() { │ │ │ │ - this.cache = null; │ │ │ │ - if (this.layer && this.layer.events) { │ │ │ │ - this.layer.events.un({ │ │ │ │ - "beforefeaturesadded": this.handleAdd, │ │ │ │ - "beforefeaturesremoved": this.handleRemove, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - return OpenLayers.Strategy.prototype.deactivate.apply(this, arguments); │ │ │ │ - }, │ │ │ │ + minRectDisplayClass: "RectReplacement", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handleAdd │ │ │ │ + * APIProperty: minRatio │ │ │ │ + * {Float} The ratio of the overview map resolution to the main map │ │ │ │ + * resolution at which to zoom farther out on the overview map. │ │ │ │ */ │ │ │ │ - handleAdd: function(event) { │ │ │ │ - if (!this.caching && this.filter) { │ │ │ │ - var features = event.features; │ │ │ │ - event.features = []; │ │ │ │ - var feature; │ │ │ │ - for (var i = 0, ii = features.length; i < ii; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - if (this.filter.evaluate(feature)) { │ │ │ │ - event.features.push(feature); │ │ │ │ - } else { │ │ │ │ - this.cache.push(feature); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + minRatio: 8, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: handleRemove │ │ │ │ - */ │ │ │ │ - handleRemove: function(event) { │ │ │ │ - if (!this.caching) { │ │ │ │ - this.cache = []; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: setFilter │ │ │ │ - * Update the filter for this strategy. This will re-evaluate │ │ │ │ - * any features on the layer and in the cache. Only features │ │ │ │ - * for which filter.evalute(feature) returns true will be │ │ │ │ - * added to the layer. Others will be cached by the strategy. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * filter - {<OpenLayers.Filter>} A filter for evaluating features. │ │ │ │ + * APIProperty: maxRatio │ │ │ │ + * {Float} The ratio of the overview map resolution to the main map │ │ │ │ + * resolution at which to zoom farther in on the overview map. │ │ │ │ */ │ │ │ │ - setFilter: function(filter) { │ │ │ │ - this.filter = filter; │ │ │ │ - var previousCache = this.cache; │ │ │ │ - this.cache = []; │ │ │ │ - // look through layer for features to remove from layer │ │ │ │ - this.handleAdd({ │ │ │ │ - features: this.layer.features │ │ │ │ - }); │ │ │ │ - // cache now contains features to remove from layer │ │ │ │ - if (this.cache.length > 0) { │ │ │ │ - this.caching = true; │ │ │ │ - this.layer.removeFeatures(this.cache.slice()); │ │ │ │ - this.caching = false; │ │ │ │ - } │ │ │ │ - // now look through previous cache for features to add to layer │ │ │ │ - if (previousCache.length > 0) { │ │ │ │ - var event = { │ │ │ │ - features: previousCache │ │ │ │ - }; │ │ │ │ - this.handleAdd(event); │ │ │ │ - if (event.features.length > 0) { │ │ │ │ - // event has features to add to layer │ │ │ │ - this.caching = true; │ │ │ │ - this.layer.addFeatures(event.features); │ │ │ │ - this.caching = false; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Filter" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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, { │ │ │ │ + maxRatio: 32, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: xmlns │ │ │ │ - * {String} │ │ │ │ + /** │ │ │ │ + * APIProperty: mapOptions │ │ │ │ + * {Object} An object containing any non-default properties to be sent to │ │ │ │ + * the overview map's map constructor. These should include any │ │ │ │ + * non-default options that the main map was constructed with. │ │ │ │ */ │ │ │ │ - xmlns: "http://www.w3.org/2000/svg", │ │ │ │ + mapOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: xlinkns │ │ │ │ - * {String} │ │ │ │ + * APIProperty: autoPan │ │ │ │ + * {Boolean} Always pan the overview map, so the extent marker remains in │ │ │ │ + * the center. Default is false. If true, when you drag the extent │ │ │ │ + * marker, the overview map will update itself so the marker returns │ │ │ │ + * to the center. │ │ │ │ */ │ │ │ │ - xlinkns: "http://www.w3.org/1999/xlink", │ │ │ │ + autoPan: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: handlers │ │ │ │ + * {Object} │ │ │ │ */ │ │ │ │ - MAX_PIXEL: 15000, │ │ │ │ + handlers: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: translationParameters │ │ │ │ - * {Object} Hash with "x" and "y" properties │ │ │ │ + * Property: resolutionFactor │ │ │ │ + * {Object} │ │ │ │ */ │ │ │ │ - translationParameters: null, │ │ │ │ + resolutionFactor: 1, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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]. │ │ │ │ + * APIProperty: maximized │ │ │ │ + * {Boolean} Start as maximized (visible). Defaults to false. │ │ │ │ */ │ │ │ │ - symbolMetrics: null, │ │ │ │ + maximized: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Renderer.SVG │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * containerID - {String} │ │ │ │ + * APIProperty: maximizeTitle │ │ │ │ + * {String} This property is used for showing a tooltip over the │ │ │ │ + * maximize div. Defaults to "" (no title). │ │ │ │ */ │ │ │ │ - initialize: function(containerID) { │ │ │ │ - if (!this.supported()) { │ │ │ │ - return; │ │ │ │ - } │ │ │ │ - OpenLayers.Renderer.Elements.prototype.initialize.apply(this, │ │ │ │ - arguments); │ │ │ │ - this.translationParameters = { │ │ │ │ - x: 0, │ │ │ │ - y: 0 │ │ │ │ - }; │ │ │ │ - │ │ │ │ - this.symbolMetrics = {}; │ │ │ │ - }, │ │ │ │ + maximizeTitle: "", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: supported │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the browser supports the SVG renderer │ │ │ │ + * APIProperty: minimizeTitle │ │ │ │ + * {String} This property is used for showing a tooltip over the │ │ │ │ + * minimize div. Defaults to "" (no title). │ │ │ │ */ │ │ │ │ - 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"))); │ │ │ │ - }, │ │ │ │ + minimizeTitle: "", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: inValidRange │ │ │ │ - * See #669 for more information │ │ │ │ + * Constructor: OpenLayers.Control.OverviewMap │ │ │ │ + * Create a new overview map │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * options - {Object} Properties of this object will be set on the overview │ │ │ │ + * map object. Note, to set options on the map object contained in this │ │ │ │ + * control, set <mapOptions> as one of the options properties. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + initialize: function(options) { │ │ │ │ + this.layers = []; │ │ │ │ + this.handlers = {}; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Deconstruct the control │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + destroy: function() { │ │ │ │ + if (!this.mapDiv) { // we've already been destroyed │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + if (this.handlers.click) { │ │ │ │ + this.handlers.click.destroy(); │ │ │ │ + } │ │ │ │ + if (this.handlers.drag) { │ │ │ │ + this.handlers.drag.destroy(); │ │ │ │ + } │ │ │ │ │ │ │ │ - // 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.ovmap && this.ovmap.viewPortDiv.removeChild(this.extentRectangle); │ │ │ │ + this.extentRectangle = null; │ │ │ │ │ │ │ │ - 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; │ │ │ │ + if (this.rectEvents) { │ │ │ │ + this.rectEvents.destroy(); │ │ │ │ + this.rectEvents = null; │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ + if (this.ovmap) { │ │ │ │ + this.ovmap.destroy(); │ │ │ │ + this.ovmap = null; │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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.element.removeChild(this.mapDiv); │ │ │ │ + this.mapDiv = null; │ │ │ │ │ │ │ │ - this.rendererRoot.setAttributeNS(null, "width", this.size.w); │ │ │ │ - this.rendererRoot.setAttributeNS(null, "height", this.size.h); │ │ │ │ - }, │ │ │ │ + this.div.removeChild(this.element); │ │ │ │ + this.element = null; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ + if (this.maximizeDiv) { │ │ │ │ + this.div.removeChild(this.maximizeDiv); │ │ │ │ + this.maximizeDiv = null; │ │ │ │ } │ │ │ │ - return nodeType; │ │ │ │ + │ │ │ │ + if (this.minimizeDiv) { │ │ │ │ + this.div.removeChild(this.minimizeDiv); │ │ │ │ + this.minimizeDiv = null; │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.map.events.un({ │ │ │ │ + buttonclick: this.onButtonClick, │ │ │ │ + moveend: this.update, │ │ │ │ + changebaselayer: this.baseLayerDraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: 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} │ │ │ │ + /** │ │ │ │ + * Method: draw │ │ │ │ + * Render the control in the browser. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (this.layers.length === 0) { │ │ │ │ + if (this.map.baseLayer) { │ │ │ │ + var layer = this.map.baseLayer.clone(); │ │ │ │ + this.layers = [layer]; │ │ │ │ } else { │ │ │ │ - var label = this.nodeFactory(null, "title"); │ │ │ │ - label.textContent = title; │ │ │ │ - node.appendChild(label); │ │ │ │ + this.map.events.register("changebaselayer", this, this.baseLayerDraw); │ │ │ │ + return this.div; │ │ │ │ } │ │ │ │ } │ │ │ │ │ │ │ │ - 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; │ │ │ │ + // create overview map DOM elements │ │ │ │ + this.element = document.createElement('div'); │ │ │ │ + this.element.className = this.displayClass + 'Element'; │ │ │ │ + this.element.style.display = 'none'; │ │ │ │ │ │ │ │ - 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; │ │ │ │ + this.mapDiv = document.createElement('div'); │ │ │ │ + this.mapDiv.style.width = this.size.w + 'px'; │ │ │ │ + this.mapDiv.style.height = this.size.h + 'px'; │ │ │ │ + this.mapDiv.style.position = 'relative'; │ │ │ │ + this.mapDiv.style.overflow = 'hidden'; │ │ │ │ + this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap'); │ │ │ │ │ │ │ │ - // 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); │ │ │ │ - } │ │ │ │ + this.extentRectangle = document.createElement('div'); │ │ │ │ + this.extentRectangle.style.position = 'absolute'; │ │ │ │ + this.extentRectangle.style.zIndex = 1000; //HACK │ │ │ │ + this.extentRectangle.className = this.displayClass + 'ExtentRectangle'; │ │ │ │ │ │ │ │ - // 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")); │ │ │ │ + this.element.appendChild(this.mapDiv); │ │ │ │ │ │ │ │ - node.setAttributeNS(null, "width", size); │ │ │ │ - node.setAttributeNS(null, "height", size); │ │ │ │ - node.setAttributeNS(null, "x", pos.x - offset); │ │ │ │ - node.setAttributeNS(null, "y", pos.y - offset); │ │ │ │ + this.div.appendChild(this.element); │ │ │ │ │ │ │ │ - // 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); │ │ │ │ + // Optionally add min/max buttons if the control will go in the │ │ │ │ + // map viewport. │ │ │ │ + if (!this.outsideViewport) { │ │ │ │ + this.div.className += " " + this.displayClass + 'Container'; │ │ │ │ + // maximize button div │ │ │ │ + var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png'); │ │ │ │ + this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ + this.displayClass + 'MaximizeButton', │ │ │ │ + null, │ │ │ │ + null, │ │ │ │ + img, │ │ │ │ + 'absolute'); │ │ │ │ + this.maximizeDiv.style.display = 'none'; │ │ │ │ + this.maximizeDiv.className = this.displayClass + 'MaximizeButton olButton'; │ │ │ │ + if (this.maximizeTitle) { │ │ │ │ + this.maximizeDiv.title = this.maximizeTitle; │ │ │ │ } │ │ │ │ + this.div.appendChild(this.maximizeDiv); │ │ │ │ │ │ │ │ - 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] + ")"); │ │ │ │ - } │ │ │ │ + // minimize button div │ │ │ │ + var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png'); │ │ │ │ + this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ + 'OpenLayers_Control_minimizeDiv', │ │ │ │ + null, │ │ │ │ + null, │ │ │ │ + img, │ │ │ │ + 'absolute'); │ │ │ │ + this.minimizeDiv.style.display = 'none'; │ │ │ │ + this.minimizeDiv.className = this.displayClass + 'MinimizeButton olButton'; │ │ │ │ + if (this.minimizeTitle) { │ │ │ │ + this.minimizeDiv.title = this.minimizeTitle; │ │ │ │ } │ │ │ │ - } │ │ │ │ - │ │ │ │ - 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)); │ │ │ │ + this.div.appendChild(this.minimizeDiv); │ │ │ │ + this.minimizeControl(); │ │ │ │ } else { │ │ │ │ - node.setAttributeNS(null, "stroke", "none"); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (style.pointerEvents) { │ │ │ │ - node.setAttributeNS(null, "pointer-events", style.pointerEvents); │ │ │ │ + // show the overview map │ │ │ │ + this.element.style.display = ''; │ │ │ │ } │ │ │ │ - │ │ │ │ - if (style.cursor != null) { │ │ │ │ - node.setAttributeNS(null, "cursor", style.cursor); │ │ │ │ + if (this.map.getExtent()) { │ │ │ │ + this.update(); │ │ │ │ } │ │ │ │ │ │ │ │ - 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, ","); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + this.map.events.on({ │ │ │ │ + buttonclick: this.onButtonClick, │ │ │ │ + moveend: this.update, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + if (this.maximized) { │ │ │ │ + this.maximizeControl(); │ │ │ │ } │ │ │ │ - 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; │ │ │ │ + return this.div; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createRoot │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * suffix - {String} suffix to append to the id │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * Method: baseLayerDraw │ │ │ │ + * Draw the base layer - called if unable to complete in the initial draw │ │ │ │ */ │ │ │ │ - createRoot: function(suffix) { │ │ │ │ - return this.nodeFactory(this.container.id + suffix, "g"); │ │ │ │ + baseLayerDraw: function() { │ │ │ │ + this.draw(); │ │ │ │ + this.map.events.unregister("changebaselayer", this, this.baseLayerDraw); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createDefs │ │ │ │ + * Method: rectDrag │ │ │ │ + * Handle extent rectangle drag │ │ │ │ * │ │ │ │ - * 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 │ │ │ │ + * Parameters: │ │ │ │ + * px - {<OpenLayers.Pixel>} The pixel location of the drag. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + rectDrag: function(px) { │ │ │ │ + var deltaX = this.handlers.drag.last.x - px.x; │ │ │ │ + var deltaY = this.handlers.drag.last.y - px.y; │ │ │ │ + if (deltaX != 0 || deltaY != 0) { │ │ │ │ + var rectTop = this.rectPxBounds.top; │ │ │ │ + var rectLeft = this.rectPxBounds.left; │ │ │ │ + var rectHeight = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ + var rectWidth = this.rectPxBounds.getWidth(); │ │ │ │ + // don't allow dragging off of parent element │ │ │ │ + var newTop = Math.max(0, (rectTop - deltaY)); │ │ │ │ + newTop = Math.min(newTop, │ │ │ │ + this.ovmap.size.h - this.hComp - rectHeight); │ │ │ │ + var newLeft = Math.max(0, (rectLeft - deltaX)); │ │ │ │ + newLeft = Math.min(newLeft, │ │ │ │ + this.ovmap.size.w - this.wComp - rectWidth); │ │ │ │ + this.setRectPxBounds(new OpenLayers.Bounds(newLeft, │ │ │ │ + newTop + rectHeight, │ │ │ │ + newLeft + rectWidth, │ │ │ │ + newTop)); │ │ │ │ } │ │ │ │ - │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: 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 │ │ │ │ + * Method: mapDivClick │ │ │ │ + * Handle browser events │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {<OpenLayers.Event>} evt │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + mapDivClick: function(evt) { │ │ │ │ + var pxCenter = this.rectPxBounds.getCenterPixel(); │ │ │ │ + var deltaX = evt.xy.x - pxCenter.x; │ │ │ │ + var deltaY = evt.xy.y - pxCenter.y; │ │ │ │ + var top = this.rectPxBounds.top; │ │ │ │ + var left = this.rectPxBounds.left; │ │ │ │ + var height = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ + var width = this.rectPxBounds.getWidth(); │ │ │ │ + var newTop = Math.max(0, (top + deltaY)); │ │ │ │ + newTop = Math.min(newTop, this.ovmap.size.h - height); │ │ │ │ + var newLeft = Math.max(0, (left + deltaX)); │ │ │ │ + newLeft = Math.min(newLeft, this.ovmap.size.w - width); │ │ │ │ + this.setRectPxBounds(new OpenLayers.Bounds(newLeft, │ │ │ │ + newTop + height, │ │ │ │ + newLeft + width, │ │ │ │ + newTop)); │ │ │ │ + this.updateMapToRect(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: 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 │ │ │ │ + * Method: onButtonClick │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + if (evt.buttonElement === this.minimizeDiv) { │ │ │ │ + this.minimizeControl(); │ │ │ │ + } else if (evt.buttonElement === this.maximizeDiv) { │ │ │ │ + this.maximizeControl(); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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 │ │ │ │ + * Method: maximizeControl │ │ │ │ + * Unhide the control. Called when the control is in the map viewport. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * e - {<OpenLayers.Event>} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + maximizeControl: function(e) { │ │ │ │ + this.element.style.display = ''; │ │ │ │ + this.showToggle(false); │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawRectangle │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * Method: minimizeControl │ │ │ │ + * Hide all the contents of the control, shrink the size, │ │ │ │ + * add the maximize icon │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} or false if the renderer could not draw the rectangle │ │ │ │ + * Parameters: │ │ │ │ + * e - {<OpenLayers.Event>} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + minimizeControl: function(e) { │ │ │ │ + this.element.style.display = 'none'; │ │ │ │ + this.showToggle(true); │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawText │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ + * Method: showToggle │ │ │ │ + * Hide/Show the toggle depending on whether the control is minimized │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * featureId - {String} │ │ │ │ - * style - │ │ │ │ - * location - {<OpenLayers.Geometry.Point>} │ │ │ │ + * minimize - {Boolean} │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ + showToggle: function(minimize) { │ │ │ │ + if (this.maximizeDiv) { │ │ │ │ + this.maximizeDiv.style.display = minimize ? '' : 'none'; │ │ │ │ } │ │ │ │ + if (this.minimizeDiv) { │ │ │ │ + this.minimizeDiv.style.display = minimize ? 'none' : ''; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ + /** │ │ │ │ + * Method: update │ │ │ │ + * Update the overview map after layers move. │ │ │ │ + */ │ │ │ │ + update: function() { │ │ │ │ + if (this.ovmap == null) { │ │ │ │ + this.createMap(); │ │ │ │ + } │ │ │ │ │ │ │ │ - var x = ((location.x - this.featureDx) / resolution + this.left); │ │ │ │ - var y = (location.y / resolution - this.top); │ │ │ │ + if (this.autoPan || !this.isSuitableOverview()) { │ │ │ │ + this.updateOverview(); │ │ │ │ + } │ │ │ │ │ │ │ │ - var suffix = (drawOutline) ? this.LABEL_OUTLINE_SUFFIX : this.LABEL_ID_SUFFIX; │ │ │ │ - var label = this.nodeFactory(featureId + suffix, "text"); │ │ │ │ + // update extent rectangle │ │ │ │ + this.updateRectToMap(); │ │ │ │ + }, │ │ │ │ │ │ │ │ - label.setAttributeNS(null, "x", x); │ │ │ │ - label.setAttributeNS(null, "y", -y); │ │ │ │ + /** │ │ │ │ + * Method: isSuitableOverview │ │ │ │ + * Determines if the overview map is suitable given the extent and │ │ │ │ + * resolution of the main map. │ │ │ │ + */ │ │ │ │ + isSuitableOverview: function() { │ │ │ │ + var mapExtent = this.map.getExtent(); │ │ │ │ + var maxExtent = this.map.getMaxExtent(); │ │ │ │ + var testExtent = new OpenLayers.Bounds( │ │ │ │ + Math.max(mapExtent.left, maxExtent.left), │ │ │ │ + Math.max(mapExtent.bottom, maxExtent.bottom), │ │ │ │ + Math.min(mapExtent.right, maxExtent.right), │ │ │ │ + Math.min(mapExtent.top, maxExtent.top)); │ │ │ │ │ │ │ │ - if (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 (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + testExtent = testExtent.transform( │ │ │ │ + this.map.getProjectionObject(), │ │ │ │ + this.ovmap.getProjectionObject()); │ │ │ │ } │ │ │ │ - if (style.fontStyle) { │ │ │ │ - label.setAttributeNS(null, "font-style", style.fontStyle); │ │ │ │ + │ │ │ │ + var resRatio = this.ovmap.getResolution() / this.map.getResolution(); │ │ │ │ + return ((resRatio > this.minRatio) && │ │ │ │ + (resRatio <= this.maxRatio) && │ │ │ │ + (this.ovmap.getExtent().containsBounds(testExtent))); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method updateOverview │ │ │ │ + * Called by <update> if <isSuitableOverview> returns true │ │ │ │ + */ │ │ │ │ + updateOverview: function() { │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ + var targetRes = this.ovmap.getResolution(); │ │ │ │ + var resRatio = targetRes / mapRes; │ │ │ │ + if (resRatio > this.maxRatio) { │ │ │ │ + // zoom in overview map │ │ │ │ + targetRes = this.minRatio * mapRes; │ │ │ │ + } else if (resRatio <= this.minRatio) { │ │ │ │ + // zoom out overview map │ │ │ │ + targetRes = this.maxRatio * mapRes; │ │ │ │ } │ │ │ │ - if (style.labelSelect === true) { │ │ │ │ - label.setAttributeNS(null, "pointer-events", "visible"); │ │ │ │ - label._featureId = featureId; │ │ │ │ + var center; │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + center = this.map.center.clone(); │ │ │ │ + center.transform(this.map.getProjectionObject(), │ │ │ │ + this.ovmap.getProjectionObject()); │ │ │ │ } else { │ │ │ │ - label.setAttributeNS(null, "pointer-events", "none"); │ │ │ │ + center = this.map.center; │ │ │ │ } │ │ │ │ - var align = style.labelAlign || OpenLayers.Renderer.defaultSymbolizer.labelAlign; │ │ │ │ - label.setAttributeNS(null, "text-anchor", │ │ │ │ - OpenLayers.Renderer.SVG.LABEL_ALIGN[align[0]] || "middle"); │ │ │ │ + this.ovmap.setCenter(center, this.ovmap.getZoomForResolution( │ │ │ │ + targetRes * this.resolutionFactor)); │ │ │ │ + this.updateRectToMap(); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (OpenLayers.IS_GECKO === true) { │ │ │ │ - label.setAttributeNS(null, "dominant-baseline", │ │ │ │ - OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]] || "central"); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Method: createMap │ │ │ │ + * Construct the map that this control contains │ │ │ │ + */ │ │ │ │ + createMap: function() { │ │ │ │ + // create the overview map │ │ │ │ + var options = OpenLayers.Util.extend({ │ │ │ │ + controls: [], │ │ │ │ + maxResolution: 'auto', │ │ │ │ + fallThrough: false │ │ │ │ + }, this.mapOptions); │ │ │ │ + this.ovmap = new OpenLayers.Map(this.mapDiv, options); │ │ │ │ + this.ovmap.viewPortDiv.appendChild(this.extentRectangle); │ │ │ │ │ │ │ │ - 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; │ │ │ │ + // prevent ovmap from being destroyed when the page unloads, because │ │ │ │ + // the OverviewMap control has to do this (and does it). │ │ │ │ + OpenLayers.Event.stopObserving(window, 'unload', this.ovmap.unloadDestroy); │ │ │ │ + │ │ │ │ + this.ovmap.addLayers(this.layers); │ │ │ │ + this.ovmap.zoomToMaxExtent(); │ │ │ │ + // check extent rectangle border width │ │ │ │ + this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ + 'border-left-width')) + │ │ │ │ + parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ + 'border-right-width')); │ │ │ │ + this.wComp = (this.wComp) ? this.wComp : 2; │ │ │ │ + this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ + 'border-top-width')) + │ │ │ │ + parseInt(OpenLayers.Element.getStyle(this.extentRectangle, │ │ │ │ + 'border-bottom-width')); │ │ │ │ + this.hComp = (this.hComp) ? this.hComp : 2; │ │ │ │ + │ │ │ │ + this.handlers.drag = new OpenLayers.Handler.Drag( │ │ │ │ + this, { │ │ │ │ + move: this.rectDrag, │ │ │ │ + done: this.updateMapToRect │ │ │ │ + }, { │ │ │ │ + map: this.ovmap │ │ │ │ } │ │ │ │ - if (OpenLayers.IS_GECKO === false) { │ │ │ │ - tspan.setAttributeNS(null, "baseline-shift", │ │ │ │ - OpenLayers.Renderer.SVG.LABEL_VSHIFT[align[1]] || "-35%"); │ │ │ │ + ); │ │ │ │ + this.handlers.click = new OpenLayers.Handler.Click( │ │ │ │ + this, { │ │ │ │ + "click": this.mapDivClick │ │ │ │ + }, { │ │ │ │ + "single": true, │ │ │ │ + "double": false, │ │ │ │ + "stopSingle": true, │ │ │ │ + "stopDouble": true, │ │ │ │ + "pixelTolerance": 1, │ │ │ │ + map: this.ovmap │ │ │ │ } │ │ │ │ - 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"); │ │ │ │ + ); │ │ │ │ + this.handlers.click.activate(); │ │ │ │ + │ │ │ │ + this.rectEvents = new OpenLayers.Events(this, this.extentRectangle, │ │ │ │ + null, true); │ │ │ │ + this.rectEvents.register("mouseover", this, function(e) { │ │ │ │ + if (!this.handlers.drag.active && !this.map.dragging) { │ │ │ │ + this.handlers.drag.activate(); │ │ │ │ } │ │ │ │ - tspan.textContent = (labelRows[i] === '') ? ' ' : labelRows[i]; │ │ │ │ - if (!tspan.parentNode) { │ │ │ │ - label.appendChild(tspan); │ │ │ │ + }); │ │ │ │ + this.rectEvents.register("mouseout", this, function(e) { │ │ │ │ + if (!this.handlers.drag.dragging) { │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ } │ │ │ │ - } │ │ │ │ + }); │ │ │ │ │ │ │ │ - if (!label.parentNode) { │ │ │ │ - this.textRoot.appendChild(label); │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + var sourceUnits = this.map.getProjectionObject().getUnits() || │ │ │ │ + this.map.units || this.map.baseLayer.units; │ │ │ │ + var targetUnits = this.ovmap.getProjectionObject().getUnits() || │ │ │ │ + this.ovmap.units || this.ovmap.baseLayer.units; │ │ │ │ + this.resolutionFactor = sourceUnits && targetUnits ? │ │ │ │ + OpenLayers.INCHES_PER_UNIT[sourceUnits] / │ │ │ │ + OpenLayers.INCHES_PER_UNIT[targetUnits] : 1; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: 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) │ │ │ │ + /** │ │ │ │ + * Method: updateRectToMap │ │ │ │ + * Updates the extent rectangle position and size to match the map extent │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + updateRectToMap: function() { │ │ │ │ + // If the projections differ we need to reproject │ │ │ │ + var bounds; │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + bounds = this.map.getExtent().transform( │ │ │ │ + this.map.getProjectionObject(), │ │ │ │ + this.ovmap.getProjectionObject()); │ │ │ │ + } else { │ │ │ │ + bounds = this.map.getExtent(); │ │ │ │ + } │ │ │ │ + var pxBounds = this.getRectBoundsFromMapBounds(bounds); │ │ │ │ + if (pxBounds) { │ │ │ │ + this.setRectPxBounds(pxBounds); │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - return { │ │ │ │ - path: strings.join(separator || ","), │ │ │ │ - complete: complete │ │ │ │ - }; │ │ │ │ + /** │ │ │ │ + * Method: updateMapToRect │ │ │ │ + * Updates the map extent to match the extent rectangle position and size │ │ │ │ + */ │ │ │ │ + updateMapToRect: function() { │ │ │ │ + var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds); │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + lonLatBounds = lonLatBounds.transform( │ │ │ │ + this.ovmap.getProjectionObject(), │ │ │ │ + this.map.getProjectionObject()); │ │ │ │ + } │ │ │ │ + this.map.panTo(lonLatBounds.getCenterLonLat()); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: 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. │ │ │ │ - * │ │ │ │ + * Method: setRectPxBounds │ │ │ │ + * Set extent rectangle pixel bounds. │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * pxBounds - {<OpenLayers.Bounds>} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + setRectPxBounds: function(pxBounds) { │ │ │ │ + var top = Math.max(pxBounds.top, 0); │ │ │ │ + var left = Math.max(pxBounds.left, 0); │ │ │ │ + var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()), │ │ │ │ + this.ovmap.size.h - this.hComp); │ │ │ │ + var right = Math.min(pxBounds.left + pxBounds.getWidth(), │ │ │ │ + this.ovmap.size.w - this.wComp); │ │ │ │ + var width = Math.max(right - left, 0); │ │ │ │ + var height = Math.max(bottom - top, 0); │ │ │ │ + if (width < this.minRectSize || height < this.minRectSize) { │ │ │ │ + this.extentRectangle.className = this.displayClass + │ │ │ │ + this.minRectDisplayClass; │ │ │ │ + var rLeft = left + (width / 2) - (this.minRectSize / 2); │ │ │ │ + var rTop = top + (height / 2) - (this.minRectSize / 2); │ │ │ │ + this.extentRectangle.style.top = Math.round(rTop) + 'px'; │ │ │ │ + this.extentRectangle.style.left = Math.round(rLeft) + 'px'; │ │ │ │ + this.extentRectangle.style.height = this.minRectSize + 'px'; │ │ │ │ + this.extentRectangle.style.width = this.minRectSize + 'px'; │ │ │ │ + } else { │ │ │ │ + this.extentRectangle.className = this.displayClass + │ │ │ │ + 'ExtentRectangle'; │ │ │ │ + this.extentRectangle.style.top = Math.round(top) + 'px'; │ │ │ │ + this.extentRectangle.style.left = Math.round(left) + 'px'; │ │ │ │ + this.extentRectangle.style.height = Math.round(height) + 'px'; │ │ │ │ + this.extentRectangle.style.width = Math.round(width) + 'px'; │ │ │ │ } │ │ │ │ - return x2 + "," + y2; │ │ │ │ + this.rectPxBounds = new OpenLayers.Bounds( │ │ │ │ + Math.round(left), Math.round(bottom), │ │ │ │ + Math.round(right), Math.round(top) │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: getShortString │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: getRectBoundsFromMapBounds │ │ │ │ + * Get the rect bounds from the map bounds. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * point - {<OpenLayers.Geometry.Point>} │ │ │ │ - * │ │ │ │ + * lonLatBounds - {<OpenLayers.Bounds>} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {String} or false if point is outside the valid range │ │ │ │ + * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent │ │ │ │ + * translated into pixel bounds for the overview map │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + getRectBoundsFromMapBounds: function(lonLatBounds) { │ │ │ │ + var leftBottomPx = this.getOverviewPxFromLonLat({ │ │ │ │ + lon: lonLatBounds.left, │ │ │ │ + lat: lonLatBounds.bottom │ │ │ │ + }); │ │ │ │ + var rightTopPx = this.getOverviewPxFromLonLat({ │ │ │ │ + lon: lonLatBounds.right, │ │ │ │ + lat: lonLatBounds.top │ │ │ │ + }); │ │ │ │ + var bounds = null; │ │ │ │ + if (leftBottomPx && rightTopPx) { │ │ │ │ + bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y, │ │ │ │ + rightTopPx.x, rightTopPx.y); │ │ │ │ } │ │ │ │ + return bounds; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getPosition │ │ │ │ - * Finds the position of an svg node. │ │ │ │ - * │ │ │ │ + * Method: getMapBoundsFromRectBounds │ │ │ │ + * Get the map bounds from the rect bounds. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * │ │ │ │ + * pxBounds - {<OpenLayers.Bounds>} │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} hash with x and y properties, representing the coordinates │ │ │ │ - * within the svg coordinate system │ │ │ │ + * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds │ │ │ │ + * translated into lon/lat bounds for the overview map │ │ │ │ */ │ │ │ │ - getPosition: function(node) { │ │ │ │ - return ({ │ │ │ │ - x: parseFloat(node.getAttributeNS(null, "cx")), │ │ │ │ - y: parseFloat(node.getAttributeNS(null, "cy")) │ │ │ │ + getMapBoundsFromRectBounds: function(pxBounds) { │ │ │ │ + var leftBottomLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ + x: pxBounds.left, │ │ │ │ + y: pxBounds.bottom │ │ │ │ + }); │ │ │ │ + var rightTopLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ + x: pxBounds.right, │ │ │ │ + y: pxBounds.top │ │ │ │ }); │ │ │ │ + return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat, │ │ │ │ + rightTopLonLat.lon, rightTopLonLat.lat); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: importSymbol │ │ │ │ - * add a new symbol definition from the rendererer's symbol hash │ │ │ │ - * │ │ │ │ + * Method: getLonLatFromOverviewPx │ │ │ │ + * Get a map location from a pixel location │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * graphicName - {String} name of the symbol to import │ │ │ │ - * │ │ │ │ + * overviewMapPx - {<OpenLayers.Pixel>|Object} OpenLayers.Pixel or │ │ │ │ + * an object with a │ │ │ │ + * 'x' and 'y' properties. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} - the imported symbol │ │ │ │ + * {Object} Location which is the passed-in overview map │ │ │ │ + * OpenLayers.Pixel, translated into lon/lat by the overview │ │ │ │ + * map. An object with a 'lon' and 'lat' properties. │ │ │ │ */ │ │ │ │ - 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(" ")); │ │ │ │ + getLonLatFromOverviewPx: function(overviewMapPx) { │ │ │ │ + var size = this.ovmap.size; │ │ │ │ + var res = this.ovmap.getResolution(); │ │ │ │ + var center = this.ovmap.getExtent().getCenterLonLat(); │ │ │ │ │ │ │ │ - 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 │ │ │ │ - ]; │ │ │ │ + var deltaX = overviewMapPx.x - (size.w / 2); │ │ │ │ + var deltaY = overviewMapPx.y - (size.h / 2); │ │ │ │ │ │ │ │ - this.defs.appendChild(symbolNode); │ │ │ │ - return symbolNode; │ │ │ │ + return { │ │ │ │ + lon: center.lon + deltaX * res, │ │ │ │ + lat: center.lat - deltaY * res │ │ │ │ + }; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getFeatureIdFromEvent │ │ │ │ - * │ │ │ │ + * Method: getOverviewPxFromLonLat │ │ │ │ + * Get a pixel location from a map location │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * evt - {Object} An <OpenLayers.Event> object │ │ │ │ + * lonlat - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an │ │ │ │ + * object with a 'lon' and 'lat' properties. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} A feature id or undefined. │ │ │ │ + * {Object} Location which is the passed-in OpenLayers.LonLat, │ │ │ │ + * translated into overview map pixels │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + getOverviewPxFromLonLat: function(lonlat) { │ │ │ │ + var res = this.ovmap.getResolution(); │ │ │ │ + var extent = this.ovmap.getExtent(); │ │ │ │ + if (extent) { │ │ │ │ + return { │ │ │ │ + x: Math.round(1 / res * (lonlat.lon - extent.left)), │ │ │ │ + y: Math.round(1 / res * (extent.top - lonlat.lat)) │ │ │ │ + }; │ │ │ │ } │ │ │ │ - return featureId; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.SVG" │ │ │ │ + CLASS_NAME: 'OpenLayers.Control.OverviewMap' │ │ │ │ }); │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * 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/Renderer/Canvas.js │ │ │ │ + OpenLayers/Control/Measure.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 │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Renderer.Canvas │ │ │ │ - * A renderer based on the 2D 'canvas' drawing element. │ │ │ │ - * │ │ │ │ - * Inherits: │ │ │ │ - * - <OpenLayers.Renderer> │ │ │ │ + * Class: OpenLayers.Control.Measure │ │ │ │ + * Allows for drawing of features for measurements. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ +OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: hitDetection │ │ │ │ - * {Boolean} Allow for hit detection of features. Default is true. │ │ │ │ + * 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>): │ │ │ │ + * measure - Triggered when a measurement sketch is complete. Listeners │ │ │ │ + * will receive an event with measure, units, order, and geometry │ │ │ │ + * properties. │ │ │ │ + * measurepartial - Triggered when a new point is added to the │ │ │ │ + * measurement sketch or if the <immediate> property is true and the │ │ │ │ + * measurement sketch is modified. Listeners receive an event with measure, │ │ │ │ + * units, order, and geometry. │ │ │ │ */ │ │ │ │ - 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). │ │ │ │ + * APIProperty: handlerOptions │ │ │ │ + * {Object} Used to set non-default properties on the control's handler │ │ │ │ */ │ │ │ │ - hitOverflow: 0, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: canvas │ │ │ │ - * {Canvas} The canvas context object. │ │ │ │ + * Property: callbacks │ │ │ │ + * {Object} The functions that are sent to the handler for callback │ │ │ │ */ │ │ │ │ - canvas: null, │ │ │ │ + callbacks: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: features │ │ │ │ - * {Object} Internal object of feature/style pairs for use in redrawing the layer. │ │ │ │ + * APIProperty: displaySystem │ │ │ │ + * {String} Display system for output measurements. Supported values │ │ │ │ + * are 'english', 'metric', and 'geographic'. Default is 'metric'. │ │ │ │ */ │ │ │ │ - features: null, │ │ │ │ + displaySystem: 'metric', │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: pendingRedraw │ │ │ │ - * {Boolean} The renderer needs a redraw call to render features added while │ │ │ │ - * the renderer was locked. │ │ │ │ + * APIProperty: geodesic │ │ │ │ + * {Boolean} Calculate geodesic metrics instead of planar metrics. This │ │ │ │ + * requires that geometries can be transformed into Geographic/WGS84 │ │ │ │ + * (if that is not already the map projection). Default is false. │ │ │ │ */ │ │ │ │ - pendingRedraw: false, │ │ │ │ + geodesic: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: cachedSymbolBounds │ │ │ │ - * {Object} Internal cache of calculated symbol extents. │ │ │ │ + * Property: displaySystemUnits │ │ │ │ + * {Object} Units for various measurement systems. Values are arrays │ │ │ │ + * of unit abbreviations (from OpenLayers.INCHES_PER_UNIT) in decreasing │ │ │ │ + * order of length. │ │ │ │ */ │ │ │ │ - cachedSymbolBounds: {}, │ │ │ │ + displaySystemUnits: { │ │ │ │ + geographic: ['dd'], │ │ │ │ + english: ['mi', 'ft', 'in'], │ │ │ │ + metric: ['km', 'm'] │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Renderer.Canvas │ │ │ │ + * Property: delay │ │ │ │ + * {Number} Number of milliseconds between clicks before the event is │ │ │ │ + * considered a double-click. The "measurepartial" event will not │ │ │ │ + * be triggered if the sketch is completed within this time. This │ │ │ │ + * is required for IE where creating a browser reflow (if a listener │ │ │ │ + * is modifying the DOM by displaying the measurement values) messes │ │ │ │ + * with the dblclick listener in the sketch handler. │ │ │ │ + */ │ │ │ │ + partialDelay: 300, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: delayedTrigger │ │ │ │ + * {Number} Timeout id of trigger for measurepartial. │ │ │ │ + */ │ │ │ │ + delayedTrigger: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: persist │ │ │ │ + * {Boolean} Keep the temporary measurement sketch drawn after the │ │ │ │ + * measurement is complete. The geometry will persist until a new │ │ │ │ + * measurement is started, the control is deactivated, or <cancel> is │ │ │ │ + * called. │ │ │ │ + */ │ │ │ │ + persist: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: immediate │ │ │ │ + * {Boolean} Activates the immediate measurement so that the "measurepartial" │ │ │ │ + * event is also fired once the measurement sketch is modified. │ │ │ │ + * Default is false. │ │ │ │ + */ │ │ │ │ + immediate: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.Measure │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * containerID - {<String>} │ │ │ │ - * options - {Object} Optional properties to be set on the renderer. │ │ │ │ + * handler - {<OpenLayers.Handler>} │ │ │ │ + * options - {Object} │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ + initialize: function(handler, options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + var callbacks = { │ │ │ │ + done: this.measureComplete, │ │ │ │ + point: this.measurePartial │ │ │ │ + }; │ │ │ │ + if (this.immediate) { │ │ │ │ + callbacks.modify = this.measureImmediate; │ │ │ │ } │ │ │ │ + this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks); │ │ │ │ + │ │ │ │ + // let the handler options override, so old code that passes 'persist' │ │ │ │ + // directly to the handler does not need an update │ │ │ │ + this.handlerOptions = OpenLayers.Util.extend({ │ │ │ │ + persist: this.persist │ │ │ │ + }, this.handlerOptions); │ │ │ │ + this.handler = new handler(this, this.callbacks, this.handlerOptions); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setExtent │ │ │ │ - * Set the visible part of the layer. │ │ │ │ + * APIMethod: deactivate │ │ │ │ + */ │ │ │ │ + deactivate: function() { │ │ │ │ + this.cancelDelay(); │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: cancel │ │ │ │ + * Stop the control from measuring. If <persist> is true, the temporary │ │ │ │ + * sketch will be erased. │ │ │ │ + */ │ │ │ │ + cancel: function() { │ │ │ │ + this.cancelDelay(); │ │ │ │ + this.handler.cancel(); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: setImmediate │ │ │ │ + * Sets the <immediate> property. Changes the activity of immediate │ │ │ │ + * measurement. │ │ │ │ + */ │ │ │ │ + setImmediate: function(immediate) { │ │ │ │ + this.immediate = immediate; │ │ │ │ + if (this.immediate) { │ │ │ │ + this.callbacks.modify = this.measureImmediate; │ │ │ │ + } else { │ │ │ │ + delete this.callbacks.modify; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: updateHandler │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * handler - {Function} One of the sketch handler constructors. │ │ │ │ + * options - {Object} Options for the handler. │ │ │ │ */ │ │ │ │ - setExtent: function() { │ │ │ │ - OpenLayers.Renderer.prototype.setExtent.apply(this, arguments); │ │ │ │ - // always redraw features │ │ │ │ - return false; │ │ │ │ + updateHandler: function(handler, options) { │ │ │ │ + var active = this.active; │ │ │ │ + if (active) { │ │ │ │ + this.deactivate(); │ │ │ │ + } │ │ │ │ + this.handler = new handler(this, this.callbacks, options); │ │ │ │ + if (active) { │ │ │ │ + this.activate(); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: measureComplete │ │ │ │ + * Called when the measurement sketch is done. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * featureId - {String} │ │ │ │ */ │ │ │ │ - eraseGeometry: function(geometry, featureId) { │ │ │ │ - this.eraseFeatures(this.features[featureId][0]); │ │ │ │ + measureComplete: function(geometry) { │ │ │ │ + this.cancelDelay(); │ │ │ │ + this.measure(geometry, "measure"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: supported │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the browser supports the renderer class │ │ │ │ + * Method: measurePartial │ │ │ │ + * Called each time a new point is added to the measurement sketch. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} The last point added. │ │ │ │ + * geometry - {<OpenLayers.Geometry>} The sketch geometry. │ │ │ │ */ │ │ │ │ - supported: function() { │ │ │ │ - return OpenLayers.CANVAS_SUPPORTED; │ │ │ │ + measurePartial: function(point, geometry) { │ │ │ │ + this.cancelDelay(); │ │ │ │ + geometry = geometry.clone(); │ │ │ │ + // when we're wating for a dblclick, we have to trigger measurepartial │ │ │ │ + // after some delay to deal with reflow issues in IE │ │ │ │ + if (this.handler.freehandMode(this.handler.evt)) { │ │ │ │ + // no dblclick in freehand mode │ │ │ │ + this.measure(geometry, "measurepartial"); │ │ │ │ + } else { │ │ │ │ + this.delayedTrigger = window.setTimeout( │ │ │ │ + OpenLayers.Function.bind(function() { │ │ │ │ + this.delayedTrigger = null; │ │ │ │ + this.measure(geometry, "measurepartial"); │ │ │ │ + }, this), │ │ │ │ + this.partialDelay │ │ │ │ + ); │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setSize │ │ │ │ - * Sets the size of the drawing surface. │ │ │ │ + * Method: measureImmediate │ │ │ │ + * Called each time the measurement sketch is modified. │ │ │ │ * │ │ │ │ - * Once the size is updated, redraw the canvas. │ │ │ │ + * Parameters: │ │ │ │ + * point - {<OpenLayers.Geometry.Point>} The point at the mouse position. │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The sketch feature. │ │ │ │ + * drawing - {Boolean} Indicates whether we're currently drawing. │ │ │ │ + */ │ │ │ │ + measureImmediate: function(point, feature, drawing) { │ │ │ │ + if (drawing && !this.handler.freehandMode(this.handler.evt)) { │ │ │ │ + this.cancelDelay(); │ │ │ │ + this.measure(feature.geometry, "measurepartial"); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: cancelDelay │ │ │ │ + * Cancels the delay measurement that measurePartial began. │ │ │ │ + */ │ │ │ │ + cancelDelay: function() { │ │ │ │ + if (this.delayedTrigger !== null) { │ │ │ │ + window.clearTimeout(this.delayedTrigger); │ │ │ │ + this.delayedTrigger = null; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: measure │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * size - {<OpenLayers.Size>} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * eventType - {String} │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + measure: function(geometry, eventType) { │ │ │ │ + var stat, order; │ │ │ │ + if (geometry.CLASS_NAME.indexOf('LineString') > -1) { │ │ │ │ + stat = this.getBestLength(geometry); │ │ │ │ + order = 1; │ │ │ │ + } else { │ │ │ │ + stat = this.getBestArea(geometry); │ │ │ │ + order = 2; │ │ │ │ } │ │ │ │ + this.events.triggerEvent(eventType, { │ │ │ │ + measure: stat[0], │ │ │ │ + units: stat[1], │ │ │ │ + order: order, │ │ │ │ + geometry: geometry │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawFeature │ │ │ │ - * Draw the feature. Stores the feature in the features list, │ │ │ │ - * then redraws the layer. │ │ │ │ + * Method: getBestArea │ │ │ │ + * Based on the <displaySystem> returns the area of a geometry. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - * style - {<Object>} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ * │ │ │ │ * 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. │ │ │ │ + * {Array([Float, String])} Returns a two item array containing the │ │ │ │ + * area and the units abbreviation. │ │ │ │ */ │ │ │ │ - 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(); │ │ │ │ + getBestArea: function(geometry) { │ │ │ │ + var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ + var unit, area; │ │ │ │ + for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ + unit = units[i]; │ │ │ │ + area = this.getArea(geometry, unit); │ │ │ │ + if (area > 1) { │ │ │ │ + break; │ │ │ │ } │ │ │ │ + } │ │ │ │ + return [area, unit]; │ │ │ │ + }, │ │ │ │ │ │ │ │ - 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; │ │ │ │ + /** │ │ │ │ + * Method: getArea │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * units - {String} Unit abbreviation │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Float} The geometry area in the given units. │ │ │ │ + */ │ │ │ │ + getArea: function(geometry, units) { │ │ │ │ + var area, geomUnits; │ │ │ │ + if (this.geodesic) { │ │ │ │ + area = geometry.getGeodesicArea(this.map.getProjectionObject()); │ │ │ │ + geomUnits = "m"; │ │ │ │ + } else { │ │ │ │ + area = geometry.getArea(); │ │ │ │ + geomUnits = this.map.getUnits(); │ │ │ │ } │ │ │ │ - if (this.pendingRedraw && !this.locked) { │ │ │ │ - this.redraw(); │ │ │ │ - this.pendingRedraw = false; │ │ │ │ + var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ + if (inPerDisplayUnit) { │ │ │ │ + var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ + area *= Math.pow((inPerMapUnit / inPerDisplayUnit), 2); │ │ │ │ } │ │ │ │ - return rendered; │ │ │ │ + return area; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: drawGeometry │ │ │ │ - * Used when looping (in redraw) over the features; draws │ │ │ │ - * the canvas. │ │ │ │ + /** │ │ │ │ + * Method: getBestLength │ │ │ │ + * Based on the <displaySystem> returns the length of a geometry. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array([Float, String])} Returns a two item array containing the │ │ │ │ + * length and the units abbreviation. │ │ │ │ */ │ │ │ │ - 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: │ │ │ │ + getBestLength: function(geometry) { │ │ │ │ + var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ + var unit, length; │ │ │ │ + for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ + unit = units[i]; │ │ │ │ + length = this.getLength(geometry, unit); │ │ │ │ + if (length > 1) { │ │ │ │ break; │ │ │ │ + } │ │ │ │ } │ │ │ │ + return [length, unit]; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawExternalGraphic │ │ │ │ - * Called to draw External graphics. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ + * Method: getLength │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ - * featureId - {String} │ │ │ │ + * units - {String} Unit abbreviation │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Float} The geometry length in the given units. │ │ │ │ */ │ │ │ │ - drawExternalGraphic: function(geometry, style, featureId) { │ │ │ │ - var img = new Image(); │ │ │ │ - │ │ │ │ - var title = style.title || style.graphicTitle; │ │ │ │ - if (title) { │ │ │ │ - img.title = title; │ │ │ │ + getLength: function(geometry, units) { │ │ │ │ + var length, geomUnits; │ │ │ │ + if (this.geodesic) { │ │ │ │ + length = geometry.getGeodesicLength(this.map.getProjectionObject()); │ │ │ │ + geomUnits = "m"; │ │ │ │ + } else { │ │ │ │ + length = geometry.getLength(); │ │ │ │ + geomUnits = this.map.getUnits(); │ │ │ │ + } │ │ │ │ + var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ + if (inPerDisplayUnit) { │ │ │ │ + var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ + length *= (inPerMapUnit / inPerDisplayUnit); │ │ │ │ } │ │ │ │ + return length; │ │ │ │ + }, │ │ │ │ │ │ │ │ - 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); │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Measure" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/ModifyFeature.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ +/* 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 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }; │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Handler/Drag.js │ │ │ │ + * @requires OpenLayers/Handler/Keyboard.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - img.onload = OpenLayers.Function.bind(onLoad, this); │ │ │ │ - img.src = style.externalGraphic; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * 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, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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} │ │ │ │ + * APIProperty: documentDrag │ │ │ │ + * {Boolean} If set to true, dragging vertices will continue even if the │ │ │ │ + * mouse cursor leaves the map viewport. Default is false. │ │ │ │ */ │ │ │ │ - drawNamedSymbol: function(geometry, style, featureId) { │ │ │ │ - var x, y, cx, cy, i, symbolBounds, scaling, angle; │ │ │ │ - var unscaledStrokeWidth; │ │ │ │ - var deg2rad = Math.PI / 180.0; │ │ │ │ + documentDrag: false, │ │ │ │ │ │ │ │ - var symbol = OpenLayers.Renderer.symbol[style.graphicName]; │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - if (!symbol) { │ │ │ │ - throw new Error(style.graphicName + ' is not a valid symbol name'); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: clickout │ │ │ │ + * {Boolean} Unselect features when clicking outside any feature. │ │ │ │ + * Default is true. │ │ │ │ + */ │ │ │ │ + clickout: true, │ │ │ │ │ │ │ │ - if (!symbol.length || symbol.length < 2) return; │ │ │ │ + /** │ │ │ │ + * APIProperty: toggle │ │ │ │ + * {Boolean} Unselect a selected feature on click. │ │ │ │ + * Default is true. │ │ │ │ + */ │ │ │ │ + toggle: true, │ │ │ │ │ │ │ │ - var pt = this.getLocalXY(geometry); │ │ │ │ - var p0 = pt[0]; │ │ │ │ - var p1 = pt[1]; │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - if (isNaN(p0) || isNaN(p1)) return; │ │ │ │ + /** │ │ │ │ + * Property: layer │ │ │ │ + * {<OpenLayers.Layer.Vector>} │ │ │ │ + */ │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ - // Use rounded line caps │ │ │ │ - this.canvas.lineCap = "round"; │ │ │ │ - this.canvas.lineJoin = "round"; │ │ │ │ + /** │ │ │ │ + * Property: feature │ │ │ │ + * {<OpenLayers.Feature.Vector>} Feature currently available for modification. │ │ │ │ + */ │ │ │ │ + feature: null, │ │ │ │ │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.lineCap = "round"; │ │ │ │ - this.hitContext.lineJoin = "round"; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: vertex │ │ │ │ + * {<OpenLayers.Feature.Vector>} Vertex currently being modified. │ │ │ │ + */ │ │ │ │ + vertex: null, │ │ │ │ │ │ │ │ - // 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; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: vertices │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} Verticies currently available │ │ │ │ + * for dragging. │ │ │ │ + */ │ │ │ │ + vertices: null, │ │ │ │ │ │ │ │ - // 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(); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: virtualVertices │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} Virtual vertices in the middle │ │ │ │ + * of each edge. │ │ │ │ + */ │ │ │ │ + virtualVertices: null, │ │ │ │ │ │ │ │ - // Step 3: place symbol at the desired location │ │ │ │ - this.canvas.translate(p0, p1); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.translate(p0, p1); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: handlers │ │ │ │ + * {Object} │ │ │ │ + */ │ │ │ │ + handlers: null, │ │ │ │ │ │ │ │ - // 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); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - // // 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); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: virtualStyle │ │ │ │ + * {Object} A symbolizer to be used for virtual vertices. │ │ │ │ + */ │ │ │ │ + virtualStyle: null, │ │ │ │ │ │ │ │ - // 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); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - // 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; │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - 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(); │ │ │ │ + /** │ │ │ │ + * APIProperty: createVertices │ │ │ │ + * {Boolean} Create new vertices by dragging the virtual vertices │ │ │ │ + * in the middle of each edge. Default is true. │ │ │ │ + */ │ │ │ │ + createVertices: true, │ │ │ │ │ │ │ │ - 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(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Property: modified │ │ │ │ + * {Boolean} The currently selected feature has been modified. │ │ │ │ + */ │ │ │ │ + modified: false, │ │ │ │ │ │ │ │ - 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(); │ │ │ │ + /** │ │ │ │ + * 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, │ │ │ │ │ │ │ │ - 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); │ │ │ │ + /** │ │ │ │ + * 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); │ │ │ │ } │ │ │ │ - this.hitContext.closePath(); │ │ │ │ - this.hitContext.stroke(); │ │ │ │ } │ │ │ │ + }; │ │ │ │ + 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, []); │ │ │ │ + }, │ │ │ │ │ │ │ │ - style.strokeWidth = unscaledStrokeWidth; │ │ │ │ - this.canvas.restore(); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.restore(); │ │ │ │ + /** │ │ │ │ + * 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; │ │ │ │ } │ │ │ │ - this.setCanvasStyle("reset"); │ │ │ │ + return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setCanvasStyle │ │ │ │ - * Prepare the canvas for drawing by setting various global settings. │ │ │ │ + * Method: beforeSelectFeature │ │ │ │ + * Called before a feature is selected. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * type - {String} one of 'stroke', 'fill', or 'reset' │ │ │ │ - * style - {Object} Symbolizer hash │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature about to be selected. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + beforeSelectFeature: function(feature) { │ │ │ │ + return this.layer.events.triggerEvent( │ │ │ │ + "beforefeaturemodified", { │ │ │ │ + feature: feature │ │ │ │ + } │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: featureIdToHex │ │ │ │ - * Convert a feature ID string into an RGB hex string. │ │ │ │ + * 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: │ │ │ │ - * featureId - {String} Feature id │ │ │ │ + * 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. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {String} RGB hex string. │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The unselected feature. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - var hex = "000000" + id.toString(16); │ │ │ │ - var len = hex.length; │ │ │ │ - hex = "#" + hex.substring(len - 6, len); │ │ │ │ - return hex; │ │ │ │ + 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: setHitContextStyle │ │ │ │ - * Prepare the hit canvas for drawing by setting various global settings. │ │ │ │ + * 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: │ │ │ │ - * type - {String} one of 'stroke', 'fill', or 'reset' │ │ │ │ - * featureId - {String} The feature id. │ │ │ │ - * symbolizer - {<OpenLayers.Symbolizer>} The symbolizer. │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The point or vertex about to be │ │ │ │ + * dragged. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ - } │ │ │ │ + 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; │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - this.hitContext.globalAlpha = 0; │ │ │ │ - this.hitContext.lineWidth = 1; │ │ │ │ + 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: drawPoint │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ - * featureId - {String} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ - } │ │ │ │ + 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: drawLineString │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ - * featureId - {String} │ │ │ │ + * Method: dragComplete │ │ │ │ + * Called by the drag handler when the feature dragging is complete. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged. │ │ │ │ */ │ │ │ │ - drawLineString: function(geometry, style, featureId) { │ │ │ │ - style = OpenLayers.Util.applyDefaults({ │ │ │ │ - fill: false │ │ │ │ - }, style); │ │ │ │ - this.drawLinearRing(geometry, style, featureId); │ │ │ │ + dragComplete: function(vertex) { │ │ │ │ + this.resetVertices(); │ │ │ │ + this.setFeatureState(); │ │ │ │ + this.onModification(this.feature); │ │ │ │ + this.layer.events.triggerEvent("featuremodified", { │ │ │ │ + feature: this.feature │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawLinearRing │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ - * featureId - {String} │ │ │ │ + * Method: setFeatureState │ │ │ │ + * Called when the feature is modified. If the current state is not │ │ │ │ + * INSERT or DELETE, the state is set to UPDATE. │ │ │ │ */ │ │ │ │ - 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"); │ │ │ │ + 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; │ │ │ │ } │ │ │ │ } │ │ │ │ - this.setCanvasStyle("reset"); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: renderPath │ │ │ │ - * Render a path with stroke and optional fill. │ │ │ │ + * Method: resetVertices │ │ │ │ */ │ │ │ │ - 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]); │ │ │ │ + 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 (type === "fill") { │ │ │ │ - context.fill(); │ │ │ │ - } else { │ │ │ │ - context.stroke(); │ │ │ │ + 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: drawPolygon │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ - * featureId - {String} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - 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"; │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ } │ │ │ │ - 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} │ │ │ │ + * Method: collectVertices │ │ │ │ + * Collect the vertices from the modifiable feature's geometry and push │ │ │ │ + * them on to the control's vertices array. │ │ │ │ */ │ │ │ │ - drawText: function(location, style) { │ │ │ │ - var pt = this.getLocalXY(location); │ │ │ │ + collectVertices: function() { │ │ │ │ + this.vertices = []; │ │ │ │ + this.virtualVertices = []; │ │ │ │ + var control = this; │ │ │ │ │ │ │ │ - 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(); │ │ │ │ + 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); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - 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"); │ │ │ │ + collectComponentVertices.call(this, this.feature.geometry); │ │ │ │ + this.layer.addFeatures(this.virtualVertices, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + this.layer.addFeatures(this.vertices, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getLocalXY │ │ │ │ - * transform geographic xy into pixel xy │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * point - {<OpenLayers.Geometry.Point>} │ │ │ │ + * Method: collectDragHandle │ │ │ │ + * Collect the drag handle for the selected geometry. │ │ │ │ */ │ │ │ │ - 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]; │ │ │ │ + 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: clear │ │ │ │ - * Clear all vectors from the renderer. │ │ │ │ + * Method: collectRadiusHandle │ │ │ │ + * Collect the radius handle for the selected geometry. │ │ │ │ */ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ + 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: getFeatureIdFromEvent │ │ │ │ - * Returns a feature id from an event on the renderer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * evt - {<OpenLayers.Event>} │ │ │ │ + * Method: setMap │ │ │ │ + * Set the map property for the control and all handlers. │ │ │ │ * │ │ │ │ - * 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. │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} The control's map. │ │ │ │ */ │ │ │ │ - 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; │ │ │ │ + setMap: function(map) { │ │ │ │ + this.handlers.drag.setMap(map); │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: eraseFeatures │ │ │ │ - * This is called by the layer to erase features; removes the feature from │ │ │ │ - * the list, then redraws the layer. │ │ │ │ + * Method: handleMapEvents │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ + * evt - {Object} │ │ │ │ */ │ │ │ │ - eraseFeatures: function(features) { │ │ │ │ - if (!(OpenLayers.Util.isArray(features))) { │ │ │ │ - features = [features]; │ │ │ │ - } │ │ │ │ - for (var i = 0; i < features.length; ++i) { │ │ │ │ - delete this.features[features[i].id]; │ │ │ │ + handleMapEvents: function(evt) { │ │ │ │ + if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ + this.moveLayerToTop(); │ │ │ │ } │ │ │ │ - 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. │ │ │ │ + * Method: moveLayerToTop │ │ │ │ + * Moves the layer for this handler to the top, so mouse events can reach │ │ │ │ + * it. │ │ │ │ */ │ │ │ │ - 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]); │ │ │ │ - } │ │ │ │ + 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.Renderer.Canvas" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ModifyFeature" │ │ │ │ }); │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Renderer.Canvas.LABEL_ALIGN │ │ │ │ - * {Object} │ │ │ │ + * Constant: RESHAPE │ │ │ │ + * {Integer} Constant used to make the control work in reshape mode │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.Canvas.LABEL_ALIGN = { │ │ │ │ - "l": "left", │ │ │ │ - "r": "right", │ │ │ │ - "t": "top", │ │ │ │ - "b": "bottom" │ │ │ │ -}; │ │ │ │ - │ │ │ │ +OpenLayers.Control.ModifyFeature.RESHAPE = 1; │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Renderer.Canvas.LABEL_FACTOR │ │ │ │ - * {Object} │ │ │ │ + * Constant: RESIZE │ │ │ │ + * {Integer} Constant used to make the control work in resize mode │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.Canvas.LABEL_FACTOR = { │ │ │ │ - "l": 0, │ │ │ │ - "r": -1, │ │ │ │ - "t": 0, │ │ │ │ - "b": -1 │ │ │ │ -}; │ │ │ │ - │ │ │ │ +OpenLayers.Control.ModifyFeature.RESIZE = 2; │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Constant: ROTATE │ │ │ │ + * {Integer} Constant used to make the control work in rotate mode │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.Canvas.drawImageScaleFactor = null; │ │ │ │ +OpenLayers.Control.ModifyFeature.ROTATE = 4; │ │ │ │ +/** │ │ │ │ + * Constant: DRAG │ │ │ │ + * {Integer} Constant used to make the control work in drag mode │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.ModifyFeature.DRAG = 8; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Renderer/VML.js │ │ │ │ + OpenLayers/Control/Split.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 │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Handler/Path.js │ │ │ │ + * @requires OpenLayers/Layer/Vector.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Renderer.VML │ │ │ │ - * Render vector features in browsers with VML capability. Construct a new │ │ │ │ - * VML renderer with the <OpenLayers.Renderer.VML> constructor. │ │ │ │ - * │ │ │ │ - * Note that for all calculations in this class, we use (num | 0) to truncate a │ │ │ │ - * float value to an integer. This is done because it seems that VML doesn't │ │ │ │ - * support float values. │ │ │ │ + * Class: OpenLayers.Control.Split │ │ │ │ + * Acts as a split feature agent while editing vector features. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Renderer.Elements> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ +OpenLayers.Control.Split = 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>): │ │ │ │ + * beforesplit - Triggered before a split occurs. Listeners receive an │ │ │ │ + * event object with *source* and *target* properties. │ │ │ │ + * split - Triggered when a split occurs. Listeners receive an event with │ │ │ │ + * an *original* property and a *features* property. The original │ │ │ │ + * is a reference to the target feature that the sketch or modified │ │ │ │ + * feature intersects. The features property is a list of all features │ │ │ │ + * that result from this single split. This event is triggered before │ │ │ │ + * the resulting features are added to the layer (while the layer still │ │ │ │ + * has a reference to the original). │ │ │ │ + * aftersplit - Triggered after all splits resulting from a single sketch │ │ │ │ + * or feature modification have occurred. The original features │ │ │ │ + * have been destroyed and features that result from the split │ │ │ │ + * have already been added to the layer. Listeners receive an event │ │ │ │ + * with a *source* and *features* property. The source references the │ │ │ │ + * sketch or modified feature used as a splitter. The features │ │ │ │ + * property is a list of all resulting features. │ │ │ │ + */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: xmlns │ │ │ │ - * {String} XML Namespace URN │ │ │ │ + * APIProperty: layer │ │ │ │ + * {<OpenLayers.Layer.Vector>} The target layer with features to be split. │ │ │ │ + * Set at construction or after construction with <setLayer>. │ │ │ │ */ │ │ │ │ - xmlns: "urn:schemas-microsoft-com:vml", │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: symbolCache │ │ │ │ - * {DOMElement} node holding symbols. This hash is keyed by symbol name, │ │ │ │ - * and each value is a hash with a "path" and an "extent" property. │ │ │ │ + * Property: source │ │ │ │ + * {<OpenLayers.Layer.Vector>} Optional source layer. Any newly created │ │ │ │ + * or modified features from this layer will be used to split features │ │ │ │ + * on the target layer. If not provided, a temporary sketch layer will │ │ │ │ + * be created. │ │ │ │ */ │ │ │ │ - symbolCache: {}, │ │ │ │ + source: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: offset │ │ │ │ - * {Object} Hash with "x" and "y" properties │ │ │ │ + * Property: sourceOptions │ │ │ │ + * {Options} If a temporary sketch layer is created, these layer options │ │ │ │ + * will be applied. │ │ │ │ */ │ │ │ │ - offset: null, │ │ │ │ + sourceOptions: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Renderer.VML │ │ │ │ - * Create a new VML renderer. │ │ │ │ + * APIProperty: tolerance │ │ │ │ + * {Number} Distance between the calculated intersection and a vertex on │ │ │ │ + * the source geometry below which the existing vertex will be used │ │ │ │ + * for the split. Default is null. │ │ │ │ + */ │ │ │ │ + tolerance: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: edge │ │ │ │ + * {Boolean} Allow splits given intersection of edges only. Default is │ │ │ │ + * true. If false, a vertex on the source must be within the │ │ │ │ + * <tolerance> distance of the calculated intersection for a split │ │ │ │ + * to occur. │ │ │ │ + */ │ │ │ │ + edge: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: deferDelete │ │ │ │ + * {Boolean} Instead of removing features from the layer, set feature │ │ │ │ + * states of split features to DELETE. This assumes a save strategy │ │ │ │ + * or other component is in charge of removing features from the │ │ │ │ + * layer. Default is false. If false, split features will be │ │ │ │ + * immediately deleted from the layer. │ │ │ │ + */ │ │ │ │ + deferDelete: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: mutual │ │ │ │ + * {Boolean} If source and target layers are the same, split source │ │ │ │ + * features and target features where they intersect. Default is │ │ │ │ + * true. If false, only target features will be split. │ │ │ │ + */ │ │ │ │ + mutual: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: targetFilter │ │ │ │ + * {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ + * to determine if a feature from the target layer is eligible for │ │ │ │ + * splitting. │ │ │ │ + */ │ │ │ │ + targetFilter: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: sourceFilter │ │ │ │ + * {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ + * to determine if a feature from the source layer is eligible for │ │ │ │ + * splitting. │ │ │ │ + */ │ │ │ │ + sourceFilter: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: handler │ │ │ │ + * {<OpenLayers.Handler.Path>} The temporary sketch handler created if │ │ │ │ + * no source layer is provided. │ │ │ │ + */ │ │ │ │ + handler: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.Split │ │ │ │ + * Creates a new split control. A control is constructed with a target │ │ │ │ + * layer and an optional source layer. While the control is active, │ │ │ │ + * creating new features or modifying existing features on the source │ │ │ │ + * layer will result in splitting any eligible features on the target │ │ │ │ + * layer. If no source layer is provided, a temporary sketch layer will │ │ │ │ + * be created to create lines for splitting features on the target. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * containerID - {String} The id for the element that contains the renderer │ │ │ │ + * options - {Object} An object containing all configuration properties for │ │ │ │ + * the control. │ │ │ │ + * │ │ │ │ + * Valid options: │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} The target layer. Features from this │ │ │ │ + * layer will be split by new or modified features on the source layer │ │ │ │ + * or temporary sketch layer. │ │ │ │ + * source - {<OpenLayers.Layer.Vector>} Optional source layer. If provided │ │ │ │ + * newly created features or modified features will be used to split │ │ │ │ + * features on the target layer. If not provided, a temporary sketch │ │ │ │ + * layer will be created for drawing lines. │ │ │ │ + * tolerance - {Number} Optional value for the distance between a source │ │ │ │ + * vertex and the calculated intersection below which the split will │ │ │ │ + * occur at the vertex. │ │ │ │ + * edge - {Boolean} Allow splits given intersection of edges only. Default │ │ │ │ + * is true. If false, a vertex on the source must be within the │ │ │ │ + * <tolerance> distance of the calculated intersection for a split │ │ │ │ + * to occur. │ │ │ │ + * mutual - {Boolean} If source and target are the same, split source │ │ │ │ + * features and target features where they intersect. Default is │ │ │ │ + * true. If false, only target features will be split. │ │ │ │ + * targetFilter - {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ + * to determine if a feature from the target layer is eligible for │ │ │ │ + * splitting. │ │ │ │ + * sourceFilter - {<OpenLayers.Filter>} Optional filter that will be evaluated │ │ │ │ + * to determine if a feature from the target layer is eligible for │ │ │ │ + * splitting. │ │ │ │ */ │ │ │ │ - initialize: function(containerID) { │ │ │ │ - if (!this.supported()) { │ │ │ │ - return; │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.options = options || {}; // TODO: this could be done by the super │ │ │ │ + │ │ │ │ + // set the source layer if provided │ │ │ │ + if (this.options.source) { │ │ │ │ + this.setSource(this.options.source); │ │ │ │ } │ │ │ │ - if (!document.namespaces.olv) { │ │ │ │ - document.namespaces.add("olv", this.xmlns); │ │ │ │ - var style = document.createStyleSheet(); │ │ │ │ - var shapes = ['shape', 'rect', 'oval', 'fill', 'stroke', 'imagedata', 'group', 'textbox']; │ │ │ │ - for (var i = 0, len = shapes.length; i < len; i++) { │ │ │ │ + }, │ │ │ │ │ │ │ │ - style.addRule('olv\\:' + shapes[i], "behavior: url(#default#VML); " + │ │ │ │ - "position: absolute; display: inline-block;"); │ │ │ │ + /** │ │ │ │ + * APIMethod: setSource │ │ │ │ + * Set the source layer for edits layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.Vector>} The new source layer layer. If │ │ │ │ + * null, a temporary sketch layer will be created. │ │ │ │ + */ │ │ │ │ + setSource: function(layer) { │ │ │ │ + if (this.active) { │ │ │ │ + this.deactivate(); │ │ │ │ + if (this.handler) { │ │ │ │ + this.handler.destroy(); │ │ │ │ + delete this.handler; │ │ │ │ } │ │ │ │ + this.source = layer; │ │ │ │ + this.activate(); │ │ │ │ + } else { │ │ │ │ + this.source = layer; │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - OpenLayers.Renderer.Elements.prototype.initialize.apply(this, │ │ │ │ - arguments); │ │ │ │ + /** │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the control. Activating the control registers listeners for │ │ │ │ + * editing related events so that during feature creation and │ │ │ │ + * modification, features in the target will be considered for │ │ │ │ + * splitting. │ │ │ │ + */ │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + if (!this.source) { │ │ │ │ + if (!this.handler) { │ │ │ │ + this.handler = new OpenLayers.Handler.Path(this, { │ │ │ │ + done: function(geometry) { │ │ │ │ + this.onSketchComplete({ │ │ │ │ + feature: new OpenLayers.Feature.Vector(geometry) │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + }, { │ │ │ │ + layerOptions: this.sourceOptions │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + this.handler.activate(); │ │ │ │ + } else if (this.source.events) { │ │ │ │ + this.source.events.on({ │ │ │ │ + sketchcomplete: this.onSketchComplete, │ │ │ │ + afterfeaturemodified: this.afterFeatureModified, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: supported │ │ │ │ - * Determine whether a browser supports this renderer. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} The browser supports the VML renderer │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the control. Deactivating the control unregisters listeners │ │ │ │ + * so feature editing may proceed without engaging the split agent. │ │ │ │ */ │ │ │ │ - supported: function() { │ │ │ │ - return !!(document.namespaces); │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + if (this.source && this.source.events) { │ │ │ │ + this.source.events.un({ │ │ │ │ + sketchcomplete: this.onSketchComplete, │ │ │ │ + afterfeaturemodified: this.afterFeatureModified, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setExtent │ │ │ │ - * Set the renderer's extent │ │ │ │ + * Method: onSketchComplete │ │ │ │ + * Registered as a listener for the sketchcomplete event on the editable │ │ │ │ + * layer. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * extent - {<OpenLayers.Bounds>} │ │ │ │ - * resolutionChanged - {Boolean} │ │ │ │ - * │ │ │ │ + * event - {Object} The sketch complete event. │ │ │ │ + * │ │ │ │ * 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. │ │ │ │ + * {Boolean} Stop the sketch from being added to the layer (it has been │ │ │ │ + * split). │ │ │ │ */ │ │ │ │ - setExtent: function(extent, resolutionChanged) { │ │ │ │ - var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments); │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ + onSketchComplete: function(event) { │ │ │ │ + this.feature = null; │ │ │ │ + return !this.considerSplit(event.feature); │ │ │ │ + }, │ │ │ │ │ │ │ │ - var left = (extent.left / resolution) | 0; │ │ │ │ - var top = (extent.top / resolution - this.size.h) | 0; │ │ │ │ - if (resolutionChanged || !this.offset) { │ │ │ │ - this.offset = { │ │ │ │ - x: left, │ │ │ │ - y: top │ │ │ │ - }; │ │ │ │ - left = 0; │ │ │ │ - top = 0; │ │ │ │ - } else { │ │ │ │ - left = left - this.offset.x; │ │ │ │ - top = top - this.offset.y; │ │ │ │ + /** │ │ │ │ + * Method: afterFeatureModified │ │ │ │ + * Registered as a listener for the afterfeaturemodified event on the │ │ │ │ + * editable layer. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * event - {Object} The after feature modified event. │ │ │ │ + */ │ │ │ │ + afterFeatureModified: function(event) { │ │ │ │ + if (event.modified) { │ │ │ │ + var feature = event.feature; │ │ │ │ + if (typeof feature.geometry.split === "function") { │ │ │ │ + this.feature = event.feature; │ │ │ │ + this.considerSplit(event.feature); │ │ │ │ + } │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - │ │ │ │ - var org = (left - this.xOffset) + " " + top; │ │ │ │ - this.root.coordorigin = org; │ │ │ │ - var roots = [this.root, this.vectorRoot, this.textRoot]; │ │ │ │ - var root; │ │ │ │ - for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ - root = roots[i]; │ │ │ │ - │ │ │ │ - var size = this.size.w + " " + this.size.h; │ │ │ │ - root.coordsize = size; │ │ │ │ - │ │ │ │ + /** │ │ │ │ + * Method: removeByGeometry │ │ │ │ + * Remove a feature from a list based on the given geometry. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * features - {Array(<OpenLayers.Feature.Vector>)} A list of features. │ │ │ │ + * geometry - {<OpenLayers.Geometry>} A geometry. │ │ │ │ + */ │ │ │ │ + removeByGeometry: function(features, geometry) { │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ + if (features[i].geometry === geometry) { │ │ │ │ + features.splice(i, 1); │ │ │ │ + break; │ │ │ │ + } │ │ │ │ } │ │ │ │ - // flip the VML display Y axis upside down so it │ │ │ │ - // matches the display Y axis of the map │ │ │ │ - this.root.style.flip = "y"; │ │ │ │ - │ │ │ │ - return coordSysUnchanged; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: setSize │ │ │ │ - * Set the size of the drawing surface │ │ │ │ + * Method: isEligible │ │ │ │ + * Test if a target feature is eligible for splitting. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * size - {<OpenLayers.Size>} the size of the drawing surface │ │ │ │ + * target - {<OpenLayers.Feature.Vector>} The target feature. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} The target is eligible for splitting. │ │ │ │ */ │ │ │ │ - setSize: function(size) { │ │ │ │ - OpenLayers.Renderer.prototype.setSize.apply(this, arguments); │ │ │ │ - │ │ │ │ - // setting width and height on all roots to avoid flicker which we │ │ │ │ - // would get with 100% width and height on child roots │ │ │ │ - var roots = [ │ │ │ │ - this.rendererRoot, │ │ │ │ - this.root, │ │ │ │ - this.vectorRoot, │ │ │ │ - this.textRoot │ │ │ │ - ]; │ │ │ │ - var w = this.size.w + "px"; │ │ │ │ - var h = this.size.h + "px"; │ │ │ │ - var root; │ │ │ │ - for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ - root = roots[i]; │ │ │ │ - root.style.width = w; │ │ │ │ - root.style.height = h; │ │ │ │ + isEligible: function(target) { │ │ │ │ + if (!target.geometry) { │ │ │ │ + return false; │ │ │ │ + } else { │ │ │ │ + return ( │ │ │ │ + target.state !== OpenLayers.State.DELETE │ │ │ │ + ) && ( │ │ │ │ + typeof target.geometry.split === "function" │ │ │ │ + ) && ( │ │ │ │ + this.feature !== target │ │ │ │ + ) && ( │ │ │ │ + !this.targetFilter || │ │ │ │ + this.targetFilter.evaluate(target.attributes) │ │ │ │ + ); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getNodeType │ │ │ │ - * Get the node type for a geometry and style │ │ │ │ + * Method: considerSplit │ │ │ │ + * Decide whether or not to split target features with the supplied │ │ │ │ + * feature. If <mutual> is true, both the source and target features │ │ │ │ + * will be split if eligible. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * style - {Object} │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The newly created or modified │ │ │ │ + * feature. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} The corresponding node type for the specified geometry │ │ │ │ + * {Boolean} The supplied feature was split (and destroyed). │ │ │ │ */ │ │ │ │ - getNodeType: function(geometry, style) { │ │ │ │ - var nodeType = null; │ │ │ │ - switch (geometry.CLASS_NAME) { │ │ │ │ - case "OpenLayers.Geometry.Point": │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - nodeType = "olv:rect"; │ │ │ │ - } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ - nodeType = "olv:shape"; │ │ │ │ + considerSplit: function(feature) { │ │ │ │ + var sourceSplit = false; │ │ │ │ + var targetSplit = false; │ │ │ │ + if (!this.sourceFilter || │ │ │ │ + this.sourceFilter.evaluate(feature.attributes)) { │ │ │ │ + var features = this.layer && this.layer.features || []; │ │ │ │ + var target, results, proceed; │ │ │ │ + var additions = [], │ │ │ │ + removals = []; │ │ │ │ + var mutual = (this.layer === this.source) && this.mutual; │ │ │ │ + var options = { │ │ │ │ + edge: this.edge, │ │ │ │ + tolerance: this.tolerance, │ │ │ │ + mutual: mutual │ │ │ │ + }; │ │ │ │ + var sourceParts = [feature.geometry]; │ │ │ │ + var targetFeature, targetParts; │ │ │ │ + var source, parts; │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ + targetFeature = features[i]; │ │ │ │ + if (this.isEligible(targetFeature)) { │ │ │ │ + targetParts = [targetFeature.geometry]; │ │ │ │ + // work through source geoms - this array may change │ │ │ │ + for (var j = 0; j < sourceParts.length; ++j) { │ │ │ │ + source = sourceParts[j]; │ │ │ │ + // work through target parts - this array may change │ │ │ │ + for (var k = 0; k < targetParts.length; ++k) { │ │ │ │ + target = targetParts[k]; │ │ │ │ + if (source.getBounds().intersectsBounds(target.getBounds())) { │ │ │ │ + results = source.split(target, options); │ │ │ │ + if (results) { │ │ │ │ + proceed = this.events.triggerEvent( │ │ │ │ + "beforesplit", { │ │ │ │ + source: feature, │ │ │ │ + target: targetFeature │ │ │ │ + } │ │ │ │ + ); │ │ │ │ + if (proceed !== false) { │ │ │ │ + if (mutual) { │ │ │ │ + parts = results[0]; │ │ │ │ + // handle parts that result from source splitting │ │ │ │ + if (parts.length > 1) { │ │ │ │ + // splice in new source parts │ │ │ │ + parts.unshift(j, 1); // add args for splice below │ │ │ │ + Array.prototype.splice.apply(sourceParts, parts); │ │ │ │ + j += parts.length - 3; │ │ │ │ + } │ │ │ │ + results = results[1]; │ │ │ │ + } │ │ │ │ + // handle parts that result from target splitting │ │ │ │ + if (results.length > 1) { │ │ │ │ + // splice in new target parts │ │ │ │ + results.unshift(k, 1); // add args for splice below │ │ │ │ + Array.prototype.splice.apply(targetParts, results); │ │ │ │ + k += results.length - 3; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (targetParts && targetParts.length > 1) { │ │ │ │ + this.geomsToFeatures(targetFeature, targetParts); │ │ │ │ + this.events.triggerEvent("split", { │ │ │ │ + original: targetFeature, │ │ │ │ + features: targetParts │ │ │ │ + }); │ │ │ │ + Array.prototype.push.apply(additions, targetParts); │ │ │ │ + removals.push(targetFeature); │ │ │ │ + targetSplit = true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (sourceParts && sourceParts.length > 1) { │ │ │ │ + this.geomsToFeatures(feature, sourceParts); │ │ │ │ + this.events.triggerEvent("split", { │ │ │ │ + original: feature, │ │ │ │ + features: sourceParts │ │ │ │ + }); │ │ │ │ + Array.prototype.push.apply(additions, sourceParts); │ │ │ │ + removals.push(feature); │ │ │ │ + sourceSplit = true; │ │ │ │ + } │ │ │ │ + if (sourceSplit || targetSplit) { │ │ │ │ + // remove and add feature events are suppressed │ │ │ │ + // listen for split event on this control instead │ │ │ │ + if (this.deferDelete) { │ │ │ │ + // Set state instead of removing. Take care to avoid │ │ │ │ + // setting delete for features that have not yet been │ │ │ │ + // inserted - those should be destroyed immediately. │ │ │ │ + var feat, destroys = []; │ │ │ │ + for (var i = 0, len = removals.length; i < len; ++i) { │ │ │ │ + feat = removals[i]; │ │ │ │ + if (feat.state === OpenLayers.State.INSERT) { │ │ │ │ + destroys.push(feat); │ │ │ │ + } else { │ │ │ │ + feat.state = OpenLayers.State.DELETE; │ │ │ │ + this.layer.drawFeature(feat); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.layer.destroyFeatures(destroys, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + for (var i = 0, len = additions.length; i < len; ++i) { │ │ │ │ + additions[i].state = OpenLayers.State.INSERT; │ │ │ │ + } │ │ │ │ } else { │ │ │ │ - nodeType = "olv:oval"; │ │ │ │ + this.layer.destroyFeatures(removals, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ } │ │ │ │ - break; │ │ │ │ - case "OpenLayers.Geometry.Rectangle": │ │ │ │ - nodeType = "olv:rect"; │ │ │ │ - break; │ │ │ │ - case "OpenLayers.Geometry.LineString": │ │ │ │ - case "OpenLayers.Geometry.LinearRing": │ │ │ │ - case "OpenLayers.Geometry.Polygon": │ │ │ │ - case "OpenLayers.Geometry.Curve": │ │ │ │ - nodeType = "olv:shape"; │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - break; │ │ │ │ + this.layer.addFeatures(additions, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + this.events.triggerEvent("aftersplit", { │ │ │ │ + source: feature, │ │ │ │ + features: additions │ │ │ │ + }); │ │ │ │ + } │ │ │ │ } │ │ │ │ - return nodeType; │ │ │ │ + return sourceSplit; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setStyle │ │ │ │ - * Use to set all the style attributes to a VML node. │ │ │ │ + * Method: geomsToFeatures │ │ │ │ + * Create new features given a template feature and a list of geometries. │ │ │ │ + * The list of geometries is modified in place. The result will be │ │ │ │ + * a list of new features. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} An VML element to decorate │ │ │ │ - * style - {Object} │ │ │ │ - * options - {Object} Currently supported options include │ │ │ │ - * 'isFilled' {Boolean} and │ │ │ │ - * 'isStroked' {Boolean} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} The feature to be cloned. │ │ │ │ + * geoms - {Array(<OpenLayers.Geometry>)} List of goemetries. This will │ │ │ │ + * become a list of new features. │ │ │ │ */ │ │ │ │ - setStyle: function(node, style, options, geometry) { │ │ │ │ - style = style || node._style; │ │ │ │ - options = options || node._options; │ │ │ │ - var fillColor = style.fillColor; │ │ │ │ - │ │ │ │ - var title = style.title || style.graphicTitle; │ │ │ │ - if (title) { │ │ │ │ - node.title = title; │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - options.isFilled = true; │ │ │ │ - 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 resolution = this.getResolution(); │ │ │ │ - var xOffset = (style.graphicXOffset != undefined) ? │ │ │ │ - style.graphicXOffset : -(0.5 * width); │ │ │ │ - var yOffset = (style.graphicYOffset != undefined) ? │ │ │ │ - style.graphicYOffset : -(0.5 * height); │ │ │ │ - │ │ │ │ - node.style.left = ((((geometry.x - this.featureDx) / resolution - this.offset.x) + xOffset) | 0) + "px"; │ │ │ │ - node.style.top = (((geometry.y / resolution - this.offset.y) - (yOffset + height)) | 0) + "px"; │ │ │ │ - node.style.width = width + "px"; │ │ │ │ - node.style.height = height + "px"; │ │ │ │ - node.style.flip = "y"; │ │ │ │ - │ │ │ │ - // modify fillColor and options for stroke styling below │ │ │ │ - fillColor = "none"; │ │ │ │ - options.isStroked = false; │ │ │ │ - } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ - var cache = this.importSymbol(style.graphicName); │ │ │ │ - node.path = cache.path; │ │ │ │ - node.coordorigin = cache.left + "," + cache.bottom; │ │ │ │ - var size = cache.size; │ │ │ │ - node.coordsize = size + "," + size; │ │ │ │ - this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ - node.style.flip = "y"; │ │ │ │ - } else { │ │ │ │ - this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ - } │ │ │ │ + geomsToFeatures: function(feature, geoms) { │ │ │ │ + var clone = feature.clone(); │ │ │ │ + delete clone.geometry; │ │ │ │ + var newFeature; │ │ │ │ + for (var i = 0, len = geoms.length; i < len; ++i) { │ │ │ │ + // turn results list from geoms to features │ │ │ │ + newFeature = clone.clone(); │ │ │ │ + newFeature.geometry = geoms[i]; │ │ │ │ + newFeature.state = OpenLayers.State.INSERT; │ │ │ │ + geoms[i] = newFeature; │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - // fill │ │ │ │ - if (options.isFilled) { │ │ │ │ - node.fillcolor = fillColor; │ │ │ │ - } else { │ │ │ │ - node.filled = "false"; │ │ │ │ + /** │ │ │ │ + * Method: destroy │ │ │ │ + * Clean up the control. │ │ │ │ + */ │ │ │ │ + destroy: function() { │ │ │ │ + if (this.active) { │ │ │ │ + this.deactivate(); // TODO: this should be handled by the super │ │ │ │ } │ │ │ │ - var fills = node.getElementsByTagName("fill"); │ │ │ │ - var fill = (fills.length == 0) ? null : fills[0]; │ │ │ │ - if (!options.isFilled) { │ │ │ │ - if (fill) { │ │ │ │ - node.removeChild(fill); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (!fill) { │ │ │ │ - fill = this.createNode('olv:fill', node.id + "_fill"); │ │ │ │ - } │ │ │ │ - fill.opacity = style.fillOpacity; │ │ │ │ - │ │ │ │ - if (node._geometryClass === "OpenLayers.Geometry.Point" && │ │ │ │ - style.externalGraphic) { │ │ │ │ - │ │ │ │ - // override fillOpacity │ │ │ │ - if (style.graphicOpacity) { │ │ │ │ - fill.opacity = style.graphicOpacity; │ │ │ │ - } │ │ │ │ + OpenLayers.Control.prototype.destroy.call(this); │ │ │ │ + }, │ │ │ │ │ │ │ │ - fill.src = style.externalGraphic; │ │ │ │ - fill.type = "frame"; │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Split" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Control/NavigationHistory.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ - fill.aspect = "atmost"; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (fill.parentNode != node) { │ │ │ │ - node.appendChild(fill); │ │ │ │ - } │ │ │ │ - } │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - // additional rendering for rotated graphics or symbols │ │ │ │ - var rotation = style.rotation; │ │ │ │ - if ((rotation !== undefined || node._rotation !== undefined)) { │ │ │ │ - node._rotation = rotation; │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ - // make the fill fully transparent, because we now have │ │ │ │ - // the graphic as imagedata element. We cannot just remove │ │ │ │ - // the fill, because this is part of the hack described │ │ │ │ - // in graphicRotate │ │ │ │ - fill.opacity = 0; │ │ │ │ - } else if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ - node.style.rotation = rotation || 0; │ │ │ │ - } │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Control/Button.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - // stroke │ │ │ │ - var strokes = node.getElementsByTagName("stroke"); │ │ │ │ - var stroke = (strokes.length == 0) ? null : strokes[0]; │ │ │ │ - if (!options.isStroked) { │ │ │ │ - node.stroked = false; │ │ │ │ - if (stroke) { │ │ │ │ - stroke.on = false; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (!stroke) { │ │ │ │ - stroke = this.createNode('olv:stroke', node.id + "_stroke"); │ │ │ │ - node.appendChild(stroke); │ │ │ │ - } │ │ │ │ - stroke.on = true; │ │ │ │ - stroke.color = style.strokeColor; │ │ │ │ - stroke.weight = style.strokeWidth + "px"; │ │ │ │ - stroke.opacity = style.strokeOpacity; │ │ │ │ - stroke.endcap = style.strokeLinecap == 'butt' ? 'flat' : │ │ │ │ - (style.strokeLinecap || 'round'); │ │ │ │ - if (style.strokeDashstyle) { │ │ │ │ - stroke.dashstyle = this.dashStyle(style); │ │ │ │ - } │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Control.NavigationHistory │ │ │ │ + * A navigation history control. This is a meta-control, that creates two │ │ │ │ + * dependent controls: <previous> and <next>. Call the trigger method │ │ │ │ + * on the <previous> and <next> controls to restore previous and next │ │ │ │ + * history states. The previous and next controls will become active │ │ │ │ + * when there are available states to restore and will become deactive │ │ │ │ + * when there are no states to restore. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ + */ │ │ │ │ +OpenLayers.Control.NavigationHistory = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ - if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ - node.style.cursor = style.cursor; │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: type │ │ │ │ + * {String} Note that this control is not intended to be added directly │ │ │ │ + * to a control panel. Instead, add the sub-controls previous and │ │ │ │ + * next. These sub-controls are button type controls that activate │ │ │ │ + * and deactivate themselves. If this parent control is added to │ │ │ │ + * a panel, it will act as a toggle. │ │ │ │ + */ │ │ │ │ + type: OpenLayers.Control.TYPE_TOGGLE, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: graphicRotate │ │ │ │ - * If a point is to be styled with externalGraphic and rotation, VML fills │ │ │ │ - * cannot be used to display the graphic, because rotation of graphic │ │ │ │ - * fills is not supported by the VML implementation of Internet Explorer. │ │ │ │ - * This method creates a olv:imagedata element inside the VML node, │ │ │ │ - * DXImageTransform.Matrix and BasicImage filters for rotation and │ │ │ │ - * opacity, and a 3-step hack to remove rendering artefacts from the │ │ │ │ - * graphic and preserve the ability of graphics to trigger events. │ │ │ │ - * Finally, OpenLayers methods are used to determine the correct │ │ │ │ - * insertion point of the rotated image, because DXImageTransform.Matrix │ │ │ │ - * does the rotation without the ability to specify a rotation center │ │ │ │ - * point. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * xOffset - {Number} rotation center relative to image, x coordinate │ │ │ │ - * yOffset - {Number} rotation center relative to image, y coordinate │ │ │ │ - * style - {Object} │ │ │ │ + * APIProperty: previous │ │ │ │ + * {<OpenLayers.Control>} A button type control whose trigger method restores │ │ │ │ + * the previous state managed by this control. │ │ │ │ */ │ │ │ │ - graphicRotate: function(node, xOffset, yOffset, style) { │ │ │ │ - var style = style || node._style; │ │ │ │ - var rotation = style.rotation || 0; │ │ │ │ + previous: null, │ │ │ │ │ │ │ │ - var aspectRatio, size; │ │ │ │ - if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ - // load the image to determine its size │ │ │ │ - var img = new Image(); │ │ │ │ - img.onreadystatechange = OpenLayers.Function.bind(function() { │ │ │ │ - if (img.readyState == "complete" || │ │ │ │ - img.readyState == "interactive") { │ │ │ │ - aspectRatio = img.width / img.height; │ │ │ │ - size = Math.max(style.pointRadius * 2, │ │ │ │ - style.graphicWidth || 0, │ │ │ │ - style.graphicHeight || 0); │ │ │ │ - xOffset = xOffset * aspectRatio; │ │ │ │ - style.graphicWidth = size * aspectRatio; │ │ │ │ - style.graphicHeight = size; │ │ │ │ - this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ - } │ │ │ │ - }, this); │ │ │ │ - img.src = style.externalGraphic; │ │ │ │ + /** │ │ │ │ + * APIProperty: previousOptions │ │ │ │ + * {Object} Set this property on the options argument of the constructor │ │ │ │ + * to set optional properties on the <previous> control. │ │ │ │ + */ │ │ │ │ + previousOptions: null, │ │ │ │ │ │ │ │ - // will be called again by the onreadystate handler │ │ │ │ - return; │ │ │ │ - } else { │ │ │ │ - size = Math.max(style.graphicWidth, style.graphicHeight); │ │ │ │ - aspectRatio = style.graphicWidth / style.graphicHeight; │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * APIProperty: next │ │ │ │ + * {<OpenLayers.Control>} A button type control whose trigger method restores │ │ │ │ + * the next state managed by this control. │ │ │ │ + */ │ │ │ │ + next: null, │ │ │ │ │ │ │ │ - var width = Math.round(style.graphicWidth || size * aspectRatio); │ │ │ │ - var height = Math.round(style.graphicHeight || size); │ │ │ │ - node.style.width = width + "px"; │ │ │ │ - node.style.height = height + "px"; │ │ │ │ + /** │ │ │ │ + * APIProperty: nextOptions │ │ │ │ + * {Object} Set this property on the options argument of the constructor │ │ │ │ + * to set optional properties on the <next> control. │ │ │ │ + */ │ │ │ │ + nextOptions: null, │ │ │ │ │ │ │ │ - // Three steps are required to remove artefacts for images with │ │ │ │ - // transparent backgrounds (resulting from using DXImageTransform │ │ │ │ - // filters on svg objects), while preserving awareness for browser │ │ │ │ - // events on images: │ │ │ │ - // - Use the fill as usual (like for unrotated images) to handle │ │ │ │ - // events │ │ │ │ - // - specify an imagedata element with the same src as the fill │ │ │ │ - // - style the imagedata element with an AlphaImageLoader filter │ │ │ │ - // with empty src │ │ │ │ - var image = document.getElementById(node.id + "_image"); │ │ │ │ - if (!image) { │ │ │ │ - image = this.createNode("olv:imagedata", node.id + "_image"); │ │ │ │ - node.appendChild(image); │ │ │ │ - } │ │ │ │ - image.style.width = width + "px"; │ │ │ │ - image.style.height = height + "px"; │ │ │ │ - image.src = style.externalGraphic; │ │ │ │ - image.style.filter = │ │ │ │ - "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + │ │ │ │ - "src='', sizingMethod='scale')"; │ │ │ │ + /** │ │ │ │ + * APIProperty: limit │ │ │ │ + * {Integer} Optional limit on the number of history items to retain. If │ │ │ │ + * null, there is no limit. Default is 50. │ │ │ │ + */ │ │ │ │ + limit: 50, │ │ │ │ │ │ │ │ - var rot = rotation * Math.PI / 180; │ │ │ │ - var sintheta = Math.sin(rot); │ │ │ │ - var costheta = Math.cos(rot); │ │ │ │ + /** │ │ │ │ + * APIProperty: autoActivate │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ + * true. │ │ │ │ + */ │ │ │ │ + autoActivate: true, │ │ │ │ │ │ │ │ - // do the rotation on the image │ │ │ │ - var filter = │ │ │ │ - "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta + │ │ │ │ - ",M12=" + (-sintheta) + ",M21=" + sintheta + ",M22=" + costheta + │ │ │ │ - ",SizingMethod='auto expand')\n"; │ │ │ │ + /** │ │ │ │ + * Property: clearOnDeactivate │ │ │ │ + * {Boolean} Clear the history when the control is deactivated. Default │ │ │ │ + * is false. │ │ │ │ + */ │ │ │ │ + clearOnDeactivate: false, │ │ │ │ │ │ │ │ - // set the opacity (needed for the imagedata) │ │ │ │ - var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ - if (opacity && opacity != 1) { │ │ │ │ - filter += │ │ │ │ - "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + │ │ │ │ - opacity + ")\n"; │ │ │ │ - } │ │ │ │ - node.style.filter = filter; │ │ │ │ + /** │ │ │ │ + * Property: registry │ │ │ │ + * {Object} An object with keys corresponding to event types. Values │ │ │ │ + * are functions that return an object representing the current state. │ │ │ │ + */ │ │ │ │ + registry: null, │ │ │ │ │ │ │ │ - // do the rotation again on a box, so we know the insertion point │ │ │ │ - var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset); │ │ │ │ - var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry(); │ │ │ │ - imgBox.rotate(style.rotation, centerPoint); │ │ │ │ - var imgBounds = imgBox.getBounds(); │ │ │ │ + /** │ │ │ │ + * Property: nextStack │ │ │ │ + * {Array} Array of items in the history. │ │ │ │ + */ │ │ │ │ + nextStack: null, │ │ │ │ │ │ │ │ - node.style.left = Math.round( │ │ │ │ - parseInt(node.style.left) + imgBounds.left) + "px"; │ │ │ │ - node.style.top = Math.round( │ │ │ │ - parseInt(node.style.top) - imgBounds.bottom) + "px"; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: previousStack │ │ │ │ + * {Array} List of items in the history. First item represents the current │ │ │ │ + * state. │ │ │ │ + */ │ │ │ │ + previousStack: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: postDraw │ │ │ │ - * Does some node postprocessing to work around browser issues: │ │ │ │ - * - Some versions of Internet Explorer seem to be unable to set fillcolor │ │ │ │ - * and strokecolor to "none" correctly before the fill node is appended │ │ │ │ - * to a visible vml node. This method takes care of that and sets │ │ │ │ - * fillcolor and strokecolor again if needed. │ │ │ │ - * - In some cases, a node won't become visible after being drawn. Setting │ │ │ │ - * style.visibility to "visible" works around that. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ + * Property: listeners │ │ │ │ + * {Object} An object containing properties corresponding to event types. │ │ │ │ + * This object is used to configure the control and is modified on │ │ │ │ + * construction. │ │ │ │ */ │ │ │ │ - postDraw: function(node) { │ │ │ │ - node.style.visibility = "visible"; │ │ │ │ - var fillColor = node._style.fillColor; │ │ │ │ - var strokeColor = node._style.strokeColor; │ │ │ │ - if (fillColor == "none" && │ │ │ │ - node.fillcolor != fillColor) { │ │ │ │ - node.fillcolor = fillColor; │ │ │ │ - } │ │ │ │ - if (strokeColor == "none" && │ │ │ │ - node.strokecolor != strokeColor) { │ │ │ │ - node.strokecolor = strokeColor; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + listeners: null, │ │ │ │ │ │ │ │ + /** │ │ │ │ + * Property: restoring │ │ │ │ + * {Boolean} Currently restoring a history state. This is set to true │ │ │ │ + * before calling restore and set to false after restore returns. │ │ │ │ + */ │ │ │ │ + restoring: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: setNodeDimension │ │ │ │ - * Get the geometry's bounds, convert it to our vml coordinate system, │ │ │ │ - * then set the node's position, size, and local coordinate system. │ │ │ │ - * │ │ │ │ + * Constructor: OpenLayers.Control.NavigationHistory │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * options - {Object} An optional object whose properties will be used │ │ │ │ + * to extend the control. │ │ │ │ */ │ │ │ │ - setNodeDimension: function(node, geometry) { │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ │ │ │ │ - var bbox = geometry.getBounds(); │ │ │ │ - if (bbox) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ + this.registry = OpenLayers.Util.extend({ │ │ │ │ + "moveend": this.getState │ │ │ │ + }, this.registry); │ │ │ │ │ │ │ │ - var scaledBox = │ │ │ │ - new OpenLayers.Bounds(((bbox.left - this.featureDx) / resolution - this.offset.x) | 0, │ │ │ │ - (bbox.bottom / resolution - this.offset.y) | 0, │ │ │ │ - ((bbox.right - this.featureDx) / resolution - this.offset.x) | 0, │ │ │ │ - (bbox.top / resolution - this.offset.y) | 0); │ │ │ │ + var previousOptions = { │ │ │ │ + trigger: OpenLayers.Function.bind(this.previousTrigger, this), │ │ │ │ + displayClass: this.displayClass + " " + this.displayClass + "Previous" │ │ │ │ + }; │ │ │ │ + OpenLayers.Util.extend(previousOptions, this.previousOptions); │ │ │ │ + this.previous = new OpenLayers.Control.Button(previousOptions); │ │ │ │ │ │ │ │ - // Set the internal coordinate system to draw the path │ │ │ │ - node.style.left = scaledBox.left + "px"; │ │ │ │ - node.style.top = scaledBox.top + "px"; │ │ │ │ - node.style.width = scaledBox.getWidth() + "px"; │ │ │ │ - node.style.height = scaledBox.getHeight() + "px"; │ │ │ │ + var nextOptions = { │ │ │ │ + trigger: OpenLayers.Function.bind(this.nextTrigger, this), │ │ │ │ + displayClass: this.displayClass + " " + this.displayClass + "Next" │ │ │ │ + }; │ │ │ │ + OpenLayers.Util.extend(nextOptions, this.nextOptions); │ │ │ │ + this.next = new OpenLayers.Control.Button(nextOptions); │ │ │ │ │ │ │ │ - node.coordorigin = scaledBox.left + " " + scaledBox.top; │ │ │ │ - node.coordsize = scaledBox.getWidth() + " " + scaledBox.getHeight(); │ │ │ │ - } │ │ │ │ + this.clear(); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: dashStyle │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: onPreviousChange │ │ │ │ + * Called when the previous history stack changes. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * style - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A VML compliant 'stroke-dasharray' value │ │ │ │ + * state - {Object} An object representing the state to be restored │ │ │ │ + * if previous is triggered again or null if no previous states remain. │ │ │ │ + * length - {Integer} The number of remaining previous states that can │ │ │ │ + * be restored. │ │ │ │ */ │ │ │ │ - dashStyle: function(style) { │ │ │ │ - var dash = style.strokeDashstyle; │ │ │ │ - switch (dash) { │ │ │ │ - case 'solid': │ │ │ │ - case 'dot': │ │ │ │ - case 'dash': │ │ │ │ - case 'dashdot': │ │ │ │ - case 'longdash': │ │ │ │ - case 'longdashdot': │ │ │ │ - return dash; │ │ │ │ - default: │ │ │ │ - // very basic guessing of dash style patterns │ │ │ │ - var parts = dash.split(/[ ,]/); │ │ │ │ - if (parts.length == 2) { │ │ │ │ - if (1 * parts[0] >= 2 * parts[1]) { │ │ │ │ - return "longdash"; │ │ │ │ - } │ │ │ │ - return (parts[0] == 1 || parts[1] == 1) ? "dot" : "dash"; │ │ │ │ - } else if (parts.length == 4) { │ │ │ │ - return (1 * parts[0] >= 2 * parts[1]) ? "longdashdot" : │ │ │ │ - "dashdot"; │ │ │ │ - } │ │ │ │ - return "solid"; │ │ │ │ + onPreviousChange: function(state, length) { │ │ │ │ + if (state && !this.previous.active) { │ │ │ │ + this.previous.activate(); │ │ │ │ + } else if (!state && this.previous.active) { │ │ │ │ + this.previous.deactivate(); │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createNode │ │ │ │ - * Create a new node │ │ │ │ + * Method: onNextChange │ │ │ │ + * Called when the next history stack changes. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * type - {String} Kind of node to draw │ │ │ │ - * id - {String} Id for node │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A new node of the given type and id │ │ │ │ + * state - {Object} An object representing the state to be restored │ │ │ │ + * if next is triggered again or null if no next states remain. │ │ │ │ + * length - {Integer} The number of remaining next states that can │ │ │ │ + * be restored. │ │ │ │ */ │ │ │ │ - createNode: function(type, id) { │ │ │ │ - var node = document.createElement(type); │ │ │ │ - if (id) { │ │ │ │ - node.id = id; │ │ │ │ + onNextChange: function(state, length) { │ │ │ │ + if (state && !this.next.active) { │ │ │ │ + this.next.activate(); │ │ │ │ + } else if (!state && this.next.active) { │ │ │ │ + this.next.deactivate(); │ │ │ │ } │ │ │ │ - │ │ │ │ - // IE hack to make elements unselectable, to prevent 'blue flash' │ │ │ │ - // while dragging vectors; #1410 │ │ │ │ - node.unselectable = 'on'; │ │ │ │ - node.onselectstart = OpenLayers.Function.False; │ │ │ │ - │ │ │ │ - return node; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: nodeTypeCompare │ │ │ │ - * Determine whether a node is of a given type │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} An VML element │ │ │ │ - * type - {String} Kind of node │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} Whether or not the specified node is of the specified type │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Destroy the control. │ │ │ │ */ │ │ │ │ - nodeTypeCompare: function(node, type) { │ │ │ │ - │ │ │ │ - //split type │ │ │ │ - var subType = type; │ │ │ │ - var splitIndex = subType.indexOf(":"); │ │ │ │ - if (splitIndex != -1) { │ │ │ │ - subType = subType.substr(splitIndex + 1); │ │ │ │ - } │ │ │ │ - │ │ │ │ - //split nodeName │ │ │ │ - var nodeName = node.nodeName; │ │ │ │ - splitIndex = nodeName.indexOf(":"); │ │ │ │ - if (splitIndex != -1) { │ │ │ │ - nodeName = nodeName.substr(splitIndex + 1); │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this); │ │ │ │ + this.previous.destroy(); │ │ │ │ + this.next.destroy(); │ │ │ │ + this.deactivate(); │ │ │ │ + for (var prop in this) { │ │ │ │ + this[prop] = null; │ │ │ │ } │ │ │ │ - │ │ │ │ - return (subType == nodeName); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: createRenderRoot │ │ │ │ - * Create the renderer root │ │ │ │ + /** │ │ │ │ + * Method: setMap │ │ │ │ + * Set the map property for the control and <previous> and <next> child │ │ │ │ + * controls. │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} The specific render engine's root element │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ */ │ │ │ │ - createRenderRoot: function() { │ │ │ │ - return this.nodeFactory(this.container.id + "_vmlRoot", "div"); │ │ │ │ + setMap: function(map) { │ │ │ │ + this.map = map; │ │ │ │ + this.next.setMap(map); │ │ │ │ + this.previous.setMap(map); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: createRoot │ │ │ │ - * Create the main root element │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * suffix - {String} suffix to append to the id │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * Method: draw │ │ │ │ + * Called when the control is added to the map. │ │ │ │ */ │ │ │ │ - createRoot: function(suffix) { │ │ │ │ - return this.nodeFactory(this.container.id + suffix, "olv:group"); │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + this.next.draw(); │ │ │ │ + this.previous.draw(); │ │ │ │ }, │ │ │ │ │ │ │ │ - /************************************** │ │ │ │ - * * │ │ │ │ - * GEOMETRY DRAWING FUNCTIONS * │ │ │ │ - * * │ │ │ │ - **************************************/ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: drawPoint │ │ │ │ - * Render a point │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ + * Method: previousTrigger │ │ │ │ + * Restore the previous state. If no items are in the previous history │ │ │ │ + * stack, this has no effect. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} or false if the point could not be drawn │ │ │ │ + * {Object} Item representing state that was restored. Undefined if no │ │ │ │ + * items are in the previous history stack. │ │ │ │ */ │ │ │ │ - drawPoint: function(node, geometry) { │ │ │ │ - return this.drawCircle(node, geometry, 1); │ │ │ │ + previousTrigger: function() { │ │ │ │ + var current = this.previousStack.shift(); │ │ │ │ + var state = this.previousStack.shift(); │ │ │ │ + if (state != undefined) { │ │ │ │ + this.nextStack.unshift(current); │ │ │ │ + this.previousStack.unshift(state); │ │ │ │ + this.restoring = true; │ │ │ │ + this.restore(state); │ │ │ │ + this.restoring = false; │ │ │ │ + this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ + this.onPreviousChange( │ │ │ │ + this.previousStack[1], this.previousStack.length - 1 │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + this.previousStack.unshift(current); │ │ │ │ + } │ │ │ │ + return state; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawCircle │ │ │ │ - * Render a circle. │ │ │ │ - * Size and Center a circle given geometry (x,y center) and radius │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * radius - {float} │ │ │ │ - * │ │ │ │ + * APIMethod: nextTrigger │ │ │ │ + * Restore the next state. If no items are in the next history │ │ │ │ + * stack, this has no effect. The next history stack is populated │ │ │ │ + * as states are restored from the previous history stack. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} or false if the circle could not ne drawn │ │ │ │ + * {Object} Item representing state that was restored. Undefined if no │ │ │ │ + * items are in the next history stack. │ │ │ │ */ │ │ │ │ - drawCircle: function(node, geometry, radius) { │ │ │ │ - if (!isNaN(geometry.x) && !isNaN(geometry.y)) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - │ │ │ │ - node.style.left = ((((geometry.x - this.featureDx) / resolution - this.offset.x) | 0) - radius) + "px"; │ │ │ │ - node.style.top = (((geometry.y / resolution - this.offset.y) | 0) - radius) + "px"; │ │ │ │ - │ │ │ │ - var diameter = radius * 2; │ │ │ │ - │ │ │ │ - node.style.width = diameter + "px"; │ │ │ │ - node.style.height = diameter + "px"; │ │ │ │ - return node; │ │ │ │ + nextTrigger: function() { │ │ │ │ + var state = this.nextStack.shift(); │ │ │ │ + if (state != undefined) { │ │ │ │ + this.previousStack.unshift(state); │ │ │ │ + this.restoring = true; │ │ │ │ + this.restore(state); │ │ │ │ + this.restoring = false; │ │ │ │ + this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ + this.onPreviousChange( │ │ │ │ + this.previousStack[1], this.previousStack.length - 1 │ │ │ │ + ); │ │ │ │ } │ │ │ │ - return false; │ │ │ │ + return state; │ │ │ │ }, │ │ │ │ │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Method: drawLineString │ │ │ │ - * Render a linestring. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * APIMethod: clear │ │ │ │ + * Clear history. │ │ │ │ */ │ │ │ │ - drawLineString: function(node, geometry) { │ │ │ │ - return this.drawLine(node, geometry, false); │ │ │ │ + clear: function() { │ │ │ │ + this.previousStack = []; │ │ │ │ + this.previous.deactivate(); │ │ │ │ + this.nextStack = []; │ │ │ │ + this.next.deactivate(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawLinearRing │ │ │ │ - * Render a linearring │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ + * Method: getState │ │ │ │ + * Get the current state and return it. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * {Object} An object representing the current state. │ │ │ │ */ │ │ │ │ - drawLinearRing: function(node, geometry) { │ │ │ │ - return this.drawLine(node, geometry, true); │ │ │ │ + getState: function() { │ │ │ │ + return { │ │ │ │ + center: this.map.getCenter(), │ │ │ │ + resolution: this.map.getResolution(), │ │ │ │ + projection: this.map.getProjectionObject(), │ │ │ │ + units: this.map.getProjectionObject().getUnits() || │ │ │ │ + this.map.units || this.map.baseLayer.units │ │ │ │ + }; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: DrawLine │ │ │ │ - * Render a line. │ │ │ │ - * │ │ │ │ + * Method: restore │ │ │ │ + * Update the state with the given object. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * closeLine - {Boolean} Close the line? (make it a ring?) │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * state - {Object} An object representing the state to restore. │ │ │ │ */ │ │ │ │ - drawLine: function(node, geometry, closeLine) { │ │ │ │ - │ │ │ │ - this.setNodeDimension(node, geometry); │ │ │ │ - │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var numComponents = geometry.components.length; │ │ │ │ - var parts = new Array(numComponents); │ │ │ │ - │ │ │ │ - var comp, x, y; │ │ │ │ - for (var i = 0; i < numComponents; i++) { │ │ │ │ - comp = geometry.components[i]; │ │ │ │ - x = ((comp.x - this.featureDx) / resolution - this.offset.x) | 0; │ │ │ │ - y = (comp.y / resolution - this.offset.y) | 0; │ │ │ │ - parts[i] = " " + x + "," + y + " l "; │ │ │ │ + restore: function(state) { │ │ │ │ + var center, zoom; │ │ │ │ + if (this.map.getProjectionObject() == state.projection) { │ │ │ │ + zoom = this.map.getZoomForResolution(state.resolution); │ │ │ │ + center = state.center; │ │ │ │ + } else { │ │ │ │ + center = state.center.clone(); │ │ │ │ + center.transform(state.projection, this.map.getProjectionObject()); │ │ │ │ + var sourceUnits = state.units; │ │ │ │ + var targetUnits = this.map.getProjectionObject().getUnits() || │ │ │ │ + this.map.units || this.map.baseLayer.units; │ │ │ │ + var resolutionFactor = sourceUnits && targetUnits ? │ │ │ │ + OpenLayers.INCHES_PER_UNIT[sourceUnits] / OpenLayers.INCHES_PER_UNIT[targetUnits] : 1; │ │ │ │ + zoom = this.map.getZoomForResolution(resolutionFactor * state.resolution); │ │ │ │ } │ │ │ │ - var end = (closeLine) ? " x e" : " e"; │ │ │ │ - node.path = "m" + parts.join("") + end; │ │ │ │ - return node; │ │ │ │ + this.map.setCenter(center, zoom); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawPolygon │ │ │ │ - * Render a polygon │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ + * Method: setListeners │ │ │ │ + * Sets functions to be registered in the listeners object. │ │ │ │ */ │ │ │ │ - drawPolygon: function(node, geometry) { │ │ │ │ - this.setNodeDimension(node, geometry); │ │ │ │ - │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - │ │ │ │ - var path = []; │ │ │ │ - var j, jj, points, area, first, second, i, ii, comp, pathComp, x, y; │ │ │ │ - for (j = 0, jj = geometry.components.length; j < jj; j++) { │ │ │ │ - path.push("m"); │ │ │ │ - points = geometry.components[j].components; │ │ │ │ - // we only close paths of interior rings with area │ │ │ │ - area = (j === 0); │ │ │ │ - first = null; │ │ │ │ - second = null; │ │ │ │ - for (i = 0, ii = points.length; i < ii; i++) { │ │ │ │ - comp = points[i]; │ │ │ │ - x = ((comp.x - this.featureDx) / resolution - this.offset.x) | 0; │ │ │ │ - y = (comp.y / resolution - this.offset.y) | 0; │ │ │ │ - pathComp = " " + x + "," + y; │ │ │ │ - path.push(pathComp); │ │ │ │ - if (i == 0) { │ │ │ │ - path.push(" l"); │ │ │ │ - } │ │ │ │ - if (!area) { │ │ │ │ - // IE improperly renders sub-paths that have no area. │ │ │ │ - // Instead of checking the area of every ring, we confirm │ │ │ │ - // the ring has at least three distinct points. This does │ │ │ │ - // not catch all non-zero area cases, but it greatly improves │ │ │ │ - // interior ring digitizing and is a minor performance hit │ │ │ │ - // when rendering rings with many points. │ │ │ │ - if (!first) { │ │ │ │ - first = pathComp; │ │ │ │ - } else if (first != pathComp) { │ │ │ │ - if (!second) { │ │ │ │ - second = pathComp; │ │ │ │ - } else if (second != pathComp) { │ │ │ │ - // stop looking │ │ │ │ - area = true; │ │ │ │ - } │ │ │ │ + setListeners: function() { │ │ │ │ + this.listeners = {}; │ │ │ │ + for (var type in this.registry) { │ │ │ │ + this.listeners[type] = OpenLayers.Function.bind(function() { │ │ │ │ + if (!this.restoring) { │ │ │ │ + var state = this.registry[type].apply(this, arguments); │ │ │ │ + this.previousStack.unshift(state); │ │ │ │ + if (this.previousStack.length > 1) { │ │ │ │ + this.onPreviousChange( │ │ │ │ + this.previousStack[1], this.previousStack.length - 1 │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (this.previousStack.length > (this.limit + 1)) { │ │ │ │ + this.previousStack.pop(); │ │ │ │ + } │ │ │ │ + if (this.nextStack.length > 0) { │ │ │ │ + this.nextStack = []; │ │ │ │ + this.onNextChange(null, 0); │ │ │ │ } │ │ │ │ } │ │ │ │ - } │ │ │ │ - path.push(area ? " x " : " "); │ │ │ │ + return true; │ │ │ │ + }, this); │ │ │ │ } │ │ │ │ - path.push("e"); │ │ │ │ - node.path = path.join(""); │ │ │ │ - return node; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: drawRectangle │ │ │ │ - * Render a rectangle │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ - * │ │ │ │ + * APIMethod: activate │ │ │ │ + * Activate the control. This registers any listeners. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - drawRectangle: function(node, geometry) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - │ │ │ │ - node.style.left = (((geometry.x - this.featureDx) / resolution - this.offset.x) | 0) + "px"; │ │ │ │ - node.style.top = ((geometry.y / resolution - this.offset.y) | 0) + "px"; │ │ │ │ - node.style.width = ((geometry.width / resolution) | 0) + "px"; │ │ │ │ - node.style.height = ((geometry.height / resolution) | 0) + "px"; │ │ │ │ - │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: drawText │ │ │ │ - * This method is only called by the renderer itself. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * featureId - {String} │ │ │ │ - * style - │ │ │ │ - * location - {<OpenLayers.Geometry.Point>} │ │ │ │ + * {Boolean} Control successfully activated. │ │ │ │ */ │ │ │ │ - drawText: function(featureId, style, location) { │ │ │ │ - var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect"); │ │ │ │ - var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox"); │ │ │ │ - │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - label.style.left = (((location.x - this.featureDx) / resolution - this.offset.x) | 0) + "px"; │ │ │ │ - label.style.top = ((location.y / resolution - this.offset.y) | 0) + "px"; │ │ │ │ - label.style.flip = "y"; │ │ │ │ - │ │ │ │ - textbox.innerText = style.label; │ │ │ │ - │ │ │ │ - if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ - textbox.style.cursor = style.cursor; │ │ │ │ - } │ │ │ │ - if (style.fontColor) { │ │ │ │ - textbox.style.color = style.fontColor; │ │ │ │ - } │ │ │ │ - if (style.fontOpacity) { │ │ │ │ - textbox.style.filter = 'alpha(opacity=' + (style.fontOpacity * 100) + ')'; │ │ │ │ - } │ │ │ │ - if (style.fontFamily) { │ │ │ │ - textbox.style.fontFamily = style.fontFamily; │ │ │ │ - } │ │ │ │ - if (style.fontSize) { │ │ │ │ - textbox.style.fontSize = style.fontSize; │ │ │ │ - } │ │ │ │ - if (style.fontWeight) { │ │ │ │ - textbox.style.fontWeight = style.fontWeight; │ │ │ │ - } │ │ │ │ - if (style.fontStyle) { │ │ │ │ - textbox.style.fontStyle = style.fontStyle; │ │ │ │ - } │ │ │ │ - if (style.labelSelect === true) { │ │ │ │ - label._featureId = featureId; │ │ │ │ - textbox._featureId = featureId; │ │ │ │ - textbox._geometry = location; │ │ │ │ - textbox._geometryClass = location.CLASS_NAME; │ │ │ │ - } │ │ │ │ - textbox.style.whiteSpace = "nowrap"; │ │ │ │ - // fun with IE: IE7 in standards compliant mode does not display any │ │ │ │ - // text with a left inset of 0. So we set this to 1px and subtract one │ │ │ │ - // pixel later when we set label.style.left │ │ │ │ - textbox.inset = "1px,0px,0px,0px"; │ │ │ │ - │ │ │ │ - if (!label.parentNode) { │ │ │ │ - label.appendChild(textbox); │ │ │ │ - this.textRoot.appendChild(label); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var align = style.labelAlign || "cm"; │ │ │ │ - if (align.length == 1) { │ │ │ │ - align += "m"; │ │ │ │ + activate: function() { │ │ │ │ + var activated = false; │ │ │ │ + if (this.map) { │ │ │ │ + if (OpenLayers.Control.prototype.activate.apply(this)) { │ │ │ │ + if (this.listeners == null) { │ │ │ │ + this.setListeners(); │ │ │ │ + } │ │ │ │ + for (var type in this.listeners) { │ │ │ │ + this.map.events.register(type, this, this.listeners[type]); │ │ │ │ + } │ │ │ │ + activated = true; │ │ │ │ + if (this.previousStack.length == 0) { │ │ │ │ + this.initStack(); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - var xshift = textbox.clientWidth * │ │ │ │ - (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0, 1)]); │ │ │ │ - var yshift = textbox.clientHeight * │ │ │ │ - (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1, 1)]); │ │ │ │ - label.style.left = parseInt(label.style.left) - xshift - 1 + "px"; │ │ │ │ - label.style.top = parseInt(label.style.top) + yshift + "px"; │ │ │ │ - │ │ │ │ + return activated; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: moveRoot │ │ │ │ - * moves this renderer's root to a different renderer. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * renderer - {<OpenLayers.Renderer>} target renderer for the moved root │ │ │ │ - * root - {DOMElement} optional root node. To be used when this renderer │ │ │ │ - * holds roots from multiple layers to tell this method which one to │ │ │ │ - * detach │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} true if successful, false otherwise │ │ │ │ + * Method: initStack │ │ │ │ + * Called after the control is activated if the previous history stack is │ │ │ │ + * empty. │ │ │ │ */ │ │ │ │ - moveRoot: function(renderer) { │ │ │ │ - var layer = this.map.getLayer(renderer.container.id); │ │ │ │ - if (layer instanceof OpenLayers.Layer.Vector.RootContainer) { │ │ │ │ - layer = this.map.getLayer(this.container.id); │ │ │ │ + initStack: function() { │ │ │ │ + if (this.map.getCenter()) { │ │ │ │ + this.listeners.moveend(); │ │ │ │ } │ │ │ │ - layer && layer.renderer.clear(); │ │ │ │ - OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments); │ │ │ │ - layer && layer.redraw(); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: importSymbol │ │ │ │ - * add a new symbol definition from the rendererer's symbol hash │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * graphicName - {String} name of the symbol to import │ │ │ │ - * │ │ │ │ + * APIMethod: deactivate │ │ │ │ + * Deactivate the control. This unregisters any listeners. │ │ │ │ + * │ │ │ │ * Returns: │ │ │ │ - * {Object} - hash of {DOMElement} "symbol" and {Number} "size" │ │ │ │ + * {Boolean} Control successfully deactivated. │ │ │ │ */ │ │ │ │ - importSymbol: function(graphicName) { │ │ │ │ - var id = this.container.id + "-" + graphicName; │ │ │ │ - │ │ │ │ - // check if symbol already exists in the cache │ │ │ │ - var cache = this.symbolCache[id]; │ │ │ │ - if (cache) { │ │ │ │ - return cache; │ │ │ │ - } │ │ │ │ - │ │ │ │ - var symbol = OpenLayers.Renderer.symbol[graphicName]; │ │ │ │ - if (!symbol) { │ │ │ │ - throw new Error(graphicName + ' is not a valid symbol name'); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var symbolExtent = new OpenLayers.Bounds( │ │ │ │ - Number.MAX_VALUE, Number.MAX_VALUE, 0, 0); │ │ │ │ - │ │ │ │ - var pathitems = ["m"]; │ │ │ │ - for (var i = 0; i < symbol.length; i = i + 2) { │ │ │ │ - var x = symbol[i]; │ │ │ │ - var 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); │ │ │ │ - │ │ │ │ - pathitems.push(x); │ │ │ │ - pathitems.push(y); │ │ │ │ - if (i == 0) { │ │ │ │ - pathitems.push("l"); │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = false; │ │ │ │ + if (this.map) { │ │ │ │ + if (OpenLayers.Control.prototype.deactivate.apply(this)) { │ │ │ │ + for (var type in this.listeners) { │ │ │ │ + this.map.events.unregister( │ │ │ │ + type, this, this.listeners[type] │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (this.clearOnDeactivate) { │ │ │ │ + this.clear(); │ │ │ │ + } │ │ │ │ + deactivated = true; │ │ │ │ } │ │ │ │ } │ │ │ │ - pathitems.push("x e"); │ │ │ │ - var path = pathitems.join(" "); │ │ │ │ - │ │ │ │ - var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2; │ │ │ │ - if (diff > 0) { │ │ │ │ - symbolExtent.bottom = symbolExtent.bottom - diff; │ │ │ │ - symbolExtent.top = symbolExtent.top + diff; │ │ │ │ - } else { │ │ │ │ - symbolExtent.left = symbolExtent.left + diff; │ │ │ │ - symbolExtent.right = symbolExtent.right - diff; │ │ │ │ - } │ │ │ │ - │ │ │ │ - cache = { │ │ │ │ - path: path, │ │ │ │ - size: symbolExtent.getWidth(), // equals getHeight() now │ │ │ │ - left: symbolExtent.left, │ │ │ │ - bottom: symbolExtent.bottom │ │ │ │ - }; │ │ │ │ - this.symbolCache[id] = cache; │ │ │ │ - │ │ │ │ - return cache; │ │ │ │ + return deactivated; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.VML" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.NavigationHistory" │ │ │ │ }); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Renderer.VML.LABEL_SHIFT │ │ │ │ - * {Object} │ │ │ │ - */ │ │ │ │ -OpenLayers.Renderer.VML.LABEL_SHIFT = { │ │ │ │ - "l": 0, │ │ │ │ - "c": .5, │ │ │ │ - "r": 1, │ │ │ │ - "t": 0, │ │ │ │ - "m": .5, │ │ │ │ - "b": 1 │ │ │ │ -}; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Marker/Box.js │ │ │ │ + OpenLayers/Control/CacheWrite.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/Marker.js │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ + * @requires OpenLayers/Console.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Marker.Box │ │ │ │ + * Class: OpenLayers.Control.CacheWrite │ │ │ │ + * A control for caching image tiles in the browser's local storage. The │ │ │ │ + * <OpenLayers.Control.CacheRead> control is used to fetch and use the cached │ │ │ │ + * tile images. │ │ │ │ + * │ │ │ │ + * Note: Before using this control on any layer that is not your own, make sure │ │ │ │ + * that the terms of service of the tile provider allow local storage of tiles. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Marker> │ │ │ │ + * - <OpenLayers.Control> │ │ │ │ */ │ │ │ │ -OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, { │ │ │ │ +OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: bounds │ │ │ │ - * {<OpenLayers.Bounds>} │ │ │ │ + * APIProperty: events │ │ │ │ + * {<OpenLayers.Events>} Events instance for listeners and triggering │ │ │ │ + * control specific events. │ │ │ │ + * │ │ │ │ + * To register events in the constructor, configure <eventListeners>. │ │ │ │ + * │ │ │ │ + * 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>): │ │ │ │ + * cachefull - Triggered when the cache is full. Listeners receive an │ │ │ │ + * object with a tile property as first argument. The tile references │ │ │ │ + * the tile that couldn't be cached. │ │ │ │ */ │ │ │ │ - bounds: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: div │ │ │ │ - * {DOMElement} │ │ │ │ + /** │ │ │ │ + * APIProperty: eventListeners │ │ │ │ + * {Object} Object with event listeners, keyed by event name. An optional │ │ │ │ + * scope property defines the scope that listeners will be executed in. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: layers │ │ │ │ + * {Array(<OpenLayers.Layer.Grid>)}. Optional. If provided, caching │ │ │ │ + * will be enabled for these layers only, otherwise for all cacheable │ │ │ │ + * layers. │ │ │ │ + */ │ │ │ │ + layers: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: imageFormat │ │ │ │ + * {String} The image format used for caching. The default is "image/png". │ │ │ │ + * Supported formats depend on the user agent. If an unsupported │ │ │ │ + * <imageFormat> is provided, "image/png" will be used. For aerial │ │ │ │ + * imagery, "image/jpeg" is recommended. │ │ │ │ + */ │ │ │ │ + imageFormat: "image/png", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: quotaRegEx │ │ │ │ + * {RegExp} │ │ │ │ + */ │ │ │ │ + quotaRegEx: (/quota/i), │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Control.CacheWrite │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} Object with API properties for this control. │ │ │ │ */ │ │ │ │ - div: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Marker.Box │ │ │ │ + * Method: setMap │ │ │ │ + * Set the map property for the control. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * map - {<OpenLayers.Map>} │ │ │ │ + */ │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + var i, layers = this.layers || map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.addLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + if (!this.layers) { │ │ │ │ + map.events.on({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: addLayer │ │ │ │ + * Adds a layer to the control. Once added, tiles requested for this layer │ │ │ │ + * will be cached. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * bounds - {<OpenLayers.Bounds>} │ │ │ │ - * borderColor - {String} │ │ │ │ - * borderWidth - {int} │ │ │ │ + * evt - {Object} Object with a layer property referencing an │ │ │ │ + * <OpenLayers.Layer> instance │ │ │ │ */ │ │ │ │ - initialize: function(bounds, borderColor, borderWidth) { │ │ │ │ - this.bounds = bounds; │ │ │ │ - this.div = OpenLayers.Util.createDiv(); │ │ │ │ - this.div.style.overflow = 'hidden'; │ │ │ │ - this.events = new OpenLayers.Events(this, this.div); │ │ │ │ - this.setBorder(borderColor, borderWidth); │ │ │ │ + addLayer: function(evt) { │ │ │ │ + evt.layer.events.on({ │ │ │ │ + tileloadstart: this.makeSameOrigin, │ │ │ │ + tileloaded: this.onTileLoaded, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: destroy │ │ │ │ + * Method: removeLayer │ │ │ │ + * Removes a layer from the control. Once removed, tiles requested for this │ │ │ │ + * layer will no longer be cached. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * evt - {Object} Object with a layer property referencing an │ │ │ │ + * <OpenLayers.Layer> instance │ │ │ │ */ │ │ │ │ - destroy: function() { │ │ │ │ - │ │ │ │ - this.bounds = null; │ │ │ │ - this.div = null; │ │ │ │ - │ │ │ │ - OpenLayers.Marker.prototype.destroy.apply(this, arguments); │ │ │ │ + removeLayer: function(evt) { │ │ │ │ + evt.layer.events.un({ │ │ │ │ + tileloadstart: this.makeSameOrigin, │ │ │ │ + tileloaded: this.onTileLoaded, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: setBorder │ │ │ │ - * Allow the user to change the box's color and border width │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: makeSameOrigin │ │ │ │ + * If the tile does not have CORS image loading enabled and is from a │ │ │ │ + * different origin, use OpenLayers.ProxyHost to make it a same origin url. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * color - {String} Default is "red" │ │ │ │ - * width - {int} Default is 2 │ │ │ │ + * evt - {<OpenLayers.Event>} │ │ │ │ */ │ │ │ │ - setBorder: function(color, width) { │ │ │ │ - if (!color) { │ │ │ │ - color = "red"; │ │ │ │ - } │ │ │ │ - if (!width) { │ │ │ │ - width = 2; │ │ │ │ + makeSameOrigin: function(evt) { │ │ │ │ + if (this.active) { │ │ │ │ + var tile = evt.tile; │ │ │ │ + if (tile instanceof OpenLayers.Tile.Image && │ │ │ │ + !tile.crossOriginKeyword && │ │ │ │ + tile.url.substr(0, 5) !== "data:") { │ │ │ │ + var sameOriginUrl = OpenLayers.Request.makeSameOrigin( │ │ │ │ + tile.url, OpenLayers.ProxyHost │ │ │ │ + ); │ │ │ │ + OpenLayers.Control.CacheWrite.urlMap[sameOriginUrl] = tile.url; │ │ │ │ + tile.url = sameOriginUrl; │ │ │ │ + } │ │ │ │ } │ │ │ │ - this.div.style.border = width + "px solid " + color; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * │ │ │ │ + /** │ │ │ │ + * Method: onTileLoaded │ │ │ │ + * Decides whether a tile can be cached and calls the cache method. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * px - {<OpenLayers.Pixel>} │ │ │ │ - * sz - {<OpenLayers.Size>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A new DOM Image with this marker's icon set at the │ │ │ │ - * location passed-in │ │ │ │ + * evt - {Event} │ │ │ │ */ │ │ │ │ - draw: function(px, sz) { │ │ │ │ - OpenLayers.Util.modifyDOMElement(this.div, null, px, sz); │ │ │ │ - return this.div; │ │ │ │ + onTileLoaded: function(evt) { │ │ │ │ + if (this.active && !evt.aborted && │ │ │ │ + evt.tile instanceof OpenLayers.Tile.Image && │ │ │ │ + evt.tile.url.substr(0, 5) !== 'data:') { │ │ │ │ + this.cache({ │ │ │ │ + tile: evt.tile │ │ │ │ + }); │ │ │ │ + delete OpenLayers.Control.CacheWrite.urlMap[evt.tile.url]; │ │ │ │ + } │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: onScreen │ │ │ │ - * │ │ │ │ - * Rreturn: │ │ │ │ - * {Boolean} Whether or not the marker is currently visible on screen. │ │ │ │ + * Method: cache │ │ │ │ + * Adds a tile to the cache. When the cache is full, the "cachefull" event │ │ │ │ + * is triggered. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {Object} Object with a tile property, tile being the │ │ │ │ + * <OpenLayers.Tile.Image> with the data to add to the cache │ │ │ │ */ │ │ │ │ - onScreen: function() { │ │ │ │ - var onScreen = false; │ │ │ │ - if (this.map) { │ │ │ │ - var screenBounds = this.map.getExtent(); │ │ │ │ - onScreen = screenBounds.containsBounds(this.bounds, true, true); │ │ │ │ + cache: function(obj) { │ │ │ │ + if (window.localStorage) { │ │ │ │ + var tile = obj.tile; │ │ │ │ + try { │ │ │ │ + var canvasContext = tile.getCanvasContext(); │ │ │ │ + if (canvasContext) { │ │ │ │ + var urlMap = OpenLayers.Control.CacheWrite.urlMap; │ │ │ │ + var url = urlMap[tile.url] || tile.url; │ │ │ │ + window.localStorage.setItem( │ │ │ │ + "olCache_" + url, │ │ │ │ + canvasContext.canvas.toDataURL(this.imageFormat) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } catch (e) { │ │ │ │ + // local storage full or CORS violation │ │ │ │ + var reason = e.name || e.message; │ │ │ │ + if (reason && this.quotaRegEx.test(reason)) { │ │ │ │ + this.events.triggerEvent("cachefull", { │ │ │ │ + tile: tile │ │ │ │ + }); │ │ │ │ + } else { │ │ │ │ + OpenLayers.Console.error(e.toString()); │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - return onScreen; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: display │ │ │ │ - * Hide or show the icon │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * display - {Boolean} │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - display: function(display) { │ │ │ │ - this.div.style.display = (display) ? "" : "none"; │ │ │ │ + destroy: function() { │ │ │ │ + if (this.layers || this.map) { │ │ │ │ + var i, layers = this.layers || this.map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.removeLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.un({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Marker.Box" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.CacheWrite" │ │ │ │ }); │ │ │ │ │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/QueryStringFilter.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/Console.js │ │ │ │ - * @requires OpenLayers/Format.js │ │ │ │ - * @requires OpenLayers/Filter/Spatial.js │ │ │ │ - * @requires OpenLayers/Filter/Comparison.js │ │ │ │ - * @requires OpenLayers/Filter/Logical.js │ │ │ │ + * APIFunction: OpenLayers.Control.CacheWrite.clearCache │ │ │ │ + * Clears all tiles cached with <OpenLayers.Control.CacheWrite> from the cache. │ │ │ │ */ │ │ │ │ +OpenLayers.Control.CacheWrite.clearCache = function() { │ │ │ │ + if (!window.localStorage) { │ │ │ │ + return; │ │ │ │ + } │ │ │ │ + var i, key; │ │ │ │ + for (i = window.localStorage.length - 1; i >= 0; --i) { │ │ │ │ + key = window.localStorage.key(i); │ │ │ │ + if (key.substr(0, 8) === "olCache_") { │ │ │ │ + window.localStorage.removeItem(key); │ │ │ │ + } │ │ │ │ + } │ │ │ │ +}; │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.QueryStringFilter │ │ │ │ - * Parser for reading a query string and creating a simple filter. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format> │ │ │ │ + * Property: OpenLayers.Control.CacheWrite.urlMap │ │ │ │ + * {Object} Mapping of same origin urls to cache url keys. Entries will be │ │ │ │ + * deleted as soon as a tile was cached. │ │ │ │ */ │ │ │ │ -OpenLayers.Format.QueryStringFilter = (function() { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Map the OpenLayers.Filter.Comparison types to the operation strings of │ │ │ │ - * the protocol. │ │ │ │ - */ │ │ │ │ - var cmpToStr = {}; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.EQUAL_TO] = "eq"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.NOT_EQUAL_TO] = "ne"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN] = "lt"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO] = "lte"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN] = "gt"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO] = "gte"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.LIKE] = "ilike"; │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Function: regex2value │ │ │ │ - * Convert the value from a regular expression string to a LIKE/ILIKE │ │ │ │ - * string known to the web service. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * value - {String} The regex string. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} The converted string. │ │ │ │ - */ │ │ │ │ - function regex2value(value) { │ │ │ │ - │ │ │ │ - // highly sensitive!! Do not change this without running the │ │ │ │ - // Protocol/HTTP.html unit tests │ │ │ │ - │ │ │ │ - // convert % to \% │ │ │ │ - value = value.replace(/%/g, "\\%"); │ │ │ │ - │ │ │ │ - // convert \\. to \\_ (\\.* occurences converted later) │ │ │ │ - value = value.replace(/\\\\\.(\*)?/g, function($0, $1) { │ │ │ │ - return $1 ? $0 : "\\\\_"; │ │ │ │ - }); │ │ │ │ - │ │ │ │ - // convert \\.* to \\% │ │ │ │ - value = value.replace(/\\\\\.\*/g, "\\\\%"); │ │ │ │ - │ │ │ │ - // convert . to _ (\. and .* occurences converted later) │ │ │ │ - value = value.replace(/(\\)?\.(\*)?/g, function($0, $1, $2) { │ │ │ │ - return $1 || $2 ? $0 : "_"; │ │ │ │ - }); │ │ │ │ - │ │ │ │ - // convert .* to % (\.* occurnces converted later) │ │ │ │ - value = value.replace(/(\\)?\.\*/g, function($0, $1) { │ │ │ │ - return $1 ? $0 : "%"; │ │ │ │ - }); │ │ │ │ - │ │ │ │ - // convert \. to . │ │ │ │ - value = value.replace(/\\\./g, "."); │ │ │ │ - │ │ │ │ - // replace \* with * (watching out for \\*) │ │ │ │ - value = value.replace(/(\\)?\\\*/g, function($0, $1) { │ │ │ │ - return $1 ? $0 : "*"; │ │ │ │ - }); │ │ │ │ - │ │ │ │ - return value; │ │ │ │ - } │ │ │ │ - │ │ │ │ - return OpenLayers.Class(OpenLayers.Format, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Serialize an <OpenLayers.Filter> objects using the "simple" filter syntax for │ │ │ │ - * query string parameters. This function must be called as a method of │ │ │ │ - * a protocol instance. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * filter - {<OpenLayers.Filter>} filter to convert. │ │ │ │ - * params - {Object} The parameters object. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} The resulting parameters object. │ │ │ │ - */ │ │ │ │ - write: function(filter, params) { │ │ │ │ - params = params || {}; │ │ │ │ - var className = filter.CLASS_NAME; │ │ │ │ - var filterType = className.substring(className.lastIndexOf(".") + 1); │ │ │ │ - switch (filterType) { │ │ │ │ - case "Spatial": │ │ │ │ - switch (filter.type) { │ │ │ │ - case OpenLayers.Filter.Spatial.BBOX: │ │ │ │ - params.bbox = filter.value.toArray(); │ │ │ │ - if (this.srsInBBOX && filter.projection) { │ │ │ │ - params.bbox.push(filter.projection.getCode()); │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case OpenLayers.Filter.Spatial.DWITHIN: │ │ │ │ - params.tolerance = filter.distance; │ │ │ │ - // no break here │ │ │ │ - case OpenLayers.Filter.Spatial.WITHIN: │ │ │ │ - params.lon = filter.value.x; │ │ │ │ - params.lat = filter.value.y; │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - OpenLayers.Console.warn( │ │ │ │ - "Unknown spatial filter type " + filter.type); │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "Comparison": │ │ │ │ - var op = cmpToStr[filter.type]; │ │ │ │ - if (op !== undefined) { │ │ │ │ - var value = filter.value; │ │ │ │ - if (filter.type == OpenLayers.Filter.Comparison.LIKE) { │ │ │ │ - value = regex2value(value); │ │ │ │ - if (this.wildcarded) { │ │ │ │ - value = "%" + value + "%"; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - params[filter.property + "__" + op] = value; │ │ │ │ - params.queryable = params.queryable || []; │ │ │ │ - params.queryable.push(filter.property); │ │ │ │ - } else { │ │ │ │ - OpenLayers.Console.warn( │ │ │ │ - "Unknown comparison filter type " + filter.type); │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "Logical": │ │ │ │ - if (filter.type === OpenLayers.Filter.Logical.AND) { │ │ │ │ - for (var i = 0, len = filter.filters.length; i < len; i++) { │ │ │ │ - params = this.write(filter.filters[i], params); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Console.warn( │ │ │ │ - "Unsupported logical filter type " + filter.type); │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - OpenLayers.Console.warn("Unknown filter type " + filterType); │ │ │ │ - } │ │ │ │ - return params; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.QueryStringFilter" │ │ │ │ - │ │ │ │ - }); │ │ │ │ +OpenLayers.Control.CacheWrite.urlMap = {}; │ │ │ │ │ │ │ │ │ │ │ │ -})(); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Format/WFSDescribeFeatureType.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 │ │ │ │ @@ -76889,512 +82267,14 @@ │ │ │ │ return schema; │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.WFSDescribeFeatureType" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/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/Format/GML.js │ │ │ │ - * @requires OpenLayers/Console.js │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WFS │ │ │ │ - * Read/Write WFS. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.GML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WFS = OpenLayers.Class(OpenLayers.Format.GML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: layer │ │ │ │ - * {<OpenLayers.Layer>} │ │ │ │ - */ │ │ │ │ - layer: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: wfsns │ │ │ │ - * {String} │ │ │ │ - */ │ │ │ │ - wfsns: "http://www.opengis.net/wfs", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: ogcns │ │ │ │ - * {String} │ │ │ │ - */ │ │ │ │ - ogcns: "http://www.opengis.net/ogc", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WFS │ │ │ │ - * Create a WFS-T formatter. This requires a layer: that layer should │ │ │ │ - * have two properties: geometry_column and typename. The parser │ │ │ │ - * for this format is subclassed entirely from GML: There is a writer │ │ │ │ - * only, which uses most of the code from the GML layer, and wraps │ │ │ │ - * it in transactional elements. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} │ │ │ │ - * layer - {<OpenLayers.Layer>} │ │ │ │ - */ │ │ │ │ - initialize: function(options, layer) { │ │ │ │ - OpenLayers.Format.GML.prototype.initialize.apply(this, [options]); │ │ │ │ - this.layer = layer; │ │ │ │ - if (this.layer.featureNS) { │ │ │ │ - this.featureNS = this.layer.featureNS; │ │ │ │ - } │ │ │ │ - if (this.layer.options.geometry_column) { │ │ │ │ - this.geometryName = this.layer.options.geometry_column; │ │ │ │ - } │ │ │ │ - if (this.layer.options.typename) { │ │ │ │ - this.featureName = this.layer.options.typename; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: write │ │ │ │ - * Takes a feature list, and generates a WFS-T Transaction │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ - */ │ │ │ │ - write: function(features) { │ │ │ │ - │ │ │ │ - var transaction = this.createElementNS(this.wfsns, 'wfs:Transaction'); │ │ │ │ - transaction.setAttribute("version", "1.0.0"); │ │ │ │ - transaction.setAttribute("service", "WFS"); │ │ │ │ - for (var i = 0; i < features.length; i++) { │ │ │ │ - switch (features[i].state) { │ │ │ │ - case OpenLayers.State.INSERT: │ │ │ │ - transaction.appendChild(this.insert(features[i])); │ │ │ │ - break; │ │ │ │ - case OpenLayers.State.UPDATE: │ │ │ │ - transaction.appendChild(this.update(features[i])); │ │ │ │ - break; │ │ │ │ - case OpenLayers.State.DELETE: │ │ │ │ - transaction.appendChild(this.remove(features[i])); │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [transaction]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: createFeatureXML │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - createFeatureXML: function(feature) { │ │ │ │ - var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ - var geomContainer = this.createElementNS(this.featureNS, "feature:" + this.geometryName); │ │ │ │ - geomContainer.appendChild(geometryNode); │ │ │ │ - var featureContainer = this.createElementNS(this.featureNS, "feature:" + this.featureName); │ │ │ │ - featureContainer.appendChild(geomContainer); │ │ │ │ - for (var attr in feature.attributes) { │ │ │ │ - var attrText = this.createTextNode(feature.attributes[attr]); │ │ │ │ - var nodename = attr; │ │ │ │ - if (attr.search(":") != -1) { │ │ │ │ - nodename = attr.split(":")[1]; │ │ │ │ - } │ │ │ │ - var attrContainer = this.createElementNS(this.featureNS, "feature:" + nodename); │ │ │ │ - attrContainer.appendChild(attrText); │ │ │ │ - featureContainer.appendChild(attrContainer); │ │ │ │ - } │ │ │ │ - return featureContainer; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: insert │ │ │ │ - * Takes a feature, and generates a WFS-T Transaction "Insert" │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - insert: function(feature) { │ │ │ │ - var insertNode = this.createElementNS(this.wfsns, 'wfs:Insert'); │ │ │ │ - insertNode.appendChild(this.createFeatureXML(feature)); │ │ │ │ - return insertNode; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: update │ │ │ │ - * Takes a feature, and generates a WFS-T Transaction "Update" │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - update: function(feature) { │ │ │ │ - if (!feature.fid) { │ │ │ │ - OpenLayers.Console.userError(OpenLayers.i18n("noFID")); │ │ │ │ - } │ │ │ │ - var updateNode = this.createElementNS(this.wfsns, 'wfs:Update'); │ │ │ │ - updateNode.setAttribute("typeName", this.featurePrefix + ':' + this.featureName); │ │ │ │ - updateNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ - │ │ │ │ - var propertyNode = this.createElementNS(this.wfsns, 'wfs:Property'); │ │ │ │ - var nameNode = this.createElementNS(this.wfsns, 'wfs:Name'); │ │ │ │ - │ │ │ │ - var txtNode = this.createTextNode(this.geometryName); │ │ │ │ - nameNode.appendChild(txtNode); │ │ │ │ - propertyNode.appendChild(nameNode); │ │ │ │ - │ │ │ │ - var valueNode = this.createElementNS(this.wfsns, 'wfs:Value'); │ │ │ │ - │ │ │ │ - var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ - │ │ │ │ - if (feature.layer) { │ │ │ │ - geometryNode.setAttribute( │ │ │ │ - "srsName", feature.layer.projection.getCode() │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - │ │ │ │ - valueNode.appendChild(geometryNode); │ │ │ │ - │ │ │ │ - propertyNode.appendChild(valueNode); │ │ │ │ - updateNode.appendChild(propertyNode); │ │ │ │ - │ │ │ │ - // add in attributes │ │ │ │ - for (var propName in feature.attributes) { │ │ │ │ - propertyNode = this.createElementNS(this.wfsns, 'wfs:Property'); │ │ │ │ - nameNode = this.createElementNS(this.wfsns, 'wfs:Name'); │ │ │ │ - nameNode.appendChild(this.createTextNode(propName)); │ │ │ │ - propertyNode.appendChild(nameNode); │ │ │ │ - valueNode = this.createElementNS(this.wfsns, 'wfs:Value'); │ │ │ │ - valueNode.appendChild(this.createTextNode(feature.attributes[propName])); │ │ │ │ - propertyNode.appendChild(valueNode); │ │ │ │ - updateNode.appendChild(propertyNode); │ │ │ │ - } │ │ │ │ - │ │ │ │ - │ │ │ │ - var filterNode = this.createElementNS(this.ogcns, 'ogc:Filter'); │ │ │ │ - var filterIdNode = this.createElementNS(this.ogcns, 'ogc:FeatureId'); │ │ │ │ - filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ - filterNode.appendChild(filterIdNode); │ │ │ │ - updateNode.appendChild(filterNode); │ │ │ │ - │ │ │ │ - return updateNode; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: remove │ │ │ │ - * Takes a feature, and generates a WFS-T Transaction "Delete" │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - remove: function(feature) { │ │ │ │ - if (!feature.fid) { │ │ │ │ - OpenLayers.Console.userError(OpenLayers.i18n("noFID")); │ │ │ │ - return false; │ │ │ │ - } │ │ │ │ - var deleteNode = this.createElementNS(this.wfsns, 'wfs:Delete'); │ │ │ │ - deleteNode.setAttribute("typeName", this.featurePrefix + ':' + this.featureName); │ │ │ │ - deleteNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ - │ │ │ │ - var filterNode = this.createElementNS(this.ogcns, 'ogc:Filter'); │ │ │ │ - var filterIdNode = this.createElementNS(this.ogcns, 'ogc:FeatureId'); │ │ │ │ - filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ - filterNode.appendChild(filterIdNode); │ │ │ │ - deleteNode.appendChild(filterNode); │ │ │ │ - │ │ │ │ - return deleteNode; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Remove ciruclar ref to layer │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - this.layer = null; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFS" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMTSCapabilities.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 │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMTSCapabilities │ │ │ │ - * Read WMTS Capabilities. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMTSCapabilities = 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", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: yx │ │ │ │ - * {Object} Members in the yx object are used to determine if a CRS URN │ │ │ │ - * corresponds to a CRS with y,x axis order. Member names are CRS URNs │ │ │ │ - * and values are boolean. By default, the following CRS URN are │ │ │ │ - * assumed to correspond to a CRS with y,x axis order: │ │ │ │ - * │ │ │ │ - * * urn:ogc:def:crs:EPSG::4326 │ │ │ │ - */ │ │ │ │ - yx: { │ │ │ │ - "urn:ogc:def:crs:EPSG::4326": true │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WMTSCapabilities │ │ │ │ - * Create a new parser for WMTS capabilities. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return information about │ │ │ │ - * the service (offering and observedProperty mostly). │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} Info about the WMTS Capabilities │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: createLayer │ │ │ │ - * Create a WMTS layer given a capabilities object. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * capabilities - {Object} The object returned from a <read> call to this │ │ │ │ - * format. │ │ │ │ - * config - {Object} Configuration properties for the layer. Defaults for │ │ │ │ - * the layer will apply if not provided. │ │ │ │ - * │ │ │ │ - * Required config properties: │ │ │ │ - * layer - {String} The layer identifier. │ │ │ │ - * │ │ │ │ - * Optional config properties: │ │ │ │ - * matrixSet - {String} The matrix set identifier, required if there is │ │ │ │ - * more than one matrix set in the layer capabilities. │ │ │ │ - * style - {String} The name of the style │ │ │ │ - * format - {String} Image format for the layer. Default is the first │ │ │ │ - * format returned in the GetCapabilities response. │ │ │ │ - * param - {Object} The dimensions values eg: {"Year": "2012"} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Layer.WMTS>} A properly configured WMTS layer. Throws an │ │ │ │ - * error if an incomplete config is provided. Returns undefined if no │ │ │ │ - * layer could be created with the provided config. │ │ │ │ - */ │ │ │ │ - createLayer: function(capabilities, config) { │ │ │ │ - var layer; │ │ │ │ - │ │ │ │ - // confirm required properties are supplied in config │ │ │ │ - if (!('layer' in config)) { │ │ │ │ - throw new Error("Missing property 'layer' in configuration."); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var contents = capabilities.contents; │ │ │ │ - │ │ │ │ - // find the layer definition with the given identifier │ │ │ │ - var layers = contents.layers; │ │ │ │ - var layerDef; │ │ │ │ - for (var i = 0, ii = contents.layers.length; i < ii; ++i) { │ │ │ │ - if (contents.layers[i].identifier === config.layer) { │ │ │ │ - layerDef = contents.layers[i]; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (!layerDef) { │ │ │ │ - throw new Error("Layer not found"); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var format = config.format; │ │ │ │ - if (!format && layerDef.formats && layerDef.formats.length) { │ │ │ │ - format = layerDef.formats[0]; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // find the matrixSet definition │ │ │ │ - var matrixSet; │ │ │ │ - if (config.matrixSet) { │ │ │ │ - matrixSet = contents.tileMatrixSets[config.matrixSet]; │ │ │ │ - } else if (layerDef.tileMatrixSetLinks.length >= 1) { │ │ │ │ - matrixSet = contents.tileMatrixSets[ │ │ │ │ - layerDef.tileMatrixSetLinks[0].tileMatrixSet]; │ │ │ │ - } │ │ │ │ - if (!matrixSet) { │ │ │ │ - throw new Error("matrixSet not found"); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // get the default style for the layer │ │ │ │ - var style; │ │ │ │ - for (var i = 0, ii = layerDef.styles.length; i < ii; ++i) { │ │ │ │ - style = layerDef.styles[i]; │ │ │ │ - if (style.isDefault) { │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - var requestEncoding = config.requestEncoding; │ │ │ │ - if (!requestEncoding) { │ │ │ │ - requestEncoding = "KVP"; │ │ │ │ - if (capabilities.operationsMetadata.GetTile.dcp.http) { │ │ │ │ - var http = capabilities.operationsMetadata.GetTile.dcp.http; │ │ │ │ - // Get first get method │ │ │ │ - if (http.get[0].constraints) { │ │ │ │ - var constraints = http.get[0].constraints; │ │ │ │ - var allowedValues = constraints.GetEncoding.allowedValues; │ │ │ │ - │ │ │ │ - // The OGC documentation is not clear if we should use │ │ │ │ - // REST or RESTful, ArcGis use RESTful, │ │ │ │ - // and OpenLayers use REST. │ │ │ │ - if (!allowedValues.KVP && │ │ │ │ - (allowedValues.REST || allowedValues.RESTful)) { │ │ │ │ - requestEncoding = "REST"; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - var dimensions = []; │ │ │ │ - var params = config.params || {}; │ │ │ │ - // to don't overwrite the changes in the applyDefaults │ │ │ │ - delete config.params; │ │ │ │ - for (var id = 0, ld = layerDef.dimensions.length; id < ld; id++) { │ │ │ │ - var dimension = layerDef.dimensions[id]; │ │ │ │ - dimensions.push(dimension.identifier); │ │ │ │ - if (!params.hasOwnProperty(dimension.identifier)) { │ │ │ │ - params[dimension.identifier] = dimension['default']; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - var projection = config.projection || matrixSet.supportedCRS.replace( │ │ │ │ - /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, "$1:$3"); │ │ │ │ - var units = config.units || │ │ │ │ - (projection === "EPSG:4326" ? "degrees" : "m"); │ │ │ │ - │ │ │ │ - var resolutions = []; │ │ │ │ - for (var mid in matrixSet.matrixIds) { │ │ │ │ - if (matrixSet.matrixIds.hasOwnProperty(mid)) { │ │ │ │ - resolutions.push( │ │ │ │ - matrixSet.matrixIds[mid].scaleDenominator * 0.28E-3 / │ │ │ │ - OpenLayers.METERS_PER_INCH / │ │ │ │ - OpenLayers.INCHES_PER_UNIT[units]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - var url; │ │ │ │ - if (requestEncoding === "REST" && layerDef.resourceUrls) { │ │ │ │ - url = []; │ │ │ │ - var resourceUrls = layerDef.resourceUrls, │ │ │ │ - resourceUrl; │ │ │ │ - for (var t = 0, tt = layerDef.resourceUrls.length; t < tt; ++t) { │ │ │ │ - resourceUrl = layerDef.resourceUrls[t]; │ │ │ │ - if (resourceUrl.format === format && resourceUrl.resourceType === "tile") { │ │ │ │ - url.push(resourceUrl.template); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - var httpGet = capabilities.operationsMetadata.GetTile.dcp.http.get; │ │ │ │ - url = []; │ │ │ │ - var constraint; │ │ │ │ - for (var i = 0, ii = httpGet.length; i < ii; i++) { │ │ │ │ - constraint = httpGet[i].constraints; │ │ │ │ - if (!constraint || (constraint && constraint.GetEncoding.allowedValues[requestEncoding])) { │ │ │ │ - url.push(httpGet[i].url); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return new OpenLayers.Layer.WMTS( │ │ │ │ - OpenLayers.Util.applyDefaults(config, { │ │ │ │ - url: url, │ │ │ │ - requestEncoding: requestEncoding, │ │ │ │ - name: layerDef.title, │ │ │ │ - style: style.identifier, │ │ │ │ - format: format, │ │ │ │ - matrixIds: matrixSet.matrixIds, │ │ │ │ - matrixSet: matrixSet.identifier, │ │ │ │ - projection: projection, │ │ │ │ - units: units, │ │ │ │ - resolutions: config.isBaseLayer === false ? undefined : resolutions, │ │ │ │ - serverResolutions: resolutions, │ │ │ │ - tileFullExtent: matrixSet.bounds, │ │ │ │ - dimensions: dimensions, │ │ │ │ - params: params │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMTSCapabilities" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/CSWGetRecords.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.CSWGetRecords │ │ │ │ - * Default version is 2.0.2. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Format>} A CSWGetRecords format of the given version. │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.CSWGetRecords = function(options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults( │ │ │ │ - options, OpenLayers.Format.CSWGetRecords.DEFAULTS │ │ │ │ - ); │ │ │ │ - var cls = OpenLayers.Format.CSWGetRecords["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (!cls) { │ │ │ │ - throw "Unsupported CSWGetRecords version: " + options.version; │ │ │ │ - } │ │ │ │ - return new cls(options); │ │ │ │ -}; │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Constant: DEFAULTS │ │ │ │ - * {Object} Default properties for the CSWGetRecords format. │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.CSWGetRecords.DEFAULTS = { │ │ │ │ - "version": "2.0.2" │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ OpenLayers/Format/Context.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. */ │ │ │ │ @@ -77727,1295 +82607,1327 @@ │ │ │ │ "WCS": "urn:ogc:serviceType:WCS", │ │ │ │ "GML": "urn:ogc:serviceType:GML", │ │ │ │ "SLD": "urn:ogc:serviceType:SLD", │ │ │ │ "FES": "urn:ogc:serviceType:FES", │ │ │ │ "KML": "urn:ogc:serviceType:KML" │ │ │ │ }; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/SOSGetFeatureOfInterest.js │ │ │ │ + OpenLayers/Format/WMC.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/v3.js │ │ │ │ + * @requires OpenLayers/Format/Context.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.SOSGetFeatureOfInterest │ │ │ │ - * Read and write SOS GetFeatureOfInterest. This is used to get to │ │ │ │ - * the location of the features (stations). The stations can have 1 or more │ │ │ │ - * sensors. │ │ │ │ + * Class: OpenLayers.Format.WMC │ │ │ │ + * Read and write Web Map Context documents. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ + * - <OpenLayers.Format.Context> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.SOSGetFeatureOfInterest = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.XML, { │ │ │ │ +OpenLayers.Format.WMC = OpenLayers.Class(OpenLayers.Format.Context, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constant: VERSION │ │ │ │ - * {String} 1.0.0 │ │ │ │ - */ │ │ │ │ - VERSION: "1.0.0", │ │ │ │ + /** │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "1.1.0". │ │ │ │ + */ │ │ │ │ + defaultVersion: "1.1.0", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - sos: "http://www.opengis.net/sos/1.0", │ │ │ │ - gml: "http://www.opengis.net/gml", │ │ │ │ - sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMC │ │ │ │ + * Create a new parser for Web Map Context documents. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} Schema location │ │ │ │ - */ │ │ │ │ - schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosAll.xsd", │ │ │ │ + /** │ │ │ │ + * Method: layerToContext │ │ │ │ + * Create a layer context object given a wms layer object. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layer - {<OpenLayers.Layer.WMS>} The layer. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} A layer context object. │ │ │ │ + */ │ │ │ │ + layerToContext: function(layer) { │ │ │ │ + var parser = this.getParser(); │ │ │ │ + var layerContext = { │ │ │ │ + queryable: layer.queryable, │ │ │ │ + visibility: layer.visibility, │ │ │ │ + name: layer.params["LAYERS"], │ │ │ │ + title: layer.name, │ │ │ │ + "abstract": layer.metadata["abstract"], │ │ │ │ + dataURL: layer.metadata.dataURL, │ │ │ │ + metadataURL: layer.metadataURL, │ │ │ │ + server: { │ │ │ │ + version: layer.params["VERSION"], │ │ │ │ + url: layer.url │ │ │ │ + }, │ │ │ │ + maxExtent: layer.maxExtent, │ │ │ │ + transparent: layer.params["TRANSPARENT"], │ │ │ │ + numZoomLevels: layer.numZoomLevels, │ │ │ │ + units: layer.units, │ │ │ │ + isBaseLayer: layer.isBaseLayer, │ │ │ │ + opacity: layer.opacity == 1 ? undefined : layer.opacity, │ │ │ │ + displayInLayerSwitcher: layer.displayInLayerSwitcher, │ │ │ │ + singleTile: layer.singleTile, │ │ │ │ + tileSize: (layer.singleTile || !layer.tileSize) ? │ │ │ │ + undefined : { │ │ │ │ + width: layer.tileSize.w, │ │ │ │ + height: layer.tileSize.h │ │ │ │ + }, │ │ │ │ + minScale: (layer.options.resolutions || │ │ │ │ + layer.options.scales || │ │ │ │ + layer.options.maxResolution || │ │ │ │ + layer.options.minScale) ? │ │ │ │ + layer.minScale : undefined, │ │ │ │ + maxScale: (layer.options.resolutions || │ │ │ │ + layer.options.scales || │ │ │ │ + layer.options.minResolution || │ │ │ │ + layer.options.maxScale) ? │ │ │ │ + layer.maxScale : undefined, │ │ │ │ + formats: [], │ │ │ │ + styles: [], │ │ │ │ + srs: layer.srs, │ │ │ │ + dimensions: layer.dimensions │ │ │ │ + }; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ - */ │ │ │ │ - defaultPrefix: "sos", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ - */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ - }, │ │ │ │ + if (layer.metadata.servertitle) { │ │ │ │ + layerContext.server.title = layer.metadata.servertitle; │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.SOSGetFeatureOfInterest │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ + if (layer.metadata.formats && layer.metadata.formats.length > 0) { │ │ │ │ + for (var i = 0, len = layer.metadata.formats.length; i < len; i++) { │ │ │ │ + var format = layer.metadata.formats[i]; │ │ │ │ + layerContext.formats.push({ │ │ │ │ + value: format.value, │ │ │ │ + current: (format.value == layer.params["FORMAT"]) │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + layerContext.formats.push({ │ │ │ │ + value: layer.params["FORMAT"], │ │ │ │ + current: true │ │ │ │ + }); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Parse a GetFeatureOfInterest response and return an array 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]); │ │ │ │ + if (layer.metadata.styles && layer.metadata.styles.length > 0) { │ │ │ │ + for (var i = 0, len = layer.metadata.styles.length; i < len; i++) { │ │ │ │ + var style = layer.metadata.styles[i]; │ │ │ │ + if ((style.href == layer.params["SLD"]) || │ │ │ │ + (style.body == layer.params["SLD_BODY"]) || │ │ │ │ + (style.name == layer.params["STYLES"])) { │ │ │ │ + style.current = true; │ │ │ │ + } else { │ │ │ │ + style.current = false; │ │ │ │ + } │ │ │ │ + layerContext.styles.push(style); │ │ │ │ } │ │ │ │ - if (data && data.nodeType == 9) { │ │ │ │ - data = data.documentElement; │ │ │ │ + } else { │ │ │ │ + layerContext.styles.push({ │ │ │ │ + href: layer.params["SLD"], │ │ │ │ + body: layer.params["SLD_BODY"], │ │ │ │ + name: layer.params["STYLES"] || parser.defaultStyleName, │ │ │ │ + title: parser.defaultStyleTitle, │ │ │ │ + current: true │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return layerContext; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: toContext │ │ │ │ + * Create a context object free from layer given a map or a │ │ │ │ + * context object. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {<OpenLayers.Map> | Object} The map or context. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} A context object. │ │ │ │ + */ │ │ │ │ + toContext: function(obj) { │ │ │ │ + var context = {}; │ │ │ │ + var layers = obj.layers; │ │ │ │ + if (obj.CLASS_NAME == "OpenLayers.Map") { │ │ │ │ + var metadata = obj.metadata || {}; │ │ │ │ + context.size = obj.getSize(); │ │ │ │ + context.bounds = obj.getExtent(); │ │ │ │ + context.projection = obj.projection; │ │ │ │ + context.title = obj.title; │ │ │ │ + context.keywords = metadata.keywords; │ │ │ │ + context["abstract"] = metadata["abstract"]; │ │ │ │ + context.logo = metadata.logo; │ │ │ │ + context.descriptionURL = metadata.descriptionURL; │ │ │ │ + context.contactInformation = metadata.contactInformation; │ │ │ │ + context.maxExtent = obj.maxExtent; │ │ │ │ + } else { │ │ │ │ + // copy all obj properties except the "layers" property │ │ │ │ + OpenLayers.Util.applyDefaults(context, obj); │ │ │ │ + if (context.layers != undefined) { │ │ │ │ + delete(context.layers); │ │ │ │ } │ │ │ │ + } │ │ │ │ │ │ │ │ - var info = { │ │ │ │ - features: [] │ │ │ │ - }; │ │ │ │ - this.readNode(data, info); │ │ │ │ + if (context.layersContext == undefined) { │ │ │ │ + context.layersContext = []; │ │ │ │ + } │ │ │ │ │ │ │ │ - var features = []; │ │ │ │ - for (var i = 0, len = info.features.length; i < len; i++) { │ │ │ │ - var container = info.features[i]; │ │ │ │ - // reproject features if needed │ │ │ │ - if (this.internalProjection && this.externalProjection && │ │ │ │ - container.components[0]) { │ │ │ │ - container.components[0].transform( │ │ │ │ - this.externalProjection, this.internalProjection │ │ │ │ - ); │ │ │ │ + // let's convert layers into layersContext object (if any) │ │ │ │ + if (layers != undefined && OpenLayers.Util.isArray(layers)) { │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + var layer = layers[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.WMS) { │ │ │ │ + context.layersContext.push(this.layerToContext(layer)); │ │ │ │ } │ │ │ │ - var feature = new OpenLayers.Feature.Vector( │ │ │ │ - container.components[0], container.attributes); │ │ │ │ - features.push(feature); │ │ │ │ } │ │ │ │ - return features; │ │ │ │ - }, │ │ │ │ + } │ │ │ │ + return context; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMC" │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WCSCapabilities.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 │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WCSCapabilities │ │ │ │ + * Read WCS Capabilities. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WCSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "1.1.0". │ │ │ │ + */ │ │ │ │ + defaultVersion: "1.1.0", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WCSCapabilities │ │ │ │ + * Create a new parser for WCS capabilities. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return a list of coverages. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array} List of named coverages. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities" │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/QueryStringFilter.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/Console.js │ │ │ │ + * @requires OpenLayers/Format.js │ │ │ │ + * @requires OpenLayers/Filter/Spatial.js │ │ │ │ + * @requires OpenLayers/Filter/Comparison.js │ │ │ │ + * @requires OpenLayers/Filter/Logical.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.QueryStringFilter │ │ │ │ + * Parser for reading a query string and creating a simple filter. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.QueryStringFilter = (function() { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Map the OpenLayers.Filter.Comparison types to the operation strings of │ │ │ │ + * the protocol. │ │ │ │ + */ │ │ │ │ + var cmpToStr = {}; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.EQUAL_TO] = "eq"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.NOT_EQUAL_TO] = "ne"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN] = "lt"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO] = "lte"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN] = "gt"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO] = "gte"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.LIKE] = "ilike"; │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Function: regex2value │ │ │ │ + * Convert the value from a regular expression string to a LIKE/ILIKE │ │ │ │ + * string known to the web service. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * value - {String} The regex string. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} The converted string. │ │ │ │ + */ │ │ │ │ + function regex2value(value) { │ │ │ │ + │ │ │ │ + // highly sensitive!! Do not change this without running the │ │ │ │ + // Protocol/HTTP.html unit tests │ │ │ │ + │ │ │ │ + // convert % to \% │ │ │ │ + value = value.replace(/%/g, "\\%"); │ │ │ │ + │ │ │ │ + // convert \\. to \\_ (\\.* occurences converted later) │ │ │ │ + value = value.replace(/\\\\\.(\*)?/g, function($0, $1) { │ │ │ │ + return $1 ? $0 : "\\\\_"; │ │ │ │ + }); │ │ │ │ + │ │ │ │ + // convert \\.* to \\% │ │ │ │ + value = value.replace(/\\\\\.\*/g, "\\\\%"); │ │ │ │ + │ │ │ │ + // convert . to _ (\. and .* occurences converted later) │ │ │ │ + value = value.replace(/(\\)?\.(\*)?/g, function($0, $1, $2) { │ │ │ │ + return $1 || $2 ? $0 : "_"; │ │ │ │ + }); │ │ │ │ + │ │ │ │ + // convert .* to % (\.* occurnces converted later) │ │ │ │ + value = value.replace(/(\\)?\.\*/g, function($0, $1) { │ │ │ │ + return $1 ? $0 : "%"; │ │ │ │ + }); │ │ │ │ + │ │ │ │ + // convert \. to . │ │ │ │ + value = value.replace(/\\\./g, "."); │ │ │ │ + │ │ │ │ + // replace \* with * (watching out for \\*) │ │ │ │ + value = value.replace(/(\\)?\\\*/g, function($0, $1) { │ │ │ │ + return $1 ? $0 : "*"; │ │ │ │ + }); │ │ │ │ + │ │ │ │ + return value; │ │ │ │ + } │ │ │ │ + │ │ │ │ + return OpenLayers.Class(OpenLayers.Format, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - readers: { │ │ │ │ - "sa": { │ │ │ │ - "SamplingPoint": function(node, obj) { │ │ │ │ - // sampling point can also be without a featureMember if │ │ │ │ - // there is only 1 │ │ │ │ - if (!obj.attributes) { │ │ │ │ - var feature = { │ │ │ │ - attributes: {} │ │ │ │ - }; │ │ │ │ - obj.features.push(feature); │ │ │ │ - obj = feature; │ │ │ │ - } │ │ │ │ - obj.attributes.id = this.getAttributeNS(node, │ │ │ │ - this.namespaces.gml, "id"); │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "position": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "gml": OpenLayers.Util.applyDefaults({ │ │ │ │ - "FeatureCollection": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "featureMember": function(node, obj) { │ │ │ │ - var feature = { │ │ │ │ - attributes: {} │ │ │ │ - }; │ │ │ │ - obj.features.push(feature); │ │ │ │ - this.readChildNodes(node, feature); │ │ │ │ - }, │ │ │ │ - "name": function(node, obj) { │ │ │ │ - obj.attributes.name = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "pos": function(node, obj) { │ │ │ │ - // we need to parse the srsName to get to the │ │ │ │ - // externalProjection, that's why we cannot use │ │ │ │ - // GML v3 for this │ │ │ │ - if (!this.externalProjection) { │ │ │ │ - this.externalProjection = new OpenLayers.Projection( │ │ │ │ - node.getAttribute("srsName")); │ │ │ │ - } │ │ │ │ - OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply( │ │ │ │ - this, [node, obj]); │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.GML.v3.prototype.readers.gml) │ │ │ │ - }, │ │ │ │ + wildcarded: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * 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 │ │ │ │ */ │ │ │ │ - writers: { │ │ │ │ - "sos": { │ │ │ │ - "GetFeatureOfInterest": function(options) { │ │ │ │ - var node = this.createElementNSPlus("GetFeatureOfInterest", { │ │ │ │ - attributes: { │ │ │ │ - version: this.VERSION, │ │ │ │ - service: 'SOS', │ │ │ │ - "xsi:schemaLocation": this.schemaLocation │ │ │ │ + srsInBBOX: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: write │ │ │ │ + * Serialize an <OpenLayers.Filter> objects using the "simple" filter syntax for │ │ │ │ + * query string parameters. This function must be called as a method of │ │ │ │ + * a protocol instance. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * filter - {<OpenLayers.Filter>} filter to convert. │ │ │ │ + * params - {Object} The parameters object. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} The resulting parameters object. │ │ │ │ + */ │ │ │ │ + write: function(filter, params) { │ │ │ │ + params = params || {}; │ │ │ │ + var className = filter.CLASS_NAME; │ │ │ │ + var filterType = className.substring(className.lastIndexOf(".") + 1); │ │ │ │ + switch (filterType) { │ │ │ │ + case "Spatial": │ │ │ │ + switch (filter.type) { │ │ │ │ + case OpenLayers.Filter.Spatial.BBOX: │ │ │ │ + params.bbox = filter.value.toArray(); │ │ │ │ + if (this.srsInBBOX && filter.projection) { │ │ │ │ + params.bbox.push(filter.projection.getCode()); │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case OpenLayers.Filter.Spatial.DWITHIN: │ │ │ │ + params.tolerance = filter.distance; │ │ │ │ + // no break here │ │ │ │ + case OpenLayers.Filter.Spatial.WITHIN: │ │ │ │ + params.lon = filter.value.x; │ │ │ │ + params.lat = filter.value.y; │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + OpenLayers.Console.warn( │ │ │ │ + "Unknown spatial filter type " + filter.type); │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case "Comparison": │ │ │ │ + var op = cmpToStr[filter.type]; │ │ │ │ + if (op !== undefined) { │ │ │ │ + var value = filter.value; │ │ │ │ + if (filter.type == OpenLayers.Filter.Comparison.LIKE) { │ │ │ │ + value = regex2value(value); │ │ │ │ + if (this.wildcarded) { │ │ │ │ + value = "%" + value + "%"; │ │ │ │ + } │ │ │ │ } │ │ │ │ - }); │ │ │ │ - for (var i = 0, len = options.fois.length; i < len; i++) { │ │ │ │ - this.writeNode("FeatureOfInterestId", { │ │ │ │ - foi: options.fois[i] │ │ │ │ - }, node); │ │ │ │ + params[filter.property + "__" + op] = value; │ │ │ │ + params.queryable = params.queryable || []; │ │ │ │ + params.queryable.push(filter.property); │ │ │ │ + } else { │ │ │ │ + OpenLayers.Console.warn( │ │ │ │ + "Unknown comparison filter type " + filter.type); │ │ │ │ } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "FeatureOfInterestId": function(options) { │ │ │ │ - var node = this.createElementNSPlus("FeatureOfInterestId", { │ │ │ │ - value: options.foi │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ - } │ │ │ │ + break; │ │ │ │ + case "Logical": │ │ │ │ + if (filter.type === OpenLayers.Filter.Logical.AND) { │ │ │ │ + for (var i = 0, len = filter.filters.length; i < len; i++) { │ │ │ │ + params = this.write(filter.filters[i], params); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Console.warn( │ │ │ │ + "Unsupported logical filter type " + filter.type); │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + OpenLayers.Console.warn("Unknown filter type " + filterType); │ │ │ │ } │ │ │ │ + return params; │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SOSGetFeatureOfInterest" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.QueryStringFilter" │ │ │ │ │ │ │ │ }); │ │ │ │ + │ │ │ │ + │ │ │ │ +})(); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/SOSGetObservation.js │ │ │ │ + OpenLayers/Format/Atom.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/SOSGetFeatureOfInterest.js │ │ │ │ + * @requires OpenLayers/Format/GML/v3.js │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.SOSGetObservation │ │ │ │ - * Read and write SOS GetObersation (to get the actual values from a sensor) │ │ │ │ - * version 1.0.0 │ │ │ │ + * Class: OpenLayers.Format.Atom │ │ │ │ + * Read/write Atom feeds. Create a new instance with the │ │ │ │ + * <OpenLayers.Format.AtomFeed> constructor. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.SOSGetObservation = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ +OpenLayers.Format.Atom = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ /** │ │ │ │ * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + * {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: { │ │ │ │ - ows: "http://www.opengis.net/ows", │ │ │ │ - gml: "http://www.opengis.net/gml", │ │ │ │ - sos: "http://www.opengis.net/sos/1.0", │ │ │ │ - ogc: "http://www.opengis.net/ogc", │ │ │ │ - om: "http://www.opengis.net/om/1.0", │ │ │ │ - sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + atom: "http://www.w3.org/2005/Atom", │ │ │ │ + georss: "http://www.georss.org/georss" │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ + * APIProperty: feedTitle │ │ │ │ + * {String} Atom feed elements require a title. Default is "untitled". │ │ │ │ */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ - }, │ │ │ │ + feedTitle: "untitled", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: VERSION │ │ │ │ - * {String} 1.0.0 │ │ │ │ + * APIProperty: defaultEntryTitle │ │ │ │ + * {String} Atom entry elements require a title. In cases where one is │ │ │ │ + * not provided in the feature attributes, this will be used. Default │ │ │ │ + * is "untitled". │ │ │ │ */ │ │ │ │ - VERSION: "1.0.0", │ │ │ │ + defaultEntryTitle: "untitled", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} Schema location │ │ │ │ + * Property: gmlParse │ │ │ │ + * {Object} GML Format object for parsing features │ │ │ │ + * Non-API and only created if necessary │ │ │ │ */ │ │ │ │ - schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosGetObservation.xsd", │ │ │ │ + gmlParser: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ + * APIProperty: xy │ │ │ │ + * {Boolean} Order of the GML coordinate: true:(x,y) or false:(y,x) │ │ │ │ + * For GeoRSS the default is (y,x), therefore: false │ │ │ │ */ │ │ │ │ - defaultPrefix: "sos", │ │ │ │ + xy: false, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.SOSGetObservation │ │ │ │ + * Constructor: OpenLayers.Format.AtomEntry │ │ │ │ + * Create a new parser for Atom. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be set on │ │ │ │ * this instance. │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: read │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * APIMethod: read │ │ │ │ + * Return a list of features from an Atom feed or entry document. │ │ │ │ + │ │ │ │ + * Parameters: │ │ │ │ + * doc - {Element} or {String} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} An object containing the measurements │ │ │ │ + * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ */ │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - } │ │ │ │ - if (data && data.nodeType == 9) { │ │ │ │ - data = data.documentElement; │ │ │ │ + read: function(doc) { │ │ │ │ + if (typeof doc == "string") { │ │ │ │ + doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]); │ │ │ │ } │ │ │ │ - var info = { │ │ │ │ - measurements: [], │ │ │ │ - observations: [] │ │ │ │ - }; │ │ │ │ - this.readNode(data, info); │ │ │ │ - return info; │ │ │ │ + return this.parseFeatures(doc); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: write │ │ │ │ + * APIMethod: write │ │ │ │ + * Serialize or more feature nodes to Atom documents. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object. │ │ │ │ + * features - {<OpenLayers.Feature.Vector>} or Array({<OpenLayers.Feature.Vector>}) │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} An SOS GetObservation request XML string. │ │ │ │ + * {String} an Atom entry document if passed one feature node, or a feed │ │ │ │ + * document if passed an array of feature nodes. │ │ │ │ */ │ │ │ │ - write: function(options) { │ │ │ │ - var node = this.writeNode("sos:GetObservation", options); │ │ │ │ - node.setAttribute("xmlns:om", this.namespaces.om); │ │ │ │ - node.setAttribute("xmlns:ogc", this.namespaces.ogc); │ │ │ │ - this.setAttributeNS( │ │ │ │ - node, this.namespaces.xsi, │ │ │ │ - "xsi:schemaLocation", this.schemaLocation │ │ │ │ - ); │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [node]); │ │ │ │ + write: function(features) { │ │ │ │ + var doc; │ │ │ │ + if (OpenLayers.Util.isArray(features)) { │ │ │ │ + doc = this.createElementNSPlus("atom:feed"); │ │ │ │ + doc.appendChild( │ │ │ │ + this.createElementNSPlus("atom:title", { │ │ │ │ + value: this.feedTitle │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + for (var i = 0, ii = features.length; i < ii; i++) { │ │ │ │ + doc.appendChild(this.buildEntryNode(features[i])); │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + doc = this.buildEntryNode(features); │ │ │ │ + } │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [doc]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: buildContentNode │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * content - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} an Atom content node. │ │ │ │ + * │ │ │ │ + * TODO: types other than text. │ │ │ │ */ │ │ │ │ - readers: { │ │ │ │ - "om": { │ │ │ │ - "ObservationCollection": function(node, obj) { │ │ │ │ - obj.id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "member": function(node, observationCollection) { │ │ │ │ - this.readChildNodes(node, observationCollection); │ │ │ │ - }, │ │ │ │ - "Measurement": function(node, observationCollection) { │ │ │ │ - var measurement = {}; │ │ │ │ - observationCollection.measurements.push(measurement); │ │ │ │ - this.readChildNodes(node, measurement); │ │ │ │ - }, │ │ │ │ - "Observation": function(node, observationCollection) { │ │ │ │ - var observation = {}; │ │ │ │ - observationCollection.observations.push(observation); │ │ │ │ - this.readChildNodes(node, observation); │ │ │ │ - }, │ │ │ │ - "samplingTime": function(node, measurement) { │ │ │ │ - var samplingTime = {}; │ │ │ │ - measurement.samplingTime = samplingTime; │ │ │ │ - this.readChildNodes(node, samplingTime); │ │ │ │ - }, │ │ │ │ - "observedProperty": function(node, measurement) { │ │ │ │ - measurement.observedProperty = │ │ │ │ - this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ - this.readChildNodes(node, measurement); │ │ │ │ - }, │ │ │ │ - "procedure": function(node, measurement) { │ │ │ │ - measurement.procedure = │ │ │ │ - this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ - this.readChildNodes(node, measurement); │ │ │ │ - }, │ │ │ │ - "featureOfInterest": function(node, observation) { │ │ │ │ - var foi = { │ │ │ │ - features: [] │ │ │ │ - }; │ │ │ │ - observation.fois = []; │ │ │ │ - observation.fois.push(foi); │ │ │ │ - this.readChildNodes(node, foi); │ │ │ │ - // postprocessing to get actual features │ │ │ │ - var features = []; │ │ │ │ - for (var i = 0, len = foi.features.length; i < len; i++) { │ │ │ │ - var feature = foi.features[i]; │ │ │ │ - features.push(new OpenLayers.Feature.Vector( │ │ │ │ - feature.components[0], feature.attributes)); │ │ │ │ - } │ │ │ │ - foi.features = features; │ │ │ │ - }, │ │ │ │ - "result": function(node, measurement) { │ │ │ │ - var result = {}; │ │ │ │ - measurement.result = result; │ │ │ │ - if (this.getChildValue(node) !== '') { │ │ │ │ - result.value = this.getChildValue(node); │ │ │ │ - result.uom = node.getAttribute("uom"); │ │ │ │ - } else { │ │ │ │ - this.readChildNodes(node, result); │ │ │ │ - } │ │ │ │ + buildContentNode: function(content) { │ │ │ │ + var node = this.createElementNSPlus("atom:content", { │ │ │ │ + attributes: { │ │ │ │ + type: content.type || null │ │ │ │ } │ │ │ │ - }, │ │ │ │ - "sa": OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.sa, │ │ │ │ - "gml": OpenLayers.Util.applyDefaults({ │ │ │ │ - "TimeInstant": function(node, samplingTime) { │ │ │ │ - var timeInstant = {}; │ │ │ │ - samplingTime.timeInstant = timeInstant; │ │ │ │ - this.readChildNodes(node, timeInstant); │ │ │ │ - }, │ │ │ │ - "timePosition": function(node, timeInstant) { │ │ │ │ - timeInstant.timePosition = this.getChildValue(node); │ │ │ │ + }); │ │ │ │ + if (content.src) { │ │ │ │ + node.setAttribute("src", content.src); │ │ │ │ + } else { │ │ │ │ + if (content.type == "text" || content.type == null) { │ │ │ │ + node.appendChild( │ │ │ │ + this.createTextNode(content.value) │ │ │ │ + ); │ │ │ │ + } else if (content.type == "html") { │ │ │ │ + if (typeof content.value != "string") { │ │ │ │ + throw "HTML content must be in form of an escaped string"; │ │ │ │ + } │ │ │ │ + node.appendChild( │ │ │ │ + this.createTextNode(content.value) │ │ │ │ + ); │ │ │ │ + } else if (content.type == "xhtml") { │ │ │ │ + node.appendChild(content.value); │ │ │ │ + } else if (content.type == "xhtml" || │ │ │ │ + content.type.match(/(\+|\/)xml$/)) { │ │ │ │ + node.appendChild(content.value); │ │ │ │ + } else { // MUST be a valid Base64 encoding │ │ │ │ + node.appendChild( │ │ │ │ + this.createTextNode(content.value) │ │ │ │ + ); │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.gml) │ │ │ │ + } │ │ │ │ + return 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. │ │ │ │ + * Method: buildEntryNode │ │ │ │ + * Build an Atom entry node from a feature object. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} an Atom entry node. │ │ │ │ + * │ │ │ │ + * These entries are geared for publication using AtomPub. │ │ │ │ + * │ │ │ │ + * TODO: support extension elements │ │ │ │ */ │ │ │ │ - writers: { │ │ │ │ - "sos": { │ │ │ │ - "GetObservation": function(options) { │ │ │ │ - var node = this.createElementNSPlus("GetObservation", { │ │ │ │ - attributes: { │ │ │ │ - version: this.VERSION, │ │ │ │ - service: 'SOS' │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.writeNode("offering", options, node); │ │ │ │ - if (options.eventTime) { │ │ │ │ - this.writeNode("eventTime", options, node); │ │ │ │ - } │ │ │ │ - for (var procedure in options.procedures) { │ │ │ │ - this.writeNode("procedure", options.procedures[procedure], node); │ │ │ │ - } │ │ │ │ - for (var observedProperty in options.observedProperties) { │ │ │ │ - this.writeNode("observedProperty", options.observedProperties[observedProperty], node); │ │ │ │ - } │ │ │ │ - if (options.foi) { │ │ │ │ - this.writeNode("featureOfInterest", options.foi, node); │ │ │ │ - } │ │ │ │ - this.writeNode("responseFormat", options, node); │ │ │ │ - if (options.resultModel) { │ │ │ │ - this.writeNode("resultModel", options, node); │ │ │ │ - } │ │ │ │ - if (options.responseMode) { │ │ │ │ - this.writeNode("responseMode", options, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "featureOfInterest": function(foi) { │ │ │ │ - var node = this.createElementNSPlus("featureOfInterest"); │ │ │ │ - this.writeNode("ObjectID", foi.objectId, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ObjectID": function(options) { │ │ │ │ - return this.createElementNSPlus("ObjectID", { │ │ │ │ - value: options │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "responseFormat": function(options) { │ │ │ │ - return this.createElementNSPlus("responseFormat", { │ │ │ │ - value: options.responseFormat │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "procedure": function(procedure) { │ │ │ │ - return this.createElementNSPlus("procedure", { │ │ │ │ - value: procedure │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "offering": function(options) { │ │ │ │ - return this.createElementNSPlus("offering", { │ │ │ │ - value: options.offering │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "observedProperty": function(observedProperty) { │ │ │ │ - return this.createElementNSPlus("observedProperty", { │ │ │ │ - value: observedProperty │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "eventTime": function(options) { │ │ │ │ - var node = this.createElementNSPlus("eventTime"); │ │ │ │ - if (options.eventTime === 'latest') { │ │ │ │ - this.writeNode("ogc:TM_Equals", options, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "resultModel": function(options) { │ │ │ │ - return this.createElementNSPlus("resultModel", { │ │ │ │ - value: options.resultModel │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "responseMode": function(options) { │ │ │ │ - return this.createElementNSPlus("responseMode", { │ │ │ │ - value: options.responseMode │ │ │ │ - }); │ │ │ │ + buildEntryNode: function(feature) { │ │ │ │ + var attrib = feature.attributes; │ │ │ │ + var atomAttrib = attrib.atom || {}; │ │ │ │ + var entryNode = this.createElementNSPlus("atom:entry"); │ │ │ │ + │ │ │ │ + // atom:author │ │ │ │ + if (atomAttrib.authors) { │ │ │ │ + var authors = OpenLayers.Util.isArray(atomAttrib.authors) ? │ │ │ │ + atomAttrib.authors : [atomAttrib.authors]; │ │ │ │ + for (var i = 0, ii = authors.length; i < ii; i++) { │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.buildPersonConstructNode( │ │ │ │ + "author", authors[i] │ │ │ │ + ) │ │ │ │ + ); │ │ │ │ } │ │ │ │ - }, │ │ │ │ - "ogc": { │ │ │ │ - "TM_Equals": function(options) { │ │ │ │ - var node = this.createElementNSPlus("ogc:TM_Equals"); │ │ │ │ - this.writeNode("ogc:PropertyName", { │ │ │ │ - property: "urn:ogc:data:time:iso8601" │ │ │ │ - }, node); │ │ │ │ - if (options.eventTime === 'latest') { │ │ │ │ - this.writeNode("gml:TimeInstant", { │ │ │ │ - value: 'latest' │ │ │ │ - }, node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "PropertyName": function(options) { │ │ │ │ - return this.createElementNSPlus("ogc:PropertyName", { │ │ │ │ - value: options.property │ │ │ │ - }); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atom:category │ │ │ │ + if (atomAttrib.categories) { │ │ │ │ + var categories = OpenLayers.Util.isArray(atomAttrib.categories) ? │ │ │ │ + atomAttrib.categories : [atomAttrib.categories]; │ │ │ │ + var category; │ │ │ │ + for (var i = 0, ii = categories.length; i < ii; i++) { │ │ │ │ + category = categories[i]; │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:category", { │ │ │ │ + attributes: { │ │ │ │ + term: category.term, │ │ │ │ + scheme: category.scheme || null, │ │ │ │ + label: category.label || null │ │ │ │ + } │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ } │ │ │ │ - }, │ │ │ │ - "gml": { │ │ │ │ - "TimeInstant": function(options) { │ │ │ │ - var node = this.createElementNSPlus("gml:TimeInstant"); │ │ │ │ - this.writeNode("gml:timePosition", options, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "timePosition": function(options) { │ │ │ │ - var node = this.createElementNSPlus("gml:timePosition", { │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atom:content │ │ │ │ + if (atomAttrib.content) { │ │ │ │ + entryNode.appendChild(this.buildContentNode(atomAttrib.content)); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atom:contributor │ │ │ │ + if (atomAttrib.contributors) { │ │ │ │ + var contributors = OpenLayers.Util.isArray(atomAttrib.contributors) ? │ │ │ │ + atomAttrib.contributors : [atomAttrib.contributors]; │ │ │ │ + for (var i = 0, ii = contributors.length; i < ii; i++) { │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.buildPersonConstructNode( │ │ │ │ + "contributor", │ │ │ │ + contributors[i] │ │ │ │ + ) │ │ │ │ + ); │ │ │ │ } │ │ │ │ } │ │ │ │ - }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SOSGetObservation" │ │ │ │ + // atom:id │ │ │ │ + if (feature.fid) { │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:id", { │ │ │ │ + value: feature.fid │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSCapabilities.js │ │ │ │ - ====================================================================== */ │ │ │ │ + // atom:link │ │ │ │ + if (atomAttrib.links) { │ │ │ │ + var links = OpenLayers.Util.isArray(atomAttrib.links) ? │ │ │ │ + atomAttrib.links : [atomAttrib.links]; │ │ │ │ + var link; │ │ │ │ + for (var i = 0, ii = links.length; i < ii; i++) { │ │ │ │ + link = links[i]; │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:link", { │ │ │ │ + attributes: { │ │ │ │ + href: link.href, │ │ │ │ + rel: link.rel || null, │ │ │ │ + type: link.type || null, │ │ │ │ + hreflang: link.hreflang || null, │ │ │ │ + title: link.title || null, │ │ │ │ + length: link.length || null │ │ │ │ + } │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ │ │ │ │ -/* 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. */ │ │ │ │ + // atom:published │ │ │ │ + if (atomAttrib.published) { │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:published", { │ │ │ │ + value: atomAttrib.published │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Format/XML/VersionedOGC.js │ │ │ │ - */ │ │ │ │ + // atom:rights │ │ │ │ + if (atomAttrib.rights) { │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:rights", { │ │ │ │ + value: atomAttrib.rights │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSCapabilities │ │ │ │ - * Read WMS Capabilities. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + // atom:source not implemented │ │ │ │ + │ │ │ │ + // atom:summary │ │ │ │ + if (atomAttrib.summary || attrib.description) { │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:summary", { │ │ │ │ + value: atomAttrib.summary || attrib.description │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // atom:title │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:title", { │ │ │ │ + value: atomAttrib.title || attrib.title || this.defaultEntryTitle │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + │ │ │ │ + // atom:updated │ │ │ │ + if (atomAttrib.updated) { │ │ │ │ + entryNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:updated", { │ │ │ │ + value: atomAttrib.updated │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + │ │ │ │ + // georss:where │ │ │ │ + if (feature.geometry) { │ │ │ │ + var whereNode = this.createElementNSPlus("georss:where"); │ │ │ │ + whereNode.appendChild( │ │ │ │ + this.buildGeometryNode(feature.geometry) │ │ │ │ + ); │ │ │ │ + entryNode.appendChild(whereNode); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return entryNode; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "1.1.1". │ │ │ │ + * Method: initGmlParser │ │ │ │ + * Creates a GML parser. │ │ │ │ */ │ │ │ │ - defaultVersion: "1.1.1", │ │ │ │ + initGmlParser: function() { │ │ │ │ + this.gmlParser = new OpenLayers.Format.GML.v3({ │ │ │ │ + xy: this.xy, │ │ │ │ + featureNS: "http://example.com#feature", │ │ │ │ + internalProjection: this.internalProjection, │ │ │ │ + externalProjection: this.externalProjection │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: profile │ │ │ │ - * {String} If provided, use a custom profile. │ │ │ │ + * Method: buildGeometryNode │ │ │ │ + * builds a GeoRSS node with a given geometry │ │ │ │ * │ │ │ │ - * Currently supported profiles: │ │ │ │ - * - WMSC - parses vendor specific capabilities for WMS-C. │ │ │ │ + * Parameters: │ │ │ │ + * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A gml node. │ │ │ │ */ │ │ │ │ - profile: null, │ │ │ │ + buildGeometryNode: function(geometry) { │ │ │ │ + if (!this.gmlParser) { │ │ │ │ + this.initGmlParser(); │ │ │ │ + } │ │ │ │ + var node = this.gmlParser.writeNode("feature:_geometry", geometry); │ │ │ │ + return node.firstChild; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WMSCapabilities │ │ │ │ - * Create a new parser for WMS capabilities. │ │ │ │ + * Method: buildPersonConstructNode │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * name - {String} │ │ │ │ + * value - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} an Atom person construct node. │ │ │ │ + * │ │ │ │ + * Example: │ │ │ │ + * >>> buildPersonConstructNode("author", {name: "John Smith"}) │ │ │ │ + * {<author><name>John Smith</name></author>} │ │ │ │ + * │ │ │ │ + * TODO: how to specify extension elements? Add to the oNames array? │ │ │ │ */ │ │ │ │ + buildPersonConstructNode: function(name, value) { │ │ │ │ + var oNames = ["uri", "email"]; │ │ │ │ + var personNode = this.createElementNSPlus("atom:" + name); │ │ │ │ + personNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:name", { │ │ │ │ + value: value.name │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + for (var i = 0, ii = oNames.length; i < ii; i++) { │ │ │ │ + if (value[oNames[i]]) { │ │ │ │ + personNode.appendChild( │ │ │ │ + this.createElementNSPlus("atom:" + oNames[i], { │ │ │ │ + value: value[oNames[i]] │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return personNode; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return a list of layers. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * Method: getFirstChildValue │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} │ │ │ │ + * nsuri - {String} Child node namespace uri ("*" for any). │ │ │ │ + * name - {String} Child node name. │ │ │ │ + * def - {String} Optional string default to return if no child found. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Array} List of named layers. │ │ │ │ + * {String} The value of the first child with the given tag name. Returns │ │ │ │ + * default value or empty string if none found. │ │ │ │ */ │ │ │ │ + getFirstChildValue: function(node, nsuri, name, def) { │ │ │ │ + var value; │ │ │ │ + var nodes = this.getElementsByTagNameNS(node, nsuri, name); │ │ │ │ + if (nodes && nodes.length > 0) { │ │ │ │ + value = this.getChildValue(nodes[0], def); │ │ │ │ + } else { │ │ │ │ + value = def; │ │ │ │ + } │ │ │ │ + return value; │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/CQL.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/WKT.js │ │ │ │ - * @requires OpenLayers/Filter/Comparison.js │ │ │ │ - * @requires OpenLayers/Filter/Logical.js │ │ │ │ - * @requires OpenLayers/Filter/Spatial.js │ │ │ │ - */ │ │ │ │ + /** │ │ │ │ + * Method: parseFeature │ │ │ │ + * Parse feature from an Atom entry node.. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} An Atom entry or feed node. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Feature.Vector>} │ │ │ │ + */ │ │ │ │ + parseFeature: function(node) { │ │ │ │ + var atomAttrib = {}; │ │ │ │ + var value = null; │ │ │ │ + var nodes = null; │ │ │ │ + var attval = null; │ │ │ │ + var atomns = this.namespaces.atom; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.CQL │ │ │ │ - * Read CQL strings to get <OpenLayers.Filter> objects. Write │ │ │ │ - * <OpenLayers.Filter> objects to get CQL strings. Create a new parser with │ │ │ │ - * the <OpenLayers.Format.CQL> constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.CQL = (function() { │ │ │ │ + // atomAuthor* │ │ │ │ + this.parsePersonConstructs(node, "author", atomAttrib); │ │ │ │ │ │ │ │ - var tokens = [ │ │ │ │ - "PROPERTY", "COMPARISON", "VALUE", "LOGICAL" │ │ │ │ - ], │ │ │ │ + // atomCategory* │ │ │ │ + nodes = this.getElementsByTagNameNS(node, atomns, "category"); │ │ │ │ + if (nodes.length > 0) { │ │ │ │ + atomAttrib.categories = []; │ │ │ │ + } │ │ │ │ + for (var i = 0, ii = nodes.length; i < ii; i++) { │ │ │ │ + value = {}; │ │ │ │ + value.term = nodes[i].getAttribute("term"); │ │ │ │ + attval = nodes[i].getAttribute("scheme"); │ │ │ │ + if (attval) { │ │ │ │ + value.scheme = attval; │ │ │ │ + } │ │ │ │ + attval = nodes[i].getAttribute("label"); │ │ │ │ + if (attval) { │ │ │ │ + value.label = attval; │ │ │ │ + } │ │ │ │ + atomAttrib.categories.push(value); │ │ │ │ + } │ │ │ │ │ │ │ │ - patterns = { │ │ │ │ - PROPERTY: /^[_a-zA-Z]\w*/, │ │ │ │ - COMPARISON: /^(=|<>|<=|<|>=|>|LIKE)/i, │ │ │ │ - IS_NULL: /^IS NULL/i, │ │ │ │ - COMMA: /^,/, │ │ │ │ - LOGICAL: /^(AND|OR)/i, │ │ │ │ - VALUE: /^('([^']|'')*'|\d+(\.\d*)?|\.\d+)/, │ │ │ │ - LPAREN: /^\(/, │ │ │ │ - RPAREN: /^\)/, │ │ │ │ - SPATIAL: /^(BBOX|INTERSECTS|DWITHIN|WITHIN|CONTAINS)/i, │ │ │ │ - NOT: /^NOT/i, │ │ │ │ - BETWEEN: /^BETWEEN/i, │ │ │ │ - GEOMETRY: function(text) { │ │ │ │ - var type = /^(POINT|LINESTRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)/.exec(text); │ │ │ │ - if (type) { │ │ │ │ - var len = text.length; │ │ │ │ - var idx = text.indexOf("(", type[0].length); │ │ │ │ - if (idx > -1) { │ │ │ │ - var depth = 1; │ │ │ │ - while (idx < len && depth > 0) { │ │ │ │ - idx++; │ │ │ │ - switch (text.charAt(idx)) { │ │ │ │ - case '(': │ │ │ │ - depth++; │ │ │ │ - break; │ │ │ │ - case ')': │ │ │ │ - depth--; │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - // in default case, do nothing │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return [text.substr(0, idx + 1)]; │ │ │ │ + // atomContent? │ │ │ │ + nodes = this.getElementsByTagNameNS(node, atomns, "content"); │ │ │ │ + if (nodes.length > 0) { │ │ │ │ + value = {}; │ │ │ │ + attval = nodes[0].getAttribute("type"); │ │ │ │ + if (attval) { │ │ │ │ + value.type = attval; │ │ │ │ + } │ │ │ │ + attval = nodes[0].getAttribute("src"); │ │ │ │ + if (attval) { │ │ │ │ + value.src = attval; │ │ │ │ + } else { │ │ │ │ + if (value.type == "text" || │ │ │ │ + value.type == "html" || │ │ │ │ + value.type == null) { │ │ │ │ + value.value = this.getFirstChildValue( │ │ │ │ + node, │ │ │ │ + atomns, │ │ │ │ + "content", │ │ │ │ + null │ │ │ │ + ); │ │ │ │ + } else if (value.type == "xhtml" || │ │ │ │ + value.type.match(/(\+|\/)xml$/)) { │ │ │ │ + value.value = this.getChildEl(nodes[0]); │ │ │ │ + } else { // MUST be base64 encoded │ │ │ │ + value.value = this.getFirstChildValue( │ │ │ │ + node, │ │ │ │ + atomns, │ │ │ │ + "content", │ │ │ │ + null │ │ │ │ + ); │ │ │ │ } │ │ │ │ - }, │ │ │ │ - END: /^$/ │ │ │ │ - }, │ │ │ │ - │ │ │ │ - follows = { │ │ │ │ - LPAREN: ['GEOMETRY', 'SPATIAL', 'PROPERTY', 'VALUE', 'LPAREN'], │ │ │ │ - RPAREN: ['NOT', 'LOGICAL', 'END', 'RPAREN'], │ │ │ │ - PROPERTY: ['COMPARISON', 'BETWEEN', 'COMMA', 'IS_NULL'], │ │ │ │ - BETWEEN: ['VALUE'], │ │ │ │ - IS_NULL: ['END'], │ │ │ │ - COMPARISON: ['VALUE'], │ │ │ │ - COMMA: ['GEOMETRY', 'VALUE', 'PROPERTY'], │ │ │ │ - VALUE: ['LOGICAL', 'COMMA', 'RPAREN', 'END'], │ │ │ │ - SPATIAL: ['LPAREN'], │ │ │ │ - LOGICAL: ['NOT', 'VALUE', 'SPATIAL', 'PROPERTY', 'LPAREN'], │ │ │ │ - NOT: ['PROPERTY', 'LPAREN'], │ │ │ │ - GEOMETRY: ['COMMA', 'RPAREN'] │ │ │ │ - }, │ │ │ │ - │ │ │ │ - operators = { │ │ │ │ - '=': OpenLayers.Filter.Comparison.EQUAL_TO, │ │ │ │ - '<>': OpenLayers.Filter.Comparison.NOT_EQUAL_TO, │ │ │ │ - '<': OpenLayers.Filter.Comparison.LESS_THAN, │ │ │ │ - '<=': OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO, │ │ │ │ - '>': OpenLayers.Filter.Comparison.GREATER_THAN, │ │ │ │ - '>=': OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO, │ │ │ │ - 'LIKE': OpenLayers.Filter.Comparison.LIKE, │ │ │ │ - 'BETWEEN': OpenLayers.Filter.Comparison.BETWEEN, │ │ │ │ - 'IS NULL': OpenLayers.Filter.Comparison.IS_NULL │ │ │ │ - }, │ │ │ │ - │ │ │ │ - operatorReverse = {}, │ │ │ │ - │ │ │ │ - logicals = { │ │ │ │ - 'AND': OpenLayers.Filter.Logical.AND, │ │ │ │ - 'OR': OpenLayers.Filter.Logical.OR │ │ │ │ - }, │ │ │ │ - │ │ │ │ - logicalReverse = {}, │ │ │ │ - │ │ │ │ - precedence = { │ │ │ │ - 'RPAREN': 3, │ │ │ │ - 'LOGICAL': 2, │ │ │ │ - 'COMPARISON': 1 │ │ │ │ - }; │ │ │ │ - │ │ │ │ - var i; │ │ │ │ - for (i in operators) { │ │ │ │ - if (operators.hasOwnProperty(i)) { │ │ │ │ - operatorReverse[operators[i]] = i; │ │ │ │ + atomAttrib.content = value; │ │ │ │ + } │ │ │ │ } │ │ │ │ - } │ │ │ │ │ │ │ │ - for (i in logicals) { │ │ │ │ - if (logicals.hasOwnProperty(i)) { │ │ │ │ - logicalReverse[logicals[i]] = i; │ │ │ │ - } │ │ │ │ - } │ │ │ │ + // atomContributor* │ │ │ │ + this.parsePersonConstructs(node, "contributor", atomAttrib); │ │ │ │ │ │ │ │ - function tryToken(text, pattern) { │ │ │ │ - if (pattern instanceof RegExp) { │ │ │ │ - return pattern.exec(text); │ │ │ │ - } else { │ │ │ │ - return pattern(text); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + // atomId │ │ │ │ + atomAttrib.id = this.getFirstChildValue(node, atomns, "id", null); │ │ │ │ │ │ │ │ - function nextToken(text, tokens) { │ │ │ │ - var i, token, len = tokens.length; │ │ │ │ - for (i = 0; i < len; i++) { │ │ │ │ - token = tokens[i]; │ │ │ │ - var pat = patterns[token]; │ │ │ │ - var matches = tryToken(text, pat); │ │ │ │ - if (matches) { │ │ │ │ - var match = matches[0]; │ │ │ │ - var remainder = text.substr(match.length).replace(/^\s*/, ""); │ │ │ │ - return { │ │ │ │ - type: token, │ │ │ │ - text: match, │ │ │ │ - remainder: remainder │ │ │ │ - }; │ │ │ │ + // atomLink* │ │ │ │ + nodes = this.getElementsByTagNameNS(node, atomns, "link"); │ │ │ │ + if (nodes.length > 0) { │ │ │ │ + atomAttrib.links = new Array(nodes.length); │ │ │ │ + } │ │ │ │ + var oAtts = ["rel", "type", "hreflang", "title", "length"]; │ │ │ │ + for (var i = 0, ii = nodes.length; i < ii; i++) { │ │ │ │ + value = {}; │ │ │ │ + value.href = nodes[i].getAttribute("href"); │ │ │ │ + for (var j = 0, jj = oAtts.length; j < jj; j++) { │ │ │ │ + attval = nodes[i].getAttribute(oAtts[j]); │ │ │ │ + if (attval) { │ │ │ │ + value[oAtts[j]] = attval; │ │ │ │ + } │ │ │ │ } │ │ │ │ + atomAttrib.links[i] = value; │ │ │ │ } │ │ │ │ │ │ │ │ - var msg = "ERROR: In parsing: [" + text + "], expected one of: "; │ │ │ │ - for (i = 0; i < len; i++) { │ │ │ │ - token = tokens[i]; │ │ │ │ - msg += "\n " + token + ": " + patterns[token]; │ │ │ │ + // atomPublished? │ │ │ │ + value = this.getFirstChildValue(node, atomns, "published", null); │ │ │ │ + if (value) { │ │ │ │ + atomAttrib.published = value; │ │ │ │ } │ │ │ │ │ │ │ │ - throw new Error(msg); │ │ │ │ - } │ │ │ │ - │ │ │ │ - function tokenize(text) { │ │ │ │ - var results = []; │ │ │ │ - var token, expect = ["NOT", "GEOMETRY", "SPATIAL", "PROPERTY", "LPAREN"]; │ │ │ │ - │ │ │ │ - do { │ │ │ │ - token = nextToken(text, expect); │ │ │ │ - text = token.remainder; │ │ │ │ - expect = follows[token.type]; │ │ │ │ - if (token.type != "END" && !expect) { │ │ │ │ - throw new Error("No follows list for " + token.type); │ │ │ │ - } │ │ │ │ - results.push(token); │ │ │ │ - } while (token.type != "END"); │ │ │ │ + // atomRights? │ │ │ │ + value = this.getFirstChildValue(node, atomns, "rights", null); │ │ │ │ + if (value) { │ │ │ │ + atomAttrib.rights = value; │ │ │ │ + } │ │ │ │ │ │ │ │ - return results; │ │ │ │ - } │ │ │ │ + // atomSource? -- not implemented │ │ │ │ │ │ │ │ - function buildAst(tokens) { │ │ │ │ - var operatorStack = [], │ │ │ │ - postfix = []; │ │ │ │ + // atomSummary? │ │ │ │ + value = this.getFirstChildValue(node, atomns, "summary", null); │ │ │ │ + if (value) { │ │ │ │ + atomAttrib.summary = value; │ │ │ │ + } │ │ │ │ │ │ │ │ - while (tokens.length) { │ │ │ │ - var tok = tokens.shift(); │ │ │ │ - switch (tok.type) { │ │ │ │ - case "PROPERTY": │ │ │ │ - case "GEOMETRY": │ │ │ │ - case "VALUE": │ │ │ │ - postfix.push(tok); │ │ │ │ - break; │ │ │ │ - case "COMPARISON": │ │ │ │ - case "BETWEEN": │ │ │ │ - case "IS_NULL": │ │ │ │ - case "LOGICAL": │ │ │ │ - var p = precedence[tok.type]; │ │ │ │ + // atomTitle │ │ │ │ + atomAttrib.title = this.getFirstChildValue( │ │ │ │ + node, atomns, "title", null │ │ │ │ + ); │ │ │ │ │ │ │ │ - while (operatorStack.length > 0 && │ │ │ │ - (precedence[operatorStack[operatorStack.length - 1].type] <= p) │ │ │ │ - ) { │ │ │ │ - postfix.push(operatorStack.pop()); │ │ │ │ - } │ │ │ │ + // atomUpdated │ │ │ │ + atomAttrib.updated = this.getFirstChildValue( │ │ │ │ + node, atomns, "updated", null │ │ │ │ + ); │ │ │ │ │ │ │ │ - operatorStack.push(tok); │ │ │ │ - break; │ │ │ │ - case "SPATIAL": │ │ │ │ - case "NOT": │ │ │ │ - case "LPAREN": │ │ │ │ - operatorStack.push(tok); │ │ │ │ - break; │ │ │ │ - case "RPAREN": │ │ │ │ - while (operatorStack.length > 0 && │ │ │ │ - (operatorStack[operatorStack.length - 1].type != "LPAREN") │ │ │ │ - ) { │ │ │ │ - postfix.push(operatorStack.pop()); │ │ │ │ - } │ │ │ │ - operatorStack.pop(); // toss out the LPAREN │ │ │ │ + var featureAttrib = { │ │ │ │ + title: atomAttrib.title, │ │ │ │ + description: atomAttrib.summary, │ │ │ │ + atom: atomAttrib │ │ │ │ + }; │ │ │ │ + var geometry = this.parseLocations(node)[0]; │ │ │ │ + var feature = new OpenLayers.Feature.Vector(geometry, featureAttrib); │ │ │ │ + feature.fid = atomAttrib.id; │ │ │ │ + return feature; │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (operatorStack.length > 0 && │ │ │ │ - operatorStack[operatorStack.length - 1].type == "SPATIAL") { │ │ │ │ - postfix.push(operatorStack.pop()); │ │ │ │ - } │ │ │ │ - case "COMMA": │ │ │ │ - case "END": │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - throw new Error("Unknown token type " + tok.type); │ │ │ │ - } │ │ │ │ + /** │ │ │ │ + * Method: parseFeatures │ │ │ │ + * Return features from an Atom entry or feed. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} An Atom entry or feed node. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ + */ │ │ │ │ + parseFeatures: function(node) { │ │ │ │ + var features = []; │ │ │ │ + var entries = this.getElementsByTagNameNS( │ │ │ │ + node, this.namespaces.atom, "entry" │ │ │ │ + ); │ │ │ │ + if (entries.length == 0) { │ │ │ │ + entries = [node]; │ │ │ │ } │ │ │ │ - │ │ │ │ - while (operatorStack.length > 0) { │ │ │ │ - postfix.push(operatorStack.pop()); │ │ │ │ + for (var i = 0, ii = entries.length; i < ii; i++) { │ │ │ │ + features.push(this.parseFeature(entries[i])); │ │ │ │ } │ │ │ │ + return features; │ │ │ │ + }, │ │ │ │ │ │ │ │ - function buildTree() { │ │ │ │ - var tok = postfix.pop(); │ │ │ │ - switch (tok.type) { │ │ │ │ - case "LOGICAL": │ │ │ │ - var rhs = buildTree(), │ │ │ │ - lhs = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Logical({ │ │ │ │ - filters: [lhs, rhs], │ │ │ │ - type: logicals[tok.text.toUpperCase()] │ │ │ │ - }); │ │ │ │ - case "NOT": │ │ │ │ - var operand = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Logical({ │ │ │ │ - filters: [operand], │ │ │ │ - type: OpenLayers.Filter.Logical.NOT │ │ │ │ - }); │ │ │ │ - case "BETWEEN": │ │ │ │ - var min, max, property; │ │ │ │ - postfix.pop(); // unneeded AND token here │ │ │ │ - max = buildTree(); │ │ │ │ - min = buildTree(); │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Comparison({ │ │ │ │ - property: property, │ │ │ │ - lowerBoundary: min, │ │ │ │ - upperBoundary: max, │ │ │ │ - type: OpenLayers.Filter.Comparison.BETWEEN │ │ │ │ - }); │ │ │ │ - case "COMPARISON": │ │ │ │ - var value = buildTree(), │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Comparison({ │ │ │ │ - property: property, │ │ │ │ - value: value, │ │ │ │ - type: operators[tok.text.toUpperCase()] │ │ │ │ - }); │ │ │ │ - case "IS_NULL": │ │ │ │ - var property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Comparison({ │ │ │ │ - property: property, │ │ │ │ - type: operators[tok.text.toUpperCase()] │ │ │ │ - }); │ │ │ │ - case "VALUE": │ │ │ │ - var match = tok.text.match(/^'(.*)'$/); │ │ │ │ - if (match) { │ │ │ │ - return match[1].replace(/''/g, "'"); │ │ │ │ - } else { │ │ │ │ - return Number(tok.text); │ │ │ │ - } │ │ │ │ - case "SPATIAL": │ │ │ │ - switch (tok.text.toUpperCase()) { │ │ │ │ - case "BBOX": │ │ │ │ - var maxy = buildTree(), │ │ │ │ - maxx = buildTree(), │ │ │ │ - miny = buildTree(), │ │ │ │ - minx = buildTree(), │ │ │ │ - prop = buildTree(); │ │ │ │ + /** │ │ │ │ + * Method: parseLocations │ │ │ │ + * Parse the locations from an Atom entry or feed. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} An Atom entry or feed node. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * Array({<OpenLayers.Geometry>}) │ │ │ │ + */ │ │ │ │ + parseLocations: function(node) { │ │ │ │ + var georssns = this.namespaces.georss; │ │ │ │ │ │ │ │ - return new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ - property: prop, │ │ │ │ - value: OpenLayers.Bounds.fromArray( │ │ │ │ - [minx, miny, maxx, maxy] │ │ │ │ - ) │ │ │ │ - }); │ │ │ │ - case "INTERSECTS": │ │ │ │ - var value = buildTree(), │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ - property: property, │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - case "WITHIN": │ │ │ │ - var value = buildTree(), │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.WITHIN, │ │ │ │ - property: property, │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - case "CONTAINS": │ │ │ │ - var value = buildTree(), │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.CONTAINS, │ │ │ │ - property: property, │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - case "DWITHIN": │ │ │ │ - var distance = buildTree(), │ │ │ │ - value = buildTree(), │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.DWITHIN, │ │ │ │ - value: value, │ │ │ │ - property: property, │ │ │ │ - distance: Number(distance) │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - case "GEOMETRY": │ │ │ │ - return OpenLayers.Geometry.fromWKT(tok.text); │ │ │ │ - default: │ │ │ │ - return tok.text; │ │ │ │ + var locations = { │ │ │ │ + components: [] │ │ │ │ + }; │ │ │ │ + var where = this.getElementsByTagNameNS(node, georssns, "where"); │ │ │ │ + if (where && where.length > 0) { │ │ │ │ + if (!this.gmlParser) { │ │ │ │ + this.initGmlParser(); │ │ │ │ + } │ │ │ │ + for (var i = 0, ii = where.length; i < ii; i++) { │ │ │ │ + this.gmlParser.readChildNodes(where[i], locations); │ │ │ │ } │ │ │ │ } │ │ │ │ │ │ │ │ - var result = buildTree(); │ │ │ │ - if (postfix.length > 0) { │ │ │ │ - var msg = "Remaining tokens after building AST: \n"; │ │ │ │ - for (var i = postfix.length - 1; i >= 0; i--) { │ │ │ │ - msg += postfix[i].type + ": " + postfix[i].text + "\n"; │ │ │ │ + var components = locations.components; │ │ │ │ + var point = this.getElementsByTagNameNS(node, georssns, "point"); │ │ │ │ + if (point && point.length > 0) { │ │ │ │ + for (var i = 0, ii = point.length; i < ii; i++) { │ │ │ │ + var xy = OpenLayers.String.trim( │ │ │ │ + point[i].firstChild.nodeValue │ │ │ │ + ).split(/\s+/); │ │ │ │ + if (xy.length != 2) { │ │ │ │ + xy = OpenLayers.String.trim( │ │ │ │ + point[i].firstChild.nodeValue │ │ │ │ + ).split(/\s*,\s*/); │ │ │ │ + } │ │ │ │ + components.push(new OpenLayers.Geometry.Point(xy[1], xy[0])); │ │ │ │ } │ │ │ │ - throw new Error(msg); │ │ │ │ } │ │ │ │ │ │ │ │ - return result; │ │ │ │ - } │ │ │ │ - │ │ │ │ - return OpenLayers.Class(OpenLayers.Format, { │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Generate a filter from a CQL string. │ │ │ │ - │ │ │ │ - * Parameters: │ │ │ │ - * text - {String} The CQL text. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Filter>} A filter based on the CQL text. │ │ │ │ - */ │ │ │ │ - read: function(text) { │ │ │ │ - var result = buildAst(tokenize(text)); │ │ │ │ - if (this.keepData) { │ │ │ │ - this.data = result; │ │ │ │ + var line = this.getElementsByTagNameNS(node, georssns, "line"); │ │ │ │ + if (line && line.length > 0) { │ │ │ │ + var coords; │ │ │ │ + var p; │ │ │ │ + var points; │ │ │ │ + for (var i = 0, ii = line.length; i < ii; i++) { │ │ │ │ + coords = OpenLayers.String.trim( │ │ │ │ + line[i].firstChild.nodeValue │ │ │ │ + ).split(/\s+/); │ │ │ │ + points = []; │ │ │ │ + for (var j = 0, jj = coords.length; j < jj; j += 2) { │ │ │ │ + p = new OpenLayers.Geometry.Point(coords[j + 1], coords[j]); │ │ │ │ + points.push(p); │ │ │ │ + } │ │ │ │ + components.push( │ │ │ │ + new OpenLayers.Geometry.LineString(points) │ │ │ │ + ); │ │ │ │ } │ │ │ │ - return result; │ │ │ │ - }, │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Convert a filter into a CQL string. │ │ │ │ - │ │ │ │ - * Parameters: │ │ │ │ - * filter - {<OpenLayers.Filter>} The filter. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A CQL string based on the filter. │ │ │ │ - */ │ │ │ │ - write: function(filter) { │ │ │ │ - if (filter instanceof OpenLayers.Geometry) { │ │ │ │ - return filter.toString(); │ │ │ │ + var polygon = this.getElementsByTagNameNS(node, georssns, "polygon"); │ │ │ │ + if (polygon && polygon.length > 0) { │ │ │ │ + var coords; │ │ │ │ + var p; │ │ │ │ + var points; │ │ │ │ + for (var i = 0, ii = polygon.length; i < ii; i++) { │ │ │ │ + coords = OpenLayers.String.trim( │ │ │ │ + polygon[i].firstChild.nodeValue │ │ │ │ + ).split(/\s+/); │ │ │ │ + points = []; │ │ │ │ + for (var j = 0, jj = coords.length; j < jj; j += 2) { │ │ │ │ + p = new OpenLayers.Geometry.Point(coords[j + 1], coords[j]); │ │ │ │ + points.push(p); │ │ │ │ + } │ │ │ │ + components.push( │ │ │ │ + new OpenLayers.Geometry.Polygon( │ │ │ │ + [new OpenLayers.Geometry.LinearRing(points)] │ │ │ │ + ) │ │ │ │ + ); │ │ │ │ } │ │ │ │ - switch (filter.CLASS_NAME) { │ │ │ │ - case "OpenLayers.Filter.Spatial": │ │ │ │ - switch (filter.type) { │ │ │ │ - case OpenLayers.Filter.Spatial.BBOX: │ │ │ │ - return "BBOX(" + │ │ │ │ - filter.property + "," + │ │ │ │ - filter.value.toBBOX() + │ │ │ │ - ")"; │ │ │ │ - case OpenLayers.Filter.Spatial.DWITHIN: │ │ │ │ - return "DWITHIN(" + │ │ │ │ - filter.property + ", " + │ │ │ │ - this.write(filter.value) + ", " + │ │ │ │ - filter.distance + ")"; │ │ │ │ - case OpenLayers.Filter.Spatial.WITHIN: │ │ │ │ - return "WITHIN(" + │ │ │ │ - filter.property + ", " + │ │ │ │ - this.write(filter.value) + ")"; │ │ │ │ - case OpenLayers.Filter.Spatial.INTERSECTS: │ │ │ │ - return "INTERSECTS(" + │ │ │ │ - filter.property + ", " + │ │ │ │ - this.write(filter.value) + ")"; │ │ │ │ - case OpenLayers.Filter.Spatial.CONTAINS: │ │ │ │ - return "CONTAINS(" + │ │ │ │ - filter.property + ", " + │ │ │ │ - this.write(filter.value) + ")"; │ │ │ │ - default: │ │ │ │ - throw new Error("Unknown spatial filter type: " + filter.type); │ │ │ │ - } │ │ │ │ - case "OpenLayers.Filter.Logical": │ │ │ │ - if (filter.type == OpenLayers.Filter.Logical.NOT) { │ │ │ │ - // TODO: deal with precedence of logical operators to │ │ │ │ - // avoid extra parentheses (not urgent) │ │ │ │ - return "NOT (" + this.write(filter.filters[0]) + ")"; │ │ │ │ - } else { │ │ │ │ - var res = "("; │ │ │ │ - var first = true; │ │ │ │ - for (var i = 0; i < filter.filters.length; i++) { │ │ │ │ - if (first) { │ │ │ │ - first = false; │ │ │ │ - } else { │ │ │ │ - res += ") " + logicalReverse[filter.type] + " ("; │ │ │ │ - } │ │ │ │ - res += this.write(filter.filters[i]); │ │ │ │ - } │ │ │ │ - return res + ")"; │ │ │ │ - } │ │ │ │ - case "OpenLayers.Filter.Comparison": │ │ │ │ - if (filter.type == OpenLayers.Filter.Comparison.BETWEEN) { │ │ │ │ - return filter.property + " BETWEEN " + │ │ │ │ - this.write(filter.lowerBoundary) + " AND " + │ │ │ │ - this.write(filter.upperBoundary); │ │ │ │ - } else { │ │ │ │ - return (filter.value !== null) ? filter.property + │ │ │ │ - " " + operatorReverse[filter.type] + " " + │ │ │ │ - this.write(filter.value) : filter.property + │ │ │ │ - " " + operatorReverse[filter.type]; │ │ │ │ - } │ │ │ │ - case undefined: │ │ │ │ - if (typeof filter === "string") { │ │ │ │ - return "'" + filter.replace(/'/g, "''") + "'"; │ │ │ │ - } else if (typeof filter === "number") { │ │ │ │ - return String(filter); │ │ │ │ - } │ │ │ │ - default: │ │ │ │ - throw new Error("Can't encode: " + filter.CLASS_NAME + " " + filter); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + for (var i = 0, ii = components.length; i < ii; i++) { │ │ │ │ + if (components[i]) { │ │ │ │ + components[i].transform( │ │ │ │ + this.externalProjection, │ │ │ │ + this.internalProjection │ │ │ │ + ); │ │ │ │ + } │ │ │ │ } │ │ │ │ - }, │ │ │ │ + } │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.CQL" │ │ │ │ + return components; │ │ │ │ + }, │ │ │ │ │ │ │ │ - }); │ │ │ │ -})(); │ │ │ │ + /** │ │ │ │ + * Method: parsePersonConstruct │ │ │ │ + * Parse Atom person constructs from an Atom entry node. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} An Atom entry or feed node. │ │ │ │ + * name - {String} Construcy name ("author" or "contributor") │ │ │ │ + * data = {Object} Object in which to put parsed persons. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * An {Object}. │ │ │ │ + */ │ │ │ │ + parsePersonConstructs: function(node, name, data) { │ │ │ │ + var persons = []; │ │ │ │ + var atomns = this.namespaces.atom; │ │ │ │ + var nodes = this.getElementsByTagNameNS(node, atomns, name); │ │ │ │ + var oAtts = ["uri", "email"]; │ │ │ │ + for (var i = 0, ii = nodes.length; i < ii; i++) { │ │ │ │ + var value = {}; │ │ │ │ + value.name = this.getFirstChildValue( │ │ │ │ + nodes[i], │ │ │ │ + atomns, │ │ │ │ + "name", │ │ │ │ + null │ │ │ │ + ); │ │ │ │ + for (var j = 0, jj = oAtts.length; j < jj; j++) { │ │ │ │ + var attval = this.getFirstChildValue( │ │ │ │ + nodes[i], │ │ │ │ + atomns, │ │ │ │ + oAtts[j], │ │ │ │ + null); │ │ │ │ + if (attval) { │ │ │ │ + value[oAtts[j]] = attval; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + persons.push(value); │ │ │ │ + } │ │ │ │ + if (persons.length > 0) { │ │ │ │ + data[name + "s"] = persons; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Format.Atom" │ │ │ │ +}); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WMC.js │ │ │ │ + OpenLayers/Format/WMSDescribeLayer.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/Context.js │ │ │ │ + * @requires OpenLayers/Format/XML/VersionedOGC.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WMC │ │ │ │ - * Read and write Web Map Context documents. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.WMSDescribeLayer │ │ │ │ + * Read SLD WMS DescribeLayer response │ │ │ │ + * DescribeLayer is meant to couple WMS to WFS and WCS │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.Context> │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WMC = OpenLayers.Class(OpenLayers.Format.Context, { │ │ │ │ +OpenLayers.Format.WMSDescribeLayer = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ │ │ │ │ /** │ │ │ │ * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "1.1.0". │ │ │ │ + * {String} Version number to assume if none found. Default is "1.1.1". │ │ │ │ */ │ │ │ │ - defaultVersion: "1.1.0", │ │ │ │ + defaultVersion: "1.1.1", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WMC │ │ │ │ - * Create a new parser for Web Map Context documents. │ │ │ │ + * Constructor: OpenLayers.Format.WMSDescribeLayer │ │ │ │ + * Create a new parser for WMS DescribeLayer responses. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be set on │ │ │ │ * this instance. │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: layerToContext │ │ │ │ - * Create a layer context object given a wms layer object. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layer - {<OpenLayers.Layer.WMS>} The layer. │ │ │ │ + * APIMethod: read │ │ │ │ + * Read DescribeLayer data from a string, and return the response. │ │ │ │ + * The OGC currently defines 2 formats which are allowed for output, │ │ │ │ + * so we need to parse these 2 types │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} A layer context object. │ │ │ │ + * {Array} Array of {<LayerDescription>} objects which have: │ │ │ │ + * - {String} owsType: WFS/WCS │ │ │ │ + * - {String} owsURL: the online resource │ │ │ │ + * - {String} typeName: the name of the typename on the service │ │ │ │ */ │ │ │ │ - layerToContext: function(layer) { │ │ │ │ - var parser = this.getParser(); │ │ │ │ - var layerContext = { │ │ │ │ - queryable: layer.queryable, │ │ │ │ - visibility: layer.visibility, │ │ │ │ - name: layer.params["LAYERS"], │ │ │ │ - title: layer.name, │ │ │ │ - "abstract": layer.metadata["abstract"], │ │ │ │ - dataURL: layer.metadata.dataURL, │ │ │ │ - metadataURL: layer.metadataURL, │ │ │ │ - server: { │ │ │ │ - version: layer.params["VERSION"], │ │ │ │ - url: layer.url │ │ │ │ - }, │ │ │ │ - maxExtent: layer.maxExtent, │ │ │ │ - transparent: layer.params["TRANSPARENT"], │ │ │ │ - numZoomLevels: layer.numZoomLevels, │ │ │ │ - units: layer.units, │ │ │ │ - isBaseLayer: layer.isBaseLayer, │ │ │ │ - opacity: layer.opacity == 1 ? undefined : layer.opacity, │ │ │ │ - displayInLayerSwitcher: layer.displayInLayerSwitcher, │ │ │ │ - singleTile: layer.singleTile, │ │ │ │ - tileSize: (layer.singleTile || !layer.tileSize) ? │ │ │ │ - undefined : { │ │ │ │ - width: layer.tileSize.w, │ │ │ │ - height: layer.tileSize.h │ │ │ │ - }, │ │ │ │ - minScale: (layer.options.resolutions || │ │ │ │ - layer.options.scales || │ │ │ │ - layer.options.maxResolution || │ │ │ │ - layer.options.minScale) ? │ │ │ │ - layer.minScale : undefined, │ │ │ │ - maxScale: (layer.options.resolutions || │ │ │ │ - layer.options.scales || │ │ │ │ - layer.options.minResolution || │ │ │ │ - layer.options.maxScale) ? │ │ │ │ - layer.maxScale : undefined, │ │ │ │ - formats: [], │ │ │ │ - styles: [], │ │ │ │ - srs: layer.srs, │ │ │ │ - dimensions: layer.dimensions │ │ │ │ - }; │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer" │ │ │ │ │ │ │ │ - if (layer.metadata.servertitle) { │ │ │ │ - layerContext.server.title = layer.metadata.servertitle; │ │ │ │ - } │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/SOSCapabilities.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - if (layer.metadata.formats && layer.metadata.formats.length > 0) { │ │ │ │ - for (var i = 0, len = layer.metadata.formats.length; i < len; i++) { │ │ │ │ - var format = layer.metadata.formats[i]; │ │ │ │ - layerContext.formats.push({ │ │ │ │ - value: format.value, │ │ │ │ - current: (format.value == layer.params["FORMAT"]) │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - layerContext.formats.push({ │ │ │ │ - value: layer.params["FORMAT"], │ │ │ │ - current: true │ │ │ │ - }); │ │ │ │ - } │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - if (layer.metadata.styles && layer.metadata.styles.length > 0) { │ │ │ │ - for (var i = 0, len = layer.metadata.styles.length; i < len; i++) { │ │ │ │ - var style = layer.metadata.styles[i]; │ │ │ │ - if ((style.href == layer.params["SLD"]) || │ │ │ │ - (style.body == layer.params["SLD_BODY"]) || │ │ │ │ - (style.name == layer.params["STYLES"])) { │ │ │ │ - style.current = true; │ │ │ │ - } else { │ │ │ │ - style.current = false; │ │ │ │ - } │ │ │ │ - layerContext.styles.push(style); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - layerContext.styles.push({ │ │ │ │ - href: layer.params["SLD"], │ │ │ │ - body: layer.params["SLD_BODY"], │ │ │ │ - name: layer.params["STYLES"] || parser.defaultStyleName, │ │ │ │ - title: parser.defaultStyleTitle, │ │ │ │ - current: true │ │ │ │ - }); │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/XML/VersionedOGC.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - return layerContext; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.SOSCapabilities │ │ │ │ + * Read SOS Capabilities. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.SOSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: toContext │ │ │ │ - * Create a context object free from layer given a map or a │ │ │ │ - * context object. │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "1.0.0". │ │ │ │ + */ │ │ │ │ + defaultVersion: "1.0.0", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.SOSCapabilities │ │ │ │ + * Create a new parser for SOS Capabilities. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * obj - {<OpenLayers.Map> | Object} The map or context. │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return information about │ │ │ │ + * the service (offering and observedProperty mostly). │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} A context object. │ │ │ │ + * {Object} Info about the SOS │ │ │ │ */ │ │ │ │ - toContext: function(obj) { │ │ │ │ - var context = {}; │ │ │ │ - var layers = obj.layers; │ │ │ │ - if (obj.CLASS_NAME == "OpenLayers.Map") { │ │ │ │ - var metadata = obj.metadata || {}; │ │ │ │ - context.size = obj.getSize(); │ │ │ │ - context.bounds = obj.getExtent(); │ │ │ │ - context.projection = obj.projection; │ │ │ │ - context.title = obj.title; │ │ │ │ - context.keywords = metadata.keywords; │ │ │ │ - context["abstract"] = metadata["abstract"]; │ │ │ │ - context.logo = metadata.logo; │ │ │ │ - context.descriptionURL = metadata.descriptionURL; │ │ │ │ - context.contactInformation = metadata.contactInformation; │ │ │ │ - context.maxExtent = obj.maxExtent; │ │ │ │ - } else { │ │ │ │ - // copy all obj properties except the "layers" property │ │ │ │ - OpenLayers.Util.applyDefaults(context, obj); │ │ │ │ - if (context.layers != undefined) { │ │ │ │ - delete(context.layers); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (context.layersContext == undefined) { │ │ │ │ - context.layersContext = []; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // let's convert layers into layersContext object (if any) │ │ │ │ - if (layers != undefined && OpenLayers.Util.isArray(layers)) { │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - var layer = layers[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.WMS) { │ │ │ │ - context.layersContext.push(this.layerToContext(layer)); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return context; │ │ │ │ - }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMC" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SOSCapabilities" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WPSCapabilities.js │ │ │ │ + OpenLayers/Format/WMSCapabilities.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 │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WPSCapabilities │ │ │ │ - * Read WPS Capabilities. │ │ │ │ + * Class: OpenLayers.Format.WMSCapabilities │ │ │ │ + * Read WMS Capabilities. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WPSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ +OpenLayers.Format.WMSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ │ │ │ │ /** │ │ │ │ * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "1.0.0". │ │ │ │ + * {String} Version number to assume if none found. Default is "1.1.1". │ │ │ │ */ │ │ │ │ - defaultVersion: "1.0.0", │ │ │ │ + defaultVersion: "1.1.1", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WPSCapabilities │ │ │ │ - * Create a new parser for WPS Capabilities. │ │ │ │ + * APIProperty: profile │ │ │ │ + * {String} If provided, use a custom profile. │ │ │ │ + * │ │ │ │ + * Currently supported profiles: │ │ │ │ + * - WMSC - parses vendor specific capabilities for WMS-C. │ │ │ │ + */ │ │ │ │ + profile: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMSCapabilities │ │ │ │ + * Create a new parser for WMS capabilities. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be set on │ │ │ │ * this instance. │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return information about │ │ │ │ - * the service. │ │ │ │ + * Read capabilities data from a string, and return a list of layers. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * data - {String} or {DOMElement} data to read/parse. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} Info about the WPS │ │ │ │ + * {Array} List of named layers. │ │ │ │ */ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WPSCapabilities" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Format/EncodedPolyline.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ @@ -79573,732 +84485,1657 @@ │ │ │ │ │ │ │ │ return result; │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.EncodedPolyline" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/Atom.js │ │ │ │ + OpenLayers/Format/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/Format/XML.js │ │ │ │ - * @requires OpenLayers/Format/GML/v3.js │ │ │ │ * @requires OpenLayers/Feature/Vector.js │ │ │ │ + * @requires OpenLayers/Geometry/Point.js │ │ │ │ + * @requires OpenLayers/Geometry/LineString.js │ │ │ │ + * @requires OpenLayers/Geometry/Polygon.js │ │ │ │ + * @requires OpenLayers/Projection.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.OSM │ │ │ │ + * OSM parser. Create a new instance with the │ │ │ │ + * <OpenLayers.Format.OSM> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.OSM = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: checkTags │ │ │ │ + * {Boolean} Should tags be checked to determine whether something │ │ │ │ + * should be treated as a seperate node. Will slow down parsing. │ │ │ │ + * Default is false. │ │ │ │ + */ │ │ │ │ + checkTags: false, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: interestingTagsExclude │ │ │ │ + * {Array} List of tags to exclude from 'interesting' checks on nodes. │ │ │ │ + * Must be set when creating the format. Will only be used if checkTags │ │ │ │ + * is set. │ │ │ │ + */ │ │ │ │ + interestingTagsExclude: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: areaTags │ │ │ │ + * {Array} List of tags indicating that something is an area. │ │ │ │ + * Must be set when creating the format. Will only be used if │ │ │ │ + * checkTags is true. │ │ │ │ + */ │ │ │ │ + areaTags: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.OSM │ │ │ │ + * Create a new parser for OSM. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + initialize: function(options) { │ │ │ │ + var layer_defaults = { │ │ │ │ + 'interestingTagsExclude': ['source', 'source_ref', │ │ │ │ + 'source:ref', 'history', 'attribution', 'created_by' │ │ │ │ + ], │ │ │ │ + 'areaTags': ['area', 'building', 'leisure', 'tourism', 'ruins', │ │ │ │ + 'historic', 'landuse', 'military', 'natural', 'sport' │ │ │ │ + ] │ │ │ │ + }; │ │ │ │ + │ │ │ │ + layer_defaults = OpenLayers.Util.extend(layer_defaults, options); │ │ │ │ + │ │ │ │ + var interesting = {}; │ │ │ │ + for (var i = 0; i < layer_defaults.interestingTagsExclude.length; i++) { │ │ │ │ + interesting[layer_defaults.interestingTagsExclude[i]] = true; │ │ │ │ + } │ │ │ │ + layer_defaults.interestingTagsExclude = interesting; │ │ │ │ + │ │ │ │ + var area = {}; │ │ │ │ + for (var i = 0; i < layer_defaults.areaTags.length; i++) { │ │ │ │ + area[layer_defaults.areaTags[i]] = true; │ │ │ │ + } │ │ │ │ + layer_defaults.areaTags = area; │ │ │ │ + │ │ │ │ + // OSM coordinates are always in longlat WGS84 │ │ │ │ + this.externalProjection = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ + │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [layer_defaults]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Return a list of features from a OSM doc │ │ │ │ + │ │ │ │ + * Parameters: │ │ │ │ + * doc - {Element} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ + */ │ │ │ │ + read: function(doc) { │ │ │ │ + if (typeof doc == "string") { │ │ │ │ + doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var nodes = this.getNodes(doc); │ │ │ │ + var ways = this.getWays(doc); │ │ │ │ + │ │ │ │ + // Geoms will contain at least ways.length entries. │ │ │ │ + var feat_list = new Array(ways.length); │ │ │ │ + │ │ │ │ + for (var i = 0; i < ways.length; i++) { │ │ │ │ + // We know the minimal of this one ahead of time. (Could be -1 │ │ │ │ + // due to areas/polygons) │ │ │ │ + var point_list = new Array(ways[i].nodes.length); │ │ │ │ + │ │ │ │ + var poly = this.isWayArea(ways[i]) ? 1 : 0; │ │ │ │ + for (var j = 0; j < ways[i].nodes.length; j++) { │ │ │ │ + var node = nodes[ways[i].nodes[j]]; │ │ │ │ + │ │ │ │ + var point = new OpenLayers.Geometry.Point(node.lon, node.lat); │ │ │ │ + │ │ │ │ + // Since OSM is topological, we stash the node ID internally. │ │ │ │ + point.osm_id = parseInt(ways[i].nodes[j]); │ │ │ │ + point_list[j] = point; │ │ │ │ + │ │ │ │ + // We don't display nodes if they're used inside other │ │ │ │ + // elements. │ │ │ │ + node.used = true; │ │ │ │ + } │ │ │ │ + var geometry = null; │ │ │ │ + if (poly) { │ │ │ │ + geometry = new OpenLayers.Geometry.Polygon( │ │ │ │ + new OpenLayers.Geometry.LinearRing(point_list)); │ │ │ │ + } else { │ │ │ │ + geometry = new OpenLayers.Geometry.LineString(point_list); │ │ │ │ + } │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + geometry.transform(this.externalProjection, │ │ │ │ + this.internalProjection); │ │ │ │ + } │ │ │ │ + var feat = new OpenLayers.Feature.Vector(geometry, │ │ │ │ + ways[i].tags); │ │ │ │ + feat.osm_id = parseInt(ways[i].id); │ │ │ │ + feat.fid = "way." + feat.osm_id; │ │ │ │ + feat_list[i] = feat; │ │ │ │ + } │ │ │ │ + for (var node_id in nodes) { │ │ │ │ + var node = nodes[node_id]; │ │ │ │ + if (!node.used || this.checkTags) { │ │ │ │ + var tags = null; │ │ │ │ + │ │ │ │ + if (this.checkTags) { │ │ │ │ + var result = this.getTags(node.node, true); │ │ │ │ + if (node.used && !result[1]) { │ │ │ │ + continue; │ │ │ │ + } │ │ │ │ + tags = result[0]; │ │ │ │ + } else { │ │ │ │ + tags = this.getTags(node.node); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var feat = new OpenLayers.Feature.Vector( │ │ │ │ + new OpenLayers.Geometry.Point(node['lon'], node['lat']), │ │ │ │ + tags); │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + feat.geometry.transform(this.externalProjection, │ │ │ │ + this.internalProjection); │ │ │ │ + } │ │ │ │ + feat.osm_id = parseInt(node_id); │ │ │ │ + feat.fid = "node." + feat.osm_id; │ │ │ │ + feat_list.push(feat); │ │ │ │ + } │ │ │ │ + // Memory cleanup │ │ │ │ + node.node = null; │ │ │ │ + } │ │ │ │ + return feat_list; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getNodes │ │ │ │ + * Return the node items from a doc. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * doc - {DOMElement} node to parse tags from │ │ │ │ + */ │ │ │ │ + getNodes: function(doc) { │ │ │ │ + var node_list = doc.getElementsByTagName("node"); │ │ │ │ + var nodes = {}; │ │ │ │ + for (var i = 0; i < node_list.length; i++) { │ │ │ │ + var node = node_list[i]; │ │ │ │ + var id = node.getAttribute("id"); │ │ │ │ + nodes[id] = { │ │ │ │ + 'lat': node.getAttribute("lat"), │ │ │ │ + 'lon': node.getAttribute("lon"), │ │ │ │ + 'node': node │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + return nodes; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getWays │ │ │ │ + * Return the way items from a doc. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * doc - {DOMElement} node to parse tags from │ │ │ │ + */ │ │ │ │ + getWays: function(doc) { │ │ │ │ + var way_list = doc.getElementsByTagName("way"); │ │ │ │ + var return_ways = []; │ │ │ │ + for (var i = 0; i < way_list.length; i++) { │ │ │ │ + var way = way_list[i]; │ │ │ │ + var way_object = { │ │ │ │ + id: way.getAttribute("id") │ │ │ │ + }; │ │ │ │ + │ │ │ │ + way_object.tags = this.getTags(way); │ │ │ │ + │ │ │ │ + var node_list = way.getElementsByTagName("nd"); │ │ │ │ + │ │ │ │ + way_object.nodes = new Array(node_list.length); │ │ │ │ + │ │ │ │ + for (var j = 0; j < node_list.length; j++) { │ │ │ │ + way_object.nodes[j] = node_list[j].getAttribute("ref"); │ │ │ │ + } │ │ │ │ + return_ways.push(way_object); │ │ │ │ + } │ │ │ │ + return return_ways; │ │ │ │ + │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: getTags │ │ │ │ + * Return the tags list attached to a specific DOM element. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * dom_node - {DOMElement} node to parse tags from │ │ │ │ + * interesting_tags - {Boolean} whether the return from this function should │ │ │ │ + * return a boolean indicating that it has 'interesting tags' -- │ │ │ │ + * tags like attribution and source are ignored. (To change the list │ │ │ │ + * of tags, see interestingTagsExclude) │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * tags - {Object} hash of tags │ │ │ │ + * interesting - {Boolean} if interesting_tags is passed, returns │ │ │ │ + * whether there are any interesting tags on this element. │ │ │ │ + */ │ │ │ │ + getTags: function(dom_node, interesting_tags) { │ │ │ │ + var tag_list = dom_node.getElementsByTagName("tag"); │ │ │ │ + var tags = {}; │ │ │ │ + var interesting = false; │ │ │ │ + for (var j = 0; j < tag_list.length; j++) { │ │ │ │ + var key = tag_list[j].getAttribute("k"); │ │ │ │ + tags[key] = tag_list[j].getAttribute("v"); │ │ │ │ + if (interesting_tags) { │ │ │ │ + if (!this.interestingTagsExclude[key]) { │ │ │ │ + interesting = true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return interesting_tags ? [tags, interesting] : tags; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: isWayArea │ │ │ │ + * Given a way object from getWays, check whether the tags and geometry │ │ │ │ + * indicate something is an area. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Boolean} │ │ │ │ + */ │ │ │ │ + isWayArea: function(way) { │ │ │ │ + var poly_shaped = false; │ │ │ │ + var poly_tags = false; │ │ │ │ + │ │ │ │ + if (way.nodes[0] == way.nodes[way.nodes.length - 1]) { │ │ │ │ + poly_shaped = true; │ │ │ │ + } │ │ │ │ + if (this.checkTags) { │ │ │ │ + for (var key in way.tags) { │ │ │ │ + if (this.areaTags[key]) { │ │ │ │ + poly_tags = true; │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return poly_shaped && (this.checkTags ? poly_tags : true); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: write │ │ │ │ + * Takes a list of features, returns a serialized OSM format file for use │ │ │ │ + * in tools like JOSM. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ + */ │ │ │ │ + write: function(features) { │ │ │ │ + if (!(OpenLayers.Util.isArray(features))) { │ │ │ │ + features = [features]; │ │ │ │ + } │ │ │ │ + │ │ │ │ + this.osm_id = 1; │ │ │ │ + this.created_nodes = {}; │ │ │ │ + var root_node = this.createElementNS(null, "osm"); │ │ │ │ + root_node.setAttribute("version", "0.5"); │ │ │ │ + root_node.setAttribute("generator", "OpenLayers " + OpenLayers.VERSION_NUMBER); │ │ │ │ + │ │ │ │ + // Loop backwards, because the deserializer puts nodes last, and │ │ │ │ + // we want them first if possible │ │ │ │ + for (var i = features.length - 1; i >= 0; i--) { │ │ │ │ + var nodes = this.createFeatureNodes(features[i]); │ │ │ │ + for (var j = 0; j < nodes.length; j++) { │ │ │ │ + root_node.appendChild(nodes[j]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [root_node]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: createFeatureNodes │ │ │ │ + * Takes a feature, returns a list of nodes from size 0->n. │ │ │ │ + * Will include all pieces of the serialization that are required which │ │ │ │ + * have not already been created. Calls out to createXML based on geometry │ │ │ │ + * type. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + */ │ │ │ │ + createFeatureNodes: function(feature) { │ │ │ │ + var nodes = []; │ │ │ │ + var className = feature.geometry.CLASS_NAME; │ │ │ │ + var type = className.substring(className.lastIndexOf(".") + 1); │ │ │ │ + type = type.toLowerCase(); │ │ │ │ + var builder = this.createXML[type]; │ │ │ │ + if (builder) { │ │ │ │ + nodes = builder.apply(this, [feature]); │ │ │ │ + } │ │ │ │ + return nodes; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: createXML │ │ │ │ + * Takes a feature, returns a list of nodes from size 0->n. │ │ │ │ + * Will include all pieces of the serialization that are required which │ │ │ │ + * have not already been created. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + */ │ │ │ │ + createXML: { │ │ │ │ + 'point': function(point) { │ │ │ │ + var id = null; │ │ │ │ + var geometry = point.geometry ? point.geometry : point; │ │ │ │ + │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + geometry = geometry.clone(); │ │ │ │ + geometry.transform(this.internalProjection, │ │ │ │ + this.externalProjection); │ │ │ │ + } │ │ │ │ + │ │ │ │ + var already_exists = false; // We don't return anything if the node │ │ │ │ + // has already been created │ │ │ │ + if (point.osm_id) { │ │ │ │ + id = point.osm_id; │ │ │ │ + if (this.created_nodes[id]) { │ │ │ │ + already_exists = true; │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + id = -this.osm_id; │ │ │ │ + this.osm_id++; │ │ │ │ + } │ │ │ │ + if (already_exists) { │ │ │ │ + node = this.created_nodes[id]; │ │ │ │ + } else { │ │ │ │ + var node = this.createElementNS(null, "node"); │ │ │ │ + } │ │ │ │ + this.created_nodes[id] = node; │ │ │ │ + node.setAttribute("id", id); │ │ │ │ + node.setAttribute("lon", geometry.x); │ │ │ │ + node.setAttribute("lat", geometry.y); │ │ │ │ + if (point.attributes) { │ │ │ │ + this.serializeTags(point, node); │ │ │ │ + } │ │ │ │ + this.setState(point, node); │ │ │ │ + return already_exists ? [] : [node]; │ │ │ │ + }, │ │ │ │ + linestring: function(feature) { │ │ │ │ + var id; │ │ │ │ + var nodes = []; │ │ │ │ + var geometry = feature.geometry; │ │ │ │ + if (feature.osm_id) { │ │ │ │ + id = feature.osm_id; │ │ │ │ + } else { │ │ │ │ + id = -this.osm_id; │ │ │ │ + this.osm_id++; │ │ │ │ + } │ │ │ │ + var way = this.createElementNS(null, "way"); │ │ │ │ + way.setAttribute("id", id); │ │ │ │ + for (var i = 0; i < geometry.components.length; i++) { │ │ │ │ + var node = this.createXML['point'].apply(this, [geometry.components[i]]); │ │ │ │ + if (node.length) { │ │ │ │ + node = node[0]; │ │ │ │ + var node_ref = node.getAttribute("id"); │ │ │ │ + nodes.push(node); │ │ │ │ + } else { │ │ │ │ + node_ref = geometry.components[i].osm_id; │ │ │ │ + node = this.created_nodes[node_ref]; │ │ │ │ + } │ │ │ │ + this.setState(feature, node); │ │ │ │ + var nd_dom = this.createElementNS(null, "nd"); │ │ │ │ + nd_dom.setAttribute("ref", node_ref); │ │ │ │ + way.appendChild(nd_dom); │ │ │ │ + } │ │ │ │ + this.serializeTags(feature, way); │ │ │ │ + nodes.push(way); │ │ │ │ + │ │ │ │ + return nodes; │ │ │ │ + }, │ │ │ │ + polygon: function(feature) { │ │ │ │ + var attrs = OpenLayers.Util.extend({ │ │ │ │ + 'area': 'yes' │ │ │ │ + }, feature.attributes); │ │ │ │ + var feat = new OpenLayers.Feature.Vector(feature.geometry.components[0], attrs); │ │ │ │ + feat.osm_id = feature.osm_id; │ │ │ │ + return this.createXML['linestring'].apply(this, [feat]); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: serializeTags │ │ │ │ + * Given a feature, serialize the attributes onto the given node. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * node - {DOMNode} │ │ │ │ + */ │ │ │ │ + serializeTags: function(feature, node) { │ │ │ │ + for (var key in feature.attributes) { │ │ │ │ + var tag = this.createElementNS(null, "tag"); │ │ │ │ + tag.setAttribute("k", key); │ │ │ │ + tag.setAttribute("v", feature.attributes[key]); │ │ │ │ + node.appendChild(tag); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: setState │ │ │ │ + * OpenStreetMap has a convention that 'state' is stored for modification or deletion. │ │ │ │ + * This allows the file to be uploaded via JOSM or the bulk uploader tool. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ + * node - {DOMNode} │ │ │ │ + */ │ │ │ │ + setState: function(feature, node) { │ │ │ │ + if (feature.state) { │ │ │ │ + var state = null; │ │ │ │ + switch (feature.state) { │ │ │ │ + case OpenLayers.State.UPDATE: │ │ │ │ + state = "modify"; │ │ │ │ + case OpenLayers.State.DELETE: │ │ │ │ + state = "delete"; │ │ │ │ + } │ │ │ │ + if (state) { │ │ │ │ + node.setAttribute("action", state); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.OSM" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/CQL.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/WKT.js │ │ │ │ + * @requires OpenLayers/Filter/Comparison.js │ │ │ │ + * @requires OpenLayers/Filter/Logical.js │ │ │ │ + * @requires OpenLayers/Filter/Spatial.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.Atom │ │ │ │ - * Read/write Atom feeds. Create a new instance with the │ │ │ │ - * <OpenLayers.Format.AtomFeed> constructor. │ │ │ │ + * Class: OpenLayers.Format.CQL │ │ │ │ + * Read CQL strings to get <OpenLayers.Filter> objects. Write │ │ │ │ + * <OpenLayers.Filter> objects to get CQL strings. Create a new parser with │ │ │ │ + * the <OpenLayers.Format.CQL> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.CQL = (function() { │ │ │ │ + │ │ │ │ + var tokens = [ │ │ │ │ + "PROPERTY", "COMPARISON", "VALUE", "LOGICAL" │ │ │ │ + ], │ │ │ │ + │ │ │ │ + patterns = { │ │ │ │ + PROPERTY: /^[_a-zA-Z]\w*/, │ │ │ │ + COMPARISON: /^(=|<>|<=|<|>=|>|LIKE)/i, │ │ │ │ + IS_NULL: /^IS NULL/i, │ │ │ │ + COMMA: /^,/, │ │ │ │ + LOGICAL: /^(AND|OR)/i, │ │ │ │ + VALUE: /^('([^']|'')*'|\d+(\.\d*)?|\.\d+)/, │ │ │ │ + LPAREN: /^\(/, │ │ │ │ + RPAREN: /^\)/, │ │ │ │ + SPATIAL: /^(BBOX|INTERSECTS|DWITHIN|WITHIN|CONTAINS)/i, │ │ │ │ + NOT: /^NOT/i, │ │ │ │ + BETWEEN: /^BETWEEN/i, │ │ │ │ + GEOMETRY: function(text) { │ │ │ │ + var type = /^(POINT|LINESTRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)/.exec(text); │ │ │ │ + if (type) { │ │ │ │ + var len = text.length; │ │ │ │ + var idx = text.indexOf("(", type[0].length); │ │ │ │ + if (idx > -1) { │ │ │ │ + var depth = 1; │ │ │ │ + while (idx < len && depth > 0) { │ │ │ │ + idx++; │ │ │ │ + switch (text.charAt(idx)) { │ │ │ │ + case '(': │ │ │ │ + depth++; │ │ │ │ + break; │ │ │ │ + case ')': │ │ │ │ + depth--; │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + // in default case, do nothing │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return [text.substr(0, idx + 1)]; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + END: /^$/ │ │ │ │ + }, │ │ │ │ + │ │ │ │ + follows = { │ │ │ │ + LPAREN: ['GEOMETRY', 'SPATIAL', 'PROPERTY', 'VALUE', 'LPAREN'], │ │ │ │ + RPAREN: ['NOT', 'LOGICAL', 'END', 'RPAREN'], │ │ │ │ + PROPERTY: ['COMPARISON', 'BETWEEN', 'COMMA', 'IS_NULL'], │ │ │ │ + BETWEEN: ['VALUE'], │ │ │ │ + IS_NULL: ['END'], │ │ │ │ + COMPARISON: ['VALUE'], │ │ │ │ + COMMA: ['GEOMETRY', 'VALUE', 'PROPERTY'], │ │ │ │ + VALUE: ['LOGICAL', 'COMMA', 'RPAREN', 'END'], │ │ │ │ + SPATIAL: ['LPAREN'], │ │ │ │ + LOGICAL: ['NOT', 'VALUE', 'SPATIAL', 'PROPERTY', 'LPAREN'], │ │ │ │ + NOT: ['PROPERTY', 'LPAREN'], │ │ │ │ + GEOMETRY: ['COMMA', 'RPAREN'] │ │ │ │ + }, │ │ │ │ + │ │ │ │ + operators = { │ │ │ │ + '=': OpenLayers.Filter.Comparison.EQUAL_TO, │ │ │ │ + '<>': OpenLayers.Filter.Comparison.NOT_EQUAL_TO, │ │ │ │ + '<': OpenLayers.Filter.Comparison.LESS_THAN, │ │ │ │ + '<=': OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO, │ │ │ │ + '>': OpenLayers.Filter.Comparison.GREATER_THAN, │ │ │ │ + '>=': OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO, │ │ │ │ + 'LIKE': OpenLayers.Filter.Comparison.LIKE, │ │ │ │ + 'BETWEEN': OpenLayers.Filter.Comparison.BETWEEN, │ │ │ │ + 'IS NULL': OpenLayers.Filter.Comparison.IS_NULL │ │ │ │ + }, │ │ │ │ + │ │ │ │ + operatorReverse = {}, │ │ │ │ + │ │ │ │ + logicals = { │ │ │ │ + 'AND': OpenLayers.Filter.Logical.AND, │ │ │ │ + 'OR': OpenLayers.Filter.Logical.OR │ │ │ │ + }, │ │ │ │ + │ │ │ │ + logicalReverse = {}, │ │ │ │ + │ │ │ │ + precedence = { │ │ │ │ + 'RPAREN': 3, │ │ │ │ + 'LOGICAL': 2, │ │ │ │ + 'COMPARISON': 1 │ │ │ │ + }; │ │ │ │ + │ │ │ │ + var i; │ │ │ │ + for (i in operators) { │ │ │ │ + if (operators.hasOwnProperty(i)) { │ │ │ │ + operatorReverse[operators[i]] = i; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + for (i in logicals) { │ │ │ │ + if (logicals.hasOwnProperty(i)) { │ │ │ │ + logicalReverse[logicals[i]] = i; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + function tryToken(text, pattern) { │ │ │ │ + if (pattern instanceof RegExp) { │ │ │ │ + return pattern.exec(text); │ │ │ │ + } else { │ │ │ │ + return pattern(text); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + function nextToken(text, tokens) { │ │ │ │ + var i, token, len = tokens.length; │ │ │ │ + for (i = 0; i < len; i++) { │ │ │ │ + token = tokens[i]; │ │ │ │ + var pat = patterns[token]; │ │ │ │ + var matches = tryToken(text, pat); │ │ │ │ + if (matches) { │ │ │ │ + var match = matches[0]; │ │ │ │ + var remainder = text.substr(match.length).replace(/^\s*/, ""); │ │ │ │ + return { │ │ │ │ + type: token, │ │ │ │ + text: match, │ │ │ │ + remainder: remainder │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + var msg = "ERROR: In parsing: [" + text + "], expected one of: "; │ │ │ │ + for (i = 0; i < len; i++) { │ │ │ │ + token = tokens[i]; │ │ │ │ + msg += "\n " + token + ": " + patterns[token]; │ │ │ │ + } │ │ │ │ + │ │ │ │ + throw new Error(msg); │ │ │ │ + } │ │ │ │ + │ │ │ │ + function tokenize(text) { │ │ │ │ + var results = []; │ │ │ │ + var token, expect = ["NOT", "GEOMETRY", "SPATIAL", "PROPERTY", "LPAREN"]; │ │ │ │ + │ │ │ │ + do { │ │ │ │ + token = nextToken(text, expect); │ │ │ │ + text = token.remainder; │ │ │ │ + expect = follows[token.type]; │ │ │ │ + if (token.type != "END" && !expect) { │ │ │ │ + throw new Error("No follows list for " + token.type); │ │ │ │ + } │ │ │ │ + results.push(token); │ │ │ │ + } while (token.type != "END"); │ │ │ │ + │ │ │ │ + return results; │ │ │ │ + } │ │ │ │ + │ │ │ │ + function buildAst(tokens) { │ │ │ │ + var operatorStack = [], │ │ │ │ + postfix = []; │ │ │ │ + │ │ │ │ + while (tokens.length) { │ │ │ │ + var tok = tokens.shift(); │ │ │ │ + switch (tok.type) { │ │ │ │ + case "PROPERTY": │ │ │ │ + case "GEOMETRY": │ │ │ │ + case "VALUE": │ │ │ │ + postfix.push(tok); │ │ │ │ + break; │ │ │ │ + case "COMPARISON": │ │ │ │ + case "BETWEEN": │ │ │ │ + case "IS_NULL": │ │ │ │ + case "LOGICAL": │ │ │ │ + var p = precedence[tok.type]; │ │ │ │ + │ │ │ │ + while (operatorStack.length > 0 && │ │ │ │ + (precedence[operatorStack[operatorStack.length - 1].type] <= p) │ │ │ │ + ) { │ │ │ │ + postfix.push(operatorStack.pop()); │ │ │ │ + } │ │ │ │ + │ │ │ │ + operatorStack.push(tok); │ │ │ │ + break; │ │ │ │ + case "SPATIAL": │ │ │ │ + case "NOT": │ │ │ │ + case "LPAREN": │ │ │ │ + operatorStack.push(tok); │ │ │ │ + break; │ │ │ │ + case "RPAREN": │ │ │ │ + while (operatorStack.length > 0 && │ │ │ │ + (operatorStack[operatorStack.length - 1].type != "LPAREN") │ │ │ │ + ) { │ │ │ │ + postfix.push(operatorStack.pop()); │ │ │ │ + } │ │ │ │ + operatorStack.pop(); // toss out the LPAREN │ │ │ │ + │ │ │ │ + if (operatorStack.length > 0 && │ │ │ │ + operatorStack[operatorStack.length - 1].type == "SPATIAL") { │ │ │ │ + postfix.push(operatorStack.pop()); │ │ │ │ + } │ │ │ │ + case "COMMA": │ │ │ │ + case "END": │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + throw new Error("Unknown token type " + tok.type); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + while (operatorStack.length > 0) { │ │ │ │ + postfix.push(operatorStack.pop()); │ │ │ │ + } │ │ │ │ + │ │ │ │ + function buildTree() { │ │ │ │ + var tok = postfix.pop(); │ │ │ │ + switch (tok.type) { │ │ │ │ + case "LOGICAL": │ │ │ │ + var rhs = buildTree(), │ │ │ │ + lhs = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Logical({ │ │ │ │ + filters: [lhs, rhs], │ │ │ │ + type: logicals[tok.text.toUpperCase()] │ │ │ │ + }); │ │ │ │ + case "NOT": │ │ │ │ + var operand = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Logical({ │ │ │ │ + filters: [operand], │ │ │ │ + type: OpenLayers.Filter.Logical.NOT │ │ │ │ + }); │ │ │ │ + case "BETWEEN": │ │ │ │ + var min, max, property; │ │ │ │ + postfix.pop(); // unneeded AND token here │ │ │ │ + max = buildTree(); │ │ │ │ + min = buildTree(); │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Comparison({ │ │ │ │ + property: property, │ │ │ │ + lowerBoundary: min, │ │ │ │ + upperBoundary: max, │ │ │ │ + type: OpenLayers.Filter.Comparison.BETWEEN │ │ │ │ + }); │ │ │ │ + case "COMPARISON": │ │ │ │ + var value = buildTree(), │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Comparison({ │ │ │ │ + property: property, │ │ │ │ + value: value, │ │ │ │ + type: operators[tok.text.toUpperCase()] │ │ │ │ + }); │ │ │ │ + case "IS_NULL": │ │ │ │ + var property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Comparison({ │ │ │ │ + property: property, │ │ │ │ + type: operators[tok.text.toUpperCase()] │ │ │ │ + }); │ │ │ │ + case "VALUE": │ │ │ │ + var match = tok.text.match(/^'(.*)'$/); │ │ │ │ + if (match) { │ │ │ │ + return match[1].replace(/''/g, "'"); │ │ │ │ + } else { │ │ │ │ + return Number(tok.text); │ │ │ │ + } │ │ │ │ + case "SPATIAL": │ │ │ │ + switch (tok.text.toUpperCase()) { │ │ │ │ + case "BBOX": │ │ │ │ + var maxy = buildTree(), │ │ │ │ + maxx = buildTree(), │ │ │ │ + miny = buildTree(), │ │ │ │ + minx = buildTree(), │ │ │ │ + prop = buildTree(); │ │ │ │ + │ │ │ │ + return new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ + property: prop, │ │ │ │ + value: OpenLayers.Bounds.fromArray( │ │ │ │ + [minx, miny, maxx, maxy] │ │ │ │ + ) │ │ │ │ + }); │ │ │ │ + case "INTERSECTS": │ │ │ │ + var value = buildTree(), │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ + property: property, │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + case "WITHIN": │ │ │ │ + var value = buildTree(), │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.WITHIN, │ │ │ │ + property: property, │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + case "CONTAINS": │ │ │ │ + var value = buildTree(), │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.CONTAINS, │ │ │ │ + property: property, │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + case "DWITHIN": │ │ │ │ + var distance = buildTree(), │ │ │ │ + value = buildTree(), │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.DWITHIN, │ │ │ │ + value: value, │ │ │ │ + property: property, │ │ │ │ + distance: Number(distance) │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + case "GEOMETRY": │ │ │ │ + return OpenLayers.Geometry.fromWKT(tok.text); │ │ │ │ + default: │ │ │ │ + return tok.text; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + var result = buildTree(); │ │ │ │ + if (postfix.length > 0) { │ │ │ │ + var msg = "Remaining tokens after building AST: \n"; │ │ │ │ + for (var i = postfix.length - 1; i >= 0; i--) { │ │ │ │ + msg += postfix[i].type + ": " + postfix[i].text + "\n"; │ │ │ │ + } │ │ │ │ + throw new Error(msg); │ │ │ │ + } │ │ │ │ + │ │ │ │ + return result; │ │ │ │ + } │ │ │ │ + │ │ │ │ + return OpenLayers.Class(OpenLayers.Format, { │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Generate a filter from a CQL string. │ │ │ │ + │ │ │ │ + * Parameters: │ │ │ │ + * text - {String} The CQL text. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {<OpenLayers.Filter>} A filter based on the CQL text. │ │ │ │ + */ │ │ │ │ + read: function(text) { │ │ │ │ + var result = buildAst(tokenize(text)); │ │ │ │ + if (this.keepData) { │ │ │ │ + this.data = result; │ │ │ │ + } │ │ │ │ + return result; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: write │ │ │ │ + * Convert a filter into a CQL string. │ │ │ │ + │ │ │ │ + * Parameters: │ │ │ │ + * filter - {<OpenLayers.Filter>} The filter. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A CQL string based on the filter. │ │ │ │ + */ │ │ │ │ + write: function(filter) { │ │ │ │ + if (filter instanceof OpenLayers.Geometry) { │ │ │ │ + return filter.toString(); │ │ │ │ + } │ │ │ │ + switch (filter.CLASS_NAME) { │ │ │ │ + case "OpenLayers.Filter.Spatial": │ │ │ │ + switch (filter.type) { │ │ │ │ + case OpenLayers.Filter.Spatial.BBOX: │ │ │ │ + return "BBOX(" + │ │ │ │ + filter.property + "," + │ │ │ │ + filter.value.toBBOX() + │ │ │ │ + ")"; │ │ │ │ + case OpenLayers.Filter.Spatial.DWITHIN: │ │ │ │ + return "DWITHIN(" + │ │ │ │ + filter.property + ", " + │ │ │ │ + this.write(filter.value) + ", " + │ │ │ │ + filter.distance + ")"; │ │ │ │ + case OpenLayers.Filter.Spatial.WITHIN: │ │ │ │ + return "WITHIN(" + │ │ │ │ + filter.property + ", " + │ │ │ │ + this.write(filter.value) + ")"; │ │ │ │ + case OpenLayers.Filter.Spatial.INTERSECTS: │ │ │ │ + return "INTERSECTS(" + │ │ │ │ + filter.property + ", " + │ │ │ │ + this.write(filter.value) + ")"; │ │ │ │ + case OpenLayers.Filter.Spatial.CONTAINS: │ │ │ │ + return "CONTAINS(" + │ │ │ │ + filter.property + ", " + │ │ │ │ + this.write(filter.value) + ")"; │ │ │ │ + default: │ │ │ │ + throw new Error("Unknown spatial filter type: " + filter.type); │ │ │ │ + } │ │ │ │ + case "OpenLayers.Filter.Logical": │ │ │ │ + if (filter.type == OpenLayers.Filter.Logical.NOT) { │ │ │ │ + // TODO: deal with precedence of logical operators to │ │ │ │ + // avoid extra parentheses (not urgent) │ │ │ │ + return "NOT (" + this.write(filter.filters[0]) + ")"; │ │ │ │ + } else { │ │ │ │ + var res = "("; │ │ │ │ + var first = true; │ │ │ │ + for (var i = 0; i < filter.filters.length; i++) { │ │ │ │ + if (first) { │ │ │ │ + first = false; │ │ │ │ + } else { │ │ │ │ + res += ") " + logicalReverse[filter.type] + " ("; │ │ │ │ + } │ │ │ │ + res += this.write(filter.filters[i]); │ │ │ │ + } │ │ │ │ + return res + ")"; │ │ │ │ + } │ │ │ │ + case "OpenLayers.Filter.Comparison": │ │ │ │ + if (filter.type == OpenLayers.Filter.Comparison.BETWEEN) { │ │ │ │ + return filter.property + " BETWEEN " + │ │ │ │ + this.write(filter.lowerBoundary) + " AND " + │ │ │ │ + this.write(filter.upperBoundary); │ │ │ │ + } else { │ │ │ │ + return (filter.value !== null) ? filter.property + │ │ │ │ + " " + operatorReverse[filter.type] + " " + │ │ │ │ + this.write(filter.value) : filter.property + │ │ │ │ + " " + operatorReverse[filter.type]; │ │ │ │ + } │ │ │ │ + case undefined: │ │ │ │ + if (typeof filter === "string") { │ │ │ │ + return "'" + filter.replace(/'/g, "''") + "'"; │ │ │ │ + } else if (typeof filter === "number") { │ │ │ │ + return String(filter); │ │ │ │ + } │ │ │ │ + default: │ │ │ │ + throw new Error("Can't encode: " + filter.CLASS_NAME + " " + filter); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.CQL" │ │ │ │ + │ │ │ │ + }); │ │ │ │ +})(); │ │ │ │ + │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/XLS.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 │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.XLS │ │ │ │ + * Read/Write XLS (OpenLS). Create a new instance with the <OpenLayers.Format.XLS> │ │ │ │ + * constructor. Currently only implemented for Location Utility Services, more │ │ │ │ + * specifically only for Geocoding. No support for Reverse Geocoding as yet. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.XLS = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "1.1.0". │ │ │ │ + */ │ │ │ │ + defaultVersion: "1.1.0", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: stringifyOutput │ │ │ │ + * {Boolean} If true, write will return a string otherwise a DOMElement. │ │ │ │ + * Default is true. │ │ │ │ + */ │ │ │ │ + stringifyOutput: true, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.XLS │ │ │ │ + * Create a new parser for XLS. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: write │ │ │ │ + * Write out an XLS request. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * request - {Object} An object representing the LUS request. │ │ │ │ + * options - {Object} Optional configuration object. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} An XLS document string. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read an XLS doc and return an object representing the result. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String | DOMElement} Data to read. │ │ │ │ + * options - {Object} Options for the reader. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} An object representing the GeocodeResponse. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.XLS" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/OWSContext.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/Context.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.OWSContext │ │ │ │ + * Read and write OWS Context documents. OWS Context documents are a │ │ │ │ + * preliminary OGC (Open Geospatial Consortium) standard for storing the │ │ │ │ + * state of a web mapping application. In a way it is the successor to │ │ │ │ + * Web Map Context (WMC), since it is more generic and more types of layers │ │ │ │ + * can be stored. Also, nesting of layers is supported since version 0.3.1. │ │ │ │ + * For more information see: http://www.ogcnetwork.net/context │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.Context> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.OWSContext = OpenLayers.Class(OpenLayers.Format.Context, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "0.3.1". │ │ │ │ + */ │ │ │ │ + defaultVersion: "0.3.1", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.OWSContext │ │ │ │ + * Create a new parser for OWS Context documents. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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 = OpenLayers.Format.XML.VersionedOGC.prototype.getVersion.apply( │ │ │ │ + this, arguments); │ │ │ │ + // 0.3.1 is backwards compatible with 0.3.0 │ │ │ │ + if (version === "0.3.0") { │ │ │ │ + version = this.defaultVersion; │ │ │ │ + } │ │ │ │ + return version; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: toContext │ │ │ │ + * Create a context object free from layer given a map or a │ │ │ │ + * context object. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * obj - {<OpenLayers.Map> | Object} The map or context. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} A context object. │ │ │ │ + */ │ │ │ │ + toContext: function(obj) { │ │ │ │ + var context = {}; │ │ │ │ + if (obj.CLASS_NAME == "OpenLayers.Map") { │ │ │ │ + context.bounds = obj.getExtent(); │ │ │ │ + context.maxExtent = obj.maxExtent; │ │ │ │ + context.projection = obj.projection; │ │ │ │ + context.size = obj.getSize(); │ │ │ │ + context.layers = obj.layers; │ │ │ │ + } │ │ │ │ + return context; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.OWSContext" │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/SOSGetObservation.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/SOSGetFeatureOfInterest.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.SOSGetObservation │ │ │ │ + * Read and write SOS GetObersation (to get the actual values from a sensor) │ │ │ │ + * version 1.0.0 │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.Atom = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ +OpenLayers.Format.SOSGetObservation = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ /** │ │ │ │ * 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. │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ namespaces: { │ │ │ │ - atom: "http://www.w3.org/2005/Atom", │ │ │ │ - georss: "http://www.georss.org/georss" │ │ │ │ + ows: "http://www.opengis.net/ows", │ │ │ │ + gml: "http://www.opengis.net/gml", │ │ │ │ + sos: "http://www.opengis.net/sos/1.0", │ │ │ │ + ogc: "http://www.opengis.net/ogc", │ │ │ │ + om: "http://www.opengis.net/om/1.0", │ │ │ │ + sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: feedTitle │ │ │ │ - * {String} Atom feed elements require a title. Default is "untitled". │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ */ │ │ │ │ - feedTitle: "untitled", │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: defaultEntryTitle │ │ │ │ - * {String} Atom entry elements require a title. In cases where one is │ │ │ │ - * not provided in the feature attributes, this will be used. Default │ │ │ │ - * is "untitled". │ │ │ │ + * Constant: VERSION │ │ │ │ + * {String} 1.0.0 │ │ │ │ */ │ │ │ │ - defaultEntryTitle: "untitled", │ │ │ │ + VERSION: "1.0.0", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: gmlParse │ │ │ │ - * {Object} GML Format object for parsing features │ │ │ │ - * Non-API and only created if necessary │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} Schema location │ │ │ │ */ │ │ │ │ - gmlParser: null, │ │ │ │ + schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosGetObservation.xsd", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: xy │ │ │ │ - * {Boolean} Order of the GML coordinate: true:(x,y) or false:(y,x) │ │ │ │ - * For GeoRSS the default is (y,x), therefore: false │ │ │ │ + * Property: defaultPrefix │ │ │ │ */ │ │ │ │ - xy: false, │ │ │ │ + defaultPrefix: "sos", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.AtomEntry │ │ │ │ - * Create a new parser for Atom. │ │ │ │ + * Constructor: OpenLayers.Format.SOSGetObservation │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be set on │ │ │ │ * this instance. │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Return a list of features from an Atom feed or entry document. │ │ │ │ - │ │ │ │ - * Parameters: │ │ │ │ - * doc - {Element} or {String} │ │ │ │ + * Method: read │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ + * {Object} An object containing the measurements │ │ │ │ */ │ │ │ │ - read: function(doc) { │ │ │ │ - if (typeof doc == "string") { │ │ │ │ - doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]); │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ } │ │ │ │ - return this.parseFeatures(doc); │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement; │ │ │ │ + } │ │ │ │ + var info = { │ │ │ │ + measurements: [], │ │ │ │ + observations: [] │ │ │ │ + }; │ │ │ │ + this.readNode(data, info); │ │ │ │ + return info; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Serialize or more feature nodes to Atom documents. │ │ │ │ + * Method: write │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * features - {<OpenLayers.Feature.Vector>} or Array({<OpenLayers.Feature.Vector>}) │ │ │ │ + * options - {Object} Optional object. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} an Atom entry document if passed one feature node, or a feed │ │ │ │ - * document if passed an array of feature nodes. │ │ │ │ + * {String} An SOS GetObservation request XML string. │ │ │ │ */ │ │ │ │ - write: function(features) { │ │ │ │ - var doc; │ │ │ │ - if (OpenLayers.Util.isArray(features)) { │ │ │ │ - doc = this.createElementNSPlus("atom:feed"); │ │ │ │ - doc.appendChild( │ │ │ │ - this.createElementNSPlus("atom:title", { │ │ │ │ - value: this.feedTitle │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - for (var i = 0, ii = features.length; i < ii; i++) { │ │ │ │ - doc.appendChild(this.buildEntryNode(features[i])); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - doc = this.buildEntryNode(features); │ │ │ │ - } │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [doc]); │ │ │ │ + write: function(options) { │ │ │ │ + var node = this.writeNode("sos:GetObservation", options); │ │ │ │ + node.setAttribute("xmlns:om", this.namespaces.om); │ │ │ │ + node.setAttribute("xmlns:ogc", this.namespaces.ogc); │ │ │ │ + this.setAttributeNS( │ │ │ │ + node, this.namespaces.xsi, │ │ │ │ + "xsi:schemaLocation", this.schemaLocation │ │ │ │ + ); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [node]); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: buildContentNode │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * content - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} an Atom content node. │ │ │ │ - * │ │ │ │ - * TODO: types other than text. │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - buildContentNode: function(content) { │ │ │ │ - var node = this.createElementNSPlus("atom:content", { │ │ │ │ - attributes: { │ │ │ │ - type: content.type || null │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (content.src) { │ │ │ │ - node.setAttribute("src", content.src); │ │ │ │ - } else { │ │ │ │ - if (content.type == "text" || content.type == null) { │ │ │ │ - node.appendChild( │ │ │ │ - this.createTextNode(content.value) │ │ │ │ - ); │ │ │ │ - } else if (content.type == "html") { │ │ │ │ - if (typeof content.value != "string") { │ │ │ │ - throw "HTML content must be in form of an escaped string"; │ │ │ │ + readers: { │ │ │ │ + "om": { │ │ │ │ + "ObservationCollection": function(node, obj) { │ │ │ │ + obj.id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "member": function(node, observationCollection) { │ │ │ │ + this.readChildNodes(node, observationCollection); │ │ │ │ + }, │ │ │ │ + "Measurement": function(node, observationCollection) { │ │ │ │ + var measurement = {}; │ │ │ │ + observationCollection.measurements.push(measurement); │ │ │ │ + this.readChildNodes(node, measurement); │ │ │ │ + }, │ │ │ │ + "Observation": function(node, observationCollection) { │ │ │ │ + var observation = {}; │ │ │ │ + observationCollection.observations.push(observation); │ │ │ │ + this.readChildNodes(node, observation); │ │ │ │ + }, │ │ │ │ + "samplingTime": function(node, measurement) { │ │ │ │ + var samplingTime = {}; │ │ │ │ + measurement.samplingTime = samplingTime; │ │ │ │ + this.readChildNodes(node, samplingTime); │ │ │ │ + }, │ │ │ │ + "observedProperty": function(node, measurement) { │ │ │ │ + measurement.observedProperty = │ │ │ │ + this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ + this.readChildNodes(node, measurement); │ │ │ │ + }, │ │ │ │ + "procedure": function(node, measurement) { │ │ │ │ + measurement.procedure = │ │ │ │ + this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ + this.readChildNodes(node, measurement); │ │ │ │ + }, │ │ │ │ + "featureOfInterest": function(node, observation) { │ │ │ │ + var foi = { │ │ │ │ + features: [] │ │ │ │ + }; │ │ │ │ + observation.fois = []; │ │ │ │ + observation.fois.push(foi); │ │ │ │ + this.readChildNodes(node, foi); │ │ │ │ + // postprocessing to get actual features │ │ │ │ + var features = []; │ │ │ │ + for (var i = 0, len = foi.features.length; i < len; i++) { │ │ │ │ + var feature = foi.features[i]; │ │ │ │ + features.push(new OpenLayers.Feature.Vector( │ │ │ │ + feature.components[0], feature.attributes)); │ │ │ │ + } │ │ │ │ + foi.features = features; │ │ │ │ + }, │ │ │ │ + "result": function(node, measurement) { │ │ │ │ + var result = {}; │ │ │ │ + measurement.result = result; │ │ │ │ + if (this.getChildValue(node) !== '') { │ │ │ │ + result.value = this.getChildValue(node); │ │ │ │ + result.uom = node.getAttribute("uom"); │ │ │ │ + } else { │ │ │ │ + this.readChildNodes(node, result); │ │ │ │ } │ │ │ │ - node.appendChild( │ │ │ │ - this.createTextNode(content.value) │ │ │ │ - ); │ │ │ │ - } else if (content.type == "xhtml") { │ │ │ │ - node.appendChild(content.value); │ │ │ │ - } else if (content.type == "xhtml" || │ │ │ │ - content.type.match(/(\+|\/)xml$/)) { │ │ │ │ - node.appendChild(content.value); │ │ │ │ - } else { // MUST be a valid Base64 encoding │ │ │ │ - node.appendChild( │ │ │ │ - this.createTextNode(content.value) │ │ │ │ - ); │ │ │ │ } │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ + }, │ │ │ │ + "sa": OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.sa, │ │ │ │ + "gml": OpenLayers.Util.applyDefaults({ │ │ │ │ + "TimeInstant": function(node, samplingTime) { │ │ │ │ + var timeInstant = {}; │ │ │ │ + samplingTime.timeInstant = timeInstant; │ │ │ │ + this.readChildNodes(node, timeInstant); │ │ │ │ + }, │ │ │ │ + "timePosition": function(node, timeInstant) { │ │ │ │ + timeInstant.timePosition = this.getChildValue(node); │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.gml) │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: buildEntryNode │ │ │ │ - * Build an Atom entry node from a feature object. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} an Atom entry node. │ │ │ │ - * │ │ │ │ - * These entries are geared for publication using AtomPub. │ │ │ │ - * │ │ │ │ - * TODO: support extension elements │ │ │ │ + * 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. │ │ │ │ */ │ │ │ │ - buildEntryNode: function(feature) { │ │ │ │ - var attrib = feature.attributes; │ │ │ │ - var atomAttrib = attrib.atom || {}; │ │ │ │ - var entryNode = this.createElementNSPlus("atom:entry"); │ │ │ │ - │ │ │ │ - // atom:author │ │ │ │ - if (atomAttrib.authors) { │ │ │ │ - var authors = OpenLayers.Util.isArray(atomAttrib.authors) ? │ │ │ │ - atomAttrib.authors : [atomAttrib.authors]; │ │ │ │ - for (var i = 0, ii = authors.length; i < ii; i++) { │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.buildPersonConstructNode( │ │ │ │ - "author", authors[i] │ │ │ │ - ) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atom:category │ │ │ │ - if (atomAttrib.categories) { │ │ │ │ - var categories = OpenLayers.Util.isArray(atomAttrib.categories) ? │ │ │ │ - atomAttrib.categories : [atomAttrib.categories]; │ │ │ │ - var category; │ │ │ │ - for (var i = 0, ii = categories.length; i < ii; i++) { │ │ │ │ - category = categories[i]; │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:category", { │ │ │ │ - attributes: { │ │ │ │ - term: category.term, │ │ │ │ - scheme: category.scheme || null, │ │ │ │ - label: category.label || null │ │ │ │ - } │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ + writers: { │ │ │ │ + "sos": { │ │ │ │ + "GetObservation": function(options) { │ │ │ │ + var node = this.createElementNSPlus("GetObservation", { │ │ │ │ + attributes: { │ │ │ │ + version: this.VERSION, │ │ │ │ + service: 'SOS' │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.writeNode("offering", options, node); │ │ │ │ + if (options.eventTime) { │ │ │ │ + this.writeNode("eventTime", options, node); │ │ │ │ + } │ │ │ │ + for (var procedure in options.procedures) { │ │ │ │ + this.writeNode("procedure", options.procedures[procedure], node); │ │ │ │ + } │ │ │ │ + for (var observedProperty in options.observedProperties) { │ │ │ │ + this.writeNode("observedProperty", options.observedProperties[observedProperty], node); │ │ │ │ + } │ │ │ │ + if (options.foi) { │ │ │ │ + this.writeNode("featureOfInterest", options.foi, node); │ │ │ │ + } │ │ │ │ + this.writeNode("responseFormat", options, node); │ │ │ │ + if (options.resultModel) { │ │ │ │ + this.writeNode("resultModel", options, node); │ │ │ │ + } │ │ │ │ + if (options.responseMode) { │ │ │ │ + this.writeNode("responseMode", options, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "featureOfInterest": function(foi) { │ │ │ │ + var node = this.createElementNSPlus("featureOfInterest"); │ │ │ │ + this.writeNode("ObjectID", foi.objectId, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ObjectID": function(options) { │ │ │ │ + return this.createElementNSPlus("ObjectID", { │ │ │ │ + value: options │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "responseFormat": function(options) { │ │ │ │ + return this.createElementNSPlus("responseFormat", { │ │ │ │ + value: options.responseFormat │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "procedure": function(procedure) { │ │ │ │ + return this.createElementNSPlus("procedure", { │ │ │ │ + value: procedure │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "offering": function(options) { │ │ │ │ + return this.createElementNSPlus("offering", { │ │ │ │ + value: options.offering │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "observedProperty": function(observedProperty) { │ │ │ │ + return this.createElementNSPlus("observedProperty", { │ │ │ │ + value: observedProperty │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "eventTime": function(options) { │ │ │ │ + var node = this.createElementNSPlus("eventTime"); │ │ │ │ + if (options.eventTime === 'latest') { │ │ │ │ + this.writeNode("ogc:TM_Equals", options, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "resultModel": function(options) { │ │ │ │ + return this.createElementNSPlus("resultModel", { │ │ │ │ + value: options.resultModel │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "responseMode": function(options) { │ │ │ │ + return this.createElementNSPlus("responseMode", { │ │ │ │ + value: options.responseMode │ │ │ │ + }); │ │ │ │ } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atom:content │ │ │ │ - if (atomAttrib.content) { │ │ │ │ - entryNode.appendChild(this.buildContentNode(atomAttrib.content)); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atom:contributor │ │ │ │ - if (atomAttrib.contributors) { │ │ │ │ - var contributors = OpenLayers.Util.isArray(atomAttrib.contributors) ? │ │ │ │ - atomAttrib.contributors : [atomAttrib.contributors]; │ │ │ │ - for (var i = 0, ii = contributors.length; i < ii; i++) { │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.buildPersonConstructNode( │ │ │ │ - "contributor", │ │ │ │ - contributors[i] │ │ │ │ - ) │ │ │ │ - ); │ │ │ │ + }, │ │ │ │ + "ogc": { │ │ │ │ + "TM_Equals": function(options) { │ │ │ │ + var node = this.createElementNSPlus("ogc:TM_Equals"); │ │ │ │ + this.writeNode("ogc:PropertyName", { │ │ │ │ + property: "urn:ogc:data:time:iso8601" │ │ │ │ + }, node); │ │ │ │ + if (options.eventTime === 'latest') { │ │ │ │ + this.writeNode("gml:TimeInstant", { │ │ │ │ + value: 'latest' │ │ │ │ + }, node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "PropertyName": function(options) { │ │ │ │ + return this.createElementNSPlus("ogc:PropertyName", { │ │ │ │ + value: options.property │ │ │ │ + }); │ │ │ │ } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atom:id │ │ │ │ - if (feature.fid) { │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:id", { │ │ │ │ - value: feature.fid │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atom:link │ │ │ │ - if (atomAttrib.links) { │ │ │ │ - var links = OpenLayers.Util.isArray(atomAttrib.links) ? │ │ │ │ - atomAttrib.links : [atomAttrib.links]; │ │ │ │ - var link; │ │ │ │ - for (var i = 0, ii = links.length; i < ii; i++) { │ │ │ │ - link = links[i]; │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:link", { │ │ │ │ - attributes: { │ │ │ │ - href: link.href, │ │ │ │ - rel: link.rel || null, │ │ │ │ - type: link.type || null, │ │ │ │ - hreflang: link.hreflang || null, │ │ │ │ - title: link.title || null, │ │ │ │ - length: link.length || null │ │ │ │ - } │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ + }, │ │ │ │ + "gml": { │ │ │ │ + "TimeInstant": function(options) { │ │ │ │ + var node = this.createElementNSPlus("gml:TimeInstant"); │ │ │ │ + this.writeNode("gml:timePosition", options, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "timePosition": function(options) { │ │ │ │ + var node = this.createElementNSPlus("gml:timePosition", { │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ } │ │ │ │ } │ │ │ │ + }, │ │ │ │ │ │ │ │ - // atom:published │ │ │ │ - if (atomAttrib.published) { │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:published", { │ │ │ │ - value: atomAttrib.published │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atom:rights │ │ │ │ - if (atomAttrib.rights) { │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:rights", { │ │ │ │ - value: atomAttrib.rights │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atom:source not implemented │ │ │ │ - │ │ │ │ - // atom:summary │ │ │ │ - if (atomAttrib.summary || attrib.description) { │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:summary", { │ │ │ │ - value: atomAttrib.summary || attrib.description │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SOSGetObservation" │ │ │ │ │ │ │ │ - // atom:title │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:title", { │ │ │ │ - value: atomAttrib.title || attrib.title || this.defaultEntryTitle │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WMTSCapabilities.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - // atom:updated │ │ │ │ - if (atomAttrib.updated) { │ │ │ │ - entryNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:updated", { │ │ │ │ - value: atomAttrib.updated │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - // georss:where │ │ │ │ - if (feature.geometry) { │ │ │ │ - var whereNode = this.createElementNSPlus("georss:where"); │ │ │ │ - whereNode.appendChild( │ │ │ │ - this.buildGeometryNode(feature.geometry) │ │ │ │ - ); │ │ │ │ - entryNode.appendChild(whereNode); │ │ │ │ - } │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/XML/VersionedOGC.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - return entryNode; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WMTSCapabilities │ │ │ │ + * Read WMTS Capabilities. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WMTSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: initGmlParser │ │ │ │ - * Creates a GML parser. │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "1.0.0". │ │ │ │ */ │ │ │ │ - initGmlParser: function() { │ │ │ │ - this.gmlParser = new OpenLayers.Format.GML.v3({ │ │ │ │ - xy: this.xy, │ │ │ │ - featureNS: "http://example.com#feature", │ │ │ │ - internalProjection: this.internalProjection, │ │ │ │ - externalProjection: this.externalProjection │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ + defaultVersion: "1.0.0", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: buildGeometryNode │ │ │ │ - * builds a GeoRSS node with a given geometry │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * geometry - {<OpenLayers.Geometry>} │ │ │ │ + * APIProperty: yx │ │ │ │ + * {Object} Members in the yx object are used to determine if a CRS URN │ │ │ │ + * corresponds to a CRS with y,x axis order. Member names are CRS URNs │ │ │ │ + * and values are boolean. By default, the following CRS URN are │ │ │ │ + * assumed to correspond to a CRS with y,x axis order: │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A gml node. │ │ │ │ + * * urn:ogc:def:crs:EPSG::4326 │ │ │ │ */ │ │ │ │ - buildGeometryNode: function(geometry) { │ │ │ │ - if (!this.gmlParser) { │ │ │ │ - this.initGmlParser(); │ │ │ │ - } │ │ │ │ - var node = this.gmlParser.writeNode("feature:_geometry", geometry); │ │ │ │ - return node.firstChild; │ │ │ │ + yx: { │ │ │ │ + "urn:ogc:def:crs:EPSG::4326": true │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: buildPersonConstructNode │ │ │ │ + * Constructor: OpenLayers.Format.WMTSCapabilities │ │ │ │ + * Create a new parser for WMTS capabilities. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * name - {String} │ │ │ │ - * value - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} an Atom person construct node. │ │ │ │ - * │ │ │ │ - * Example: │ │ │ │ - * >>> buildPersonConstructNode("author", {name: "John Smith"}) │ │ │ │ - * {<author><name>John Smith</name></author>} │ │ │ │ - * │ │ │ │ - * TODO: how to specify extension elements? Add to the oNames array? │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ */ │ │ │ │ - buildPersonConstructNode: function(name, value) { │ │ │ │ - var oNames = ["uri", "email"]; │ │ │ │ - var personNode = this.createElementNSPlus("atom:" + name); │ │ │ │ - personNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:name", { │ │ │ │ - value: value.name │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - for (var i = 0, ii = oNames.length; i < ii; i++) { │ │ │ │ - if (value[oNames[i]]) { │ │ │ │ - personNode.appendChild( │ │ │ │ - this.createElementNSPlus("atom:" + oNames[i], { │ │ │ │ - value: value[oNames[i]] │ │ │ │ - }) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return personNode; │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: getFirstChildValue │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return information about │ │ │ │ + * the service (offering and observedProperty mostly). │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} │ │ │ │ - * nsuri - {String} Child node namespace uri ("*" for any). │ │ │ │ - * name - {String} Child node name. │ │ │ │ - * def - {String} Optional string default to return if no child found. │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {String} The value of the first child with the given tag name. Returns │ │ │ │ - * default value or empty string if none found. │ │ │ │ + * {Object} Info about the WMTS Capabilities │ │ │ │ */ │ │ │ │ - getFirstChildValue: function(node, nsuri, name, def) { │ │ │ │ - var value; │ │ │ │ - var nodes = this.getElementsByTagNameNS(node, nsuri, name); │ │ │ │ - if (nodes && nodes.length > 0) { │ │ │ │ - value = this.getChildValue(nodes[0], def); │ │ │ │ - } else { │ │ │ │ - value = def; │ │ │ │ - } │ │ │ │ - return value; │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: parseFeature │ │ │ │ - * Parse feature from an Atom entry node.. │ │ │ │ + * APIMethod: createLayer │ │ │ │ + * Create a WMTS layer given a capabilities object. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * node - {DOMElement} An Atom entry or feed node. │ │ │ │ + * capabilities - {Object} The object returned from a <read> call to this │ │ │ │ + * format. │ │ │ │ + * config - {Object} Configuration properties for the layer. Defaults for │ │ │ │ + * the layer will apply if not provided. │ │ │ │ + * │ │ │ │ + * Required config properties: │ │ │ │ + * layer - {String} The layer identifier. │ │ │ │ + * │ │ │ │ + * Optional config properties: │ │ │ │ + * matrixSet - {String} The matrix set identifier, required if there is │ │ │ │ + * more than one matrix set in the layer capabilities. │ │ │ │ + * style - {String} The name of the style │ │ │ │ + * format - {String} Image format for the layer. Default is the first │ │ │ │ + * format returned in the GetCapabilities response. │ │ │ │ + * param - {Object} The dimensions values eg: {"Year": "2012"} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {<OpenLayers.Feature.Vector>} │ │ │ │ + * {<OpenLayers.Layer.WMTS>} A properly configured WMTS layer. Throws an │ │ │ │ + * error if an incomplete config is provided. Returns undefined if no │ │ │ │ + * layer could be created with the provided config. │ │ │ │ */ │ │ │ │ - parseFeature: function(node) { │ │ │ │ - var atomAttrib = {}; │ │ │ │ - var value = null; │ │ │ │ - var nodes = null; │ │ │ │ - var attval = null; │ │ │ │ - var atomns = this.namespaces.atom; │ │ │ │ - │ │ │ │ - // atomAuthor* │ │ │ │ - this.parsePersonConstructs(node, "author", atomAttrib); │ │ │ │ - │ │ │ │ - // atomCategory* │ │ │ │ - nodes = this.getElementsByTagNameNS(node, atomns, "category"); │ │ │ │ - if (nodes.length > 0) { │ │ │ │ - atomAttrib.categories = []; │ │ │ │ - } │ │ │ │ - for (var i = 0, ii = nodes.length; i < ii; i++) { │ │ │ │ - value = {}; │ │ │ │ - value.term = nodes[i].getAttribute("term"); │ │ │ │ - attval = nodes[i].getAttribute("scheme"); │ │ │ │ - if (attval) { │ │ │ │ - value.scheme = attval; │ │ │ │ - } │ │ │ │ - attval = nodes[i].getAttribute("label"); │ │ │ │ - if (attval) { │ │ │ │ - value.label = attval; │ │ │ │ - } │ │ │ │ - atomAttrib.categories.push(value); │ │ │ │ - } │ │ │ │ + createLayer: function(capabilities, config) { │ │ │ │ + var layer; │ │ │ │ │ │ │ │ - // atomContent? │ │ │ │ - nodes = this.getElementsByTagNameNS(node, atomns, "content"); │ │ │ │ - if (nodes.length > 0) { │ │ │ │ - value = {}; │ │ │ │ - attval = nodes[0].getAttribute("type"); │ │ │ │ - if (attval) { │ │ │ │ - value.type = attval; │ │ │ │ - } │ │ │ │ - attval = nodes[0].getAttribute("src"); │ │ │ │ - if (attval) { │ │ │ │ - value.src = attval; │ │ │ │ - } else { │ │ │ │ - if (value.type == "text" || │ │ │ │ - value.type == "html" || │ │ │ │ - value.type == null) { │ │ │ │ - value.value = this.getFirstChildValue( │ │ │ │ - node, │ │ │ │ - atomns, │ │ │ │ - "content", │ │ │ │ - null │ │ │ │ - ); │ │ │ │ - } else if (value.type == "xhtml" || │ │ │ │ - value.type.match(/(\+|\/)xml$/)) { │ │ │ │ - value.value = this.getChildEl(nodes[0]); │ │ │ │ - } else { // MUST be base64 encoded │ │ │ │ - value.value = this.getFirstChildValue( │ │ │ │ - node, │ │ │ │ - atomns, │ │ │ │ - "content", │ │ │ │ - null │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - atomAttrib.content = value; │ │ │ │ - } │ │ │ │ + // confirm required properties are supplied in config │ │ │ │ + if (!('layer' in config)) { │ │ │ │ + throw new Error("Missing property 'layer' in configuration."); │ │ │ │ } │ │ │ │ │ │ │ │ - // atomContributor* │ │ │ │ - this.parsePersonConstructs(node, "contributor", atomAttrib); │ │ │ │ - │ │ │ │ - // atomId │ │ │ │ - atomAttrib.id = this.getFirstChildValue(node, atomns, "id", null); │ │ │ │ + var contents = capabilities.contents; │ │ │ │ │ │ │ │ - // atomLink* │ │ │ │ - nodes = this.getElementsByTagNameNS(node, atomns, "link"); │ │ │ │ - if (nodes.length > 0) { │ │ │ │ - atomAttrib.links = new Array(nodes.length); │ │ │ │ - } │ │ │ │ - var oAtts = ["rel", "type", "hreflang", "title", "length"]; │ │ │ │ - for (var i = 0, ii = nodes.length; i < ii; i++) { │ │ │ │ - value = {}; │ │ │ │ - value.href = nodes[i].getAttribute("href"); │ │ │ │ - for (var j = 0, jj = oAtts.length; j < jj; j++) { │ │ │ │ - attval = nodes[i].getAttribute(oAtts[j]); │ │ │ │ - if (attval) { │ │ │ │ - value[oAtts[j]] = attval; │ │ │ │ - } │ │ │ │ + // find the layer definition with the given identifier │ │ │ │ + var layers = contents.layers; │ │ │ │ + var layerDef; │ │ │ │ + for (var i = 0, ii = contents.layers.length; i < ii; ++i) { │ │ │ │ + if (contents.layers[i].identifier === config.layer) { │ │ │ │ + layerDef = contents.layers[i]; │ │ │ │ + break; │ │ │ │ } │ │ │ │ - atomAttrib.links[i] = value; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // atomPublished? │ │ │ │ - value = this.getFirstChildValue(node, atomns, "published", null); │ │ │ │ - if (value) { │ │ │ │ - atomAttrib.published = value; │ │ │ │ } │ │ │ │ - │ │ │ │ - // atomRights? │ │ │ │ - value = this.getFirstChildValue(node, atomns, "rights", null); │ │ │ │ - if (value) { │ │ │ │ - atomAttrib.rights = value; │ │ │ │ + if (!layerDef) { │ │ │ │ + throw new Error("Layer not found"); │ │ │ │ } │ │ │ │ │ │ │ │ - // atomSource? -- not implemented │ │ │ │ - │ │ │ │ - // atomSummary? │ │ │ │ - value = this.getFirstChildValue(node, atomns, "summary", null); │ │ │ │ - if (value) { │ │ │ │ - atomAttrib.summary = value; │ │ │ │ + var format = config.format; │ │ │ │ + if (!format && layerDef.formats && layerDef.formats.length) { │ │ │ │ + format = layerDef.formats[0]; │ │ │ │ } │ │ │ │ │ │ │ │ - // atomTitle │ │ │ │ - atomAttrib.title = this.getFirstChildValue( │ │ │ │ - node, atomns, "title", null │ │ │ │ - ); │ │ │ │ - │ │ │ │ - // atomUpdated │ │ │ │ - atomAttrib.updated = this.getFirstChildValue( │ │ │ │ - node, atomns, "updated", null │ │ │ │ - ); │ │ │ │ - │ │ │ │ - var featureAttrib = { │ │ │ │ - title: atomAttrib.title, │ │ │ │ - description: atomAttrib.summary, │ │ │ │ - atom: atomAttrib │ │ │ │ - }; │ │ │ │ - var geometry = this.parseLocations(node)[0]; │ │ │ │ - var feature = new OpenLayers.Feature.Vector(geometry, featureAttrib); │ │ │ │ - feature.fid = atomAttrib.id; │ │ │ │ - return feature; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: parseFeatures │ │ │ │ - * Return features from an Atom entry or feed. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} An Atom entry or feed node. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ - */ │ │ │ │ - parseFeatures: function(node) { │ │ │ │ - var features = []; │ │ │ │ - var entries = this.getElementsByTagNameNS( │ │ │ │ - node, this.namespaces.atom, "entry" │ │ │ │ - ); │ │ │ │ - if (entries.length == 0) { │ │ │ │ - entries = [node]; │ │ │ │ + // find the matrixSet definition │ │ │ │ + var matrixSet; │ │ │ │ + if (config.matrixSet) { │ │ │ │ + matrixSet = contents.tileMatrixSets[config.matrixSet]; │ │ │ │ + } else if (layerDef.tileMatrixSetLinks.length >= 1) { │ │ │ │ + matrixSet = contents.tileMatrixSets[ │ │ │ │ + layerDef.tileMatrixSetLinks[0].tileMatrixSet]; │ │ │ │ } │ │ │ │ - for (var i = 0, ii = entries.length; i < ii; i++) { │ │ │ │ - features.push(this.parseFeature(entries[i])); │ │ │ │ + if (!matrixSet) { │ │ │ │ + throw new Error("matrixSet not found"); │ │ │ │ } │ │ │ │ - return features; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: parseLocations │ │ │ │ - * Parse the locations from an Atom entry or feed. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} An Atom entry or feed node. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * Array({<OpenLayers.Geometry>}) │ │ │ │ - */ │ │ │ │ - parseLocations: function(node) { │ │ │ │ - var georssns = this.namespaces.georss; │ │ │ │ │ │ │ │ - var locations = { │ │ │ │ - components: [] │ │ │ │ - }; │ │ │ │ - var where = this.getElementsByTagNameNS(node, georssns, "where"); │ │ │ │ - if (where && where.length > 0) { │ │ │ │ - if (!this.gmlParser) { │ │ │ │ - this.initGmlParser(); │ │ │ │ - } │ │ │ │ - for (var i = 0, ii = where.length; i < ii; i++) { │ │ │ │ - this.gmlParser.readChildNodes(where[i], locations); │ │ │ │ + // get the default style for the layer │ │ │ │ + var style; │ │ │ │ + for (var i = 0, ii = layerDef.styles.length; i < ii; ++i) { │ │ │ │ + style = layerDef.styles[i]; │ │ │ │ + if (style.isDefault) { │ │ │ │ + break; │ │ │ │ } │ │ │ │ } │ │ │ │ │ │ │ │ - var components = locations.components; │ │ │ │ - var point = this.getElementsByTagNameNS(node, georssns, "point"); │ │ │ │ - if (point && point.length > 0) { │ │ │ │ - for (var i = 0, ii = point.length; i < ii; i++) { │ │ │ │ - var xy = OpenLayers.String.trim( │ │ │ │ - point[i].firstChild.nodeValue │ │ │ │ - ).split(/\s+/); │ │ │ │ - if (xy.length != 2) { │ │ │ │ - xy = OpenLayers.String.trim( │ │ │ │ - point[i].firstChild.nodeValue │ │ │ │ - ).split(/\s*,\s*/); │ │ │ │ + var requestEncoding = config.requestEncoding; │ │ │ │ + if (!requestEncoding) { │ │ │ │ + requestEncoding = "KVP"; │ │ │ │ + if (capabilities.operationsMetadata.GetTile.dcp.http) { │ │ │ │ + var http = capabilities.operationsMetadata.GetTile.dcp.http; │ │ │ │ + // Get first get method │ │ │ │ + if (http.get[0].constraints) { │ │ │ │ + var constraints = http.get[0].constraints; │ │ │ │ + var allowedValues = constraints.GetEncoding.allowedValues; │ │ │ │ + │ │ │ │ + // The OGC documentation is not clear if we should use │ │ │ │ + // REST or RESTful, ArcGis use RESTful, │ │ │ │ + // and OpenLayers use REST. │ │ │ │ + if (!allowedValues.KVP && │ │ │ │ + (allowedValues.REST || allowedValues.RESTful)) { │ │ │ │ + requestEncoding = "REST"; │ │ │ │ + } │ │ │ │ } │ │ │ │ - components.push(new OpenLayers.Geometry.Point(xy[1], xy[0])); │ │ │ │ } │ │ │ │ } │ │ │ │ │ │ │ │ - var line = this.getElementsByTagNameNS(node, georssns, "line"); │ │ │ │ - if (line && line.length > 0) { │ │ │ │ - var coords; │ │ │ │ - var p; │ │ │ │ - var points; │ │ │ │ - for (var i = 0, ii = line.length; i < ii; i++) { │ │ │ │ - coords = OpenLayers.String.trim( │ │ │ │ - line[i].firstChild.nodeValue │ │ │ │ - ).split(/\s+/); │ │ │ │ - points = []; │ │ │ │ - for (var j = 0, jj = coords.length; j < jj; j += 2) { │ │ │ │ - p = new OpenLayers.Geometry.Point(coords[j + 1], coords[j]); │ │ │ │ - points.push(p); │ │ │ │ - } │ │ │ │ - components.push( │ │ │ │ - new OpenLayers.Geometry.LineString(points) │ │ │ │ - ); │ │ │ │ + var dimensions = []; │ │ │ │ + var params = config.params || {}; │ │ │ │ + // to don't overwrite the changes in the applyDefaults │ │ │ │ + delete config.params; │ │ │ │ + for (var id = 0, ld = layerDef.dimensions.length; id < ld; id++) { │ │ │ │ + var dimension = layerDef.dimensions[id]; │ │ │ │ + dimensions.push(dimension.identifier); │ │ │ │ + if (!params.hasOwnProperty(dimension.identifier)) { │ │ │ │ + params[dimension.identifier] = dimension['default']; │ │ │ │ } │ │ │ │ } │ │ │ │ │ │ │ │ - var polygon = this.getElementsByTagNameNS(node, georssns, "polygon"); │ │ │ │ - if (polygon && polygon.length > 0) { │ │ │ │ - var coords; │ │ │ │ - var p; │ │ │ │ - var points; │ │ │ │ - for (var i = 0, ii = polygon.length; i < ii; i++) { │ │ │ │ - coords = OpenLayers.String.trim( │ │ │ │ - polygon[i].firstChild.nodeValue │ │ │ │ - ).split(/\s+/); │ │ │ │ - points = []; │ │ │ │ - for (var j = 0, jj = coords.length; j < jj; j += 2) { │ │ │ │ - p = new OpenLayers.Geometry.Point(coords[j + 1], coords[j]); │ │ │ │ - points.push(p); │ │ │ │ - } │ │ │ │ - components.push( │ │ │ │ - new OpenLayers.Geometry.Polygon( │ │ │ │ - [new OpenLayers.Geometry.LinearRing(points)] │ │ │ │ - ) │ │ │ │ - ); │ │ │ │ + var projection = config.projection || matrixSet.supportedCRS.replace( │ │ │ │ + /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, "$1:$3"); │ │ │ │ + var units = config.units || │ │ │ │ + (projection === "EPSG:4326" ? "degrees" : "m"); │ │ │ │ + │ │ │ │ + var resolutions = []; │ │ │ │ + for (var mid in matrixSet.matrixIds) { │ │ │ │ + if (matrixSet.matrixIds.hasOwnProperty(mid)) { │ │ │ │ + resolutions.push( │ │ │ │ + matrixSet.matrixIds[mid].scaleDenominator * 0.28E-3 / │ │ │ │ + OpenLayers.METERS_PER_INCH / │ │ │ │ + OpenLayers.INCHES_PER_UNIT[units]); │ │ │ │ } │ │ │ │ } │ │ │ │ │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - for (var i = 0, ii = components.length; i < ii; i++) { │ │ │ │ - if (components[i]) { │ │ │ │ - components[i].transform( │ │ │ │ - this.externalProjection, │ │ │ │ - this.internalProjection │ │ │ │ - ); │ │ │ │ + var url; │ │ │ │ + if (requestEncoding === "REST" && layerDef.resourceUrls) { │ │ │ │ + url = []; │ │ │ │ + var resourceUrls = layerDef.resourceUrls, │ │ │ │ + resourceUrl; │ │ │ │ + for (var t = 0, tt = layerDef.resourceUrls.length; t < tt; ++t) { │ │ │ │ + resourceUrl = layerDef.resourceUrls[t]; │ │ │ │ + if (resourceUrl.format === format && resourceUrl.resourceType === "tile") { │ │ │ │ + url.push(resourceUrl.template); │ │ │ │ } │ │ │ │ } │ │ │ │ - } │ │ │ │ - │ │ │ │ - return components; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: parsePersonConstruct │ │ │ │ - * Parse Atom person constructs from an Atom entry node. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} An Atom entry or feed node. │ │ │ │ - * name - {String} Construcy name ("author" or "contributor") │ │ │ │ - * data = {Object} Object in which to put parsed persons. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * An {Object}. │ │ │ │ - */ │ │ │ │ - parsePersonConstructs: function(node, name, data) { │ │ │ │ - var persons = []; │ │ │ │ - var atomns = this.namespaces.atom; │ │ │ │ - var nodes = this.getElementsByTagNameNS(node, atomns, name); │ │ │ │ - var oAtts = ["uri", "email"]; │ │ │ │ - for (var i = 0, ii = nodes.length; i < ii; i++) { │ │ │ │ - var value = {}; │ │ │ │ - value.name = this.getFirstChildValue( │ │ │ │ - nodes[i], │ │ │ │ - atomns, │ │ │ │ - "name", │ │ │ │ - null │ │ │ │ - ); │ │ │ │ - for (var j = 0, jj = oAtts.length; j < jj; j++) { │ │ │ │ - var attval = this.getFirstChildValue( │ │ │ │ - nodes[i], │ │ │ │ - atomns, │ │ │ │ - oAtts[j], │ │ │ │ - null); │ │ │ │ - if (attval) { │ │ │ │ - value[oAtts[j]] = attval; │ │ │ │ + } else { │ │ │ │ + var httpGet = capabilities.operationsMetadata.GetTile.dcp.http.get; │ │ │ │ + url = []; │ │ │ │ + var constraint; │ │ │ │ + for (var i = 0, ii = httpGet.length; i < ii; i++) { │ │ │ │ + constraint = httpGet[i].constraints; │ │ │ │ + if (!constraint || (constraint && constraint.GetEncoding.allowedValues[requestEncoding])) { │ │ │ │ + url.push(httpGet[i].url); │ │ │ │ } │ │ │ │ } │ │ │ │ - persons.push(value); │ │ │ │ - } │ │ │ │ - if (persons.length > 0) { │ │ │ │ - data[name + "s"] = persons; │ │ │ │ } │ │ │ │ + │ │ │ │ + return new OpenLayers.Layer.WMTS( │ │ │ │ + OpenLayers.Util.applyDefaults(config, { │ │ │ │ + url: url, │ │ │ │ + requestEncoding: requestEncoding, │ │ │ │ + name: layerDef.title, │ │ │ │ + style: style.identifier, │ │ │ │ + format: format, │ │ │ │ + matrixIds: matrixSet.matrixIds, │ │ │ │ + matrixSet: matrixSet.identifier, │ │ │ │ + projection: projection, │ │ │ │ + units: units, │ │ │ │ + resolutions: config.isBaseLayer === false ? undefined : resolutions, │ │ │ │ + serverResolutions: resolutions, │ │ │ │ + tileFullExtent: matrixSet.bounds, │ │ │ │ + dimensions: dimensions, │ │ │ │ + params: params │ │ │ │ + }) │ │ │ │ + ); │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.Atom" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMTSCapabilities" │ │ │ │ + │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Format/GeoRSS.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ @@ -80711,14 +86548,65 @@ │ │ │ │ } │ │ │ │ return this.createTextNode(path); │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.GeoRSS" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ + OpenLayers/Format/WFSCapabilities.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 │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WFSCapabilities │ │ │ │ + * Read WFS Capabilities. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WFSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: defaultVersion │ │ │ │ + * {String} Version number to assume if none found. Default is "1.1.0". │ │ │ │ + */ │ │ │ │ + defaultVersion: "1.1.0", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WFSCapabilities │ │ │ │ + * Create a new parser for WFS capabilities. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return a list of layers. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array} List of named layers. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities" │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ OpenLayers/Format/CSWGetDomain.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. */ │ │ │ │ @@ -80749,487 +86637,14 @@ │ │ │ │ * Constant: DEFAULTS │ │ │ │ * {Object} Default properties for the CSWGetDomain format. │ │ │ │ */ │ │ │ │ OpenLayers.Format.CSWGetDomain.DEFAULTS = { │ │ │ │ "version": "2.0.2" │ │ │ │ }; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/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/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/Projection.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.OSM │ │ │ │ - * OSM parser. Create a new instance with the │ │ │ │ - * <OpenLayers.Format.OSM> constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.OSM = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: checkTags │ │ │ │ - * {Boolean} Should tags be checked to determine whether something │ │ │ │ - * should be treated as a seperate node. Will slow down parsing. │ │ │ │ - * Default is false. │ │ │ │ - */ │ │ │ │ - checkTags: false, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: interestingTagsExclude │ │ │ │ - * {Array} List of tags to exclude from 'interesting' checks on nodes. │ │ │ │ - * Must be set when creating the format. Will only be used if checkTags │ │ │ │ - * is set. │ │ │ │ - */ │ │ │ │ - interestingTagsExclude: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: areaTags │ │ │ │ - * {Array} List of tags indicating that something is an area. │ │ │ │ - * Must be set when creating the format. Will only be used if │ │ │ │ - * checkTags is true. │ │ │ │ - */ │ │ │ │ - areaTags: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.OSM │ │ │ │ - * Create a new parser for OSM. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - var layer_defaults = { │ │ │ │ - 'interestingTagsExclude': ['source', 'source_ref', │ │ │ │ - 'source:ref', 'history', 'attribution', 'created_by' │ │ │ │ - ], │ │ │ │ - 'areaTags': ['area', 'building', 'leisure', 'tourism', 'ruins', │ │ │ │ - 'historic', 'landuse', 'military', 'natural', 'sport' │ │ │ │ - ] │ │ │ │ - }; │ │ │ │ - │ │ │ │ - layer_defaults = OpenLayers.Util.extend(layer_defaults, options); │ │ │ │ - │ │ │ │ - var interesting = {}; │ │ │ │ - for (var i = 0; i < layer_defaults.interestingTagsExclude.length; i++) { │ │ │ │ - interesting[layer_defaults.interestingTagsExclude[i]] = true; │ │ │ │ - } │ │ │ │ - layer_defaults.interestingTagsExclude = interesting; │ │ │ │ - │ │ │ │ - var area = {}; │ │ │ │ - for (var i = 0; i < layer_defaults.areaTags.length; i++) { │ │ │ │ - area[layer_defaults.areaTags[i]] = true; │ │ │ │ - } │ │ │ │ - layer_defaults.areaTags = area; │ │ │ │ - │ │ │ │ - // OSM coordinates are always in longlat WGS84 │ │ │ │ - this.externalProjection = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ - │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [layer_defaults]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Return a list of features from a OSM doc │ │ │ │ - │ │ │ │ - * Parameters: │ │ │ │ - * doc - {Element} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * Array({<OpenLayers.Feature.Vector>}) │ │ │ │ - */ │ │ │ │ - read: function(doc) { │ │ │ │ - if (typeof doc == "string") { │ │ │ │ - doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var nodes = this.getNodes(doc); │ │ │ │ - var ways = this.getWays(doc); │ │ │ │ - │ │ │ │ - // Geoms will contain at least ways.length entries. │ │ │ │ - var feat_list = new Array(ways.length); │ │ │ │ - │ │ │ │ - for (var i = 0; i < ways.length; i++) { │ │ │ │ - // We know the minimal of this one ahead of time. (Could be -1 │ │ │ │ - // due to areas/polygons) │ │ │ │ - var point_list = new Array(ways[i].nodes.length); │ │ │ │ - │ │ │ │ - var poly = this.isWayArea(ways[i]) ? 1 : 0; │ │ │ │ - for (var j = 0; j < ways[i].nodes.length; j++) { │ │ │ │ - var node = nodes[ways[i].nodes[j]]; │ │ │ │ - │ │ │ │ - var point = new OpenLayers.Geometry.Point(node.lon, node.lat); │ │ │ │ - │ │ │ │ - // Since OSM is topological, we stash the node ID internally. │ │ │ │ - point.osm_id = parseInt(ways[i].nodes[j]); │ │ │ │ - point_list[j] = point; │ │ │ │ - │ │ │ │ - // We don't display nodes if they're used inside other │ │ │ │ - // elements. │ │ │ │ - node.used = true; │ │ │ │ - } │ │ │ │ - var geometry = null; │ │ │ │ - if (poly) { │ │ │ │ - geometry = new OpenLayers.Geometry.Polygon( │ │ │ │ - new OpenLayers.Geometry.LinearRing(point_list)); │ │ │ │ - } else { │ │ │ │ - geometry = new OpenLayers.Geometry.LineString(point_list); │ │ │ │ - } │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - geometry.transform(this.externalProjection, │ │ │ │ - this.internalProjection); │ │ │ │ - } │ │ │ │ - var feat = new OpenLayers.Feature.Vector(geometry, │ │ │ │ - ways[i].tags); │ │ │ │ - feat.osm_id = parseInt(ways[i].id); │ │ │ │ - feat.fid = "way." + feat.osm_id; │ │ │ │ - feat_list[i] = feat; │ │ │ │ - } │ │ │ │ - for (var node_id in nodes) { │ │ │ │ - var node = nodes[node_id]; │ │ │ │ - if (!node.used || this.checkTags) { │ │ │ │ - var tags = null; │ │ │ │ - │ │ │ │ - if (this.checkTags) { │ │ │ │ - var result = this.getTags(node.node, true); │ │ │ │ - if (node.used && !result[1]) { │ │ │ │ - continue; │ │ │ │ - } │ │ │ │ - tags = result[0]; │ │ │ │ - } else { │ │ │ │ - tags = this.getTags(node.node); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var feat = new OpenLayers.Feature.Vector( │ │ │ │ - new OpenLayers.Geometry.Point(node['lon'], node['lat']), │ │ │ │ - tags); │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - feat.geometry.transform(this.externalProjection, │ │ │ │ - this.internalProjection); │ │ │ │ - } │ │ │ │ - feat.osm_id = parseInt(node_id); │ │ │ │ - feat.fid = "node." + feat.osm_id; │ │ │ │ - feat_list.push(feat); │ │ │ │ - } │ │ │ │ - // Memory cleanup │ │ │ │ - node.node = null; │ │ │ │ - } │ │ │ │ - return feat_list; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getNodes │ │ │ │ - * Return the node items from a doc. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * doc - {DOMElement} node to parse tags from │ │ │ │ - */ │ │ │ │ - getNodes: function(doc) { │ │ │ │ - var node_list = doc.getElementsByTagName("node"); │ │ │ │ - var nodes = {}; │ │ │ │ - for (var i = 0; i < node_list.length; i++) { │ │ │ │ - var node = node_list[i]; │ │ │ │ - var id = node.getAttribute("id"); │ │ │ │ - nodes[id] = { │ │ │ │ - 'lat': node.getAttribute("lat"), │ │ │ │ - 'lon': node.getAttribute("lon"), │ │ │ │ - 'node': node │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - return nodes; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getWays │ │ │ │ - * Return the way items from a doc. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * doc - {DOMElement} node to parse tags from │ │ │ │ - */ │ │ │ │ - getWays: function(doc) { │ │ │ │ - var way_list = doc.getElementsByTagName("way"); │ │ │ │ - var return_ways = []; │ │ │ │ - for (var i = 0; i < way_list.length; i++) { │ │ │ │ - var way = way_list[i]; │ │ │ │ - var way_object = { │ │ │ │ - id: way.getAttribute("id") │ │ │ │ - }; │ │ │ │ - │ │ │ │ - way_object.tags = this.getTags(way); │ │ │ │ - │ │ │ │ - var node_list = way.getElementsByTagName("nd"); │ │ │ │ - │ │ │ │ - way_object.nodes = new Array(node_list.length); │ │ │ │ - │ │ │ │ - for (var j = 0; j < node_list.length; j++) { │ │ │ │ - way_object.nodes[j] = node_list[j].getAttribute("ref"); │ │ │ │ - } │ │ │ │ - return_ways.push(way_object); │ │ │ │ - } │ │ │ │ - return return_ways; │ │ │ │ - │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getTags │ │ │ │ - * Return the tags list attached to a specific DOM element. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * dom_node - {DOMElement} node to parse tags from │ │ │ │ - * interesting_tags - {Boolean} whether the return from this function should │ │ │ │ - * return a boolean indicating that it has 'interesting tags' -- │ │ │ │ - * tags like attribution and source are ignored. (To change the list │ │ │ │ - * of tags, see interestingTagsExclude) │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * tags - {Object} hash of tags │ │ │ │ - * interesting - {Boolean} if interesting_tags is passed, returns │ │ │ │ - * whether there are any interesting tags on this element. │ │ │ │ - */ │ │ │ │ - getTags: function(dom_node, interesting_tags) { │ │ │ │ - var tag_list = dom_node.getElementsByTagName("tag"); │ │ │ │ - var tags = {}; │ │ │ │ - var interesting = false; │ │ │ │ - for (var j = 0; j < tag_list.length; j++) { │ │ │ │ - var key = tag_list[j].getAttribute("k"); │ │ │ │ - tags[key] = tag_list[j].getAttribute("v"); │ │ │ │ - if (interesting_tags) { │ │ │ │ - if (!this.interestingTagsExclude[key]) { │ │ │ │ - interesting = true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return interesting_tags ? [tags, interesting] : tags; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: isWayArea │ │ │ │ - * Given a way object from getWays, check whether the tags and geometry │ │ │ │ - * indicate something is an area. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - isWayArea: function(way) { │ │ │ │ - var poly_shaped = false; │ │ │ │ - var poly_tags = false; │ │ │ │ - │ │ │ │ - if (way.nodes[0] == way.nodes[way.nodes.length - 1]) { │ │ │ │ - poly_shaped = true; │ │ │ │ - } │ │ │ │ - if (this.checkTags) { │ │ │ │ - for (var key in way.tags) { │ │ │ │ - if (this.areaTags[key]) { │ │ │ │ - poly_tags = true; │ │ │ │ - break; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return poly_shaped && (this.checkTags ? poly_tags : true); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Takes a list of features, returns a serialized OSM format file for use │ │ │ │ - * in tools like JOSM. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ - */ │ │ │ │ - write: function(features) { │ │ │ │ - if (!(OpenLayers.Util.isArray(features))) { │ │ │ │ - features = [features]; │ │ │ │ - } │ │ │ │ - │ │ │ │ - this.osm_id = 1; │ │ │ │ - this.created_nodes = {}; │ │ │ │ - var root_node = this.createElementNS(null, "osm"); │ │ │ │ - root_node.setAttribute("version", "0.5"); │ │ │ │ - root_node.setAttribute("generator", "OpenLayers " + OpenLayers.VERSION_NUMBER); │ │ │ │ - │ │ │ │ - // Loop backwards, because the deserializer puts nodes last, and │ │ │ │ - // we want them first if possible │ │ │ │ - for (var i = features.length - 1; i >= 0; i--) { │ │ │ │ - var nodes = this.createFeatureNodes(features[i]); │ │ │ │ - for (var j = 0; j < nodes.length; j++) { │ │ │ │ - root_node.appendChild(nodes[j]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [root_node]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: createFeatureNodes │ │ │ │ - * Takes a feature, returns a list of nodes from size 0->n. │ │ │ │ - * Will include all pieces of the serialization that are required which │ │ │ │ - * have not already been created. Calls out to createXML based on geometry │ │ │ │ - * type. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - createFeatureNodes: function(feature) { │ │ │ │ - var nodes = []; │ │ │ │ - var className = feature.geometry.CLASS_NAME; │ │ │ │ - var type = className.substring(className.lastIndexOf(".") + 1); │ │ │ │ - type = type.toLowerCase(); │ │ │ │ - var builder = this.createXML[type]; │ │ │ │ - if (builder) { │ │ │ │ - nodes = builder.apply(this, [feature]); │ │ │ │ - } │ │ │ │ - return nodes; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: createXML │ │ │ │ - * Takes a feature, returns a list of nodes from size 0->n. │ │ │ │ - * Will include all pieces of the serialization that are required which │ │ │ │ - * have not already been created. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - */ │ │ │ │ - createXML: { │ │ │ │ - 'point': function(point) { │ │ │ │ - var id = null; │ │ │ │ - var geometry = point.geometry ? point.geometry : point; │ │ │ │ - │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - geometry = geometry.clone(); │ │ │ │ - geometry.transform(this.internalProjection, │ │ │ │ - this.externalProjection); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var already_exists = false; // We don't return anything if the node │ │ │ │ - // has already been created │ │ │ │ - if (point.osm_id) { │ │ │ │ - id = point.osm_id; │ │ │ │ - if (this.created_nodes[id]) { │ │ │ │ - already_exists = true; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - id = -this.osm_id; │ │ │ │ - this.osm_id++; │ │ │ │ - } │ │ │ │ - if (already_exists) { │ │ │ │ - node = this.created_nodes[id]; │ │ │ │ - } else { │ │ │ │ - var node = this.createElementNS(null, "node"); │ │ │ │ - } │ │ │ │ - this.created_nodes[id] = node; │ │ │ │ - node.setAttribute("id", id); │ │ │ │ - node.setAttribute("lon", geometry.x); │ │ │ │ - node.setAttribute("lat", geometry.y); │ │ │ │ - if (point.attributes) { │ │ │ │ - this.serializeTags(point, node); │ │ │ │ - } │ │ │ │ - this.setState(point, node); │ │ │ │ - return already_exists ? [] : [node]; │ │ │ │ - }, │ │ │ │ - linestring: function(feature) { │ │ │ │ - var id; │ │ │ │ - var nodes = []; │ │ │ │ - var geometry = feature.geometry; │ │ │ │ - if (feature.osm_id) { │ │ │ │ - id = feature.osm_id; │ │ │ │ - } else { │ │ │ │ - id = -this.osm_id; │ │ │ │ - this.osm_id++; │ │ │ │ - } │ │ │ │ - var way = this.createElementNS(null, "way"); │ │ │ │ - way.setAttribute("id", id); │ │ │ │ - for (var i = 0; i < geometry.components.length; i++) { │ │ │ │ - var node = this.createXML['point'].apply(this, [geometry.components[i]]); │ │ │ │ - if (node.length) { │ │ │ │ - node = node[0]; │ │ │ │ - var node_ref = node.getAttribute("id"); │ │ │ │ - nodes.push(node); │ │ │ │ - } else { │ │ │ │ - node_ref = geometry.components[i].osm_id; │ │ │ │ - node = this.created_nodes[node_ref]; │ │ │ │ - } │ │ │ │ - this.setState(feature, node); │ │ │ │ - var nd_dom = this.createElementNS(null, "nd"); │ │ │ │ - nd_dom.setAttribute("ref", node_ref); │ │ │ │ - way.appendChild(nd_dom); │ │ │ │ - } │ │ │ │ - this.serializeTags(feature, way); │ │ │ │ - nodes.push(way); │ │ │ │ - │ │ │ │ - return nodes; │ │ │ │ - }, │ │ │ │ - polygon: function(feature) { │ │ │ │ - var attrs = OpenLayers.Util.extend({ │ │ │ │ - 'area': 'yes' │ │ │ │ - }, feature.attributes); │ │ │ │ - var feat = new OpenLayers.Feature.Vector(feature.geometry.components[0], attrs); │ │ │ │ - feat.osm_id = feature.osm_id; │ │ │ │ - return this.createXML['linestring'].apply(this, [feat]); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: serializeTags │ │ │ │ - * Given a feature, serialize the attributes onto the given node. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - * node - {DOMNode} │ │ │ │ - */ │ │ │ │ - serializeTags: function(feature, node) { │ │ │ │ - for (var key in feature.attributes) { │ │ │ │ - var tag = this.createElementNS(null, "tag"); │ │ │ │ - tag.setAttribute("k", key); │ │ │ │ - tag.setAttribute("v", feature.attributes[key]); │ │ │ │ - node.appendChild(tag); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setState │ │ │ │ - * OpenStreetMap has a convention that 'state' is stored for modification or deletion. │ │ │ │ - * This allows the file to be uploaded via JOSM or the bulk uploader tool. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ - * node - {DOMNode} │ │ │ │ - */ │ │ │ │ - setState: function(feature, node) { │ │ │ │ - if (feature.state) { │ │ │ │ - var state = null; │ │ │ │ - switch (feature.state) { │ │ │ │ - case OpenLayers.State.UPDATE: │ │ │ │ - state = "modify"; │ │ │ │ - case OpenLayers.State.DELETE: │ │ │ │ - state = "delete"; │ │ │ │ - } │ │ │ │ - if (state) { │ │ │ │ - node.setAttribute("action", state); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.OSM" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ OpenLayers/Format/GPX.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. */ │ │ │ │ @@ -81612,204 +87027,241 @@ │ │ │ │ node.appendChild(desc); │ │ │ │ // TBD - deal with remaining (non name/description) attributes. │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.GPX" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WCSCapabilities.js │ │ │ │ + OpenLayers/Format/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/Format/XML/VersionedOGC.js │ │ │ │ + * @requires OpenLayers/Format/GML.js │ │ │ │ + * @requires OpenLayers/Console.js │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WCSCapabilities │ │ │ │ - * Read WCS Capabilities. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.WFS │ │ │ │ + * Read/Write WFS. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ + * - <OpenLayers.Format.GML> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WCSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ +OpenLayers.Format.WFS = OpenLayers.Class(OpenLayers.Format.GML, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: layer │ │ │ │ + * {<OpenLayers.Layer>} │ │ │ │ + */ │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "1.1.0". │ │ │ │ + * APIProperty: wfsns │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ - defaultVersion: "1.1.0", │ │ │ │ + wfsns: "http://www.opengis.net/wfs", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WCSCapabilities │ │ │ │ - * Create a new parser for WCS capabilities. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * Property: ogcns │ │ │ │ + * {String} │ │ │ │ */ │ │ │ │ + ogcns: "http://www.opengis.net/ogc", │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return a list of coverages. │ │ │ │ + * Constructor: OpenLayers.Format.WFS │ │ │ │ + * Create a WFS-T formatter. This requires a layer: that layer should │ │ │ │ + * have two properties: geometry_column and typename. The parser │ │ │ │ + * for this format is subclassed entirely from GML: There is a writer │ │ │ │ + * only, which uses most of the code from the GML layer, and wraps │ │ │ │ + * it in transactional elements. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} List of named coverages. │ │ │ │ + * options - {Object} │ │ │ │ + * layer - {<OpenLayers.Layer>} │ │ │ │ */ │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/OWSContext.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/Context.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.OWSContext │ │ │ │ - * Read and write OWS Context documents. OWS Context documents are a │ │ │ │ - * preliminary OGC (Open Geospatial Consortium) standard for storing the │ │ │ │ - * state of a web mapping application. In a way it is the successor to │ │ │ │ - * Web Map Context (WMC), since it is more generic and more types of layers │ │ │ │ - * can be stored. Also, nesting of layers is supported since version 0.3.1. │ │ │ │ - * For more information see: http://www.ogcnetwork.net/context │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.Context> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.OWSContext = OpenLayers.Class(OpenLayers.Format.Context, { │ │ │ │ + initialize: function(options, layer) { │ │ │ │ + OpenLayers.Format.GML.prototype.initialize.apply(this, [options]); │ │ │ │ + this.layer = layer; │ │ │ │ + if (this.layer.featureNS) { │ │ │ │ + this.featureNS = this.layer.featureNS; │ │ │ │ + } │ │ │ │ + if (this.layer.options.geometry_column) { │ │ │ │ + this.geometryName = this.layer.options.geometry_column; │ │ │ │ + } │ │ │ │ + if (this.layer.options.typename) { │ │ │ │ + this.featureName = this.layer.options.typename; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "0.3.1". │ │ │ │ + * Method: write │ │ │ │ + * Takes a feature list, and generates a WFS-T Transaction │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * features - {Array(<OpenLayers.Feature.Vector>)} │ │ │ │ */ │ │ │ │ - defaultVersion: "0.3.1", │ │ │ │ + write: function(features) { │ │ │ │ + │ │ │ │ + var transaction = this.createElementNS(this.wfsns, 'wfs:Transaction'); │ │ │ │ + transaction.setAttribute("version", "1.0.0"); │ │ │ │ + transaction.setAttribute("service", "WFS"); │ │ │ │ + for (var i = 0; i < features.length; i++) { │ │ │ │ + switch (features[i].state) { │ │ │ │ + case OpenLayers.State.INSERT: │ │ │ │ + transaction.appendChild(this.insert(features[i])); │ │ │ │ + break; │ │ │ │ + case OpenLayers.State.UPDATE: │ │ │ │ + transaction.appendChild(this.update(features[i])); │ │ │ │ + break; │ │ │ │ + case OpenLayers.State.DELETE: │ │ │ │ + transaction.appendChild(this.remove(features[i])); │ │ │ │ + break; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [transaction]); │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.OWSContext │ │ │ │ - * Create a new parser for OWS Context documents. │ │ │ │ + * Method: createFeatureXML │ │ │ │ * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ */ │ │ │ │ + createFeatureXML: function(feature) { │ │ │ │ + var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ + var geomContainer = this.createElementNS(this.featureNS, "feature:" + this.geometryName); │ │ │ │ + geomContainer.appendChild(geometryNode); │ │ │ │ + var featureContainer = this.createElementNS(this.featureNS, "feature:" + this.featureName); │ │ │ │ + featureContainer.appendChild(geomContainer); │ │ │ │ + for (var attr in feature.attributes) { │ │ │ │ + var attrText = this.createTextNode(feature.attributes[attr]); │ │ │ │ + var nodename = attr; │ │ │ │ + if (attr.search(":") != -1) { │ │ │ │ + nodename = attr.split(":")[1]; │ │ │ │ + } │ │ │ │ + var attrContainer = this.createElementNS(this.featureNS, "feature:" + nodename); │ │ │ │ + attrContainer.appendChild(attrText); │ │ │ │ + featureContainer.appendChild(attrContainer); │ │ │ │ + } │ │ │ │ + return featureContainer; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Method: insert │ │ │ │ + * Takes a feature, and generates a WFS-T Transaction "Insert" │ │ │ │ * │ │ │ │ - * Returns: │ │ │ │ - * {String} The version to use. │ │ │ │ + * Parameters: │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ */ │ │ │ │ - getVersion: function(root, options) { │ │ │ │ - var version = OpenLayers.Format.XML.VersionedOGC.prototype.getVersion.apply( │ │ │ │ - this, arguments); │ │ │ │ - // 0.3.1 is backwards compatible with 0.3.0 │ │ │ │ - if (version === "0.3.0") { │ │ │ │ - version = this.defaultVersion; │ │ │ │ - } │ │ │ │ - return version; │ │ │ │ + insert: function(feature) { │ │ │ │ + var insertNode = this.createElementNS(this.wfsns, 'wfs:Insert'); │ │ │ │ + insertNode.appendChild(this.createFeatureXML(feature)); │ │ │ │ + return insertNode; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: toContext │ │ │ │ - * Create a context object free from layer given a map or a │ │ │ │ - * context object. │ │ │ │ + * Method: update │ │ │ │ + * Takes a feature, and generates a WFS-T Transaction "Update" │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * obj - {<OpenLayers.Map> | Object} The map or context. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} A context object. │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ */ │ │ │ │ - toContext: function(obj) { │ │ │ │ - var context = {}; │ │ │ │ - if (obj.CLASS_NAME == "OpenLayers.Map") { │ │ │ │ - context.bounds = obj.getExtent(); │ │ │ │ - context.maxExtent = obj.maxExtent; │ │ │ │ - context.projection = obj.projection; │ │ │ │ - context.size = obj.getSize(); │ │ │ │ - context.layers = obj.layers; │ │ │ │ + update: function(feature) { │ │ │ │ + if (!feature.fid) { │ │ │ │ + OpenLayers.Console.userError(OpenLayers.i18n("noFID")); │ │ │ │ } │ │ │ │ - return context; │ │ │ │ - }, │ │ │ │ + var updateNode = this.createElementNS(this.wfsns, 'wfs:Update'); │ │ │ │ + updateNode.setAttribute("typeName", this.featurePrefix + ':' + this.featureName); │ │ │ │ + updateNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.OWSContext" │ │ │ │ + var propertyNode = this.createElementNS(this.wfsns, 'wfs:Property'); │ │ │ │ + var nameNode = this.createElementNS(this.wfsns, 'wfs:Name'); │ │ │ │ │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WFSCapabilities.js │ │ │ │ - ====================================================================== */ │ │ │ │ + var txtNode = this.createTextNode(this.geometryName); │ │ │ │ + nameNode.appendChild(txtNode); │ │ │ │ + propertyNode.appendChild(nameNode); │ │ │ │ │ │ │ │ -/* 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 valueNode = this.createElementNS(this.wfsns, 'wfs:Value'); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Format/XML/VersionedOGC.js │ │ │ │ - */ │ │ │ │ + var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WFSCapabilities │ │ │ │ - * Read WFS Capabilities. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WFSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + if (feature.layer) { │ │ │ │ + geometryNode.setAttribute( │ │ │ │ + "srsName", feature.layer.projection.getCode() │ │ │ │ + ); │ │ │ │ + } │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "1.1.0". │ │ │ │ - */ │ │ │ │ - defaultVersion: "1.1.0", │ │ │ │ + valueNode.appendChild(geometryNode); │ │ │ │ + │ │ │ │ + propertyNode.appendChild(valueNode); │ │ │ │ + updateNode.appendChild(propertyNode); │ │ │ │ + │ │ │ │ + // add in attributes │ │ │ │ + for (var propName in feature.attributes) { │ │ │ │ + propertyNode = this.createElementNS(this.wfsns, 'wfs:Property'); │ │ │ │ + nameNode = this.createElementNS(this.wfsns, 'wfs:Name'); │ │ │ │ + nameNode.appendChild(this.createTextNode(propName)); │ │ │ │ + propertyNode.appendChild(nameNode); │ │ │ │ + valueNode = this.createElementNS(this.wfsns, 'wfs:Value'); │ │ │ │ + valueNode.appendChild(this.createTextNode(feature.attributes[propName])); │ │ │ │ + propertyNode.appendChild(valueNode); │ │ │ │ + updateNode.appendChild(propertyNode); │ │ │ │ + } │ │ │ │ + │ │ │ │ + │ │ │ │ + var filterNode = this.createElementNS(this.ogcns, 'ogc:Filter'); │ │ │ │ + var filterIdNode = this.createElementNS(this.ogcns, 'ogc:FeatureId'); │ │ │ │ + filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ + filterNode.appendChild(filterIdNode); │ │ │ │ + updateNode.appendChild(filterNode); │ │ │ │ + │ │ │ │ + return updateNode; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WFSCapabilities │ │ │ │ - * Create a new parser for WFS capabilities. │ │ │ │ + * Method: remove │ │ │ │ + * Takes a feature, and generates a WFS-T Transaction "Delete" │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * feature - {<OpenLayers.Feature.Vector>} │ │ │ │ */ │ │ │ │ + remove: function(feature) { │ │ │ │ + if (!feature.fid) { │ │ │ │ + OpenLayers.Console.userError(OpenLayers.i18n("noFID")); │ │ │ │ + return false; │ │ │ │ + } │ │ │ │ + var deleteNode = this.createElementNS(this.wfsns, 'wfs:Delete'); │ │ │ │ + deleteNode.setAttribute("typeName", this.featurePrefix + ':' + this.featureName); │ │ │ │ + deleteNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ + │ │ │ │ + var filterNode = this.createElementNS(this.ogcns, 'ogc:Filter'); │ │ │ │ + var filterIdNode = this.createElementNS(this.ogcns, 'ogc:FeatureId'); │ │ │ │ + filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ + filterNode.appendChild(filterIdNode); │ │ │ │ + deleteNode.appendChild(filterNode); │ │ │ │ + │ │ │ │ + return deleteNode; │ │ │ │ + }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return a list of layers. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} List of named layers. │ │ │ │ + * APIMethod: destroy │ │ │ │ + * Remove ciruclar ref to layer │ │ │ │ */ │ │ │ │ + destroy: function() { │ │ │ │ + this.layer = null; │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities" │ │ │ │ - │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFS" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ 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. │ │ │ │ @@ -83325,2708 +88777,409 @@ │ │ │ │ return extendedData; │ │ │ │ } │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.KML" │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSDescribeLayer.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 │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSDescribeLayer │ │ │ │ - * Read SLD WMS DescribeLayer response │ │ │ │ - * DescribeLayer is meant to couple WMS to WFS and WCS │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSDescribeLayer = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "1.1.1". │ │ │ │ - */ │ │ │ │ - defaultVersion: "1.1.1", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WMSDescribeLayer │ │ │ │ - * Create a new parser for WMS DescribeLayer responses. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read DescribeLayer data from a string, and return the response. │ │ │ │ - * The OGC currently defines 2 formats which are allowed for output, │ │ │ │ - * so we need to parse these 2 types │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} Array of {<LayerDescription>} objects which have: │ │ │ │ - * - {String} owsType: WFS/WCS │ │ │ │ - * - {String} owsURL: the online resource │ │ │ │ - * - {String} typeName: the name of the typename on the service │ │ │ │ - */ │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/XLS.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 │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.XLS │ │ │ │ - * Read/Write XLS (OpenLS). Create a new instance with the <OpenLayers.Format.XLS> │ │ │ │ - * constructor. Currently only implemented for Location Utility Services, more │ │ │ │ - * specifically only for Geocoding. No support for Reverse Geocoding as yet. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.XLS = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: defaultVersion │ │ │ │ - * {String} Version number to assume if none found. Default is "1.1.0". │ │ │ │ - */ │ │ │ │ - defaultVersion: "1.1.0", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: stringifyOutput │ │ │ │ - * {Boolean} If true, write will return a string otherwise a DOMElement. │ │ │ │ - * Default is true. │ │ │ │ - */ │ │ │ │ - stringifyOutput: true, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.XLS │ │ │ │ - * Create a new parser for XLS. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Write out an XLS request. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * request - {Object} An object representing the LUS request. │ │ │ │ - * options - {Object} Optional configuration object. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} An XLS document string. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read an XLS doc and return an object representing the result. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String | DOMElement} Data to read. │ │ │ │ - * options - {Object} Options for the reader. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An object representing the GeocodeResponse. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.XLS" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/SOSCapabilities.js │ │ │ │ + OpenLayers/Format/WPSCapabilities.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 │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.SOSCapabilities │ │ │ │ - * Read SOS Capabilities. │ │ │ │ + * Class: OpenLayers.Format.WPSCapabilities │ │ │ │ + * Read WPS Capabilities. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Format.XML.VersionedOGC> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.SOSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ +OpenLayers.Format.WPSCapabilities = 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", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.SOSCapabilities │ │ │ │ - * Create a new parser for SOS Capabilities. │ │ │ │ + * Constructor: OpenLayers.Format.WPSCapabilities │ │ │ │ + * Create a new parser for WPS Capabilities. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be set on │ │ │ │ * this instance. │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: read │ │ │ │ * Read capabilities data from a string, and return information about │ │ │ │ - * the service (offering and observedProperty mostly). │ │ │ │ + * the service. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * data - {String} or {DOMElement} data to read/parse. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Object} Info about the SOS │ │ │ │ - */ │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SOSCapabilities" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - 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/Format/ArcXML/Features.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/ArcXML.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.ArcXML.Features │ │ │ │ - * Read/Write ArcXML features. Create a new instance with the │ │ │ │ - * <OpenLayers.Format.ArcXML.Features> constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.ArcXML.Features = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.ArcXML.Features │ │ │ │ - * Create a new parser/writer for ArcXML Features. Create an instance of this class │ │ │ │ - * to get a set of features from an ArcXML response. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * {Object} Info about the WPS │ │ │ │ */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read data from a string of ArcXML, and return a set of OpenLayers features. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array(<OpenLayers.Feature.Vector>)} A collection of features. │ │ │ │ - */ │ │ │ │ - read: function(data) { │ │ │ │ - var axl = new OpenLayers.Format.ArcXML(); │ │ │ │ - var parsed = axl.read(data); │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WPSCapabilities" │ │ │ │ │ │ │ │ - return parsed.features.feature; │ │ │ │ - } │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSDescribeLayer/v1_1.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/WMSDescribeLayer.js │ │ │ │ - * @requires OpenLayers/Format/OGCExceptionReport.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSDescribeLayer.v1_1_1 │ │ │ │ - * Read SLD WMS DescribeLayer response for WMS 1.1.X │ │ │ │ - * WMS 1.1.X is tightly coupled to SLD 1.0.0 │ │ │ │ - * │ │ │ │ - * Example DescribeLayer request: │ │ │ │ - * http://demo.opengeo.org/geoserver/wms?request=DescribeLayer&version=1.1.1&layers=topp:states │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMSDescribeLayer> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSDescribeLayer.v1_1_1 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WMSDescribeLayer, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WMSDescribeLayer │ │ │ │ - * Create a new parser for WMS DescribeLayer responses. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.WMSDescribeLayer.prototype.initialize.apply(this, │ │ │ │ - [options]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read DescribeLayer data from a string, and return the response. │ │ │ │ - * The OGC defines 2 formats which are allowed for output, │ │ │ │ - * so we need to parse these 2 types for version 1.1.X │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} Object with a layerDescriptions property, which holds an Array │ │ │ │ - * of {<LayerDescription>} objects which have: │ │ │ │ - * - {String} owsType: WFS/WCS │ │ │ │ - * - {String} owsURL: the online resource │ │ │ │ - * - {String} typeName: the name of the typename on the owsType service │ │ │ │ - * - {String} layerName: the name of the WMS layer we did a lookup for │ │ │ │ - */ │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - } │ │ │ │ - var root = data.documentElement; │ │ │ │ - var children = root.childNodes; │ │ │ │ - var describelayer = { │ │ │ │ - layerDescriptions: [] │ │ │ │ - }; │ │ │ │ - var childNode, nodeName; │ │ │ │ - for (var i = 0; i < children.length; ++i) { │ │ │ │ - childNode = children[i]; │ │ │ │ - nodeName = childNode.nodeName; │ │ │ │ - if (nodeName == 'LayerDescription') { │ │ │ │ - var layerName = childNode.getAttribute('name'); │ │ │ │ - var owsType = ''; │ │ │ │ - var owsURL = ''; │ │ │ │ - var typeName = ''; │ │ │ │ - // check for owsType and owsURL attributes │ │ │ │ - if (childNode.getAttribute('owsType')) { │ │ │ │ - owsType = childNode.getAttribute('owsType'); │ │ │ │ - owsURL = childNode.getAttribute('owsURL'); │ │ │ │ - } else { │ │ │ │ - // look for wfs or wcs attribute │ │ │ │ - if (childNode.getAttribute('wfs') != '') { │ │ │ │ - owsType = 'WFS'; │ │ │ │ - owsURL = childNode.getAttribute('wfs'); │ │ │ │ - } else if (childNode.getAttribute('wcs') != '') { │ │ │ │ - owsType = 'WCS'; │ │ │ │ - owsURL = childNode.getAttribute('wcs'); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - // look for Query child │ │ │ │ - var query = childNode.getElementsByTagName('Query'); │ │ │ │ - if (query.length > 0) { │ │ │ │ - typeName = query[0].getAttribute('typeName'); │ │ │ │ - if (!typeName) { │ │ │ │ - // because of Ionic bug │ │ │ │ - typeName = query[0].getAttribute('typename'); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var layerDescription = { │ │ │ │ - layerName: layerName, │ │ │ │ - owsType: owsType, │ │ │ │ - owsURL: owsURL, │ │ │ │ - typeName: typeName │ │ │ │ - }; │ │ │ │ - describelayer.layerDescriptions.push(layerDescription); │ │ │ │ - │ │ │ │ - //TODO do this in deprecated.js instead: │ │ │ │ - // array style index for backwards compatibility │ │ │ │ - describelayer.length = describelayer.layerDescriptions.length; │ │ │ │ - describelayer[describelayer.length - 1] = layerDescription; │ │ │ │ - │ │ │ │ - } else if (nodeName == 'ServiceException') { │ │ │ │ - // an exception must have occurred, so parse it │ │ │ │ - var parser = new OpenLayers.Format.OGCExceptionReport(); │ │ │ │ - return { │ │ │ │ - error: parser.read(data) │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return describelayer; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer.v1_1_1" │ │ │ │ - │ │ │ │ - }); │ │ │ │ - │ │ │ │ -// Version alias - workaround for http://trac.osgeo.org/mapserver/ticket/2257 │ │ │ │ -OpenLayers.Format.WMSDescribeLayer.v1_1_0 = │ │ │ │ - OpenLayers.Format.WMSDescribeLayer.v1_1_1; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSCapabilities/v1.js │ │ │ │ + OpenLayers/Format/WCSCapabilities/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/WMSCapabilities.js │ │ │ │ - * @requires OpenLayers/Format/OGCExceptionReport.js │ │ │ │ - * @requires OpenLayers/Format/XML.js │ │ │ │ + * @requires OpenLayers/Format/WCSCapabilities.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WMSCapabilities.v1 │ │ │ │ - * Abstract class not to be instantiated directly. Creates │ │ │ │ - * the common parts for both WMS 1.1.X and WMS 1.3.X. │ │ │ │ + * Class: OpenLayers.Format.WCSCapabilities.v1 │ │ │ │ + * Abstract class not to be instantiated directly. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1 = OpenLayers.Class( │ │ │ │ +OpenLayers.Format.WCSCapabilities.v1 = OpenLayers.Class( │ │ │ │ OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - wms: "http://www.opengis.net/wms", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + splitSpace: (/\s+/) │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * Property: defaultPrefix │ │ │ │ */ │ │ │ │ - defaultPrefix: "wms", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WMSCapabilities.v1 │ │ │ │ - * Create an instance of one of the subclasses. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ + defaultPrefix: "wcs", │ │ │ │ │ │ │ │ /** │ │ │ │ * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return a list of layers. │ │ │ │ + * Read capabilities data from a string, and return a list of coverages. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * data - {String} or {DOMElement} data to read/parse. │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ - * {Array} List of named layers. │ │ │ │ + * {Array} List of named coverages. │ │ │ │ */ │ │ │ │ read: function(data) { │ │ │ │ if (typeof data == "string") { │ │ │ │ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ } │ │ │ │ var raw = data; │ │ │ │ if (data && data.nodeType == 9) { │ │ │ │ data = data.documentElement; │ │ │ │ } │ │ │ │ var capabilities = {}; │ │ │ │ this.readNode(data, capabilities); │ │ │ │ - if (capabilities.service === undefined) { │ │ │ │ - // an exception must have occurred, so parse it │ │ │ │ - var parser = new OpenLayers.Format.OGCExceptionReport(); │ │ │ │ - capabilities.error = parser.read(raw); │ │ │ │ - } │ │ │ │ return capabilities; │ │ │ │ }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "wms": { │ │ │ │ - "Service": function(node, obj) { │ │ │ │ - obj.service = {}; │ │ │ │ - this.readChildNodes(node, obj.service); │ │ │ │ - }, │ │ │ │ - "Name": function(node, obj) { │ │ │ │ - obj.name = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Title": function(node, obj) { │ │ │ │ - obj.title = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Abstract": function(node, obj) { │ │ │ │ - obj["abstract"] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "BoundingBox": function(node, obj) { │ │ │ │ - var bbox = {}; │ │ │ │ - bbox.bbox = [ │ │ │ │ - parseFloat(node.getAttribute("minx")), │ │ │ │ - parseFloat(node.getAttribute("miny")), │ │ │ │ - parseFloat(node.getAttribute("maxx")), │ │ │ │ - parseFloat(node.getAttribute("maxy")) │ │ │ │ - ]; │ │ │ │ - var res = { │ │ │ │ - x: parseFloat(node.getAttribute("resx")), │ │ │ │ - y: parseFloat(node.getAttribute("resy")) │ │ │ │ - }; │ │ │ │ - │ │ │ │ - if (!(isNaN(res.x) && isNaN(res.y))) { │ │ │ │ - bbox.res = res; │ │ │ │ - } │ │ │ │ - // return the bbox so that descendant classes can set the │ │ │ │ - // CRS and SRS and add it to the obj │ │ │ │ - return bbox; │ │ │ │ - }, │ │ │ │ - "OnlineResource": function(node, obj) { │ │ │ │ - obj.href = this.getAttributeNS(node, this.namespaces.xlink, │ │ │ │ - "href"); │ │ │ │ - }, │ │ │ │ - "ContactInformation": function(node, obj) { │ │ │ │ - obj.contactInformation = {}; │ │ │ │ - this.readChildNodes(node, obj.contactInformation); │ │ │ │ - }, │ │ │ │ - "ContactPersonPrimary": function(node, obj) { │ │ │ │ - obj.personPrimary = {}; │ │ │ │ - this.readChildNodes(node, obj.personPrimary); │ │ │ │ - }, │ │ │ │ - "ContactPerson": function(node, obj) { │ │ │ │ - obj.person = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ContactOrganization": function(node, obj) { │ │ │ │ - obj.organization = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ContactPosition": function(node, obj) { │ │ │ │ - obj.position = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ContactAddress": function(node, obj) { │ │ │ │ - obj.contactAddress = {}; │ │ │ │ - this.readChildNodes(node, obj.contactAddress); │ │ │ │ - }, │ │ │ │ - "AddressType": function(node, obj) { │ │ │ │ - obj.type = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Address": function(node, obj) { │ │ │ │ - obj.address = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "City": function(node, obj) { │ │ │ │ - obj.city = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "StateOrProvince": function(node, obj) { │ │ │ │ - obj.stateOrProvince = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "PostCode": function(node, obj) { │ │ │ │ - obj.postcode = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Country": function(node, obj) { │ │ │ │ - obj.country = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ContactVoiceTelephone": function(node, obj) { │ │ │ │ - obj.phone = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ContactFacsimileTelephone": function(node, obj) { │ │ │ │ - obj.fax = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ContactElectronicMailAddress": function(node, obj) { │ │ │ │ - obj.email = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Fees": function(node, obj) { │ │ │ │ - var fees = this.getChildValue(node); │ │ │ │ - if (fees && fees.toLowerCase() != "none") { │ │ │ │ - obj.fees = fees; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "AccessConstraints": function(node, obj) { │ │ │ │ - var constraints = this.getChildValue(node); │ │ │ │ - if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ - obj.accessConstraints = constraints; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Capability": function(node, obj) { │ │ │ │ - obj.capability = { │ │ │ │ - nestedLayers: [], │ │ │ │ - layers: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.capability); │ │ │ │ - }, │ │ │ │ - "Request": function(node, obj) { │ │ │ │ - obj.request = {}; │ │ │ │ - this.readChildNodes(node, obj.request); │ │ │ │ - }, │ │ │ │ - "GetCapabilities": function(node, obj) { │ │ │ │ - obj.getcapabilities = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getcapabilities); │ │ │ │ - }, │ │ │ │ - "Format": function(node, obj) { │ │ │ │ - if (OpenLayers.Util.isArray(obj.formats)) { │ │ │ │ - obj.formats.push(this.getChildValue(node)); │ │ │ │ - } else { │ │ │ │ - obj.format = this.getChildValue(node); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "DCPType": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "HTTP": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "Get": function(node, obj) { │ │ │ │ - obj.get = {}; │ │ │ │ - this.readChildNodes(node, obj.get); │ │ │ │ - // backwards compatibility │ │ │ │ - if (!obj.href) { │ │ │ │ - obj.href = obj.get.href; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Post": function(node, obj) { │ │ │ │ - obj.post = {}; │ │ │ │ - this.readChildNodes(node, obj.post); │ │ │ │ - // backwards compatibility │ │ │ │ - if (!obj.href) { │ │ │ │ - obj.href = obj.get.href; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "GetMap": function(node, obj) { │ │ │ │ - obj.getmap = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getmap); │ │ │ │ - }, │ │ │ │ - "GetFeatureInfo": function(node, obj) { │ │ │ │ - obj.getfeatureinfo = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getfeatureinfo); │ │ │ │ - }, │ │ │ │ - "Exception": function(node, obj) { │ │ │ │ - obj.exception = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.exception); │ │ │ │ - }, │ │ │ │ - "Layer": function(node, obj) { │ │ │ │ - var parentLayer, capability; │ │ │ │ - if (obj.capability) { │ │ │ │ - capability = obj.capability; │ │ │ │ - parentLayer = obj; │ │ │ │ - } else { │ │ │ │ - capability = obj; │ │ │ │ - } │ │ │ │ - var attrNode = node.getAttributeNode("queryable"); │ │ │ │ - var queryable = (attrNode && attrNode.specified) ? │ │ │ │ - node.getAttribute("queryable") : null; │ │ │ │ - attrNode = node.getAttributeNode("cascaded"); │ │ │ │ - var cascaded = (attrNode && attrNode.specified) ? │ │ │ │ - node.getAttribute("cascaded") : null; │ │ │ │ - attrNode = node.getAttributeNode("opaque"); │ │ │ │ - var opaque = (attrNode && attrNode.specified) ? │ │ │ │ - node.getAttribute('opaque') : null; │ │ │ │ - var noSubsets = node.getAttribute('noSubsets'); │ │ │ │ - var fixedWidth = node.getAttribute('fixedWidth'); │ │ │ │ - var fixedHeight = node.getAttribute('fixedHeight'); │ │ │ │ - var parent = parentLayer || {}, │ │ │ │ - extend = OpenLayers.Util.extend; │ │ │ │ - var layer = { │ │ │ │ - nestedLayers: [], │ │ │ │ - styles: parentLayer ? [].concat(parentLayer.styles) : [], │ │ │ │ - srs: parentLayer ? extend({}, parent.srs) : {}, │ │ │ │ - metadataURLs: [], │ │ │ │ - bbox: parentLayer ? extend({}, parent.bbox) : {}, │ │ │ │ - llbbox: parent.llbbox, │ │ │ │ - dimensions: parentLayer ? extend({}, parent.dimensions) : {}, │ │ │ │ - authorityURLs: parentLayer ? extend({}, parent.authorityURLs) : {}, │ │ │ │ - identifiers: {}, │ │ │ │ - keywords: [], │ │ │ │ - queryable: (queryable && queryable !== "") ? │ │ │ │ - (queryable === "1" || queryable === "true") : (parent.queryable || false), │ │ │ │ - cascaded: (cascaded !== null) ? parseInt(cascaded) : (parent.cascaded || 0), │ │ │ │ - opaque: opaque ? │ │ │ │ - (opaque === "1" || opaque === "true") : (parent.opaque || false), │ │ │ │ - noSubsets: (noSubsets !== null) ? │ │ │ │ - (noSubsets === "1" || noSubsets === "true") : (parent.noSubsets || false), │ │ │ │ - fixedWidth: (fixedWidth != null) ? │ │ │ │ - parseInt(fixedWidth) : (parent.fixedWidth || 0), │ │ │ │ - fixedHeight: (fixedHeight != null) ? │ │ │ │ - parseInt(fixedHeight) : (parent.fixedHeight || 0), │ │ │ │ - minScale: parent.minScale, │ │ │ │ - maxScale: parent.maxScale, │ │ │ │ - attribution: parent.attribution │ │ │ │ - }; │ │ │ │ - obj.nestedLayers.push(layer); │ │ │ │ - layer.capability = capability; │ │ │ │ - this.readChildNodes(node, layer); │ │ │ │ - delete layer.capability; │ │ │ │ - if (layer.name) { │ │ │ │ - var parts = layer.name.split(":"), │ │ │ │ - request = capability.request, │ │ │ │ - gfi = request.getfeatureinfo; │ │ │ │ - if (parts.length > 0) { │ │ │ │ - layer.prefix = parts[0]; │ │ │ │ - } │ │ │ │ - capability.layers.push(layer); │ │ │ │ - if (layer.formats === undefined) { │ │ │ │ - layer.formats = request.getmap.formats; │ │ │ │ - } │ │ │ │ - if (layer.infoFormats === undefined && gfi) { │ │ │ │ - layer.infoFormats = gfi.formats; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Attribution": function(node, obj) { │ │ │ │ - obj.attribution = {}; │ │ │ │ - this.readChildNodes(node, obj.attribution); │ │ │ │ - }, │ │ │ │ - "LogoURL": function(node, obj) { │ │ │ │ - obj.logo = { │ │ │ │ - width: node.getAttribute("width"), │ │ │ │ - height: node.getAttribute("height") │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.logo); │ │ │ │ - }, │ │ │ │ - "Style": function(node, obj) { │ │ │ │ - var style = {}; │ │ │ │ - obj.styles.push(style); │ │ │ │ - this.readChildNodes(node, style); │ │ │ │ - }, │ │ │ │ - "LegendURL": function(node, obj) { │ │ │ │ - var legend = { │ │ │ │ - width: node.getAttribute("width"), │ │ │ │ - height: node.getAttribute("height") │ │ │ │ - }; │ │ │ │ - obj.legend = legend; │ │ │ │ - this.readChildNodes(node, legend); │ │ │ │ - }, │ │ │ │ - "MetadataURL": function(node, obj) { │ │ │ │ - var metadataURL = { │ │ │ │ - type: node.getAttribute("type") │ │ │ │ - }; │ │ │ │ - obj.metadataURLs.push(metadataURL); │ │ │ │ - this.readChildNodes(node, metadataURL); │ │ │ │ - }, │ │ │ │ - "DataURL": function(node, obj) { │ │ │ │ - obj.dataURL = {}; │ │ │ │ - this.readChildNodes(node, obj.dataURL); │ │ │ │ - }, │ │ │ │ - "FeatureListURL": function(node, obj) { │ │ │ │ - obj.featureListURL = {}; │ │ │ │ - this.readChildNodes(node, obj.featureListURL); │ │ │ │ - }, │ │ │ │ - "AuthorityURL": function(node, obj) { │ │ │ │ - var name = node.getAttribute("name"); │ │ │ │ - var authority = {}; │ │ │ │ - this.readChildNodes(node, authority); │ │ │ │ - obj.authorityURLs[name] = authority.href; │ │ │ │ - }, │ │ │ │ - "Identifier": function(node, obj) { │ │ │ │ - var authority = node.getAttribute("authority"); │ │ │ │ - obj.identifiers[authority] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "KeywordList": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "SRS": function(node, obj) { │ │ │ │ - obj.srs[this.getChildValue(node)] = true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSCapabilities/v1_1.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/WMSCapabilities/v1.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSCapabilities.v1_1 │ │ │ │ - * Abstract class not to be instantiated directly. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMSCapabilities.v1> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ - "WMT_MS_Capabilities": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "Keyword": function(node, obj) { │ │ │ │ - if (obj.keywords) { │ │ │ │ - obj.keywords.push(this.getChildValue(node)); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "DescribeLayer": function(node, obj) { │ │ │ │ - obj.describelayer = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.describelayer); │ │ │ │ - }, │ │ │ │ - "GetLegendGraphic": function(node, obj) { │ │ │ │ - obj.getlegendgraphic = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getlegendgraphic); │ │ │ │ - }, │ │ │ │ - "GetStyles": function(node, obj) { │ │ │ │ - obj.getstyles = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getstyles); │ │ │ │ - }, │ │ │ │ - "PutStyles": function(node, obj) { │ │ │ │ - obj.putstyles = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.putstyles); │ │ │ │ - }, │ │ │ │ - "UserDefinedSymbolization": function(node, obj) { │ │ │ │ - var userSymbols = { │ │ │ │ - supportSLD: parseInt(node.getAttribute("SupportSLD")) == 1, │ │ │ │ - userLayer: parseInt(node.getAttribute("UserLayer")) == 1, │ │ │ │ - userStyle: parseInt(node.getAttribute("UserStyle")) == 1, │ │ │ │ - remoteWFS: parseInt(node.getAttribute("RemoteWFS")) == 1 │ │ │ │ - }; │ │ │ │ - obj.userSymbols = userSymbols; │ │ │ │ - }, │ │ │ │ - "LatLonBoundingBox": function(node, obj) { │ │ │ │ - obj.llbbox = [ │ │ │ │ - parseFloat(node.getAttribute("minx")), │ │ │ │ - parseFloat(node.getAttribute("miny")), │ │ │ │ - parseFloat(node.getAttribute("maxx")), │ │ │ │ - parseFloat(node.getAttribute("maxy")) │ │ │ │ - ]; │ │ │ │ - }, │ │ │ │ - "BoundingBox": function(node, obj) { │ │ │ │ - var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ - bbox.srs = node.getAttribute("SRS"); │ │ │ │ - obj.bbox[bbox.srs] = bbox; │ │ │ │ - }, │ │ │ │ - "ScaleHint": function(node, obj) { │ │ │ │ - var min = node.getAttribute("min"); │ │ │ │ - var max = node.getAttribute("max"); │ │ │ │ - var rad2 = Math.pow(2, 0.5); │ │ │ │ - var ipm = OpenLayers.INCHES_PER_UNIT["m"]; │ │ │ │ - if (min != 0) { │ │ │ │ - obj.maxScale = parseFloat( │ │ │ │ - ((min / rad2) * ipm * │ │ │ │ - OpenLayers.DOTS_PER_INCH).toPrecision(13) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (max != Number.POSITIVE_INFINITY) { │ │ │ │ - obj.minScale = parseFloat( │ │ │ │ - ((max / rad2) * ipm * │ │ │ │ - OpenLayers.DOTS_PER_INCH).toPrecision(13) │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Dimension": function(node, obj) { │ │ │ │ - var name = node.getAttribute("name").toLowerCase(); │ │ │ │ - var dim = { │ │ │ │ - name: name, │ │ │ │ - units: node.getAttribute("units"), │ │ │ │ - unitsymbol: node.getAttribute("unitSymbol") │ │ │ │ - }; │ │ │ │ - obj.dimensions[dim.name] = dim; │ │ │ │ - }, │ │ │ │ - "Extent": function(node, obj) { │ │ │ │ - var name = node.getAttribute("name").toLowerCase(); │ │ │ │ - if (name in obj["dimensions"]) { │ │ │ │ - var extent = obj.dimensions[name]; │ │ │ │ - extent.nearestVal = │ │ │ │ - node.getAttribute("nearestValue") === "1"; │ │ │ │ - extent.multipleVal = │ │ │ │ - node.getAttribute("multipleValues") === "1"; │ │ │ │ - extent.current = node.getAttribute("current") === "1"; │ │ │ │ - extent["default"] = node.getAttribute("default") || ""; │ │ │ │ - var values = this.getChildValue(node); │ │ │ │ - extent.values = values.split(","); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSCapabilities/v1_3.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/WMSCapabilities/v1.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSCapabilities/v1_3 │ │ │ │ - * Abstract base class for WMS Capabilities version 1.3.X. │ │ │ │ - * SLD 1.1.0 adds in the extra operations DescribeLayer and GetLegendGraphic, │ │ │ │ - * see: http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMSCapabilities.v1> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_3 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ - "WMS_Capabilities": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "LayerLimit": function(node, obj) { │ │ │ │ - obj.layerLimit = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "MaxWidth": function(node, obj) { │ │ │ │ - obj.maxWidth = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "MaxHeight": function(node, obj) { │ │ │ │ - obj.maxHeight = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "BoundingBox": function(node, obj) { │ │ │ │ - var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ - bbox.srs = node.getAttribute("CRS"); │ │ │ │ - obj.bbox[bbox.srs] = bbox; │ │ │ │ - }, │ │ │ │ - "CRS": function(node, obj) { │ │ │ │ - // CRS is the synonym of SRS │ │ │ │ - this.readers.wms.SRS.apply(this, [node, obj]); │ │ │ │ - }, │ │ │ │ - "EX_GeographicBoundingBox": function(node, obj) { │ │ │ │ - // replacement of LatLonBoundingBox │ │ │ │ - obj.llbbox = []; │ │ │ │ - this.readChildNodes(node, obj.llbbox); │ │ │ │ - │ │ │ │ - }, │ │ │ │ - "westBoundLongitude": function(node, obj) { │ │ │ │ - obj[0] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "eastBoundLongitude": function(node, obj) { │ │ │ │ - obj[2] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "southBoundLatitude": function(node, obj) { │ │ │ │ - obj[1] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "northBoundLatitude": function(node, obj) { │ │ │ │ - obj[3] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "MinScaleDenominator": function(node, obj) { │ │ │ │ - obj.maxScale = parseFloat(this.getChildValue(node)).toPrecision(16); │ │ │ │ - }, │ │ │ │ - "MaxScaleDenominator": function(node, obj) { │ │ │ │ - obj.minScale = parseFloat(this.getChildValue(node)).toPrecision(16); │ │ │ │ - }, │ │ │ │ - "Dimension": function(node, obj) { │ │ │ │ - // dimension has extra attributes: default, multipleValues, │ │ │ │ - // nearestValue, current which used to be part of Extent. It now │ │ │ │ - // also contains the values. │ │ │ │ - var name = node.getAttribute("name").toLowerCase(); │ │ │ │ - var dim = { │ │ │ │ - name: name, │ │ │ │ - units: node.getAttribute("units"), │ │ │ │ - unitsymbol: node.getAttribute("unitSymbol"), │ │ │ │ - nearestVal: node.getAttribute("nearestValue") === "1", │ │ │ │ - multipleVal: node.getAttribute("multipleValues") === "1", │ │ │ │ - "default": node.getAttribute("default") || "", │ │ │ │ - current: node.getAttribute("current") === "1", │ │ │ │ - values: this.getChildValue(node).split(",") │ │ │ │ - │ │ │ │ - }; │ │ │ │ - // Theoretically there can be more dimensions with the same │ │ │ │ - // name, but with a different unit. Until we meet such a case, │ │ │ │ - // let's just keep the same structure as the WMS 1.1 │ │ │ │ - // GetCapabilities parser uses. We will store the last │ │ │ │ - // one encountered. │ │ │ │ - obj.dimensions[dim.name] = dim; │ │ │ │ - }, │ │ │ │ - "Keyword": function(node, obj) { │ │ │ │ - // TODO: should we change the structure of keyword in v1.js? │ │ │ │ - // Make it an object with a value instead of a string? │ │ │ │ - var keyword = { │ │ │ │ - value: this.getChildValue(node), │ │ │ │ - vocabulary: node.getAttribute("vocabulary") │ │ │ │ - }; │ │ │ │ - if (obj.keywords) { │ │ │ │ - obj.keywords.push(keyword); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]), │ │ │ │ - "sld": { │ │ │ │ - "UserDefinedSymbolization": function(node, obj) { │ │ │ │ - this.readers.wms.UserDefinedSymbolization.apply(this, [node, obj]); │ │ │ │ - // add the two extra attributes │ │ │ │ - obj.userSymbols.inlineFeature = parseInt(node.getAttribute("InlineFeature")) == 1; │ │ │ │ - obj.userSymbols.remoteWCS = parseInt(node.getAttribute("RemoteWCS")) == 1; │ │ │ │ - }, │ │ │ │ - "DescribeLayer": function(node, obj) { │ │ │ │ - this.readers.wms.DescribeLayer.apply(this, [node, obj]); │ │ │ │ - }, │ │ │ │ - "GetLegendGraphic": function(node, obj) { │ │ │ │ - this.readers.wms.GetLegendGraphic.apply(this, [node, obj]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSCapabilities/v1_3_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/WMSCapabilities/v1_3.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSCapabilities/v1_3_0 │ │ │ │ - * Read WMS Capabilities version 1.3.0. │ │ │ │ - * SLD 1.1.0 adds in the extra operations DescribeLayer and GetLegendGraphic, │ │ │ │ - * see: http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMSCapabilities.v1_3> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_3_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WMSCapabilities.v1_3, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} The specific parser version. │ │ │ │ - */ │ │ │ │ - version: "1.3.0", │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3_0" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSCapabilities/v1_1_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/WMSCapabilities/v1_1.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSCapabilities/v1_1_0 │ │ │ │ - * Read WMS Capabilities version 1.1.0. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMSCapabilities.v1_1> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} The specific parser version. │ │ │ │ - */ │ │ │ │ - version: "1.1.0", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_0 │ │ │ │ - * Create a new parser for WMS capabilities version 1.1.0. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ - "SRS": function(node, obj) { │ │ │ │ - var srs = this.getChildValue(node); │ │ │ │ - var values = srs.split(/ +/); │ │ │ │ - for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ - obj.srs[values[i]] = true; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSCapabilities/v1_1_1.js │ │ │ │ + OpenLayers/Format/WCSCapabilities/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/WMSCapabilities/v1_1.js │ │ │ │ + * @requires OpenLayers/Format/WCSCapabilities/v1.js │ │ │ │ + * @requires OpenLayers/Format/GML/v3.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WMSCapabilities/v1_1_1 │ │ │ │ - * Read WMS Capabilities version 1.1.1. │ │ │ │ - * │ │ │ │ - * Note on <ScaleHint> parsing: If the 'min' attribute is set to "0", no │ │ │ │ - * maxScale will be set on the layer object. If the 'max' attribute is set to │ │ │ │ - * "Infinity", no minScale will be set. This makes it easy to create proper │ │ │ │ - * {<OpenLayers.Layer.WMS>} configurations directly from the layer object │ │ │ │ - * literals returned by this format, because no minScale/maxScale modifications │ │ │ │ - * need to be made. │ │ │ │ + * Class: OpenLayers.Format.WCSCapabilities/v1_0_0 │ │ │ │ + * Read WCS Capabilities version 1.0.0. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMSCapabilities.v1_1> │ │ │ │ + * - <OpenLayers.Format.WCSCapabilities.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1_1 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} The specific parser version. │ │ │ │ - */ │ │ │ │ - version: "1.1.1", │ │ │ │ +OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_1 │ │ │ │ - * Create a new parser for WMS capabilities version 1.1.1. │ │ │ │ + * Constructor: OpenLayers.Format.WCSCapabilities.v1_0_0 │ │ │ │ + * Create a new parser for WCS capabilities version 1.0.0. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be set on │ │ │ │ * this instance. │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * 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. │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ - readers: { │ │ │ │ - "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ - "SRS": function(node, obj) { │ │ │ │ - obj.srs[this.getChildValue(node)] = true; │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ + namespaces: { │ │ │ │ + wcs: "http://www.opengis.net/wcs", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ + ows: "http://www.opengis.net/ows" │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WMSCapabilities/v1_1_1_WMSC.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/WMSCapabilities/v1_1_1.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WMSCapabilities/v1_1_1_WMSC │ │ │ │ - * Read WMS-C Capabilities version 1.1.1. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMSCapabilities.v1_1_1> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WMSCapabilities.v1_1_1, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} The specific parser version. │ │ │ │ - */ │ │ │ │ - version: "1.1.1", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: profile │ │ │ │ - * {String} The specific profile │ │ │ │ - */ │ │ │ │ - profile: "WMSC", │ │ │ │ - │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_1 │ │ │ │ - * Create a new parser for WMS-C capabilities version 1.1.1. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ + * Property: errorProperty │ │ │ │ + * {String} Which property of the returned object to check for in order to │ │ │ │ + * determine whether or not parsing has failed. In the case that the │ │ │ │ + * errorProperty is undefined on the returned object, the document will be │ │ │ │ + * run through an OGCExceptionReport parser. │ │ │ │ */ │ │ │ │ + errorProperty: "service", │ │ │ │ │ │ │ │ /** │ │ │ │ * 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: { │ │ │ │ - "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ - "VendorSpecificCapabilities": function(node, obj) { │ │ │ │ - obj.vendorSpecific = { │ │ │ │ - tileSets: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.vendorSpecific); │ │ │ │ + "wcs": { │ │ │ │ + "WCS_Capabilities": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ }, │ │ │ │ - "TileSet": function(node, vendorSpecific) { │ │ │ │ - var tileset = { │ │ │ │ - srs: {}, │ │ │ │ - bbox: {}, │ │ │ │ - resolutions: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, tileset); │ │ │ │ - vendorSpecific.tileSets.push(tileset); │ │ │ │ + "Service": function(node, obj) { │ │ │ │ + obj.service = {}; │ │ │ │ + this.readChildNodes(node, obj.service); │ │ │ │ }, │ │ │ │ - "Resolutions": function(node, tileset) { │ │ │ │ - var res = this.getChildValue(node).split(" "); │ │ │ │ - for (var i = 0, len = res.length; i < len; i++) { │ │ │ │ - if (res[i] != "") { │ │ │ │ - tileset.resolutions.push(parseFloat(res[i])); │ │ │ │ - } │ │ │ │ - } │ │ │ │ + "name": function(node, service) { │ │ │ │ + service.name = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "Width": function(node, tileset) { │ │ │ │ - tileset.width = parseInt(this.getChildValue(node)); │ │ │ │ + "label": function(node, service) { │ │ │ │ + service.label = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "Height": function(node, tileset) { │ │ │ │ - tileset.height = parseInt(this.getChildValue(node)); │ │ │ │ + "keywords": function(node, service) { │ │ │ │ + service.keywords = []; │ │ │ │ + this.readChildNodes(node, service.keywords); │ │ │ │ }, │ │ │ │ - "Layers": function(node, tileset) { │ │ │ │ - tileset.layers = this.getChildValue(node); │ │ │ │ + "keyword": function(node, keywords) { │ │ │ │ + // Append the keyword to the keywords list │ │ │ │ + keywords.push(this.getChildValue(node)); │ │ │ │ }, │ │ │ │ - "Styles": function(node, tileset) { │ │ │ │ - tileset.styles = this.getChildValue(node); │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1_1_1.prototype.readers["wms"]) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WPSCapabilities/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/WPSCapabilities.js │ │ │ │ - * @requires OpenLayers/Format/OWSCommon/v1_1_0.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WPSCapabilities.v1_0_0 │ │ │ │ - * Read WPS Capabilities version 1.0.0. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WPSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - ows: "http://www.opengis.net/ows/1.1", │ │ │ │ - wps: "http://www.opengis.net/wps/1.0.0", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ - */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WPSCapabilities.v1_0_0 │ │ │ │ - * Create a new parser for WPS capabilities version 1.0.0. │ │ │ │ - * │ │ │ │ - * 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]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return info about the WPS. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} Information about the WPS service. │ │ │ │ - */ │ │ │ │ - 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 capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - return capabilities; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "wps": { │ │ │ │ - "Capabilities": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ + "responsibleParty": function(node, service) { │ │ │ │ + service.responsibleParty = {}; │ │ │ │ + this.readChildNodes(node, service.responsibleParty); │ │ │ │ }, │ │ │ │ - "ProcessOfferings": function(node, obj) { │ │ │ │ - obj.processOfferings = {}; │ │ │ │ - this.readChildNodes(node, obj.processOfferings); │ │ │ │ + "individualName": function(node, responsibleParty) { │ │ │ │ + responsibleParty.individualName = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "Process": function(node, processOfferings) { │ │ │ │ - var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); │ │ │ │ - var process = { │ │ │ │ - processVersion: processVersion │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, process); │ │ │ │ - processOfferings[process.identifier] = process; │ │ │ │ + "organisationName": function(node, responsibleParty) { │ │ │ │ + responsibleParty.organisationName = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "Languages": function(node, obj) { │ │ │ │ - obj.languages = []; │ │ │ │ - this.readChildNodes(node, obj.languages); │ │ │ │ + "positionName": function(node, responsibleParty) { │ │ │ │ + responsibleParty.positionName = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "Default": function(node, languages) { │ │ │ │ - var language = { │ │ │ │ - isDefault: true │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, language); │ │ │ │ - languages.push(language); │ │ │ │ + "contactInfo": function(node, responsibleParty) { │ │ │ │ + responsibleParty.contactInfo = {}; │ │ │ │ + this.readChildNodes(node, responsibleParty.contactInfo); │ │ │ │ }, │ │ │ │ - "Supported": function(node, languages) { │ │ │ │ - var language = {}; │ │ │ │ - this.readChildNodes(node, language); │ │ │ │ - languages.push(language); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WPSCapabilities.v1_0_0" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/CSWGetRecords/v2_0_2.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/CSWGetRecords.js │ │ │ │ - * @requires OpenLayers/Format/Filter/v1_0_0.js │ │ │ │ - * @requires OpenLayers/Format/Filter/v1_1_0.js │ │ │ │ - * @requires OpenLayers/Format/OWSCommon/v1_0_0.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.CSWGetRecords.v2_0_2 │ │ │ │ - * A format for creating CSWGetRecords v2.0.2 transactions. │ │ │ │ - * Create a new instance with the │ │ │ │ - * <OpenLayers.Format.CSWGetRecords.v2_0_2> constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.CSWGetRecords.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - csw: "http://www.opengis.net/cat/csw/2.0.2", │ │ │ │ - dc: "http://purl.org/dc/elements/1.1/", │ │ │ │ - dct: "http://purl.org/dc/terms/", │ │ │ │ - gmd: "http://www.isotc211.org/2005/gmd", │ │ │ │ - geonet: "http://www.fao.org/geonetwork", │ │ │ │ - ogc: "http://www.opengis.net/ogc", │ │ │ │ - ows: "http://www.opengis.net/ows", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ - * {String} The default prefix (used by Format.XML). │ │ │ │ - */ │ │ │ │ - defaultPrefix: "csw", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} CSW version number. │ │ │ │ - */ │ │ │ │ - version: "2.0.2", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} http://www.opengis.net/cat/csw/2.0.2 │ │ │ │ - * http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd │ │ │ │ - */ │ │ │ │ - schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: requestId │ │ │ │ - * {String} Value of the requestId attribute of the GetRecords element. │ │ │ │ - */ │ │ │ │ - requestId: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: resultType │ │ │ │ - * {String} Value of the resultType attribute of the GetRecords element, │ │ │ │ - * specifies the result type in the GetRecords response, "hits" is │ │ │ │ - * the default. │ │ │ │ - */ │ │ │ │ - resultType: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: outputFormat │ │ │ │ - * {String} Value of the outputFormat attribute of the GetRecords element, │ │ │ │ - * specifies the format of the GetRecords response, │ │ │ │ - * "application/xml" is the default. │ │ │ │ - */ │ │ │ │ - outputFormat: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: outputSchema │ │ │ │ - * {String} Value of the outputSchema attribute of the GetRecords element, │ │ │ │ - * specifies the schema of the GetRecords response. │ │ │ │ - */ │ │ │ │ - outputSchema: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: startPosition │ │ │ │ - * {String} Value of the startPosition attribute of the GetRecords element, │ │ │ │ - * specifies the start position (offset+1) for the GetRecords response, │ │ │ │ - * 1 is the default. │ │ │ │ - */ │ │ │ │ - startPosition: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: maxRecords │ │ │ │ - * {String} Value of the maxRecords attribute of the GetRecords element, │ │ │ │ - * specifies the maximum number of records in the GetRecords response, │ │ │ │ - * 10 is the default. │ │ │ │ - */ │ │ │ │ - maxRecords: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: DistributedSearch │ │ │ │ - * {String} Value of the csw:DistributedSearch element, used when writing │ │ │ │ - * a csw:GetRecords document. │ │ │ │ - */ │ │ │ │ - DistributedSearch: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: ResponseHandler │ │ │ │ - * {Array({String})} Values of the csw:ResponseHandler elements, used when │ │ │ │ - * writting a csw:GetRecords document. │ │ │ │ - */ │ │ │ │ - ResponseHandler: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: Query │ │ │ │ - * {String} Value of the csw:Query element, used when writing a csw:GetRecords │ │ │ │ - * document. │ │ │ │ - */ │ │ │ │ - Query: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ - */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.CSWGetRecords.v2_0_2 │ │ │ │ - * A class for parsing and generating CSWGetRecords v2.0.2 transactions. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ - * │ │ │ │ - * Valid options properties (documented as class properties): │ │ │ │ - * - requestId │ │ │ │ - * - resultType │ │ │ │ - * - outputFormat │ │ │ │ - * - outputSchema │ │ │ │ - * - startPosition │ │ │ │ - * - maxRecords │ │ │ │ - * - DistributedSearch │ │ │ │ - * - ResponseHandler │ │ │ │ - * - Query │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Parse the response from a GetRecords request. │ │ │ │ - */ │ │ │ │ - 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 obj = {}; │ │ │ │ - this.readNode(data, obj); │ │ │ │ - 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: { │ │ │ │ - "csw": { │ │ │ │ - "GetRecordsResponse": function(node, obj) { │ │ │ │ - obj.records = []; │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - var version = this.getAttributeNS(node, "", 'version'); │ │ │ │ - if (version != "") { │ │ │ │ - obj.version = version; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "RequestId": function(node, obj) { │ │ │ │ - obj.RequestId = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "SearchStatus": function(node, obj) { │ │ │ │ - obj.SearchStatus = {}; │ │ │ │ - var timestamp = this.getAttributeNS(node, "", 'timestamp'); │ │ │ │ - if (timestamp != "") { │ │ │ │ - obj.SearchStatus.timestamp = timestamp; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "SearchResults": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var SearchResults = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - if ((attrs[i].name == "numberOfRecordsMatched") || │ │ │ │ - (attrs[i].name == "numberOfRecordsReturned") || │ │ │ │ - (attrs[i].name == "nextRecord")) { │ │ │ │ - SearchResults[attrs[i].name] = parseInt(attrs[i].nodeValue); │ │ │ │ - } else { │ │ │ │ - SearchResults[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - obj.SearchResults = SearchResults; │ │ │ │ - }, │ │ │ │ - "SummaryRecord": function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "SummaryRecord" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record); │ │ │ │ - }, │ │ │ │ - "BriefRecord": function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "BriefRecord" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record); │ │ │ │ - }, │ │ │ │ - "DCMIRecord": function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "DCMIRecord" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record); │ │ │ │ - }, │ │ │ │ - "Record": function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "Record" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record); │ │ │ │ - }, │ │ │ │ - "*": function(node, obj) { │ │ │ │ - var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ - obj[name] = this.getChildValue(node); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "geonet": { │ │ │ │ - "info": function(node, obj) { │ │ │ │ - var gninfo = {}; │ │ │ │ - this.readChildNodes(node, gninfo); │ │ │ │ - obj.gninfo = gninfo; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "dc": { │ │ │ │ - // audience, contributor, coverage, creator, date, description, format, │ │ │ │ - // identifier, language, provenance, publisher, relation, rights, │ │ │ │ - // rightsHolder, source, subject, title, type, URI │ │ │ │ - "*": function(node, obj) { │ │ │ │ - var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ - if (!(OpenLayers.Util.isArray(obj[name]))) { │ │ │ │ - obj[name] = []; │ │ │ │ - } │ │ │ │ - var dc_element = {}; │ │ │ │ - var attrs = node.attributes; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - dc_element[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ - } │ │ │ │ - dc_element.value = this.getChildValue(node); │ │ │ │ - if (dc_element.value != "") { │ │ │ │ - obj[name].push(dc_element); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "dct": { │ │ │ │ - // abstract, modified, spatial │ │ │ │ - "*": function(node, obj) { │ │ │ │ - var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ - if (!(OpenLayers.Util.isArray(obj[name]))) { │ │ │ │ - obj[name] = []; │ │ │ │ - } │ │ │ │ - obj[name].push(this.getChildValue(node)); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "ows": OpenLayers.Util.applyDefaults({ │ │ │ │ - "BoundingBox": function(node, obj) { │ │ │ │ - if (obj.bounds) { │ │ │ │ - obj.BoundingBox = [{ │ │ │ │ - crs: obj.projection, │ │ │ │ - value: [ │ │ │ │ - obj.bounds.left, │ │ │ │ - obj.bounds.bottom, │ │ │ │ - obj.bounds.right, │ │ │ │ - obj.bounds.top │ │ │ │ - ] │ │ │ │ - }]; │ │ │ │ - delete obj.projection; │ │ │ │ - delete obj.bounds; │ │ │ │ - } │ │ │ │ - OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]["BoundingBox"].apply( │ │ │ │ - this, arguments); │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: write │ │ │ │ - * Given an configuration js object, write a CSWGetRecords request. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} A object mapping the request. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A serialized CSWGetRecords request. │ │ │ │ - */ │ │ │ │ - write: function(options) { │ │ │ │ - var node = this.writeNode("csw:GetRecords", options); │ │ │ │ - node.setAttribute("xmlns:gmd", this.namespaces.gmd); │ │ │ │ - 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: { │ │ │ │ - "csw": { │ │ │ │ - "GetRecords": function(options) { │ │ │ │ - if (!options) { │ │ │ │ - options = {}; │ │ │ │ - } │ │ │ │ - var node = this.createElementNSPlus("csw:GetRecords", { │ │ │ │ - attributes: { │ │ │ │ - service: "CSW", │ │ │ │ - version: this.version, │ │ │ │ - requestId: options.requestId || this.requestId, │ │ │ │ - resultType: options.resultType || this.resultType, │ │ │ │ - outputFormat: options.outputFormat || this.outputFormat, │ │ │ │ - outputSchema: options.outputSchema || this.outputSchema, │ │ │ │ - startPosition: options.startPosition || this.startPosition, │ │ │ │ - maxRecords: options.maxRecords || this.maxRecords │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (options.DistributedSearch || this.DistributedSearch) { │ │ │ │ - this.writeNode( │ │ │ │ - "csw:DistributedSearch", │ │ │ │ - options.DistributedSearch || this.DistributedSearch, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - var ResponseHandler = options.ResponseHandler || this.ResponseHandler; │ │ │ │ - if (OpenLayers.Util.isArray(ResponseHandler) && ResponseHandler.length > 0) { │ │ │ │ - // ResponseHandler must be a non-empty array │ │ │ │ - for (var i = 0, len = ResponseHandler.length; i < len; i++) { │ │ │ │ - this.writeNode( │ │ │ │ - "csw:ResponseHandler", │ │ │ │ - ResponseHandler[i], │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.writeNode("Query", options.Query || this.Query, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "DistributedSearch": function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:DistributedSearch", { │ │ │ │ - attributes: { │ │ │ │ - hopCount: options.hopCount │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ResponseHandler": function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:ResponseHandler", { │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Query": function(options) { │ │ │ │ - if (!options) { │ │ │ │ - options = {}; │ │ │ │ - } │ │ │ │ - var node = this.createElementNSPlus("csw:Query", { │ │ │ │ - attributes: { │ │ │ │ - typeNames: options.typeNames || "csw:Record" │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - var ElementName = options.ElementName; │ │ │ │ - if (OpenLayers.Util.isArray(ElementName) && ElementName.length > 0) { │ │ │ │ - // ElementName must be a non-empty array │ │ │ │ - for (var i = 0, len = ElementName.length; i < len; i++) { │ │ │ │ - this.writeNode( │ │ │ │ - "csw:ElementName", │ │ │ │ - ElementName[i], │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.writeNode( │ │ │ │ - "csw:ElementSetName", │ │ │ │ - options.ElementSetName || { │ │ │ │ - value: 'summary' │ │ │ │ - }, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (options.Constraint) { │ │ │ │ - this.writeNode( │ │ │ │ - "csw:Constraint", │ │ │ │ - options.Constraint, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - if (options.SortBy) { │ │ │ │ - this.writeNode( │ │ │ │ - "ogc:SortBy", │ │ │ │ - options.SortBy, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ElementName": function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:ElementName", { │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ElementSetName": function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:ElementSetName", { │ │ │ │ - attributes: { │ │ │ │ - typeNames: options.typeNames │ │ │ │ - }, │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Constraint": function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:Constraint", { │ │ │ │ - attributes: { │ │ │ │ - version: options.version │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (options.Filter) { │ │ │ │ - var format = new OpenLayers.Format.Filter({ │ │ │ │ - version: options.version │ │ │ │ - }); │ │ │ │ - node.appendChild(format.write(options.Filter)); │ │ │ │ - } else if (options.CqlText) { │ │ │ │ - var child = this.createElementNSPlus("CqlText", { │ │ │ │ - value: options.CqlText.value │ │ │ │ - }); │ │ │ │ - node.appendChild(child); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "ogc": OpenLayers.Format.Filter.v1_1_0.prototype.writers["ogc"] │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.CSWGetRecords.v2_0_2" │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/SLD/v1_0_0_GeoServer.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/SLD/v1_0_0.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.SLD/v1_0_0_GeoServer │ │ │ │ - * Read and write SLD version 1.0.0 with GeoServer-specific enhanced options. │ │ │ │ - * See http://svn.osgeo.org/geotools/trunk/modules/extension/xsd/xsd-sld/src/main/resources/org/geotools/sld/bindings/StyledLayerDescriptor.xsd │ │ │ │ - * for more information. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.SLD.v1_0_0> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.SLD.v1_0_0, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} The specific parser version. │ │ │ │ - */ │ │ │ │ - version: "1.0.0", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: profile │ │ │ │ - * {String} The specific profile │ │ │ │ - */ │ │ │ │ - profile: "GeoServer", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.SLD.v1_0_0_GeoServer │ │ │ │ - * Create a new parser for GeoServer-enhanced SLD version 1.0.0. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: OpenLayers.Util.applyDefaults({ │ │ │ │ - "sld": OpenLayers.Util.applyDefaults({ │ │ │ │ - "Priority": function(node, obj) { │ │ │ │ - var value = this.readers.ogc._expression.call(this, node); │ │ │ │ - if (value) { │ │ │ │ - obj.priority = value; │ │ │ │ - } │ │ │ │ + "phone": function(node, contactInfo) { │ │ │ │ + contactInfo.phone = {}; │ │ │ │ + this.readChildNodes(node, contactInfo.phone); │ │ │ │ }, │ │ │ │ - "VendorOption": function(node, obj) { │ │ │ │ - if (!obj.vendorOptions) { │ │ │ │ - obj.vendorOptions = {}; │ │ │ │ - } │ │ │ │ - obj.vendorOptions[node.getAttribute("name")] = this.getChildValue(node); │ │ │ │ + "voice": function(node, phone) { │ │ │ │ + phone.voice = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "TextSymbolizer": function(node, rule) { │ │ │ │ - OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld.TextSymbolizer.apply(this, arguments); │ │ │ │ - var symbolizer = this.multipleSymbolizers ? rule.symbolizers[rule.symbolizers.length - 1] : rule.symbolizer["Text"]; │ │ │ │ - if (symbolizer.graphic === undefined) { │ │ │ │ - symbolizer.graphic = false; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.readers["sld"]) │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.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: OpenLayers.Util.applyDefaults({ │ │ │ │ - "sld": OpenLayers.Util.applyDefaults({ │ │ │ │ - "Priority": function(priority) { │ │ │ │ - return this.writers.sld._OGCExpression.call( │ │ │ │ - this, "sld:Priority", priority │ │ │ │ - ); │ │ │ │ + "facsimile": function(node, phone) { │ │ │ │ + phone.facsimile = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "VendorOption": function(option) { │ │ │ │ - return this.createElementNSPlus("sld:VendorOption", { │ │ │ │ - attributes: { │ │ │ │ - name: option.name │ │ │ │ - }, │ │ │ │ - value: option.value │ │ │ │ - }); │ │ │ │ + "address": function(node, contactInfo) { │ │ │ │ + contactInfo.address = {}; │ │ │ │ + this.readChildNodes(node, contactInfo.address); │ │ │ │ }, │ │ │ │ - "TextSymbolizer": function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["TextSymbolizer"].apply(this, arguments); │ │ │ │ - if (symbolizer.graphic !== false && (symbolizer.externalGraphic || symbolizer.graphicName)) { │ │ │ │ - this.writeNode("Graphic", symbolizer, node); │ │ │ │ - } │ │ │ │ - if ("priority" in symbolizer) { │ │ │ │ - this.writeNode("Priority", symbolizer.priority, node); │ │ │ │ - } │ │ │ │ - return this.addVendorOptions(node, symbolizer); │ │ │ │ + "deliveryPoint": function(node, address) { │ │ │ │ + address.deliveryPoint = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "PointSymbolizer": function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["PointSymbolizer"].apply(this, arguments); │ │ │ │ - return this.addVendorOptions(node, symbolizer); │ │ │ │ + "city": function(node, address) { │ │ │ │ + address.city = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "LineSymbolizer": function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["LineSymbolizer"].apply(this, arguments); │ │ │ │ - return this.addVendorOptions(node, symbolizer); │ │ │ │ + "postalCode": function(node, address) { │ │ │ │ + address.postalCode = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "PolygonSymbolizer": function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["PolygonSymbolizer"].apply(this, arguments); │ │ │ │ - return this.addVendorOptions(node, symbolizer); │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.writers["sld"]) │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.writers), │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: addVendorOptions │ │ │ │ - * Add in the VendorOption tags and return the node again. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * node - {DOMElement} A DOM node. │ │ │ │ - * symbolizer - {Object} │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} A DOM node. │ │ │ │ - */ │ │ │ │ - addVendorOptions: function(node, symbolizer) { │ │ │ │ - var options = symbolizer.vendorOptions; │ │ │ │ - if (options) { │ │ │ │ - for (var key in symbolizer.vendorOptions) { │ │ │ │ - this.writeNode("VendorOption", { │ │ │ │ - name: key, │ │ │ │ - value: symbolizer.vendorOptions[key] │ │ │ │ - }, node); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0_GeoServer" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/CSWGetDomain/v2_0_2.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/CSWGetDomain.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.CSWGetDomain.v2_0_2 │ │ │ │ - * A format for creating CSWGetDomain v2.0.2 transactions. │ │ │ │ - * Create a new instance with the │ │ │ │ - * <OpenLayers.Format.CSWGetDomain.v2_0_2> constructor. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.CSWGetDomain.v2_0_2 = 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", │ │ │ │ - csw: "http://www.opengis.net/cat/csw/2.0.2" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ - * {String} The default prefix (used by Format.XML). │ │ │ │ - */ │ │ │ │ - defaultPrefix: "csw", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} CSW version number. │ │ │ │ - */ │ │ │ │ - version: "2.0.2", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} http://www.opengis.net/cat/csw/2.0.2 │ │ │ │ - * http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd │ │ │ │ - */ │ │ │ │ - schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: PropertyName │ │ │ │ - * {String} Value of the csw:PropertyName element, used when │ │ │ │ - * writing a GetDomain document. │ │ │ │ - */ │ │ │ │ - PropertyName: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: ParameterName │ │ │ │ - * {String} Value of the csw:ParameterName element, used when │ │ │ │ - * writing a GetDomain document. │ │ │ │ - */ │ │ │ │ - ParameterName: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.CSWGetDomain.v2_0_2 │ │ │ │ - * A class for parsing and generating CSWGetDomain v2.0.2 transactions. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ - * │ │ │ │ - * Valid options properties: │ │ │ │ - * - PropertyName │ │ │ │ - * - ParameterName │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Parse the response from a GetDomain request. │ │ │ │ - */ │ │ │ │ - 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 obj = {}; │ │ │ │ - this.readNode(data, obj); │ │ │ │ - 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: { │ │ │ │ - "csw": { │ │ │ │ - "GetDomainResponse": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "DomainValues": function(node, obj) { │ │ │ │ - if (!(OpenLayers.Util.isArray(obj.DomainValues))) { │ │ │ │ - obj.DomainValues = []; │ │ │ │ - } │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var domainValue = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - domainValue[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ - } │ │ │ │ - this.readChildNodes(node, domainValue); │ │ │ │ - obj.DomainValues.push(domainValue); │ │ │ │ - }, │ │ │ │ - "PropertyName": function(node, obj) { │ │ │ │ - obj.PropertyName = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ParameterName": function(node, obj) { │ │ │ │ - obj.ParameterName = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ListOfValues": function(node, obj) { │ │ │ │ - if (!(OpenLayers.Util.isArray(obj.ListOfValues))) { │ │ │ │ - obj.ListOfValues = []; │ │ │ │ - } │ │ │ │ - this.readChildNodes(node, obj.ListOfValues); │ │ │ │ - }, │ │ │ │ - "Value": function(node, obj) { │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var value = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - value[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ - } │ │ │ │ - value.value = this.getChildValue(node); │ │ │ │ - obj.push({ │ │ │ │ - Value: value │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "ConceptualScheme": function(node, obj) { │ │ │ │ - obj.ConceptualScheme = {}; │ │ │ │ - this.readChildNodes(node, obj.ConceptualScheme); │ │ │ │ - }, │ │ │ │ - "Name": function(node, obj) { │ │ │ │ - obj.Name = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Document": function(node, obj) { │ │ │ │ - obj.Document = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Authority": function(node, obj) { │ │ │ │ - obj.Authority = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "RangeOfValues": function(node, obj) { │ │ │ │ - obj.RangeOfValues = {}; │ │ │ │ - this.readChildNodes(node, obj.RangeOfValues); │ │ │ │ - }, │ │ │ │ - "MinValue": function(node, obj) { │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var value = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - value[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ - } │ │ │ │ - value.value = this.getChildValue(node); │ │ │ │ - obj.MinValue = value; │ │ │ │ - }, │ │ │ │ - "MaxValue": function(node, obj) { │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var value = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - value[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ - } │ │ │ │ - value.value = this.getChildValue(node); │ │ │ │ - obj.MaxValue = value; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + "country": function(node, address) { │ │ │ │ + address.country = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "electronicMailAddress": function(node, address) { │ │ │ │ + address.electronicMailAddress = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "fees": function(node, service) { │ │ │ │ + service.fees = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "accessConstraints": function(node, service) { │ │ │ │ + service.accessConstraints = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ContentMetadata": function(node, obj) { │ │ │ │ + obj.contentMetadata = []; │ │ │ │ + this.readChildNodes(node, obj.contentMetadata); │ │ │ │ + }, │ │ │ │ + "CoverageOfferingBrief": function(node, contentMetadata) { │ │ │ │ + var coverageOfferingBrief = {}; │ │ │ │ + this.readChildNodes(node, coverageOfferingBrief); │ │ │ │ + contentMetadata.push(coverageOfferingBrief); │ │ │ │ + }, │ │ │ │ + "name": function(node, coverageOfferingBrief) { │ │ │ │ + coverageOfferingBrief.name = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "label": function(node, coverageOfferingBrief) { │ │ │ │ + coverageOfferingBrief.label = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "lonLatEnvelope": function(node, coverageOfferingBrief) { │ │ │ │ + var nodeList = this.getElementsByTagNameNS(node, "http://www.opengis.net/gml", "pos"); │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: write │ │ │ │ - * Given an configuration js object, write a CSWGetDomain request. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} A object mapping the request. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {String} A serialized CSWGetDomain request. │ │ │ │ - */ │ │ │ │ - write: function(options) { │ │ │ │ - var node = this.writeNode("csw:GetDomain", options); │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [node]); │ │ │ │ - }, │ │ │ │ + // We expect two nodes here, to create the corners of a bounding box │ │ │ │ + if (nodeList.length == 2) { │ │ │ │ + var min = {}; │ │ │ │ + var max = {}; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "csw": { │ │ │ │ - "GetDomain": function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:GetDomain", { │ │ │ │ - attributes: { │ │ │ │ - service: "CSW", │ │ │ │ - version: this.version │ │ │ │ + OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[0], min]); │ │ │ │ + OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[1], max]); │ │ │ │ + │ │ │ │ + coverageOfferingBrief.lonLatEnvelope = {}; │ │ │ │ + coverageOfferingBrief.lonLatEnvelope.srsName = node.getAttribute("srsName"); │ │ │ │ + coverageOfferingBrief.lonLatEnvelope.min = min.points[0]; │ │ │ │ + coverageOfferingBrief.lonLatEnvelope.max = max.points[0]; │ │ │ │ } │ │ │ │ - }); │ │ │ │ - if (options.PropertyName || this.PropertyName) { │ │ │ │ - this.writeNode( │ │ │ │ - "csw:PropertyName", │ │ │ │ - options.PropertyName || this.PropertyName, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ - } else if (options.ParameterName || this.ParameterName) { │ │ │ │ - this.writeNode( │ │ │ │ - "csw:ParameterName", │ │ │ │ - options.ParameterName || this.ParameterName, │ │ │ │ - node │ │ │ │ - ); │ │ │ │ } │ │ │ │ - this.readChildNodes(node, options); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "PropertyName": function(value) { │ │ │ │ - var node = this.createElementNSPlus("csw:PropertyName", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "ParameterName": function(value) { │ │ │ │ - var node = this.createElementNSPlus("csw:ParameterName", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - return node; │ │ │ │ } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.CSWGetDomain.v2_0_2" │ │ │ │ -}); │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_0_0" │ │ │ │ + │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WMTSCapabilities/v1_0_0.js │ │ │ │ + OpenLayers/Format/WCSCapabilities/v1_1_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/WMTSCapabilities.js │ │ │ │ + * @requires OpenLayers/Format/WCSCapabilities/v1.js │ │ │ │ * @requires OpenLayers/Format/OWSCommon/v1_1_0.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WMTSCapabilities.v1_0_0 │ │ │ │ - * Read WMTS Capabilities version 1.0.0. │ │ │ │ + * Class: OpenLayers.Format.WCSCapabilities/v1_1_0 │ │ │ │ + * Read WCS Capabilities version 1.1.0. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WMTSCapabilities> │ │ │ │ + * - <OpenLayers.Format.WCSCapabilities.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WMTSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.OWSCommon.v1_1_0, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} The parser version ("1.0.0"). │ │ │ │ - */ │ │ │ │ - version: "1.0.0", │ │ │ │ +OpenLayers.Format.WCSCapabilities.v1_1_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ │ │ │ │ /** │ │ │ │ * Property: namespaces │ │ │ │ * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ namespaces: { │ │ │ │ - ows: "http://www.opengis.net/ows/1.1", │ │ │ │ - wmts: "http://www.opengis.net/wmts/1.0", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink" │ │ │ │ + wcs: "http://www.opengis.net/wcs/1.1", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ + ows: "http://www.opengis.net/ows/1.1" │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: yx │ │ │ │ - * {Object} Members in the yx object are used to determine if a CRS URN │ │ │ │ - * corresponds to a CRS with y,x axis order. Member names are CRS URNs │ │ │ │ - * and values are boolean. Defaults come from the │ │ │ │ - * <OpenLayers.Format.WMTSCapabilities> prototype. │ │ │ │ - */ │ │ │ │ - yx: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ - * {String} The default namespace alias for creating element nodes. │ │ │ │ + * APIProperty: errorProperty │ │ │ │ + * {String} Which property of the returned object to check for in order to │ │ │ │ + * determine whether or not parsing has failed. In the case that the │ │ │ │ + * errorProperty is undefined on the returned object, the document will be │ │ │ │ + * run through an OGCExceptionReport parser. │ │ │ │ */ │ │ │ │ - defaultPrefix: "wmts", │ │ │ │ + errorProperty: "operationsMetadata", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WMTSCapabilities.v1_0_0 │ │ │ │ - * Create a new parser for WMTS capabilities version 1.0.0. │ │ │ │ + * Constructor: OpenLayers.Format.WCSCapabilities.v1_1_0 │ │ │ │ + * Create a new parser for WCS capabilities version 1.1.0. │ │ │ │ * │ │ │ │ * 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]); │ │ │ │ - this.options = options; │ │ │ │ - var yx = OpenLayers.Util.extend({}, OpenLayers.Format.WMTSCapabilities.prototype.yx); │ │ │ │ - this.yx = OpenLayers.Util.extend(yx, this.yx); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return info about the WMTS. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} Information about the SOS service. │ │ │ │ - */ │ │ │ │ - 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 capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - capabilities.version = this.version; │ │ │ │ - return capabilities; │ │ │ │ - }, │ │ │ │ │ │ │ │ /** │ │ │ │ * 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: { │ │ │ │ - "wmts": { │ │ │ │ + "wcs": OpenLayers.Util.applyDefaults({ │ │ │ │ + // In 1.0.0, this was WCS_Capabilties, in 1.1.0, it's Capabilities │ │ │ │ "Capabilities": function(node, obj) { │ │ │ │ this.readChildNodes(node, obj); │ │ │ │ }, │ │ │ │ - "Contents": function(node, obj) { │ │ │ │ - obj.contents = {}; │ │ │ │ - obj.contents.layers = []; │ │ │ │ - obj.contents.tileMatrixSets = {}; │ │ │ │ - this.readChildNodes(node, obj.contents); │ │ │ │ - }, │ │ │ │ - "Layer": function(node, obj) { │ │ │ │ - var layer = { │ │ │ │ - styles: [], │ │ │ │ - formats: [], │ │ │ │ - dimensions: [], │ │ │ │ - tileMatrixSetLinks: [] │ │ │ │ - }; │ │ │ │ - layer.layers = []; │ │ │ │ - this.readChildNodes(node, layer); │ │ │ │ - obj.layers.push(layer); │ │ │ │ - }, │ │ │ │ - "Style": function(node, obj) { │ │ │ │ - var style = {}; │ │ │ │ - style.isDefault = (node.getAttribute("isDefault") === "true"); │ │ │ │ - this.readChildNodes(node, style); │ │ │ │ - obj.styles.push(style); │ │ │ │ - }, │ │ │ │ - "Format": function(node, obj) { │ │ │ │ - obj.formats.push(this.getChildValue(node)); │ │ │ │ + "Contents": function(node, request) { │ │ │ │ + request.contentMetadata = []; │ │ │ │ + this.readChildNodes(node, request.contentMetadata); │ │ │ │ }, │ │ │ │ - "TileMatrixSetLink": function(node, obj) { │ │ │ │ - var tileMatrixSetLink = {}; │ │ │ │ - this.readChildNodes(node, tileMatrixSetLink); │ │ │ │ - obj.tileMatrixSetLinks.push(tileMatrixSetLink); │ │ │ │ + "CoverageSummary": function(node, contentMetadata) { │ │ │ │ + var coverageSummary = {}; │ │ │ │ + // Read the summary: │ │ │ │ + this.readChildNodes(node, coverageSummary); │ │ │ │ + │ │ │ │ + // Add it to the contentMetadata array: │ │ │ │ + contentMetadata.push(coverageSummary); │ │ │ │ }, │ │ │ │ - "TileMatrixSet": function(node, obj) { │ │ │ │ - // node could be child of wmts:Contents or wmts:TileMatrixSetLink │ │ │ │ - // duck type wmts:Contents by looking for layers │ │ │ │ - if (obj.layers) { │ │ │ │ - // TileMatrixSet as object type in schema │ │ │ │ - var tileMatrixSet = { │ │ │ │ - matrixIds: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, tileMatrixSet); │ │ │ │ - obj.tileMatrixSets[tileMatrixSet.identifier] = tileMatrixSet; │ │ │ │ - } else { │ │ │ │ - // TileMatrixSet as string type in schema │ │ │ │ - obj.tileMatrixSet = this.getChildValue(node); │ │ │ │ - } │ │ │ │ + "Identifier": function(node, coverageSummary) { │ │ │ │ + coverageSummary.identifier = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "TileMatrix": function(node, obj) { │ │ │ │ - var tileMatrix = { │ │ │ │ - supportedCRS: obj.supportedCRS │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, tileMatrix); │ │ │ │ - obj.matrixIds.push(tileMatrix); │ │ │ │ + "Title": function(node, coverageSummary) { │ │ │ │ + coverageSummary.title = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "ScaleDenominator": function(node, obj) { │ │ │ │ - obj.scaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ + "Abstract": function(node, coverageSummary) { │ │ │ │ + coverageSummary["abstract"] = this.getChildValue(node); │ │ │ │ }, │ │ │ │ - "TopLeftCorner": function(node, obj) { │ │ │ │ - var topLeftCorner = this.getChildValue(node); │ │ │ │ - var coords = topLeftCorner.split(" "); │ │ │ │ - // decide on axis order for the given CRS │ │ │ │ - var yx; │ │ │ │ - if (obj.supportedCRS) { │ │ │ │ - // extract out version from URN │ │ │ │ - var crs = obj.supportedCRS.replace( │ │ │ │ - /urn:ogc:def:crs:(\w+):.+:(\w+)$/, │ │ │ │ - "urn:ogc:def:crs:$1::$2" │ │ │ │ - ); │ │ │ │ - yx = !!this.yx[crs]; │ │ │ │ - } │ │ │ │ - if (yx) { │ │ │ │ - obj.topLeftCorner = new OpenLayers.LonLat( │ │ │ │ - coords[1], coords[0] │ │ │ │ - ); │ │ │ │ - } else { │ │ │ │ - obj.topLeftCorner = new OpenLayers.LonLat( │ │ │ │ - coords[0], coords[1] │ │ │ │ - ); │ │ │ │ + "SupportedCRS": function(node, coverageSummary) { │ │ │ │ + var crs = this.getChildValue(node); │ │ │ │ + if (crs) { │ │ │ │ + if (!coverageSummary.supportedCRS) { │ │ │ │ + coverageSummary.supportedCRS = []; │ │ │ │ + } │ │ │ │ + coverageSummary.supportedCRS.push(crs); │ │ │ │ } │ │ │ │ }, │ │ │ │ - "TileWidth": function(node, obj) { │ │ │ │ - obj.tileWidth = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "TileHeight": function(node, obj) { │ │ │ │ - obj.tileHeight = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "MatrixWidth": function(node, obj) { │ │ │ │ - obj.matrixWidth = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "MatrixHeight": function(node, obj) { │ │ │ │ - obj.matrixHeight = parseInt(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "ResourceURL": function(node, obj) { │ │ │ │ - obj.resourceUrl = obj.resourceUrl || {}; │ │ │ │ - var resourceType = node.getAttribute("resourceType"); │ │ │ │ - if (!obj.resourceUrls) { │ │ │ │ - obj.resourceUrls = []; │ │ │ │ + "SupportedFormat": function(node, coverageSummary) { │ │ │ │ + var format = this.getChildValue(node); │ │ │ │ + if (format) { │ │ │ │ + if (!coverageSummary.supportedFormat) { │ │ │ │ + coverageSummary.supportedFormat = []; │ │ │ │ + } │ │ │ │ + coverageSummary.supportedFormat.push(format); │ │ │ │ } │ │ │ │ - var resourceUrl = obj.resourceUrl[resourceType] = { │ │ │ │ - format: node.getAttribute("format"), │ │ │ │ - template: node.getAttribute("template"), │ │ │ │ - resourceType: resourceType │ │ │ │ - }; │ │ │ │ - obj.resourceUrls.push(resourceUrl); │ │ │ │ - }, │ │ │ │ - // not used for now, can be added in the future though │ │ │ │ - /*"Themes": function(node, obj) { │ │ │ │ - obj.themes = []; │ │ │ │ - this.readChildNodes(node, obj.themes); │ │ │ │ - }, │ │ │ │ - "Theme": function(node, obj) { │ │ │ │ - var theme = {}; │ │ │ │ - this.readChildNodes(node, theme); │ │ │ │ - obj.push(theme); │ │ │ │ - },*/ │ │ │ │ - "WSDL": function(node, obj) { │ │ │ │ - obj.wsdl = {}; │ │ │ │ - obj.wsdl.href = node.getAttribute("xlink:href"); │ │ │ │ - // TODO: other attributes of <WSDL> element │ │ │ │ - }, │ │ │ │ - "ServiceMetadataURL": function(node, obj) { │ │ │ │ - obj.serviceMetadataUrl = {}; │ │ │ │ - obj.serviceMetadataUrl.href = node.getAttribute("xlink:href"); │ │ │ │ - // TODO: other attributes of <ServiceMetadataURL> element │ │ │ │ - }, │ │ │ │ - "LegendURL": function(node, obj) { │ │ │ │ - obj.legend = {}; │ │ │ │ - obj.legend.href = node.getAttribute("xlink:href"); │ │ │ │ - obj.legend.format = node.getAttribute("format"); │ │ │ │ - }, │ │ │ │ - "Dimension": function(node, obj) { │ │ │ │ - var dimension = { │ │ │ │ - values: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, dimension); │ │ │ │ - obj.dimensions.push(dimension); │ │ │ │ - }, │ │ │ │ - "Default": function(node, obj) { │ │ │ │ - obj["default"] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Value": function(node, obj) { │ │ │ │ - obj.values.push(this.getChildValue(node)); │ │ │ │ } │ │ │ │ - }, │ │ │ │ + }, OpenLayers.Format.WCSCapabilities.v1.prototype.readers["wcs"]), │ │ │ │ "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMTSCapabilities.v1_0_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_1_0" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Format/WMC/v1.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ @@ -87295,143 +90448,101 @@ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.WMC.v1" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WMC/v1_1_0.js │ │ │ │ + OpenLayers/Format/WMC/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/WMC/v1.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WMC.v1_1_0 │ │ │ │ - * Read and write WMC version 1.1.0. │ │ │ │ - * │ │ │ │ - * Differences between 1.1.0 and 1.0.0: │ │ │ │ - * - 1.1.0 Layers have optional sld:MinScaleDenominator and │ │ │ │ - * sld:MaxScaleDenominator │ │ │ │ + * Class: OpenLayers.Format.WMC.v1_0_0 │ │ │ │ + * Read and write WMC version 1.0.0. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Format.WMC.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WMC.v1_1_0 = OpenLayers.Class( │ │ │ │ +OpenLayers.Format.WMC.v1_0_0 = OpenLayers.Class( │ │ │ │ OpenLayers.Format.WMC.v1, { │ │ │ │ │ │ │ │ /** │ │ │ │ * Constant: VERSION │ │ │ │ - * {String} 1.1.0 │ │ │ │ + * {String} 1.0.0 │ │ │ │ */ │ │ │ │ - VERSION: "1.1.0", │ │ │ │ + VERSION: "1.0.0", │ │ │ │ │ │ │ │ /** │ │ │ │ * Property: schemaLocation │ │ │ │ * {String} http://www.opengis.net/context │ │ │ │ - * http://schemas.opengis.net/context/1.1.0/context.xsd │ │ │ │ + * http://schemas.opengis.net/context/1.0.0/context.xsd │ │ │ │ */ │ │ │ │ - schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.1.0/context.xsd", │ │ │ │ + schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.0.0/context.xsd", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WMC.v1_1_0 │ │ │ │ + * Constructor: OpenLayers.Format.WMC.v1_0_0 │ │ │ │ * Instances of this class are not created directly. Use the │ │ │ │ * <OpenLayers.Format.WMC> constructor instead. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be set on │ │ │ │ * this instance. │ │ │ │ */ │ │ │ │ initialize: function(options) { │ │ │ │ OpenLayers.Format.WMC.v1.prototype.initialize.apply( │ │ │ │ this, [options] │ │ │ │ ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ - * Method: read_sld_MinScaleDenominator │ │ │ │ - * Read a sld:MinScaleDenominator node. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layerContext - {Object} An object representing a layer. │ │ │ │ - * node - {Element} An element node. │ │ │ │ - */ │ │ │ │ - read_sld_MinScaleDenominator: function(layerContext, node) { │ │ │ │ - var minScaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ - if (minScaleDenominator > 0) { │ │ │ │ - layerContext.maxScale = minScaleDenominator; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: read_sld_MaxScaleDenominator │ │ │ │ - * Read a sld:MaxScaleDenominator node. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * layerContext - {Object} An object representing a layer. │ │ │ │ - * node - {Element} An element node. │ │ │ │ - */ │ │ │ │ - read_sld_MaxScaleDenominator: function(layerContext, node) { │ │ │ │ - layerContext.minScale = parseFloat(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ * Method: read_wmc_SRS │ │ │ │ */ │ │ │ │ read_wmc_SRS: function(layerContext, node) { │ │ │ │ - if (!("srs" in layerContext)) { │ │ │ │ - layerContext.srs = {}; │ │ │ │ + var srs = this.getChildValue(node); │ │ │ │ + if (typeof layerContext.projections != "object") { │ │ │ │ + layerContext.projections = {}; │ │ │ │ + } │ │ │ │ + var values = srs.split(/ +/); │ │ │ │ + for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ + layerContext.projections[values[i]] = true; │ │ │ │ } │ │ │ │ - layerContext.srs[this.getChildValue(node)] = true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * Method: write_wmc_Layer │ │ │ │ * Create a Layer node given a layer context object. This method adds │ │ │ │ - * elements specific to version 1.1.0. │ │ │ │ + * elements specific to version 1.0.0. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * context - {Object} A layer context object.} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ * {Element} A WMC Layer element node. │ │ │ │ */ │ │ │ │ write_wmc_Layer: function(context) { │ │ │ │ var node = OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply( │ │ │ │ this, [context] │ │ │ │ ); │ │ │ │ │ │ │ │ - // min/max scale denominator elements go before the 4th element in v1 │ │ │ │ - if (context.maxScale) { │ │ │ │ - var minSD = this.createElementNS( │ │ │ │ - this.namespaces.sld, "sld:MinScaleDenominator" │ │ │ │ - ); │ │ │ │ - minSD.appendChild(this.createTextNode(context.maxScale.toPrecision(16))); │ │ │ │ - node.appendChild(minSD); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (context.minScale) { │ │ │ │ - var maxSD = this.createElementNS( │ │ │ │ - this.namespaces.sld, "sld:MaxScaleDenominator" │ │ │ │ - ); │ │ │ │ - maxSD.appendChild(this.createTextNode(context.minScale.toPrecision(16))); │ │ │ │ - node.appendChild(maxSD); │ │ │ │ - } │ │ │ │ - │ │ │ │ // optional SRS element(s) │ │ │ │ if (context.srs) { │ │ │ │ + var projections = []; │ │ │ │ for (var name in context.srs) { │ │ │ │ - node.appendChild(this.createElementDefaultNS("SRS", name)); │ │ │ │ + projections.push(name); │ │ │ │ } │ │ │ │ + node.appendChild(this.createElementDefaultNS("SRS", projections.join(" "))); │ │ │ │ } │ │ │ │ │ │ │ │ // optional FormatList element │ │ │ │ node.appendChild(this.write_wmc_FormatList(context)); │ │ │ │ │ │ │ │ // optional StyleList element │ │ │ │ node.appendChild(this.write_wmc_StyleList(context)); │ │ │ │ @@ -87439,110 +90550,149 @@ │ │ │ │ // optional DimensionList element │ │ │ │ if (context.dimensions) { │ │ │ │ node.appendChild(this.write_wmc_DimensionList(context)); │ │ │ │ } │ │ │ │ │ │ │ │ // OpenLayers specific properties go in an Extension element │ │ │ │ node.appendChild(this.write_wmc_LayerExtension(context)); │ │ │ │ - │ │ │ │ - return node; │ │ │ │ - │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMC.v1_1_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMC.v1_0_0" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/WMC/v1_0_0.js │ │ │ │ + OpenLayers/Format/WMC/v1_1_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/WMC/v1.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.WMC.v1_0_0 │ │ │ │ - * Read and write WMC version 1.0.0. │ │ │ │ + * Class: OpenLayers.Format.WMC.v1_1_0 │ │ │ │ + * Read and write WMC version 1.1.0. │ │ │ │ + * │ │ │ │ + * Differences between 1.1.0 and 1.0.0: │ │ │ │ + * - 1.1.0 Layers have optional sld:MinScaleDenominator and │ │ │ │ + * sld:MaxScaleDenominator │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Format.WMC.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.WMC.v1_0_0 = OpenLayers.Class( │ │ │ │ +OpenLayers.Format.WMC.v1_1_0 = OpenLayers.Class( │ │ │ │ OpenLayers.Format.WMC.v1, { │ │ │ │ │ │ │ │ /** │ │ │ │ * Constant: VERSION │ │ │ │ - * {String} 1.0.0 │ │ │ │ + * {String} 1.1.0 │ │ │ │ */ │ │ │ │ - VERSION: "1.0.0", │ │ │ │ + VERSION: "1.1.0", │ │ │ │ │ │ │ │ /** │ │ │ │ * Property: schemaLocation │ │ │ │ * {String} http://www.opengis.net/context │ │ │ │ - * http://schemas.opengis.net/context/1.0.0/context.xsd │ │ │ │ + * http://schemas.opengis.net/context/1.1.0/context.xsd │ │ │ │ */ │ │ │ │ - schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.0.0/context.xsd", │ │ │ │ + schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.1.0/context.xsd", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.WMC.v1_0_0 │ │ │ │ + * Constructor: OpenLayers.Format.WMC.v1_1_0 │ │ │ │ * Instances of this class are not created directly. Use the │ │ │ │ * <OpenLayers.Format.WMC> constructor instead. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be set on │ │ │ │ * this instance. │ │ │ │ */ │ │ │ │ initialize: function(options) { │ │ │ │ OpenLayers.Format.WMC.v1.prototype.initialize.apply( │ │ │ │ this, [options] │ │ │ │ ); │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ + * Method: read_sld_MinScaleDenominator │ │ │ │ + * Read a sld:MinScaleDenominator node. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layerContext - {Object} An object representing a layer. │ │ │ │ + * node - {Element} An element node. │ │ │ │ + */ │ │ │ │ + read_sld_MinScaleDenominator: function(layerContext, node) { │ │ │ │ + var minScaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ + if (minScaleDenominator > 0) { │ │ │ │ + layerContext.maxScale = minScaleDenominator; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: read_sld_MaxScaleDenominator │ │ │ │ + * Read a sld:MaxScaleDenominator node. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * layerContext - {Object} An object representing a layer. │ │ │ │ + * node - {Element} An element node. │ │ │ │ + */ │ │ │ │ + read_sld_MaxScaleDenominator: function(layerContext, node) { │ │ │ │ + layerContext.minScale = parseFloat(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ * Method: read_wmc_SRS │ │ │ │ */ │ │ │ │ read_wmc_SRS: function(layerContext, node) { │ │ │ │ - var srs = this.getChildValue(node); │ │ │ │ - if (typeof layerContext.projections != "object") { │ │ │ │ - layerContext.projections = {}; │ │ │ │ - } │ │ │ │ - var values = srs.split(/ +/); │ │ │ │ - for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ - layerContext.projections[values[i]] = true; │ │ │ │ + if (!("srs" in layerContext)) { │ │ │ │ + layerContext.srs = {}; │ │ │ │ } │ │ │ │ + layerContext.srs[this.getChildValue(node)] = true; │ │ │ │ }, │ │ │ │ │ │ │ │ /** │ │ │ │ * Method: write_wmc_Layer │ │ │ │ * Create a Layer node given a layer context object. This method adds │ │ │ │ - * elements specific to version 1.0.0. │ │ │ │ + * elements specific to version 1.1.0. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * context - {Object} A layer context object.} │ │ │ │ * │ │ │ │ * Returns: │ │ │ │ * {Element} A WMC Layer element node. │ │ │ │ */ │ │ │ │ write_wmc_Layer: function(context) { │ │ │ │ var node = OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply( │ │ │ │ this, [context] │ │ │ │ ); │ │ │ │ │ │ │ │ + // min/max scale denominator elements go before the 4th element in v1 │ │ │ │ + if (context.maxScale) { │ │ │ │ + var minSD = this.createElementNS( │ │ │ │ + this.namespaces.sld, "sld:MinScaleDenominator" │ │ │ │ + ); │ │ │ │ + minSD.appendChild(this.createTextNode(context.maxScale.toPrecision(16))); │ │ │ │ + node.appendChild(minSD); │ │ │ │ + } │ │ │ │ + │ │ │ │ + if (context.minScale) { │ │ │ │ + var maxSD = this.createElementNS( │ │ │ │ + this.namespaces.sld, "sld:MaxScaleDenominator" │ │ │ │ + ); │ │ │ │ + maxSD.appendChild(this.createTextNode(context.minScale.toPrecision(16))); │ │ │ │ + node.appendChild(maxSD); │ │ │ │ + } │ │ │ │ + │ │ │ │ // optional SRS element(s) │ │ │ │ if (context.srs) { │ │ │ │ - var projections = []; │ │ │ │ for (var name in context.srs) { │ │ │ │ - projections.push(name); │ │ │ │ + node.appendChild(this.createElementDefaultNS("SRS", name)); │ │ │ │ } │ │ │ │ - node.appendChild(this.createElementDefaultNS("SRS", projections.join(" "))); │ │ │ │ } │ │ │ │ │ │ │ │ // optional FormatList element │ │ │ │ node.appendChild(this.write_wmc_FormatList(context)); │ │ │ │ │ │ │ │ // optional StyleList element │ │ │ │ node.appendChild(this.write_wmc_StyleList(context)); │ │ │ │ @@ -87550,682 +90700,20 @@ │ │ │ │ // optional DimensionList element │ │ │ │ if (context.dimensions) { │ │ │ │ node.appendChild(this.write_wmc_DimensionList(context)); │ │ │ │ } │ │ │ │ │ │ │ │ // OpenLayers specific properties go in an Extension element │ │ │ │ node.appendChild(this.write_wmc_LayerExtension(context)); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMC.v1_0_0" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WCSCapabilities/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/WCSCapabilities.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WCSCapabilities.v1 │ │ │ │ - * Abstract class not to be instantiated directly. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WCSCapabilities.v1 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - splitSpace: (/\s+/) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ - */ │ │ │ │ - defaultPrefix: "wcs", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return a list of coverages. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} List of named coverages. │ │ │ │ - */ │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - } │ │ │ │ - var raw = data; │ │ │ │ - if (data && data.nodeType == 9) { │ │ │ │ - data = data.documentElement; │ │ │ │ - } │ │ │ │ - var capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - return capabilities; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WCSCapabilities/v1_1_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/WCSCapabilities/v1.js │ │ │ │ - * @requires OpenLayers/Format/OWSCommon/v1_1_0.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WCSCapabilities/v1_1_0 │ │ │ │ - * Read WCS Capabilities version 1.1.0. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WCSCapabilities.v1> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WCSCapabilities.v1_1_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - wcs: "http://www.opengis.net/wcs/1.1", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ - ows: "http://www.opengis.net/ows/1.1" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: errorProperty │ │ │ │ - * {String} Which property of the returned object to check for in order to │ │ │ │ - * determine whether or not parsing has failed. In the case that the │ │ │ │ - * errorProperty is undefined on the returned object, the document will be │ │ │ │ - * run through an OGCExceptionReport parser. │ │ │ │ - */ │ │ │ │ - errorProperty: "operationsMetadata", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WCSCapabilities.v1_1_0 │ │ │ │ - * Create a new parser for WCS capabilities version 1.1.0. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "wcs": OpenLayers.Util.applyDefaults({ │ │ │ │ - // In 1.0.0, this was WCS_Capabilties, in 1.1.0, it's Capabilities │ │ │ │ - "Capabilities": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "Contents": function(node, request) { │ │ │ │ - request.contentMetadata = []; │ │ │ │ - this.readChildNodes(node, request.contentMetadata); │ │ │ │ - }, │ │ │ │ - "CoverageSummary": function(node, contentMetadata) { │ │ │ │ - var coverageSummary = {}; │ │ │ │ - // Read the summary: │ │ │ │ - this.readChildNodes(node, coverageSummary); │ │ │ │ - │ │ │ │ - // Add it to the contentMetadata array: │ │ │ │ - contentMetadata.push(coverageSummary); │ │ │ │ - }, │ │ │ │ - "Identifier": function(node, coverageSummary) { │ │ │ │ - coverageSummary.identifier = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Title": function(node, coverageSummary) { │ │ │ │ - coverageSummary.title = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "Abstract": function(node, coverageSummary) { │ │ │ │ - coverageSummary["abstract"] = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "SupportedCRS": function(node, coverageSummary) { │ │ │ │ - var crs = this.getChildValue(node); │ │ │ │ - if (crs) { │ │ │ │ - if (!coverageSummary.supportedCRS) { │ │ │ │ - coverageSummary.supportedCRS = []; │ │ │ │ - } │ │ │ │ - coverageSummary.supportedCRS.push(crs); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "SupportedFormat": function(node, coverageSummary) { │ │ │ │ - var format = this.getChildValue(node); │ │ │ │ - if (format) { │ │ │ │ - if (!coverageSummary.supportedFormat) { │ │ │ │ - coverageSummary.supportedFormat = []; │ │ │ │ - } │ │ │ │ - coverageSummary.supportedFormat.push(format); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WCSCapabilities.v1.prototype.readers["wcs"]), │ │ │ │ - "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_1_0" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WCSCapabilities/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/WCSCapabilities/v1.js │ │ │ │ - * @requires OpenLayers/Format/GML/v3.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WCSCapabilities/v1_0_0 │ │ │ │ - * Read WCS Capabilities version 1.0.0. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WCSCapabilities.v1> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WCSCapabilities.v1_0_0 │ │ │ │ - * Create a new parser for WCS capabilities version 1.0.0. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - wcs: "http://www.opengis.net/wcs", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ - ows: "http://www.opengis.net/ows" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: errorProperty │ │ │ │ - * {String} Which property of the returned object to check for in order to │ │ │ │ - * determine whether or not parsing has failed. In the case that the │ │ │ │ - * errorProperty is undefined on the returned object, the document will be │ │ │ │ - * run through an OGCExceptionReport parser. │ │ │ │ - */ │ │ │ │ - errorProperty: "service", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "wcs": { │ │ │ │ - "WCS_Capabilities": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "Service": function(node, obj) { │ │ │ │ - obj.service = {}; │ │ │ │ - this.readChildNodes(node, obj.service); │ │ │ │ - }, │ │ │ │ - "name": function(node, service) { │ │ │ │ - service.name = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "label": function(node, service) { │ │ │ │ - service.label = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "keywords": function(node, service) { │ │ │ │ - service.keywords = []; │ │ │ │ - this.readChildNodes(node, service.keywords); │ │ │ │ - }, │ │ │ │ - "keyword": function(node, keywords) { │ │ │ │ - // Append the keyword to the keywords list │ │ │ │ - keywords.push(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "responsibleParty": function(node, service) { │ │ │ │ - service.responsibleParty = {}; │ │ │ │ - this.readChildNodes(node, service.responsibleParty); │ │ │ │ - }, │ │ │ │ - "individualName": function(node, responsibleParty) { │ │ │ │ - responsibleParty.individualName = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "organisationName": function(node, responsibleParty) { │ │ │ │ - responsibleParty.organisationName = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "positionName": function(node, responsibleParty) { │ │ │ │ - responsibleParty.positionName = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "contactInfo": function(node, responsibleParty) { │ │ │ │ - responsibleParty.contactInfo = {}; │ │ │ │ - this.readChildNodes(node, responsibleParty.contactInfo); │ │ │ │ - }, │ │ │ │ - "phone": function(node, contactInfo) { │ │ │ │ - contactInfo.phone = {}; │ │ │ │ - this.readChildNodes(node, contactInfo.phone); │ │ │ │ - }, │ │ │ │ - "voice": function(node, phone) { │ │ │ │ - phone.voice = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "facsimile": function(node, phone) { │ │ │ │ - phone.facsimile = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "address": function(node, contactInfo) { │ │ │ │ - contactInfo.address = {}; │ │ │ │ - this.readChildNodes(node, contactInfo.address); │ │ │ │ - }, │ │ │ │ - "deliveryPoint": function(node, address) { │ │ │ │ - address.deliveryPoint = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "city": function(node, address) { │ │ │ │ - address.city = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "postalCode": function(node, address) { │ │ │ │ - address.postalCode = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "country": function(node, address) { │ │ │ │ - address.country = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "electronicMailAddress": function(node, address) { │ │ │ │ - address.electronicMailAddress = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "fees": function(node, service) { │ │ │ │ - service.fees = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "accessConstraints": function(node, service) { │ │ │ │ - service.accessConstraints = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "ContentMetadata": function(node, obj) { │ │ │ │ - obj.contentMetadata = []; │ │ │ │ - this.readChildNodes(node, obj.contentMetadata); │ │ │ │ - }, │ │ │ │ - "CoverageOfferingBrief": function(node, contentMetadata) { │ │ │ │ - var coverageOfferingBrief = {}; │ │ │ │ - this.readChildNodes(node, coverageOfferingBrief); │ │ │ │ - contentMetadata.push(coverageOfferingBrief); │ │ │ │ - }, │ │ │ │ - "name": function(node, coverageOfferingBrief) { │ │ │ │ - coverageOfferingBrief.name = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "label": function(node, coverageOfferingBrief) { │ │ │ │ - coverageOfferingBrief.label = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "lonLatEnvelope": function(node, coverageOfferingBrief) { │ │ │ │ - var nodeList = this.getElementsByTagNameNS(node, "http://www.opengis.net/gml", "pos"); │ │ │ │ - │ │ │ │ - // We expect two nodes here, to create the corners of a bounding box │ │ │ │ - if (nodeList.length == 2) { │ │ │ │ - var min = {}; │ │ │ │ - var max = {}; │ │ │ │ - │ │ │ │ - OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[0], min]); │ │ │ │ - OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[1], max]); │ │ │ │ - │ │ │ │ - coverageOfferingBrief.lonLatEnvelope = {}; │ │ │ │ - coverageOfferingBrief.lonLatEnvelope.srsName = node.getAttribute("srsName"); │ │ │ │ - coverageOfferingBrief.lonLatEnvelope.min = min.points[0]; │ │ │ │ - coverageOfferingBrief.lonLatEnvelope.max = max.points[0]; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_0_0" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WFSCapabilities/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/WFSCapabilities.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WFSCapabilities.v1 │ │ │ │ - * Abstract class not to be instantiated directly. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XML> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WFSCapabilities.v1 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - wfs: "http://www.opengis.net/wfs", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ - ows: "http://www.opengis.net/ows" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: errorProperty │ │ │ │ - * {String} Which property of the returned object to check for in order to │ │ │ │ - * determine whether or not parsing has failed. In the case that the │ │ │ │ - * errorProperty is undefined on the returned object, the document will be │ │ │ │ - * run through an OGCExceptionReport parser. │ │ │ │ - */ │ │ │ │ - errorProperty: "featureTypeList", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: defaultPrefix │ │ │ │ - */ │ │ │ │ - defaultPrefix: "wfs", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WFSCapabilities.v1_1 │ │ │ │ - * Create an instance of one of the subclasses. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: read │ │ │ │ - * Read capabilities data from a string, and return a list of layers. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array} List of named layers. │ │ │ │ - */ │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - } │ │ │ │ - var raw = data; │ │ │ │ - if (data && data.nodeType == 9) { │ │ │ │ - data = data.documentElement; │ │ │ │ - } │ │ │ │ - var capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - return capabilities; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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": { │ │ │ │ - "WFS_Capabilities": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "FeatureTypeList": function(node, request) { │ │ │ │ - request.featureTypeList = { │ │ │ │ - featureTypes: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, request.featureTypeList); │ │ │ │ - }, │ │ │ │ - "FeatureType": function(node, featureTypeList) { │ │ │ │ - var featureType = {}; │ │ │ │ - this.readChildNodes(node, featureType); │ │ │ │ - featureTypeList.featureTypes.push(featureType); │ │ │ │ - }, │ │ │ │ - "Name": function(node, obj) { │ │ │ │ - var name = this.getChildValue(node); │ │ │ │ - if (name) { │ │ │ │ - var parts = name.split(":"); │ │ │ │ - obj.name = parts.pop(); │ │ │ │ - if (parts.length > 0) { │ │ │ │ - obj.featureNS = this.lookupNamespaceURI(node, parts[0]); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Title": function(node, obj) { │ │ │ │ - var title = this.getChildValue(node); │ │ │ │ - if (title) { │ │ │ │ - obj.title = title; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Abstract": function(node, obj) { │ │ │ │ - var abst = this.getChildValue(node); │ │ │ │ - if (abst) { │ │ │ │ - obj["abstract"] = abst; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WFSCapabilities/v1_1_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/WFSCapabilities/v1.js │ │ │ │ - * @requires OpenLayers/Format/OWSCommon/v1.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WFSCapabilities/v1_1_0 │ │ │ │ - * Read WFS Capabilities version 1.1.0. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WFSCapabilities> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WFSCapabilities.v1_1_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ - */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WFSCapabilities.v1_1_0 │ │ │ │ - * Create a new parser for WFS capabilities version 1.1.0. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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({ │ │ │ │ - "DefaultSRS": function(node, obj) { │ │ │ │ - var defaultSRS = this.getChildValue(node); │ │ │ │ - if (defaultSRS) { │ │ │ │ - obj.srs = defaultSRS; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]), │ │ │ │ - "ows": OpenLayers.Format.OWSCommon.v1.prototype.readers.ows │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_1_0" │ │ │ │ - │ │ │ │ - }); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Format/WFSCapabilities/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/WFSCapabilities/v1.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Class: OpenLayers.Format.WFSCapabilities/v1_0_0 │ │ │ │ - * Read WFS Capabilities version 1.0.0. │ │ │ │ - * │ │ │ │ - * Inherits from: │ │ │ │ - * - <OpenLayers.Format.WFSCapabilities.v1> │ │ │ │ - */ │ │ │ │ -OpenLayers.Format.WFSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.WFSCapabilities.v1_0_0 │ │ │ │ - * Create a new parser for WFS capabilities version 1.0.0. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ + return node; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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({ │ │ │ │ - "Service": function(node, capabilities) { │ │ │ │ - capabilities.service = {}; │ │ │ │ - this.readChildNodes(node, capabilities.service); │ │ │ │ - }, │ │ │ │ - "Fees": function(node, service) { │ │ │ │ - var fees = this.getChildValue(node); │ │ │ │ - if (fees && fees.toLowerCase() != "none") { │ │ │ │ - service.fees = fees; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "AccessConstraints": function(node, service) { │ │ │ │ - var constraints = this.getChildValue(node); │ │ │ │ - if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ - service.accessConstraints = constraints; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "OnlineResource": function(node, service) { │ │ │ │ - var onlineResource = this.getChildValue(node); │ │ │ │ - if (onlineResource && onlineResource.toLowerCase() != "none") { │ │ │ │ - service.onlineResource = onlineResource; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Keywords": function(node, service) { │ │ │ │ - var keywords = this.getChildValue(node); │ │ │ │ - if (keywords && keywords.toLowerCase() != "none") { │ │ │ │ - service.keywords = keywords.split(', '); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "Capability": function(node, capabilities) { │ │ │ │ - capabilities.capability = {}; │ │ │ │ - this.readChildNodes(node, capabilities.capability); │ │ │ │ - }, │ │ │ │ - "Request": function(node, obj) { │ │ │ │ - obj.request = {}; │ │ │ │ - this.readChildNodes(node, obj.request); │ │ │ │ - }, │ │ │ │ - "GetFeature": function(node, request) { │ │ │ │ - request.getfeature = { │ │ │ │ - href: {}, // DCPType │ │ │ │ - formats: [] // ResultFormat │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, request.getfeature); │ │ │ │ - }, │ │ │ │ - "ResultFormat": function(node, obj) { │ │ │ │ - var children = node.childNodes; │ │ │ │ - var childNode; │ │ │ │ - for (var i = 0; i < children.length; i++) { │ │ │ │ - childNode = children[i]; │ │ │ │ - if (childNode.nodeType == 1) { │ │ │ │ - obj.formats.push(childNode.nodeName); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - "DCPType": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - }, │ │ │ │ - "HTTP": function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj.href); │ │ │ │ - }, │ │ │ │ - "Get": function(node, obj) { │ │ │ │ - obj.get = node.getAttribute("onlineResource"); │ │ │ │ - }, │ │ │ │ - "Post": function(node, obj) { │ │ │ │ - obj.post = node.getAttribute("onlineResource"); │ │ │ │ - }, │ │ │ │ - "SRS": function(node, obj) { │ │ │ │ - var srs = this.getChildValue(node); │ │ │ │ - if (srs) { │ │ │ │ - obj.srs = srs; │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]) │ │ │ │ }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_0_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMC.v1_1_0" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Format/SOSCapabilities/v1_0_0.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ @@ -88383,14 +90871,623 @@ │ │ │ │ "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.SOSCapabilities.v1_0_0" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ + OpenLayers/Format/XLS/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/XLS.js │ │ │ │ + * @requires OpenLayers/Format/GML/v3.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.XLS.v1 │ │ │ │ + * Superclass for XLS version 1 parsers. Only supports GeocodeRequest for now. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.XLS.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + */ │ │ │ │ + namespaces: { │ │ │ │ + xls: "http://www.opengis.net/xls", │ │ │ │ + gml: "http://www.opengis.net/gml", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ + */ │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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: defaultPrefix │ │ │ │ + */ │ │ │ │ + defaultPrefix: "xls", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} Schema location for a particular minor version. │ │ │ │ + */ │ │ │ │ + schemaLocation: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.XLS.v1 │ │ │ │ + * Instances of this class are not created directly. Use the │ │ │ │ + * <OpenLayers.Format.XLS> constructor instead. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: read │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {DOMElement} An XLS document element. │ │ │ │ + * options - {Object} Options for the reader. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} An object representing the XLSResponse. │ │ │ │ + */ │ │ │ │ + read: function(data, options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ + var xls = {}; │ │ │ │ + this.readChildNodes(data, xls); │ │ │ │ + return xls; │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "xls": { │ │ │ │ + "XLS": function(node, xls) { │ │ │ │ + xls.version = node.getAttribute("version"); │ │ │ │ + this.readChildNodes(node, xls); │ │ │ │ + }, │ │ │ │ + "Response": function(node, xls) { │ │ │ │ + this.readChildNodes(node, xls); │ │ │ │ + }, │ │ │ │ + "GeocodeResponse": function(node, xls) { │ │ │ │ + xls.responseLists = []; │ │ │ │ + this.readChildNodes(node, xls); │ │ │ │ + }, │ │ │ │ + "GeocodeResponseList": function(node, xls) { │ │ │ │ + var responseList = { │ │ │ │ + features: [], │ │ │ │ + numberOfGeocodedAddresses: parseInt(node.getAttribute("numberOfGeocodedAddresses")) │ │ │ │ + }; │ │ │ │ + xls.responseLists.push(responseList); │ │ │ │ + this.readChildNodes(node, responseList); │ │ │ │ + }, │ │ │ │ + "GeocodedAddress": function(node, responseList) { │ │ │ │ + var feature = new OpenLayers.Feature.Vector(); │ │ │ │ + responseList.features.push(feature); │ │ │ │ + this.readChildNodes(node, feature); │ │ │ │ + // post-process geometry │ │ │ │ + feature.geometry = feature.components[0]; │ │ │ │ + }, │ │ │ │ + "GeocodeMatchCode": function(node, feature) { │ │ │ │ + feature.attributes.matchCode = { │ │ │ │ + accuracy: parseFloat(node.getAttribute("accuracy")), │ │ │ │ + matchType: node.getAttribute("matchType") │ │ │ │ + }; │ │ │ │ + }, │ │ │ │ + "Address": function(node, feature) { │ │ │ │ + var address = { │ │ │ │ + countryCode: node.getAttribute("countryCode"), │ │ │ │ + addressee: node.getAttribute("addressee"), │ │ │ │ + street: [], │ │ │ │ + place: [] │ │ │ │ + }; │ │ │ │ + feature.attributes.address = address; │ │ │ │ + this.readChildNodes(node, address); │ │ │ │ + }, │ │ │ │ + "freeFormAddress": function(node, address) { │ │ │ │ + address.freeFormAddress = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "StreetAddress": function(node, address) { │ │ │ │ + this.readChildNodes(node, address); │ │ │ │ + }, │ │ │ │ + "Building": function(node, address) { │ │ │ │ + address.building = { │ │ │ │ + 'number': node.getAttribute("number"), │ │ │ │ + subdivision: node.getAttribute("subdivision"), │ │ │ │ + buildingName: node.getAttribute("buildingName") │ │ │ │ + }; │ │ │ │ + }, │ │ │ │ + "Street": function(node, address) { │ │ │ │ + // only support the built-in primitive type for now │ │ │ │ + address.street.push(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "Place": function(node, address) { │ │ │ │ + // type is one of CountrySubdivision, │ │ │ │ + // CountrySecondarySubdivision, Municipality or │ │ │ │ + // MunicipalitySubdivision │ │ │ │ + address.place[node.getAttribute("type")] = │ │ │ │ + this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "PostalCode": function(node, address) { │ │ │ │ + address.postalCode = this.getChildValue(node); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "gml": OpenLayers.Format.GML.v3.prototype.readers.gml │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Method: write │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * request - {Object} An object representing the geocode request. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} The root of an XLS document. │ │ │ │ + */ │ │ │ │ + write: function(request) { │ │ │ │ + return this.writers.xls.XLS.apply(this, [request]); │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "xls": { │ │ │ │ + "XLS": function(request) { │ │ │ │ + var root = this.createElementNSPlus( │ │ │ │ + "xls:XLS", { │ │ │ │ + attributes: { │ │ │ │ + "version": this.VERSION, │ │ │ │ + "xsi:schemaLocation": this.schemaLocation │ │ │ │ + } │ │ │ │ + } │ │ │ │ + ); │ │ │ │ + this.writeNode("RequestHeader", request.header, root); │ │ │ │ + this.writeNode("Request", request, root); │ │ │ │ + return root; │ │ │ │ + }, │ │ │ │ + "RequestHeader": function(header) { │ │ │ │ + return this.createElementNSPlus("xls:RequestHeader"); │ │ │ │ + }, │ │ │ │ + "Request": function(request) { │ │ │ │ + var node = this.createElementNSPlus("xls:Request", { │ │ │ │ + attributes: { │ │ │ │ + methodName: "GeocodeRequest", │ │ │ │ + requestID: request.requestID || "", │ │ │ │ + version: this.VERSION │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.writeNode("GeocodeRequest", request.addresses, node); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "GeocodeRequest": function(addresses) { │ │ │ │ + var node = this.createElementNSPlus("xls:GeocodeRequest"); │ │ │ │ + for (var i = 0, len = addresses.length; i < len; i++) { │ │ │ │ + this.writeNode("Address", addresses[i], node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Address": function(address) { │ │ │ │ + var node = this.createElementNSPlus("xls:Address", { │ │ │ │ + attributes: { │ │ │ │ + countryCode: address.countryCode │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (address.freeFormAddress) { │ │ │ │ + this.writeNode("freeFormAddress", address.freeFormAddress, node); │ │ │ │ + } else { │ │ │ │ + if (address.street) { │ │ │ │ + this.writeNode("StreetAddress", address, node); │ │ │ │ + } │ │ │ │ + if (address.municipality) { │ │ │ │ + this.writeNode("Municipality", address.municipality, node); │ │ │ │ + } │ │ │ │ + if (address.countrySubdivision) { │ │ │ │ + this.writeNode("CountrySubdivision", address.countrySubdivision, node); │ │ │ │ + } │ │ │ │ + if (address.postalCode) { │ │ │ │ + this.writeNode("PostalCode", address.postalCode, node); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "freeFormAddress": function(freeFormAddress) { │ │ │ │ + return this.createElementNSPlus("freeFormAddress", { │ │ │ │ + value: freeFormAddress │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "StreetAddress": function(address) { │ │ │ │ + var node = this.createElementNSPlus("xls:StreetAddress"); │ │ │ │ + if (address.building) { │ │ │ │ + this.writeNode(node, "Building", address.building); │ │ │ │ + } │ │ │ │ + var street = address.street; │ │ │ │ + if (!(OpenLayers.Util.isArray(street))) { │ │ │ │ + street = [street]; │ │ │ │ + } │ │ │ │ + for (var i = 0, len = street.length; i < len; i++) { │ │ │ │ + this.writeNode("Street", street[i], node); │ │ │ │ + } │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "Building": function(building) { │ │ │ │ + return this.createElementNSPlus("xls:Building", { │ │ │ │ + attributes: { │ │ │ │ + "number": building["number"], │ │ │ │ + "subdivision": building.subdivision, │ │ │ │ + "buildingName": building.buildingName │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Street": function(street) { │ │ │ │ + return this.createElementNSPlus("xls:Street", { │ │ │ │ + value: street │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "Municipality": function(municipality) { │ │ │ │ + return this.createElementNSPlus("xls:Place", { │ │ │ │ + attributes: { │ │ │ │ + type: "Municipality" │ │ │ │ + }, │ │ │ │ + value: municipality │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "CountrySubdivision": function(countrySubdivision) { │ │ │ │ + return this.createElementNSPlus("xls:Place", { │ │ │ │ + attributes: { │ │ │ │ + type: "CountrySubdivision" │ │ │ │ + }, │ │ │ │ + value: countrySubdivision │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "PostalCode": function(postalCode) { │ │ │ │ + return this.createElementNSPlus("xls:PostalCode", { │ │ │ │ + value: postalCode │ │ │ │ + }); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.XLS.v1" │ │ │ │ + │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/XLS/v1_1_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/XLS/v1.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.XLS.v1_1_0 │ │ │ │ + * Read / write XLS version 1.1.0. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XLS.v1> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.XLS.v1_1_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.XLS.v1, { │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constant: VERSION │ │ │ │ + * {String} 1.1 │ │ │ │ + */ │ │ │ │ + VERSION: "1.1", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} http://www.opengis.net/xls │ │ │ │ + * http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd │ │ │ │ + */ │ │ │ │ + schemaLocation: "http://www.opengis.net/xls http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.XLS.v1_1_0 │ │ │ │ + * Instances of this class are not created directly. Use the │ │ │ │ + * <OpenLayers.Format.XLS> constructor instead. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.XLS.v1_1_0" │ │ │ │ + │ │ │ │ + }); │ │ │ │ + │ │ │ │ +// Support non standard implementation │ │ │ │ +OpenLayers.Format.XLS.v1_1 = OpenLayers.Format.XLS.v1_1_0; │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/CSWGetDomain/v2_0_2.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/CSWGetDomain.js │ │ │ │ + */ │ │ │ │ + │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.CSWGetDomain.v2_0_2 │ │ │ │ + * A format for creating CSWGetDomain v2.0.2 transactions. │ │ │ │ + * Create a new instance with the │ │ │ │ + * <OpenLayers.Format.CSWGetDomain.v2_0_2> constructor. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.CSWGetDomain.v2_0_2 = 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", │ │ │ │ + csw: "http://www.opengis.net/cat/csw/2.0.2" │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: defaultPrefix │ │ │ │ + * {String} The default prefix (used by Format.XML). │ │ │ │ + */ │ │ │ │ + defaultPrefix: "csw", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} CSW version number. │ │ │ │ + */ │ │ │ │ + version: "2.0.2", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Property: schemaLocation │ │ │ │ + * {String} http://www.opengis.net/cat/csw/2.0.2 │ │ │ │ + * http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd │ │ │ │ + */ │ │ │ │ + schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: PropertyName │ │ │ │ + * {String} Value of the csw:PropertyName element, used when │ │ │ │ + * writing a GetDomain document. │ │ │ │ + */ │ │ │ │ + PropertyName: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIProperty: ParameterName │ │ │ │ + * {String} Value of the csw:ParameterName element, used when │ │ │ │ + * writing a GetDomain document. │ │ │ │ + */ │ │ │ │ + ParameterName: null, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.CSWGetDomain.v2_0_2 │ │ │ │ + * A class for parsing and generating CSWGetDomain v2.0.2 transactions. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ + * instance. │ │ │ │ + * │ │ │ │ + * Valid options properties: │ │ │ │ + * - PropertyName │ │ │ │ + * - ParameterName │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Parse the response from a GetDomain request. │ │ │ │ + */ │ │ │ │ + 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 obj = {}; │ │ │ │ + this.readNode(data, obj); │ │ │ │ + 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: { │ │ │ │ + "csw": { │ │ │ │ + "GetDomainResponse": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "DomainValues": function(node, obj) { │ │ │ │ + if (!(OpenLayers.Util.isArray(obj.DomainValues))) { │ │ │ │ + obj.DomainValues = []; │ │ │ │ + } │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var domainValue = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + domainValue[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ + } │ │ │ │ + this.readChildNodes(node, domainValue); │ │ │ │ + obj.DomainValues.push(domainValue); │ │ │ │ + }, │ │ │ │ + "PropertyName": function(node, obj) { │ │ │ │ + obj.PropertyName = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ParameterName": function(node, obj) { │ │ │ │ + obj.ParameterName = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ListOfValues": function(node, obj) { │ │ │ │ + if (!(OpenLayers.Util.isArray(obj.ListOfValues))) { │ │ │ │ + obj.ListOfValues = []; │ │ │ │ + } │ │ │ │ + this.readChildNodes(node, obj.ListOfValues); │ │ │ │ + }, │ │ │ │ + "Value": function(node, obj) { │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var value = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + value[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ + } │ │ │ │ + value.value = this.getChildValue(node); │ │ │ │ + obj.push({ │ │ │ │ + Value: value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "ConceptualScheme": function(node, obj) { │ │ │ │ + obj.ConceptualScheme = {}; │ │ │ │ + this.readChildNodes(node, obj.ConceptualScheme); │ │ │ │ + }, │ │ │ │ + "Name": function(node, obj) { │ │ │ │ + obj.Name = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Document": function(node, obj) { │ │ │ │ + obj.Document = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Authority": function(node, obj) { │ │ │ │ + obj.Authority = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "RangeOfValues": function(node, obj) { │ │ │ │ + obj.RangeOfValues = {}; │ │ │ │ + this.readChildNodes(node, obj.RangeOfValues); │ │ │ │ + }, │ │ │ │ + "MinValue": function(node, obj) { │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var value = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + value[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ + } │ │ │ │ + value.value = this.getChildValue(node); │ │ │ │ + obj.MinValue = value; │ │ │ │ + }, │ │ │ │ + "MaxValue": function(node, obj) { │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var value = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + value[attrs[i].name] = attrs[i].nodeValue; │ │ │ │ + } │ │ │ │ + value.value = this.getChildValue(node); │ │ │ │ + obj.MaxValue = value; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * APIMethod: write │ │ │ │ + * Given an configuration js object, write a CSWGetDomain request. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} A object mapping the request. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {String} A serialized CSWGetDomain request. │ │ │ │ + */ │ │ │ │ + write: function(options) { │ │ │ │ + var node = this.writeNode("csw:GetDomain", options); │ │ │ │ + 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: { │ │ │ │ + "csw": { │ │ │ │ + "GetDomain": function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:GetDomain", { │ │ │ │ + attributes: { │ │ │ │ + service: "CSW", │ │ │ │ + version: this.version │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (options.PropertyName || this.PropertyName) { │ │ │ │ + this.writeNode( │ │ │ │ + "csw:PropertyName", │ │ │ │ + options.PropertyName || this.PropertyName, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } else if (options.ParameterName || this.ParameterName) { │ │ │ │ + this.writeNode( │ │ │ │ + "csw:ParameterName", │ │ │ │ + options.ParameterName || this.ParameterName, │ │ │ │ + node │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + this.readChildNodes(node, options); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "PropertyName": function(value) { │ │ │ │ + var node = this.createElementNSPlus("csw:PropertyName", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ + "ParameterName": function(value) { │ │ │ │ + var node = this.createElementNSPlus("csw:ParameterName", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + return node; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.CSWGetDomain.v2_0_2" │ │ │ │ +}); │ │ │ │ +/* ====================================================================== │ │ │ │ OpenLayers/Format/OWSContext/v0_3_1.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. */ │ │ │ │ @@ -89005,2598 +92102,1948 @@ │ │ │ │ "feature": OpenLayers.Format.GML.v2.prototype.writers.feature │ │ │ │ }, │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.OWSContext.v0_3_1" │ │ │ │ │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/XLS/v1.js │ │ │ │ + OpenLayers/Format/WPSCapabilities/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/XLS.js │ │ │ │ - * @requires OpenLayers/Format/GML/v3.js │ │ │ │ + * @requires OpenLayers/Format/WPSCapabilities.js │ │ │ │ + * @requires OpenLayers/Format/OWSCommon/v1_1_0.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.XLS.v1 │ │ │ │ - * Superclass for XLS version 1 parsers. Only supports GeocodeRequest for now. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.WPSCapabilities.v1_0_0 │ │ │ │ + * Read WPS Capabilities version 1.0.0. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.XLS.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: namespaces │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ - */ │ │ │ │ - namespaces: { │ │ │ │ - xls: "http://www.opengis.net/xls", │ │ │ │ - gml: "http://www.opengis.net/gml", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: regExes │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ - */ │ │ │ │ - regExes: { │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: defaultPrefix │ │ │ │ - */ │ │ │ │ - defaultPrefix: "xls", │ │ │ │ +OpenLayers.Format.WPSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} Schema location for a particular minor version. │ │ │ │ - */ │ │ │ │ - schemaLocation: null, │ │ │ │ + /** │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + */ │ │ │ │ + namespaces: { │ │ │ │ + ows: "http://www.opengis.net/ows/1.1", │ │ │ │ + wps: "http://www.opengis.net/wps/1.0.0", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink" │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Format.XLS.v1 │ │ │ │ - * Instances of this class are not created directly. Use the │ │ │ │ - * <OpenLayers.Format.XLS> constructor instead. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ - * this instance. │ │ │ │ - */ │ │ │ │ + /** │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ + */ │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: read │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {DOMElement} An XLS document element. │ │ │ │ - * options - {Object} Options for the reader. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} An object representing the XLSResponse. │ │ │ │ - */ │ │ │ │ - read: function(data, options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ - var xls = {}; │ │ │ │ - this.readChildNodes(data, xls); │ │ │ │ - return xls; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WPSCapabilities.v1_0_0 │ │ │ │ + * Create a new parser for WPS capabilities version 1.0.0. │ │ │ │ + * │ │ │ │ + * 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]); │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "xls": { │ │ │ │ - "XLS": function(node, xls) { │ │ │ │ - xls.version = node.getAttribute("version"); │ │ │ │ - this.readChildNodes(node, xls); │ │ │ │ - }, │ │ │ │ - "Response": function(node, xls) { │ │ │ │ - this.readChildNodes(node, xls); │ │ │ │ - }, │ │ │ │ - "GeocodeResponse": function(node, xls) { │ │ │ │ - xls.responseLists = []; │ │ │ │ - this.readChildNodes(node, xls); │ │ │ │ - }, │ │ │ │ - "GeocodeResponseList": function(node, xls) { │ │ │ │ - var responseList = { │ │ │ │ - features: [], │ │ │ │ - numberOfGeocodedAddresses: parseInt(node.getAttribute("numberOfGeocodedAddresses")) │ │ │ │ - }; │ │ │ │ - xls.responseLists.push(responseList); │ │ │ │ - this.readChildNodes(node, responseList); │ │ │ │ - }, │ │ │ │ - "GeocodedAddress": function(node, responseList) { │ │ │ │ - var feature = new OpenLayers.Feature.Vector(); │ │ │ │ - responseList.features.push(feature); │ │ │ │ - this.readChildNodes(node, feature); │ │ │ │ - // post-process geometry │ │ │ │ - feature.geometry = feature.components[0]; │ │ │ │ - }, │ │ │ │ - "GeocodeMatchCode": function(node, feature) { │ │ │ │ - feature.attributes.matchCode = { │ │ │ │ - accuracy: parseFloat(node.getAttribute("accuracy")), │ │ │ │ - matchType: node.getAttribute("matchType") │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ - "Address": function(node, feature) { │ │ │ │ - var address = { │ │ │ │ - countryCode: node.getAttribute("countryCode"), │ │ │ │ - addressee: node.getAttribute("addressee"), │ │ │ │ - street: [], │ │ │ │ - place: [] │ │ │ │ - }; │ │ │ │ - feature.attributes.address = address; │ │ │ │ - this.readChildNodes(node, address); │ │ │ │ - }, │ │ │ │ - "freeFormAddress": function(node, address) { │ │ │ │ - address.freeFormAddress = this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "StreetAddress": function(node, address) { │ │ │ │ - this.readChildNodes(node, address); │ │ │ │ - }, │ │ │ │ - "Building": function(node, address) { │ │ │ │ - address.building = { │ │ │ │ - 'number': node.getAttribute("number"), │ │ │ │ - subdivision: node.getAttribute("subdivision"), │ │ │ │ - buildingName: node.getAttribute("buildingName") │ │ │ │ - }; │ │ │ │ - }, │ │ │ │ - "Street": function(node, address) { │ │ │ │ - // only support the built-in primitive type for now │ │ │ │ - address.street.push(this.getChildValue(node)); │ │ │ │ - }, │ │ │ │ - "Place": function(node, address) { │ │ │ │ - // type is one of CountrySubdivision, │ │ │ │ - // CountrySecondarySubdivision, Municipality or │ │ │ │ - // MunicipalitySubdivision │ │ │ │ - address.place[node.getAttribute("type")] = │ │ │ │ - this.getChildValue(node); │ │ │ │ - }, │ │ │ │ - "PostalCode": function(node, address) { │ │ │ │ - address.postalCode = this.getChildValue(node); │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return info about the WPS. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} Information about the WPS service. │ │ │ │ + */ │ │ │ │ + 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 capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + return capabilities; │ │ │ │ }, │ │ │ │ - "gml": OpenLayers.Format.GML.v3.prototype.readers.gml │ │ │ │ - }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: write │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * request - {Object} An object representing the geocode request. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} The root of an XLS document. │ │ │ │ - */ │ │ │ │ - write: function(request) { │ │ │ │ - return this.writers.xls.XLS.apply(this, [request]); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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: { │ │ │ │ - "xls": { │ │ │ │ - "XLS": function(request) { │ │ │ │ - var root = this.createElementNSPlus( │ │ │ │ - "xls:XLS", { │ │ │ │ - attributes: { │ │ │ │ - "version": this.VERSION, │ │ │ │ - "xsi:schemaLocation": this.schemaLocation │ │ │ │ - } │ │ │ │ - } │ │ │ │ - ); │ │ │ │ - this.writeNode("RequestHeader", request.header, root); │ │ │ │ - this.writeNode("Request", request, root); │ │ │ │ - return root; │ │ │ │ - }, │ │ │ │ - "RequestHeader": function(header) { │ │ │ │ - return this.createElementNSPlus("xls:RequestHeader"); │ │ │ │ - }, │ │ │ │ - "Request": function(request) { │ │ │ │ - var node = this.createElementNSPlus("xls:Request", { │ │ │ │ - attributes: { │ │ │ │ - methodName: "GeocodeRequest", │ │ │ │ - requestID: request.requestID || "", │ │ │ │ - version: this.VERSION │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.writeNode("GeocodeRequest", request.addresses, node); │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "GeocodeRequest": function(addresses) { │ │ │ │ - var node = this.createElementNSPlus("xls:GeocodeRequest"); │ │ │ │ - for (var i = 0, len = addresses.length; i < len; i++) { │ │ │ │ - this.writeNode("Address", addresses[i], node); │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Address": function(address) { │ │ │ │ - var node = this.createElementNSPlus("xls:Address", { │ │ │ │ - attributes: { │ │ │ │ - countryCode: address.countryCode │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (address.freeFormAddress) { │ │ │ │ - this.writeNode("freeFormAddress", address.freeFormAddress, node); │ │ │ │ - } else { │ │ │ │ - if (address.street) { │ │ │ │ - this.writeNode("StreetAddress", address, node); │ │ │ │ - } │ │ │ │ - if (address.municipality) { │ │ │ │ - this.writeNode("Municipality", address.municipality, node); │ │ │ │ - } │ │ │ │ - if (address.countrySubdivision) { │ │ │ │ - this.writeNode("CountrySubdivision", address.countrySubdivision, node); │ │ │ │ - } │ │ │ │ - if (address.postalCode) { │ │ │ │ - this.writeNode("PostalCode", address.postalCode, node); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "freeFormAddress": function(freeFormAddress) { │ │ │ │ - return this.createElementNSPlus("freeFormAddress", { │ │ │ │ - value: freeFormAddress │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "StreetAddress": function(address) { │ │ │ │ - var node = this.createElementNSPlus("xls:StreetAddress"); │ │ │ │ - if (address.building) { │ │ │ │ - this.writeNode(node, "Building", address.building); │ │ │ │ - } │ │ │ │ - var street = address.street; │ │ │ │ - if (!(OpenLayers.Util.isArray(street))) { │ │ │ │ - street = [street]; │ │ │ │ - } │ │ │ │ - for (var i = 0, len = street.length; i < len; i++) { │ │ │ │ - this.writeNode("Street", street[i], node); │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wps": { │ │ │ │ + "Capabilities": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "ProcessOfferings": function(node, obj) { │ │ │ │ + obj.processOfferings = {}; │ │ │ │ + this.readChildNodes(node, obj.processOfferings); │ │ │ │ + }, │ │ │ │ + "Process": function(node, processOfferings) { │ │ │ │ + var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); │ │ │ │ + var process = { │ │ │ │ + processVersion: processVersion │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, process); │ │ │ │ + processOfferings[process.identifier] = process; │ │ │ │ + }, │ │ │ │ + "Languages": function(node, obj) { │ │ │ │ + obj.languages = []; │ │ │ │ + this.readChildNodes(node, obj.languages); │ │ │ │ + }, │ │ │ │ + "Default": function(node, languages) { │ │ │ │ + var language = { │ │ │ │ + isDefault: true │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, language); │ │ │ │ + languages.push(language); │ │ │ │ + }, │ │ │ │ + "Supported": function(node, languages) { │ │ │ │ + var language = {}; │ │ │ │ + this.readChildNodes(node, language); │ │ │ │ + languages.push(language); │ │ │ │ } │ │ │ │ - return node; │ │ │ │ - }, │ │ │ │ - "Building": function(building) { │ │ │ │ - return this.createElementNSPlus("xls:Building", { │ │ │ │ - attributes: { │ │ │ │ - "number": building["number"], │ │ │ │ - "subdivision": building.subdivision, │ │ │ │ - "buildingName": building.buildingName │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Street": function(street) { │ │ │ │ - return this.createElementNSPlus("xls:Street", { │ │ │ │ - value: street │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "Municipality": function(municipality) { │ │ │ │ - return this.createElementNSPlus("xls:Place", { │ │ │ │ - attributes: { │ │ │ │ - type: "Municipality" │ │ │ │ - }, │ │ │ │ - value: municipality │ │ │ │ - }); │ │ │ │ - }, │ │ │ │ - "CountrySubdivision": function(countrySubdivision) { │ │ │ │ - return this.createElementNSPlus("xls:Place", { │ │ │ │ - attributes: { │ │ │ │ - type: "CountrySubdivision" │ │ │ │ - }, │ │ │ │ - value: countrySubdivision │ │ │ │ - }); │ │ │ │ }, │ │ │ │ - "PostalCode": function(postalCode) { │ │ │ │ - return this.createElementNSPlus("xls:PostalCode", { │ │ │ │ - value: postalCode │ │ │ │ - }); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.XLS.v1" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WPSCapabilities.v1_0_0" │ │ │ │ │ │ │ │ -}); │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Format/XLS/v1_1_0.js │ │ │ │ + OpenLayers/Format/WFSCapabilities/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/XLS/v1.js │ │ │ │ + * @requires OpenLayers/Format/WFSCapabilities.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Format.XLS.v1_1_0 │ │ │ │ - * Read / write XLS version 1.1.0. │ │ │ │ + * Class: OpenLayers.Format.WFSCapabilities.v1 │ │ │ │ + * Abstract class not to be instantiated directly. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Format.XLS.v1> │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Format.XLS.v1_1_0 = OpenLayers.Class( │ │ │ │ - OpenLayers.Format.XLS.v1, { │ │ │ │ +OpenLayers.Format.WFSCapabilities.v1 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: VERSION │ │ │ │ - * {String} 1.1 │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ */ │ │ │ │ - VERSION: "1.1", │ │ │ │ + namespaces: { │ │ │ │ + wfs: "http://www.opengis.net/wfs", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ + ows: "http://www.opengis.net/ows" │ │ │ │ + }, │ │ │ │ + │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: schemaLocation │ │ │ │ - * {String} http://www.opengis.net/xls │ │ │ │ - * http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd │ │ │ │ + * APIProperty: errorProperty │ │ │ │ + * {String} Which property of the returned object to check for in order to │ │ │ │ + * determine whether or not parsing has failed. In the case that the │ │ │ │ + * errorProperty is undefined on the returned object, the document will be │ │ │ │ + * run through an OGCExceptionReport parser. │ │ │ │ */ │ │ │ │ - schemaLocation: "http://www.opengis.net/xls http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd", │ │ │ │ + errorProperty: "featureTypeList", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Format.XLS.v1_1_0 │ │ │ │ - * Instances of this class are not created directly. Use the │ │ │ │ - * <OpenLayers.Format.XLS> constructor instead. │ │ │ │ + * Property: defaultPrefix │ │ │ │ + */ │ │ │ │ + defaultPrefix: "wfs", │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WFSCapabilities.v1_1 │ │ │ │ + * Create an instance of one of the subclasses. │ │ │ │ * │ │ │ │ * Parameters: │ │ │ │ * options - {Object} An optional object whose properties will be set on │ │ │ │ * this instance. │ │ │ │ */ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.XLS.v1_1_0" │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return a list of layers. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array} List of named layers. │ │ │ │ + */ │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ + } │ │ │ │ + var raw = data; │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement; │ │ │ │ + } │ │ │ │ + var capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + return capabilities; │ │ │ │ + }, │ │ │ │ │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * 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": { │ │ │ │ + "WFS_Capabilities": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "FeatureTypeList": function(node, request) { │ │ │ │ + request.featureTypeList = { │ │ │ │ + featureTypes: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, request.featureTypeList); │ │ │ │ + }, │ │ │ │ + "FeatureType": function(node, featureTypeList) { │ │ │ │ + var featureType = {}; │ │ │ │ + this.readChildNodes(node, featureType); │ │ │ │ + featureTypeList.featureTypes.push(featureType); │ │ │ │ + }, │ │ │ │ + "Name": function(node, obj) { │ │ │ │ + var name = this.getChildValue(node); │ │ │ │ + if (name) { │ │ │ │ + var parts = name.split(":"); │ │ │ │ + obj.name = parts.pop(); │ │ │ │ + if (parts.length > 0) { │ │ │ │ + obj.featureNS = this.lookupNamespaceURI(node, parts[0]); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Title": function(node, obj) { │ │ │ │ + var title = this.getChildValue(node); │ │ │ │ + if (title) { │ │ │ │ + obj.title = title; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Abstract": function(node, obj) { │ │ │ │ + var abst = this.getChildValue(node); │ │ │ │ + if (abst) { │ │ │ │ + obj["abstract"] = abst; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ │ │ │ │ -// Support non standard implementation │ │ │ │ -OpenLayers.Format.XLS.v1_1 = OpenLayers.Format.XLS.v1_1_0; │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1" │ │ │ │ + │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Tile/Image/IFrame.js │ │ │ │ + OpenLayers/Format/WFSCapabilities/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/Tile/Image.js │ │ │ │ + * @requires OpenLayers/Format/WFSCapabilities/v1.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constant: OpenLayers.Tile.Image.IFrame │ │ │ │ - * Mixin for tiles that use form-encoded POST requests to get images from │ │ │ │ - * remote services. Images will be loaded using HTTP-POST into an IFrame. │ │ │ │ - * │ │ │ │ - * This mixin will be applied to <OpenLayers.Tile.Image> instances │ │ │ │ - * configured with <OpenLayers.Tile.Image.maxGetUrlLength> set. │ │ │ │ + * Class: OpenLayers.Format.WFSCapabilities/v1_0_0 │ │ │ │ + * Read WFS Capabilities version 1.0.0. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.WFSCapabilities.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Tile.Image.IFrame = { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: useIFrame │ │ │ │ - * {Boolean} true if we are currently using an IFrame to render POST │ │ │ │ - * responses, false if we are using an img element to render GET responses. │ │ │ │ - */ │ │ │ │ - useIFrame: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: blankImageUrl │ │ │ │ - * {String} Using a data scheme url is not supported by all browsers, but │ │ │ │ - * we don't care because we either set it as css backgroundImage, or the │ │ │ │ - * image's display style is set to "none" when we use it. │ │ │ │ - */ │ │ │ │ - blankImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: draw │ │ │ │ - * Set useIFrame in the instance, and operate the image/iframe switch. │ │ │ │ - * Then call Tile.Image.draw. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Boolean} │ │ │ │ - */ │ │ │ │ - draw: function() { │ │ │ │ - var draw = OpenLayers.Tile.Image.prototype.shouldDraw.call(this); │ │ │ │ - if (draw) { │ │ │ │ - │ │ │ │ - // this.url isn't set to the currect value yet, so we call getURL │ │ │ │ - // on the layer and store the result in a local variable │ │ │ │ - var url = this.layer.getURL(this.bounds); │ │ │ │ - │ │ │ │ - var usedIFrame = this.useIFrame; │ │ │ │ - this.useIFrame = this.maxGetUrlLength !== null && │ │ │ │ - !this.layer.async && │ │ │ │ - url.length > this.maxGetUrlLength; │ │ │ │ - │ │ │ │ - var fromIFrame = usedIFrame && !this.useIFrame; │ │ │ │ - var toIFrame = !usedIFrame && this.useIFrame; │ │ │ │ - │ │ │ │ - if (fromIFrame || toIFrame) { │ │ │ │ - │ │ │ │ - // Switching between GET (image) and POST (iframe). │ │ │ │ - │ │ │ │ - // We remove the imgDiv (really either an image or an iframe) │ │ │ │ - // from the frame and set it to null to make sure initImage │ │ │ │ - // will call getImage. │ │ │ │ - │ │ │ │ - if (this.imgDiv && this.imgDiv.parentNode === this.frame) { │ │ │ │ - this.frame.removeChild(this.imgDiv); │ │ │ │ - } │ │ │ │ - this.imgDiv = null; │ │ │ │ +OpenLayers.Format.WFSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ │ │ │ │ - // And if we had an iframe we also remove the event pane. │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WFSCapabilities.v1_0_0 │ │ │ │ + * Create a new parser for WFS capabilities version 1.0.0. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ │ │ │ │ - if (fromIFrame) { │ │ │ │ - this.frame.removeChild(this.frame.firstChild); │ │ │ │ + /** │ │ │ │ + * 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({ │ │ │ │ + "Service": function(node, capabilities) { │ │ │ │ + capabilities.service = {}; │ │ │ │ + this.readChildNodes(node, capabilities.service); │ │ │ │ + }, │ │ │ │ + "Fees": function(node, service) { │ │ │ │ + var fees = this.getChildValue(node); │ │ │ │ + if (fees && fees.toLowerCase() != "none") { │ │ │ │ + service.fees = fees; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "AccessConstraints": function(node, service) { │ │ │ │ + var constraints = this.getChildValue(node); │ │ │ │ + if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ + service.accessConstraints = constraints; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "OnlineResource": function(node, service) { │ │ │ │ + var onlineResource = this.getChildValue(node); │ │ │ │ + if (onlineResource && onlineResource.toLowerCase() != "none") { │ │ │ │ + service.onlineResource = onlineResource; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Keywords": function(node, service) { │ │ │ │ + var keywords = this.getChildValue(node); │ │ │ │ + if (keywords && keywords.toLowerCase() != "none") { │ │ │ │ + service.keywords = keywords.split(', '); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Capability": function(node, capabilities) { │ │ │ │ + capabilities.capability = {}; │ │ │ │ + this.readChildNodes(node, capabilities.capability); │ │ │ │ + }, │ │ │ │ + "Request": function(node, obj) { │ │ │ │ + obj.request = {}; │ │ │ │ + this.readChildNodes(node, obj.request); │ │ │ │ + }, │ │ │ │ + "GetFeature": function(node, request) { │ │ │ │ + request.getfeature = { │ │ │ │ + href: {}, // DCPType │ │ │ │ + formats: [] // ResultFormat │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, request.getfeature); │ │ │ │ + }, │ │ │ │ + "ResultFormat": function(node, obj) { │ │ │ │ + var children = node.childNodes; │ │ │ │ + var childNode; │ │ │ │ + for (var i = 0; i < children.length; i++) { │ │ │ │ + childNode = children[i]; │ │ │ │ + if (childNode.nodeType == 1) { │ │ │ │ + obj.formats.push(childNode.nodeName); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "DCPType": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "HTTP": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj.href); │ │ │ │ + }, │ │ │ │ + "Get": function(node, obj) { │ │ │ │ + obj.get = node.getAttribute("onlineResource"); │ │ │ │ + }, │ │ │ │ + "Post": function(node, obj) { │ │ │ │ + obj.post = node.getAttribute("onlineResource"); │ │ │ │ + }, │ │ │ │ + "SRS": function(node, obj) { │ │ │ │ + var srs = this.getChildValue(node); │ │ │ │ + if (srs) { │ │ │ │ + obj.srs = srs; │ │ │ │ + } │ │ │ │ } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return OpenLayers.Tile.Image.prototype.draw.apply(this, arguments); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: getImage │ │ │ │ - * Creates the content for the frame on the tile. │ │ │ │ - */ │ │ │ │ - getImage: function() { │ │ │ │ - if (this.useIFrame === true) { │ │ │ │ - if (!this.frame.childNodes.length) { │ │ │ │ - var eventPane = document.createElement("div"), │ │ │ │ - style = eventPane.style; │ │ │ │ - style.position = "absolute"; │ │ │ │ - style.width = "100%"; │ │ │ │ - style.height = "100%"; │ │ │ │ - style.zIndex = 1; │ │ │ │ - style.backgroundImage = "url(" + this.blankImageUrl + ")"; │ │ │ │ - this.frame.appendChild(eventPane); │ │ │ │ - } │ │ │ │ - │ │ │ │ - var id = this.id + '_iFrame', │ │ │ │ - iframe; │ │ │ │ - if (parseFloat(navigator.appVersion.split("MSIE")[1]) < 9) { │ │ │ │ - // Older IE versions do not set the name attribute of an iFrame │ │ │ │ - // properly via DOM manipulation, so we need to do it on our own with │ │ │ │ - // this hack. │ │ │ │ - iframe = document.createElement('<iframe name="' + id + '">'); │ │ │ │ - │ │ │ │ - // IFrames in older IE versions are not transparent, if you set │ │ │ │ - // the backgroundColor transparent. This is a workaround to get │ │ │ │ - // transparent iframes. │ │ │ │ - iframe.style.backgroundColor = '#FFFFFF'; │ │ │ │ - iframe.style.filter = 'chroma(color=#FFFFFF)'; │ │ │ │ - } else { │ │ │ │ - iframe = document.createElement('iframe'); │ │ │ │ - iframe.style.backgroundColor = 'transparent'; │ │ │ │ - │ │ │ │ - // iframe.name needs to be an unique id, otherwise it │ │ │ │ - // could happen that other iframes are overwritten. │ │ │ │ - iframe.name = id; │ │ │ │ - } │ │ │ │ - │ │ │ │ - // some special properties to avoid scaling the images and scrollbars │ │ │ │ - // in the iframe │ │ │ │ - iframe.scrolling = 'no'; │ │ │ │ - iframe.marginWidth = '0px'; │ │ │ │ - iframe.marginHeight = '0px'; │ │ │ │ - iframe.frameBorder = '0'; │ │ │ │ - │ │ │ │ - iframe.style.position = "absolute"; │ │ │ │ - iframe.style.width = "100%"; │ │ │ │ - iframe.style.height = "100%"; │ │ │ │ - │ │ │ │ - if (this.layer.opacity < 1) { │ │ │ │ - OpenLayers.Util.modifyDOMElement(iframe, null, null, null, │ │ │ │ - null, null, null, this.layer.opacity); │ │ │ │ - } │ │ │ │ - this.frame.appendChild(iframe); │ │ │ │ - this.imgDiv = iframe; │ │ │ │ - return iframe; │ │ │ │ - } else { │ │ │ │ - return OpenLayers.Tile.Image.prototype.getImage.apply(this, arguments); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: createRequestForm │ │ │ │ - * Create the html <form> element with width, height, bbox and all │ │ │ │ - * parameters specified in the layer params. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} The form element which sends the HTTP-POST request to the │ │ │ │ - * WMS. │ │ │ │ - */ │ │ │ │ - createRequestForm: function() { │ │ │ │ - // creation of the form element │ │ │ │ - var form = document.createElement('form'); │ │ │ │ - form.method = 'POST'; │ │ │ │ - var cacheId = this.layer.params["_OLSALT"]; │ │ │ │ - cacheId = (cacheId ? cacheId + "_" : "") + this.bounds.toBBOX(); │ │ │ │ - form.action = OpenLayers.Util.urlAppend(this.layer.url, cacheId); │ │ │ │ - form.target = this.id + '_iFrame'; │ │ │ │ - │ │ │ │ - // adding all parameters in layer params as hidden fields to the html │ │ │ │ - // form element │ │ │ │ - var imageSize = this.layer.getImageSize(), │ │ │ │ - params = OpenLayers.Util.getParameters(this.url), │ │ │ │ - field; │ │ │ │ - │ │ │ │ - for (var par in params) { │ │ │ │ - field = document.createElement('input'); │ │ │ │ - field.type = 'hidden'; │ │ │ │ - field.name = par; │ │ │ │ - field.value = params[par]; │ │ │ │ - form.appendChild(field); │ │ │ │ - } │ │ │ │ - │ │ │ │ - return form; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: setImgSrc │ │ │ │ - * Sets the source for the tile image │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * url - {String} │ │ │ │ - */ │ │ │ │ - setImgSrc: function(url) { │ │ │ │ - if (this.useIFrame === true) { │ │ │ │ - if (url) { │ │ │ │ - var form = this.createRequestForm(); │ │ │ │ - this.frame.appendChild(form); │ │ │ │ - form.submit(); │ │ │ │ - this.frame.removeChild(form); │ │ │ │ - } else if (this.imgDiv.parentNode === this.frame) { │ │ │ │ - // we don't reuse iframes to avoid caching issues │ │ │ │ - this.frame.removeChild(this.imgDiv); │ │ │ │ - this.imgDiv = null; │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Tile.Image.prototype.setImgSrc.apply(this, arguments); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]) │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: onImageLoad │ │ │ │ - * Handler for the image onload event │ │ │ │ - */ │ │ │ │ - onImageLoad: function() { │ │ │ │ - //TODO de-uglify opacity handling │ │ │ │ - OpenLayers.Tile.Image.prototype.onImageLoad.apply(this, arguments); │ │ │ │ - if (this.useIFrame === true) { │ │ │ │ - this.imgDiv.style.opacity = 1; │ │ │ │ - this.frame.style.opacity = this.layer.opacity; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_0_0" │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: createBackBuffer │ │ │ │ - * Override createBackBuffer to do nothing when we use an iframe. Moving an │ │ │ │ - * iframe from one element to another makes it necessary to reload the iframe │ │ │ │ - * because its content is lost. So we just give up. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {DOMElement} │ │ │ │ - */ │ │ │ │ - createBackBuffer: function() { │ │ │ │ - var backBuffer; │ │ │ │ - if (this.useIFrame === false) { │ │ │ │ - backBuffer = OpenLayers.Tile.Image.prototype.createBackBuffer.call(this); │ │ │ │ - } │ │ │ │ - return backBuffer; │ │ │ │ - } │ │ │ │ -}; │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/WFS.js │ │ │ │ + OpenLayers/Format/WFSCapabilities/v1_1_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.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. │ │ │ │ + * @requires OpenLayers/Format/WFSCapabilities/v1.js │ │ │ │ + * @requires OpenLayers/Format/OWSCommon/v1.js │ │ │ │ */ │ │ │ │ -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. │ │ │ │ + * Class: OpenLayers.Format.WFSCapabilities/v1_1_0 │ │ │ │ + * Read WFS Capabilities version 1.1.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>} │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.WFSCapabilities> │ │ │ │ */ │ │ │ │ -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 │ │ │ │ - )); │ │ │ │ -}; │ │ │ │ +OpenLayers.Format.WFSCapabilities.v1_1_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Protocol.WFS.DEFAULTS │ │ │ │ - */ │ │ │ │ -OpenLayers.Protocol.WFS.DEFAULTS = { │ │ │ │ - "version": "1.0.0" │ │ │ │ -}; │ │ │ │ + /** │ │ │ │ + * Property: regExes │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ + */ │ │ │ │ + regExes: { │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ + }, │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WFSCapabilities.v1_1_0 │ │ │ │ + * Create a new parser for WFS capabilities version 1.1.0. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + │ │ │ │ + /** │ │ │ │ + * 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({ │ │ │ │ + "DefaultSRS": function(node, obj) { │ │ │ │ + var defaultSRS = this.getChildValue(node); │ │ │ │ + if (defaultSRS) { │ │ │ │ + obj.srs = defaultSRS; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]), │ │ │ │ + "ows": OpenLayers.Format.OWSCommon.v1.prototype.readers.ows │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_1_0" │ │ │ │ + │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/Script.js │ │ │ │ + OpenLayers/Format/SLD/v1_0_0_GeoServer.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/Feature/Vector.js │ │ │ │ - * @requires OpenLayers/Format/GeoJSON.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * if application uses the query string, for example, for BBOX parameters, │ │ │ │ - * OpenLayers/Format/QueryStringFilter.js should be included in the build config file │ │ │ │ + * @requires OpenLayers/Format/SLD/v1_0_0.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.Script │ │ │ │ - * A basic Script protocol for vector layers. Create a new instance with the │ │ │ │ - * <OpenLayers.Protocol.Script> constructor. A script protocol is used to │ │ │ │ - * get around the same origin policy. It works with services that return │ │ │ │ - * JSONP - that is, JSON wrapped in a client-specified callback. The │ │ │ │ - * protocol handles fetching and parsing of feature data and sends parsed │ │ │ │ - * features to the <callback> configured with the protocol. The protocol │ │ │ │ - * expects features serialized as GeoJSON by default, but can be configured │ │ │ │ - * to work with other formats by setting the <format> property. │ │ │ │ + * Class: OpenLayers.Format.SLD/v1_0_0_GeoServer │ │ │ │ + * Read and write SLD version 1.0.0 with GeoServer-specific enhanced options. │ │ │ │ + * See http://svn.osgeo.org/geotools/trunk/modules/extension/xsd/xsd-sld/src/main/resources/org/geotools/sld/bindings/StyledLayerDescriptor.xsd │ │ │ │ + * for more information. │ │ │ │ * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol> │ │ │ │ + * - <OpenLayers.Format.SLD.v1_0_0> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol.Script = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: url │ │ │ │ - * {String} Service URL. The service is expected to return serialized │ │ │ │ - * features wrapped in a named callback (where the callback name is │ │ │ │ - * generated by this protocol). │ │ │ │ - * Read-only, set through the options passed to the constructor. │ │ │ │ - */ │ │ │ │ - url: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: params │ │ │ │ - * {Object} Query string parameters to be appended to the URL. │ │ │ │ - * Read-only, set through the options passed to the constructor. │ │ │ │ - * Example: {maxFeatures: 50} │ │ │ │ - */ │ │ │ │ - params: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: callback │ │ │ │ - * {Object} Function to be called when the <read> operation completes. │ │ │ │ - */ │ │ │ │ - callback: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: callbackTemplate │ │ │ │ - * {String} Template for creating a unique callback function name │ │ │ │ - * for the registry. Should include ${id}. The ${id} variable will be │ │ │ │ - * replaced with a string identifier prefixed with a "c" (e.g. c1, c2). │ │ │ │ - * Default is "OpenLayers.Protocol.Script.registry.${id}". │ │ │ │ - */ │ │ │ │ - callbackTemplate: "OpenLayers.Protocol.Script.registry.${id}", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: callbackKey │ │ │ │ - * {String} The name of the query string parameter that the service │ │ │ │ - * recognizes as the callback identifier. Default is "callback". │ │ │ │ - * This key is used to generate the URL for the script. For example │ │ │ │ - * setting <callbackKey> to "myCallback" would result in a URL like │ │ │ │ - * http://example.com/?myCallback=... │ │ │ │ - */ │ │ │ │ - callbackKey: "callback", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: callbackPrefix │ │ │ │ - * {String} Where a service requires that the callback query string │ │ │ │ - * parameter value is prefixed by some string, this value may be set. │ │ │ │ - * For example, setting <callbackPrefix> to "foo:" would result in a │ │ │ │ - * URL like http://example.com/?callback=foo:... Default is "". │ │ │ │ - */ │ │ │ │ - callbackPrefix: "", │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: scope │ │ │ │ - * {Object} Optional ``this`` object for the callback. Read-only, set │ │ │ │ - * through the options passed to the constructor. │ │ │ │ - */ │ │ │ │ - scope: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: format │ │ │ │ - * {<OpenLayers.Format>} Format for parsing features. Default is an │ │ │ │ - * <OpenLayers.Format.GeoJSON> format. If an alternative is provided, │ │ │ │ - * the format's read method must take an object and return an array │ │ │ │ - * of features. │ │ │ │ - */ │ │ │ │ - format: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Property: pendingRequests │ │ │ │ - * {Object} References all pending requests. Property names are script │ │ │ │ - * identifiers and property values are script elements. │ │ │ │ - */ │ │ │ │ - pendingRequests: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: srsInBBOX │ │ │ │ - * {Boolean} Include the SRS identifier in BBOX query string parameter. │ │ │ │ - * Setting this property has no effect if a custom filterToParams method │ │ │ │ - * is provided. 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.Script │ │ │ │ - * A class for giving layers generic Script protocol. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ - * │ │ │ │ - * Valid options include: │ │ │ │ - * url - {String} │ │ │ │ - * params - {Object} │ │ │ │ - * callback - {Function} │ │ │ │ - * scope - {Object} │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - this.params = {}; │ │ │ │ - this.pendingRequests = {}; │ │ │ │ - OpenLayers.Protocol.prototype.initialize.apply(this, arguments); │ │ │ │ - if (!this.format) { │ │ │ │ - this.format = new OpenLayers.Format.GeoJSON(); │ │ │ │ - } │ │ │ │ - │ │ │ │ - if (!this.filterToParams && OpenLayers.Format.QueryStringFilter) { │ │ │ │ - var format = new OpenLayers.Format.QueryStringFilter({ │ │ │ │ - srsInBBOX: this.srsInBBOX │ │ │ │ - }); │ │ │ │ - this.filterToParams = function(filter, params) { │ │ │ │ - return format.write(filter, params); │ │ │ │ - }; │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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. │ │ │ │ - * filter - {<OpenLayers.Filter>} Filter to get serialized as a │ │ │ │ - * query string. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Protocol.Response>} A response object, whose "priv" property │ │ │ │ - * references the injected script. 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 = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ - options.params = OpenLayers.Util.applyDefaults( │ │ │ │ - options.params, this.options.params │ │ │ │ - ); │ │ │ │ - if (options.filter && this.filterToParams) { │ │ │ │ - options.params = this.filterToParams( │ │ │ │ - options.filter, options.params │ │ │ │ - ); │ │ │ │ - } │ │ │ │ - var response = new OpenLayers.Protocol.Response({ │ │ │ │ - requestType: "read" │ │ │ │ - }); │ │ │ │ - var request = this.createRequest( │ │ │ │ - options.url, │ │ │ │ - options.params, │ │ │ │ - OpenLayers.Function.bind(function(data) { │ │ │ │ - response.data = data; │ │ │ │ - this.handleRead(response, options); │ │ │ │ - }, this) │ │ │ │ - ); │ │ │ │ - response.priv = request; │ │ │ │ - return response; │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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, any filter will not be serialized. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * filter - {<OpenLayers.Filter>} filter to convert. │ │ │ │ - * params - {Object} The parameters object. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} The resulting parameters object. │ │ │ │ - */ │ │ │ │ +OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.SLD.v1_0_0, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: createRequest │ │ │ │ - * Issues a request for features by creating injecting a script in the │ │ │ │ - * document head. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * url - {String} Service URL. │ │ │ │ - * params - {Object} Query string parameters. │ │ │ │ - * callback - {Function} Callback to be called with resulting data. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {HTMLScriptElement} The script pending execution. │ │ │ │ - */ │ │ │ │ - createRequest: function(url, params, callback) { │ │ │ │ - var id = OpenLayers.Protocol.Script.register(callback); │ │ │ │ - var name = OpenLayers.String.format(this.callbackTemplate, { │ │ │ │ - id: id │ │ │ │ - }); │ │ │ │ - params = OpenLayers.Util.extend({}, params); │ │ │ │ - params[this.callbackKey] = this.callbackPrefix + name; │ │ │ │ - url = OpenLayers.Util.urlAppend( │ │ │ │ - url, OpenLayers.Util.getParameterString(params) │ │ │ │ - ); │ │ │ │ - var script = document.createElement("script"); │ │ │ │ - script.type = "text/javascript"; │ │ │ │ - script.src = url; │ │ │ │ - script.id = "OpenLayers_Protocol_Script_" + id; │ │ │ │ - this.pendingRequests[script.id] = script; │ │ │ │ - var head = document.getElementsByTagName("head")[0]; │ │ │ │ - head.appendChild(script); │ │ │ │ - return script; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} The specific parser version. │ │ │ │ + */ │ │ │ │ + version: "1.0.0", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: destroyRequest │ │ │ │ - * Remove a script node associated with a response from the document. Also │ │ │ │ - * unregisters the callback and removes the script from the │ │ │ │ - * <pendingRequests> object. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * script - {HTMLScriptElement} │ │ │ │ - */ │ │ │ │ - destroyRequest: function(script) { │ │ │ │ - OpenLayers.Protocol.Script.unregister(script.id.split("_").pop()); │ │ │ │ - delete this.pendingRequests[script.id]; │ │ │ │ - if (script.parentNode) { │ │ │ │ - script.parentNode.removeChild(script); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: profile │ │ │ │ + * {String} The specific profile │ │ │ │ + */ │ │ │ │ + profile: "GeoServer", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: handleRead │ │ │ │ - * Individual callbacks are created for read, create and update, should │ │ │ │ - * a subclass need to override each one separately. │ │ │ │ - * │ │ │ │ - * 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) { │ │ │ │ - this.handleResponse(response, options); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.SLD.v1_0_0_GeoServer │ │ │ │ + * Create a new parser for GeoServer-enhanced SLD version 1.0.0. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: handleResponse │ │ │ │ - * Called by CRUD specific handlers. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * response - {<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(response, options) { │ │ │ │ - if (options.callback) { │ │ │ │ - if (response.data) { │ │ │ │ - response.features = this.parseFeatures(response.data); │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ - } else { │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ - } │ │ │ │ - this.destroyRequest(response.priv); │ │ │ │ - options.callback.call(options.scope, response); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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: OpenLayers.Util.applyDefaults({ │ │ │ │ + "sld": OpenLayers.Util.applyDefaults({ │ │ │ │ + "Priority": function(node, obj) { │ │ │ │ + var value = this.readers.ogc._expression.call(this, node); │ │ │ │ + if (value) { │ │ │ │ + obj.priority = value; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "VendorOption": function(node, obj) { │ │ │ │ + if (!obj.vendorOptions) { │ │ │ │ + obj.vendorOptions = {}; │ │ │ │ + } │ │ │ │ + obj.vendorOptions[node.getAttribute("name")] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "TextSymbolizer": function(node, rule) { │ │ │ │ + OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld.TextSymbolizer.apply(this, arguments); │ │ │ │ + var symbolizer = this.multipleSymbolizers ? rule.symbolizers[rule.symbolizers.length - 1] : rule.symbolizer["Text"]; │ │ │ │ + if (symbolizer.graphic === undefined) { │ │ │ │ + symbolizer.graphic = false; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.readers["sld"]) │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.readers), │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: parseFeatures │ │ │ │ - * Read Script response body and return features. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * data - {Object} The data sent to the callback function by the server. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array({<OpenLayers.Feature.Vector>})} or │ │ │ │ - * {<OpenLayers.Feature.Vector>} Array of features or a single feature. │ │ │ │ - */ │ │ │ │ - parseFeatures: function(data) { │ │ │ │ - return this.format.read(data); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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: OpenLayers.Util.applyDefaults({ │ │ │ │ + "sld": OpenLayers.Util.applyDefaults({ │ │ │ │ + "Priority": function(priority) { │ │ │ │ + return this.writers.sld._OGCExpression.call( │ │ │ │ + this, "sld:Priority", priority │ │ │ │ + ); │ │ │ │ + }, │ │ │ │ + "VendorOption": function(option) { │ │ │ │ + return this.createElementNSPlus("sld:VendorOption", { │ │ │ │ + attributes: { │ │ │ │ + name: option.name │ │ │ │ + }, │ │ │ │ + value: option.value │ │ │ │ + }); │ │ │ │ + }, │ │ │ │ + "TextSymbolizer": function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["TextSymbolizer"].apply(this, arguments); │ │ │ │ + if (symbolizer.graphic !== false && (symbolizer.externalGraphic || symbolizer.graphicName)) { │ │ │ │ + this.writeNode("Graphic", symbolizer, node); │ │ │ │ + } │ │ │ │ + if ("priority" in symbolizer) { │ │ │ │ + this.writeNode("Priority", symbolizer.priority, node); │ │ │ │ + } │ │ │ │ + return this.addVendorOptions(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "PointSymbolizer": function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["PointSymbolizer"].apply(this, arguments); │ │ │ │ + return this.addVendorOptions(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "LineSymbolizer": function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["LineSymbolizer"].apply(this, arguments); │ │ │ │ + return this.addVendorOptions(node, symbolizer); │ │ │ │ + }, │ │ │ │ + "PolygonSymbolizer": function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["PolygonSymbolizer"].apply(this, arguments); │ │ │ │ + return this.addVendorOptions(node, symbolizer); │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.writers["sld"]) │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.writers), │ │ │ │ │ │ │ │ - /** │ │ │ │ - * APIMethod: abort │ │ │ │ - * Abort an ongoing request. If no response is provided, all pending │ │ │ │ - * requests will be aborted. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * response - {<OpenLayers.Protocol.Response>} The response object returned │ │ │ │ - * from a <read> request. │ │ │ │ - */ │ │ │ │ - abort: function(response) { │ │ │ │ - if (response) { │ │ │ │ - this.destroyRequest(response.priv); │ │ │ │ - } else { │ │ │ │ - for (var key in this.pendingRequests) { │ │ │ │ - this.destroyRequest(this.pendingRequests[key]); │ │ │ │ + /** │ │ │ │ + * Method: addVendorOptions │ │ │ │ + * Add in the VendorOption tags and return the node again. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * node - {DOMElement} A DOM node. │ │ │ │ + * symbolizer - {Object} │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {DOMElement} A DOM node. │ │ │ │ + */ │ │ │ │ + addVendorOptions: function(node, symbolizer) { │ │ │ │ + var options = symbolizer.vendorOptions; │ │ │ │ + if (options) { │ │ │ │ + for (var key in symbolizer.vendorOptions) { │ │ │ │ + this.writeNode("VendorOption", { │ │ │ │ + name: key, │ │ │ │ + value: symbolizer.vendorOptions[key] │ │ │ │ + }, node); │ │ │ │ + } │ │ │ │ } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIMethod: destroy │ │ │ │ - * Clean up the protocol. │ │ │ │ - */ │ │ │ │ - destroy: function() { │ │ │ │ - this.abort(); │ │ │ │ - delete this.params; │ │ │ │ - delete this.format; │ │ │ │ - OpenLayers.Protocol.prototype.destroy.apply(this); │ │ │ │ - }, │ │ │ │ - │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.Script" │ │ │ │ -}); │ │ │ │ - │ │ │ │ -(function() { │ │ │ │ - var o = OpenLayers.Protocol.Script; │ │ │ │ - var counter = 0; │ │ │ │ - o.registry = {}; │ │ │ │ + return node; │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Function: OpenLayers.Protocol.Script.register │ │ │ │ - * Register a callback for a newly created script. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * callback - {Function} The callback to be executed when the newly added │ │ │ │ - * script loads. This callback will be called with a single argument │ │ │ │ - * that is the JSON returned by the service. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Number} An identifier for retrieving the registered callback. │ │ │ │ - */ │ │ │ │ - o.register = function(callback) { │ │ │ │ - var id = "c" + (++counter); │ │ │ │ - o.registry[id] = function() { │ │ │ │ - callback.apply(this, arguments); │ │ │ │ - }; │ │ │ │ - return id; │ │ │ │ - }; │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0_GeoServer" │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Function: OpenLayers.Protocol.Script.unregister │ │ │ │ - * Unregister a callback previously registered with the register function. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * id - {Number} The identifer returned by the register function. │ │ │ │ - */ │ │ │ │ - o.unregister = function(id) { │ │ │ │ - delete o.registry[id]; │ │ │ │ - }; │ │ │ │ -})(); │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/CSW.js │ │ │ │ + OpenLayers/Format/WMSDescribeLayer/v1_1.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/Format/WMSDescribeLayer.js │ │ │ │ + * @requires OpenLayers/Format/OGCExceptionReport.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.CSW │ │ │ │ - * Used to create a versioned CSW protocol. Default version is 2.0.2. │ │ │ │ + * Class: OpenLayers.Format.WMSDescribeLayer.v1_1_1 │ │ │ │ + * Read SLD WMS DescribeLayer response for WMS 1.1.X │ │ │ │ + * WMS 1.1.X is tightly coupled to SLD 1.0.0 │ │ │ │ + * │ │ │ │ + * Example DescribeLayer request: │ │ │ │ + * http://demo.opengeo.org/geoserver/wms?request=DescribeLayer&version=1.1.1&layers=topp:states │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.WMSDescribeLayer> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol.CSW = function(options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults( │ │ │ │ - options, OpenLayers.Protocol.CSW.DEFAULTS │ │ │ │ - ); │ │ │ │ - var cls = OpenLayers.Protocol.CSW["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (!cls) { │ │ │ │ - throw "Unsupported CSW version: " + options.version; │ │ │ │ - } │ │ │ │ - return new cls(options); │ │ │ │ -}; │ │ │ │ +OpenLayers.Format.WMSDescribeLayer.v1_1_1 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WMSDescribeLayer, { │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Protocol.CSW.DEFAULTS │ │ │ │ - */ │ │ │ │ -OpenLayers.Protocol.CSW.DEFAULTS = { │ │ │ │ - "version": "2.0.2" │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Protocol/SOS.js │ │ │ │ - ====================================================================== */ │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMSDescribeLayer │ │ │ │ + * Create a new parser for WMS DescribeLayer responses. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.WMSDescribeLayer.prototype.initialize.apply(this, │ │ │ │ + [options]); │ │ │ │ + }, │ │ │ │ │ │ │ │ -/* 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. */ │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read DescribeLayer data from a string, and return the response. │ │ │ │ + * The OGC defines 2 formats which are allowed for output, │ │ │ │ + * so we need to parse these 2 types for version 1.1.X │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} Object with a layerDescriptions property, which holds an Array │ │ │ │ + * of {<LayerDescription>} objects which have: │ │ │ │ + * - {String} owsType: WFS/WCS │ │ │ │ + * - {String} owsURL: the online resource │ │ │ │ + * - {String} typeName: the name of the typename on the owsType service │ │ │ │ + * - {String} layerName: the name of the WMS layer we did a lookup for │ │ │ │ + */ │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ + } │ │ │ │ + var root = data.documentElement; │ │ │ │ + var children = root.childNodes; │ │ │ │ + var describelayer = { │ │ │ │ + layerDescriptions: [] │ │ │ │ + }; │ │ │ │ + var childNode, nodeName; │ │ │ │ + for (var i = 0; i < children.length; ++i) { │ │ │ │ + childNode = children[i]; │ │ │ │ + nodeName = childNode.nodeName; │ │ │ │ + if (nodeName == 'LayerDescription') { │ │ │ │ + var layerName = childNode.getAttribute('name'); │ │ │ │ + var owsType = ''; │ │ │ │ + var owsURL = ''; │ │ │ │ + var typeName = ''; │ │ │ │ + // check for owsType and owsURL attributes │ │ │ │ + if (childNode.getAttribute('owsType')) { │ │ │ │ + owsType = childNode.getAttribute('owsType'); │ │ │ │ + owsURL = childNode.getAttribute('owsURL'); │ │ │ │ + } else { │ │ │ │ + // look for wfs or wcs attribute │ │ │ │ + if (childNode.getAttribute('wfs') != '') { │ │ │ │ + owsType = 'WFS'; │ │ │ │ + owsURL = childNode.getAttribute('wfs'); │ │ │ │ + } else if (childNode.getAttribute('wcs') != '') { │ │ │ │ + owsType = 'WCS'; │ │ │ │ + owsURL = childNode.getAttribute('wcs'); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + // look for Query child │ │ │ │ + var query = childNode.getElementsByTagName('Query'); │ │ │ │ + if (query.length > 0) { │ │ │ │ + typeName = query[0].getAttribute('typeName'); │ │ │ │ + if (!typeName) { │ │ │ │ + // because of Ionic bug │ │ │ │ + typeName = query[0].getAttribute('typename'); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var layerDescription = { │ │ │ │ + layerName: layerName, │ │ │ │ + owsType: owsType, │ │ │ │ + owsURL: owsURL, │ │ │ │ + typeName: typeName │ │ │ │ + }; │ │ │ │ + describelayer.layerDescriptions.push(layerDescription); │ │ │ │ │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Protocol.js │ │ │ │ - */ │ │ │ │ + //TODO do this in deprecated.js instead: │ │ │ │ + // array style index for backwards compatibility │ │ │ │ + describelayer.length = describelayer.layerDescriptions.length; │ │ │ │ + describelayer[describelayer.length - 1] = layerDescription; │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Function: OpenLayers.Protocol.SOS │ │ │ │ - * Used to create a versioned SOS protocol. Default version is 1.0.0. │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {<OpenLayers.Protocol>} An SOS protocol for the given version. │ │ │ │ - */ │ │ │ │ -OpenLayers.Protocol.SOS = function(options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults( │ │ │ │ - options, OpenLayers.Protocol.SOS.DEFAULTS │ │ │ │ - ); │ │ │ │ - var cls = OpenLayers.Protocol.SOS["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (!cls) { │ │ │ │ - throw "Unsupported SOS version: " + options.version; │ │ │ │ - } │ │ │ │ - return new cls(options); │ │ │ │ -}; │ │ │ │ + } else if (nodeName == 'ServiceException') { │ │ │ │ + // an exception must have occurred, so parse it │ │ │ │ + var parser = new OpenLayers.Format.OGCExceptionReport(); │ │ │ │ + return { │ │ │ │ + error: parser.read(data) │ │ │ │ + }; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return describelayer; │ │ │ │ + }, │ │ │ │ │ │ │ │ -/** │ │ │ │ - * Constant: OpenLayers.Protocol.SOS.DEFAULTS │ │ │ │ - */ │ │ │ │ -OpenLayers.Protocol.SOS.DEFAULTS = { │ │ │ │ - "version": "1.0.0" │ │ │ │ -}; │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer.v1_1_1" │ │ │ │ + │ │ │ │ + }); │ │ │ │ + │ │ │ │ +// Version alias - workaround for http://trac.osgeo.org/mapserver/ticket/2257 │ │ │ │ +OpenLayers.Format.WMSDescribeLayer.v1_1_0 = │ │ │ │ + OpenLayers.Format.WMSDescribeLayer.v1_1_1; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/HTTP.js │ │ │ │ + OpenLayers/Format/WMTSCapabilities/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.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 │ │ │ │ + * @requires OpenLayers/Format/WMTSCapabilities.js │ │ │ │ + * @requires OpenLayers/Format/OWSCommon/v1_1_0.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.HTTP │ │ │ │ - * A basic HTTP protocol for vector layers. Create a new instance with the │ │ │ │ - * <OpenLayers.Protocol.HTTP> constructor. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.WMTSCapabilities.v1_0_0 │ │ │ │ + * Read WMTS Capabilities version 1.0.0. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol> │ │ │ │ + * - <OpenLayers.Format.WMTSCapabilities> │ │ │ │ */ │ │ │ │ -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); │ │ │ │ +OpenLayers.Format.WMTSCapabilities.v1_0_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.OWSCommon.v1_1_0, { │ │ │ │ │ │ │ │ - return resp; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} The parser version ("1.0.0"). │ │ │ │ + */ │ │ │ │ + version: "1.0.0", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + */ │ │ │ │ + namespaces: { │ │ │ │ + ows: "http://www.opengis.net/ows/1.1", │ │ │ │ + wmts: "http://www.opengis.net/wmts/1.0", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink" │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: yx │ │ │ │ + * {Object} Members in the yx object are used to determine if a CRS URN │ │ │ │ + * corresponds to a CRS with y,x axis order. Member names are CRS URNs │ │ │ │ + * and values are boolean. Defaults come from the │ │ │ │ + * <OpenLayers.Format.WMTSCapabilities> prototype. │ │ │ │ + */ │ │ │ │ + yx: null, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: defaultPrefix │ │ │ │ + * {String} The default namespace alias for creating element nodes. │ │ │ │ + */ │ │ │ │ + defaultPrefix: "wmts", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMTSCapabilities.v1_0_0 │ │ │ │ + * Create a new parser for WMTS capabilities version 1.0.0. │ │ │ │ + * │ │ │ │ + * 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]); │ │ │ │ + this.options = options; │ │ │ │ + var yx = OpenLayers.Util.extend({}, OpenLayers.Format.WMTSCapabilities.prototype.yx); │ │ │ │ + this.yx = OpenLayers.Util.extend(yx, this.yx); │ │ │ │ + }, │ │ │ │ │ │ │ │ - // 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); │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return info about the WMTS. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Object} Information about the SOS service. │ │ │ │ + */ │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ } │ │ │ │ - } │ │ │ │ - // 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; │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement; │ │ │ │ } │ │ │ │ - finalResponse.insertIds = fids; │ │ │ │ - callback.apply(this, [response]); │ │ │ │ - } │ │ │ │ + var capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + capabilities.version = this.version; │ │ │ │ + return capabilities; │ │ │ │ + }, │ │ │ │ │ │ │ │ - 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]); │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wmts": { │ │ │ │ + "Capabilities": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "Contents": function(node, obj) { │ │ │ │ + obj.contents = {}; │ │ │ │ + obj.contents.layers = []; │ │ │ │ + obj.contents.tileMatrixSets = {}; │ │ │ │ + this.readChildNodes(node, obj.contents); │ │ │ │ + }, │ │ │ │ + "Layer": function(node, obj) { │ │ │ │ + var layer = { │ │ │ │ + styles: [], │ │ │ │ + formats: [], │ │ │ │ + dimensions: [], │ │ │ │ + tileMatrixSetLinks: [] │ │ │ │ + }; │ │ │ │ + layer.layers = []; │ │ │ │ + this.readChildNodes(node, layer); │ │ │ │ + obj.layers.push(layer); │ │ │ │ + }, │ │ │ │ + "Style": function(node, obj) { │ │ │ │ + var style = {}; │ │ │ │ + style.isDefault = (node.getAttribute("isDefault") === "true"); │ │ │ │ + this.readChildNodes(node, style); │ │ │ │ + obj.styles.push(style); │ │ │ │ + }, │ │ │ │ + "Format": function(node, obj) { │ │ │ │ + obj.formats.push(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "TileMatrixSetLink": function(node, obj) { │ │ │ │ + var tileMatrixSetLink = {}; │ │ │ │ + this.readChildNodes(node, tileMatrixSetLink); │ │ │ │ + obj.tileMatrixSetLinks.push(tileMatrixSetLink); │ │ │ │ + }, │ │ │ │ + "TileMatrixSet": function(node, obj) { │ │ │ │ + // node could be child of wmts:Contents or wmts:TileMatrixSetLink │ │ │ │ + // duck type wmts:Contents by looking for layers │ │ │ │ + if (obj.layers) { │ │ │ │ + // TileMatrixSet as object type in schema │ │ │ │ + var tileMatrixSet = { │ │ │ │ + matrixIds: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, tileMatrixSet); │ │ │ │ + obj.tileMatrixSets[tileMatrixSet.identifier] = tileMatrixSet; │ │ │ │ + } else { │ │ │ │ + // TileMatrixSet as string type in schema │ │ │ │ + obj.tileMatrixSet = this.getChildValue(node); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "TileMatrix": function(node, obj) { │ │ │ │ + var tileMatrix = { │ │ │ │ + supportedCRS: obj.supportedCRS │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, tileMatrix); │ │ │ │ + obj.matrixIds.push(tileMatrix); │ │ │ │ + }, │ │ │ │ + "ScaleDenominator": function(node, obj) { │ │ │ │ + obj.scaleDenominator = parseFloat(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "TopLeftCorner": function(node, obj) { │ │ │ │ + var topLeftCorner = this.getChildValue(node); │ │ │ │ + var coords = topLeftCorner.split(" "); │ │ │ │ + // decide on axis order for the given CRS │ │ │ │ + var yx; │ │ │ │ + if (obj.supportedCRS) { │ │ │ │ + // extract out version from URN │ │ │ │ + var crs = obj.supportedCRS.replace( │ │ │ │ + /urn:ogc:def:crs:(\w+):.+:(\w+)$/, │ │ │ │ + "urn:ogc:def:crs:$1::$2" │ │ │ │ + ); │ │ │ │ + yx = !!this.yx[crs]; │ │ │ │ + } │ │ │ │ + if (yx) { │ │ │ │ + obj.topLeftCorner = new OpenLayers.LonLat( │ │ │ │ + coords[1], coords[0] │ │ │ │ + ); │ │ │ │ + } else { │ │ │ │ + obj.topLeftCorner = new OpenLayers.LonLat( │ │ │ │ + coords[0], coords[1] │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "TileWidth": function(node, obj) { │ │ │ │ + obj.tileWidth = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "TileHeight": function(node, obj) { │ │ │ │ + obj.tileHeight = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "MatrixWidth": function(node, obj) { │ │ │ │ + obj.matrixWidth = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "MatrixHeight": function(node, obj) { │ │ │ │ + obj.matrixHeight = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "ResourceURL": function(node, obj) { │ │ │ │ + obj.resourceUrl = obj.resourceUrl || {}; │ │ │ │ + var resourceType = node.getAttribute("resourceType"); │ │ │ │ + if (!obj.resourceUrls) { │ │ │ │ + obj.resourceUrls = []; │ │ │ │ + } │ │ │ │ + var resourceUrl = obj.resourceUrl[resourceType] = { │ │ │ │ + format: node.getAttribute("format"), │ │ │ │ + template: node.getAttribute("template"), │ │ │ │ + resourceType: resourceType │ │ │ │ + }; │ │ │ │ + obj.resourceUrls.push(resourceUrl); │ │ │ │ + }, │ │ │ │ + // not used for now, can be added in the future though │ │ │ │ + /*"Themes": function(node, obj) { │ │ │ │ + obj.themes = []; │ │ │ │ + this.readChildNodes(node, obj.themes); │ │ │ │ + }, │ │ │ │ + "Theme": function(node, obj) { │ │ │ │ + var theme = {}; │ │ │ │ + this.readChildNodes(node, theme); │ │ │ │ + obj.push(theme); │ │ │ │ + },*/ │ │ │ │ + "WSDL": function(node, obj) { │ │ │ │ + obj.wsdl = {}; │ │ │ │ + obj.wsdl.href = node.getAttribute("xlink:href"); │ │ │ │ + // TODO: other attributes of <WSDL> element │ │ │ │ + }, │ │ │ │ + "ServiceMetadataURL": function(node, obj) { │ │ │ │ + obj.serviceMetadataUrl = {}; │ │ │ │ + obj.serviceMetadataUrl.href = node.getAttribute("xlink:href"); │ │ │ │ + // TODO: other attributes of <ServiceMetadataURL> element │ │ │ │ + }, │ │ │ │ + "LegendURL": function(node, obj) { │ │ │ │ + obj.legend = {}; │ │ │ │ + obj.legend.href = node.getAttribute("xlink:href"); │ │ │ │ + obj.legend.format = node.getAttribute("format"); │ │ │ │ + }, │ │ │ │ + "Dimension": function(node, obj) { │ │ │ │ + var dimension = { │ │ │ │ + values: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, dimension); │ │ │ │ + obj.dimensions.push(dimension); │ │ │ │ + }, │ │ │ │ + "Default": function(node, obj) { │ │ │ │ + obj["default"] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Value": function(node, obj) { │ │ │ │ + obj.values.push(this.getChildValue(node)); │ │ │ │ } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - // 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(); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + }, │ │ │ │ + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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.Format.WMTSCapabilities.v1_0_0" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.HTTP" │ │ │ │ -}); │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/CSW/v2_0_2.js │ │ │ │ + OpenLayers/Format/WMSCapabilities/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/CSW.js │ │ │ │ - * @requires OpenLayers/Format/CSWGetRecords/v2_0_2.js │ │ │ │ + * @requires OpenLayers/Format/WMSCapabilities.js │ │ │ │ + * @requires OpenLayers/Format/OGCExceptionReport.js │ │ │ │ + * @requires OpenLayers/Format/XML.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.CSW.v2_0_2 │ │ │ │ - * CS-W (Catalogue services for the Web) version 2.0.2 protocol. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.WMSCapabilities.v1 │ │ │ │ + * Abstract class not to be instantiated directly. Creates │ │ │ │ + * the common parts for both WMS 1.1.X and WMS 1.3.X. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol> │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol.CSW.v2_0_2 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Protocol.CSW.v2_0_2 │ │ │ │ - * A class for CSW version 2.0.2 protocol management. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ - if (!options.format) { │ │ │ │ - this.format = new OpenLayers.Format.CSWGetRecords.v2_0_2(OpenLayers.Util.extend({}, this.formatOptions)); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: namespaces │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ + */ │ │ │ │ + namespaces: { │ │ │ │ + wms: "http://www.opengis.net/wms", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: read │ │ │ │ - * Construct a request for reading new records from the Catalogue. │ │ │ │ - */ │ │ │ │ - read: function(options) { │ │ │ │ - options = OpenLayers.Util.extend({}, options); │ │ │ │ - OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ - var response = new OpenLayers.Protocol.Response({ │ │ │ │ - requestType: "read" │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * Property: defaultPrefix │ │ │ │ + */ │ │ │ │ + defaultPrefix: "wms", │ │ │ │ │ │ │ │ - var data = this.format.write(options.params || options); │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMSCapabilities.v1 │ │ │ │ + * Create an instance of one of the subclasses. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ │ │ │ │ - response.priv = OpenLayers.Request.POST({ │ │ │ │ - url: options.url, │ │ │ │ - callback: this.createCallback(this.handleRead, response, options), │ │ │ │ - params: options.params, │ │ │ │ - headers: options.headers, │ │ │ │ - data: data │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * APIMethod: read │ │ │ │ + * Read capabilities data from a string, and return a list of layers. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ + * │ │ │ │ + * Returns: │ │ │ │ + * {Array} List of named layers. │ │ │ │ + */ │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ + } │ │ │ │ + var raw = data; │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement; │ │ │ │ + } │ │ │ │ + var capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + if (capabilities.service === undefined) { │ │ │ │ + // an exception must have occurred, so parse it │ │ │ │ + var parser = new OpenLayers.Format.OGCExceptionReport(); │ │ │ │ + capabilities.error = parser.read(raw); │ │ │ │ + } │ │ │ │ + return capabilities; │ │ │ │ + }, │ │ │ │ │ │ │ │ - return response; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wms": { │ │ │ │ + "Service": function(node, obj) { │ │ │ │ + obj.service = {}; │ │ │ │ + this.readChildNodes(node, obj.service); │ │ │ │ + }, │ │ │ │ + "Name": function(node, obj) { │ │ │ │ + obj.name = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Title": function(node, obj) { │ │ │ │ + obj.title = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Abstract": function(node, obj) { │ │ │ │ + obj["abstract"] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "BoundingBox": function(node, obj) { │ │ │ │ + var bbox = {}; │ │ │ │ + bbox.bbox = [ │ │ │ │ + parseFloat(node.getAttribute("minx")), │ │ │ │ + parseFloat(node.getAttribute("miny")), │ │ │ │ + parseFloat(node.getAttribute("maxx")), │ │ │ │ + parseFloat(node.getAttribute("maxy")) │ │ │ │ + ]; │ │ │ │ + var res = { │ │ │ │ + x: parseFloat(node.getAttribute("resx")), │ │ │ │ + y: parseFloat(node.getAttribute("resy")) │ │ │ │ + }; │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: handleRead │ │ │ │ - * Deal with response from the read request. │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * response - {<OpenLayers.Protocol.Response>} The response object to pass │ │ │ │ - * to the user callback. │ │ │ │ - * This response is given a code property, and optionally a data property. │ │ │ │ - * The latter represents the CSW records as returned by the call to │ │ │ │ - * the CSW format read method. │ │ │ │ - * options - {Object} The user options passed to the read call. │ │ │ │ - */ │ │ │ │ - handleRead: function(response, options) { │ │ │ │ - if (options.callback) { │ │ │ │ - var request = response.priv; │ │ │ │ - if (request.status >= 200 && request.status < 300) { │ │ │ │ - // success │ │ │ │ - response.data = this.parseData(request); │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ - } else { │ │ │ │ - // failure │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ + if (!(isNaN(res.x) && isNaN(res.y))) { │ │ │ │ + bbox.res = res; │ │ │ │ + } │ │ │ │ + // return the bbox so that descendant classes can set the │ │ │ │ + // CRS and SRS and add it to the obj │ │ │ │ + return bbox; │ │ │ │ + }, │ │ │ │ + "OnlineResource": function(node, obj) { │ │ │ │ + obj.href = this.getAttributeNS(node, this.namespaces.xlink, │ │ │ │ + "href"); │ │ │ │ + }, │ │ │ │ + "ContactInformation": function(node, obj) { │ │ │ │ + obj.contactInformation = {}; │ │ │ │ + this.readChildNodes(node, obj.contactInformation); │ │ │ │ + }, │ │ │ │ + "ContactPersonPrimary": function(node, obj) { │ │ │ │ + obj.personPrimary = {}; │ │ │ │ + this.readChildNodes(node, obj.personPrimary); │ │ │ │ + }, │ │ │ │ + "ContactPerson": function(node, obj) { │ │ │ │ + obj.person = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ContactOrganization": function(node, obj) { │ │ │ │ + obj.organization = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ContactPosition": function(node, obj) { │ │ │ │ + obj.position = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ContactAddress": function(node, obj) { │ │ │ │ + obj.contactAddress = {}; │ │ │ │ + this.readChildNodes(node, obj.contactAddress); │ │ │ │ + }, │ │ │ │ + "AddressType": function(node, obj) { │ │ │ │ + obj.type = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Address": function(node, obj) { │ │ │ │ + obj.address = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "City": function(node, obj) { │ │ │ │ + obj.city = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "StateOrProvince": function(node, obj) { │ │ │ │ + obj.stateOrProvince = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "PostCode": function(node, obj) { │ │ │ │ + obj.postcode = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Country": function(node, obj) { │ │ │ │ + obj.country = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ContactVoiceTelephone": function(node, obj) { │ │ │ │ + obj.phone = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ContactFacsimileTelephone": function(node, obj) { │ │ │ │ + obj.fax = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "ContactElectronicMailAddress": function(node, obj) { │ │ │ │ + obj.email = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Fees": function(node, obj) { │ │ │ │ + var fees = this.getChildValue(node); │ │ │ │ + if (fees && fees.toLowerCase() != "none") { │ │ │ │ + obj.fees = fees; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "AccessConstraints": function(node, obj) { │ │ │ │ + var constraints = this.getChildValue(node); │ │ │ │ + if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ + obj.accessConstraints = constraints; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Capability": function(node, obj) { │ │ │ │ + obj.capability = { │ │ │ │ + nestedLayers: [], │ │ │ │ + layers: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.capability); │ │ │ │ + }, │ │ │ │ + "Request": function(node, obj) { │ │ │ │ + obj.request = {}; │ │ │ │ + this.readChildNodes(node, obj.request); │ │ │ │ + }, │ │ │ │ + "GetCapabilities": function(node, obj) { │ │ │ │ + obj.getcapabilities = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getcapabilities); │ │ │ │ + }, │ │ │ │ + "Format": function(node, obj) { │ │ │ │ + if (OpenLayers.Util.isArray(obj.formats)) { │ │ │ │ + obj.formats.push(this.getChildValue(node)); │ │ │ │ + } else { │ │ │ │ + obj.format = this.getChildValue(node); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "DCPType": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "HTTP": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "Get": function(node, obj) { │ │ │ │ + obj.get = {}; │ │ │ │ + this.readChildNodes(node, obj.get); │ │ │ │ + // backwards compatibility │ │ │ │ + if (!obj.href) { │ │ │ │ + obj.href = obj.get.href; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Post": function(node, obj) { │ │ │ │ + obj.post = {}; │ │ │ │ + this.readChildNodes(node, obj.post); │ │ │ │ + // backwards compatibility │ │ │ │ + if (!obj.href) { │ │ │ │ + obj.href = obj.get.href; │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "GetMap": function(node, obj) { │ │ │ │ + obj.getmap = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getmap); │ │ │ │ + }, │ │ │ │ + "GetFeatureInfo": function(node, obj) { │ │ │ │ + obj.getfeatureinfo = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getfeatureinfo); │ │ │ │ + }, │ │ │ │ + "Exception": function(node, obj) { │ │ │ │ + obj.exception = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.exception); │ │ │ │ + }, │ │ │ │ + "Layer": function(node, obj) { │ │ │ │ + var parentLayer, capability; │ │ │ │ + if (obj.capability) { │ │ │ │ + capability = obj.capability; │ │ │ │ + parentLayer = obj; │ │ │ │ + } else { │ │ │ │ + capability = obj; │ │ │ │ + } │ │ │ │ + var attrNode = node.getAttributeNode("queryable"); │ │ │ │ + var queryable = (attrNode && attrNode.specified) ? │ │ │ │ + node.getAttribute("queryable") : null; │ │ │ │ + attrNode = node.getAttributeNode("cascaded"); │ │ │ │ + var cascaded = (attrNode && attrNode.specified) ? │ │ │ │ + node.getAttribute("cascaded") : null; │ │ │ │ + attrNode = node.getAttributeNode("opaque"); │ │ │ │ + var opaque = (attrNode && attrNode.specified) ? │ │ │ │ + node.getAttribute('opaque') : null; │ │ │ │ + var noSubsets = node.getAttribute('noSubsets'); │ │ │ │ + var fixedWidth = node.getAttribute('fixedWidth'); │ │ │ │ + var fixedHeight = node.getAttribute('fixedHeight'); │ │ │ │ + var parent = parentLayer || {}, │ │ │ │ + extend = OpenLayers.Util.extend; │ │ │ │ + var layer = { │ │ │ │ + nestedLayers: [], │ │ │ │ + styles: parentLayer ? [].concat(parentLayer.styles) : [], │ │ │ │ + srs: parentLayer ? extend({}, parent.srs) : {}, │ │ │ │ + metadataURLs: [], │ │ │ │ + bbox: parentLayer ? extend({}, parent.bbox) : {}, │ │ │ │ + llbbox: parent.llbbox, │ │ │ │ + dimensions: parentLayer ? extend({}, parent.dimensions) : {}, │ │ │ │ + authorityURLs: parentLayer ? extend({}, parent.authorityURLs) : {}, │ │ │ │ + identifiers: {}, │ │ │ │ + keywords: [], │ │ │ │ + queryable: (queryable && queryable !== "") ? │ │ │ │ + (queryable === "1" || queryable === "true") : (parent.queryable || false), │ │ │ │ + cascaded: (cascaded !== null) ? parseInt(cascaded) : (parent.cascaded || 0), │ │ │ │ + opaque: opaque ? │ │ │ │ + (opaque === "1" || opaque === "true") : (parent.opaque || false), │ │ │ │ + noSubsets: (noSubsets !== null) ? │ │ │ │ + (noSubsets === "1" || noSubsets === "true") : (parent.noSubsets || false), │ │ │ │ + fixedWidth: (fixedWidth != null) ? │ │ │ │ + parseInt(fixedWidth) : (parent.fixedWidth || 0), │ │ │ │ + fixedHeight: (fixedHeight != null) ? │ │ │ │ + parseInt(fixedHeight) : (parent.fixedHeight || 0), │ │ │ │ + minScale: parent.minScale, │ │ │ │ + maxScale: parent.maxScale, │ │ │ │ + attribution: parent.attribution │ │ │ │ + }; │ │ │ │ + obj.nestedLayers.push(layer); │ │ │ │ + layer.capability = capability; │ │ │ │ + this.readChildNodes(node, layer); │ │ │ │ + delete layer.capability; │ │ │ │ + if (layer.name) { │ │ │ │ + var parts = layer.name.split(":"), │ │ │ │ + request = capability.request, │ │ │ │ + gfi = request.getfeatureinfo; │ │ │ │ + if (parts.length > 0) { │ │ │ │ + layer.prefix = parts[0]; │ │ │ │ + } │ │ │ │ + capability.layers.push(layer); │ │ │ │ + if (layer.formats === undefined) { │ │ │ │ + layer.formats = request.getmap.formats; │ │ │ │ + } │ │ │ │ + if (layer.infoFormats === undefined && gfi) { │ │ │ │ + layer.infoFormats = gfi.formats; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Attribution": function(node, obj) { │ │ │ │ + obj.attribution = {}; │ │ │ │ + this.readChildNodes(node, obj.attribution); │ │ │ │ + }, │ │ │ │ + "LogoURL": function(node, obj) { │ │ │ │ + obj.logo = { │ │ │ │ + width: node.getAttribute("width"), │ │ │ │ + height: node.getAttribute("height") │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.logo); │ │ │ │ + }, │ │ │ │ + "Style": function(node, obj) { │ │ │ │ + var style = {}; │ │ │ │ + obj.styles.push(style); │ │ │ │ + this.readChildNodes(node, style); │ │ │ │ + }, │ │ │ │ + "LegendURL": function(node, obj) { │ │ │ │ + var legend = { │ │ │ │ + width: node.getAttribute("width"), │ │ │ │ + height: node.getAttribute("height") │ │ │ │ + }; │ │ │ │ + obj.legend = legend; │ │ │ │ + this.readChildNodes(node, legend); │ │ │ │ + }, │ │ │ │ + "MetadataURL": function(node, obj) { │ │ │ │ + var metadataURL = { │ │ │ │ + type: node.getAttribute("type") │ │ │ │ + }; │ │ │ │ + obj.metadataURLs.push(metadataURL); │ │ │ │ + this.readChildNodes(node, metadataURL); │ │ │ │ + }, │ │ │ │ + "DataURL": function(node, obj) { │ │ │ │ + obj.dataURL = {}; │ │ │ │ + this.readChildNodes(node, obj.dataURL); │ │ │ │ + }, │ │ │ │ + "FeatureListURL": function(node, obj) { │ │ │ │ + obj.featureListURL = {}; │ │ │ │ + this.readChildNodes(node, obj.featureListURL); │ │ │ │ + }, │ │ │ │ + "AuthorityURL": function(node, obj) { │ │ │ │ + var name = node.getAttribute("name"); │ │ │ │ + var authority = {}; │ │ │ │ + this.readChildNodes(node, authority); │ │ │ │ + obj.authorityURLs[name] = authority.href; │ │ │ │ + }, │ │ │ │ + "Identifier": function(node, obj) { │ │ │ │ + var authority = node.getAttribute("authority"); │ │ │ │ + obj.identifiers[authority] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "KeywordList": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "SRS": function(node, obj) { │ │ │ │ + obj.srs[this.getChildValue(node)] = true; │ │ │ │ + } │ │ │ │ } │ │ │ │ - options.callback.call(options.scope, response); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Method: parseData │ │ │ │ - * Read HTTP response body and return records │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * request - {XMLHttpRequest} The request object │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Object} The CSW records as returned by the call to the format read method. │ │ │ │ - */ │ │ │ │ - parseData: 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); │ │ │ │ - }, │ │ │ │ + }, │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.CSW.v2_0_2" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1" │ │ │ │ │ │ │ │ -}); │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/SOS/v1_0_0.js │ │ │ │ + OpenLayers/Format/WMSCapabilities/v1_1.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/SOS.js │ │ │ │ - * @requires OpenLayers/Format/SOSGetFeatureOfInterest.js │ │ │ │ + * @requires OpenLayers/Format/WMSCapabilities/v1.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.SOS.v1_0_0 │ │ │ │ - * An SOS v1.0.0 Protocol for vector layers. Create a new instance with the │ │ │ │ - * <OpenLayers.Protocol.SOS.v1_0_0> constructor. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.WMSCapabilities.v1_1 │ │ │ │ + * Abstract class not to be instantiated directly. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol> │ │ │ │ + * - <OpenLayers.Format.WMSCapabilities.v1> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol.SOS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * APIProperty: fois │ │ │ │ - * {Array(String)} Array of features of interest (foi) │ │ │ │ - */ │ │ │ │ - fois: null, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Protocol.SOS │ │ │ │ - * A class for giving layers an SOS 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). │ │ │ │ - * fois - {Array} The features of interest (required). │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ - if (!options.format) { │ │ │ │ - this.format = new OpenLayers.Format.SOSGetFeatureOfInterest( │ │ │ │ - this.formatOptions); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - │ │ │ │ - /** │ │ │ │ - * 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 sensor positions. This is done by │ │ │ │ - * issuing one GetFeatureOfInterest request. │ │ │ │ - */ │ │ │ │ - read: function(options) { │ │ │ │ - options = OpenLayers.Util.extend({}, options); │ │ │ │ - OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ - var response = new OpenLayers.Protocol.Response({ │ │ │ │ - requestType: "read" │ │ │ │ - }); │ │ │ │ - var format = this.format; │ │ │ │ - var data = OpenLayers.Format.XML.prototype.write.apply(format, │ │ │ │ - [format.writeNode("sos:GetFeatureOfInterest", { │ │ │ │ - fois: this.fois │ │ │ │ - })] │ │ │ │ - ); │ │ │ │ - response.priv = OpenLayers.Request.POST({ │ │ │ │ - url: options.url, │ │ │ │ - callback: this.createCallback(this.handleRead, response, options), │ │ │ │ - data: data │ │ │ │ - }); │ │ │ │ - return response; │ │ │ │ - }, │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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) { │ │ │ │ - if (options.callback) { │ │ │ │ - var request = response.priv; │ │ │ │ - if (request.status >= 200 && request.status < 300) { │ │ │ │ - // success │ │ │ │ - response.features = this.parseFeatures(request); │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ - } else { │ │ │ │ - // failure │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ - } │ │ │ │ - options.callback.call(options.scope, response); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ + "WMT_MS_Capabilities": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "Keyword": function(node, obj) { │ │ │ │ + if (obj.keywords) { │ │ │ │ + obj.keywords.push(this.getChildValue(node)); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "DescribeLayer": function(node, obj) { │ │ │ │ + obj.describelayer = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.describelayer); │ │ │ │ + }, │ │ │ │ + "GetLegendGraphic": function(node, obj) { │ │ │ │ + obj.getlegendgraphic = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getlegendgraphic); │ │ │ │ + }, │ │ │ │ + "GetStyles": function(node, obj) { │ │ │ │ + obj.getstyles = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getstyles); │ │ │ │ + }, │ │ │ │ + "PutStyles": function(node, obj) { │ │ │ │ + obj.putstyles = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.putstyles); │ │ │ │ + }, │ │ │ │ + "UserDefinedSymbolization": function(node, obj) { │ │ │ │ + var userSymbols = { │ │ │ │ + supportSLD: parseInt(node.getAttribute("SupportSLD")) == 1, │ │ │ │ + userLayer: parseInt(node.getAttribute("UserLayer")) == 1, │ │ │ │ + userStyle: parseInt(node.getAttribute("UserStyle")) == 1, │ │ │ │ + remoteWFS: parseInt(node.getAttribute("RemoteWFS")) == 1 │ │ │ │ + }; │ │ │ │ + obj.userSymbols = userSymbols; │ │ │ │ + }, │ │ │ │ + "LatLonBoundingBox": function(node, obj) { │ │ │ │ + obj.llbbox = [ │ │ │ │ + parseFloat(node.getAttribute("minx")), │ │ │ │ + parseFloat(node.getAttribute("miny")), │ │ │ │ + parseFloat(node.getAttribute("maxx")), │ │ │ │ + parseFloat(node.getAttribute("maxy")) │ │ │ │ + ]; │ │ │ │ + }, │ │ │ │ + "BoundingBox": function(node, obj) { │ │ │ │ + var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ + bbox.srs = node.getAttribute("SRS"); │ │ │ │ + obj.bbox[bbox.srs] = bbox; │ │ │ │ + }, │ │ │ │ + "ScaleHint": function(node, obj) { │ │ │ │ + var min = node.getAttribute("min"); │ │ │ │ + var max = node.getAttribute("max"); │ │ │ │ + var rad2 = Math.pow(2, 0.5); │ │ │ │ + var ipm = OpenLayers.INCHES_PER_UNIT["m"]; │ │ │ │ + if (min != 0) { │ │ │ │ + obj.maxScale = parseFloat( │ │ │ │ + ((min / rad2) * ipm * │ │ │ │ + OpenLayers.DOTS_PER_INCH).toPrecision(13) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + if (max != Number.POSITIVE_INFINITY) { │ │ │ │ + obj.minScale = parseFloat( │ │ │ │ + ((max / rad2) * ipm * │ │ │ │ + OpenLayers.DOTS_PER_INCH).toPrecision(13) │ │ │ │ + ); │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + "Dimension": function(node, obj) { │ │ │ │ + var name = node.getAttribute("name").toLowerCase(); │ │ │ │ + var dim = { │ │ │ │ + name: name, │ │ │ │ + units: node.getAttribute("units"), │ │ │ │ + unitsymbol: node.getAttribute("unitSymbol") │ │ │ │ + }; │ │ │ │ + obj.dimensions[dim.name] = dim; │ │ │ │ + }, │ │ │ │ + "Extent": function(node, obj) { │ │ │ │ + var name = node.getAttribute("name").toLowerCase(); │ │ │ │ + if (name in obj["dimensions"]) { │ │ │ │ + var extent = obj.dimensions[name]; │ │ │ │ + extent.nearestVal = │ │ │ │ + node.getAttribute("nearestValue") === "1"; │ │ │ │ + extent.multipleVal = │ │ │ │ + node.getAttribute("multipleValues") === "1"; │ │ │ │ + extent.current = node.getAttribute("current") === "1"; │ │ │ │ + extent["default"] = node.getAttribute("default") || ""; │ │ │ │ + var values = this.getChildValue(node); │ │ │ │ + extent.values = values.split(","); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]) │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Method: parseFeatures │ │ │ │ - * Read HTTP response body and return features │ │ │ │ - * │ │ │ │ - * Parameters: │ │ │ │ - * request - {XMLHttpRequest} The request object │ │ │ │ - * │ │ │ │ - * Returns: │ │ │ │ - * {Array({<OpenLayers.Feature.Vector>})} Array of features │ │ │ │ - */ │ │ │ │ - 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); │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.SOS.v1_0_0" │ │ │ │ -}); │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/WFS/v1.js │ │ │ │ + OpenLayers/Format/WMSCapabilities/v1_1_1.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 │ │ │ │ + * @requires OpenLayers/Format/WMSCapabilities/v1_1.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.WFS.v1 │ │ │ │ - * Abstract class for for v1.0.0 and v1.1.0 protocol. │ │ │ │ + * Class: OpenLayers.Format.WMSCapabilities/v1_1_1 │ │ │ │ + * Read WMS Capabilities version 1.1.1. │ │ │ │ * │ │ │ │ + * Note on <ScaleHint> parsing: If the 'min' attribute is set to "0", no │ │ │ │ + * maxScale will be set on the layer object. If the 'max' attribute is set to │ │ │ │ + * "Infinity", no minScale will be set. This makes it easy to create proper │ │ │ │ + * {<OpenLayers.Layer.WMS>} configurations directly from the layer object │ │ │ │ + * literals returned by this format, because no minScale/maxScale modifications │ │ │ │ + * need to be made. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol> │ │ │ │ + * - <OpenLayers.Format.WMSCapabilities.v1_1> │ │ │ │ */ │ │ │ │ -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, │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1_1 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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: version │ │ │ │ + * {String} The specific parser version. │ │ │ │ + */ │ │ │ │ + version: "1.1.1", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: readOptions │ │ │ │ - * {Object} Optional object to pass to format's read. │ │ │ │ - */ │ │ │ │ - readOptions: null, │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_1 │ │ │ │ + * Create a new parser for WMS capabilities version 1.1.1. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ + "SRS": function(node, obj) { │ │ │ │ + obj.srs[this.getChildValue(node)] = true; │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1" │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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" │ │ │ │ - }); │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WMSCapabilities/v1_1_1_WMSC.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - var data = OpenLayers.Format.XML.prototype.write.apply( │ │ │ │ - this.format, [this.format.writeNode("wfs:GetFeature", options)] │ │ │ │ - ); │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - response.priv = OpenLayers.Request.POST({ │ │ │ │ - url: options.url, │ │ │ │ - callback: this.createCallback(this.handleRead, response, options), │ │ │ │ - params: options.params, │ │ │ │ - headers: options.headers, │ │ │ │ - data: data │ │ │ │ - }); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/WMSCapabilities/v1_1_1.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - return response; │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WMSCapabilities/v1_1_1_WMSC │ │ │ │ + * Read WMS-C Capabilities version 1.1.1. │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.WMSCapabilities.v1_1_1> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WMSCapabilities.v1_1_1, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} The specific parser version. │ │ │ │ + */ │ │ │ │ + version: "1.1.1", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: profile │ │ │ │ + * {String} The specific profile │ │ │ │ + */ │ │ │ │ + profile: "WMSC", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_1 │ │ │ │ + * Create a new parser for WMS-C capabilities version 1.1.1. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ │ │ │ │ - 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; │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ + "VendorSpecificCapabilities": function(node, obj) { │ │ │ │ + obj.vendorSpecific = { │ │ │ │ + tileSets: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.vendorSpecific); │ │ │ │ + }, │ │ │ │ + "TileSet": function(node, vendorSpecific) { │ │ │ │ + var tileset = { │ │ │ │ + srs: {}, │ │ │ │ + bbox: {}, │ │ │ │ + resolutions: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, tileset); │ │ │ │ + vendorSpecific.tileSets.push(tileset); │ │ │ │ + }, │ │ │ │ + "Resolutions": function(node, tileset) { │ │ │ │ + var res = this.getChildValue(node).split(" "); │ │ │ │ + for (var i = 0, len = res.length; i < len; i++) { │ │ │ │ + if (res[i] != "") { │ │ │ │ + tileset.resolutions.push(parseFloat(res[i])); │ │ │ │ + } │ │ │ │ } │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS; │ │ │ │ - } else { │ │ │ │ - // failure (service exception) │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ - response.error = result; │ │ │ │ + }, │ │ │ │ + "Width": function(node, tileset) { │ │ │ │ + tileset.width = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "Height": function(node, tileset) { │ │ │ │ + tileset.height = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "Layers": function(node, tileset) { │ │ │ │ + tileset.layers = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "Styles": function(node, tileset) { │ │ │ │ + tileset.styles = this.getChildValue(node); │ │ │ │ } │ │ │ │ - } 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; │ │ │ │ - }, │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1_1_1.prototype.readers["wms"]) │ │ │ │ + }, │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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; │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC" │ │ │ │ │ │ │ │ - // ensure that we have an xml doc │ │ │ │ - var data = request.responseXML; │ │ │ │ - if (!data || !data.documentElement) { │ │ │ │ - data = request.responseText; │ │ │ │ - } │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WMSCapabilities/v1_3.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - var obj = this.format.read(data) || {}; │ │ │ │ +/* 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. */ │ │ │ │ │ │ │ │ - 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); │ │ │ │ - } │ │ │ │ - }, │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/WMSCapabilities/v1.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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); │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WMSCapabilities/v1_3 │ │ │ │ + * Abstract base class for WMS Capabilities version 1.3.X. │ │ │ │ + * SLD 1.1.0 adds in the extra operations DescribeLayer and GetLegendGraphic, │ │ │ │ + * see: http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.WMSCapabilities.v1> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_3 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ │ │ │ │ - var response = new OpenLayers.Protocol.Response({ │ │ │ │ - requestType: "commit" │ │ │ │ - }); │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ + "WMS_Capabilities": function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + }, │ │ │ │ + "LayerLimit": function(node, obj) { │ │ │ │ + obj.layerLimit = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "MaxWidth": function(node, obj) { │ │ │ │ + obj.maxWidth = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "MaxHeight": function(node, obj) { │ │ │ │ + obj.maxHeight = parseInt(this.getChildValue(node)); │ │ │ │ + }, │ │ │ │ + "BoundingBox": function(node, obj) { │ │ │ │ + var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ + bbox.srs = node.getAttribute("CRS"); │ │ │ │ + obj.bbox[bbox.srs] = bbox; │ │ │ │ + }, │ │ │ │ + "CRS": function(node, obj) { │ │ │ │ + // CRS is the synonym of SRS │ │ │ │ + this.readers.wms.SRS.apply(this, [node, obj]); │ │ │ │ + }, │ │ │ │ + "EX_GeographicBoundingBox": function(node, obj) { │ │ │ │ + // replacement of LatLonBoundingBox │ │ │ │ + obj.llbbox = []; │ │ │ │ + this.readChildNodes(node, obj.llbbox); │ │ │ │ │ │ │ │ - var root = this.format.createElementNSPlus("wfs:Transaction", { │ │ │ │ - attributes: { │ │ │ │ - service: "WFS", │ │ │ │ - version: this.version │ │ │ │ - } │ │ │ │ - }); │ │ │ │ + }, │ │ │ │ + "westBoundLongitude": function(node, obj) { │ │ │ │ + obj[0] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "eastBoundLongitude": function(node, obj) { │ │ │ │ + obj[2] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "southBoundLatitude": function(node, obj) { │ │ │ │ + obj[1] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "northBoundLatitude": function(node, obj) { │ │ │ │ + obj[3] = this.getChildValue(node); │ │ │ │ + }, │ │ │ │ + "MinScaleDenominator": function(node, obj) { │ │ │ │ + obj.maxScale = parseFloat(this.getChildValue(node)).toPrecision(16); │ │ │ │ + }, │ │ │ │ + "MaxScaleDenominator": function(node, obj) { │ │ │ │ + obj.minScale = parseFloat(this.getChildValue(node)).toPrecision(16); │ │ │ │ + }, │ │ │ │ + "Dimension": function(node, obj) { │ │ │ │ + // dimension has extra attributes: default, multipleValues, │ │ │ │ + // nearestValue, current which used to be part of Extent. It now │ │ │ │ + // also contains the values. │ │ │ │ + var name = node.getAttribute("name").toLowerCase(); │ │ │ │ + var dim = { │ │ │ │ + name: name, │ │ │ │ + units: node.getAttribute("units"), │ │ │ │ + unitsymbol: node.getAttribute("unitSymbol"), │ │ │ │ + nearestVal: node.getAttribute("nearestValue") === "1", │ │ │ │ + multipleVal: node.getAttribute("multipleValues") === "1", │ │ │ │ + "default": node.getAttribute("default") || "", │ │ │ │ + current: node.getAttribute("current") === "1", │ │ │ │ + values: this.getChildValue(node).split(",") │ │ │ │ │ │ │ │ - var deleteNode = this.format.createElementNSPlus("wfs:Delete", { │ │ │ │ - attributes: { │ │ │ │ - typeName: (options.featureNS ? this.featurePrefix + ":" : "") + │ │ │ │ - options.featureType │ │ │ │ + }; │ │ │ │ + // Theoretically there can be more dimensions with the same │ │ │ │ + // name, but with a different unit. Until we meet such a case, │ │ │ │ + // let's just keep the same structure as the WMS 1.1 │ │ │ │ + // GetCapabilities parser uses. We will store the last │ │ │ │ + // one encountered. │ │ │ │ + obj.dimensions[dim.name] = dim; │ │ │ │ + }, │ │ │ │ + "Keyword": function(node, obj) { │ │ │ │ + // TODO: should we change the structure of keyword in v1.js? │ │ │ │ + // Make it an object with a value instead of a string? │ │ │ │ + var keyword = { │ │ │ │ + value: this.getChildValue(node), │ │ │ │ + vocabulary: node.getAttribute("vocabulary") │ │ │ │ + }; │ │ │ │ + if (obj.keywords) { │ │ │ │ + obj.keywords.push(keyword); │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]), │ │ │ │ + "sld": { │ │ │ │ + "UserDefinedSymbolization": function(node, obj) { │ │ │ │ + this.readers.wms.UserDefinedSymbolization.apply(this, [node, obj]); │ │ │ │ + // add the two extra attributes │ │ │ │ + obj.userSymbols.inlineFeature = parseInt(node.getAttribute("InlineFeature")) == 1; │ │ │ │ + obj.userSymbols.remoteWCS = parseInt(node.getAttribute("RemoteWCS")) == 1; │ │ │ │ + }, │ │ │ │ + "DescribeLayer": function(node, obj) { │ │ │ │ + this.readers.wms.DescribeLayer.apply(this, [node, obj]); │ │ │ │ + }, │ │ │ │ + "GetLegendGraphic": function(node, obj) { │ │ │ │ + this.readers.wms.GetLegendGraphic.apply(this, [node, obj]); │ │ │ │ + } │ │ │ │ } │ │ │ │ - }); │ │ │ │ + }, │ │ │ │ │ │ │ │ - if (options.featureNS) { │ │ │ │ - deleteNode.setAttribute("xmlns:" + this.featurePrefix, options.featureNS); │ │ │ │ - } │ │ │ │ - var filterNode = this.format.writeNode("ogc:Filter", filter); │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3" │ │ │ │ │ │ │ │ - deleteNode.appendChild(filterNode); │ │ │ │ + }); │ │ │ │ +/* ====================================================================== │ │ │ │ + OpenLayers/Format/WMSCapabilities/v1_3_0.js │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ - root.appendChild(deleteNode); │ │ │ │ +/* 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 data = OpenLayers.Format.XML.prototype.write.apply( │ │ │ │ - this.format, [root] │ │ │ │ - ); │ │ │ │ +/** │ │ │ │ + * @requires OpenLayers/Format/WMSCapabilities/v1_3.js │ │ │ │ + */ │ │ │ │ │ │ │ │ - return OpenLayers.Request.POST({ │ │ │ │ - url: this.url, │ │ │ │ - callback: options.callback || function() {}, │ │ │ │ - data: data │ │ │ │ - }); │ │ │ │ +/** │ │ │ │ + * Class: OpenLayers.Format.WMSCapabilities/v1_3_0 │ │ │ │ + * Read WMS Capabilities version 1.3.0. │ │ │ │ + * SLD 1.1.0 adds in the extra operations DescribeLayer and GetLegendGraphic, │ │ │ │ + * see: http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd │ │ │ │ + * │ │ │ │ + * Inherits from: │ │ │ │ + * - <OpenLayers.Format.WMSCapabilities.v1_3> │ │ │ │ + */ │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_3_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WMSCapabilities.v1_3, { │ │ │ │ │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} The specific parser version. │ │ │ │ + */ │ │ │ │ + version: "1.3.0", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * 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.Format.WMSCapabilities.v1_3_0" │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.WFS.v1" │ │ │ │ -}); │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/WFS/v1_1_0.js │ │ │ │ + OpenLayers/Format/WMSCapabilities/v1_1_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_1_0.js │ │ │ │ + * @requires OpenLayers/Format/WMSCapabilities/v1_1.js │ │ │ │ */ │ │ │ │ │ │ │ │ /** │ │ │ │ - * Class: OpenLayers.Protocol.WFS.v1_1_0 │ │ │ │ - * A WFS v1.1.0 protocol for vector layers. Create a new instance with the │ │ │ │ - * <OpenLayers.Protocol.WFS.v1_1_0> constructor. │ │ │ │ - * │ │ │ │ - * Differences from the v1.0.0 protocol: │ │ │ │ - * - uses Filter Encoding 1.1.0 instead of 1.0.0 │ │ │ │ - * - uses GML 3 instead of 2 if no format is provided │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.WMSCapabilities/v1_1_0 │ │ │ │ + * Read WMS Capabilities version 1.1.0. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol.WFS.v1> │ │ │ │ + * - <OpenLayers.Format.WMSCapabilities.v1_1> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol.WFS.v1_1_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1_0 = OpenLayers.Class( │ │ │ │ + OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Property: version │ │ │ │ - * {String} WFS version number. │ │ │ │ - */ │ │ │ │ - version: "1.1.0", │ │ │ │ + /** │ │ │ │ + * Property: version │ │ │ │ + * {String} The specific parser version. │ │ │ │ + */ │ │ │ │ + version: "1.1.0", │ │ │ │ │ │ │ │ - /** │ │ │ │ - * Constructor: OpenLayers.Protocol.WFS.v1_1_0 │ │ │ │ - * A class for giving layers WFS v1.1.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'. │ │ │ │ - * outputFormat - {String} Optional output format to use for WFS GetFeature │ │ │ │ - * requests. This can be any format advertized by the WFS's │ │ │ │ - * GetCapabilities response. If set, an appropriate readFormat also │ │ │ │ - * has to be provided, unless outputFormat is GML3, GML2 or JSON. │ │ │ │ - * readFormat - {<OpenLayers.Format>} An appropriate format parser if │ │ │ │ - * outputFormat is none of GML3, GML2 or JSON. │ │ │ │ - */ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Protocol.WFS.v1.prototype.initialize.apply(this, arguments); │ │ │ │ - if (this.outputFormat && !this.readFormat) { │ │ │ │ - if (this.outputFormat.toLowerCase() == "gml2") { │ │ │ │ - this.readFormat = new OpenLayers.Format.GML.v2({ │ │ │ │ - featureType: this.featureType, │ │ │ │ - featureNS: this.featureNS, │ │ │ │ - geometryName: this.geometryName │ │ │ │ - }); │ │ │ │ - } else if (this.outputFormat.toLowerCase() == "json") { │ │ │ │ - this.readFormat = new OpenLayers.Format.GeoJSON(); │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ + /** │ │ │ │ + * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_0 │ │ │ │ + * Create a new parser for WMS capabilities version 1.1.0. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ + */ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.WFS.v1_1_0" │ │ │ │ -}); │ │ │ │ + /** │ │ │ │ + * 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: { │ │ │ │ + "wms": OpenLayers.Util.applyDefaults({ │ │ │ │ + "SRS": function(node, obj) { │ │ │ │ + var srs = this.getChildValue(node); │ │ │ │ + var values = srs.split(/ +/); │ │ │ │ + for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ + obj.srs[values[i]] = true; │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ + }, │ │ │ │ + │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_0" │ │ │ │ + │ │ │ │ + }); │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Protocol/WFS/v1_0_0.js │ │ │ │ + OpenLayers/Format/ArcXML/Features.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 │ │ │ │ + * @requires OpenLayers/Format/ArcXML.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. │ │ │ │ - * │ │ │ │ + * Class: OpenLayers.Format.ArcXML.Features │ │ │ │ + * Read/Write ArcXML features. Create a new instance with the │ │ │ │ + * <OpenLayers.Format.ArcXML.Features> constructor. │ │ │ │ + * │ │ │ │ * Inherits from: │ │ │ │ - * - <OpenLayers.Protocol.WFS.v1> │ │ │ │ + * - <OpenLayers.Format.XML> │ │ │ │ */ │ │ │ │ -OpenLayers.Protocol.WFS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ +OpenLayers.Format.ArcXML.Features = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ │ │ │ /** │ │ │ │ - * Property: version │ │ │ │ - * {String} WFS version number. │ │ │ │ + * Constructor: OpenLayers.Format.ArcXML.Features │ │ │ │ + * Create a new parser/writer for ArcXML Features. Create an instance of this class │ │ │ │ + * to get a set of features from an ArcXML response. │ │ │ │ + * │ │ │ │ + * Parameters: │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ + * this instance. │ │ │ │ */ │ │ │ │ - version: "1.0.0", │ │ │ │ │ │ │ │ /** │ │ │ │ - * Constructor: OpenLayers.Protocol.WFS.v1_0_0 │ │ │ │ - * A class for giving layers WFS v1.0.0 protocol. │ │ │ │ - * │ │ │ │ + * APIMethod: read │ │ │ │ + * Read data from a string of ArcXML, and return a set of OpenLayers features. │ │ │ │ + * │ │ │ │ * Parameters: │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ - * instance. │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ * │ │ │ │ - * 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'. │ │ │ │ + * Returns: │ │ │ │ + * {Array(<OpenLayers.Feature.Vector>)} A collection of features. │ │ │ │ */ │ │ │ │ + read: function(data) { │ │ │ │ + var axl = new OpenLayers.Format.ArcXML(); │ │ │ │ + var parsed = axl.read(data); │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.WFS.v1_0_0" │ │ │ │ + return parsed.features.feature; │ │ │ │ + } │ │ │ │ }); │ │ │ │ /* ====================================================================== │ │ │ │ OpenLayers/Events/featureclick.js │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ @@ -91941,2461 +94388,14 @@ │ │ │ │ * Extension event type for handling leaving a feature. │ │ │ │ * │ │ │ │ * Event types provided by this extension: │ │ │ │ * - featureout │ │ │ │ */ │ │ │ │ OpenLayers.Events.featureout = OpenLayers.Events.featureclick; │ │ │ │ /* ====================================================================== │ │ │ │ - OpenLayers/Lang/en.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["en"] │ │ │ │ - * Dictionary for English. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang.en = { │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Unhandled request return ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Permalink", │ │ │ │ - │ │ │ │ - 'Overlays': "Overlays", │ │ │ │ - │ │ │ │ - 'Base Layer': "Base Layer", │ │ │ │ - │ │ │ │ - 'noFID': "Can't update a feature for which there is no FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'minZoomLevelError': "The minZoomLevel property is only intended for use " + │ │ │ │ - "with the FixedZoomLevels-descendent layers. That this " + │ │ │ │ - "wfs layer checks for minZoomLevel is a relic of the" + │ │ │ │ - "past. We cannot, however, remove it without possibly " + │ │ │ │ - "breaking OL based applications that may depend on it." + │ │ │ │ - " Therefore we are deprecating it -- the minZoomLevel " + │ │ │ │ - "check below will be removed at 3.0. Please instead " + │ │ │ │ - "use min/max resolution setting as described here: " + │ │ │ │ - "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS Transaction: SUCCESS ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS Transaction: FAILED ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "The Google Layer was unable to load correctly.<br><br>" + │ │ │ │ - "To get rid of this message, select a new BaseLayer " + │ │ │ │ - "in the layer switcher in the upper-right corner.<br><br>" + │ │ │ │ - "Most likely, this is because the Google Maps library " + │ │ │ │ - "script was either not included, or does not contain the " + │ │ │ │ - "correct API key for your site.<br><br>" + │ │ │ │ - "Developers: For help getting this working correctly, " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ - "target='_blank'>click here</a>", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "The ${layerType} Layer was unable to load correctly.<br><br>" + │ │ │ │ - "To get rid of this message, select a new BaseLayer " + │ │ │ │ - "in the layer switcher in the upper-right corner.<br><br>" + │ │ │ │ - "Most likely, this is because the ${layerLib} library " + │ │ │ │ - "script was not correctly included.<br><br>" + │ │ │ │ - "Developers: For help getting this working correctly, " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ - "target='_blank'>click here</a>", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Scale = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - //labels for the graticule control │ │ │ │ - 'W': 'W', │ │ │ │ - 'E': 'E', │ │ │ │ - 'N': 'N', │ │ │ │ - 'S': 'S', │ │ │ │ - 'Graticule': 'Graticule', │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'reprojectDeprecated': "You are using the 'reproject' option " + │ │ │ │ - "on the ${layerName} layer. This option is deprecated: " + │ │ │ │ - "its use was designed to support displaying data over commercial " + │ │ │ │ - "basemaps, but that functionality should now be achieved by using " + │ │ │ │ - "Spherical Mercator support. More information is available from " + │ │ │ │ - "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'methodDeprecated': "This method has been deprecated and will be removed in 3.0. " + │ │ │ │ - "Please use ${newMethod} instead.", │ │ │ │ - │ │ │ │ - // **** end **** │ │ │ │ - 'end': '' │ │ │ │ - │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/oc.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Cedric31 │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["oc"] │ │ │ │ - * Dictionary for Occitan. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["oc"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Requèsta pas gerida, retorna ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Permaligam", │ │ │ │ - │ │ │ │ - 'Overlays': "Calques", │ │ │ │ - │ │ │ │ - 'Base Layer': "Calc de basa", │ │ │ │ - │ │ │ │ - 'noFID': "Impossible de metre a jorn un objècte sens identificant (fid).", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Vòstre navegidor supòrta pas lo rendut vectorial. Los renderers actualament suportats son : \n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "La proprietat minZoomLevel deu èsser utilizada solament per de jaces FixedZoomLevels-descendent. Lo fach qu\'aqueste jaç WFS verifique la preséncia de minZoomLevel es una relica del passat. Çaquelà, la podèm suprimir sens copar d\'aplicacions que ne poirián dependre. Es per aquò que la depreciam -- la verificacion del minZoomLevel serà suprimida en version 3.0. A la plaça, mercés d\'utilizar los paramètres de resolucions min/max tal coma descrich sus : http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "Transaccion WFS : SUCCES ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "Transaccion WFS : FRACAS ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Lo jaç Google es pas estat en mesura de se cargar corrèctament.\x3cbr\x3e\x3cbr\x3ePer suprimir aqueste messatge, causissètz una BaseLayer novèla dins lo selector de jaç en naut a drecha.\x3cbr\x3e\x3cbr\x3eAquò es possiblament causat par la non-inclusion de la librariá Google Maps, o alara perque que la clau de l\'API correspond pas a vòstre site.\x3cbr\x3e\x3cbr\x3eDesvolopaires : per saber cossí corregir aquò, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclicatz aicí\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "Lo jaç ${layerType} es pas en mesura de se cargar corrèctament.\x3cbr\x3e\x3cbr\x3ePer suprimir aqueste messatge, causissètz una BaseLayer novèla dins lo selector de jaç en naut a drecha.\x3cbr\x3e\x3cbr\x3eAquò es possiblament causat per la non-inclusion de la librariá ${layerLib}.\x3cbr\x3e\x3cbr\x3eDesvolopaires : per saber cossí corregir aquí, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclicatz aicí\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Escala ~ 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "O", │ │ │ │ - │ │ │ │ - 'E': "È", │ │ │ │ - │ │ │ │ - 'N': "N", │ │ │ │ - │ │ │ │ - 'S': "S", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Utilizatz l\'opcion \'reproject\' sul jaç ${layerName}. Aquesta opcion es despreciada : Son usatge permetiá d\'afichar de donadas al dessús de jaces raster comercials. Aquesta foncionalitat ara es suportada en utilizant lo supòrt de la projeccion Mercator Esferica. Mai d\'informacion es disponibla sus http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Aqueste metòde es despreciada, e serà suprimida a la version 3.0. Mercés d\'utilizar ${newMethod} a la plaça." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/zh-TW.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["zh-TW"] │ │ │ │ - * Dictionary for Traditional Chinese. (Used Mainly in Taiwan) │ │ │ │ - * Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["zh-TW"] = { │ │ │ │ - │ │ │ │ - 'unhandledRequest': "未處理的請求,傳回值為 ${statusText}。", │ │ │ │ - │ │ │ │ - 'Permalink': "永久連結", │ │ │ │ - │ │ │ │ - 'Overlays': "額外圖層", │ │ │ │ - │ │ │ │ - 'Base Layer': "基礎圖層", │ │ │ │ - │ │ │ │ - 'noFID': "因為沒有 FID 所以無法更新 feature。", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "您的瀏覽器未支援向量渲染. 目前支援的渲染方式是:\n${renderers}", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'minZoomLevelError': "minZoomLevel 屬性僅適合用在 " + │ │ │ │ - "FixedZoomLevels-descendent 類型的圖層. 這個" + │ │ │ │ - "wfs layer 的 minZoomLevel 是過去所遺留下來的," + │ │ │ │ - "然而我們不能移除它而不讓它將" + │ │ │ │ - "過去的程式相容性給破壞掉。" + │ │ │ │ - "因此我們將會迴避使用它 -- minZoomLevel " + │ │ │ │ - "會在3.0被移除,請改" + │ │ │ │ - "用在這邊描述的 min/max resolution 設定: " + │ │ │ │ - "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS Transaction: 成功 ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS Transaction: 失敗 ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "The Google Layer 圖層無法被正確的載入。<br><br>" + │ │ │ │ - "要迴避這個訊息, 請在右上角的圖層改變器裡," + │ │ │ │ - "選一個新的基礎圖層。<br><br>" + │ │ │ │ - "很有可能是因為 Google Maps 的函式庫" + │ │ │ │ - "腳本沒有被正確的置入,或沒有包含 " + │ │ │ │ - "您網站上正確的 API key <br><br>" + │ │ │ │ - "開發者: 要幫助這個行為正確完成," + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ - "target='_blank'>請按這裡</a>", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "${layerType} 圖層無法被正確的載入。<br><br>" + │ │ │ │ - "要迴避這個訊息, 請在右上角的圖層改變器裡," + │ │ │ │ - "選一個新的基礎圖層。<br><br>" + │ │ │ │ - "很有可能是因為 ${layerLib} 的函式庫" + │ │ │ │ - "腳本沒有被正確的置入。<br><br>" + │ │ │ │ - "開發者: 要幫助這個行為正確完成," + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ - "target='_blank'>請按這裡</a>", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Scale = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'reprojectDeprecated': "你正使用 'reproject' 這個選項 " + │ │ │ │ - "在 ${layerName} 層。這個選項已經不再使用:" + │ │ │ │ - "它的使用原本是設計用來支援在商業地圖上秀出資料," + │ │ │ │ - "但這個功能已經被" + │ │ │ │ - "Spherical Mercator所取代。更多的資訊可以在 " + │ │ │ │ - "http://trac.openlayers.org/wiki/SphericalMercator 找到。", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'methodDeprecated': "這個方法已經不再使用且在3.0將會被移除," + │ │ │ │ - "請使用 ${newMethod} 來代替。", │ │ │ │ - │ │ │ │ - 'end': '' │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/sk.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Helix84 │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["sk"] │ │ │ │ - * Dictionary for Slovenčina. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["sk"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Neobslúžené požiadavky vracajú ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Trvalý odkaz", │ │ │ │ - │ │ │ │ - 'Overlays': "Prekrytia", │ │ │ │ - │ │ │ │ - 'Base Layer': "Základná vrstva", │ │ │ │ - │ │ │ │ - 'noFID': "Nie je možné aktualizovať vlastnosť, pre ktorú neexistuje FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Váš prehliadač nepodporuje vykresľovanie vektorov. Momentálne podporované vykresľovače sú:\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "Vlastnosť minZoomLevel je určený iba na použitie s vrstvami odvodenými od FixedZoomLevels. To, že táto wfs vrstva kontroluje minZoomLevel je pozostatok z minulosti. Nemôžeme ho však odstrániť, aby sme sa vyhli možnému porušeniu aplikácií založených na Open Layers, ktoré na tomto môže závisieť. Preto ho označujeme ako zavrhovaný - dolu uvedená kontrola minZoomLevel bude odstránená vo verzii 3.0. Použite prosím namiesto toho kontrolu min./max. rozlíšenia podľa tu uvedeného popisu: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "Transakcia WFS: ÚSPEŠNÁ ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "Transakcia WFS: ZLYHALA ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Vrstvu Google nebolo možné správne načítať.\x3cbr\x3e\x3cbr\x3eAby ste sa tejto správy zbavili vyberte novú BaseLayer v prepínači vrstiev v pravom hornom rohu.\x3cbr\x3e\x3cbr\x3eToto sa stalo pravdepodobne preto, že skript knižnice Google Maps buď nebol načítaný alebo neobsahuje správny kľúč API pre vašu lokalitu.\x3cbr\x3e\x3cbr\x3eVývojári: Tu môžete získať \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3epomoc so sfunkčnením\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "Vrstvu ${layerType} nebolo možné správne načítať.\x3cbr\x3e\x3cbr\x3eAby ste sa tejto správy zbavili vyberte novú BaseLayer v prepínači vrstiev v pravom hornom rohu.\x3cbr\x3e\x3cbr\x3eToto sa stalo pravdepodobne preto, že skript knižnice ${layerType} buď nebol načítaný alebo neobsahuje správny kľúč API pre vašu lokalitu.\x3cbr\x3e\x3cbr\x3eVývojári: Tu môžete získať \x3ca href=\'http://trac.openlayers.org/wiki/${layerType}\' target=\'_blank\'\x3epomoc so sfunkčnením\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Mierka = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Používate voľby „reproject“ vrstvy ${layerType}. Táto voľba je zzavrhovaná: jej použitie bolo navrhnuté na podporu zobrazovania údajov nad komerčnými základovými mapami, ale túto funkcionalitu je teraz možné dosiahnuť pomocou Spherical Mercator. Ďalšie informácie získate na stránke http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Táto metóda je zavrhovaná a bude odstránená vo verzii 3.0. Použite prosím namiesto nej metódu ${newMethod}." │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/gl.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Toliño │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["gl"] │ │ │ │ - * Dictionary for Galego. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["gl"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Solicitude non xerada; a resposta foi: ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Ligazón permanente", │ │ │ │ - │ │ │ │ - 'Overlays': "Capas superpostas", │ │ │ │ - │ │ │ │ - 'Base Layer': "Capa base", │ │ │ │ - │ │ │ │ - 'noFID': "Non se pode actualizar a funcionalidade para a que non hai FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "O seu navegador non soporta a renderización de vectores. Os renderizadores soportados actualmente son:\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "A propiedade minZoomLevel é só para uso conxuntamente coas capas FixedZoomLevels-descendent. O feito de que esa capa wfs verifique o minZoomLevel é unha reliquia do pasado. Non podemos, con todo, eliminala sen a posibilidade de non romper as aplicacións baseadas en OL que poidan depender dela. Por iso a estamos deixando obsoleta (a comprobación minZoomLevel de embaixo será eliminada na versión 3.0). Por favor, no canto diso use o axuste de resolución mín/máx tal e como está descrito aquí: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "Transacción WFS: ÉXITO ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "Transacción WFS: FALLIDA ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "A capa do Google non puido cargarse correctamente.\x3cbr\x3e\x3cbr\x3ePara evitar esta mensaxe, escolla unha nova capa base no seleccionador de capas na marxe superior dereita.\x3cbr\x3e\x3cbr\x3eProbablemente, isto acontece porque a escritura da libraría do Google Maps ou ben non foi incluída ou ben non contén a clave API correcta para o seu sitio.\x3cbr\x3e\x3cbr\x3eDesenvolvedores: para axudar a facer funcionar isto correctamente, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3epremede aquí\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "A capa ${layerType} foi incapaz de cargarse correctamente.\x3cbr\x3e\x3cbr\x3ePara evitar esta mensaxe, escolla unha nova capa base no seleccionador de capas na marxe superior dereita.\x3cbr\x3e\x3cbr\x3eProbablemente, isto acontece porque a escritura da libraría ${layerLib} non foi ben incluída.\x3cbr\x3e\x3cbr\x3eDesenvolvedores: para axudar a facer funcionar isto correctamente, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3epremede aquí\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Escala = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "O", │ │ │ │ - │ │ │ │ - 'E': "L", │ │ │ │ - │ │ │ │ - 'N': "N", │ │ │ │ - │ │ │ │ - 'S': "S", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Está usando a opción \"reproject\" na capa ${layerName}. Esta opción está obsoleta: o seu uso foi deseñado para a visualización de datos sobre mapas base comerciais, pero esta funcionalidade debera agora ser obtida utilizando a proxección Spherical Mercator. Hai dispoñible máis información en http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Este método está obsoleto e será eliminado na versión 3.0. Por favor, no canto deste use ${newMethod}." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/nb.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["nb"] │ │ │ │ - * Dictionary for norwegian bokmål (Norway). Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["nb"] = { │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Ubehandlet forespørsel returnerte ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Kobling til denne siden", │ │ │ │ - │ │ │ │ - 'Overlays': "Kartlag", │ │ │ │ - │ │ │ │ - 'Base Layer': "Bakgrunnskart", │ │ │ │ - │ │ │ │ - 'noFID': "Kan ikke oppdatere et feature (et objekt) som ikke har FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Din nettleser støtter ikke vektortegning. Tegnemetodene som støttes er:\n${renderers}", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'minZoomLevelError': "Egenskapen minZoomLevel er kun ment til bruk på lag " + │ │ │ │ - "basert på FixedZoomLevels. At dette wfs-laget sjekker " + │ │ │ │ - "minZoomLevel er en etterlevning fra tidligere versjoner. Det kan dog ikke " + │ │ │ │ - "tas bort uten å risikere at OL-baserte applikasjoner " + │ │ │ │ - "slutter å virke, så det er merket som foreldet: " + │ │ │ │ - "minZoomLevel i sjekken nedenfor vil fjernes i 3.0. " + │ │ │ │ - "Vennligst bruk innstillingene for min/maks oppløsning " + │ │ │ │ - "som er beskrevet her: " + │ │ │ │ - "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS-transaksjon: LYKTES ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS-transaksjon: MISLYKTES ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Google-laget kunne ikke lastes.<br><br>" + │ │ │ │ - "Bytt til et annet bakgrunnslag i lagvelgeren i " + │ │ │ │ - "øvre høyre hjørne for å slippe denne meldingen.<br><br>" + │ │ │ │ - "Sannsynligvis forårsakes feilen av at Google Maps-biblioteket " + │ │ │ │ - "ikke er riktig inkludert på nettsiden, eller at det ikke er " + │ │ │ │ - "angitt riktig API-nøkkel for nettstedet.<br><br>" + │ │ │ │ - "Utviklere: For hjelp til å få dette til å virke se " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ - "target='_blank'>her</a>.", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "${layerType}-laget kunne ikke lastes.<br><br>" + │ │ │ │ - "Bytt til et annet bakgrunnslag i lagvelgeren i " + │ │ │ │ - "øvre høyre hjørne for å slippe denne meldingen.<br><br>" + │ │ │ │ - "Sannsynligvis forårsakes feilen av at " + │ │ │ │ - "${layerLib}-biblioteket ikke var riktig inkludert " + │ │ │ │ - "på nettsiden.<br><br>" + │ │ │ │ - "Utviklere: For hjelp til å få dette til å virke se " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ - "target='_blank'>her</a>.", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "<strong>Skala</strong> 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'reprojectDeprecated': "Du bruker innstillingen 'reproject' på laget ${layerName}. " + │ │ │ │ - "Denne innstillingen er foreldet, den var ment for å støtte " + │ │ │ │ - "visning av kartdata over kommersielle bakgrunnskart, men det " + │ │ │ │ - "bør nå gjøres med støtten for Spherical Mercator. Mer informasjon " + │ │ │ │ - "finnes på http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'methodDeprecated': "Denne metoden er markert som foreldet og vil bli fjernet i 3.0. " + │ │ │ │ - "Vennligst bruk ${newMethod} i stedet.", │ │ │ │ - │ │ │ │ - 'end': '' │ │ │ │ -}; │ │ │ │ - │ │ │ │ -OpenLayers.Lang["no"] = OpenLayers.Lang["nb"]; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/cs-CZ.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Mormegil │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["cs-CZ"] │ │ │ │ - * Dictionary for Česky. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["cs-CZ"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Nezpracovaná návratová hodnota ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Trvalý odkaz", │ │ │ │ - │ │ │ │ - 'Overlays': "Překryvné vrstvy", │ │ │ │ - │ │ │ │ - 'Base Layer': "Podkladové vrstvy", │ │ │ │ - │ │ │ │ - 'noFID': "Nelze aktualizovat prvek, pro který neexistuje FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Váš prohlížeč nepodporuje vykreslování vektorů. Momentálně podporované nástroje jsou::\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "Vlastnost minZoomLevel by se měla používat pouze s potomky FixedZoomLevels vrstvami. To znamená, že vrstva wfs kontroluje, zda-li minZoomLevel není zbytek z minulosti.Nelze to ovšem vyjmout bez možnosti, že bychom rozbili aplikace postavené na OL, které by na tom mohly záviset. Proto tuto vlastnost nedoporučujeme používat -- kontrola minZoomLevel bude odstraněna ve verzi 3.0. Použijte prosím raději nastavení min/max podle příkaldu popsaného na: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS Transaction: ÚSPĚCH ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS Transaction: CHYBA ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Nepodařilo se správně načíst vrstvu Google.\x3cbr\x3e\x3cbr\x3eAbyste se zbavili této zprávy, zvolte jinou základní vrstvu v přepínači vrstev.\x3cbr\x3e\x3cbr\x3eTo se většinou stává, pokud nebyl načten skript, nebo neobsahuje správný klíč pro API pro tuto stránku.\x3cbr\x3e\x3cbr\x3eVývojáři: Pro pomoc, aby tohle fungovalo , \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eklikněte sem\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "The ${layerType} Layer was unable to load correctly.\x3cbr\x3e\x3cbr\x3eTo get rid of this message, select a new BaseLayer in the layer switcher in the upper-right corner.\x3cbr\x3e\x3cbr\x3eMost likely, this is because the ${layerLib} library script was either not correctly included.\x3cbr\x3e\x3cbr\x3eDevelopers: For help getting this working correctly, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclick here\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Měřítko = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Použil jste volbu \'reproject\' ve vrstvě ${layerName}. Tato volba není doporučená: byla zde proto, aby bylo možno zobrazovat data z okomerčních serverů, ale tato funkce je nyní zajištěna pomocí podpory Spherical Mercator. Více informací naleznete na http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Tato metoda je zavržená a bude ve verzi 3.0 odstraněna. Prosím, použijte raději ${newMethod}." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/nl.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Siebrand │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["nl"] │ │ │ │ - * Dictionary for Nederlands. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["nl"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Het verzoek is niet afgehandeld met de volgende melding: ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Permanente verwijzing", │ │ │ │ - │ │ │ │ - 'Overlays': "Overlays", │ │ │ │ - │ │ │ │ - 'Base Layer': "Achtergrondkaart", │ │ │ │ - │ │ │ │ - 'noFID': "Een optie die geen FID heeft kan niet bijgewerkt worden.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Uw browser ondersteunt het weergeven van vectoren niet.\nMomenteel ondersteunde weergavemogelijkheden:\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "De eigenschap minZoomLevel is alleen bedoeld voor gebruik lagen met die afstammen van FixedZoomLevels-lagen.\nDat deze WFS-laag minZoomLevel controleert, is een overblijfsel uit het verleden.\nWe kunnen deze controle echter niet verwijderen zonder op OL gebaseerde applicaties die hervan afhankelijk zijn stuk te maken.\nDaarom heeft deze functionaliteit de eigenschap \'deprecated\' gekregen - de minZoomLevel wordt verwijderd in versie 3.0.\nGebruik in plaats van deze functie de mogelijkheid om min/max voor resolutie in te stellen zoals op de volgende pagina wordt beschreven:\nhttp://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS-transactie: succesvol ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS-transactie: mislukt ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "De Google-Layer kon niet correct geladen worden.\x3cbr /\x3e\x3cbr /\x3e\nOm deze melding niet meer te krijgen, moet u een andere achtergrondkaart kiezen in de laagwisselaar in de rechterbovenhoek.\x3cbr /\x3e\x3cbr /\x3e\nDit komt waarschijnlijk doordat de bibliotheek ${layerLib} niet correct ingevoegd is.\x3cbr /\x3e\x3cbr /\x3e\nOntwikkelaars: \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik hier\x3c/a\x3e om dit werkend te krijgen.", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "De laag ${layerType} kon niet goed geladen worden.\x3cbr /\x3e\x3cbr /\x3e\nOm deze melding niet meer te krijgen, moet u een andere achtergrondkaart kiezen in de laagwisselaar in de rechterbovenhoek.\x3cbr /\x3e\x3cbr /\x3e\nDit komt waarschijnlijk doordat de bibliotheek ${layerLib} niet correct is ingevoegd.\x3cbr /\x3e\x3cbr /\x3e\nOntwikkelaars: \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik hier\x3c/a\x3e om dit werkend te krijgen.", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Schaal = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "W", │ │ │ │ - │ │ │ │ - 'E': "O", │ │ │ │ - │ │ │ │ - 'N': "N", │ │ │ │ - │ │ │ │ - 'S': "Z", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "U gebruikt de optie \'reproject\' op de laag ${layerName}.\nDeze optie is vervallen: deze optie was ontwikkeld om gegevens over commerciële basiskaarten weer te geven, maar deze functionaliteit wordt nu bereikt door ondersteuning van Spherical Mercator.\nMeer informatie is beschikbaar op http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Deze methode is verouderd en wordt verwijderd in versie 3.0.\nGebruik ${newMethod}." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/br.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Fulup │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["br"] │ │ │ │ - * Dictionary for Brezhoneg. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["br"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Distro evel reked anveret ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Peurliamm", │ │ │ │ - │ │ │ │ - 'Overlays': "Gwiskadoù", │ │ │ │ - │ │ │ │ - 'Base Layer': "Gwiskad diazez", │ │ │ │ - │ │ │ │ - 'noFID': "N\'haller ket hizivaat un elfenn ma n\'eus ket a niverenn-anaout (FID) eviti.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "N\'eo ket skoret an daskor vektorel gant ho merdeer. Setu aze an daskorerioù skoret evit ar poent :\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "Ne zleer implijout ar perzh minZoomLevel nemet evit gwiskadoù FixedZoomLevels-descendent. Ar fed ma wiria ar gwiskad WHS-se hag-eñ ez eus eus minZoomLevel zo un aspadenn gozh. Koulskoude n\'omp ket evit e ziverkañ kuit da derriñ arloadoù diazezet war OL a c\'hallfe bezañ stag outañ. Setu perak eo dispredet -- Lamet kuit e vo ar gwiriañ minZoomLevel a-is er stumm 3.0. Ober gant an arventennoù bihanañ/brasañ evel deskrivet amañ e plas : http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "Treuzgread WFS : MAT EO ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "Treuzgread WFS Transaction: C\'HWITET ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "N\'eus ket bet gallet kargañ ar gwiskad Google ent reizh.\x3cbr\x3e\x3cbr\x3eEvit en em zizober eus ar c\'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c\'horn dehoù el laez.\x3cbr\x3e\x3cbr\x3eSur a-walc\'h eo peogwir n\'eo ket bet ensoc\'het levraoueg Google Maps pe neuze ne glot ket an alc\'hwez API gant ho lec\'hienn.\x3cbr\x3e\x3cbr\x3eDiorroerien : Evit reizhañ an dra-se, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclick here\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "N\'haller ket kargañ ar gwiskad ${layerType} ent reizh.\x3cbr\x3e\x3cbr\x3eEvit en em zizober eus ar c\'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c\'horn dehoù el laez.\x3cbr\x3e\x3cbr\x3eSur a-walc\'h eo peogwir n\'eo ket bet ensoc\'het mat al levraoueg ${layerLib}.\x3cbr\x3e\x3cbr\x3eDiorroerien : Evit gouzout penaos reizhañ an dra-se, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclick here\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Skeul = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "K", │ │ │ │ - │ │ │ │ - 'E': "R", │ │ │ │ - │ │ │ │ - 'N': "N", │ │ │ │ - │ │ │ │ - 'S': "S", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Emaoc\'h oc\'h implijout an dibarzh \'reproject\' war ar gwiskad ${layerName}. Dispredet eo an dibarzh-mañ : bet eo hag e talveze da ziskwel roadennoù war-c\'horre kartennoù diazez kenwerzhel, un dra hag a c\'haller ober bremañ gant an arc\'hwel dre skor banndres boullek Mercator. Muioc\'h a ditouroù a c\'haller da gaout war http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Dispredet eo an daore-se ha tennet e vo kuit eus ar stumm 3.0. Grit gant ${newMethod} e plas." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/nds.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Slomox │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["nds"] │ │ │ │ - * Dictionary for Plattdüütsch. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["nds"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Unbehannelt Trüchmellels för de Anfraag ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Permalink", │ │ │ │ - │ │ │ │ - 'Overlays': "Overlays", │ │ │ │ - │ │ │ │ - 'Base Layer': "Achtergrundkoort", │ │ │ │ - │ │ │ │ - 'noFID': "En Feature, dat keen FID hett, kann nich aktuell maakt warrn.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Dien Browser ünnerstütt keen Vektorbiller. Ünnerstütt Renderers:\n${renderers}", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS-Transakschoon: hett klappt ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS-Transakschoon: hett nich klappt ${response}", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Skaal = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Disse Methood is oold un schall dat in 3.0 nich mehr geven. Bruuk dor man beter ${newMethod} för." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/is.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Ævar Arnfjörð Bjarmason │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["is"] │ │ │ │ - * Dictionary for Íslenska. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["is"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'Permalink': "Varanlegur tengill", │ │ │ │ - │ │ │ │ - 'Overlays': "Þekjur", │ │ │ │ - │ │ │ │ - 'Base Layer': "Grunnlag", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Skali = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Þetta fall hefur verið úrelt og verður fjarlægt í 3.0. Notaðu ${newMethod} í staðin." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/ca.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["ca"] │ │ │ │ - * Dictionary for Catalan, UTF8 encoding. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang.ca = { │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Resposta a petició no gestionada ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Enllaç permanent", │ │ │ │ - │ │ │ │ - 'Overlays': "Capes addicionals", │ │ │ │ - │ │ │ │ - 'Base Layer': "Capa Base", │ │ │ │ - │ │ │ │ - 'noFID': "No es pot actualitzar un element per al que no existeix FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "El seu navegador no suporta renderització vectorial. Els renderitzadors suportats actualment són:\n${renderers}", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'minZoomLevelError': "La propietat minZoomLevel s'ha d'utilitzar només " + │ │ │ │ - "amb les capes que tenen FixedZoomLevels. El fet que " + │ │ │ │ - "una capa wfs comprovi minZoomLevel és una relíquia del " + │ │ │ │ - "passat. No podem, però, eliminar-la sense trencar " + │ │ │ │ - "les aplicacions d'OpenLayers que en puguin dependre. " + │ │ │ │ - "Així doncs estem fent-la obsoleta -- la comprovació " + │ │ │ │ - "minZoomLevel s'eliminarà a la versió 3.0. Feu servir " + │ │ │ │ - "els paràmetres min/max resolution en substitució, tal com es descriu aquí: " + │ │ │ │ - "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "Transacció WFS: CORRECTA ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "Transacció WFS: HA FALLAT ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "La capa Google no s'ha pogut carregar correctament.<br><br>" + │ │ │ │ - "Per evitar aquest missatge, seleccioneu una nova Capa Base " + │ │ │ │ - "al gestor de capes de la cantonada superior dreta.<br><br>" + │ │ │ │ - "Probablement això és degut a que l'script de la biblioteca de " + │ │ │ │ - "Google Maps no ha estat inclòs a la vostra pàgina, o no " + │ │ │ │ - "conté la clau de l'API correcta per a la vostra adreça.<br><br>" + │ │ │ │ - "Desenvolupadors: Per obtenir consells sobre com fer anar això, " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ - "target='_blank'>féu clic aquí</a>", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "Per evitar aquest missatge, seleccioneu una nova Capa Base " + │ │ │ │ - "al gestor de capes de la cantonada superior dreta.<br><br>" + │ │ │ │ - "Probablement això és degut a que l'script de la biblioteca " + │ │ │ │ - "${layerLib} " + │ │ │ │ - "no ha estat inclòs a la vostra pàgina.<br><br>" + │ │ │ │ - "Desenvolupadors: Per obtenir consells sobre com fer anar això, " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ - "target='_blank'>féu clic aquí</a>", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Escala = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - //labels for the graticule control │ │ │ │ - 'W': 'O', │ │ │ │ - 'E': 'E', │ │ │ │ - 'N': 'N', │ │ │ │ - 'S': 'S', │ │ │ │ - 'Graticule': 'Retícula', │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'reprojectDeprecated': "Esteu fent servir l'opció 'reproject' a la capa " + │ │ │ │ - "${layerName}. Aquesta opció és obsoleta: el seu ús fou concebut " + │ │ │ │ - "per suportar la visualització de dades sobre mapes base comercials, " + │ │ │ │ - "però ara aquesta funcionalitat s'hauria d'assolir mitjançant el suport " + │ │ │ │ - "de la projecció Spherical Mercator. Més informació disponible a " + │ │ │ │ - "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'methodDeprecated': "Aquest mètode és obsolet i s'eliminarà a la versió 3.0. " + │ │ │ │ - "Si us plau feu servir em mètode alternatiu ${newMethod}.", │ │ │ │ - │ │ │ │ - // **** end **** │ │ │ │ - 'end': '' │ │ │ │ - │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/ar.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Meno25 │ │ │ │ - * - Mutarjem horr │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["ar"] │ │ │ │ - * Dictionary for العربية. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["ar"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'Permalink': "وصلة دائمة", │ │ │ │ - │ │ │ │ - 'Base Layer': "الطبقة الاساسية", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "النسبة = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "غ", │ │ │ │ - │ │ │ │ - 'E': "شر", │ │ │ │ - │ │ │ │ - 'N': "شم", │ │ │ │ - │ │ │ │ - 'S': "ج" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/ru.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Ferrer │ │ │ │ - * - Komzpa │ │ │ │ - * - Lockal │ │ │ │ - * - Александр Сигачёв │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["ru"] │ │ │ │ - * Dictionary for Русский. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["ru"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Необработанный запрос вернул ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Постоянная ссылка", │ │ │ │ - │ │ │ │ - 'Overlays': "Слои", │ │ │ │ - │ │ │ │ - 'Base Layer': "Основной слой", │ │ │ │ - │ │ │ │ - 'noFID': "Невозможно обновить объект, для которого нет FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Ваш браузер не поддерживает векторную графику. На данный момент поддерживаются:\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "Свойство minZoomLevel предназначено только для использования со слоями, являющимися потомками FixedZoomLevels. То, что этот WFS-слой проверяется на minZoomLevel — реликт прошлого. Однако мы не можем удалить эту функцию, так как, возможно, от неё зависят некоторые основанные на OpenLayers приложения. Функция объявлена устаревшей — проверка minZoomLevel будет удалена в 3.0. Пожалуйста, используйте вместо неё настройку мин/макс разрешения, описанную здесь: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "Транзакция WFS: УСПЕШНО ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "Транзакция WFS: ОШИБКА ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Слой Google не удалось нормально загрузить.\x3cbr\x3e\x3cbr\x3eЧтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.\x3cbr\x3e\x3cbr\x3eСкорее всего, причина в том, что библиотека Google Maps не была включена или не содержит корректного API-ключа для вашего сайта.\x3cbr\x3e\x3cbr\x3eРазработчикам: чтобы узнать, как сделать, чтобы всё заработало, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eщёлкните тут\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "Слой ${layerType} не удалось нормально загрузить. \x3cbr\x3e\x3cbr\x3eЧтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.\x3cbr\x3e\x3cbr\x3eСкорее всего, причина в том, что библиотека ${layerLib} не была включена или была включена некорректно.\x3cbr\x3e\x3cbr\x3eРазработчикам: чтобы узнать, как сделать, чтобы всё заработало, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eщёлкните тут\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Масштаб = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "З", │ │ │ │ - │ │ │ │ - 'E': "В", │ │ │ │ - │ │ │ │ - 'N': "С", │ │ │ │ - │ │ │ │ - 'S': "Ю", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Вы используете опцию \'reproject\' для слоя ${layerName}. Эта опция является устаревшей: ее использование предполагалось для поддержки показа данных поверх коммерческих базовых карт, но теперь этот функционал несёт встроенная поддержка сферической проекции Меркатора. Больше сведений доступно на http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Этот метод считается устаревшим и будет удалён в версии 3.0. Пожалуйста, пользуйтесь ${newMethod}." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/zh-CN.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["zh-CN"] │ │ │ │ - * Dictionary for Simplified Chinese. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["zh-CN"] = { │ │ │ │ - │ │ │ │ - 'unhandledRequest': "未处理的请求,返回值为 ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "永久链接", │ │ │ │ - │ │ │ │ - 'Overlays': "叠加层", │ │ │ │ - │ │ │ │ - 'Base Layer': "基础图层", │ │ │ │ - │ │ │ │ - 'noFID': "无法更新feature,缺少FID。", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "你使用的浏览器不支持矢量渲染。当前支持的渲染方式包括:\n${renderers}", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'minZoomLevelError': "minZoomLevel属性仅适合用于" + │ │ │ │ - "使用了固定缩放级别的图层。这个 " + │ │ │ │ - "wfs 图层检查 minZoomLevel 是过去遗留下来的。" + │ │ │ │ - "然而,我们不能移除它," + │ │ │ │ - "而破坏依赖于它的基于OL的应用程序。" + │ │ │ │ - "因此,我们废除了它 -- minZoomLevel " + │ │ │ │ - "将会在3.0中被移除。请改用 " + │ │ │ │ - "min/max resolution 设置,参考:" + │ │ │ │ - "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS Transaction: 成功。 ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS Transaction: 失败。 ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Google图层不能正确加载。<br><br>" + │ │ │ │ - "要消除这个信息,请在右上角的" + │ │ │ │ - "图层控制面板中选择其他的基础图层。<br><br>" + │ │ │ │ - "这种情况很可能是没有正确的包含Google地图脚本库," + │ │ │ │ - "或者是没有包含在你的站点上" + │ │ │ │ - "使用的正确的Google Maps API密匙。<br><br>" + │ │ │ │ - "开发者:获取使其正确工作的帮助信息," + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ - "target='_blank'>点击这里</a>", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "${layerType} 图层不能正确加载。<br><br>" + │ │ │ │ - "要消除这个信息,请在右上角的" + │ │ │ │ - "图层控制面板中选择其他的基础图层。<br><br>" + │ │ │ │ - "这种情况很可能是没有正确的包含" + │ │ │ │ - "${layerLib} 脚本库。<br><br>" + │ │ │ │ - "开发者:获取使其正确工作的帮助信息," + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ - "target='_blank'>点击这里</a>", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "比例尺 = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'reprojectDeprecated': "你正在使用 ${layerName} 图层上的'reproject'选项。" + │ │ │ │ - "这个选项已经不再使用:" + │ │ │ │ - "它是被设计用来支持显示商业的地图数据," + │ │ │ │ - "不过现在该功能可以通过使用Spherical Mercator来实现。" + │ │ │ │ - "更多信息可以参阅" + │ │ │ │ - "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'methodDeprecated': "该方法已经不再被支持,并且将在3.0中被移除。" + │ │ │ │ - "请使用 ${newMethod} 方法来替代。", │ │ │ │ - │ │ │ │ - 'end': '' │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/vi.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Minh Nguyen │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["vi"] │ │ │ │ - * Dictionary for Tiếng Việt. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["vi"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Không xử lý được phản hồi ${statusText} cho yêu cầu", │ │ │ │ - │ │ │ │ - 'Permalink': "Liên kết thường trực", │ │ │ │ - │ │ │ │ - 'Overlays': "Lấp bản đồ", │ │ │ │ - │ │ │ │ - 'Base Layer': "Lớp nền", │ │ │ │ - │ │ │ │ - 'noFID': "Không thể cập nhật tính năng thiếu FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Trình duyệt của bạn không hỗ trợ chức năng vẽ bằng vectơ. Hiện hỗ trợ các bộ kết xuất:\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "Chỉ nên sử dụng thuộc tính minZoomLevel với các lớp FixedZoomLevels-descendent. Việc lớp wfs này tìm cho minZoomLevel là di tích còn lại từ xưa. Tuy nhiên, nếu chúng tôi dời nó thì sẽ vỡ các chương trình OpenLayers mà dựa trên nó. Bởi vậy chúng tôi phản đối sử dụng nó\x26nbsp;– bước tìm cho minZoomLevel sẽ được dời vào phiên bản 3.0. Xin sử dụng thiết lập độ phân tích tối thiểu / tối đa thay thế, theo hướng dẫn này: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "Giao dịch WFS: THÀNH CÔNG ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "Giao dịch WFS: THẤT BẠI ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Không thể tải lớp Google đúng đắn.\x3cbr\x3e\x3cbr\x3eĐể tránh thông báo này lần sau, hãy chọn BaseLayer mới dùng điều khiển chọn lớp ở góc trên phải.\x3cbr\x3e\x3cbr\x3eChắc script thư viện Google Maps hoặc không được bao gồm hoặc không chứa khóa API hợp với website của bạn.\x3cbr\x3e\x3cbr\x3e\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eTrợ giúp về tính năng này\x3c/a\x3e cho người phát triển.", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "Không thể tải lớp ${layerType} đúng đắn.\x3cbr\x3e\x3cbr\x3eĐể tránh thông báo này lần sau, hãy chọn BaseLayer mới dùng điều khiển chọn lớp ở góc trên phải.\x3cbr\x3e\x3cbr\x3eChắc script thư viện ${layerLib} không được bao gồm đúng kiểu.\x3cbr\x3e\x3cbr\x3e\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eTrợ giúp về tính năng này\x3c/a\x3e cho người phát triển.", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Tỷ lệ = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "T", │ │ │ │ - │ │ │ │ - 'E': "Đ", │ │ │ │ - │ │ │ │ - 'N': "B", │ │ │ │ - │ │ │ │ - 'S': "N", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Bạn đang áp dụng chế độ “reproject” vào lớp ${layerName}. Chế độ này đã bị phản đối: nó có mục đích hỗ trợ lấp dữ liệu trên các nền bản đồ thương mại; nên thực hiện hiệu ứng đó dùng tính năng Mercator Hình cầu. Có sẵn thêm chi tiết tại http://trac.openlayers.org/wiki/SphericalMercator .", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Phương thức này đã bị phản đối và sẽ bị dời vào phiên bản 3.0. Xin hãy sử dụng ${newMethod} thay thế." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/io.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Malafaya │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["io"] │ │ │ │ - * Dictionary for Ido. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["io"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Skalo = 1 : ${scaleDenom}" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/ia.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - McDutchie │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["ia"] │ │ │ │ - * Dictionary for Interlingua. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["ia"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Le responsa a un requesta non esseva maneate: ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Permaligamine", │ │ │ │ - │ │ │ │ - 'Overlays': "Superpositiones", │ │ │ │ - │ │ │ │ - 'Base Layer': "Strato de base", │ │ │ │ - │ │ │ │ - 'noFID': "Non pote actualisar un elemento sin FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Tu navigator non supporta le rendition de vectores. Le renditores actualmente supportate es:\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "Le proprietate minZoomLevel es solmente pro uso con le stratos descendente de FixedZoomLevels. Le facto que iste strato WFS verifica minZoomLevel es un reliquia del passato. Nonobstante, si nos lo remove immediatemente, nos pote rumper applicationes a base de OL que depende de illo. Ergo nos lo declara obsolete; le verification de minZoomLevel in basso essera removite in version 3.0. Per favor usa in su loco le configuration de resolutiones min/max como describite a: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "Transaction WFS: SUCCESSO ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "Transaction WFS: FALLEVA ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Le strato Google non poteva esser cargate correctemente.\x3cbr\x3e\x3cbr\x3ePro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.\x3cbr\x3e\x3cbr\x3eMulto probabilemente, isto es proque le script del libreria de Google Maps non esseva includite o non contine le clave API correcte pro tu sito.\x3cbr\x3e\x3cbr\x3eDisveloppatores: Pro adjuta de corriger isto, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclicca hic\x3c/a", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "Le strato ${layerType} non poteva esser cargate correctemente.\x3cbr\x3e\x3cbr\x3ePro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.\x3cbr\x3e\x3cbr\x3eMulto probabilemente, isto es proque le script del libreria de ${layerLib} non esseva correctemente includite.\x3cbr\x3e\x3cbr\x3eDisveloppatores: Pro adjuta de corriger isto, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclicca hic\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Scala = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "W", │ │ │ │ - │ │ │ │ - 'E': "E", │ │ │ │ - │ │ │ │ - 'N': "N", │ │ │ │ - │ │ │ │ - 'S': "S", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Tu usa le option \'reproject\' in le strato ${layerName} layer. Iste option es obsolescente: illo esseva pro poter monstrar datos super cartas de base commercial, ma iste functionalitate pote ora esser attingite con le uso de Spherical Mercator. Ulterior information es disponibile a http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Iste methodo ha essite declarate obsolescente e essera removite in version 3.0. Per favor usa ${newMethod} in su loco." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/be-tarask.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - EugeneZelenko │ │ │ │ - * - Jim-by │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["be-tarask"] │ │ │ │ - * Dictionary for Беларуская (тарашкевіца). Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["be-tarask"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Неапрацаваны вынік запыту ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Сталая спасылка", │ │ │ │ - │ │ │ │ - 'Overlays': "Слаі", │ │ │ │ - │ │ │ │ - 'Base Layer': "Базавы слой", │ │ │ │ - │ │ │ │ - 'noFID': "Немагчыма абнавіць магчымасьць, для якога не існуе FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Ваш браўзэр не падтрымлівае вэктарную графіку. У цяперашні момант падтрымліваюцца: ${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "Уласьцівасьць minZoomLevel прызначана толькі для выкарыстаньня са слаямі вытворнымі ад FixedZoomLevels. Тое, што гэты wfs-слой правяраецца на minZoomLevel — рэха прошлага. Але мы ня можам выдаліць гэтую магчымасьць, таму што ад яе залежаць некаторыя заснаваныя на OL дастасаваньні. Тым ня менш, праверка minZoomLevel будзе выдаленая ў вэрсіі 3.0. Калі ласка, выкарыстоўваеце замест яе ўстаноўкі мінімальнага/максымальнага памераў, як апісана тут: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS-транзакцыя: ПОСЬПЕХ ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS-транзакцыя: ПАМЫЛКА ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Не атрымалася загрузіць слой Google. \x3cbr\x3e\x3cbr\x3eКаб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.\x3cbr\x3e\x3cbr\x3e Хутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі Google Maps ня быў уключаныя альбо не ўтрымлівае слушны API-ключ для Вашага сайта.\x3cbr\x3e\x3cbr\x3eРаспрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eнацісьніце тут\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "Немагчыма загрузіць слой ${layerType}.\x3cbr\x3e\x3cbr\x3eКаб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.\x3cbr\x3e\x3cbr\x3eХутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі ${layerLib} ня быў слушна ўключаны.\x3cbr\x3e\x3cbr\x3eРаспрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eнацісьніце тут\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Маштаб = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "З", │ │ │ │ - │ │ │ │ - 'E': "У", │ │ │ │ - │ │ │ │ - 'N': "Пн", │ │ │ │ - │ │ │ │ - 'S': "Пд", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Вы выкарыстоўваеце ўстаноўку \'reproject\' для слоя ${layerName}. Гэтая ўстаноўка зьяўляецца састарэлай: яна выкарыстоўвалася для падтрымкі паказу зьвестак на камэрцыйных базавых мапах, але гэта функцыя цяпер рэалізаваная ў убудаванай падтрымцы сфэрычнай праекцыі Мэркатара. Дадатковая інфармацыя ёсьць на http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Гэты мэтад састарэлы і будзе выдалены ў вэрсіі 3.0. Калі ласка, замест яго выкарыстоўвайце ${newMethod}." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/hu.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - City-busz │ │ │ │ - * - Glanthor Reviol │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["hu"] │ │ │ │ - * Dictionary for Magyar. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["hu"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Nem kezelt kérés visszatérése ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Permalink", │ │ │ │ - │ │ │ │ - 'Overlays': "Rávetítések", │ │ │ │ - │ │ │ │ - 'Base Layer': "Alapréteg", │ │ │ │ - │ │ │ │ - 'noFID': "Nem frissíthető olyan jellemző, amely nem rendelkezik FID-del.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "A böngészője nem támogatja a vektoros renderelést. A jelenleg támogatott renderelők:\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "A minZoomLevel tulajdonságot csak a következővel való használatra szánták: FixedZoomLevels-leszármazott fóliák. Ez azt jelenti, hogy a minZoomLevel wfs fólia jelölőnégyzetei már a múlté. Mi azonban nem távolíthatjuk el annak a veszélye nélkül, hogy az esetlegesen ettől függő OL alapú alkalmazásokat tönkretennénk. Ezért ezt érvénytelenítjük -- a minZoomLevel az alul levő jelölőnégyzet a 3.0-s verzióból el lesz távolítva. Kérjük, helyette használja a min/max felbontás beállítást, amelyről az alábbi helyen talál leírást: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS tranzakció: SIKERES ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS tranzakció: SIKERTELEN ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "A Google fólia betöltése sikertelen.\x3cbr\x3e\x3cbr\x3eAhhoz, hogy ez az üzenet eltűnjön, válasszon egy új BaseLayer fóliát a jobb felső sarokban található fóliakapcsoló segítségével.\x3cbr\x3e\x3cbr\x3eNagy valószínűséggel ez azért van, mert a Google Maps könyvtár parancsfájlja nem található, vagy nem tartalmazza az Ön oldalához tartozó megfelelő API-kulcsot.\x3cbr\x3e\x3cbr\x3eFejlesztőknek: A helyes működtetésre vonatkozó segítség az alábbi helyen érhető el, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3ekattintson ide\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "A(z) ${layerType} fólia nem töltődött be helyesen.\x3cbr\x3e\x3cbr\x3eAhhoz, hogy ez az üzenet eltűnjön, válasszon egy új BaseLayer fóliát a jobb felső sarokban található fóliakapcsoló segítségével.\x3cbr\x3e\x3cbr\x3eNagy valószínűséggel ez azért van, mert a(z) ${layerLib} könyvtár parancsfájlja helytelen.\x3cbr\x3e\x3cbr\x3eFejlesztőknek: A helyes működtetésre vonatkozó segítség az alábbi helyen érhető el, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3ekattintson ide\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Lépték = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "Ny", │ │ │ │ - │ │ │ │ - 'E': "K", │ │ │ │ - │ │ │ │ - 'N': "É", │ │ │ │ - │ │ │ │ - 'S': "D", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Ön a \'reproject\' beállítást használja a(z) ${layerName} fólián. Ez a beállítás érvénytelen: használata az üzleti alaptérképek fölötti adatok megjelenítésének támogatására szolgált, de ezt a funkció ezentúl a Gömbi Mercator használatával érhető el. További információ az alábbi helyen érhető el: http://trac.openlayers.org/wiki/SphericalMercator", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Ez a módszer érvénytelenítve lett és a 3.0-s verzióból el lesz távolítva. Használja a(z) ${newMethod} módszert helyette." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/bg.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - DCLXVI │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["bg"] │ │ │ │ - * Dictionary for Български. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["bg"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'Permalink': "Постоянна препратка", │ │ │ │ - │ │ │ │ - 'Base Layer': "Основен слой", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Мащаб = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Този метод е остарял и ще бъде премахват в 3.0. Вместо него използвайте ${newMethod}." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/ro.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["ro"] │ │ │ │ - * Dictionary for Romanian. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang.ro = { │ │ │ │ - 'unhandledRequest': "Cerere nesoluționată return ${statusText}", │ │ │ │ - 'Permalink': "Legatură permanentă", │ │ │ │ - 'Overlays': "Straturi vector", │ │ │ │ - 'Base Layer': "Straturi de bază", │ │ │ │ - 'noFID': "Nu pot actualiza un feature pentru care nu există FID.", │ │ │ │ - 'browserNotSupported': "Browserul tău nu suportă afișarea vectorilor. Supoetul curent pentru randare:\n${renderers}", │ │ │ │ - // console message │ │ │ │ - 'minZoomLevelError': "Proprietatea minZoomLevel este doar pentru a fi folosită " + │ │ │ │ - "cu straturile FixedZoomLevels-descendent. De aceea acest " + │ │ │ │ - "strat wfs verifică dacă minZoomLevel este o relicvă" + │ │ │ │ - ". Nu îl putem , oricum, înlătura fără " + │ │ │ │ - "a afecta aplicațiile Openlayers care depind de ea." + │ │ │ │ - " De aceea considerăm depreciat -- minZoomLevel " + │ │ │ │ - "și îl vom înlătura în 3.0. Folosește " + │ │ │ │ - "min/max resolution cum este descrisă aici: " + │ │ │ │ - "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - 'commitSuccess': "Tranzacție WFS: SUCCES ${response}", │ │ │ │ - 'commitFailed': "Tranzacție WFS : EȘEC ${response}", │ │ │ │ - 'googleWarning': "Stratul Google nu a putut fi încărcat corect.<br><br>" + │ │ │ │ - "Pentru a elimina acest mesaj, selectează un nou strat de bază " + │ │ │ │ - "în Layerswitcher din colțul dreata-sus.<br><br>" + │ │ │ │ - "Asta datorită, faptului că Google Maps library " + │ │ │ │ - "script nu este inclus, sau nu conține " + │ │ │ │ - "cheia API corectă pentru situl tău.<br><br>" + │ │ │ │ - "Developeri: Pentru ajutor, " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ - "target='_blank'>apăsați aici</a>", │ │ │ │ - 'getLayerWarning': "Stratul ${layerType} nu a putut fi încărcat corect.<br><br>" + │ │ │ │ - "pentru a înlătura acest mesaj, selectează un nou strat de bază " + │ │ │ │ - "Acesta eroare apare de obicei când ${layerLib} library " + │ │ │ │ - "script nu a fost încărcat corect.<br><br>" + │ │ │ │ - "Developeri: Pentru ajutor privind utilizarea corectă, " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ - "target='_blank'>apasă aici</a>", │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Scara = 1 : ${scaleDenom}", │ │ │ │ - //labels for the graticule control │ │ │ │ - 'W': 'V', │ │ │ │ - 'E': 'E', │ │ │ │ - 'N': 'N', │ │ │ │ - 'S': 'S', │ │ │ │ - 'Graticule': 'Graticule', │ │ │ │ - // console message │ │ │ │ - 'reprojectDeprecated': "folosești opțiunea 'reproject' " + │ │ │ │ - "pentru stratul ${layerName} . Această opțiune este depreciată: " + │ │ │ │ - "a fost utilizată pentru afișarea straturilor de bază comerciale " + │ │ │ │ - "Mai multe informații despre proiecția Mercator sunt disponibile aici " + │ │ │ │ - "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - // console message │ │ │ │ - 'methodDeprecated': "Această metodă este depreciată și va fi înlăturată in versiunea 3.0. " + │ │ │ │ - "folosește metoda ${newMethod}.", │ │ │ │ - // **** end **** │ │ │ │ - 'end': '' │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/da-DK.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["da-DK"] │ │ │ │ - * Dictionary for Danish. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang['da-DK'] = { │ │ │ │ - │ │ │ │ - 'unhandledRequest': "En ikke håndteret forespørgsel returnerede ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Permalink", │ │ │ │ - │ │ │ │ - 'Overlays': "Kortlag", │ │ │ │ - │ │ │ │ - 'Base Layer': "Baggrundslag", │ │ │ │ - │ │ │ │ - 'noFID': "Kan ikke opdateret en feature (et objekt) der ikke har et FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Din browser understøtter ikke vektor visning. Følgende vektor visninger understøttes:\n${renderers}", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'minZoomLevelError': "Egenskaben minZoomLevel er kun beregnet til brug " + │ │ │ │ - "med FixedZoomLevels. At dette WFS lag kontrollerer " + │ │ │ │ - "minZoomLevel egenskaben, er et levn fra en tidligere " + │ │ │ │ - "version. Vi kan desværre ikke fjerne dette uden at risikere " + │ │ │ │ - "at ødelægge eksisterende OL baserede programmer der " + │ │ │ │ - " benytter denne funktionalitet. " + │ │ │ │ - "Egenskaben bør derfor ikke anvendes, og minZoomLevel " + │ │ │ │ - "kontrollen herunder vil blive fjernet i version 3.0. " + │ │ │ │ - "Benyt istedet min/max opløsnings indstillingerne, som " + │ │ │ │ - "er beskrevet her: " + │ │ │ │ - "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS transaktion: LYKKEDES ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS transaktion: MISLYKKEDES ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Google laget kunne ikke indlæses.<br><br>" + │ │ │ │ - "For at fjerne denne besked, vælg et nyt bagrundskort i " + │ │ │ │ - "lagskifteren i øverste højre hjørne.<br><br>" + │ │ │ │ - "Fejlen skyldes formentlig at Google Maps bibliotekts " + │ │ │ │ - "scriptet ikke er inkluderet, eller ikke indeholder den " + │ │ │ │ - "korrkte API nøgle for dit site.<br><br>" + │ │ │ │ - "Udviklere: For hjælp til at få dette til at fungere, " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ - "target='_blank'>klik her</a>", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "${layerType}-laget kunne ikke indlæses.<br><br>" + │ │ │ │ - "For at fjerne denne besked, vælg et nyt bagrundskort i " + │ │ │ │ - "lagskifteren i øverste højre hjørne.<br><br>" + │ │ │ │ - "Fejlen skyldes formentlig at ${layerLib} bibliotekts " + │ │ │ │ - "scriptet ikke er inkluderet.<br><br>" + │ │ │ │ - "Udviklere: For hjælp til at få dette til at fungere, " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ - "target='_blank'>klik her</a>", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Målforhold = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'reprojectDeprecated': "Du anvender indstillingen 'reproject' på laget ${layerName}." + │ │ │ │ - "Denne indstilling bør ikke længere anvendes. Den var beregnet " + │ │ │ │ - "til at vise data ovenpå kommercielle grundkort, men den funktionalitet " + │ │ │ │ - "bør nu opnås ved at anvende Spherical Mercator understøttelsen. " + │ │ │ │ - "Mere information er tilgængelig her: " + │ │ │ │ - "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'methodDeprecated': "Denne funktion bør ikke længere anvendes, og vil blive fjernet i version 3.0. " + │ │ │ │ - "Anvend venligst funktionen ${newMethod} istedet." │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/fr.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Damouns │ │ │ │ - * - IAlex │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["fr"] │ │ │ │ - * Dictionary for Français. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["fr"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Requête non gérée, retournant ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Permalien", │ │ │ │ - │ │ │ │ - 'Overlays': "Calques", │ │ │ │ - │ │ │ │ - 'Base Layer': "Calque de base", │ │ │ │ - │ │ │ │ - 'noFID': "Impossible de mettre à jour un objet sans identifiant (fid).", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Votre navigateur ne supporte pas le rendu vectoriel. Les renderers actuellement supportés sont : \n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "La propriété minZoomLevel doit seulement être utilisée pour des couches FixedZoomLevels-descendent. Le fait que cette couche WFS vérifie la présence de minZoomLevel est une relique du passé. Nous ne pouvons toutefois la supprimer sans casser des applications qui pourraient en dépendre. C\'est pourquoi nous la déprécions -- la vérification du minZoomLevel sera supprimée en version 3.0. A la place, merci d\'utiliser les paramètres de résolutions min/max tel que décrit sur : http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "Transaction WFS : SUCCES ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "Transaction WFS : ECHEC ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "La couche Google n\'a pas été en mesure de se charger correctement.\x3cbr\x3e\x3cbr\x3ePour supprimer ce message, choisissez une nouvelle BaseLayer dans le sélecteur de couche en haut à droite.\x3cbr\x3e\x3cbr\x3eCela est possiblement causé par la non-inclusion de la librairie Google Maps, ou alors parce que la clé de l\'API ne correspond pas à votre site.\x3cbr\x3e\x3cbr\x3eDéveloppeurs : pour savoir comment corriger ceci, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3ecliquez ici\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "La couche ${layerType} n\'est pas en mesure de se charger correctement.\x3cbr\x3e\x3cbr\x3ePour supprimer ce message, choisissez une nouvelle BaseLayer dans le sélecteur de couche en haut à droite.\x3cbr\x3e\x3cbr\x3eCela est possiblement causé par la non-inclusion de la librairie ${layerLib}.\x3cbr\x3e\x3cbr\x3eDéveloppeurs : pour savoir comment corriger ceci, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3ecliquez ici\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Echelle ~ 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "O", │ │ │ │ - │ │ │ │ - 'E': "E", │ │ │ │ - │ │ │ │ - 'N': "N", │ │ │ │ - │ │ │ │ - 'S': "S", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Vous utilisez l\'option \'reproject\' sur la couche ${layerName}. Cette option est dépréciée : Son usage permettait d\'afficher des données au dessus de couches raster commerciales.Cette fonctionalité est maintenant supportée en utilisant le support de la projection Mercator Sphérique. Plus d\'information est disponible sur http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Cette méthode est dépréciée, et sera supprimée à la version 3.0. Merci d\'utiliser ${newMethod} à la place." │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/sv-SE.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Sannab │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["sv"] │ │ │ │ - * Dictionary for Svenska. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["sv"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Ej hanterad fråga retur ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Permalänk", │ │ │ │ - │ │ │ │ - 'Overlays': "Kartlager", │ │ │ │ - │ │ │ │ - 'Base Layer': "Bakgrundskarta", │ │ │ │ - │ │ │ │ - 'noFID': "Kan ej uppdatera feature (objekt) för vilket FID saknas.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Din webbläsare stöder inte vektorvisning. För närvarande stöds följande visning:\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "Egenskapen minZoomLevel är endast avsedd att användas med lager med FixedZoomLevels. Att detta WFS-lager kontrollerar minZoomLevel är en relik från äldre versioner. Vi kan dock inte ta bort det utan att riskera att OL-baserade tillämpningar som använder detta slutar fungera. Därför är det satt som deprecated, minZoomLevel kommer att tas bort i version 3.0. Använd i stället inställning av min/max resolution som beskrivs här: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS-transaktion: LYCKADES ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS-transaktion: MISSLYCKADES ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Google-lagret kunde inte laddas korrekt.\x3cbr\x3e\x3cbr\x3eFör att slippa detta meddelande, välj en annan bakgrundskarta i lagerväljaren i övre högra hörnet.\x3cbr\x3e\x3cbr\x3eSannolikt beror felet på att Google Maps-biblioteket inte är inkluderat på webbsidan eller på att sidan inte anger korrekt API-nyckel för webbplatsen.\x3cbr\x3e\x3cbr\x3eUtvecklare: hjälp för att åtgärda detta, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eklicka här\x3c/a\x3e.", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "${layerType}-lagret kunde inte laddas korrekt.\x3cbr\x3e\x3cbr\x3eFör att slippa detta meddelande, välj en annan bakgrundskarta i lagerväljaren i övre högra hörnet.\x3cbr\x3e\x3cbr\x3eSannolikt beror felet på att ${layerLib}-biblioteket inte är inkluderat på webbsidan.\x3cbr\x3e\x3cbr\x3eUtvecklare: hjälp för att åtgärda detta, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklicka här\x3c/a\x3e.", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "\x3cstrong\x3eSkala\x3c/strong\x3e 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Du använder inställningen \'reproject\' på lagret ${layerName}. Denna inställning markerad som deprecated: den var avsedd att användas för att stödja visning av kartdata på kommersiella bakgrundskartor, men nu bör man i stället använda Spherical Mercator-stöd för den funktionaliteten. Mer information finns på http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Denna metod är markerad som deprecated och kommer att tas bort i 3.0. Använd ${newMethod} i stället." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/gsw.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Als-Holder │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["gsw"] │ │ │ │ - * Dictionary for Alemannisch. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["gsw"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Nit behandleti Aafrogsruckmäldig ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Permalink", │ │ │ │ - │ │ │ │ - 'Overlays': "Iberlagerige", │ │ │ │ - │ │ │ │ - 'Base Layer': "Grundcharte", │ │ │ │ - │ │ │ │ - 'noFID': "E Feature, wu s kei FID derfir git, cha nit aktualisiert wäre.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Dyy Browser unterstitzt kei Vektordarstellig. Aktuäll unterstitzti Renderer:\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "D minZoomLevel-Eigeschaft isch nume dänk fir d Layer, wu vu dr FixedZoomLevels abstamme. Ass dää wfs-Layer minZoomLevel prieft, scih e Relikt us dr Vergangeheit. Mir chenne s aber nit ändere ohni OL_basierti Aawändige villicht kaputt gehn, wu dervu abhänge. Us däm Grund het die Funktion d Eigeschaft \'deprecated\' iberchuu. D minZoomLevel-Priefig unte wird in dr Version 3.0 usegnuu. Bitte verwänd statt däm e min/max-Uflesig wie s do bschriben isch: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS-Transaktion: ERFOLGRYCH ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS-Transaktion: FÄHLGSCHLAA ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Dr Google-Layer het nit korräkt chenne glade wäre.\x3cbr\x3e\x3cbr\x3eGo die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.\x3cbr\x3e\x3cbr\x3eDää Fähler git s seli hyfig, wel s Skript vu dr Google-Maps-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.\x3cbr\x3e\x3cbr\x3eEntwickler: Fir Hilf zum korräkte Yybinde vum Google-Layer \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3edoo drucke\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "Dr ${layerType}-Layer het nit korräkt chenne glade wäre.\x3cbr\x3e\x3cbr\x3eGo die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.\x3cbr\x3e\x3cbr\x3eDää Fähler git s seli hyfig, wel s Skript vu dr \'${layerLib}\'-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.\x3cbr\x3e\x3cbr\x3eEntwickler: Fir Hilf zum korräkte Yybinde vu Layer \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3edoo drucke\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Maßstab = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "W", │ │ │ │ - │ │ │ │ - 'E': "O", │ │ │ │ - │ │ │ │ - 'N': "N", │ │ │ │ - │ │ │ │ - 'S': "S", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Du bruchsch d \'reproject\'-Option bim ${layerName}-Layer. Die Option isch nimi giltig: si isch aagleit wore go Date iber kommerziälli Grundcharte lege, aber des sott mer jetz mache mit dr Unterstitzig vu Spherical Mercator. Meh Informatione git s uf http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Die Methode isch veraltet un wird us dr Version 3.0 usegnuu. Bitte verwäbnd statt däm ${newMethod}." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/hsb.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Michawiki │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["hsb"] │ │ │ │ - * Dictionary for Hornjoserbsce. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["hsb"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Wotmołwa njewobdźěłaneho naprašowanja ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Trajny wotkaz", │ │ │ │ - │ │ │ │ - 'Overlays': "Naworštowanja", │ │ │ │ - │ │ │ │ - 'Base Layer': "Zakładna runina", │ │ │ │ - │ │ │ │ - 'noFID': "Funkcija, za kotruž FID njeje, njeda so aktualizować.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Twój wobhladowak wektorowe rysowanje njepodpěruje. Tuchwilu podpěrowane rysowaki su:\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "Kajkosć minZoomLevel je jenož za wužiwanje z worštami myslena, kotrež wot FixedZoomLevels pochadźeja. Zo tuta woršta wfs za minZoomLevel přepruwuje, je relikt zańdźenosće. Njemóžemy wšak ju wotstronić, bjeztoho zo aplikacije, kotrež na OpenLayers bazěruja a snano tutu kajkosć wužiwaja, hižo njefunguja. Tohodla smy ju jako zestarjenu woznamjenili -- přepruwowanje za minZoomLevel budu so we wersiji 3.0 wotstronjeć. Prošu wužij město toho nastajenje min/max, kaž je tu wopisane: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS-Transakcija: WUSPĚŠNA ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS-Transakcija: NJEPORADŹENA ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Woršta Google njemóžeše so korektnje začitać.\x3cbr\x3e\x3cbr\x3eZo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.\x3cbr\x3e\x3cbr\x3eNajskerje so to stawa, dokelž skript biblioteki Google Maps pak njebu zapřijaty pak njewobsahuje korektny kluč API za twoje sydło.\x3cbr\x3e\x3cbr\x3eWuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3etu kliknyć\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "Woršta ${layerType} njemóžeše so korektnje začitać.\x3cbr\x3e\x3cbr\x3eZo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.\x3cbr\x3e\x3cbr\x3eNajskerje so to stawa, dokelž skript biblioteki ${layerLib} njebu korektnje zapřijaty.\x3cbr\x3e\x3cbr\x3eWuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3etu kliknyć\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Měritko = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "Z", │ │ │ │ - │ │ │ │ - 'E': "W", │ │ │ │ - │ │ │ │ - 'N': "S", │ │ │ │ - │ │ │ │ - 'S': "J", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Wužiwaš opciju \"reproject\" wořšty ${layerName}. Tuta opcija je zestarjena: jeje wužiwanje bě myslene, zo by zwobraznjenje datow nad komercielnymi bazowymi kartami podpěrało, ale funkcionalnosć měła so nětko z pomocu Sperical Mercator docpěć. Dalše informacije steja na http://trac.openlayers.org/wiki/SphericalMercator k dispoziciji.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Tuta metoda je so njeschwaliła a budźe so w 3.0 wotstronjeć. Prošu wužij ${newMethod} město toho." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/te.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Veeven │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["te"] │ │ │ │ - * Dictionary for తెలుగు. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["te"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'Permalink': "స్థిరలింకు", │ │ │ │ - │ │ │ │ - 'W': "ప", │ │ │ │ - │ │ │ │ - 'E': "తూ", │ │ │ │ - │ │ │ │ - 'N': "ఉ", │ │ │ │ - │ │ │ │ - 'S': "ద" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/el.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Omnipaedista │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["el"] │ │ │ │ - * Dictionary for Ελληνικά. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["el"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Κλίμακα ~ 1 : ${scaleDenom}" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/de.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Grille chompa │ │ │ │ - * - Nikiwaibel │ │ │ │ - * - Umherirrender │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["de"] │ │ │ │ - * Dictionary for Deutsch. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["de"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Unbehandelte Anfragerückmeldung ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Permalink", │ │ │ │ - │ │ │ │ - 'Overlays': "Overlays", │ │ │ │ - │ │ │ │ - 'Base Layer': "Grundkarte", │ │ │ │ - │ │ │ │ - 'noFID': "Ein Feature, für das keine FID existiert, kann nicht aktualisiert werden.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Ihr Browser unterstützt keine Vektordarstellung. Aktuell unterstützte Renderer:\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "Die \x3ccode\x3eminZoomLevel\x3c/code\x3e-Eigenschaft ist nur für die Verwendung mit \x3ccode\x3eFixedZoomLevels\x3c/code\x3e-untergeordneten Layers vorgesehen. Das dieser \x3ctt\x3ewfs\x3c/tt\x3e-Layer die \x3ccode\x3eminZoomLevel\x3c/code\x3e-Eigenschaft überprüft ist ein Relikt der Vergangenheit. Wir können diese Überprüfung nicht entfernen, ohne das OL basierende Applikationen nicht mehr funktionieren. Daher markieren wir es als veraltet - die \x3ccode\x3eminZoomLevel\x3c/code\x3e-Überprüfung wird in Version 3.0 entfernt werden. Bitte verwenden Sie stattdessen die Min-/Max-Lösung, wie sie unter http://trac.openlayers.org/wiki/SettingZoomLevels beschrieben ist.", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS-Transaktion: Erfolgreich ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS-Transaktion: Fehlgeschlagen ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Der Google-Layer konnte nicht korrekt geladen werden.\x3cbr\x3e\x3cbr\x3eUm diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.\x3cbr\x3e\x3cbr\x3eSehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der Google-Maps-Bibliothek nicht eingebunden wurde oder keinen gültigen API-Schlüssel für Ihre URL enthält.\x3cbr\x3e\x3cbr\x3eEntwickler: Besuche \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3edas Wiki\x3c/a\x3e für Hilfe zum korrekten Einbinden des Google-Layers", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "Der ${layerType}-Layer konnte nicht korrekt geladen werden.\x3cbr\x3e\x3cbr\x3eUm diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.\x3cbr\x3e\x3cbr\x3eSehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der \'${layerLib}\'-Bibliothek nicht eingebunden wurde.\x3cbr\x3e\x3cbr\x3eEntwickler: Besuche \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3edas Wiki\x3c/a\x3e für Hilfe zum korrekten Einbinden von Layern", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Maßstab = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "W", │ │ │ │ - │ │ │ │ - 'E': "O", │ │ │ │ - │ │ │ │ - 'N': "N", │ │ │ │ - │ │ │ │ - 'S': "S", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Sie verwenden die „Reproject“-Option des Layers ${layerName}. Diese Option ist veraltet: Sie wurde entwickelt um die Anzeige von Daten auf kommerziellen Basiskarten zu unterstützen, aber diese Funktion sollte jetzt durch Unterstützung der „Spherical Mercator“ erreicht werden. Weitere Informationen sind unter http://trac.openlayers.org/wiki/SphericalMercator verfügbar.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Die Methode ist veraltet und wird in 3.0 entfernt. Bitte verwende stattdessen ${newMethod}." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/pt.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Hamilton Abreu │ │ │ │ - * - Malafaya │ │ │ │ - * - Waldir │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["pt"] │ │ │ │ - * Dictionary for Português. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["pt"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Servidor devolveu erro não contemplado ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Ligação permanente", │ │ │ │ - │ │ │ │ - 'Overlays': "Sobreposições", │ │ │ │ - │ │ │ │ - 'Base Layer': "Camada Base", │ │ │ │ - │ │ │ │ - 'noFID': "Não é possível atualizar um elemento para a qual não há FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "O seu navegador não suporta renderização vetorial. Actualmente os renderizadores suportados são:\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "A propriedade minZoomLevel só deve ser usada com as camadas descendentes da FixedZoomLevels. A verificação da propriedade por esta camada wfs é uma relíquia do passado. No entanto, não podemos removê-la sem correr o risco de afectar aplicações OL que dependam dela. Portanto, estamos a torná-la obsoleta -- a verificação minZoomLevel será removida na versão 3.0. Em vez dela, por favor, use as opções de resolução min/max descritas aqui: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "Transacção WFS: SUCESSO ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "Transacção WFS: FALHOU ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "A Camada Google não foi correctamente carregada.\x3cbr\x3e\x3cbr\x3ePara deixar de receber esta mensagem, seleccione uma nova Camada-Base no \'\'switcher\'\' de camadas no canto superior direito.\x3cbr\x3e\x3cbr\x3eProvavelmente, isto acontece porque o \'\'script\'\' da biblioteca do Google Maps não foi incluído ou não contém a chave API correcta para o seu sítio.\x3cbr\x3e\x3cbr\x3eProgramadores: Para ajuda sobre como solucionar o problema \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclique aqui\x3c/a\x3e .", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "A camada ${layerType} não foi correctamente carregada.\x3cbr\x3e\x3cbr\x3ePara desactivar esta mensagem, seleccione uma nova Camada-Base no \'\'switcher\'\' de camadas no canto superior direito.\x3cbr\x3e\x3cbr\x3eProvavelmente, isto acontece porque o \'\'script\'\' da biblioteca ${layerLib} não foi incluído correctamente.\x3cbr\x3e\x3cbr\x3eProgramadores: Para ajuda sobre como solucionar o problema \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclique aqui\x3c/a\x3e .", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Escala = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "O", │ │ │ │ - │ │ │ │ - 'E': "E", │ │ │ │ - │ │ │ │ - 'N': "N", │ │ │ │ - │ │ │ │ - 'S': "S", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Está usando a opção \'reproject\' na camada ${layerName}. Esta opção é obsoleta: foi concebida para permitir a apresentação de dados sobre mapas-base comerciais, mas esta funcionalidade é agora suportada pelo Mercator Esférico. Mais informação está disponível em http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Este método foi declarado obsoleto e será removido na versão 3.0. Por favor, use ${newMethod} em vez disso." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/pt-BR.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Luckas Blade │ │ │ │ - * - Rodrigo Avila │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["pt-br"] │ │ │ │ - * Dictionary for Português do Brasil. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["pt-BR"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "A requisição retornou um erro não tratado: ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Link para essa página", │ │ │ │ - │ │ │ │ - 'Overlays': "Camadas de Sobreposição", │ │ │ │ - │ │ │ │ - 'Base Layer': "Camada Base", │ │ │ │ - │ │ │ │ - 'noFID': "Não é possível atualizar uma feição que não tenha um FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Seu navegador não suporta renderização de vetores. Os renderizadores suportados atualmente são:\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "A propriedade minZoomLevel é de uso restrito das camadas descendentes de FixedZoomLevels. A verificação dessa propriedade pelas camadas wfs é um resíduo do passado. Não podemos, entretanto não é possível removê-la sem possívelmente quebrar o funcionamento de aplicações OL que possuem depência com ela. Portanto estamos tornando seu uso obsoleto -- a verificação desse atributo será removida na versão 3.0. Ao invés, use as opções de resolução min/max como descrito em: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "Transação WFS : SUCESSO ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "Transação WFS : ERRO ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Não foi possível carregar a camada Google corretamente.\x3cbr\x3e\x3cbr\x3ePara se livrar dessa mensagem, selecione uma nova Camada Base, na ferramenta de alternação de camadas localização do canto superior direito.\x3cbr\x3e\x3cbr\x3eMuito provavelmente, isso foi causado porque o script da biblioteca do Google Maps não foi incluído, ou porque ele não contém a chave correta da API para o seu site.\x3cbr\x3e\x3cbr\x3eDesenvolvedores: Para obter ajuda em solucionar esse problema \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3ecliquem aqui\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "Não foi possível carregar a camada ${layerType} corretamente.\x3cbr\x3e\x3cbr\x3ePara se livrar dessa mensagem, selecione uma nova Camada Base, na ferramenta de alternação de camadas localização do canto superior direito.\x3cbr\x3e\x3cbr\x3eMuito provavelmente, isso foi causado porque o script da biblioteca ${layerLib} não foi incluído corretamente.\x3cbr\x3e\x3cbr\x3eDesenvolvedores: Para obter ajuda em solucionar esse problema \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3ecliquem aqui\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Escala = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "O", │ │ │ │ - │ │ │ │ - 'E': "L", │ │ │ │ - │ │ │ │ - 'N': "N", │ │ │ │ - │ │ │ │ - 'S': "S", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Você está usando a opção \'reproject\' na camada ${layerName}. Essa opção está obsoleta: seu uso foi projetado para suportar a visualização de dados sobre bases de mapas comerciais, entretanto essa funcionalidade deve agora ser alcançada usando o suporte à projeção Mercator. Mais informação está disponível em: http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Esse método está obsoleto e será removido na versão 3.0. Ao invés, por favor use ${newMethod}." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/nn.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Harald Khan │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["nn"] │ │ │ │ - * Dictionary for ‪Norsk (nynorsk)‬. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["nn"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Skala = 1 : ${scaleDenom}" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/hr.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Mvrban │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["hr"] │ │ │ │ - * Dictionary for Hrvatski. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["hr"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Nepodržani zahtjev ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Permalink", │ │ │ │ - │ │ │ │ - 'Overlays': "Overlays", │ │ │ │ - │ │ │ │ - 'Base Layer': "Osnovna karta", │ │ │ │ - │ │ │ │ - 'noFID': "Ne mogu ažurirati značajku za koju ne postoji FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Vaš preglednik ne podržava vektorsko renderiranje. Trenutno podržani rendereri su: ${renderers}", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS Transakcija: USPJEŠNA ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS Transakcija: NEUSPJEŠNA ${response}", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Mjerilo = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Ova metoda nije odobrena i biti će maknuta u 3.0. Koristite ${newMethod}." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/km.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - វ័ណថារិទ្ធ │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["km"] │ │ │ │ - * Dictionary for ភាសាខ្មែរ. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["km"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'Permalink': "តំណភ្ជាប់អចិន្ត្រៃយ៍", │ │ │ │ - │ │ │ │ - 'Base Layer': "ស្រទាប់បាត​", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "មាត្រដ្ឋាន = ១ ៖ ${scaleDenom}" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/pl.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators: │ │ │ │ - * - Arkadiusz Grabka │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["pl"] │ │ │ │ - * Dictionary for Polish. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["pl"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Nieobsługiwane żądanie zwróciło ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Permalink", │ │ │ │ - │ │ │ │ - 'Overlays': "Nakładki", │ │ │ │ - │ │ │ │ - 'Base Layer': "Warstwa podstawowa", │ │ │ │ - │ │ │ │ - 'noFID': "Nie można zaktualizować funkcji, dla których nie ma FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Twoja przeglądarka nie obsługuje renderowania wektorów. Obecnie obsługiwane renderowanie to:\n${renderers}", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'minZoomLevelError': "Właściwość minZoomLevel jest przeznaczona tylko do użytku " + │ │ │ │ - "z warstwami FixedZoomLevels-descendent." + │ │ │ │ - "Warstwa wfs, która sprawdza minZoomLevel jest reliktem przeszłości." + │ │ │ │ - "Nie możemy jej jednak usunąc bez mozliwości łamania OL aplikacji, " + │ │ │ │ - "które mogą być od niej zależne. " + │ │ │ │ - "Dlatego jesteśmy za deprecjację -- minZoomLevel " + │ │ │ │ - "zostanie usunięta w wersji 3.0. W zamian prosze użyj " + │ │ │ │ - "min/max rozdzielczości w sposób opisany tutaj: " + │ │ │ │ - "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "Transakcja WFS: SUKCES ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "Transakcja WFS: FAILED ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Warstwa Google nie był w stanie załadować się poprawnie.<br><br>" + │ │ │ │ - "Aby pozbyć się tej wiadomości, wybierz nową Warstwe podstawową " + │ │ │ │ - "w przełączniku warstw w górnym prawym rogu mapy.<br><br>" + │ │ │ │ - "Najprawdopodobniej jest to spowodowane tym, że biblioteka Google Maps " + │ │ │ │ - "nie jest załadowana, lub nie zawiera poprawnego klucza do API dla twojej strony<br><br>" + │ │ │ │ - "Programisto: Aby uzyskać pomoc , " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ - "target='_blank'>kliknij tutaj</a>", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "Warstwa ${layerType} nie mogła zostać załadowana poprawnie.<br><br>" + │ │ │ │ - "Aby pozbyć się tej wiadomości, wybierz nową Warstwe podstawową " + │ │ │ │ - "w przełączniku warstw w górnym prawym rogu mapy.<br><br>" + │ │ │ │ - "Najprawdopodobniej jest to spowodowane tym, że biblioteka ${layerLib} " + │ │ │ │ - "nie jest załadowana, lub może(o ile biblioteka tego wymaga) " + │ │ │ │ - "byc potrzebny klucza do API dla twojej strony<br><br>" + │ │ │ │ - "Programisto: Aby uzyskać pomoc , " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ - "target='_blank'>kliknij tutaj</a>", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Skala = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - //labels for the graticule control │ │ │ │ - 'W': 'ZACH', │ │ │ │ - 'E': 'WSCH', │ │ │ │ - 'N': 'PN', │ │ │ │ - 'S': 'PD', │ │ │ │ - 'Graticule': 'Siatka', │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'reprojectDeprecated': "w warstwie ${layerName} używasz opcji 'reproject'. " + │ │ │ │ - "Ta opcja jest przestarzała: " + │ │ │ │ - "jej zastosowanie został zaprojektowany, aby wspierać wyświetlania danych przez komercyjne mapy, " + │ │ │ │ - "jednak obecnie ta funkcjonalność powinien zostać osiągnięty za pomocą Spherical Mercator " + │ │ │ │ - "its use was designed to support displaying data over commercial. Więcje informacji na ten temat możesz znaleźć na stronie " + │ │ │ │ - "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'methodDeprecated': "Ta metoda jest przestarzała i będzie usunięta od wersji 3.0. " + │ │ │ │ - "W zamian użyj ${newMethod}." │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/fur.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Klenje │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["fur"] │ │ │ │ - * Dictionary for Furlan. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["fur"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'Permalink': "Leam Permanent", │ │ │ │ - │ │ │ │ - 'Overlays': "Livei parsore", │ │ │ │ - │ │ │ │ - 'Base Layer': "Livel di base", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Il to sgarfadôr nol supuarte la renderizazion vetoriâl. Al moment a son supuartâts:\n${renderers}", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Scjale = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "O", │ │ │ │ - │ │ │ │ - 'E': "E", │ │ │ │ - │ │ │ │ - 'N': "N", │ │ │ │ - │ │ │ │ - 'S': "S" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/es.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["es"] │ │ │ │ - * Dictionary for Spanish, UTF8 encoding. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang.es = { │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Respuesta a petición no gestionada ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Enlace permanente", │ │ │ │ - │ │ │ │ - 'Overlays': "Capas superpuestas", │ │ │ │ - │ │ │ │ - 'Base Layer': "Capa Base", │ │ │ │ - │ │ │ │ - 'noFID': "No se puede actualizar un elemento para el que no existe FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Su navegador no soporta renderización vectorial. Los renderizadores soportados actualmente son:\n${renderers}", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'minZoomLevelError': "La propiedad minZoomLevel debe sólo utilizarse " + │ │ │ │ - "con las capas que tienen FixedZoomLevels. El hecho de que " + │ │ │ │ - "una capa wfs compruebe minZoomLevel es una reliquia del " + │ │ │ │ - "pasado. Sin embargo, no podemos eliminarla sin discontinuar " + │ │ │ │ - "probablemente las aplicaciones OL que puedan depender de ello. " + │ │ │ │ - "Así pues estamos haciéndolo obsoleto --la comprobación " + │ │ │ │ - "minZoomLevel se eliminará en la versión 3.0. Utilice el ajuste " + │ │ │ │ - "de resolution min/max en su lugar, tal como se describe aquí: " + │ │ │ │ - "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "Transacción WFS: ÉXITO ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "Transacción WFS: FALLÓ ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "La capa Google no pudo ser cargada correctamente.<br><br>" + │ │ │ │ - "Para evitar este mensaje, seleccione una nueva Capa Base " + │ │ │ │ - "en el selector de capas en la esquina superior derecha.<br><br>" + │ │ │ │ - "Probablemente, esto se debe a que el script de la biblioteca de " + │ │ │ │ - "Google Maps no fue correctamente incluido en su página, o no " + │ │ │ │ - "contiene la clave del API correcta para su sitio.<br><br>" + │ │ │ │ - "Desarrolladores: Para ayudar a hacer funcionar esto correctamente, " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ - "target='_blank'>haga clic aquí</a>", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "La capa ${layerType} no pudo ser cargada correctamente.<br><br>" + │ │ │ │ - "Para evitar este mensaje, seleccione una nueva Capa Base " + │ │ │ │ - "en el selector de capas en la esquina superior derecha.<br><br>" + │ │ │ │ - "Probablemente, esto se debe a que el script de " + │ │ │ │ - "la biblioteca ${layerLib} " + │ │ │ │ - "no fue correctamente incluido en su página.<br><br>" + │ │ │ │ - "Desarrolladores: Para ayudar a hacer funcionar esto correctamente, " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ - "target='_blank'>haga clic aquí</a>", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Escala = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - //labels for the graticule control │ │ │ │ - 'W': 'O', │ │ │ │ - 'E': 'E', │ │ │ │ - 'N': 'N', │ │ │ │ - 'S': 'S', │ │ │ │ - 'Graticule': 'Retícula', │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'reprojectDeprecated': "Está usando la opción 'reproject' en la capa " + │ │ │ │ - "${layerName}. Esta opción es obsoleta: su uso fue diseñado " + │ │ │ │ - "para soportar la visualización de datos sobre mapas base comerciales, " + │ │ │ │ - "pero ahora esa funcionalidad debería conseguirse mediante el soporte " + │ │ │ │ - "de la proyección Spherical Mercator. Más información disponible en " + │ │ │ │ - "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'methodDeprecated': "Este método es obsoleto y se eliminará en la versión 3.0. " + │ │ │ │ - "Por favor utilice el método ${newMethod} en su lugar.", │ │ │ │ - │ │ │ │ - // **** end **** │ │ │ │ - 'end': '' │ │ │ │ - │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/en-CA.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang/en.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["en-CA"] │ │ │ │ - * Dictionary for English-CA. This dictionary inherits from the standard │ │ │ │ - * English dictionary. Override only those entries with language specific │ │ │ │ - * to the CA region. │ │ │ │ - * │ │ │ │ - * Keys for entries are used in calls to <OpenLayers.Lang.translate>. Entry │ │ │ │ - * bodies are normal strings or strings formatted for use with │ │ │ │ - * <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang['en-CA'] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - // add any entries specific for this region here │ │ │ │ - // e.g. │ │ │ │ - // "someKey": "Some regionally specific value" │ │ │ │ - │ │ │ │ -}, OpenLayers.Lang["en"]); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/ja.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Fryed-peach │ │ │ │ - * - Mage Whopper │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["ja"] │ │ │ │ - * Dictionary for 日本語. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["ja"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "未処理の要求は ${statusText} を返します", │ │ │ │ - │ │ │ │ - 'Permalink': "パーマリンク", │ │ │ │ - │ │ │ │ - 'Overlays': "オーバーレイ", │ │ │ │ - │ │ │ │ - 'Base Layer': "基底レイヤー", │ │ │ │ - │ │ │ │ - 'noFID': "FID のない地物は更新できません。", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "あなたのブラウザはベクターグラフィックスの描写に対応していません。現時点で対応しているソフトウェアは以下のものです。\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "minZoomLevel プロパティは FixedZoomLevels を継承するレイヤーでの使用のみを想定しています。この minZoomLevel に対する WFS レイヤーの検査は歴史的なものです。しかしながら、この検査を除去するとそれに依存する OpenLayers ベースのアプリケーションを破壊してしまう可能性があります。よって廃止が予定されており、この minZoomLevel 検査はバージョン3.0で除去されます。代わりに、http://trac.openlayers.org/wiki/SettingZoomLevels で解説されている、最小および最大解像度設定を使用してください。", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS トランザクション: 成功 ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS トランザクション: 失敗 ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Google レイヤーが正しく読み込みを行えませんでした。\x3cbr\x3e\x3cbr\x3eこのメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。\x3cbr\x3e\x3cbr\x3eおそらく、これは Google マップ用ライブラリのスクリプトが組み込まれていないか、あなたのサイトに対応する正しい API キーが設定されていないためです。\x3cbr\x3e\x3cbr\x3e開発者の方へ: 正しい動作をさせるために\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eこちらのウィキ\x3c/a\x3eを参照してください。", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "${layerType} レイヤーが正しく読み込みを行えませんでした。\x3cbr\x3e\x3cbr\x3eこのメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。\x3cbr\x3e\x3cbr\x3eおそらく、これは ${layerLib} ライブラリのスクリプトが正しく組み込まれていないためです。\x3cbr\x3e\x3cbr\x3e開発者の方へ: 正しい動作をさせるために\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eこちらのウィキ\x3c/a\x3eを参照してください。", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "縮尺 = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "西", │ │ │ │ - │ │ │ │ - 'E': "東", │ │ │ │ - │ │ │ │ - 'N': "北", │ │ │ │ - │ │ │ │ - 'S': "南", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "あなたは「${layerName}」レイヤーで reproject オプションを使っています。このオプションは商用の基底地図上に情報を表示する目的で設計されましたが、現在ではその機能は Spherical Mercator サポートを利用して実現されており、このオプションの使用は非推奨です。追加の情報は http://trac.openlayers.org/wiki/SphericalMercator で入手できます。", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "このメソッドは廃止が予定されており、バージョン3.0で除去されます。代わりに ${newMethod} を使用してください。" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/fi.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Nike │ │ │ │ - * - Str4nd │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["fi"] │ │ │ │ - * Dictionary for Suomi. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["fi"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'Permalink': "Ikilinkki", │ │ │ │ - │ │ │ │ - 'Overlays': "Kerrokset", │ │ │ │ - │ │ │ │ - 'Base Layer': "Peruskerros", │ │ │ │ - │ │ │ │ - 'W': "L", │ │ │ │ - │ │ │ │ - 'E': "I", │ │ │ │ - │ │ │ │ - 'N': "P", │ │ │ │ - │ │ │ │ - 'S': "E" │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/it.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["it"] │ │ │ │ - * Dictionary for Italian. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang.it = { │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Codice di ritorno della richiesta ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Permalink", │ │ │ │ - │ │ │ │ - 'Overlays': "Overlays", │ │ │ │ - │ │ │ │ - 'Base Layer': "Livello base", │ │ │ │ - │ │ │ │ - 'noFID': "Impossibile aggiornare un elemento grafico che non abbia il FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Il tuo browser non supporta il rendering vettoriale. I renderizzatore attualemnte supportati sono:\n${renderers}", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'minZoomLevelError': "La proprietà minZoomLevel è da utilizzare solamente " + │ │ │ │ - "con livelli che abbiano FixedZoomLevels. Il fatto che " + │ │ │ │ - "questo livello wfs controlli la proprietà minZoomLevel è " + │ │ │ │ - "un retaggio del passato. Non possiamo comunque rimuoverla " + │ │ │ │ - "senza rompere le vecchie applicazioni che dipendono su di essa." + │ │ │ │ - "Quindi siamo costretti a deprecarla -- minZoomLevel " + │ │ │ │ - "e sarà rimossa dalla vesione 3.0. Si prega di utilizzare i " + │ │ │ │ - "settaggi di risoluzione min/max come descritto qui: " + │ │ │ │ - "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "Transazione WFS: SUCCESS ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "Transazione WFS: FAILED ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Il livello Google non è riuscito a caricare correttamente.<br><br>" + │ │ │ │ - "Per evitare questo messaggio, seleziona un nuovo BaseLayer " + │ │ │ │ - "nel selettore di livelli nell'angolo in alto a destra.<br><br>" + │ │ │ │ - "Più precisamente, ciò accade perchè la libreria Google Maps " + │ │ │ │ - "non è stata inclusa nella pagina, oppure non contiene la " + │ │ │ │ - "corretta API key per il tuo sito.<br><br>" + │ │ │ │ - "Sviluppatori: Per aiuto su come farlo funzionare correttamente, " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/Google' " + │ │ │ │ - "target='_blank'>clicca qui</a>", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "Il livello ${layerType} non è riuscito a caricare correttamente.<br><br>" + │ │ │ │ - "Per evitare questo messaggio, seleziona un nuovo BaseLayer " + │ │ │ │ - "nel selettore di livelli nell'angolo in alto a destra.<br><br>" + │ │ │ │ - "Più precisamente, ciò accade perchè la libreria ${layerLib} " + │ │ │ │ - "non è stata inclusa nella pagina.<br><br>" + │ │ │ │ - "Sviluppatori: Per aiuto su come farlo funzionare correttamente, " + │ │ │ │ - "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + │ │ │ │ - "target='_blank'>clicca qui</a>", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Scala = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'reprojectDeprecated': "Stai utilizzando l'opzione 'reproject' sul livello ${layerName}. " + │ │ │ │ - "Questa opzione è deprecata: il suo utilizzo è stato introdotto per" + │ │ │ │ - "supportare il disegno dei dati sopra mappe commerciali, ma tale " + │ │ │ │ - "funzionalità dovrebbe essere ottenuta tramite l'utilizzo della proiezione " + │ │ │ │ - "Spherical Mercator. Per maggiori informazioni consultare qui " + │ │ │ │ - "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'methodDeprecated': "Questo metodo è stato deprecato e sarà rimosso dalla versione 3.0. " + │ │ │ │ - "Si prega di utilizzare il metodo ${newMethod} in alternativa.", │ │ │ │ - │ │ │ │ - 'end': '' │ │ │ │ -}; │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/lt.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["lt"] │ │ │ │ - * Dictionary for Lithuanian. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang['lt'] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Neapdorota užklausa gražino ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Pastovi nuoroda", │ │ │ │ - │ │ │ │ - 'Overlays': "Papildomi sluoksniai", │ │ │ │ - │ │ │ │ - 'Base Layer': "Pagrindinis sluoksnis", │ │ │ │ - │ │ │ │ - 'noFID': "Negaliu atnaujinti objekto, kuris neturi FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Jūsų naršyklė nemoka parodyti vektorių. Šiuo metu galima naudotis tokiais rodymo varikliais:\n{renderers}", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS Tranzakcija: PAVYKO ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS Tranzakcija: ŽLUGO ${response}", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Mastelis = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - //labels for the graticule control │ │ │ │ - 'W': 'V', │ │ │ │ - 'E': 'R', │ │ │ │ - 'N': 'Š', │ │ │ │ - 'S': 'P', │ │ │ │ - 'Graticule': 'Tinklelis', │ │ │ │ - │ │ │ │ - // console message │ │ │ │ - 'methodDeprecated': "Šis metodas yra pasenęs ir 3.0 versijoje bus pašalintas. " + │ │ │ │ - "Prašome naudoti ${newMethod}.", │ │ │ │ - │ │ │ │ - // **** end **** │ │ │ │ - 'end': '' │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/ksh.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Purodha │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["ksh"] │ │ │ │ - * Dictionary for Ripoarisch. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["ksh"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Met dä Antwoot op en Aanfrooch ham_mer nix aanjefange: ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Lengk op Duuer", │ │ │ │ - │ │ │ │ - 'Overlays': "Drövver jelaat", │ │ │ │ - │ │ │ │ - 'Base Layer': "Jrund-Nivoh", │ │ │ │ - │ │ │ │ - 'noFID': "En Saach, woh kein \x3ci lang=\"en\"\x3eFID\x3c/i\x3e för doh es, löht sesch nit ändere.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Dinge Brauser kann kein Väktore ußjävve. De Zoote Ußjaabe, di em Momang jon, sen:\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "De Eijeschaff „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“ es bloß doför jedaach, dat mer se met dä Nivvohß bruch, di vun \x3ccode lang=\"en\"\x3eFixedZoomLevels\x3c/code\x3e affhange don. Dat dat \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Nivvoh övverhoup de Eijeschaff „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“ pröhfe deiht, es noch övveresch vun fröhjer. Mer künne dat ävver jez nit fott lohße, oohne dat mer Jevaa loufe, dat Aanwendunge vun OpenLayers nit mieh loufe, di sesch doh velleijsch noch drop am verlohße sin. Dröm sare mer, dat mer et nit mieh han welle, un de „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“-Eijeschaff weed hee vun de Version 3.0 af nit mieh jeprööf wäde. Nemm doför de Enstellung för de hühßte un de kleinßte Oplöhsung, esu wi et en http://trac.openlayers.org/wiki/SettingZoomLevels opjeschrevve es.", │ │ │ │ - │ │ │ │ - 'commitSuccess': "Dä \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Vörjang es joot jeloufe: ${response}", │ │ │ │ - │ │ │ │ - 'commitFailed': "Dä \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Vörjang es scheif jejange: ${response}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Dat Nivvoh \x3ccode lang=\"en\"\x3eGoogle\x3c/code\x3e kunnt nit reschtesch jelaade wääde.\x3cbr /\x3e\x3cbr /\x3eÖm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhke, rähß bovve en de Äk.\x3cbr /\x3e\x3cbr /\x3eWascheinlesch es dat wiel dat \x3ci lang=\"en\"\x3eGoogle-Maps\x3c/i\x3e-Skrepp entweeder nit reschtesch enjebonge wood, udder nit dä reschtejje \x3ci lang=\"en\"\x3eAPI\x3c/i\x3e-Schlößel för Ding Web-ßait scheke deiht.\x3cbr /\x3e\x3cbr /\x3eFör Projrammierer jidd_et Hölp do_drövver, \x3ca href=\"http://trac.openlayers.org/wiki/Google\" target=\"_blank\"\x3ewi mer dat aan et Loufe brengk\x3c/a\x3e.", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "Dat Nivvoh \x3ccode\x3e${layerType}\x3c/code\x3e kunnt nit reschtesch jelaade wääde.\x3cbr /\x3e\x3cbr /\x3eÖm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhkre, rähß bovve en de Äk.\x3cbr /\x3e\x3cbr /\x3eWascheinlesch es dat, wiel dat Skrepp \x3ccode\x3e${layerLib}\x3c/code\x3e nit reschtesch enjebonge wood.\x3cbr /\x3e\x3cbr /\x3eFör Projrammierer jidd_Et Hölp do_drövver, \x3ca href=\"http://trac.openlayers.org/wiki/${layerLib}\" target=\"_blank\"\x3ewi mer dat aan et Loufe brengk\x3c/a\x3e.", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Mohßshtaab = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "W", │ │ │ │ - │ │ │ │ - 'E': "O", │ │ │ │ - │ │ │ │ - 'N': "N", │ │ │ │ - │ │ │ │ - 'S': "S", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Do bruchs de Ußwahl \x3ccode\x3ereproject\x3c/code\x3e op däm Nivvoh \x3ccode\x3e${layerName}\x3c/code\x3e. Di Ußwahl es nit mieh jähn jesinn. Se wohr doför jedaach, öm Date op jeschääfsmäßesch eruß jejovve Kaate bovve drop ze moole, wat ävver enzwesche besser met dä Öngershtözung för de ßfääresche Mäkaator Beldscher jeiht. Doh kanns De mieh drövver fenge op dä Sigg: http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Hee di Metood es nim_mih aktoäll un et weed se en dä Version 3.0 nit mieh jävve. Nemm \x3ccode\x3e${newMethod}\x3c/code\x3e doföör." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ - OpenLayers/Lang/id.js │ │ │ │ - ====================================================================== */ │ │ │ │ - │ │ │ │ -/* Translators (2009 onwards): │ │ │ │ - * - Irwangatot │ │ │ │ - * - IvanLanin │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ - */ │ │ │ │ - │ │ │ │ -/** │ │ │ │ - * Namespace: OpenLayers.Lang["id"] │ │ │ │ - * Dictionary for Bahasa Indonesia. Keys for entries are used in calls to │ │ │ │ - * <OpenLayers.Lang.translate>. Entry bodies are normal strings or │ │ │ │ - * strings formatted for use with <OpenLayers.String.format> calls. │ │ │ │ - */ │ │ │ │ -OpenLayers.Lang["id"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - │ │ │ │ - 'unhandledRequest': "Permintaan yang tak tertangani menghasilkan ${statusText}", │ │ │ │ - │ │ │ │ - 'Permalink': "Pranala permanen", │ │ │ │ - │ │ │ │ - 'Overlays': "Hamparan", │ │ │ │ - │ │ │ │ - 'Base Layer': "Lapisan Dasar", │ │ │ │ - │ │ │ │ - 'noFID': "Tidak dapat memperbarui fitur yang tidak memiliki FID.", │ │ │ │ - │ │ │ │ - 'browserNotSupported': "Peramban Anda tidak mendukung penggambaran vektor. Penggambar yang didukung saat ini adalah:\n${renderers}", │ │ │ │ - │ │ │ │ - 'minZoomLevelError': "Properti minZoomLevel hanya ditujukan bekerja dengan lapisan FixedZoomLevels-descendent. Pengecekan minZoomLevel oleh lapisan wfs adalah peninggalan masa lalu. Kami tidak dapat menghapusnya tanpa kemungkinan merusak aplikasi berbasis OL yang mungkin bergantung padanya. Karenanya, kami menganggapnya tidak berlaku -- Cek minZoomLevel di bawah ini akan dihapus pada 3.0. Silakan gunakan penyetelan resolusi min/maks seperti dijabarkan di sini: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - │ │ │ │ - 'commitSuccess': "WFS Transaksi: BERHASIL ${respon}", │ │ │ │ - │ │ │ │ - 'commitFailed': "WFS Transaksi: GAGAL ${respon}", │ │ │ │ - │ │ │ │ - 'googleWarning': "Lapisan Google tidak dapat dimuat dengan benar.\x3cbr\x3e\x3cbr\x3eUntuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.\x3cbr\x3e\x3cbr\x3eKemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan atau tidak mengandung kunci API yang tepat untuk situs Anda.\x3cbr\x3e\x3cbr\x3ePengembang: Untuk bantuan mengatasi masalah ini, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eklik di sini\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'getLayerWarning': "Lapisan ${layerType} tidak dapat dimuat dengan benar.\x3cbr\x3e\x3cbr\x3eUntuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.\x3cbr\x3e\x3cbr\x3eKemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan dengan benar.\x3cbr\x3e\x3cbr\x3ePengembang: Untuk bantuan mengatasi masalah ini, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik di sini\x3c/a\x3e", │ │ │ │ - │ │ │ │ - 'Scale = 1 : ${scaleDenom}': "Sekala = 1 : ${scaleDenom}", │ │ │ │ - │ │ │ │ - 'W': "B", │ │ │ │ - │ │ │ │ - 'E': "T", │ │ │ │ - │ │ │ │ - 'N': "U", │ │ │ │ - │ │ │ │ - 'S': "S", │ │ │ │ - │ │ │ │ - 'reprojectDeprecated': "Anda menggunakan opsi \'reproject\' pada lapisan ${layerName}. Opsi ini telah ditinggalkan: penggunaannya dirancang untuk mendukung tampilan data melalui peta dasar komersial, tapi fungsionalitas tersebut saat ini harus dilakukan dengan menggunakan dukungan Spherical Mercator. Informasi lebih lanjut tersedia di http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - │ │ │ │ - 'methodDeprecated': "Metode ini telah usang dan akan dihapus di 3.0. Sebaliknya, harap gunakan ${newMethod}." │ │ │ │ - │ │ │ │ -}); │ │ │ │ -/* ====================================================================== │ │ │ │ OpenLayers/Popup/Framed.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. */ │ │ ├── ./usr/share/javascript/openlayers/OpenLayers.tests.min.js │ │ │ ├── js-beautify {} │ │ │ │ @@ -13318,98 +13318,35 @@ │ │ │ │ var corner = OpenLayers.Bounds.oppositeQuadrant(this.relativePosition); │ │ │ │ OpenLayers.Util.removeItem(corners, corner); │ │ │ │ return corners.join(" ") │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Popup.AnchoredBubble" │ │ │ │ }); │ │ │ │ OpenLayers.Popup.AnchoredBubble.CORNER_SIZE = 5; │ │ │ │ -OpenLayers.Rule = OpenLayers.Class({ │ │ │ │ - id: null, │ │ │ │ - name: null, │ │ │ │ - title: null, │ │ │ │ - description: null, │ │ │ │ - context: null, │ │ │ │ - filter: null, │ │ │ │ - elseFilter: false, │ │ │ │ - symbolizer: null, │ │ │ │ - symbolizers: null, │ │ │ │ - minScaleDenominator: null, │ │ │ │ - maxScaleDenominator: null, │ │ │ │ +OpenLayers.Filter = OpenLayers.Class({ │ │ │ │ initialize: function(options) { │ │ │ │ - this.symbolizer = {}; │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - if (this.symbolizers) { │ │ │ │ - delete this.symbolizer │ │ │ │ - } │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - for (var i in this.symbolizer) { │ │ │ │ - this.symbolizer[i] = null │ │ │ │ - } │ │ │ │ - this.symbolizer = null; │ │ │ │ - delete this.symbolizers │ │ │ │ - }, │ │ │ │ - evaluate: function(feature) { │ │ │ │ - var context = this.getContext(feature); │ │ │ │ - var applies = true; │ │ │ │ - if (this.minScaleDenominator || this.maxScaleDenominator) { │ │ │ │ - var scale = feature.layer.map.getScale() │ │ │ │ - } │ │ │ │ - if (this.minScaleDenominator) { │ │ │ │ - applies = scale >= OpenLayers.Style.createLiteral(this.minScaleDenominator, context) │ │ │ │ - } │ │ │ │ - if (applies && this.maxScaleDenominator) { │ │ │ │ - applies = scale < OpenLayers.Style.createLiteral(this.maxScaleDenominator, context) │ │ │ │ - } │ │ │ │ - if (applies && this.filter) { │ │ │ │ - if (this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") { │ │ │ │ - applies = this.filter.evaluate(feature) │ │ │ │ - } else { │ │ │ │ - applies = this.filter.evaluate(context) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return applies │ │ │ │ + OpenLayers.Util.extend(this, options) │ │ │ │ }, │ │ │ │ - getContext: function(feature) { │ │ │ │ - var context = this.context; │ │ │ │ - if (!context) { │ │ │ │ - context = feature.attributes || feature.data │ │ │ │ - } │ │ │ │ - if (typeof this.context == "function") { │ │ │ │ - context = this.context(feature) │ │ │ │ - } │ │ │ │ - return context │ │ │ │ + destroy: function() {}, │ │ │ │ + evaluate: function(context) { │ │ │ │ + return true │ │ │ │ }, │ │ │ │ clone: function() { │ │ │ │ - var options = OpenLayers.Util.extend({}, this); │ │ │ │ - if (this.symbolizers) { │ │ │ │ - var len = this.symbolizers.length; │ │ │ │ - options.symbolizers = new Array(len); │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ - options.symbolizers[i] = this.symbolizers[i].clone() │ │ │ │ - } │ │ │ │ + return null │ │ │ │ + }, │ │ │ │ + toString: function() { │ │ │ │ + var string; │ │ │ │ + if (OpenLayers.Format && OpenLayers.Format.CQL) { │ │ │ │ + string = OpenLayers.Format.CQL.prototype.write(this) │ │ │ │ } else { │ │ │ │ - options.symbolizer = {}; │ │ │ │ - var value, type; │ │ │ │ - for (var key in this.symbolizer) { │ │ │ │ - value = this.symbolizer[key]; │ │ │ │ - type = typeof value; │ │ │ │ - if (type === "object") { │ │ │ │ - options.symbolizer[key] = OpenLayers.Util.extend({}, value) │ │ │ │ - } else if (type === "string") { │ │ │ │ - options.symbolizer[key] = value │ │ │ │ - } │ │ │ │ - } │ │ │ │ + string = Object.prototype.toString.call(this) │ │ │ │ } │ │ │ │ - options.filter = this.filter && this.filter.clone(); │ │ │ │ - options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ - return new OpenLayers.Rule(options) │ │ │ │ + return string │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Rule" │ │ │ │ + CLASS_NAME: "OpenLayers.Filter" │ │ │ │ }); │ │ │ │ OpenLayers.TileManager = OpenLayers.Class({ │ │ │ │ cacheSize: 256, │ │ │ │ tilesPerFrame: 2, │ │ │ │ frameDelay: 16, │ │ │ │ moveDelay: 100, │ │ │ │ zoomDelay: 200, │ │ │ │ @@ -13647,143 +13584,14 @@ │ │ │ │ this.tileQueue = null; │ │ │ │ this.tileQueueId = null; │ │ │ │ this.tileCache = null; │ │ │ │ this.tileCacheIndex = null; │ │ │ │ this._destroyed = true │ │ │ │ } │ │ │ │ }); │ │ │ │ -OpenLayers.Strategy = OpenLayers.Class({ │ │ │ │ - layer: null, │ │ │ │ - options: null, │ │ │ │ - active: null, │ │ │ │ - autoActivate: true, │ │ │ │ - autoDestroy: true, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ - this.options = options; │ │ │ │ - this.active = false │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - this.layer = null; │ │ │ │ - this.options = null │ │ │ │ - }, │ │ │ │ - setLayer: function(layer) { │ │ │ │ - this.layer = layer │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (!this.active) { │ │ │ │ - this.active = true; │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (this.active) { │ │ │ │ - this.active = false; │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler = OpenLayers.Class({ │ │ │ │ - id: null, │ │ │ │ - control: null, │ │ │ │ - map: null, │ │ │ │ - keyMask: null, │ │ │ │ - active: false, │ │ │ │ - evt: null, │ │ │ │ - touch: false, │ │ │ │ - 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 + "_") │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - this.map = map │ │ │ │ - }, │ │ │ │ - checkModifiers: function(evt) { │ │ │ │ - if (this.keyMask == null) { │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - 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); │ │ │ │ - return keyModifiers == this.keyMask │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (this.active) { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (!this.active) { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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]]) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - callback: function(name, args) { │ │ │ │ - if (name && this.callbacks[name]) { │ │ │ │ - this.callbacks[name].apply(this.control, args) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - register: function(name, method) { │ │ │ │ - this.map.events.registerPriority(name, this, method); │ │ │ │ - this.map.events.registerPriority(name, this, this.setEvent) │ │ │ │ - }, │ │ │ │ - unregister: function(name, method) { │ │ │ │ - this.map.events.unregister(name, this, method); │ │ │ │ - this.map.events.unregister(name, this, this.setEvent) │ │ │ │ - }, │ │ │ │ - setEvent: function(evt) { │ │ │ │ - this.evt = evt; │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - this.control = this.map = null │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.MOD_NONE = 0; │ │ │ │ -OpenLayers.Handler.MOD_SHIFT = 1; │ │ │ │ -OpenLayers.Handler.MOD_CTRL = 2; │ │ │ │ -OpenLayers.Handler.MOD_ALT = 4; │ │ │ │ -OpenLayers.Handler.MOD_META = 8; │ │ │ │ OpenLayers.Icon = OpenLayers.Class({ │ │ │ │ url: null, │ │ │ │ size: null, │ │ │ │ offset: null, │ │ │ │ calculateOffset: null, │ │ │ │ imageDiv: null, │ │ │ │ px: null, │ │ │ │ @@ -13858,14 +13666,96 @@ │ │ │ │ }, │ │ │ │ isDrawn: function() { │ │ │ │ var isDrawn = this.imageDiv && this.imageDiv.parentNode && this.imageDiv.parentNode.nodeType != 11; │ │ │ │ return isDrawn │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Icon" │ │ │ │ }); │ │ │ │ +OpenLayers.Marker = OpenLayers.Class({ │ │ │ │ + icon: null, │ │ │ │ + lonlat: null, │ │ │ │ + events: null, │ │ │ │ + map: null, │ │ │ │ + initialize: function(lonlat, icon) { │ │ │ │ + this.lonlat = lonlat; │ │ │ │ + var newIcon = icon ? icon : OpenLayers.Marker.defaultIcon(); │ │ │ │ + if (this.icon == null) { │ │ │ │ + this.icon = newIcon │ │ │ │ + } else { │ │ │ │ + this.icon.url = newIcon.url; │ │ │ │ + this.icon.size = newIcon.size; │ │ │ │ + this.icon.offset = newIcon.offset; │ │ │ │ + this.icon.calculateOffset = newIcon.calculateOffset │ │ │ │ + } │ │ │ │ + this.events = new OpenLayers.Events(this, this.icon.imageDiv) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.erase(); │ │ │ │ + this.map = null; │ │ │ │ + this.events.destroy(); │ │ │ │ + this.events = null; │ │ │ │ + if (this.icon != null) { │ │ │ │ + this.icon.destroy(); │ │ │ │ + this.icon = null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + draw: function(px) { │ │ │ │ + return this.icon.draw(px) │ │ │ │ + }, │ │ │ │ + erase: function() { │ │ │ │ + if (this.icon != null) { │ │ │ │ + this.icon.erase() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + moveTo: function(px) { │ │ │ │ + if (px != null && this.icon != null) { │ │ │ │ + this.icon.moveTo(px) │ │ │ │ + } │ │ │ │ + this.lonlat = this.map.getLonLatFromLayerPx(px) │ │ │ │ + }, │ │ │ │ + isDrawn: function() { │ │ │ │ + var isDrawn = this.icon && this.icon.isDrawn(); │ │ │ │ + return isDrawn │ │ │ │ + }, │ │ │ │ + onScreen: function() { │ │ │ │ + var onScreen = false; │ │ │ │ + if (this.map) { │ │ │ │ + var screenBounds = this.map.getExtent(); │ │ │ │ + onScreen = screenBounds.containsLonLat(this.lonlat) │ │ │ │ + } │ │ │ │ + return onScreen │ │ │ │ + }, │ │ │ │ + inflate: function(inflate) { │ │ │ │ + if (this.icon) { │ │ │ │ + this.icon.setSize({ │ │ │ │ + w: this.icon.size.w * inflate, │ │ │ │ + h: this.icon.size.h * inflate │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ + this.icon.setOpacity(opacity) │ │ │ │ + }, │ │ │ │ + setUrl: function(url) { │ │ │ │ + this.icon.setUrl(url) │ │ │ │ + }, │ │ │ │ + display: function(display) { │ │ │ │ + this.icon.display(display) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Marker" │ │ │ │ +}); │ │ │ │ +OpenLayers.Marker.defaultIcon = function() { │ │ │ │ + return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"), { │ │ │ │ + w: 21, │ │ │ │ + h: 25 │ │ │ │ + }, { │ │ │ │ + x: -10.5, │ │ │ │ + y: -25 │ │ │ │ + }) │ │ │ │ +}; │ │ │ │ OpenLayers.Format.GeoJSON = OpenLayers.Class(OpenLayers.Format.JSON, { │ │ │ │ ignoreExtraDims: false, │ │ │ │ read: function(json, type, filter) { │ │ │ │ type = type ? type : "FeatureCollection"; │ │ │ │ var results = null; │ │ │ │ var obj = null; │ │ │ │ if (typeof json == "string") { │ │ │ │ @@ -14842,36 +14732,14 @@ │ │ │ │ throw "Unsupported WFST version: " + options.version │ │ │ │ } │ │ │ │ return new cls(options) │ │ │ │ }; │ │ │ │ OpenLayers.Format.WFST.DEFAULTS = { │ │ │ │ version: "1.0.0" │ │ │ │ }; │ │ │ │ -OpenLayers.Filter = OpenLayers.Class({ │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options) │ │ │ │ - }, │ │ │ │ - destroy: function() {}, │ │ │ │ - evaluate: function(context) { │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - clone: function() { │ │ │ │ - return null │ │ │ │ - }, │ │ │ │ - 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.Spatial = OpenLayers.Class(OpenLayers.Filter, { │ │ │ │ type: null, │ │ │ │ property: null, │ │ │ │ value: null, │ │ │ │ distance: null, │ │ │ │ distanceUnits: null, │ │ │ │ evaluate: function(feature) { │ │ │ │ @@ -17718,181 +17586,326 @@ │ │ │ │ process: null, │ │ │ │ output: null, │ │ │ │ initialize: function(options) { │ │ │ │ OpenLayers.Util.extend(this, options) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.WPSProcess.ChainLink" │ │ │ │ }); │ │ │ │ +OpenLayers.Strategy = OpenLayers.Class({ │ │ │ │ + layer: null, │ │ │ │ + options: null, │ │ │ │ + active: null, │ │ │ │ + autoActivate: true, │ │ │ │ + autoDestroy: true, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + this.options = options; │ │ │ │ + this.active = false │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + this.layer = null; │ │ │ │ + this.options = null │ │ │ │ + }, │ │ │ │ + setLayer: function(layer) { │ │ │ │ + this.layer = layer │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (!this.active) { │ │ │ │ + this.active = true; │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (this.active) { │ │ │ │ + this.active = false; │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ +}); │ │ │ │ +OpenLayers.Kinetic = OpenLayers.Class({ │ │ │ │ + threshold: 0, │ │ │ │ + deceleration: .0035, │ │ │ │ + nbPoints: 100, │ │ │ │ + delay: 200, │ │ │ │ + points: undefined, │ │ │ │ + timerId: undefined, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Util.extend(this, options) │ │ │ │ + }, │ │ │ │ + begin: function() { │ │ │ │ + OpenLayers.Animation.stop(this.timerId); │ │ │ │ + this.timerId = undefined; │ │ │ │ + this.points = [] │ │ │ │ + }, │ │ │ │ + update: function(xy) { │ │ │ │ + this.points.unshift({ │ │ │ │ + xy: xy, │ │ │ │ + tick: (new Date).getTime() │ │ │ │ + }); │ │ │ │ + if (this.points.length > this.nbPoints) { │ │ │ │ + this.points.pop() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 + 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.Rule = OpenLayers.Class({ │ │ │ │ + id: null, │ │ │ │ + name: null, │ │ │ │ + title: null, │ │ │ │ + description: null, │ │ │ │ + context: null, │ │ │ │ + filter: null, │ │ │ │ + elseFilter: false, │ │ │ │ + symbolizer: null, │ │ │ │ + symbolizers: null, │ │ │ │ + minScaleDenominator: null, │ │ │ │ + maxScaleDenominator: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + this.symbolizer = {}; │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ + if (this.symbolizers) { │ │ │ │ + delete this.symbolizer │ │ │ │ + } │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + for (var i in this.symbolizer) { │ │ │ │ + this.symbolizer[i] = null │ │ │ │ + } │ │ │ │ + this.symbolizer = null; │ │ │ │ + delete this.symbolizers │ │ │ │ + }, │ │ │ │ + evaluate: function(feature) { │ │ │ │ + var context = this.getContext(feature); │ │ │ │ + var applies = true; │ │ │ │ + if (this.minScaleDenominator || this.maxScaleDenominator) { │ │ │ │ + var scale = feature.layer.map.getScale() │ │ │ │ + } │ │ │ │ + if (this.minScaleDenominator) { │ │ │ │ + applies = scale >= OpenLayers.Style.createLiteral(this.minScaleDenominator, context) │ │ │ │ + } │ │ │ │ + if (applies && this.maxScaleDenominator) { │ │ │ │ + applies = scale < OpenLayers.Style.createLiteral(this.maxScaleDenominator, context) │ │ │ │ + } │ │ │ │ + if (applies && this.filter) { │ │ │ │ + if (this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") { │ │ │ │ + applies = this.filter.evaluate(feature) │ │ │ │ + } else { │ │ │ │ + applies = this.filter.evaluate(context) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return applies │ │ │ │ + }, │ │ │ │ + getContext: function(feature) { │ │ │ │ + var context = this.context; │ │ │ │ + if (!context) { │ │ │ │ + context = feature.attributes || feature.data │ │ │ │ + } │ │ │ │ + if (typeof this.context == "function") { │ │ │ │ + context = this.context(feature) │ │ │ │ + } │ │ │ │ + return context │ │ │ │ + }, │ │ │ │ + clone: function() { │ │ │ │ + var options = OpenLayers.Util.extend({}, this); │ │ │ │ + if (this.symbolizers) { │ │ │ │ + var len = this.symbolizers.length; │ │ │ │ + options.symbolizers = new Array(len); │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ + options.symbolizers[i] = this.symbolizers[i].clone() │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + options.symbolizer = {}; │ │ │ │ + var value, type; │ │ │ │ + for (var key in this.symbolizer) { │ │ │ │ + value = this.symbolizer[key]; │ │ │ │ + type = typeof value; │ │ │ │ + if (type === "object") { │ │ │ │ + options.symbolizer[key] = OpenLayers.Util.extend({}, value) │ │ │ │ + } else if (type === "string") { │ │ │ │ + options.symbolizer[key] = value │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + options.filter = this.filter && this.filter.clone(); │ │ │ │ + options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ + return new OpenLayers.Rule(options) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Rule" │ │ │ │ +}); │ │ │ │ OpenLayers.Spherical = OpenLayers.Spherical || {}; │ │ │ │ OpenLayers.Spherical.DEFAULT_RADIUS = 6378137; │ │ │ │ OpenLayers.Spherical.computeDistanceBetween = function(from, to, radius) { │ │ │ │ var R = radius || OpenLayers.Spherical.DEFAULT_RADIUS; │ │ │ │ var sinHalfDeltaLon = Math.sin(Math.PI * (to.lon - from.lon) / 360); │ │ │ │ var sinHalfDeltaLat = Math.sin(Math.PI * (to.lat - from.lat) / 360); │ │ │ │ var a = sinHalfDeltaLat * sinHalfDeltaLat + sinHalfDeltaLon * sinHalfDeltaLon * Math.cos(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) │ │ │ │ }; │ │ │ │ OpenLayers.Spherical.computeHeading = function(from, to) { │ │ │ │ var y = Math.sin(Math.PI * (from.lon - to.lon) / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ var x = Math.cos(Math.PI * from.lat / 180) * Math.sin(Math.PI * to.lat / 180) - Math.sin(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180) * Math.cos(Math.PI * (from.lon - to.lon) / 180); │ │ │ │ return 180 * Math.atan2(y, x) / Math.PI │ │ │ │ }; │ │ │ │ -OpenLayers.Symbolizer = OpenLayers.Class({ │ │ │ │ - zIndex: 0, │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Util.extend(this, config) │ │ │ │ - }, │ │ │ │ - clone: function() { │ │ │ │ - var Type = eval(this.CLASS_NAME); │ │ │ │ - return new Type(OpenLayers.Util.extend({}, this)) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer" │ │ │ │ -}); │ │ │ │ -OpenLayers.Marker = OpenLayers.Class({ │ │ │ │ - icon: null, │ │ │ │ - lonlat: null, │ │ │ │ - events: null, │ │ │ │ +OpenLayers.Handler = OpenLayers.Class({ │ │ │ │ + id: null, │ │ │ │ + control: null, │ │ │ │ map: null, │ │ │ │ - initialize: function(lonlat, icon) { │ │ │ │ - this.lonlat = lonlat; │ │ │ │ - var newIcon = icon ? icon : OpenLayers.Marker.defaultIcon(); │ │ │ │ - if (this.icon == null) { │ │ │ │ - this.icon = newIcon │ │ │ │ - } else { │ │ │ │ - this.icon.url = newIcon.url; │ │ │ │ - this.icon.size = newIcon.size; │ │ │ │ - this.icon.offset = newIcon.offset; │ │ │ │ - this.icon.calculateOffset = newIcon.calculateOffset │ │ │ │ - } │ │ │ │ - this.events = new OpenLayers.Events(this, this.icon.imageDiv) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.erase(); │ │ │ │ - this.map = null; │ │ │ │ - this.events.destroy(); │ │ │ │ - this.events = null; │ │ │ │ - if (this.icon != null) { │ │ │ │ - this.icon.destroy(); │ │ │ │ - this.icon = null │ │ │ │ + keyMask: null, │ │ │ │ + active: false, │ │ │ │ + evt: null, │ │ │ │ + touch: false, │ │ │ │ + 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 + "_") │ │ │ │ }, │ │ │ │ - draw: function(px) { │ │ │ │ - return this.icon.draw(px) │ │ │ │ + setMap: function(map) { │ │ │ │ + this.map = map │ │ │ │ }, │ │ │ │ - erase: function() { │ │ │ │ - if (this.icon != null) { │ │ │ │ - this.icon.erase() │ │ │ │ + checkModifiers: function(evt) { │ │ │ │ + if (this.keyMask == null) { │ │ │ │ + return true │ │ │ │ } │ │ │ │ + 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); │ │ │ │ + return keyModifiers == this.keyMask │ │ │ │ }, │ │ │ │ - moveTo: function(px) { │ │ │ │ - if (px != null && this.icon != null) { │ │ │ │ - this.icon.moveTo(px) │ │ │ │ + activate: function() { │ │ │ │ + if (this.active) { │ │ │ │ + return false │ │ │ │ } │ │ │ │ - this.lonlat = this.map.getLonLatFromLayerPx(px) │ │ │ │ - }, │ │ │ │ - isDrawn: function() { │ │ │ │ - var isDrawn = this.icon && this.icon.isDrawn(); │ │ │ │ - return isDrawn │ │ │ │ - }, │ │ │ │ - onScreen: function() { │ │ │ │ - var onScreen = false; │ │ │ │ - if (this.map) { │ │ │ │ - var screenBounds = this.map.getExtent(); │ │ │ │ - onScreen = screenBounds.containsLonLat(this.lonlat) │ │ │ │ + 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]]) │ │ │ │ + } │ │ │ │ } │ │ │ │ - return onScreen │ │ │ │ + this.active = true; │ │ │ │ + return true │ │ │ │ }, │ │ │ │ - inflate: function(inflate) { │ │ │ │ - if (this.icon) { │ │ │ │ - this.icon.setSize({ │ │ │ │ - w: this.icon.size.w * inflate, │ │ │ │ - h: this.icon.size.h * inflate │ │ │ │ - }) │ │ │ │ + deactivate: function() { │ │ │ │ + if (!this.active) { │ │ │ │ + return false │ │ │ │ } │ │ │ │ + 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 │ │ │ │ }, │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ - this.icon.setOpacity(opacity) │ │ │ │ - }, │ │ │ │ - setUrl: function(url) { │ │ │ │ - this.icon.setUrl(url) │ │ │ │ - }, │ │ │ │ - display: function(display) { │ │ │ │ - this.icon.display(display) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Marker" │ │ │ │ -}); │ │ │ │ -OpenLayers.Marker.defaultIcon = function() { │ │ │ │ - return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"), { │ │ │ │ - w: 21, │ │ │ │ - h: 25 │ │ │ │ - }, { │ │ │ │ - x: -10.5, │ │ │ │ - y: -25 │ │ │ │ - }) │ │ │ │ -}; │ │ │ │ -OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Point" │ │ │ │ -}); │ │ │ │ -OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ + 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]]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Line" │ │ │ │ -}); │ │ │ │ -OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ + callback: function(name, args) { │ │ │ │ + if (name && this.callbacks[name]) { │ │ │ │ + this.callbacks[name].apply(this.control, args) │ │ │ │ + } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Polygon" │ │ │ │ -}); │ │ │ │ -OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ + register: function(name, method) { │ │ │ │ + this.map.events.registerPriority(name, this, method); │ │ │ │ + this.map.events.registerPriority(name, this, this.setEvent) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Text" │ │ │ │ -}); │ │ │ │ -OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ + unregister: function(name, method) { │ │ │ │ + this.map.events.unregister(name, this, method); │ │ │ │ + this.map.events.unregister(name, this, this.setEvent) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Raster" │ │ │ │ -}); │ │ │ │ -OpenLayers.Style2 = OpenLayers.Class({ │ │ │ │ - id: null, │ │ │ │ - name: null, │ │ │ │ - title: null, │ │ │ │ - description: null, │ │ │ │ - layerName: null, │ │ │ │ - isDefault: false, │ │ │ │ - rules: null, │ │ │ │ - initialize: function(config) { │ │ │ │ - OpenLayers.Util.extend(this, config); │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ + setEvent: function(evt) { │ │ │ │ + this.evt = evt; │ │ │ │ + return true │ │ │ │ }, │ │ │ │ destroy: function() { │ │ │ │ - for (var i = 0, len = this.rules.length; i < len; i++) { │ │ │ │ - this.rules[i].destroy() │ │ │ │ - } │ │ │ │ - delete this.rules │ │ │ │ - }, │ │ │ │ - clone: function() { │ │ │ │ - var config = OpenLayers.Util.extend({}, this); │ │ │ │ - if (this.rules) { │ │ │ │ - config.rules = []; │ │ │ │ - for (var i = 0, len = this.rules.length; i < len; ++i) { │ │ │ │ - config.rules.push(this.rules[i].clone()) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return new OpenLayers.Style2(config) │ │ │ │ + this.deactivate(); │ │ │ │ + this.control = this.map = null │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Style2" │ │ │ │ + CLASS_NAME: "OpenLayers.Handler" │ │ │ │ }); │ │ │ │ +OpenLayers.Handler.MOD_NONE = 0; │ │ │ │ +OpenLayers.Handler.MOD_SHIFT = 1; │ │ │ │ +OpenLayers.Handler.MOD_CTRL = 2; │ │ │ │ +OpenLayers.Handler.MOD_ALT = 4; │ │ │ │ +OpenLayers.Handler.MOD_META = 8; │ │ │ │ OpenLayers.Format.WPSDescribeProcess = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ VERSION: "1.0.0", │ │ │ │ namespaces: { │ │ │ │ wps: "http://www.opengis.net/wps/1.0.0", │ │ │ │ ows: "http://www.opengis.net/ows/1.1", │ │ │ │ xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ }, │ │ │ │ @@ -18077,1205 +18090,85 @@ │ │ │ │ destroy: function() { │ │ │ │ this.events.destroy(); │ │ │ │ this.events = null; │ │ │ │ this.servers = null │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.WPSClient" │ │ │ │ }); │ │ │ │ -OpenLayers.Kinetic = OpenLayers.Class({ │ │ │ │ - threshold: 0, │ │ │ │ - deceleration: .0035, │ │ │ │ - nbPoints: 100, │ │ │ │ - delay: 200, │ │ │ │ - points: undefined, │ │ │ │ - timerId: undefined, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Util.extend(this, options) │ │ │ │ - }, │ │ │ │ - begin: function() { │ │ │ │ - OpenLayers.Animation.stop(this.timerId); │ │ │ │ - this.timerId = undefined; │ │ │ │ - this.points = [] │ │ │ │ - }, │ │ │ │ - update: function(xy) { │ │ │ │ - this.points.unshift({ │ │ │ │ - xy: xy, │ │ │ │ - tick: (new Date).getTime() │ │ │ │ - }); │ │ │ │ - if (this.points.length > this.nbPoints) { │ │ │ │ - this.points.pop() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 + 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.GeoRSS = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ - location: null, │ │ │ │ - features: null, │ │ │ │ - formatOptions: null, │ │ │ │ - selectedFeature: null, │ │ │ │ - icon: null, │ │ │ │ - popupSize: null, │ │ │ │ - useFeedTitle: true, │ │ │ │ - initialize: function(name, location, options) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.initialize.apply(this, [name, options]); │ │ │ │ - this.location = location; │ │ │ │ - this.features = [] │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ - this.clearFeatures(); │ │ │ │ - this.features = null │ │ │ │ - }, │ │ │ │ - loadRSS: function() { │ │ │ │ - if (!this.loaded) { │ │ │ │ - this.events.triggerEvent("loadstart"); │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ - url: this.location, │ │ │ │ - success: this.parseData, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.loaded = true │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ - if (this.visibility && !this.loaded) { │ │ │ │ - this.loadRSS() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - parseData: function(ajaxRequest) { │ │ │ │ - var doc = ajaxRequest.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = OpenLayers.Format.XML.prototype.read(ajaxRequest.responseText) │ │ │ │ - } │ │ │ │ - if (this.useFeedTitle) { │ │ │ │ - var name = null; │ │ │ │ - try { │ │ │ │ - name = doc.getElementsByTagNameNS("*", "title")[0].firstChild.nodeValue │ │ │ │ - } catch (e) { │ │ │ │ - try { │ │ │ │ - name = doc.getElementsByTagName("title")[0].firstChild.nodeValue │ │ │ │ - } catch (e) {} │ │ │ │ - } │ │ │ │ - if (name) { │ │ │ │ - this.setName(name) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var options = {}; │ │ │ │ - OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ - if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ - options.externalProjection = this.projection; │ │ │ │ - options.internalProjection = this.map.getProjectionObject() │ │ │ │ - } │ │ │ │ - var format = new OpenLayers.Format.GeoRSS(options); │ │ │ │ - var features = format.read(doc); │ │ │ │ - for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ - var data = {}; │ │ │ │ - var feature = features[i]; │ │ │ │ - if (!feature.geometry) { │ │ │ │ - continue │ │ │ │ - } │ │ │ │ - var title = feature.attributes.title ? feature.attributes.title : "Untitled"; │ │ │ │ - var description = feature.attributes.description ? feature.attributes.description : "No description."; │ │ │ │ - var link = feature.attributes.link ? feature.attributes.link : ""; │ │ │ │ - var location = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ - data.icon = this.icon == null ? OpenLayers.Marker.defaultIcon() : this.icon.clone(); │ │ │ │ - data.popupSize = this.popupSize ? this.popupSize.clone() : new OpenLayers.Size(250, 120); │ │ │ │ - if (title || description) { │ │ │ │ - data.title = title; │ │ │ │ - data.description = description; │ │ │ │ - var contentHTML = '<div class="olLayerGeoRSSClose">[x]</div>'; │ │ │ │ - contentHTML += '<div class="olLayerGeoRSSTitle">'; │ │ │ │ - if (link) { │ │ │ │ - contentHTML += '<a class="link" href="' + link + '" target="_blank">' │ │ │ │ - } │ │ │ │ - contentHTML += title; │ │ │ │ - if (link) { │ │ │ │ - contentHTML += "</a>" │ │ │ │ - } │ │ │ │ - contentHTML += "</div>"; │ │ │ │ - contentHTML += '<div style="" class="olLayerGeoRSSDescription">'; │ │ │ │ - contentHTML += description; │ │ │ │ - contentHTML += "</div>"; │ │ │ │ - data["popupContentHTML"] = contentHTML │ │ │ │ - } │ │ │ │ - var feature = new OpenLayers.Feature(this, location, data); │ │ │ │ - this.features.push(feature); │ │ │ │ - var marker = feature.createMarker(); │ │ │ │ - marker.events.register("click", feature, this.markerClick); │ │ │ │ - this.addMarker(marker) │ │ │ │ - } │ │ │ │ - this.events.triggerEvent("loadend") │ │ │ │ - }, │ │ │ │ - markerClick: function(evt) { │ │ │ │ - var sameMarkerClicked = this == this.layer.selectedFeature; │ │ │ │ - this.layer.selectedFeature = !sameMarkerClicked ? this : null; │ │ │ │ - for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ - this.layer.map.removePopup(this.layer.map.popups[i]) │ │ │ │ - } │ │ │ │ - if (!sameMarkerClicked) { │ │ │ │ - var popup = this.createPopup(); │ │ │ │ - OpenLayers.Event.observe(popup.div, "click", OpenLayers.Function.bind(function() { │ │ │ │ - for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ - this.layer.map.removePopup(this.layer.map.popups[i]) │ │ │ │ - } │ │ │ │ - }, this)); │ │ │ │ - this.layer.map.addPopup(popup) │ │ │ │ - } │ │ │ │ - OpenLayers.Event.stop(evt) │ │ │ │ - }, │ │ │ │ - clearFeatures: function() { │ │ │ │ - if (this.features != null) { │ │ │ │ - while (this.features.length > 0) { │ │ │ │ - var feature = this.features[0]; │ │ │ │ - OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ - feature.destroy() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.GeoRSS" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - isBaseLayer: true, │ │ │ │ - sphericalMercator: false, │ │ │ │ - zoomOffset: 0, │ │ │ │ - serverResolutions: null, │ │ │ │ - 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]) │ │ │ │ - }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.XYZ(this.name, this.url, this.getOptions()) │ │ │ │ - } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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.ArcGISCache = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ - url: null, │ │ │ │ - tileOrigin: null, │ │ │ │ - tileSize: new OpenLayers.Size(256, 256), │ │ │ │ - useArcGISServer: true, │ │ │ │ - type: "png", │ │ │ │ - useScales: false, │ │ │ │ - overrideDPI: false, │ │ │ │ - initialize: function(name, url, options) { │ │ │ │ - OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments); │ │ │ │ - if (this.resolutions) { │ │ │ │ - this.serverResolutions = this.resolutions; │ │ │ │ - this.maxExtent = this.getMaxExtentForResolution(this.resolutions[0]) │ │ │ │ - } │ │ │ │ - if (this.layerInfo) { │ │ │ │ - var info = this.layerInfo; │ │ │ │ - var startingTileExtent = new OpenLayers.Bounds(info.fullExtent.xmin, info.fullExtent.ymin, info.fullExtent.xmax, info.fullExtent.ymax); │ │ │ │ - this.projection = "EPSG:" + info.spatialReference.wkid; │ │ │ │ - this.sphericalMercator = info.spatialReference.wkid == 102100; │ │ │ │ - this.units = info.units == "esriFeet" ? "ft" : "m"; │ │ │ │ - if (!!info.tileInfo) { │ │ │ │ - this.tileSize = new OpenLayers.Size(info.tileInfo.width || info.tileInfo.cols, info.tileInfo.height || info.tileInfo.rows); │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat(info.tileInfo.origin.x, info.tileInfo.origin.y); │ │ │ │ - var upperLeft = new OpenLayers.Geometry.Point(startingTileExtent.left, startingTileExtent.top); │ │ │ │ - var bottomRight = new OpenLayers.Geometry.Point(startingTileExtent.right, startingTileExtent.bottom); │ │ │ │ - if (this.useScales) { │ │ │ │ - this.scales = [] │ │ │ │ - } else { │ │ │ │ - this.resolutions = [] │ │ │ │ - } │ │ │ │ - this.lods = []; │ │ │ │ - for (var key in info.tileInfo.lods) { │ │ │ │ - if (info.tileInfo.lods.hasOwnProperty(key)) { │ │ │ │ - var lod = info.tileInfo.lods[key]; │ │ │ │ - if (this.useScales) { │ │ │ │ - this.scales.push(lod.scale) │ │ │ │ - } else { │ │ │ │ - this.resolutions.push(lod.resolution) │ │ │ │ - } │ │ │ │ - var start = this.getContainingTileCoords(upperLeft, lod.resolution); │ │ │ │ - lod.startTileCol = start.x; │ │ │ │ - lod.startTileRow = start.y; │ │ │ │ - var end = this.getContainingTileCoords(bottomRight, lod.resolution); │ │ │ │ - lod.endTileCol = end.x; │ │ │ │ - lod.endTileRow = end.y; │ │ │ │ - this.lods.push(lod) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.maxExtent = this.calculateMaxExtentWithLOD(this.lods[0]); │ │ │ │ - this.serverResolutions = this.resolutions; │ │ │ │ - if (this.overrideDPI && info.tileInfo.dpi) { │ │ │ │ - OpenLayers.DOTS_PER_INCH = info.tileInfo.dpi │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getContainingTileCoords: function(point, res) { │ │ │ │ - return new OpenLayers.Pixel(Math.max(Math.floor((point.x - this.tileOrigin.lon) / (this.tileSize.w * res)), 0), Math.max(Math.floor((this.tileOrigin.lat - point.y) / (this.tileSize.h * res)), 0)) │ │ │ │ - }, │ │ │ │ - calculateMaxExtentWithLOD: function(lod) { │ │ │ │ - var numTileCols = lod.endTileCol - lod.startTileCol + 1; │ │ │ │ - var numTileRows = lod.endTileRow - lod.startTileRow + 1; │ │ │ │ - var minX = this.tileOrigin.lon + lod.startTileCol * this.tileSize.w * lod.resolution; │ │ │ │ - var maxX = minX + numTileCols * this.tileSize.w * lod.resolution; │ │ │ │ - var maxY = this.tileOrigin.lat - lod.startTileRow * this.tileSize.h * lod.resolution; │ │ │ │ - var minY = maxY - numTileRows * this.tileSize.h * lod.resolution; │ │ │ │ - return new OpenLayers.Bounds(minX, minY, maxX, maxY) │ │ │ │ - }, │ │ │ │ - calculateMaxExtentWithExtent: function(extent, res) { │ │ │ │ - var upperLeft = new OpenLayers.Geometry.Point(extent.left, extent.top); │ │ │ │ - var bottomRight = new OpenLayers.Geometry.Point(extent.right, extent.bottom); │ │ │ │ - var start = this.getContainingTileCoords(upperLeft, res); │ │ │ │ - var end = this.getContainingTileCoords(bottomRight, res); │ │ │ │ - var lod = { │ │ │ │ - resolution: res, │ │ │ │ - startTileCol: start.x, │ │ │ │ - startTileRow: start.y, │ │ │ │ - endTileCol: end.x, │ │ │ │ - endTileRow: end.y │ │ │ │ - }; │ │ │ │ - return this.calculateMaxExtentWithLOD(lod) │ │ │ │ - }, │ │ │ │ - getUpperLeftTileCoord: function(res) { │ │ │ │ - var upperLeft = new OpenLayers.Geometry.Point(this.maxExtent.left, this.maxExtent.top); │ │ │ │ - return this.getContainingTileCoords(upperLeft, res) │ │ │ │ - }, │ │ │ │ - getLowerRightTileCoord: function(res) { │ │ │ │ - var bottomRight = new OpenLayers.Geometry.Point(this.maxExtent.right, this.maxExtent.bottom); │ │ │ │ - return this.getContainingTileCoords(bottomRight, res) │ │ │ │ - }, │ │ │ │ - getMaxExtentForResolution: function(res) { │ │ │ │ - var start = this.getUpperLeftTileCoord(res); │ │ │ │ - var end = this.getLowerRightTileCoord(res); │ │ │ │ - var numTileCols = end.x - start.x + 1; │ │ │ │ - var numTileRows = end.y - start.y + 1; │ │ │ │ - var minX = this.tileOrigin.lon + start.x * this.tileSize.w * res; │ │ │ │ - var maxX = minX + numTileCols * this.tileSize.w * res; │ │ │ │ - var maxY = this.tileOrigin.lat - start.y * this.tileSize.h * res; │ │ │ │ - var minY = maxY - numTileRows * this.tileSize.h * res; │ │ │ │ - return new OpenLayers.Bounds(minX, minY, maxX, maxY) │ │ │ │ - }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.ArcGISCache(this.name, this.url, this.options) │ │ │ │ - } │ │ │ │ - return OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]) │ │ │ │ - }, │ │ │ │ - initGriddedTiles: function(bounds) { │ │ │ │ - delete this._tileOrigin; │ │ │ │ - OpenLayers.Layer.XYZ.prototype.initGriddedTiles.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - getMaxExtent: function() { │ │ │ │ - var resolution = this.map.getResolution(); │ │ │ │ - return this.maxExtent = this.getMaxExtentForResolution(resolution) │ │ │ │ - }, │ │ │ │ - getTileOrigin: function() { │ │ │ │ - if (!this._tileOrigin) { │ │ │ │ - var extent = this.getMaxExtent(); │ │ │ │ - this._tileOrigin = new OpenLayers.LonLat(extent.left, extent.bottom) │ │ │ │ - } │ │ │ │ - return this._tileOrigin │ │ │ │ +OpenLayers.Symbolizer = OpenLayers.Class({ │ │ │ │ + zIndex: 0, │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Util.extend(this, config) │ │ │ │ }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - var res = this.getResolution(); │ │ │ │ - var originTileX = this.tileOrigin.lon + res * this.tileSize.w / 2; │ │ │ │ - var originTileY = this.tileOrigin.lat - res * this.tileSize.h / 2; │ │ │ │ - var center = bounds.getCenterLonLat(); │ │ │ │ - var point = { │ │ │ │ - x: center.lon, │ │ │ │ - y: center.lat │ │ │ │ - }; │ │ │ │ - var x = Math.round(Math.abs((center.lon - originTileX) / (res * this.tileSize.w))); │ │ │ │ - var y = Math.round(Math.abs((originTileY - center.lat) / (res * this.tileSize.h))); │ │ │ │ - var z = this.map.getZoom(); │ │ │ │ - if (this.lods) { │ │ │ │ - var lod = this.lods[this.map.getZoom()]; │ │ │ │ - if (x < lod.startTileCol || x > lod.endTileCol || (y < lod.startTileRow || y > lod.endTileRow)) { │ │ │ │ - return null │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - var start = this.getUpperLeftTileCoord(res); │ │ │ │ - var end = this.getLowerRightTileCoord(res); │ │ │ │ - if (x < start.x || x >= end.x || (y < start.y || y >= end.y)) { │ │ │ │ - return null │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var url = this.url; │ │ │ │ - var s = "" + x + y + z; │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(s, url) │ │ │ │ - } │ │ │ │ - if (this.useArcGISServer) { │ │ │ │ - url = url + "/tile/${z}/${y}/${x}" │ │ │ │ - } else { │ │ │ │ - x = "C" + OpenLayers.Number.zeroPad(x, 8, 16); │ │ │ │ - y = "R" + OpenLayers.Number.zeroPad(y, 8, 16); │ │ │ │ - z = "L" + OpenLayers.Number.zeroPad(z, 2, 10); │ │ │ │ - url = url + "/${z}/${y}/${x}." + this.type │ │ │ │ - } │ │ │ │ - url = OpenLayers.String.format(url, { │ │ │ │ - x: x, │ │ │ │ - y: y, │ │ │ │ - z: z │ │ │ │ - }); │ │ │ │ - return OpenLayers.Util.urlAppend(url, OpenLayers.Util.getParameterString(this.params)) │ │ │ │ + clone: function() { │ │ │ │ + var Type = eval(this.CLASS_NAME); │ │ │ │ + return new Type(OpenLayers.Util.extend({}, this)) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.ArcGISCache" │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ - key: null, │ │ │ │ - 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, .5971642833948135, .29858214169740677, .14929107084870338, .07464553542435169], │ │ │ │ - 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>", │ │ │ │ - metadata: null, │ │ │ │ - protocolRegex: /^http:/i, │ │ │ │ - type: "Road", │ │ │ │ - culture: "en-US", │ │ │ │ - metadataParams: null, │ │ │ │ - tileOptions: null, │ │ │ │ - protocol: ~window.location.href.indexOf("http") ? "" : "http:", │ │ │ │ - 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() │ │ │ │ - }, │ │ │ │ - loadMetadata: function() { │ │ │ │ - this._callbackId = "_callback_" + this.id.replace(/\./g, "_"); │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - 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]; │ │ │ │ - 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" │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - setMap: function() { │ │ │ │ - OpenLayers.Layer.XYZ.prototype.setMap.apply(this, arguments); │ │ │ │ - this.map.events.register("moveend", this, this.updateAttribution) │ │ │ │ - }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.Bing(this.options) │ │ │ │ - } │ │ │ │ - obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.map && this.map.events.unregister("moveend", this, this.updateAttribution); │ │ │ │ - OpenLayers.Layer.XYZ.prototype.destroy.apply(this, arguments) │ │ │ │ +OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Bing" │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Point" │ │ │ │ }); │ │ │ │ -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; │ │ │ │ - delete this._callbackId │ │ │ │ -}; │ │ │ │ -OpenLayers.Layer.Google = OpenLayers.Class(OpenLayers.Layer.EventPane, OpenLayers.Layer.FixedZoomLevels, { │ │ │ │ - MIN_ZOOM_LEVEL: 0, │ │ │ │ - MAX_ZOOM_LEVEL: 21, │ │ │ │ - RESOLUTIONS: [1.40625, .703125, .3515625, .17578125, .087890625, .0439453125, .02197265625, .010986328125, .0054931640625, .00274658203125, .001373291015625, .0006866455078125, .00034332275390625, .000171661376953125, 858306884765625e-19, 4291534423828125e-20, 2145767211914062e-20, 1072883605957031e-20, 536441802978515e-20, 268220901489257e-20, 1341104507446289e-21, 6.705522537231445e-7], │ │ │ │ - type: null, │ │ │ │ - wrapDateLine: true, │ │ │ │ - sphericalMercator: false, │ │ │ │ - version: null, │ │ │ │ - initialize: function(name, options) { │ │ │ │ - options = options || {}; │ │ │ │ - if (!options.version) { │ │ │ │ - options.version = typeof GMap2 === "function" ? "2" : "3" │ │ │ │ - } │ │ │ │ - var mixin = OpenLayers.Layer.Google["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (mixin) { │ │ │ │ - OpenLayers.Util.applyDefaults(options, mixin) │ │ │ │ - } else { │ │ │ │ - throw "Unsupported Google Maps API version: " + options.version │ │ │ │ - } │ │ │ │ - OpenLayers.Util.applyDefaults(options, mixin.DEFAULTS); │ │ │ │ - if (options.maxExtent) { │ │ │ │ - options.maxExtent = options.maxExtent.clone() │ │ │ │ - } │ │ │ │ - OpenLayers.Layer.EventPane.prototype.initialize.apply(this, [name, options]); │ │ │ │ - OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, [name, options]); │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator); │ │ │ │ - this.initMercatorParameters() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clone: function() { │ │ │ │ - return new OpenLayers.Layer.Google(this.name, this.getOptions()) │ │ │ │ - }, │ │ │ │ - setVisibility: function(visible) { │ │ │ │ - var opacity = this.opacity == null ? 1 : this.opacity; │ │ │ │ - OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this, arguments); │ │ │ │ - this.setOpacity(opacity) │ │ │ │ - }, │ │ │ │ - display: function(visible) { │ │ │ │ - if (!this._dragging) { │ │ │ │ - this.setGMapVisibility(visible) │ │ │ │ - } │ │ │ │ - OpenLayers.Layer.EventPane.prototype.display.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - this._dragging = dragging; │ │ │ │ - OpenLayers.Layer.EventPane.prototype.moveTo.apply(this, arguments); │ │ │ │ - delete this._dragging │ │ │ │ - }, │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ - if (opacity !== this.opacity) { │ │ │ │ - if (this.map != null) { │ │ │ │ - this.map.events.triggerEvent("changelayer", { │ │ │ │ - layer: this, │ │ │ │ - property: "opacity" │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - this.opacity = opacity │ │ │ │ - } │ │ │ │ - if (this.getVisibility()) { │ │ │ │ - var container = this.getMapContainer(); │ │ │ │ - OpenLayers.Util.modifyDOMElement(container, null, null, null, null, null, null, opacity) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.setGMapVisibility(false); │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache && cache.count <= 1) { │ │ │ │ - this.removeGMapElements() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - OpenLayers.Layer.EventPane.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - removeGMapElements: function() { │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - var container = this.mapObject && this.getMapContainer(); │ │ │ │ - if (container && container.parentNode) { │ │ │ │ - container.parentNode.removeChild(container) │ │ │ │ - } │ │ │ │ - var termsOfUse = cache.termsOfUse; │ │ │ │ - if (termsOfUse && termsOfUse.parentNode) { │ │ │ │ - termsOfUse.parentNode.removeChild(termsOfUse) │ │ │ │ - } │ │ │ │ - var poweredBy = cache.poweredBy; │ │ │ │ - if (poweredBy && poweredBy.parentNode) { │ │ │ │ - poweredBy.parentNode.removeChild(poweredBy) │ │ │ │ - } │ │ │ │ - if (this.mapObject && window.google && google.maps && google.maps.event && google.maps.event.clearListeners) { │ │ │ │ - google.maps.event.clearListeners(this.mapObject, "tilesloaded") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - removeMap: function(map) { │ │ │ │ - if (this.visibility && this.mapObject) { │ │ │ │ - this.setGMapVisibility(false) │ │ │ │ - } │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[map.id]; │ │ │ │ - if (cache) { │ │ │ │ - if (cache.count <= 1) { │ │ │ │ - this.removeGMapElements(); │ │ │ │ - delete OpenLayers.Layer.Google.cache[map.id] │ │ │ │ - } else { │ │ │ │ - --cache.count │ │ │ │ - } │ │ │ │ - } │ │ │ │ - delete this.termsOfUse; │ │ │ │ - delete this.poweredBy; │ │ │ │ - delete this.mapObject; │ │ │ │ - delete this.dragObject; │ │ │ │ - OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - getOLBoundsFromMapObjectBounds: function(moBounds) { │ │ │ │ - var olBounds = null; │ │ │ │ - if (moBounds != null) { │ │ │ │ - var sw = moBounds.getSouthWest(); │ │ │ │ - var ne = moBounds.getNorthEast(); │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - sw = this.forwardMercator(sw.lng(), sw.lat()); │ │ │ │ - ne = this.forwardMercator(ne.lng(), ne.lat()) │ │ │ │ - } else { │ │ │ │ - sw = new OpenLayers.LonLat(sw.lng(), sw.lat()); │ │ │ │ - ne = new OpenLayers.LonLat(ne.lng(), ne.lat()) │ │ │ │ - } │ │ │ │ - olBounds = new OpenLayers.Bounds(sw.lon, sw.lat, ne.lon, ne.lat) │ │ │ │ - } │ │ │ │ - return olBounds │ │ │ │ - }, │ │ │ │ - getWarningHTML: function() { │ │ │ │ - return OpenLayers.i18n("googleWarning") │ │ │ │ - }, │ │ │ │ - getMapObjectCenter: function() { │ │ │ │ - return this.mapObject.getCenter() │ │ │ │ - }, │ │ │ │ - getMapObjectZoom: function() { │ │ │ │ - return this.mapObject.getZoom() │ │ │ │ - }, │ │ │ │ - getLongitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - return this.sphericalMercator ? this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon : moLonLat.lng() │ │ │ │ - }, │ │ │ │ - getLatitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - var lat = this.sphericalMercator ? this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat : moLonLat.lat(); │ │ │ │ - return lat │ │ │ │ - }, │ │ │ │ - getXFromMapObjectPixel: function(moPixel) { │ │ │ │ - return moPixel.x │ │ │ │ - }, │ │ │ │ - getYFromMapObjectPixel: function(moPixel) { │ │ │ │ - return moPixel.y │ │ │ │ +OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Google" │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Line" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.Google.cache = {}; │ │ │ │ -OpenLayers.Layer.Google.v2 = { │ │ │ │ - termsOfUse: null, │ │ │ │ - poweredBy: null, │ │ │ │ - dragObject: null, │ │ │ │ - loadMapObject: function() { │ │ │ │ - if (!this.type) { │ │ │ │ - this.type = G_NORMAL_MAP │ │ │ │ - } │ │ │ │ - var mapObject, termsOfUse, poweredBy; │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - mapObject = cache.mapObject; │ │ │ │ - termsOfUse = cache.termsOfUse; │ │ │ │ - poweredBy = cache.poweredBy; │ │ │ │ - ++cache.count │ │ │ │ - } else { │ │ │ │ - var container = this.map.viewPortDiv; │ │ │ │ - var div = document.createElement("div"); │ │ │ │ - div.id = this.map.id + "_GMap2Container"; │ │ │ │ - div.style.position = "absolute"; │ │ │ │ - div.style.width = "100%"; │ │ │ │ - div.style.height = "100%"; │ │ │ │ - container.appendChild(div); │ │ │ │ - try { │ │ │ │ - mapObject = new GMap2(div); │ │ │ │ - termsOfUse = div.lastChild; │ │ │ │ - container.appendChild(termsOfUse); │ │ │ │ - termsOfUse.style.zIndex = "1100"; │ │ │ │ - termsOfUse.style.right = ""; │ │ │ │ - termsOfUse.style.bottom = ""; │ │ │ │ - termsOfUse.className = "olLayerGoogleCopyright"; │ │ │ │ - poweredBy = div.lastChild; │ │ │ │ - container.appendChild(poweredBy); │ │ │ │ - poweredBy.style.zIndex = "1100"; │ │ │ │ - poweredBy.style.right = ""; │ │ │ │ - poweredBy.style.bottom = ""; │ │ │ │ - poweredBy.className = "olLayerGooglePoweredBy gmnoprint" │ │ │ │ - } catch (e) { │ │ │ │ - throw e │ │ │ │ - } │ │ │ │ - OpenLayers.Layer.Google.cache[this.map.id] = { │ │ │ │ - mapObject: mapObject, │ │ │ │ - termsOfUse: termsOfUse, │ │ │ │ - poweredBy: poweredBy, │ │ │ │ - count: 1 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.mapObject = mapObject; │ │ │ │ - this.termsOfUse = termsOfUse; │ │ │ │ - this.poweredBy = poweredBy; │ │ │ │ - if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(), this.type) === -1) { │ │ │ │ - this.mapObject.addMapType(this.type) │ │ │ │ - } │ │ │ │ - if (typeof mapObject.getDragObject == "function") { │ │ │ │ - this.dragObject = mapObject.getDragObject() │ │ │ │ - } else { │ │ │ │ - this.dragPanMapObject = null │ │ │ │ - } │ │ │ │ - if (this.isBaseLayer === false) { │ │ │ │ - this.setGMapVisibility(this.div.style.display !== "none") │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - onMapResize: function() { │ │ │ │ - if (this.visibility && this.mapObject.isLoaded()) { │ │ │ │ - this.mapObject.checkResize() │ │ │ │ - } else { │ │ │ │ - if (!this._resized) { │ │ │ │ - var layer = this; │ │ │ │ - var handle = GEvent.addListener(this.mapObject, "load", function() { │ │ │ │ - GEvent.removeListener(handle); │ │ │ │ - delete layer._resized; │ │ │ │ - layer.mapObject.checkResize(); │ │ │ │ - layer.moveTo(layer.map.getCenter(), layer.map.getZoom()) │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - this._resized = true │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setGMapVisibility: function(visible) { │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - var container = this.mapObject.getContainer(); │ │ │ │ - if (visible === true) { │ │ │ │ - this.mapObject.setMapType(this.type); │ │ │ │ - container.style.display = ""; │ │ │ │ - this.termsOfUse.style.left = ""; │ │ │ │ - this.termsOfUse.style.display = ""; │ │ │ │ - this.poweredBy.style.display = ""; │ │ │ │ - cache.displayed = this.id │ │ │ │ - } else { │ │ │ │ - if (cache.displayed === this.id) { │ │ │ │ - delete cache.displayed │ │ │ │ - } │ │ │ │ - if (!cache.displayed) { │ │ │ │ - container.style.display = "none"; │ │ │ │ - this.termsOfUse.style.display = "none"; │ │ │ │ - this.termsOfUse.style.left = "-9999px"; │ │ │ │ - this.poweredBy.style.display = "none" │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getMapContainer: function() { │ │ │ │ - return this.mapObject.getContainer() │ │ │ │ - }, │ │ │ │ - getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ - var moBounds = null; │ │ │ │ - if (olBounds != null) { │ │ │ │ - var sw = this.sphericalMercator ? this.inverseMercator(olBounds.bottom, olBounds.left) : new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ - var ne = this.sphericalMercator ? this.inverseMercator(olBounds.top, olBounds.right) : new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ - moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon), new GLatLng(ne.lat, ne.lon)) │ │ │ │ - } │ │ │ │ - return moBounds │ │ │ │ - }, │ │ │ │ - setMapObjectCenter: function(center, zoom) { │ │ │ │ - this.mapObject.setCenter(center, zoom) │ │ │ │ - }, │ │ │ │ - dragPanMapObject: function(dX, dY) { │ │ │ │ - this.dragObject.moveBy(new GSize(-dX, dY)) │ │ │ │ - }, │ │ │ │ - getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ - return this.mapObject.fromContainerPixelToLatLng(moPixel) │ │ │ │ - }, │ │ │ │ - getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - return this.mapObject.fromLatLngToContainerPixel(moLonLat) │ │ │ │ - }, │ │ │ │ - getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ - return this.mapObject.getBoundsZoomLevel(moBounds) │ │ │ │ - }, │ │ │ │ - getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ - var gLatLng; │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - var lonlat = this.inverseMercator(lon, lat); │ │ │ │ - gLatLng = new GLatLng(lonlat.lat, lonlat.lon) │ │ │ │ - } else { │ │ │ │ - gLatLng = new GLatLng(lat, lon) │ │ │ │ - } │ │ │ │ - return gLatLng │ │ │ │ - }, │ │ │ │ - getMapObjectPixelFromXY: function(x, y) { │ │ │ │ - return new GPoint(x, y) │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -OpenLayers.Layer.WorldWind = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - DEFAULT_PARAMS: {}, │ │ │ │ - isBaseLayer: true, │ │ │ │ - lzd: null, │ │ │ │ - zoomLevels: null, │ │ │ │ - initialize: function(name, url, lzd, zoomLevels, params, options) { │ │ │ │ - this.lzd = lzd; │ │ │ │ - this.zoomLevels = zoomLevels; │ │ │ │ - var newArguments = []; │ │ │ │ - newArguments.push(name, url, params, options); │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments); │ │ │ │ - this.params = OpenLayers.Util.applyDefaults(this.params, this.DEFAULT_PARAMS) │ │ │ │ - }, │ │ │ │ - getZoom: function() { │ │ │ │ - var zoom = this.map.getZoom(); │ │ │ │ - var extent = this.map.getMaxExtent(); │ │ │ │ - zoom = zoom - Math.log(this.maxResolution / (this.lzd / 512)) / Math.log(2); │ │ │ │ - return zoom │ │ │ │ - }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var zoom = this.getZoom(); │ │ │ │ - var extent = this.map.getMaxExtent(); │ │ │ │ - var deg = this.lzd / Math.pow(2, this.getZoom()); │ │ │ │ - var x = Math.floor((bounds.left - extent.left) / deg); │ │ │ │ - var y = Math.floor((bounds.bottom - extent.bottom) / deg); │ │ │ │ - if (this.map.getResolution() <= this.lzd / 512 && this.getZoom() <= this.zoomLevels) { │ │ │ │ - return this.getFullRequestString({ │ │ │ │ - L: zoom, │ │ │ │ - X: x, │ │ │ │ - Y: y │ │ │ │ - }) │ │ │ │ - } else { │ │ │ │ - return OpenLayers.Util.getImageLocation("blank.gif") │ │ │ │ - } │ │ │ │ +OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.WorldWind" │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Polygon" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.TileCache = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - isBaseLayer: true, │ │ │ │ - format: "image/png", │ │ │ │ - serverResolutions: null, │ │ │ │ - initialize: function(name, url, layername, options) { │ │ │ │ - this.layername = layername; │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, [name, url, {}, options]); │ │ │ │ - this.extension = this.format.split("/")[1].toLowerCase(); │ │ │ │ - this.extension = this.extension == "jpg" ? "jpeg" : this.extension │ │ │ │ - }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.TileCache(this.name, this.url, this.layername, this.getOptions()) │ │ │ │ - } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ - }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var bbox = this.maxExtent; │ │ │ │ - var size = this.tileSize; │ │ │ │ - var tileX = Math.round((bounds.left - bbox.left) / (res * size.w)); │ │ │ │ - var tileY = Math.round((bounds.bottom - bbox.bottom) / (res * size.h)); │ │ │ │ - var tileZ = this.serverResolutions != null ? OpenLayers.Util.indexOf(this.serverResolutions, res) : this.map.getZoom(); │ │ │ │ - var components = [this.layername, OpenLayers.Number.zeroPad(tileZ, 2), OpenLayers.Number.zeroPad(parseInt(tileX / 1e6), 3), OpenLayers.Number.zeroPad(parseInt(tileX / 1e3) % 1e3, 3), OpenLayers.Number.zeroPad(parseInt(tileX) % 1e3, 3), OpenLayers.Number.zeroPad(parseInt(tileY / 1e6), 3), OpenLayers.Number.zeroPad(parseInt(tileY / 1e3) % 1e3, 3), OpenLayers.Number.zeroPad(parseInt(tileY) % 1e3, 3) + "." + this.extension]; │ │ │ │ - var path = components.join("/"); │ │ │ │ - var url = this.url; │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(path, url) │ │ │ │ - } │ │ │ │ - url = url.charAt(url.length - 1) == "/" ? url : url + "/"; │ │ │ │ - return url + path │ │ │ │ +OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.TileCache" │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Text" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.Text = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ - defaultStyle: null, │ │ │ │ - extractStyles: true, │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - if (options.extractStyles !== false) { │ │ │ │ - options.defaultStyle = { │ │ │ │ - externalGraphic: OpenLayers.Util.getImageLocation("marker.png"), │ │ │ │ - graphicWidth: 21, │ │ │ │ - graphicHeight: 25, │ │ │ │ - graphicXOffset: -10.5, │ │ │ │ - graphicYOffset: -12.5 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - OpenLayers.Format.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - read: function(text) { │ │ │ │ - var lines = text.split("\n"); │ │ │ │ - var columns; │ │ │ │ - var features = []; │ │ │ │ - for (var lcv = 0; lcv < lines.length - 1; lcv++) { │ │ │ │ - var currLine = lines[lcv].replace(/^\s*/, "").replace(/\s*$/, ""); │ │ │ │ - if (currLine.charAt(0) != "#") { │ │ │ │ - if (!columns) { │ │ │ │ - columns = currLine.split("\t") │ │ │ │ - } else { │ │ │ │ - var vals = currLine.split("\t"); │ │ │ │ - var geometry = new OpenLayers.Geometry.Point(0, 0); │ │ │ │ - var attributes = {}; │ │ │ │ - var style = this.defaultStyle ? OpenLayers.Util.applyDefaults({}, this.defaultStyle) : null; │ │ │ │ - var icon, iconSize, iconOffset, overflow; │ │ │ │ - var set = false; │ │ │ │ - for (var valIndex = 0; valIndex < vals.length; valIndex++) { │ │ │ │ - if (vals[valIndex]) { │ │ │ │ - if (columns[valIndex] == "point") { │ │ │ │ - var coords = vals[valIndex].split(","); │ │ │ │ - geometry.y = parseFloat(coords[0]); │ │ │ │ - geometry.x = parseFloat(coords[1]); │ │ │ │ - set = true │ │ │ │ - } else if (columns[valIndex] == "lat") { │ │ │ │ - geometry.y = parseFloat(vals[valIndex]); │ │ │ │ - set = true │ │ │ │ - } else if (columns[valIndex] == "lon") { │ │ │ │ - geometry.x = parseFloat(vals[valIndex]); │ │ │ │ - set = true │ │ │ │ - } else if (columns[valIndex] == "title") attributes["title"] = vals[valIndex]; │ │ │ │ - else if (columns[valIndex] == "image" || columns[valIndex] == "icon" && style) { │ │ │ │ - style["externalGraphic"] = vals[valIndex] │ │ │ │ - } else if (columns[valIndex] == "iconSize" && style) { │ │ │ │ - var size = vals[valIndex].split(","); │ │ │ │ - style["graphicWidth"] = parseFloat(size[0]); │ │ │ │ - style["graphicHeight"] = parseFloat(size[1]) │ │ │ │ - } else if (columns[valIndex] == "iconOffset" && style) { │ │ │ │ - var offset = vals[valIndex].split(","); │ │ │ │ - style["graphicXOffset"] = parseFloat(offset[0]); │ │ │ │ - style["graphicYOffset"] = parseFloat(offset[1]) │ │ │ │ - } else if (columns[valIndex] == "description") { │ │ │ │ - attributes["description"] = vals[valIndex] │ │ │ │ - } else if (columns[valIndex] == "overflow") { │ │ │ │ - attributes["overflow"] = vals[valIndex] │ │ │ │ - } else { │ │ │ │ - attributes[columns[valIndex]] = vals[valIndex] │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (set) { │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - geometry.transform(this.externalProjection, this.internalProjection) │ │ │ │ - } │ │ │ │ - var feature = new OpenLayers.Feature.Vector(geometry, attributes, style); │ │ │ │ - features.push(feature) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return features │ │ │ │ +OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.Text" │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Raster" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.Text = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ - location: null, │ │ │ │ - features: null, │ │ │ │ - formatOptions: null, │ │ │ │ - selectedFeature: null, │ │ │ │ - initialize: function(name, options) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.initialize.apply(this, arguments); │ │ │ │ - this.features = [] │ │ │ │ +OpenLayers.Style2 = OpenLayers.Class({ │ │ │ │ + id: null, │ │ │ │ + name: null, │ │ │ │ + title: null, │ │ │ │ + description: null, │ │ │ │ + layerName: null, │ │ │ │ + isDefault: false, │ │ │ │ + rules: null, │ │ │ │ + initialize: function(config) { │ │ │ │ + OpenLayers.Util.extend(this, config); │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_") │ │ │ │ }, │ │ │ │ destroy: function() { │ │ │ │ - OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ - this.clearFeatures(); │ │ │ │ - this.features = null │ │ │ │ - }, │ │ │ │ - loadText: function() { │ │ │ │ - if (!this.loaded) { │ │ │ │ - if (this.location != null) { │ │ │ │ - var onFail = function(e) { │ │ │ │ - this.events.triggerEvent("loadend") │ │ │ │ - }; │ │ │ │ - this.events.triggerEvent("loadstart"); │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ - url: this.location, │ │ │ │ - success: this.parseData, │ │ │ │ - failure: onFail, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.loaded = true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ - OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ - if (this.visibility && !this.loaded) { │ │ │ │ - this.loadText() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - parseData: function(ajaxRequest) { │ │ │ │ - var text = ajaxRequest.responseText; │ │ │ │ - var options = {}; │ │ │ │ - OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ - if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ - options.externalProjection = this.projection; │ │ │ │ - options.internalProjection = this.map.getProjectionObject() │ │ │ │ - } │ │ │ │ - var parser = new OpenLayers.Format.Text(options); │ │ │ │ - var features = parser.read(text); │ │ │ │ - for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ - var data = {}; │ │ │ │ - var feature = features[i]; │ │ │ │ - var location; │ │ │ │ - var iconSize, iconOffset; │ │ │ │ - location = new OpenLayers.LonLat(feature.geometry.x, feature.geometry.y); │ │ │ │ - if (feature.style.graphicWidth && feature.style.graphicHeight) { │ │ │ │ - iconSize = new OpenLayers.Size(feature.style.graphicWidth, feature.style.graphicHeight) │ │ │ │ - } │ │ │ │ - if (feature.style.graphicXOffset !== undefined && feature.style.graphicYOffset !== undefined) { │ │ │ │ - iconOffset = new OpenLayers.Pixel(feature.style.graphicXOffset, feature.style.graphicYOffset) │ │ │ │ - } │ │ │ │ - if (feature.style.externalGraphic != null) { │ │ │ │ - data.icon = new OpenLayers.Icon(feature.style.externalGraphic, iconSize, iconOffset) │ │ │ │ - } else { │ │ │ │ - data.icon = OpenLayers.Marker.defaultIcon(); │ │ │ │ - if (iconSize != null) { │ │ │ │ - data.icon.setSize(iconSize) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (feature.attributes.title != null && feature.attributes.description != null) { │ │ │ │ - data["popupContentHTML"] = "<h2>" + feature.attributes.title + "</h2>" + "<p>" + feature.attributes.description + "</p>" │ │ │ │ - } │ │ │ │ - data["overflow"] = feature.attributes.overflow || "auto"; │ │ │ │ - var markerFeature = new OpenLayers.Feature(this, location, data); │ │ │ │ - this.features.push(markerFeature); │ │ │ │ - var marker = markerFeature.createMarker(); │ │ │ │ - if (feature.attributes.title != null && feature.attributes.description != null) { │ │ │ │ - marker.events.register("click", markerFeature, this.markerClick) │ │ │ │ - } │ │ │ │ - this.addMarker(marker) │ │ │ │ - } │ │ │ │ - this.events.triggerEvent("loadend") │ │ │ │ - }, │ │ │ │ - markerClick: function(evt) { │ │ │ │ - var sameMarkerClicked = this == this.layer.selectedFeature; │ │ │ │ - this.layer.selectedFeature = !sameMarkerClicked ? this : null; │ │ │ │ - for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ - this.layer.map.removePopup(this.layer.map.popups[i]) │ │ │ │ - } │ │ │ │ - if (!sameMarkerClicked) { │ │ │ │ - this.layer.map.addPopup(this.createPopup()) │ │ │ │ - } │ │ │ │ - OpenLayers.Event.stop(evt) │ │ │ │ - }, │ │ │ │ - clearFeatures: function() { │ │ │ │ - if (this.features != null) { │ │ │ │ - while (this.features.length > 0) { │ │ │ │ - var feature = this.features[0]; │ │ │ │ - OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ - feature.destroy() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Text" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.Boxes = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ - drawMarker: function(marker) { │ │ │ │ - var topleft = this.map.getLayerPxFromLonLat({ │ │ │ │ - lon: marker.bounds.left, │ │ │ │ - lat: marker.bounds.top │ │ │ │ - }); │ │ │ │ - var botright = this.map.getLayerPxFromLonLat({ │ │ │ │ - lon: marker.bounds.right, │ │ │ │ - lat: marker.bounds.bottom │ │ │ │ - }); │ │ │ │ - if (botright == null || topleft == null) { │ │ │ │ - marker.display(false) │ │ │ │ - } else { │ │ │ │ - var markerDiv = marker.draw(topleft, { │ │ │ │ - w: Math.max(1, botright.x - topleft.x), │ │ │ │ - h: Math.max(1, botright.y - topleft.y) │ │ │ │ - }); │ │ │ │ - if (!marker.drawn) { │ │ │ │ - this.div.appendChild(markerDiv); │ │ │ │ - marker.drawn = true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - removeMarker: function(marker) { │ │ │ │ - OpenLayers.Util.removeItem(this.markers, marker); │ │ │ │ - if (marker.div != null && marker.div.parentNode == this.div) { │ │ │ │ - this.div.removeChild(marker.div) │ │ │ │ + for (var i = 0, len = this.rules.length; i < len; i++) { │ │ │ │ + this.rules[i].destroy() │ │ │ │ } │ │ │ │ + delete this.rules │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Boxes" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.PointTrack = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ - dataFrom: null, │ │ │ │ - styleFrom: null, │ │ │ │ - addNodes: function(pointFeatures, options) { │ │ │ │ - if (pointFeatures.length < 2) { │ │ │ │ - throw new Error("At least two point features have to be added to " + "create a line from") │ │ │ │ - } │ │ │ │ - var lines = new Array(pointFeatures.length - 1); │ │ │ │ - var pointFeature, startPoint, endPoint; │ │ │ │ - for (var i = 0, len = pointFeatures.length; i < len; i++) { │ │ │ │ - pointFeature = pointFeatures[i]; │ │ │ │ - endPoint = pointFeature.geometry; │ │ │ │ - if (!endPoint) { │ │ │ │ - var lonlat = pointFeature.lonlat; │ │ │ │ - endPoint = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat) │ │ │ │ - } else if (endPoint.CLASS_NAME != "OpenLayers.Geometry.Point") { │ │ │ │ - throw new TypeError("Only features with point geometries are supported.") │ │ │ │ - } │ │ │ │ - if (i > 0) { │ │ │ │ - var attributes = this.dataFrom != null ? pointFeatures[i + this.dataFrom].data || pointFeatures[i + this.dataFrom].attributes : null; │ │ │ │ - var style = this.styleFrom != null ? pointFeatures[i + this.styleFrom].style : null; │ │ │ │ - var line = new OpenLayers.Geometry.LineString([startPoint, endPoint]); │ │ │ │ - lines[i - 1] = new OpenLayers.Feature.Vector(line, attributes, style) │ │ │ │ + clone: function() { │ │ │ │ + var config = OpenLayers.Util.extend({}, this); │ │ │ │ + if (this.rules) { │ │ │ │ + config.rules = []; │ │ │ │ + for (var i = 0, len = this.rules.length; i < len; ++i) { │ │ │ │ + config.rules.push(this.rules[i].clone()) │ │ │ │ } │ │ │ │ - startPoint = endPoint │ │ │ │ } │ │ │ │ - this.addFeatures(lines, options) │ │ │ │ + return new OpenLayers.Style2(config) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.PointTrack" │ │ │ │ + CLASS_NAME: "OpenLayers.Style2" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.PointTrack.SOURCE_NODE = -1; │ │ │ │ -OpenLayers.Layer.PointTrack.TARGET_NODE = 0; │ │ │ │ -OpenLayers.Layer.PointTrack.dataFrom = { │ │ │ │ - SOURCE_NODE: -1, │ │ │ │ - TARGET_NODE: 0 │ │ │ │ -}; │ │ │ │ OpenLayers.Tile.UTFGrid = OpenLayers.Class(OpenLayers.Tile, { │ │ │ │ url: null, │ │ │ │ utfgridResolution: 2, │ │ │ │ json: null, │ │ │ │ format: null, │ │ │ │ destroy: function() { │ │ │ │ this.clear(); │ │ │ │ @@ -19373,3359 +18266,3132 @@ │ │ │ │ this.json = this.format.read(str) │ │ │ │ }, │ │ │ │ clear: function() { │ │ │ │ this.json = null │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Tile.UTFGrid" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.UTFGrid = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ - isBaseLayer: false, │ │ │ │ - projection: new OpenLayers.Projection("EPSG:900913"), │ │ │ │ - useJSONP: false, │ │ │ │ - tileClass: OpenLayers.Tile.UTFGrid, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, [options.name, options.url, {}, options]); │ │ │ │ - this.tileOptions = OpenLayers.Util.extend({ │ │ │ │ - utfgridResolution: this.utfgridResolution │ │ │ │ - }, this.tileOptions) │ │ │ │ - }, │ │ │ │ - createBackBuffer: function() {}, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.UTFGrid(this.getOptions()) │ │ │ │ +OpenLayers.Tile.Image.IFrame = { │ │ │ │ + useIFrame: null, │ │ │ │ + blankImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7", │ │ │ │ + draw: function() { │ │ │ │ + var draw = OpenLayers.Tile.Image.prototype.shouldDraw.call(this); │ │ │ │ + if (draw) { │ │ │ │ + var url = this.layer.getURL(this.bounds); │ │ │ │ + var usedIFrame = this.useIFrame; │ │ │ │ + this.useIFrame = this.maxGetUrlLength !== null && !this.layer.async && url.length > this.maxGetUrlLength; │ │ │ │ + var fromIFrame = usedIFrame && !this.useIFrame; │ │ │ │ + var toIFrame = !usedIFrame && this.useIFrame; │ │ │ │ + if (fromIFrame || toIFrame) { │ │ │ │ + if (this.imgDiv && this.imgDiv.parentNode === this.frame) { │ │ │ │ + this.frame.removeChild(this.imgDiv) │ │ │ │ + } │ │ │ │ + this.imgDiv = null; │ │ │ │ + if (fromIFrame) { │ │ │ │ + this.frame.removeChild(this.frame.firstChild) │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ + return OpenLayers.Tile.Image.prototype.draw.apply(this, arguments) │ │ │ │ }, │ │ │ │ - getFeatureInfo: function(location) { │ │ │ │ - var info = null; │ │ │ │ - var tileInfo = this.getTileData(location); │ │ │ │ - if (tileInfo && tileInfo.tile) { │ │ │ │ - info = tileInfo.tile.getFeatureInfo(tileInfo.i, tileInfo.j) │ │ │ │ + getImage: function() { │ │ │ │ + if (this.useIFrame === true) { │ │ │ │ + if (!this.frame.childNodes.length) { │ │ │ │ + var eventPane = document.createElement("div"), │ │ │ │ + style = eventPane.style; │ │ │ │ + style.position = "absolute"; │ │ │ │ + style.width = "100%"; │ │ │ │ + style.height = "100%"; │ │ │ │ + style.zIndex = 1; │ │ │ │ + style.backgroundImage = "url(" + this.blankImageUrl + ")"; │ │ │ │ + this.frame.appendChild(eventPane) │ │ │ │ + } │ │ │ │ + var id = this.id + "_iFrame", │ │ │ │ + iframe; │ │ │ │ + if (parseFloat(navigator.appVersion.split("MSIE")[1]) < 9) { │ │ │ │ + iframe = document.createElement('<iframe name="' + id + '">'); │ │ │ │ + iframe.style.backgroundColor = "#FFFFFF"; │ │ │ │ + iframe.style.filter = "chroma(color=#FFFFFF)" │ │ │ │ + } else { │ │ │ │ + iframe = document.createElement("iframe"); │ │ │ │ + iframe.style.backgroundColor = "transparent"; │ │ │ │ + iframe.name = id │ │ │ │ + } │ │ │ │ + iframe.scrolling = "no"; │ │ │ │ + iframe.marginWidth = "0px"; │ │ │ │ + iframe.marginHeight = "0px"; │ │ │ │ + iframe.frameBorder = "0"; │ │ │ │ + iframe.style.position = "absolute"; │ │ │ │ + iframe.style.width = "100%"; │ │ │ │ + iframe.style.height = "100%"; │ │ │ │ + if (this.layer.opacity < 1) { │ │ │ │ + OpenLayers.Util.modifyDOMElement(iframe, null, null, null, null, null, null, this.layer.opacity) │ │ │ │ + } │ │ │ │ + this.frame.appendChild(iframe); │ │ │ │ + this.imgDiv = iframe; │ │ │ │ + return iframe │ │ │ │ + } else { │ │ │ │ + return OpenLayers.Tile.Image.prototype.getImage.apply(this, arguments) │ │ │ │ } │ │ │ │ - return info │ │ │ │ }, │ │ │ │ - getFeatureId: function(location) { │ │ │ │ - var id = null; │ │ │ │ - var info = this.getTileData(location); │ │ │ │ - if (info.tile) { │ │ │ │ - id = info.tile.getFeatureId(info.i, info.j) │ │ │ │ + createRequestForm: function() { │ │ │ │ + var form = document.createElement("form"); │ │ │ │ + form.method = "POST"; │ │ │ │ + var cacheId = this.layer.params["_OLSALT"]; │ │ │ │ + cacheId = (cacheId ? cacheId + "_" : "") + this.bounds.toBBOX(); │ │ │ │ + form.action = OpenLayers.Util.urlAppend(this.layer.url, cacheId); │ │ │ │ + form.target = this.id + "_iFrame"; │ │ │ │ + var imageSize = this.layer.getImageSize(), │ │ │ │ + params = OpenLayers.Util.getParameters(this.url), │ │ │ │ + field; │ │ │ │ + for (var par in params) { │ │ │ │ + field = document.createElement("input"); │ │ │ │ + field.type = "hidden"; │ │ │ │ + field.name = par; │ │ │ │ + field.value = params[par]; │ │ │ │ + form.appendChild(field) │ │ │ │ } │ │ │ │ - return id │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.UTFGrid" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.PointGrid = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ - dx: null, │ │ │ │ - dy: null, │ │ │ │ - ratio: 1.5, │ │ │ │ - maxFeatures: 250, │ │ │ │ - rotation: 0, │ │ │ │ - origin: null, │ │ │ │ - gridBounds: null, │ │ │ │ - initialize: function(config) { │ │ │ │ - config = config || {}; │ │ │ │ - OpenLayers.Layer.Vector.prototype.initialize.apply(this, [config.name, config]) │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ - map.events.register("moveend", this, this.onMoveEnd) │ │ │ │ - }, │ │ │ │ - removeMap: function(map) { │ │ │ │ - map.events.unregister("moveend", this, this.onMoveEnd); │ │ │ │ - OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - setRatio: function(ratio) { │ │ │ │ - this.ratio = ratio; │ │ │ │ - this.updateGrid(true) │ │ │ │ - }, │ │ │ │ - setMaxFeatures: function(maxFeatures) { │ │ │ │ - this.maxFeatures = maxFeatures; │ │ │ │ - this.updateGrid(true) │ │ │ │ - }, │ │ │ │ - setSpacing: function(dx, dy) { │ │ │ │ - this.dx = dx; │ │ │ │ - this.dy = dy || dx; │ │ │ │ - this.updateGrid(true) │ │ │ │ - }, │ │ │ │ - setOrigin: function(origin) { │ │ │ │ - this.origin = origin; │ │ │ │ - this.updateGrid(true) │ │ │ │ + return form │ │ │ │ }, │ │ │ │ - getOrigin: function() { │ │ │ │ - if (!this.origin) { │ │ │ │ - this.origin = this.map.getExtent().getCenterLonLat() │ │ │ │ + setImgSrc: function(url) { │ │ │ │ + if (this.useIFrame === true) { │ │ │ │ + if (url) { │ │ │ │ + var form = this.createRequestForm(); │ │ │ │ + this.frame.appendChild(form); │ │ │ │ + form.submit(); │ │ │ │ + this.frame.removeChild(form) │ │ │ │ + } else if (this.imgDiv.parentNode === this.frame) { │ │ │ │ + this.frame.removeChild(this.imgDiv); │ │ │ │ + this.imgDiv = null │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Tile.Image.prototype.setImgSrc.apply(this, arguments) │ │ │ │ } │ │ │ │ - return this.origin │ │ │ │ - }, │ │ │ │ - setRotation: function(rotation) { │ │ │ │ - this.rotation = rotation; │ │ │ │ - this.updateGrid(true) │ │ │ │ - }, │ │ │ │ - onMoveEnd: function() { │ │ │ │ - this.updateGrid() │ │ │ │ }, │ │ │ │ - getViewBounds: function() { │ │ │ │ - var bounds = this.map.getExtent(); │ │ │ │ - if (this.rotation) { │ │ │ │ - var origin = this.getOrigin(); │ │ │ │ - var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); │ │ │ │ - var rect = bounds.toGeometry(); │ │ │ │ - rect.rotate(-this.rotation, rotationOrigin); │ │ │ │ - bounds = rect.getBounds() │ │ │ │ + onImageLoad: function() { │ │ │ │ + OpenLayers.Tile.Image.prototype.onImageLoad.apply(this, arguments); │ │ │ │ + if (this.useIFrame === true) { │ │ │ │ + this.imgDiv.style.opacity = 1; │ │ │ │ + this.frame.style.opacity = this.layer.opacity │ │ │ │ } │ │ │ │ - return bounds │ │ │ │ }, │ │ │ │ - updateGrid: function(force) { │ │ │ │ - if (force || this.invalidBounds()) { │ │ │ │ - var viewBounds = this.getViewBounds(); │ │ │ │ - var origin = this.getOrigin(); │ │ │ │ - var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); │ │ │ │ - var viewBoundsWidth = viewBounds.getWidth(); │ │ │ │ - var viewBoundsHeight = viewBounds.getHeight(); │ │ │ │ - var aspectRatio = viewBoundsWidth / viewBoundsHeight; │ │ │ │ - var maxHeight = Math.sqrt(this.dx * this.dy * this.maxFeatures / aspectRatio); │ │ │ │ - var maxWidth = maxHeight * aspectRatio; │ │ │ │ - var gridWidth = Math.min(viewBoundsWidth * this.ratio, maxWidth); │ │ │ │ - var gridHeight = Math.min(viewBoundsHeight * this.ratio, maxHeight); │ │ │ │ - var center = viewBounds.getCenterLonLat(); │ │ │ │ - this.gridBounds = new OpenLayers.Bounds(center.lon - gridWidth / 2, center.lat - gridHeight / 2, center.lon + gridWidth / 2, center.lat + gridHeight / 2); │ │ │ │ - var rows = Math.floor(gridHeight / this.dy); │ │ │ │ - var cols = Math.floor(gridWidth / this.dx); │ │ │ │ - var gridLeft = origin.lon + this.dx * Math.ceil((this.gridBounds.left - origin.lon) / this.dx); │ │ │ │ - var gridBottom = origin.lat + this.dy * Math.ceil((this.gridBounds.bottom - origin.lat) / this.dy); │ │ │ │ - var features = new Array(rows * cols); │ │ │ │ - var x, y, point; │ │ │ │ - for (var i = 0; i < cols; ++i) { │ │ │ │ - x = gridLeft + i * this.dx; │ │ │ │ - for (var j = 0; j < rows; ++j) { │ │ │ │ - y = gridBottom + j * this.dy; │ │ │ │ - point = new OpenLayers.Geometry.Point(x, y); │ │ │ │ - if (this.rotation) { │ │ │ │ - point.rotate(this.rotation, rotationOrigin) │ │ │ │ - } │ │ │ │ - features[i * rows + j] = new OpenLayers.Feature.Vector(point) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.destroyFeatures(this.features, { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ - this.addFeatures(features, { │ │ │ │ - silent: true │ │ │ │ - }) │ │ │ │ + createBackBuffer: function() { │ │ │ │ + var backBuffer; │ │ │ │ + if (this.useIFrame === false) { │ │ │ │ + backBuffer = OpenLayers.Tile.Image.prototype.createBackBuffer.call(this) │ │ │ │ } │ │ │ │ - }, │ │ │ │ - invalidBounds: function() { │ │ │ │ - return !this.gridBounds || !this.gridBounds.containsBounds(this.getViewBounds()) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.PointGrid" │ │ │ │ + return backBuffer │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.Lang["io"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Skalo = 1 : ${scaleDenom}" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.Zoomify = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - size: null, │ │ │ │ - isBaseLayer: true, │ │ │ │ - standardTileSize: 256, │ │ │ │ - tileOriginCorner: "tl", │ │ │ │ - numberOfTiers: 0, │ │ │ │ - tileCountUpToTier: null, │ │ │ │ - tierSizeInTiles: null, │ │ │ │ - tierImageSize: null, │ │ │ │ - initialize: function(name, url, size, options) { │ │ │ │ - this.initializeZoomify(size); │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, [name, url, size, {}, options]) │ │ │ │ - }, │ │ │ │ - initializeZoomify: function(size) { │ │ │ │ - var imageSize = size.clone(); │ │ │ │ - this.size = size.clone(); │ │ │ │ - var tiles = new OpenLayers.Size(Math.ceil(imageSize.w / this.standardTileSize), Math.ceil(imageSize.h / this.standardTileSize)); │ │ │ │ - this.tierSizeInTiles = [tiles]; │ │ │ │ - this.tierImageSize = [imageSize]; │ │ │ │ - while (imageSize.w > this.standardTileSize || imageSize.h > this.standardTileSize) { │ │ │ │ - imageSize = new OpenLayers.Size(Math.floor(imageSize.w / 2), Math.floor(imageSize.h / 2)); │ │ │ │ - tiles = new OpenLayers.Size(Math.ceil(imageSize.w / this.standardTileSize), Math.ceil(imageSize.h / this.standardTileSize)); │ │ │ │ - this.tierSizeInTiles.push(tiles); │ │ │ │ - this.tierImageSize.push(imageSize) │ │ │ │ - } │ │ │ │ - this.tierSizeInTiles.reverse(); │ │ │ │ - this.tierImageSize.reverse(); │ │ │ │ - this.numberOfTiers = this.tierSizeInTiles.length; │ │ │ │ - var resolutions = [1]; │ │ │ │ - this.tileCountUpToTier = [0]; │ │ │ │ - for (var i = 1; i < this.numberOfTiers; i++) { │ │ │ │ - resolutions.unshift(Math.pow(2, i)); │ │ │ │ - this.tileCountUpToTier.push(this.tierSizeInTiles[i - 1].w * this.tierSizeInTiles[i - 1].h + this.tileCountUpToTier[i - 1]) │ │ │ │ - } │ │ │ │ - if (!this.serverResolutions) { │ │ │ │ - this.serverResolutions = resolutions │ │ │ │ - } │ │ │ │ +OpenLayers.Lang["be-tarask"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Неапрацаваны вынік запыту ${statusText}", │ │ │ │ + Permalink: "Сталая спасылка", │ │ │ │ + Overlays: "Слаі", │ │ │ │ + "Base Layer": "Базавы слой", │ │ │ │ + noFID: "Немагчыма абнавіць магчымасьць, для якога не існуе FID.", │ │ │ │ + browserNotSupported: "Ваш браўзэр не падтрымлівае вэктарную графіку. У цяперашні момант падтрымліваюцца: ${renderers}", │ │ │ │ + minZoomLevelError: "Уласьцівасьць minZoomLevel прызначана толькі для выкарыстаньня са слаямі вытворнымі ад FixedZoomLevels. Тое, што гэты wfs-слой правяраецца на minZoomLevel — рэха прошлага. Але мы ня можам выдаліць гэтую магчымасьць, таму што ад яе залежаць некаторыя заснаваныя на OL дастасаваньні. Тым ня менш, праверка minZoomLevel будзе выдаленая ў вэрсіі 3.0. Калі ласка, выкарыстоўваеце замест яе ўстаноўкі мінімальнага/максымальнага памераў, як апісана тут: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "WFS-транзакцыя: ПОСЬПЕХ ${response}", │ │ │ │ + commitFailed: "WFS-транзакцыя: ПАМЫЛКА ${response}", │ │ │ │ + googleWarning: "Не атрымалася загрузіць слой Google. <br><br>Каб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.<br><br> Хутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі Google Maps ня быў уключаныя альбо не ўтрымлівае слушны API-ключ для Вашага сайта.<br><br>Распрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>націсьніце тут</a>", │ │ │ │ + getLayerWarning: "Немагчыма загрузіць слой ${layerType}.<br><br>Каб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.<br><br>Хутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі ${layerLib} ня быў слушна ўключаны.<br><br>Распрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>націсьніце тут</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Маштаб = 1 : ${scaleDenom}", │ │ │ │ + W: "З", │ │ │ │ + E: "У", │ │ │ │ + N: "Пн", │ │ │ │ + S: "Пд", │ │ │ │ + reprojectDeprecated: "Вы выкарыстоўваеце ўстаноўку 'reproject' для слоя ${layerName}. Гэтая ўстаноўка зьяўляецца састарэлай: яна выкарыстоўвалася для падтрымкі паказу зьвестак на камэрцыйных базавых мапах, але гэта функцыя цяпер рэалізаваная ў убудаванай падтрымцы сфэрычнай праекцыі Мэркатара. Дадатковая інфармацыя ёсьць на http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Гэты мэтад састарэлы і будзе выдалены ў вэрсіі 3.0. Калі ласка, замест яго выкарыстоўвайце ${newMethod}." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["gsw"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Nit behandleti Aafrogsruckmäldig ${statusText}", │ │ │ │ + Permalink: "Permalink", │ │ │ │ + Overlays: "Iberlagerige", │ │ │ │ + "Base Layer": "Grundcharte", │ │ │ │ + noFID: "E Feature, wu s kei FID derfir git, cha nit aktualisiert wäre.", │ │ │ │ + browserNotSupported: "Dyy Browser unterstitzt kei Vektordarstellig. Aktuäll unterstitzti Renderer:\n${renderers}", │ │ │ │ + minZoomLevelError: "D minZoomLevel-Eigeschaft isch nume dänk fir d Layer, wu vu dr FixedZoomLevels abstamme. Ass dää wfs-Layer minZoomLevel prieft, scih e Relikt us dr Vergangeheit. Mir chenne s aber nit ändere ohni OL_basierti Aawändige villicht kaputt gehn, wu dervu abhänge. Us däm Grund het die Funktion d Eigeschaft 'deprecated' iberchuu. D minZoomLevel-Priefig unte wird in dr Version 3.0 usegnuu. Bitte verwänd statt däm e min/max-Uflesig wie s do bschriben isch: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "WFS-Transaktion: ERFOLGRYCH ${response}", │ │ │ │ + commitFailed: "WFS-Transaktion: FÄHLGSCHLAA ${response}", │ │ │ │ + googleWarning: "Dr Google-Layer het nit korräkt chenne glade wäre.<br><br>Go die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.<br><br>Dää Fähler git s seli hyfig, wel s Skript vu dr Google-Maps-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.<br><br>Entwickler: Fir Hilf zum korräkte Yybinde vum Google-Layer <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>doo drucke</a>", │ │ │ │ + getLayerWarning: "Dr ${layerType}-Layer het nit korräkt chenne glade wäre.<br><br>Go die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.<br><br>Dää Fähler git s seli hyfig, wel s Skript vu dr '${layerLib}'-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.<br><br>Entwickler: Fir Hilf zum korräkte Yybinde vu Layer <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>doo drucke</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Maßstab = 1 : ${scaleDenom}", │ │ │ │ + W: "W", │ │ │ │ + E: "O", │ │ │ │ + N: "N", │ │ │ │ + S: "S", │ │ │ │ + reprojectDeprecated: "Du bruchsch d 'reproject'-Option bim ${layerName}-Layer. Die Option isch nimi giltig: si isch aagleit wore go Date iber kommerziälli Grundcharte lege, aber des sott mer jetz mache mit dr Unterstitzig vu Spherical Mercator. Meh Informatione git s uf http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Die Methode isch veraltet un wird us dr Version 3.0 usegnuu. Bitte verwäbnd statt däm ${newMethod}." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["fi"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + Permalink: "Ikilinkki", │ │ │ │ + Overlays: "Kerrokset", │ │ │ │ + "Base Layer": "Peruskerros", │ │ │ │ + W: "L", │ │ │ │ + E: "I", │ │ │ │ + N: "P", │ │ │ │ + S: "E" │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["hu"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Nem kezelt kérés visszatérése ${statusText}", │ │ │ │ + Permalink: "Permalink", │ │ │ │ + Overlays: "Rávetítések", │ │ │ │ + "Base Layer": "Alapréteg", │ │ │ │ + noFID: "Nem frissíthető olyan jellemző, amely nem rendelkezik FID-del.", │ │ │ │ + browserNotSupported: "A böngészője nem támogatja a vektoros renderelést. A jelenleg támogatott renderelők:\n${renderers}", │ │ │ │ + minZoomLevelError: "A minZoomLevel tulajdonságot csak a következővel való használatra szánták: FixedZoomLevels-leszármazott fóliák. Ez azt jelenti, hogy a minZoomLevel wfs fólia jelölőnégyzetei már a múlté. Mi azonban nem távolíthatjuk el annak a veszélye nélkül, hogy az esetlegesen ettől függő OL alapú alkalmazásokat tönkretennénk. Ezért ezt érvénytelenítjük -- a minZoomLevel az alul levő jelölőnégyzet a 3.0-s verzióból el lesz távolítva. Kérjük, helyette használja a min/max felbontás beállítást, amelyről az alábbi helyen talál leírást: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "WFS tranzakció: SIKERES ${response}", │ │ │ │ + commitFailed: "WFS tranzakció: SIKERTELEN ${response}", │ │ │ │ + googleWarning: "A Google fólia betöltése sikertelen.<br><br>Ahhoz, hogy ez az üzenet eltűnjön, válasszon egy új BaseLayer fóliát a jobb felső sarokban található fóliakapcsoló segítségével.<br><br>Nagy valószínűséggel ez azért van, mert a Google Maps könyvtár parancsfájlja nem található, vagy nem tartalmazza az Ön oldalához tartozó megfelelő API-kulcsot.<br><br>Fejlesztőknek: A helyes működtetésre vonatkozó segítség az alábbi helyen érhető el, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>kattintson ide</a>", │ │ │ │ + getLayerWarning: "A(z) ${layerType} fólia nem töltődött be helyesen.<br><br>Ahhoz, hogy ez az üzenet eltűnjön, válasszon egy új BaseLayer fóliát a jobb felső sarokban található fóliakapcsoló segítségével.<br><br>Nagy valószínűséggel ez azért van, mert a(z) ${layerLib} könyvtár parancsfájlja helytelen.<br><br>Fejlesztőknek: A helyes működtetésre vonatkozó segítség az alábbi helyen érhető el, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>kattintson ide</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Lépték = 1 : ${scaleDenom}", │ │ │ │ + W: "Ny", │ │ │ │ + E: "K", │ │ │ │ + N: "É", │ │ │ │ + S: "D", │ │ │ │ + reprojectDeprecated: "Ön a 'reproject' beállítást használja a(z) ${layerName} fólián. Ez a beállítás érvénytelen: használata az üzleti alaptérképek fölötti adatok megjelenítésének támogatására szolgált, de ezt a funkció ezentúl a Gömbi Mercator használatával érhető el. További információ az alábbi helyen érhető el: http://trac.openlayers.org/wiki/SphericalMercator", │ │ │ │ + methodDeprecated: "Ez a módszer érvénytelenítve lett és a 3.0-s verzióból el lesz távolítva. Használja a(z) ${newMethod} módszert helyette." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["bg"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + Permalink: "Постоянна препратка", │ │ │ │ + "Base Layer": "Основен слой", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Мащаб = 1 : ${scaleDenom}", │ │ │ │ + methodDeprecated: "Този метод е остарял и ще бъде премахват в 3.0. Вместо него използвайте ${newMethod}." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["nb"] = { │ │ │ │ + unhandledRequest: "Ubehandlet forespørsel returnerte ${statusText}", │ │ │ │ + Permalink: "Kobling til denne siden", │ │ │ │ + Overlays: "Kartlag", │ │ │ │ + "Base Layer": "Bakgrunnskart", │ │ │ │ + noFID: "Kan ikke oppdatere et feature (et objekt) som ikke har FID.", │ │ │ │ + browserNotSupported: "Din nettleser støtter ikke vektortegning. Tegnemetodene som støttes er:\n${renderers}", │ │ │ │ + minZoomLevelError: "Egenskapen minZoomLevel er kun ment til bruk på lag " + "basert på FixedZoomLevels. At dette wfs-laget sjekker " + "minZoomLevel er en etterlevning fra tidligere versjoner. Det kan dog ikke " + "tas bort uten å risikere at OL-baserte applikasjoner " + "slutter å virke, så det er merket som foreldet: " + "minZoomLevel i sjekken nedenfor vil fjernes i 3.0. " + "Vennligst bruk innstillingene for min/maks oppløsning " + "som er beskrevet her: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "WFS-transaksjon: LYKTES ${response}", │ │ │ │ + commitFailed: "WFS-transaksjon: MISLYKTES ${response}", │ │ │ │ + googleWarning: "Google-laget kunne ikke lastes.<br><br>" + "Bytt til et annet bakgrunnslag i lagvelgeren i " + "øvre høyre hjørne for å slippe denne meldingen.<br><br>" + "Sannsynligvis forårsakes feilen av at Google Maps-biblioteket " + "ikke er riktig inkludert på nettsiden, eller at det ikke er " + "angitt riktig API-nøkkel for nettstedet.<br><br>" + "Utviklere: For hjelp til å få dette til å virke se " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>her</a>.", │ │ │ │ + getLayerWarning: "${layerType}-laget kunne ikke lastes.<br><br>" + "Bytt til et annet bakgrunnslag i lagvelgeren i " + "øvre høyre hjørne for å slippe denne meldingen.<br><br>" + "Sannsynligvis forårsakes feilen av at " + "${layerLib}-biblioteket ikke var riktig inkludert " + "på nettsiden.<br><br>" + "Utviklere: For hjelp til å få dette til å virke se " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>her</a>.", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "<strong>Skala</strong> 1 : ${scaleDenom}", │ │ │ │ + reprojectDeprecated: "Du bruker innstillingen 'reproject' på laget ${layerName}. " + "Denne innstillingen er foreldet, den var ment for å støtte " + "visning av kartdata over kommersielle bakgrunnskart, men det " + "bør nå gjøres med støtten for Spherical Mercator. Mer informasjon " + "finnes på http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Denne metoden er markert som foreldet og vil bli fjernet i 3.0. " + "Vennligst bruk ${newMethod} i stedet.", │ │ │ │ + end: "" │ │ │ │ +}; │ │ │ │ +OpenLayers.Lang["no"] = OpenLayers.Lang["nb"]; │ │ │ │ +OpenLayers.Lang["pt"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Servidor devolveu erro não contemplado ${statusText}", │ │ │ │ + Permalink: "Ligação permanente", │ │ │ │ + Overlays: "Sobreposições", │ │ │ │ + "Base Layer": "Camada Base", │ │ │ │ + noFID: "Não é possível atualizar um elemento para a qual não há FID.", │ │ │ │ + browserNotSupported: "O seu navegador não suporta renderização vetorial. Actualmente os renderizadores suportados são:\n${renderers}", │ │ │ │ + minZoomLevelError: "A propriedade minZoomLevel só deve ser usada com as camadas descendentes da FixedZoomLevels. A verificação da propriedade por esta camada wfs é uma relíquia do passado. No entanto, não podemos removê-la sem correr o risco de afectar aplicações OL que dependam dela. Portanto, estamos a torná-la obsoleta -- a verificação minZoomLevel será removida na versão 3.0. Em vez dela, por favor, use as opções de resolução min/max descritas aqui: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "Transacção WFS: SUCESSO ${response}", │ │ │ │ + commitFailed: "Transacção WFS: FALHOU ${response}", │ │ │ │ + googleWarning: "A Camada Google não foi correctamente carregada.<br><br>Para deixar de receber esta mensagem, seleccione uma nova Camada-Base no ''switcher'' de camadas no canto superior direito.<br><br>Provavelmente, isto acontece porque o ''script'' da biblioteca do Google Maps não foi incluído ou não contém a chave API correcta para o seu sítio.<br><br>Programadores: Para ajuda sobre como solucionar o problema <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>clique aqui</a> .", │ │ │ │ + getLayerWarning: "A camada ${layerType} não foi correctamente carregada.<br><br>Para desactivar esta mensagem, seleccione uma nova Camada-Base no ''switcher'' de camadas no canto superior direito.<br><br>Provavelmente, isto acontece porque o ''script'' da biblioteca ${layerLib} não foi incluído correctamente.<br><br>Programadores: Para ajuda sobre como solucionar o problema <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>clique aqui</a> .", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Escala = 1 : ${scaleDenom}", │ │ │ │ + W: "O", │ │ │ │ + E: "E", │ │ │ │ + N: "N", │ │ │ │ + S: "S", │ │ │ │ + reprojectDeprecated: "Está usando a opção 'reproject' na camada ${layerName}. Esta opção é obsoleta: foi concebida para permitir a apresentação de dados sobre mapas-base comerciais, mas esta funcionalidade é agora suportada pelo Mercator Esférico. Mais informação está disponível em http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Este método foi declarado obsoleto e será removido na versão 3.0. Por favor, use ${newMethod} em vez disso." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang.en = { │ │ │ │ + unhandledRequest: "Unhandled request return ${statusText}", │ │ │ │ + Permalink: "Permalink", │ │ │ │ + Overlays: "Overlays", │ │ │ │ + "Base Layer": "Base Layer", │ │ │ │ + noFID: "Can't update a feature for which there is no FID.", │ │ │ │ + browserNotSupported: "Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}", │ │ │ │ + minZoomLevelError: "The minZoomLevel property is only intended for use " + "with the FixedZoomLevels-descendent layers. That this " + "wfs layer checks for minZoomLevel is a relic of the" + "past. We cannot, however, remove it without possibly " + "breaking OL based applications that may depend on it." + " Therefore we are deprecating it -- the minZoomLevel " + "check below will be removed at 3.0. Please instead " + "use min/max resolution setting as described here: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "WFS Transaction: SUCCESS ${response}", │ │ │ │ + commitFailed: "WFS Transaction: FAILED ${response}", │ │ │ │ + googleWarning: "The Google Layer was unable to load correctly.<br><br>" + "To get rid of this message, select a new BaseLayer " + "in the layer switcher in the upper-right corner.<br><br>" + "Most likely, this is because the Google Maps library " + "script was either not included, or does not contain the " + "correct API key for your site.<br><br>" + "Developers: For help getting this working correctly, " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>click here</a>", │ │ │ │ + getLayerWarning: "The ${layerType} Layer was unable to load correctly.<br><br>" + "To get rid of this message, select a new BaseLayer " + "in the layer switcher in the upper-right corner.<br><br>" + "Most likely, this is because the ${layerLib} library " + "script was not correctly included.<br><br>" + "Developers: For help getting this working correctly, " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>click here</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Scale = 1 : ${scaleDenom}", │ │ │ │ + W: "W", │ │ │ │ + E: "E", │ │ │ │ + N: "N", │ │ │ │ + S: "S", │ │ │ │ + Graticule: "Graticule", │ │ │ │ + reprojectDeprecated: "You are using the 'reproject' option " + "on the ${layerName} layer. This option is deprecated: " + "its use was designed to support displaying data over commercial " + "basemaps, but that functionality should now be achieved by using " + "Spherical Mercator support. More information is available from " + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "This method has been deprecated and will be removed in 3.0. " + "Please use ${newMethod} instead.", │ │ │ │ + end: "" │ │ │ │ +}; │ │ │ │ +OpenLayers.Lang["fr"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Requête non gérée, retournant ${statusText}", │ │ │ │ + Permalink: "Permalien", │ │ │ │ + Overlays: "Calques", │ │ │ │ + "Base Layer": "Calque de base", │ │ │ │ + noFID: "Impossible de mettre à jour un objet sans identifiant (fid).", │ │ │ │ + browserNotSupported: "Votre navigateur ne supporte pas le rendu vectoriel. Les renderers actuellement supportés sont : \n${renderers}", │ │ │ │ + minZoomLevelError: "La propriété minZoomLevel doit seulement être utilisée pour des couches FixedZoomLevels-descendent. Le fait que cette couche WFS vérifie la présence de minZoomLevel est une relique du passé. Nous ne pouvons toutefois la supprimer sans casser des applications qui pourraient en dépendre. C'est pourquoi nous la déprécions -- la vérification du minZoomLevel sera supprimée en version 3.0. A la place, merci d'utiliser les paramètres de résolutions min/max tel que décrit sur : http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "Transaction WFS : SUCCES ${response}", │ │ │ │ + commitFailed: "Transaction WFS : ECHEC ${response}", │ │ │ │ + googleWarning: "La couche Google n'a pas été en mesure de se charger correctement.<br><br>Pour supprimer ce message, choisissez une nouvelle BaseLayer dans le sélecteur de couche en haut à droite.<br><br>Cela est possiblement causé par la non-inclusion de la librairie Google Maps, ou alors parce que la clé de l'API ne correspond pas à votre site.<br><br>Développeurs : pour savoir comment corriger ceci, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>cliquez ici</a>", │ │ │ │ + getLayerWarning: "La couche ${layerType} n'est pas en mesure de se charger correctement.<br><br>Pour supprimer ce message, choisissez une nouvelle BaseLayer dans le sélecteur de couche en haut à droite.<br><br>Cela est possiblement causé par la non-inclusion de la librairie ${layerLib}.<br><br>Développeurs : pour savoir comment corriger ceci, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>cliquez ici</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Echelle ~ 1 : ${scaleDenom}", │ │ │ │ + W: "O", │ │ │ │ + E: "E", │ │ │ │ + N: "N", │ │ │ │ + S: "S", │ │ │ │ + reprojectDeprecated: "Vous utilisez l'option 'reproject' sur la couche ${layerName}. Cette option est dépréciée : Son usage permettait d'afficher des données au dessus de couches raster commerciales.Cette fonctionalité est maintenant supportée en utilisant le support de la projection Mercator Sphérique. Plus d'information est disponible sur http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Cette méthode est dépréciée, et sera supprimée à la version 3.0. Merci d'utiliser ${newMethod} à la place." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["de"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Unbehandelte Anfragerückmeldung ${statusText}", │ │ │ │ + Permalink: "Permalink", │ │ │ │ + Overlays: "Overlays", │ │ │ │ + "Base Layer": "Grundkarte", │ │ │ │ + noFID: "Ein Feature, für das keine FID existiert, kann nicht aktualisiert werden.", │ │ │ │ + browserNotSupported: "Ihr Browser unterstützt keine Vektordarstellung. Aktuell unterstützte Renderer:\n${renderers}", │ │ │ │ + minZoomLevelError: "Die <code>minZoomLevel</code>-Eigenschaft ist nur für die Verwendung mit <code>FixedZoomLevels</code>-untergeordneten Layers vorgesehen. Das dieser <tt>wfs</tt>-Layer die <code>minZoomLevel</code>-Eigenschaft überprüft ist ein Relikt der Vergangenheit. Wir können diese Überprüfung nicht entfernen, ohne das OL basierende Applikationen nicht mehr funktionieren. Daher markieren wir es als veraltet - die <code>minZoomLevel</code>-Überprüfung wird in Version 3.0 entfernt werden. Bitte verwenden Sie stattdessen die Min-/Max-Lösung, wie sie unter http://trac.openlayers.org/wiki/SettingZoomLevels beschrieben ist.", │ │ │ │ + commitSuccess: "WFS-Transaktion: Erfolgreich ${response}", │ │ │ │ + commitFailed: "WFS-Transaktion: Fehlgeschlagen ${response}", │ │ │ │ + googleWarning: "Der Google-Layer konnte nicht korrekt geladen werden.<br><br>Um diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.<br><br>Sehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der Google-Maps-Bibliothek nicht eingebunden wurde oder keinen gültigen API-Schlüssel für Ihre URL enthält.<br><br>Entwickler: Besuche <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>das Wiki</a> für Hilfe zum korrekten Einbinden des Google-Layers", │ │ │ │ + getLayerWarning: "Der ${layerType}-Layer konnte nicht korrekt geladen werden.<br><br>Um diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.<br><br>Sehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der '${layerLib}'-Bibliothek nicht eingebunden wurde.<br><br>Entwickler: Besuche <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>das Wiki</a> für Hilfe zum korrekten Einbinden von Layern", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Maßstab = 1 : ${scaleDenom}", │ │ │ │ + W: "W", │ │ │ │ + E: "O", │ │ │ │ + N: "N", │ │ │ │ + S: "S", │ │ │ │ + reprojectDeprecated: "Sie verwenden die „Reproject“-Option des Layers ${layerName}. Diese Option ist veraltet: Sie wurde entwickelt um die Anzeige von Daten auf kommerziellen Basiskarten zu unterstützen, aber diese Funktion sollte jetzt durch Unterstützung der „Spherical Mercator“ erreicht werden. Weitere Informationen sind unter http://trac.openlayers.org/wiki/SphericalMercator verfügbar.", │ │ │ │ + methodDeprecated: "Die Methode ist veraltet und wird in 3.0 entfernt. Bitte verwende stattdessen ${newMethod}." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["km"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + Permalink: "តំណភ្ជាប់អចិន្ត្រៃយ៍", │ │ │ │ + "Base Layer": "ស្រទាប់បាត​", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "មាត្រដ្ឋាន = ១ ៖ ${scaleDenom}" │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang.ro = { │ │ │ │ + unhandledRequest: "Cerere nesoluționată return ${statusText}", │ │ │ │ + Permalink: "Legatură permanentă", │ │ │ │ + Overlays: "Straturi vector", │ │ │ │ + "Base Layer": "Straturi de bază", │ │ │ │ + noFID: "Nu pot actualiza un feature pentru care nu există FID.", │ │ │ │ + browserNotSupported: "Browserul tău nu suportă afișarea vectorilor. Supoetul curent pentru randare:\n${renderers}", │ │ │ │ + minZoomLevelError: "Proprietatea minZoomLevel este doar pentru a fi folosită " + "cu straturile FixedZoomLevels-descendent. De aceea acest " + "strat wfs verifică dacă minZoomLevel este o relicvă" + ". Nu îl putem , oricum, înlătura fără " + "a afecta aplicațiile Openlayers care depind de ea." + " De aceea considerăm depreciat -- minZoomLevel " + "și îl vom înlătura în 3.0. Folosește " + "min/max resolution cum este descrisă aici: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "Tranzacție WFS: SUCCES ${response}", │ │ │ │ + commitFailed: "Tranzacție WFS : EȘEC ${response}", │ │ │ │ + googleWarning: "Stratul Google nu a putut fi încărcat corect.<br><br>" + "Pentru a elimina acest mesaj, selectează un nou strat de bază " + "în Layerswitcher din colțul dreata-sus.<br><br>" + "Asta datorită, faptului că Google Maps library " + "script nu este inclus, sau nu conține " + "cheia API corectă pentru situl tău.<br><br>" + "Developeri: Pentru ajutor, " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>apăsați aici</a>", │ │ │ │ + getLayerWarning: "Stratul ${layerType} nu a putut fi încărcat corect.<br><br>" + "pentru a înlătura acest mesaj, selectează un nou strat de bază " + "Acesta eroare apare de obicei când ${layerLib} library " + "script nu a fost încărcat corect.<br><br>" + "Developeri: Pentru ajutor privind utilizarea corectă, " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>apasă aici</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Scara = 1 : ${scaleDenom}", │ │ │ │ + W: "V", │ │ │ │ + E: "E", │ │ │ │ + N: "N", │ │ │ │ + S: "S", │ │ │ │ + Graticule: "Graticule", │ │ │ │ + reprojectDeprecated: "folosești opțiunea 'reproject' " + "pentru stratul ${layerName} . Această opțiune este depreciată: " + "a fost utilizată pentru afișarea straturilor de bază comerciale " + "Mai multe informații despre proiecția Mercator sunt disponibile aici " + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Această metodă este depreciată și va fi înlăturată in versiunea 3.0. " + "folosește metoda ${newMethod}.", │ │ │ │ + end: "" │ │ │ │ +}; │ │ │ │ +OpenLayers.Lang["cs-CZ"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Nezpracovaná návratová hodnota ${statusText}", │ │ │ │ + Permalink: "Trvalý odkaz", │ │ │ │ + Overlays: "Překryvné vrstvy", │ │ │ │ + "Base Layer": "Podkladové vrstvy", │ │ │ │ + noFID: "Nelze aktualizovat prvek, pro který neexistuje FID.", │ │ │ │ + browserNotSupported: "Váš prohlížeč nepodporuje vykreslování vektorů. Momentálně podporované nástroje jsou::\n${renderers}", │ │ │ │ + minZoomLevelError: "Vlastnost minZoomLevel by se měla používat pouze s potomky FixedZoomLevels vrstvami. To znamená, že vrstva wfs kontroluje, zda-li minZoomLevel není zbytek z minulosti.Nelze to ovšem vyjmout bez možnosti, že bychom rozbili aplikace postavené na OL, které by na tom mohly záviset. Proto tuto vlastnost nedoporučujeme používat -- kontrola minZoomLevel bude odstraněna ve verzi 3.0. Použijte prosím raději nastavení min/max podle příkaldu popsaného na: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "WFS Transaction: ÚSPĚCH ${response}", │ │ │ │ + commitFailed: "WFS Transaction: CHYBA ${response}", │ │ │ │ + googleWarning: "Nepodařilo se správně načíst vrstvu Google.<br><br>Abyste se zbavili této zprávy, zvolte jinou základní vrstvu v přepínači vrstev.<br><br>To se většinou stává, pokud nebyl načten skript, nebo neobsahuje správný klíč pro API pro tuto stránku.<br><br>Vývojáři: Pro pomoc, aby tohle fungovalo , <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>klikněte sem</a>", │ │ │ │ + getLayerWarning: "The ${layerType} Layer was unable to load correctly.<br><br>To get rid of this message, select a new BaseLayer in the layer switcher in the upper-right corner.<br><br>Most likely, this is because the ${layerLib} library script was either not correctly included.<br><br>Developers: For help getting this working correctly, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>click here</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Měřítko = 1 : ${scaleDenom}", │ │ │ │ + reprojectDeprecated: "Použil jste volbu 'reproject' ve vrstvě ${layerName}. Tato volba není doporučená: byla zde proto, aby bylo možno zobrazovat data z okomerčních serverů, ale tato funkce je nyní zajištěna pomocí podpory Spherical Mercator. Více informací naleznete na http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Tato metoda je zavržená a bude ve verzi 3.0 odstraněna. Prosím, použijte raději ${newMethod}." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["te"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + Permalink: "స్థిరలింకు", │ │ │ │ + W: "ప", │ │ │ │ + E: "తూ", │ │ │ │ + N: "ఉ", │ │ │ │ + S: "ద" │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["hsb"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Wotmołwa njewobdźěłaneho naprašowanja ${statusText}", │ │ │ │ + Permalink: "Trajny wotkaz", │ │ │ │ + Overlays: "Naworštowanja", │ │ │ │ + "Base Layer": "Zakładna runina", │ │ │ │ + noFID: "Funkcija, za kotruž FID njeje, njeda so aktualizować.", │ │ │ │ + browserNotSupported: "Twój wobhladowak wektorowe rysowanje njepodpěruje. Tuchwilu podpěrowane rysowaki su:\n${renderers}", │ │ │ │ + minZoomLevelError: "Kajkosć minZoomLevel je jenož za wužiwanje z worštami myslena, kotrež wot FixedZoomLevels pochadźeja. Zo tuta woršta wfs za minZoomLevel přepruwuje, je relikt zańdźenosće. Njemóžemy wšak ju wotstronić, bjeztoho zo aplikacije, kotrež na OpenLayers bazěruja a snano tutu kajkosć wužiwaja, hižo njefunguja. Tohodla smy ju jako zestarjenu woznamjenili -- přepruwowanje za minZoomLevel budu so we wersiji 3.0 wotstronjeć. Prošu wužij město toho nastajenje min/max, kaž je tu wopisane: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "WFS-Transakcija: WUSPĚŠNA ${response}", │ │ │ │ + commitFailed: "WFS-Transakcija: NJEPORADŹENA ${response}", │ │ │ │ + googleWarning: "Woršta Google njemóžeše so korektnje začitać.<br><br>Zo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.<br><br>Najskerje so to stawa, dokelž skript biblioteki Google Maps pak njebu zapřijaty pak njewobsahuje korektny kluč API za twoje sydło.<br><br>Wuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n<a href='http://trac.openlayers.org/wiki/Google' target='_blank'>tu kliknyć</a>", │ │ │ │ + getLayerWarning: "Woršta ${layerType} njemóžeše so korektnje začitać.<br><br>Zo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.<br><br>Najskerje so to stawa, dokelž skript biblioteki ${layerLib} njebu korektnje zapřijaty.<br><br>Wuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n<a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>tu kliknyć</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Měritko = 1 : ${scaleDenom}", │ │ │ │ + W: "Z", │ │ │ │ + E: "W", │ │ │ │ + N: "S", │ │ │ │ + S: "J", │ │ │ │ + reprojectDeprecated: 'Wužiwaš opciju "reproject" wořšty ${layerName}. Tuta opcija je zestarjena: jeje wužiwanje bě myslene, zo by zwobraznjenje datow nad komercielnymi bazowymi kartami podpěrało, ale funkcionalnosć měła so nětko z pomocu Sperical Mercator docpěć. Dalše informacije steja na http://trac.openlayers.org/wiki/SphericalMercator k dispoziciji.', │ │ │ │ + methodDeprecated: "Tuta metoda je so njeschwaliła a budźe so w 3.0 wotstronjeć. Prošu wužij ${newMethod} město toho." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang.ca = { │ │ │ │ + unhandledRequest: "Resposta a petició no gestionada ${statusText}", │ │ │ │ + Permalink: "Enllaç permanent", │ │ │ │ + Overlays: "Capes addicionals", │ │ │ │ + "Base Layer": "Capa Base", │ │ │ │ + noFID: "No es pot actualitzar un element per al que no existeix FID.", │ │ │ │ + browserNotSupported: "El seu navegador no suporta renderització vectorial. Els renderitzadors suportats actualment són:\n${renderers}", │ │ │ │ + minZoomLevelError: "La propietat minZoomLevel s'ha d'utilitzar només " + "amb les capes que tenen FixedZoomLevels. El fet que " + "una capa wfs comprovi minZoomLevel és una relíquia del " + "passat. No podem, però, eliminar-la sense trencar " + "les aplicacions d'OpenLayers que en puguin dependre. " + "Així doncs estem fent-la obsoleta -- la comprovació " + "minZoomLevel s'eliminarà a la versió 3.0. Feu servir " + "els paràmetres min/max resolution en substitució, tal com es descriu aquí: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "Transacció WFS: CORRECTA ${response}", │ │ │ │ + commitFailed: "Transacció WFS: HA FALLAT ${response}", │ │ │ │ + googleWarning: "La capa Google no s'ha pogut carregar correctament.<br><br>" + "Per evitar aquest missatge, seleccioneu una nova Capa Base " + "al gestor de capes de la cantonada superior dreta.<br><br>" + "Probablement això és degut a que l'script de la biblioteca de " + "Google Maps no ha estat inclòs a la vostra pàgina, o no " + "conté la clau de l'API correcta per a la vostra adreça.<br><br>" + "Desenvolupadors: Per obtenir consells sobre com fer anar això, " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>féu clic aquí</a>", │ │ │ │ + getLayerWarning: "Per evitar aquest missatge, seleccioneu una nova Capa Base " + "al gestor de capes de la cantonada superior dreta.<br><br>" + "Probablement això és degut a que l'script de la biblioteca " + "${layerLib} " + "no ha estat inclòs a la vostra pàgina.<br><br>" + "Desenvolupadors: Per obtenir consells sobre com fer anar això, " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>féu clic aquí</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Escala = 1 : ${scaleDenom}", │ │ │ │ + W: "O", │ │ │ │ + E: "E", │ │ │ │ + N: "N", │ │ │ │ + S: "S", │ │ │ │ + Graticule: "Retícula", │ │ │ │ + reprojectDeprecated: "Esteu fent servir l'opció 'reproject' a la capa " + "${layerName}. Aquesta opció és obsoleta: el seu ús fou concebut " + "per suportar la visualització de dades sobre mapes base comercials, " + "però ara aquesta funcionalitat s'hauria d'assolir mitjançant el suport " + "de la projecció Spherical Mercator. Més informació disponible a " + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Aquest mètode és obsolet i s'eliminarà a la versió 3.0. " + "Si us plau feu servir em mètode alternatiu ${newMethod}.", │ │ │ │ + end: "" │ │ │ │ +}; │ │ │ │ +OpenLayers.Lang["nn"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Skala = 1 : ${scaleDenom}" │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["ar"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + Permalink: "وصلة دائمة", │ │ │ │ + "Base Layer": "الطبقة الاساسية", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "النسبة = 1 : ${scaleDenom}", │ │ │ │ + W: "غ", │ │ │ │ + E: "شر", │ │ │ │ + N: "شم", │ │ │ │ + S: "ج" │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["ja"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "未処理の要求は ${statusText} を返します", │ │ │ │ + Permalink: "パーマリンク", │ │ │ │ + Overlays: "オーバーレイ", │ │ │ │ + "Base Layer": "基底レイヤー", │ │ │ │ + noFID: "FID のない地物は更新できません。", │ │ │ │ + browserNotSupported: "あなたのブラウザはベクターグラフィックスの描写に対応していません。現時点で対応しているソフトウェアは以下のものです。\n${renderers}", │ │ │ │ + minZoomLevelError: "minZoomLevel プロパティは FixedZoomLevels を継承するレイヤーでの使用のみを想定しています。この minZoomLevel に対する WFS レイヤーの検査は歴史的なものです。しかしながら、この検査を除去するとそれに依存する OpenLayers ベースのアプリケーションを破壊してしまう可能性があります。よって廃止が予定されており、この minZoomLevel 検査はバージョン3.0で除去されます。代わりに、http://trac.openlayers.org/wiki/SettingZoomLevels で解説されている、最小および最大解像度設定を使用してください。", │ │ │ │ + commitSuccess: "WFS トランザクション: 成功 ${response}", │ │ │ │ + commitFailed: "WFS トランザクション: 失敗 ${response}", │ │ │ │ + googleWarning: "Google レイヤーが正しく読み込みを行えませんでした。<br><br>このメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。<br><br>おそらく、これは Google マップ用ライブラリのスクリプトが組み込まれていないか、あなたのサイトに対応する正しい API キーが設定されていないためです。<br><br>開発者の方へ: 正しい動作をさせるために<a href='http://trac.openlayers.org/wiki/Google' target='_blank'>こちらのウィキ</a>を参照してください。", │ │ │ │ + getLayerWarning: "${layerType} レイヤーが正しく読み込みを行えませんでした。<br><br>このメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。<br><br>おそらく、これは ${layerLib} ライブラリのスクリプトが正しく組み込まれていないためです。<br><br>開発者の方へ: 正しい動作をさせるために<a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>こちらのウィキ</a>を参照してください。", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "縮尺 = 1 : ${scaleDenom}", │ │ │ │ + W: "西", │ │ │ │ + E: "東", │ │ │ │ + N: "北", │ │ │ │ + S: "南", │ │ │ │ + reprojectDeprecated: "あなたは「${layerName}」レイヤーで reproject オプションを使っています。このオプションは商用の基底地図上に情報を表示する目的で設計されましたが、現在ではその機能は Spherical Mercator サポートを利用して実現されており、このオプションの使用は非推奨です。追加の情報は http://trac.openlayers.org/wiki/SphericalMercator で入手できます。", │ │ │ │ + methodDeprecated: "このメソッドは廃止が予定されており、バージョン3.0で除去されます。代わりに ${newMethod} を使用してください。" │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["hr"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Nepodržani zahtjev ${statusText}", │ │ │ │ + Permalink: "Permalink", │ │ │ │ + Overlays: "Overlays", │ │ │ │ + "Base Layer": "Osnovna karta", │ │ │ │ + noFID: "Ne mogu ažurirati značajku za koju ne postoji FID.", │ │ │ │ + browserNotSupported: "Vaš preglednik ne podržava vektorsko renderiranje. Trenutno podržani rendereri su: ${renderers}", │ │ │ │ + commitSuccess: "WFS Transakcija: USPJEŠNA ${response}", │ │ │ │ + commitFailed: "WFS Transakcija: NEUSPJEŠNA ${response}", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Mjerilo = 1 : ${scaleDenom}", │ │ │ │ + methodDeprecated: "Ova metoda nije odobrena i biti će maknuta u 3.0. Koristite ${newMethod}." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["sv"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Ej hanterad fråga retur ${statusText}", │ │ │ │ + Permalink: "Permalänk", │ │ │ │ + Overlays: "Kartlager", │ │ │ │ + "Base Layer": "Bakgrundskarta", │ │ │ │ + noFID: "Kan ej uppdatera feature (objekt) för vilket FID saknas.", │ │ │ │ + browserNotSupported: "Din webbläsare stöder inte vektorvisning. För närvarande stöds följande visning:\n${renderers}", │ │ │ │ + minZoomLevelError: "Egenskapen minZoomLevel är endast avsedd att användas med lager med FixedZoomLevels. Att detta WFS-lager kontrollerar minZoomLevel är en relik från äldre versioner. Vi kan dock inte ta bort det utan att riskera att OL-baserade tillämpningar som använder detta slutar fungera. Därför är det satt som deprecated, minZoomLevel kommer att tas bort i version 3.0. Använd i stället inställning av min/max resolution som beskrivs här: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "WFS-transaktion: LYCKADES ${response}", │ │ │ │ + commitFailed: "WFS-transaktion: MISSLYCKADES ${response}", │ │ │ │ + googleWarning: "Google-lagret kunde inte laddas korrekt.<br><br>För att slippa detta meddelande, välj en annan bakgrundskarta i lagerväljaren i övre högra hörnet.<br><br>Sannolikt beror felet på att Google Maps-biblioteket inte är inkluderat på webbsidan eller på att sidan inte anger korrekt API-nyckel för webbplatsen.<br><br>Utvecklare: hjälp för att åtgärda detta, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>klicka här</a>.", │ │ │ │ + getLayerWarning: "${layerType}-lagret kunde inte laddas korrekt.<br><br>För att slippa detta meddelande, välj en annan bakgrundskarta i lagerväljaren i övre högra hörnet.<br><br>Sannolikt beror felet på att ${layerLib}-biblioteket inte är inkluderat på webbsidan.<br><br>Utvecklare: hjälp för att åtgärda detta, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>klicka här</a>.", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "<strong>Skala</strong> 1 : ${scaleDenom}", │ │ │ │ + reprojectDeprecated: "Du använder inställningen 'reproject' på lagret ${layerName}. Denna inställning markerad som deprecated: den var avsedd att användas för att stödja visning av kartdata på kommersiella bakgrundskartor, men nu bör man i stället använda Spherical Mercator-stöd för den funktionaliteten. Mer information finns på http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Denna metod är markerad som deprecated och kommer att tas bort i 3.0. Använd ${newMethod} i stället." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["en-CA"] = OpenLayers.Util.applyDefaults({}, OpenLayers.Lang["en"]); │ │ │ │ +OpenLayers.Lang["lt"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Neapdorota užklausa gražino ${statusText}", │ │ │ │ + Permalink: "Pastovi nuoroda", │ │ │ │ + Overlays: "Papildomi sluoksniai", │ │ │ │ + "Base Layer": "Pagrindinis sluoksnis", │ │ │ │ + noFID: "Negaliu atnaujinti objekto, kuris neturi FID.", │ │ │ │ + browserNotSupported: "Jūsų naršyklė nemoka parodyti vektorių. Šiuo metu galima naudotis tokiais rodymo varikliais:\n{renderers}", │ │ │ │ + commitSuccess: "WFS Tranzakcija: PAVYKO ${response}", │ │ │ │ + commitFailed: "WFS Tranzakcija: ŽLUGO ${response}", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Mastelis = 1 : ${scaleDenom}", │ │ │ │ + W: "V", │ │ │ │ + E: "R", │ │ │ │ + N: "Š", │ │ │ │ + S: "P", │ │ │ │ + Graticule: "Tinklelis", │ │ │ │ + methodDeprecated: "Šis metodas yra pasenęs ir 3.0 versijoje bus pašalintas. " + "Prašome naudoti ${newMethod}.", │ │ │ │ + end: "" │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["is"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + Permalink: "Varanlegur tengill", │ │ │ │ + Overlays: "Þekjur", │ │ │ │ + "Base Layer": "Grunnlag", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Skali = 1 : ${scaleDenom}", │ │ │ │ + methodDeprecated: "Þetta fall hefur verið úrelt og verður fjarlægt í 3.0. Notaðu ${newMethod} í staðin." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["gl"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Solicitude non xerada; a resposta foi: ${statusText}", │ │ │ │ + Permalink: "Ligazón permanente", │ │ │ │ + Overlays: "Capas superpostas", │ │ │ │ + "Base Layer": "Capa base", │ │ │ │ + noFID: "Non se pode actualizar a funcionalidade para a que non hai FID.", │ │ │ │ + browserNotSupported: "O seu navegador non soporta a renderización de vectores. Os renderizadores soportados actualmente son:\n${renderers}", │ │ │ │ + minZoomLevelError: "A propiedade minZoomLevel é só para uso conxuntamente coas capas FixedZoomLevels-descendent. O feito de que esa capa wfs verifique o minZoomLevel é unha reliquia do pasado. Non podemos, con todo, eliminala sen a posibilidade de non romper as aplicacións baseadas en OL que poidan depender dela. Por iso a estamos deixando obsoleta (a comprobación minZoomLevel de embaixo será eliminada na versión 3.0). Por favor, no canto diso use o axuste de resolución mín/máx tal e como está descrito aquí: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "Transacción WFS: ÉXITO ${response}", │ │ │ │ + commitFailed: "Transacción WFS: FALLIDA ${response}", │ │ │ │ + googleWarning: "A capa do Google non puido cargarse correctamente.<br><br>Para evitar esta mensaxe, escolla unha nova capa base no seleccionador de capas na marxe superior dereita.<br><br>Probablemente, isto acontece porque a escritura da libraría do Google Maps ou ben non foi incluída ou ben non contén a clave API correcta para o seu sitio.<br><br>Desenvolvedores: para axudar a facer funcionar isto correctamente, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>premede aquí</a>", │ │ │ │ + getLayerWarning: "A capa ${layerType} foi incapaz de cargarse correctamente.<br><br>Para evitar esta mensaxe, escolla unha nova capa base no seleccionador de capas na marxe superior dereita.<br><br>Probablemente, isto acontece porque a escritura da libraría ${layerLib} non foi ben incluída.<br><br>Desenvolvedores: para axudar a facer funcionar isto correctamente, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>premede aquí</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Escala = 1 : ${scaleDenom}", │ │ │ │ + W: "O", │ │ │ │ + E: "L", │ │ │ │ + N: "N", │ │ │ │ + S: "S", │ │ │ │ + reprojectDeprecated: 'Está usando a opción "reproject" na capa ${layerName}. Esta opción está obsoleta: o seu uso foi deseñado para a visualización de datos sobre mapas base comerciais, pero esta funcionalidade debera agora ser obtida utilizando a proxección Spherical Mercator. Hai dispoñible máis información en http://trac.openlayers.org/wiki/SphericalMercator.', │ │ │ │ + methodDeprecated: "Este método está obsoleto e será eliminado na versión 3.0. Por favor, no canto deste use ${newMethod}." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["nds"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Unbehannelt Trüchmellels för de Anfraag ${statusText}", │ │ │ │ + Permalink: "Permalink", │ │ │ │ + Overlays: "Overlays", │ │ │ │ + "Base Layer": "Achtergrundkoort", │ │ │ │ + noFID: "En Feature, dat keen FID hett, kann nich aktuell maakt warrn.", │ │ │ │ + browserNotSupported: "Dien Browser ünnerstütt keen Vektorbiller. Ünnerstütt Renderers:\n${renderers}", │ │ │ │ + commitSuccess: "WFS-Transakschoon: hett klappt ${response}", │ │ │ │ + commitFailed: "WFS-Transakschoon: hett nich klappt ${response}", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Skaal = 1 : ${scaleDenom}", │ │ │ │ + methodDeprecated: "Disse Methood is oold un schall dat in 3.0 nich mehr geven. Bruuk dor man beter ${newMethod} för." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["fur"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + Permalink: "Leam Permanent", │ │ │ │ + Overlays: "Livei parsore", │ │ │ │ + "Base Layer": "Livel di base", │ │ │ │ + browserNotSupported: "Il to sgarfadôr nol supuarte la renderizazion vetoriâl. Al moment a son supuartâts:\n${renderers}", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Scjale = 1 : ${scaleDenom}", │ │ │ │ + W: "O", │ │ │ │ + E: "E", │ │ │ │ + N: "N", │ │ │ │ + S: "S" │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["pt-BR"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "A requisição retornou um erro não tratado: ${statusText}", │ │ │ │ + Permalink: "Link para essa página", │ │ │ │ + Overlays: "Camadas de Sobreposição", │ │ │ │ + "Base Layer": "Camada Base", │ │ │ │ + noFID: "Não é possível atualizar uma feição que não tenha um FID.", │ │ │ │ + browserNotSupported: "Seu navegador não suporta renderização de vetores. Os renderizadores suportados atualmente são:\n${renderers}", │ │ │ │ + minZoomLevelError: "A propriedade minZoomLevel é de uso restrito das camadas descendentes de FixedZoomLevels. A verificação dessa propriedade pelas camadas wfs é um resíduo do passado. Não podemos, entretanto não é possível removê-la sem possívelmente quebrar o funcionamento de aplicações OL que possuem depência com ela. Portanto estamos tornando seu uso obsoleto -- a verificação desse atributo será removida na versão 3.0. Ao invés, use as opções de resolução min/max como descrito em: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "Transação WFS : SUCESSO ${response}", │ │ │ │ + commitFailed: "Transação WFS : ERRO ${response}", │ │ │ │ + googleWarning: "Não foi possível carregar a camada Google corretamente.<br><br>Para se livrar dessa mensagem, selecione uma nova Camada Base, na ferramenta de alternação de camadas localização do canto superior direito.<br><br>Muito provavelmente, isso foi causado porque o script da biblioteca do Google Maps não foi incluído, ou porque ele não contém a chave correta da API para o seu site.<br><br>Desenvolvedores: Para obter ajuda em solucionar esse problema <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>cliquem aqui</a>", │ │ │ │ + getLayerWarning: "Não foi possível carregar a camada ${layerType} corretamente.<br><br>Para se livrar dessa mensagem, selecione uma nova Camada Base, na ferramenta de alternação de camadas localização do canto superior direito.<br><br>Muito provavelmente, isso foi causado porque o script da biblioteca ${layerLib} não foi incluído corretamente.<br><br>Desenvolvedores: Para obter ajuda em solucionar esse problema <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>cliquem aqui</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Escala = 1 : ${scaleDenom}", │ │ │ │ + W: "O", │ │ │ │ + E: "L", │ │ │ │ + N: "N", │ │ │ │ + S: "S", │ │ │ │ + reprojectDeprecated: "Você está usando a opção 'reproject' na camada ${layerName}. Essa opção está obsoleta: seu uso foi projetado para suportar a visualização de dados sobre bases de mapas comerciais, entretanto essa funcionalidade deve agora ser alcançada usando o suporte à projeção Mercator. Mais informação está disponível em: http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Esse método está obsoleto e será removido na versão 3.0. Ao invés, por favor use ${newMethod}." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["ia"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Le responsa a un requesta non esseva maneate: ${statusText}", │ │ │ │ + Permalink: "Permaligamine", │ │ │ │ + Overlays: "Superpositiones", │ │ │ │ + "Base Layer": "Strato de base", │ │ │ │ + noFID: "Non pote actualisar un elemento sin FID.", │ │ │ │ + browserNotSupported: "Tu navigator non supporta le rendition de vectores. Le renditores actualmente supportate es:\n${renderers}", │ │ │ │ + minZoomLevelError: "Le proprietate minZoomLevel es solmente pro uso con le stratos descendente de FixedZoomLevels. Le facto que iste strato WFS verifica minZoomLevel es un reliquia del passato. Nonobstante, si nos lo remove immediatemente, nos pote rumper applicationes a base de OL que depende de illo. Ergo nos lo declara obsolete; le verification de minZoomLevel in basso essera removite in version 3.0. Per favor usa in su loco le configuration de resolutiones min/max como describite a: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "Transaction WFS: SUCCESSO ${response}", │ │ │ │ + commitFailed: "Transaction WFS: FALLEVA ${response}", │ │ │ │ + googleWarning: "Le strato Google non poteva esser cargate correctemente.<br><br>Pro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.<br><br>Multo probabilemente, isto es proque le script del libreria de Google Maps non esseva includite o non contine le clave API correcte pro tu sito.<br><br>Disveloppatores: Pro adjuta de corriger isto, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>clicca hic</a", │ │ │ │ + getLayerWarning: "Le strato ${layerType} non poteva esser cargate correctemente.<br><br>Pro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.<br><br>Multo probabilemente, isto es proque le script del libreria de ${layerLib} non esseva correctemente includite.<br><br>Disveloppatores: Pro adjuta de corriger isto, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>clicca hic</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Scala = 1 : ${scaleDenom}", │ │ │ │ + W: "W", │ │ │ │ + E: "E", │ │ │ │ + N: "N", │ │ │ │ + S: "S", │ │ │ │ + reprojectDeprecated: "Tu usa le option 'reproject' in le strato ${layerName} layer. Iste option es obsolescente: illo esseva pro poter monstrar datos super cartas de base commercial, ma iste functionalitate pote ora esser attingite con le uso de Spherical Mercator. Ulterior information es disponibile a http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Iste methodo ha essite declarate obsolescente e essera removite in version 3.0. Per favor usa ${newMethod} in su loco." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["zh-TW"] = { │ │ │ │ + unhandledRequest: "未處理的請求,傳回值為 ${statusText}。", │ │ │ │ + Permalink: "永久連結", │ │ │ │ + Overlays: "額外圖層", │ │ │ │ + "Base Layer": "基礎圖層", │ │ │ │ + noFID: "因為沒有 FID 所以無法更新 feature。", │ │ │ │ + browserNotSupported: "您的瀏覽器未支援向量渲染. 目前支援的渲染方式是:\n${renderers}", │ │ │ │ + minZoomLevelError: "minZoomLevel 屬性僅適合用在 " + "FixedZoomLevels-descendent 類型的圖層. 這個" + "wfs layer 的 minZoomLevel 是過去所遺留下來的," + "然而我們不能移除它而不讓它將" + "過去的程式相容性給破壞掉。" + "因此我們將會迴避使用它 -- minZoomLevel " + "會在3.0被移除,請改" + "用在這邊描述的 min/max resolution 設定: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "WFS Transaction: 成功 ${response}", │ │ │ │ + commitFailed: "WFS Transaction: 失敗 ${response}", │ │ │ │ + googleWarning: "The Google Layer 圖層無法被正確的載入。<br><br>" + "要迴避這個訊息, 請在右上角的圖層改變器裡," + "選一個新的基礎圖層。<br><br>" + "很有可能是因為 Google Maps 的函式庫" + "腳本沒有被正確的置入,或沒有包含 " + "您網站上正確的 API key <br><br>" + "開發者: 要幫助這個行為正確完成," + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>請按這裡</a>", │ │ │ │ + getLayerWarning: "${layerType} 圖層無法被正確的載入。<br><br>" + "要迴避這個訊息, 請在右上角的圖層改變器裡," + "選一個新的基礎圖層。<br><br>" + "很有可能是因為 ${layerLib} 的函式庫" + "腳本沒有被正確的置入。<br><br>" + "開發者: 要幫助這個行為正確完成," + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>請按這裡</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Scale = 1 : ${scaleDenom}", │ │ │ │ + reprojectDeprecated: "你正使用 'reproject' 這個選項 " + "在 ${layerName} 層。這個選項已經不再使用:" + "它的使用原本是設計用來支援在商業地圖上秀出資料," + "但這個功能已經被" + "Spherical Mercator所取代。更多的資訊可以在 " + "http://trac.openlayers.org/wiki/SphericalMercator 找到。", │ │ │ │ + methodDeprecated: "這個方法已經不再使用且在3.0將會被移除," + "請使用 ${newMethod} 來代替。", │ │ │ │ + end: "" │ │ │ │ +}; │ │ │ │ +OpenLayers.Lang["vi"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Không xử lý được phản hồi ${statusText} cho yêu cầu", │ │ │ │ + Permalink: "Liên kết thường trực", │ │ │ │ + Overlays: "Lấp bản đồ", │ │ │ │ + "Base Layer": "Lớp nền", │ │ │ │ + noFID: "Không thể cập nhật tính năng thiếu FID.", │ │ │ │ + browserNotSupported: "Trình duyệt của bạn không hỗ trợ chức năng vẽ bằng vectơ. Hiện hỗ trợ các bộ kết xuất:\n${renderers}", │ │ │ │ + minZoomLevelError: "Chỉ nên sử dụng thuộc tính minZoomLevel với các lớp FixedZoomLevels-descendent. Việc lớp wfs này tìm cho minZoomLevel là di tích còn lại từ xưa. Tuy nhiên, nếu chúng tôi dời nó thì sẽ vỡ các chương trình OpenLayers mà dựa trên nó. Bởi vậy chúng tôi phản đối sử dụng nó – bước tìm cho minZoomLevel sẽ được dời vào phiên bản 3.0. Xin sử dụng thiết lập độ phân tích tối thiểu / tối đa thay thế, theo hướng dẫn này: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "Giao dịch WFS: THÀNH CÔNG ${response}", │ │ │ │ + commitFailed: "Giao dịch WFS: THẤT BẠI ${response}", │ │ │ │ + googleWarning: "Không thể tải lớp Google đúng đắn.<br><br>Để tránh thông báo này lần sau, hãy chọn BaseLayer mới dùng điều khiển chọn lớp ở góc trên phải.<br><br>Chắc script thư viện Google Maps hoặc không được bao gồm hoặc không chứa khóa API hợp với website của bạn.<br><br><a href='http://trac.openlayers.org/wiki/Google' target='_blank'>Trợ giúp về tính năng này</a> cho người phát triển.", │ │ │ │ + getLayerWarning: "Không thể tải lớp ${layerType} đúng đắn.<br><br>Để tránh thông báo này lần sau, hãy chọn BaseLayer mới dùng điều khiển chọn lớp ở góc trên phải.<br><br>Chắc script thư viện ${layerLib} không được bao gồm đúng kiểu.<br><br><a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>Trợ giúp về tính năng này</a> cho người phát triển.", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Tỷ lệ = 1 : ${scaleDenom}", │ │ │ │ + W: "T", │ │ │ │ + E: "Đ", │ │ │ │ + N: "B", │ │ │ │ + S: "N", │ │ │ │ + reprojectDeprecated: "Bạn đang áp dụng chế độ “reproject” vào lớp ${layerName}. Chế độ này đã bị phản đối: nó có mục đích hỗ trợ lấp dữ liệu trên các nền bản đồ thương mại; nên thực hiện hiệu ứng đó dùng tính năng Mercator Hình cầu. Có sẵn thêm chi tiết tại http://trac.openlayers.org/wiki/SphericalMercator .", │ │ │ │ + methodDeprecated: "Phương thức này đã bị phản đối và sẽ bị dời vào phiên bản 3.0. Xin hãy sử dụng ${newMethod} thay thế." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["nl"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Het verzoek is niet afgehandeld met de volgende melding: ${statusText}", │ │ │ │ + Permalink: "Permanente verwijzing", │ │ │ │ + Overlays: "Overlays", │ │ │ │ + "Base Layer": "Achtergrondkaart", │ │ │ │ + noFID: "Een optie die geen FID heeft kan niet bijgewerkt worden.", │ │ │ │ + browserNotSupported: "Uw browser ondersteunt het weergeven van vectoren niet.\nMomenteel ondersteunde weergavemogelijkheden:\n${renderers}", │ │ │ │ + minZoomLevelError: "De eigenschap minZoomLevel is alleen bedoeld voor gebruik lagen met die afstammen van FixedZoomLevels-lagen.\nDat deze WFS-laag minZoomLevel controleert, is een overblijfsel uit het verleden.\nWe kunnen deze controle echter niet verwijderen zonder op OL gebaseerde applicaties die hervan afhankelijk zijn stuk te maken.\nDaarom heeft deze functionaliteit de eigenschap 'deprecated' gekregen - de minZoomLevel wordt verwijderd in versie 3.0.\nGebruik in plaats van deze functie de mogelijkheid om min/max voor resolutie in te stellen zoals op de volgende pagina wordt beschreven:\nhttp://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "WFS-transactie: succesvol ${response}", │ │ │ │ + commitFailed: "WFS-transactie: mislukt ${response}", │ │ │ │ + googleWarning: "De Google-Layer kon niet correct geladen worden.<br /><br />\nOm deze melding niet meer te krijgen, moet u een andere achtergrondkaart kiezen in de laagwisselaar in de rechterbovenhoek.<br /><br />\nDit komt waarschijnlijk doordat de bibliotheek ${layerLib} niet correct ingevoegd is.<br /><br />\nOntwikkelaars: <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>klik hier</a> om dit werkend te krijgen.", │ │ │ │ + getLayerWarning: "De laag ${layerType} kon niet goed geladen worden.<br /><br />\nOm deze melding niet meer te krijgen, moet u een andere achtergrondkaart kiezen in de laagwisselaar in de rechterbovenhoek.<br /><br />\nDit komt waarschijnlijk doordat de bibliotheek ${layerLib} niet correct is ingevoegd.<br /><br />\nOntwikkelaars: <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>klik hier</a> om dit werkend te krijgen.", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Schaal = 1 : ${scaleDenom}", │ │ │ │ + W: "W", │ │ │ │ + E: "O", │ │ │ │ + N: "N", │ │ │ │ + S: "Z", │ │ │ │ + reprojectDeprecated: "U gebruikt de optie 'reproject' op de laag ${layerName}.\nDeze optie is vervallen: deze optie was ontwikkeld om gegevens over commerciële basiskaarten weer te geven, maar deze functionaliteit wordt nu bereikt door ondersteuning van Spherical Mercator.\nMeer informatie is beschikbaar op http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Deze methode is verouderd en wordt verwijderd in versie 3.0.\nGebruik ${newMethod}." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["id"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Permintaan yang tak tertangani menghasilkan ${statusText}", │ │ │ │ + Permalink: "Pranala permanen", │ │ │ │ + Overlays: "Hamparan", │ │ │ │ + "Base Layer": "Lapisan Dasar", │ │ │ │ + noFID: "Tidak dapat memperbarui fitur yang tidak memiliki FID.", │ │ │ │ + browserNotSupported: "Peramban Anda tidak mendukung penggambaran vektor. Penggambar yang didukung saat ini adalah:\n${renderers}", │ │ │ │ + minZoomLevelError: "Properti minZoomLevel hanya ditujukan bekerja dengan lapisan FixedZoomLevels-descendent. Pengecekan minZoomLevel oleh lapisan wfs adalah peninggalan masa lalu. Kami tidak dapat menghapusnya tanpa kemungkinan merusak aplikasi berbasis OL yang mungkin bergantung padanya. Karenanya, kami menganggapnya tidak berlaku -- Cek minZoomLevel di bawah ini akan dihapus pada 3.0. Silakan gunakan penyetelan resolusi min/maks seperti dijabarkan di sini: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "WFS Transaksi: BERHASIL ${respon}", │ │ │ │ + commitFailed: "WFS Transaksi: GAGAL ${respon}", │ │ │ │ + googleWarning: "Lapisan Google tidak dapat dimuat dengan benar.<br><br>Untuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.<br><br>Kemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan atau tidak mengandung kunci API yang tepat untuk situs Anda.<br><br>Pengembang: Untuk bantuan mengatasi masalah ini, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>klik di sini</a>", │ │ │ │ + getLayerWarning: "Lapisan ${layerType} tidak dapat dimuat dengan benar.<br><br>Untuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.<br><br>Kemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan dengan benar.<br><br>Pengembang: Untuk bantuan mengatasi masalah ini, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>klik di sini</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Sekala = 1 : ${scaleDenom}", │ │ │ │ + W: "B", │ │ │ │ + E: "T", │ │ │ │ + N: "U", │ │ │ │ + S: "S", │ │ │ │ + reprojectDeprecated: "Anda menggunakan opsi 'reproject' pada lapisan ${layerName}. Opsi ini telah ditinggalkan: penggunaannya dirancang untuk mendukung tampilan data melalui peta dasar komersial, tapi fungsionalitas tersebut saat ini harus dilakukan dengan menggunakan dukungan Spherical Mercator. Informasi lebih lanjut tersedia di http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Metode ini telah usang dan akan dihapus di 3.0. Sebaliknya, harap gunakan ${newMethod}." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["oc"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Requèsta pas gerida, retorna ${statusText}", │ │ │ │ + Permalink: "Permaligam", │ │ │ │ + Overlays: "Calques", │ │ │ │ + "Base Layer": "Calc de basa", │ │ │ │ + noFID: "Impossible de metre a jorn un objècte sens identificant (fid).", │ │ │ │ + browserNotSupported: "Vòstre navegidor supòrta pas lo rendut vectorial. Los renderers actualament suportats son : \n${renderers}", │ │ │ │ + minZoomLevelError: "La proprietat minZoomLevel deu èsser utilizada solament per de jaces FixedZoomLevels-descendent. Lo fach qu'aqueste jaç WFS verifique la preséncia de minZoomLevel es una relica del passat. Çaquelà, la podèm suprimir sens copar d'aplicacions que ne poirián dependre. Es per aquò que la depreciam -- la verificacion del minZoomLevel serà suprimida en version 3.0. A la plaça, mercés d'utilizar los paramètres de resolucions min/max tal coma descrich sus : http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "Transaccion WFS : SUCCES ${response}", │ │ │ │ + commitFailed: "Transaccion WFS : FRACAS ${response}", │ │ │ │ + googleWarning: "Lo jaç Google es pas estat en mesura de se cargar corrèctament.<br><br>Per suprimir aqueste messatge, causissètz una BaseLayer novèla dins lo selector de jaç en naut a drecha.<br><br>Aquò es possiblament causat par la non-inclusion de la librariá Google Maps, o alara perque que la clau de l'API correspond pas a vòstre site.<br><br>Desvolopaires : per saber cossí corregir aquò, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>clicatz aicí</a>", │ │ │ │ + getLayerWarning: "Lo jaç ${layerType} es pas en mesura de se cargar corrèctament.<br><br>Per suprimir aqueste messatge, causissètz una BaseLayer novèla dins lo selector de jaç en naut a drecha.<br><br>Aquò es possiblament causat per la non-inclusion de la librariá ${layerLib}.<br><br>Desvolopaires : per saber cossí corregir aquí, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>clicatz aicí</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Escala ~ 1 : ${scaleDenom}", │ │ │ │ + W: "O", │ │ │ │ + E: "È", │ │ │ │ + N: "N", │ │ │ │ + S: "S", │ │ │ │ + reprojectDeprecated: "Utilizatz l'opcion 'reproject' sul jaç ${layerName}. Aquesta opcion es despreciada : Son usatge permetiá d'afichar de donadas al dessús de jaces raster comercials. Aquesta foncionalitat ara es suportada en utilizant lo supòrt de la projeccion Mercator Esferica. Mai d'informacion es disponibla sus http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Aqueste metòde es despreciada, e serà suprimida a la version 3.0. Mercés d'utilizar ${newMethod} a la plaça." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["ru"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Необработанный запрос вернул ${statusText}", │ │ │ │ + Permalink: "Постоянная ссылка", │ │ │ │ + Overlays: "Слои", │ │ │ │ + "Base Layer": "Основной слой", │ │ │ │ + noFID: "Невозможно обновить объект, для которого нет FID.", │ │ │ │ + browserNotSupported: "Ваш браузер не поддерживает векторную графику. На данный момент поддерживаются:\n${renderers}", │ │ │ │ + minZoomLevelError: "Свойство minZoomLevel предназначено только для использования со слоями, являющимися потомками FixedZoomLevels. То, что этот WFS-слой проверяется на minZoomLevel — реликт прошлого. Однако мы не можем удалить эту функцию, так как, возможно, от неё зависят некоторые основанные на OpenLayers приложения. Функция объявлена устаревшей — проверка minZoomLevel будет удалена в 3.0. Пожалуйста, используйте вместо неё настройку мин/макс разрешения, описанную здесь: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "Транзакция WFS: УСПЕШНО ${response}", │ │ │ │ + commitFailed: "Транзакция WFS: ОШИБКА ${response}", │ │ │ │ + googleWarning: "Слой Google не удалось нормально загрузить.<br><br>Чтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.<br><br>Скорее всего, причина в том, что библиотека Google Maps не была включена или не содержит корректного API-ключа для вашего сайта.<br><br>Разработчикам: чтобы узнать, как сделать, чтобы всё заработало, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>щёлкните тут</a>", │ │ │ │ + getLayerWarning: "Слой ${layerType} не удалось нормально загрузить. <br><br>Чтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.<br><br>Скорее всего, причина в том, что библиотека ${layerLib} не была включена или была включена некорректно.<br><br>Разработчикам: чтобы узнать, как сделать, чтобы всё заработало, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>щёлкните тут</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Масштаб = 1 : ${scaleDenom}", │ │ │ │ + W: "З", │ │ │ │ + E: "В", │ │ │ │ + N: "С", │ │ │ │ + S: "Ю", │ │ │ │ + reprojectDeprecated: "Вы используете опцию 'reproject' для слоя ${layerName}. Эта опция является устаревшей: ее использование предполагалось для поддержки показа данных поверх коммерческих базовых карт, но теперь этот функционал несёт встроенная поддержка сферической проекции Меркатора. Больше сведений доступно на http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Этот метод считается устаревшим и будет удалён в версии 3.0. Пожалуйста, пользуйтесь ${newMethod}." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["pl"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Nieobsługiwane żądanie zwróciło ${statusText}", │ │ │ │ + Permalink: "Permalink", │ │ │ │ + Overlays: "Nakładki", │ │ │ │ + "Base Layer": "Warstwa podstawowa", │ │ │ │ + noFID: "Nie można zaktualizować funkcji, dla których nie ma FID.", │ │ │ │ + browserNotSupported: "Twoja przeglądarka nie obsługuje renderowania wektorów. Obecnie obsługiwane renderowanie to:\n${renderers}", │ │ │ │ + minZoomLevelError: "Właściwość minZoomLevel jest przeznaczona tylko do użytku " + "z warstwami FixedZoomLevels-descendent." + "Warstwa wfs, która sprawdza minZoomLevel jest reliktem przeszłości." + "Nie możemy jej jednak usunąc bez mozliwości łamania OL aplikacji, " + "które mogą być od niej zależne. " + "Dlatego jesteśmy za deprecjację -- minZoomLevel " + "zostanie usunięta w wersji 3.0. W zamian prosze użyj " + "min/max rozdzielczości w sposób opisany tutaj: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "Transakcja WFS: SUKCES ${response}", │ │ │ │ + commitFailed: "Transakcja WFS: FAILED ${response}", │ │ │ │ + googleWarning: "Warstwa Google nie był w stanie załadować się poprawnie.<br><br>" + "Aby pozbyć się tej wiadomości, wybierz nową Warstwe podstawową " + "w przełączniku warstw w górnym prawym rogu mapy.<br><br>" + "Najprawdopodobniej jest to spowodowane tym, że biblioteka Google Maps " + "nie jest załadowana, lub nie zawiera poprawnego klucza do API dla twojej strony<br><br>" + "Programisto: Aby uzyskać pomoc , " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>kliknij tutaj</a>", │ │ │ │ + getLayerWarning: "Warstwa ${layerType} nie mogła zostać załadowana poprawnie.<br><br>" + "Aby pozbyć się tej wiadomości, wybierz nową Warstwe podstawową " + "w przełączniku warstw w górnym prawym rogu mapy.<br><br>" + "Najprawdopodobniej jest to spowodowane tym, że biblioteka ${layerLib} " + "nie jest załadowana, lub może(o ile biblioteka tego wymaga) " + "byc potrzebny klucza do API dla twojej strony<br><br>" + "Programisto: Aby uzyskać pomoc , " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>kliknij tutaj</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Skala = 1 : ${scaleDenom}", │ │ │ │ + W: "ZACH", │ │ │ │ + E: "WSCH", │ │ │ │ + N: "PN", │ │ │ │ + S: "PD", │ │ │ │ + Graticule: "Siatka", │ │ │ │ + reprojectDeprecated: "w warstwie ${layerName} używasz opcji 'reproject'. " + "Ta opcja jest przestarzała: " + "jej zastosowanie został zaprojektowany, aby wspierać wyświetlania danych przez komercyjne mapy, " + "jednak obecnie ta funkcjonalność powinien zostać osiągnięty za pomocą Spherical Mercator " + "its use was designed to support displaying data over commercial. Więcje informacji na ten temat możesz znaleźć na stronie " + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Ta metoda jest przestarzała i będzie usunięta od wersji 3.0. " + "W zamian użyj ${newMethod}." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["ksh"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Met dä Antwoot op en Aanfrooch ham_mer nix aanjefange: ${statusText}", │ │ │ │ + Permalink: "Lengk op Duuer", │ │ │ │ + Overlays: "Drövver jelaat", │ │ │ │ + "Base Layer": "Jrund-Nivoh", │ │ │ │ + noFID: 'En Saach, woh kein <i lang="en">FID</i> för doh es, löht sesch nit ändere.', │ │ │ │ + browserNotSupported: "Dinge Brauser kann kein Väktore ußjävve. De Zoote Ußjaabe, di em Momang jon, sen:\n${renderers}", │ │ │ │ + minZoomLevelError: 'De Eijeschaff „<code lang="en">minZoomLevel</code>“ es bloß doför jedaach, dat mer se met dä Nivvohß bruch, di vun <code lang="en">FixedZoomLevels</code> affhange don. Dat dat <i lang="en">WFS</i>-Nivvoh övverhoup de Eijeschaff „<code lang="en">minZoomLevel</code>“ pröhfe deiht, es noch övveresch vun fröhjer. Mer künne dat ävver jez nit fott lohße, oohne dat mer Jevaa loufe, dat Aanwendunge vun OpenLayers nit mieh loufe, di sesch doh velleijsch noch drop am verlohße sin. Dröm sare mer, dat mer et nit mieh han welle, un de „<code lang="en">minZoomLevel</code>“-Eijeschaff weed hee vun de Version 3.0 af nit mieh jeprööf wäde. Nemm doför de Enstellung för de hühßte un de kleinßte Oplöhsung, esu wi et en http://trac.openlayers.org/wiki/SettingZoomLevels opjeschrevve es.', │ │ │ │ + commitSuccess: 'Dä <i lang="en">WFS</i>-Vörjang es joot jeloufe: ${response}', │ │ │ │ + commitFailed: 'Dä <i lang="en">WFS</i>-Vörjang es scheif jejange: ${response}', │ │ │ │ + googleWarning: 'Dat Nivvoh <code lang="en">Google</code> kunnt nit reschtesch jelaade wääde.<br /><br />Öm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhke, rähß bovve en de Äk.<br /><br />Wascheinlesch es dat wiel dat <i lang="en">Google-Maps</i>-Skrepp entweeder nit reschtesch enjebonge wood, udder nit dä reschtejje <i lang="en">API</i>-Schlößel för Ding Web-ßait scheke deiht.<br /><br />För Projrammierer jidd_et Hölp do_drövver, <a href="http://trac.openlayers.org/wiki/Google" target="_blank">wi mer dat aan et Loufe brengk</a>.', │ │ │ │ + getLayerWarning: 'Dat Nivvoh <code>${layerType}</code> kunnt nit reschtesch jelaade wääde.<br /><br />Öm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhkre, rähß bovve en de Äk.<br /><br />Wascheinlesch es dat, wiel dat Skrepp <code>${layerLib}</code> nit reschtesch enjebonge wood.<br /><br />För Projrammierer jidd_Et Hölp do_drövver, <a href="http://trac.openlayers.org/wiki/${layerLib}" target="_blank">wi mer dat aan et Loufe brengk</a>.', │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Mohßshtaab = 1 : ${scaleDenom}", │ │ │ │ + W: "W", │ │ │ │ + E: "O", │ │ │ │ + N: "N", │ │ │ │ + S: "S", │ │ │ │ + reprojectDeprecated: "Do bruchs de Ußwahl <code>reproject</code> op däm Nivvoh <code>${layerName}</code>. Di Ußwahl es nit mieh jähn jesinn. Se wohr doför jedaach, öm Date op jeschääfsmäßesch eruß jejovve Kaate bovve drop ze moole, wat ävver enzwesche besser met dä Öngershtözung för de ßfääresche Mäkaator Beldscher jeiht. Doh kanns De mieh drövver fenge op dä Sigg: http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Hee di Metood es nim_mih aktoäll un et weed se en dä Version 3.0 nit mieh jävve. Nemm <code>${newMethod}</code> doföör." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang.es = { │ │ │ │ + unhandledRequest: "Respuesta a petición no gestionada ${statusText}", │ │ │ │ + Permalink: "Enlace permanente", │ │ │ │ + Overlays: "Capas superpuestas", │ │ │ │ + "Base Layer": "Capa Base", │ │ │ │ + noFID: "No se puede actualizar un elemento para el que no existe FID.", │ │ │ │ + browserNotSupported: "Su navegador no soporta renderización vectorial. Los renderizadores soportados actualmente son:\n${renderers}", │ │ │ │ + minZoomLevelError: "La propiedad minZoomLevel debe sólo utilizarse " + "con las capas que tienen FixedZoomLevels. El hecho de que " + "una capa wfs compruebe minZoomLevel es una reliquia del " + "pasado. Sin embargo, no podemos eliminarla sin discontinuar " + "probablemente las aplicaciones OL que puedan depender de ello. " + "Así pues estamos haciéndolo obsoleto --la comprobación " + "minZoomLevel se eliminará en la versión 3.0. Utilice el ajuste " + "de resolution min/max en su lugar, tal como se describe aquí: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "Transacción WFS: ÉXITO ${response}", │ │ │ │ + commitFailed: "Transacción WFS: FALLÓ ${response}", │ │ │ │ + googleWarning: "La capa Google no pudo ser cargada correctamente.<br><br>" + "Para evitar este mensaje, seleccione una nueva Capa Base " + "en el selector de capas en la esquina superior derecha.<br><br>" + "Probablemente, esto se debe a que el script de la biblioteca de " + "Google Maps no fue correctamente incluido en su página, o no " + "contiene la clave del API correcta para su sitio.<br><br>" + "Desarrolladores: Para ayudar a hacer funcionar esto correctamente, " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>haga clic aquí</a>", │ │ │ │ + getLayerWarning: "La capa ${layerType} no pudo ser cargada correctamente.<br><br>" + "Para evitar este mensaje, seleccione una nueva Capa Base " + "en el selector de capas en la esquina superior derecha.<br><br>" + "Probablemente, esto se debe a que el script de " + "la biblioteca ${layerLib} " + "no fue correctamente incluido en su página.<br><br>" + "Desarrolladores: Para ayudar a hacer funcionar esto correctamente, " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>haga clic aquí</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Escala = 1 : ${scaleDenom}", │ │ │ │ + W: "O", │ │ │ │ + E: "E", │ │ │ │ + N: "N", │ │ │ │ + S: "S", │ │ │ │ + Graticule: "Retícula", │ │ │ │ + reprojectDeprecated: "Está usando la opción 'reproject' en la capa " + "${layerName}. Esta opción es obsoleta: su uso fue diseñado " + "para soportar la visualización de datos sobre mapas base comerciales, " + "pero ahora esa funcionalidad debería conseguirse mediante el soporte " + "de la proyección Spherical Mercator. Más información disponible en " + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Este método es obsoleto y se eliminará en la versión 3.0. " + "Por favor utilice el método ${newMethod} en su lugar.", │ │ │ │ + end: "" │ │ │ │ +}; │ │ │ │ +OpenLayers.Lang["el"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Κλίμακα ~ 1 : ${scaleDenom}" │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang.it = { │ │ │ │ + unhandledRequest: "Codice di ritorno della richiesta ${statusText}", │ │ │ │ + Permalink: "Permalink", │ │ │ │ + Overlays: "Overlays", │ │ │ │ + "Base Layer": "Livello base", │ │ │ │ + noFID: "Impossibile aggiornare un elemento grafico che non abbia il FID.", │ │ │ │ + browserNotSupported: "Il tuo browser non supporta il rendering vettoriale. I renderizzatore attualemnte supportati sono:\n${renderers}", │ │ │ │ + minZoomLevelError: "La proprietà minZoomLevel è da utilizzare solamente " + "con livelli che abbiano FixedZoomLevels. Il fatto che " + "questo livello wfs controlli la proprietà minZoomLevel è " + "un retaggio del passato. Non possiamo comunque rimuoverla " + "senza rompere le vecchie applicazioni che dipendono su di essa." + "Quindi siamo costretti a deprecarla -- minZoomLevel " + "e sarà rimossa dalla vesione 3.0. Si prega di utilizzare i " + "settaggi di risoluzione min/max come descritto qui: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "Transazione WFS: SUCCESS ${response}", │ │ │ │ + commitFailed: "Transazione WFS: FAILED ${response}", │ │ │ │ + googleWarning: "Il livello Google non è riuscito a caricare correttamente.<br><br>" + "Per evitare questo messaggio, seleziona un nuovo BaseLayer " + "nel selettore di livelli nell'angolo in alto a destra.<br><br>" + "Più precisamente, ciò accade perchè la libreria Google Maps " + "non è stata inclusa nella pagina, oppure non contiene la " + "corretta API key per il tuo sito.<br><br>" + "Sviluppatori: Per aiuto su come farlo funzionare correttamente, " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>clicca qui</a>", │ │ │ │ + getLayerWarning: "Il livello ${layerType} non è riuscito a caricare correttamente.<br><br>" + "Per evitare questo messaggio, seleziona un nuovo BaseLayer " + "nel selettore di livelli nell'angolo in alto a destra.<br><br>" + "Più precisamente, ciò accade perchè la libreria ${layerLib} " + "non è stata inclusa nella pagina.<br><br>" + "Sviluppatori: Per aiuto su come farlo funzionare correttamente, " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>clicca qui</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Scala = 1 : ${scaleDenom}", │ │ │ │ + reprojectDeprecated: "Stai utilizzando l'opzione 'reproject' sul livello ${layerName}. " + "Questa opzione è deprecata: il suo utilizzo è stato introdotto per" + "supportare il disegno dei dati sopra mappe commerciali, ma tale " + "funzionalità dovrebbe essere ottenuta tramite l'utilizzo della proiezione " + "Spherical Mercator. Per maggiori informazioni consultare qui " + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Questo metodo è stato deprecato e sarà rimosso dalla versione 3.0. " + "Si prega di utilizzare il metodo ${newMethod} in alternativa.", │ │ │ │ + end: "" │ │ │ │ +}; │ │ │ │ +OpenLayers.Lang["da-DK"] = { │ │ │ │ + unhandledRequest: "En ikke håndteret forespørgsel returnerede ${statusText}", │ │ │ │ + Permalink: "Permalink", │ │ │ │ + Overlays: "Kortlag", │ │ │ │ + "Base Layer": "Baggrundslag", │ │ │ │ + noFID: "Kan ikke opdateret en feature (et objekt) der ikke har et FID.", │ │ │ │ + browserNotSupported: "Din browser understøtter ikke vektor visning. Følgende vektor visninger understøttes:\n${renderers}", │ │ │ │ + minZoomLevelError: "Egenskaben minZoomLevel er kun beregnet til brug " + "med FixedZoomLevels. At dette WFS lag kontrollerer " + "minZoomLevel egenskaben, er et levn fra en tidligere " + "version. Vi kan desværre ikke fjerne dette uden at risikere " + "at ødelægge eksisterende OL baserede programmer der " + " benytter denne funktionalitet. " + "Egenskaben bør derfor ikke anvendes, og minZoomLevel " + "kontrollen herunder vil blive fjernet i version 3.0. " + "Benyt istedet min/max opløsnings indstillingerne, som " + "er beskrevet her: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "WFS transaktion: LYKKEDES ${response}", │ │ │ │ + commitFailed: "WFS transaktion: MISLYKKEDES ${response}", │ │ │ │ + googleWarning: "Google laget kunne ikke indlæses.<br><br>" + "For at fjerne denne besked, vælg et nyt bagrundskort i " + "lagskifteren i øverste højre hjørne.<br><br>" + "Fejlen skyldes formentlig at Google Maps bibliotekts " + "scriptet ikke er inkluderet, eller ikke indeholder den " + "korrkte API nøgle for dit site.<br><br>" + "Udviklere: For hjælp til at få dette til at fungere, " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>klik her</a>", │ │ │ │ + getLayerWarning: "${layerType}-laget kunne ikke indlæses.<br><br>" + "For at fjerne denne besked, vælg et nyt bagrundskort i " + "lagskifteren i øverste højre hjørne.<br><br>" + "Fejlen skyldes formentlig at ${layerLib} bibliotekts " + "scriptet ikke er inkluderet.<br><br>" + "Udviklere: For hjælp til at få dette til at fungere, " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>klik her</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Målforhold = 1 : ${scaleDenom}", │ │ │ │ + reprojectDeprecated: "Du anvender indstillingen 'reproject' på laget ${layerName}." + "Denne indstilling bør ikke længere anvendes. Den var beregnet " + "til at vise data ovenpå kommercielle grundkort, men den funktionalitet " + "bør nu opnås ved at anvende Spherical Mercator understøttelsen. " + "Mere information er tilgængelig her: " + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Denne funktion bør ikke længere anvendes, og vil blive fjernet i version 3.0. " + "Anvend venligst funktionen ${newMethod} istedet." │ │ │ │ +}; │ │ │ │ +OpenLayers.Lang["br"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Distro evel reked anveret ${statusText}", │ │ │ │ + Permalink: "Peurliamm", │ │ │ │ + Overlays: "Gwiskadoù", │ │ │ │ + "Base Layer": "Gwiskad diazez", │ │ │ │ + noFID: "N'haller ket hizivaat un elfenn ma n'eus ket a niverenn-anaout (FID) eviti.", │ │ │ │ + browserNotSupported: "N'eo ket skoret an daskor vektorel gant ho merdeer. Setu aze an daskorerioù skoret evit ar poent :\n${renderers}", │ │ │ │ + minZoomLevelError: "Ne zleer implijout ar perzh minZoomLevel nemet evit gwiskadoù FixedZoomLevels-descendent. Ar fed ma wiria ar gwiskad WHS-se hag-eñ ez eus eus minZoomLevel zo un aspadenn gozh. Koulskoude n'omp ket evit e ziverkañ kuit da derriñ arloadoù diazezet war OL a c'hallfe bezañ stag outañ. Setu perak eo dispredet -- Lamet kuit e vo ar gwiriañ minZoomLevel a-is er stumm 3.0. Ober gant an arventennoù bihanañ/brasañ evel deskrivet amañ e plas : http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "Treuzgread WFS : MAT EO ${response}", │ │ │ │ + commitFailed: "Treuzgread WFS Transaction: C'HWITET ${response}", │ │ │ │ + googleWarning: "N'eus ket bet gallet kargañ ar gwiskad Google ent reizh.<br><br>Evit en em zizober eus ar c'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c'horn dehoù el laez.<br><br>Sur a-walc'h eo peogwir n'eo ket bet ensoc'het levraoueg Google Maps pe neuze ne glot ket an alc'hwez API gant ho lec'hienn.<br><br>Diorroerien : Evit reizhañ an dra-se, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>click here</a>", │ │ │ │ + getLayerWarning: "N'haller ket kargañ ar gwiskad ${layerType} ent reizh.<br><br>Evit en em zizober eus ar c'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c'horn dehoù el laez.<br><br>Sur a-walc'h eo peogwir n'eo ket bet ensoc'het mat al levraoueg ${layerLib}.<br><br>Diorroerien : Evit gouzout penaos reizhañ an dra-se, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>click here</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Skeul = 1 : ${scaleDenom}", │ │ │ │ + W: "K", │ │ │ │ + E: "R", │ │ │ │ + N: "N", │ │ │ │ + S: "S", │ │ │ │ + reprojectDeprecated: "Emaoc'h oc'h implijout an dibarzh 'reproject' war ar gwiskad ${layerName}. Dispredet eo an dibarzh-mañ : bet eo hag e talveze da ziskwel roadennoù war-c'horre kartennoù diazez kenwerzhel, un dra hag a c'haller ober bremañ gant an arc'hwel dre skor banndres boullek Mercator. Muioc'h a ditouroù a c'haller da gaout war http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Dispredet eo an daore-se ha tennet e vo kuit eus ar stumm 3.0. Grit gant ${newMethod} e plas." │ │ │ │ +}); │ │ │ │ +OpenLayers.Lang["zh-CN"] = { │ │ │ │ + unhandledRequest: "未处理的请求,返回值为 ${statusText}", │ │ │ │ + Permalink: "永久链接", │ │ │ │ + Overlays: "叠加层", │ │ │ │ + "Base Layer": "基础图层", │ │ │ │ + noFID: "无法更新feature,缺少FID。", │ │ │ │ + browserNotSupported: "你使用的浏览器不支持矢量渲染。当前支持的渲染方式包括:\n${renderers}", │ │ │ │ + minZoomLevelError: "minZoomLevel属性仅适合用于" + "使用了固定缩放级别的图层。这个 " + "wfs 图层检查 minZoomLevel 是过去遗留下来的。" + "然而,我们不能移除它," + "而破坏依赖于它的基于OL的应用程序。" + "因此,我们废除了它 -- minZoomLevel " + "将会在3.0中被移除。请改用 " + "min/max resolution 设置,参考:" + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "WFS Transaction: 成功。 ${response}", │ │ │ │ + commitFailed: "WFS Transaction: 失败。 ${response}", │ │ │ │ + googleWarning: "Google图层不能正确加载。<br><br>" + "要消除这个信息,请在右上角的" + "图层控制面板中选择其他的基础图层。<br><br>" + "这种情况很可能是没有正确的包含Google地图脚本库," + "或者是没有包含在你的站点上" + "使用的正确的Google Maps API密匙。<br><br>" + "开发者:获取使其正确工作的帮助信息," + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>点击这里</a>", │ │ │ │ + getLayerWarning: "${layerType} 图层不能正确加载。<br><br>" + "要消除这个信息,请在右上角的" + "图层控制面板中选择其他的基础图层。<br><br>" + "这种情况很可能是没有正确的包含" + "${layerLib} 脚本库。<br><br>" + "开发者:获取使其正确工作的帮助信息," + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>点击这里</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "比例尺 = 1 : ${scaleDenom}", │ │ │ │ + reprojectDeprecated: "你正在使用 ${layerName} 图层上的'reproject'选项。" + "这个选项已经不再使用:" + "它是被设计用来支持显示商业的地图数据," + "不过现在该功能可以通过使用Spherical Mercator来实现。" + "更多信息可以参阅" + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "该方法已经不再被支持,并且将在3.0中被移除。" + "请使用 ${newMethod} 方法来替代。", │ │ │ │ + end: "" │ │ │ │ +}; │ │ │ │ +OpenLayers.Lang["sk"] = OpenLayers.Util.applyDefaults({ │ │ │ │ + unhandledRequest: "Neobslúžené požiadavky vracajú ${statusText}", │ │ │ │ + Permalink: "Trvalý odkaz", │ │ │ │ + Overlays: "Prekrytia", │ │ │ │ + "Base Layer": "Základná vrstva", │ │ │ │ + noFID: "Nie je možné aktualizovať vlastnosť, pre ktorú neexistuje FID.", │ │ │ │ + browserNotSupported: "Váš prehliadač nepodporuje vykresľovanie vektorov. Momentálne podporované vykresľovače sú:\n${renderers}", │ │ │ │ + minZoomLevelError: "Vlastnosť minZoomLevel je určený iba na použitie s vrstvami odvodenými od FixedZoomLevels. To, že táto wfs vrstva kontroluje minZoomLevel je pozostatok z minulosti. Nemôžeme ho však odstrániť, aby sme sa vyhli možnému porušeniu aplikácií založených na Open Layers, ktoré na tomto môže závisieť. Preto ho označujeme ako zavrhovaný - dolu uvedená kontrola minZoomLevel bude odstránená vo verzii 3.0. Použite prosím namiesto toho kontrolu min./max. rozlíšenia podľa tu uvedeného popisu: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ + commitSuccess: "Transakcia WFS: ÚSPEŠNÁ ${response}", │ │ │ │ + commitFailed: "Transakcia WFS: ZLYHALA ${response}", │ │ │ │ + googleWarning: "Vrstvu Google nebolo možné správne načítať.<br><br>Aby ste sa tejto správy zbavili vyberte novú BaseLayer v prepínači vrstiev v pravom hornom rohu.<br><br>Toto sa stalo pravdepodobne preto, že skript knižnice Google Maps buď nebol načítaný alebo neobsahuje správny kľúč API pre vašu lokalitu.<br><br>Vývojári: Tu môžete získať <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>pomoc so sfunkčnením</a>", │ │ │ │ + getLayerWarning: "Vrstvu ${layerType} nebolo možné správne načítať.<br><br>Aby ste sa tejto správy zbavili vyberte novú BaseLayer v prepínači vrstiev v pravom hornom rohu.<br><br>Toto sa stalo pravdepodobne preto, že skript knižnice ${layerType} buď nebol načítaný alebo neobsahuje správny kľúč API pre vašu lokalitu.<br><br>Vývojári: Tu môžete získať <a href='http://trac.openlayers.org/wiki/${layerType}' target='_blank'>pomoc so sfunkčnením</a>", │ │ │ │ + "Scale = 1 : ${scaleDenom}": "Mierka = 1 : ${scaleDenom}", │ │ │ │ + reprojectDeprecated: "Používate voľby „reproject“ vrstvy ${layerType}. Táto voľba je zzavrhovaná: jej použitie bolo navrhnuté na podporu zobrazovania údajov nad komerčnými základovými mapami, ale túto funkcionalitu je teraz možné dosiahnuť pomocou Spherical Mercator. Ďalšie informácie získate na stránke http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ + methodDeprecated: "Táto metóda je zavrhovaná a bude odstránená vo verzii 3.0. Použite prosím namiesto nej metódu ${newMethod}." │ │ │ │ +}); │ │ │ │ +OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, { │ │ │ │ + bounds: null, │ │ │ │ + div: null, │ │ │ │ + initialize: function(bounds, borderColor, borderWidth) { │ │ │ │ + this.bounds = bounds; │ │ │ │ + this.div = OpenLayers.Util.createDiv(); │ │ │ │ + this.div.style.overflow = "hidden"; │ │ │ │ + this.events = new OpenLayers.Events(this, this.div); │ │ │ │ + this.setBorder(borderColor, borderWidth) │ │ │ │ }, │ │ │ │ destroy: function() { │ │ │ │ - OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments); │ │ │ │ - this.tileCountUpToTier.length = 0; │ │ │ │ - this.tierSizeInTiles.length = 0; │ │ │ │ - this.tierImageSize.length = 0 │ │ │ │ + this.bounds = null; │ │ │ │ + this.div = null; │ │ │ │ + OpenLayers.Marker.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.Zoomify(this.name, this.url, this.size, this.options) │ │ │ │ + setBorder: function(color, width) { │ │ │ │ + if (!color) { │ │ │ │ + color = "red" │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ - }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ - var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ - var z = this.getZoomForResolution(res); │ │ │ │ - var tileIndex = x + y * this.tierSizeInTiles[z].w + this.tileCountUpToTier[z]; │ │ │ │ - var path = "TileGroup" + Math.floor(tileIndex / 256) + "/" + z + "-" + x + "-" + y + ".jpg"; │ │ │ │ - var url = this.url; │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(path, url) │ │ │ │ + if (!width) { │ │ │ │ + width = 2 │ │ │ │ } │ │ │ │ - return url + path │ │ │ │ + this.div.style.border = width + "px solid " + color │ │ │ │ }, │ │ │ │ - getImageSize: function() { │ │ │ │ - if (arguments.length > 0) { │ │ │ │ - var bounds = this.adjustBounds(arguments[0]); │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ - var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ - var z = this.getZoomForResolution(res); │ │ │ │ - var w = this.standardTileSize; │ │ │ │ - var h = this.standardTileSize; │ │ │ │ - if (x == this.tierSizeInTiles[z].w - 1) { │ │ │ │ - var w = this.tierImageSize[z].w % this.standardTileSize │ │ │ │ - } │ │ │ │ - if (y == this.tierSizeInTiles[z].h - 1) { │ │ │ │ - var h = this.tierImageSize[z].h % this.standardTileSize │ │ │ │ - } │ │ │ │ - return new OpenLayers.Size(w, h) │ │ │ │ - } else { │ │ │ │ - return this.tileSize │ │ │ │ + draw: function(px, sz) { │ │ │ │ + OpenLayers.Util.modifyDOMElement(this.div, null, px, sz); │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + onScreen: function() { │ │ │ │ + var onScreen = false; │ │ │ │ + if (this.map) { │ │ │ │ + var screenBounds = this.map.getExtent(); │ │ │ │ + onScreen = screenBounds.containsBounds(this.bounds, true, true) │ │ │ │ } │ │ │ │ + return onScreen │ │ │ │ }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left, this.map.maxExtent.top) │ │ │ │ + display: function(display) { │ │ │ │ + this.div.style.display = display ? "" : "none" │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Zoomify" │ │ │ │ + CLASS_NAME: "OpenLayers.Marker.Box" │ │ │ │ }); │ │ │ │ -OpenLayers.Layer.TMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - serviceVersion: "1.0.0", │ │ │ │ - layername: null, │ │ │ │ - type: null, │ │ │ │ - isBaseLayer: true, │ │ │ │ - tileOrigin: null, │ │ │ │ - serverResolutions: null, │ │ │ │ - zoomOffset: 0, │ │ │ │ - initialize: function(name, url, options) { │ │ │ │ - var newArguments = []; │ │ │ │ - newArguments.push(name, url, {}, options); │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments) │ │ │ │ - }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.TMS(this.name, this.url, this.getOptions()) │ │ │ │ +OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ + hitDetection: true, │ │ │ │ + hitOverflow: 0, │ │ │ │ + canvas: null, │ │ │ │ + features: null, │ │ │ │ + pendingRedraw: false, │ │ │ │ + cachedSymbolBounds: {}, │ │ │ │ + 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") │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ - var y = Math.round((bounds.bottom - this.tileOrigin.lat) / (res * this.tileSize.h)); │ │ │ │ - var z = this.getServerZoom(); │ │ │ │ - var path = this.serviceVersion + "/" + this.layername + "/" + z + "/" + x + "/" + y + "." + this.type; │ │ │ │ - var url = this.url; │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(path, url) │ │ │ │ - } │ │ │ │ - return url + path │ │ │ │ + setExtent: function() { │ │ │ │ + OpenLayers.Renderer.prototype.setExtent.apply(this, arguments); │ │ │ │ + return false │ │ │ │ }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); │ │ │ │ - if (!this.tileOrigin) { │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left, this.map.maxExtent.bottom) │ │ │ │ + eraseGeometry: function(geometry, featureId) { │ │ │ │ + this.eraseFeatures(this.features[featureId][0]) │ │ │ │ + }, │ │ │ │ + supported: function() { │ │ │ │ + return OpenLayers.CANVAS_SUPPORTED │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.TMS" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.ArcXML = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - fontStyleKeys: ["antialiasing", "blockout", "font", "fontcolor", "fontsize", "fontstyle", "glowing", "interval", "outline", "printmode", "shadow", "transparency"], │ │ │ │ - request: null, │ │ │ │ - response: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - this.request = new OpenLayers.Format.ArcXML.Request; │ │ │ │ - this.response = new OpenLayers.Format.ArcXML.Response; │ │ │ │ - if (options) { │ │ │ │ - if (options.requesttype == "feature") { │ │ │ │ - this.request.get_image = null; │ │ │ │ - var qry = this.request.get_feature.query; │ │ │ │ - this.addCoordSys(qry.featurecoordsys, options.featureCoordSys); │ │ │ │ - this.addCoordSys(qry.filtercoordsys, options.filterCoordSys); │ │ │ │ - if (options.polygon) { │ │ │ │ - qry.isspatial = true; │ │ │ │ - qry.spatialfilter.polygon = options.polygon │ │ │ │ - } else if (options.envelope) { │ │ │ │ - qry.isspatial = true; │ │ │ │ - qry.spatialfilter.envelope = { │ │ │ │ - minx: 0, │ │ │ │ - miny: 0, │ │ │ │ - maxx: 0, │ │ │ │ - maxy: 0 │ │ │ │ - }; │ │ │ │ - this.parseEnvelope(qry.spatialfilter.envelope, options.envelope) │ │ │ │ - } │ │ │ │ - } else if (options.requesttype == "image") { │ │ │ │ - this.request.get_feature = null; │ │ │ │ - var props = this.request.get_image.properties; │ │ │ │ - this.parseEnvelope(props.envelope, options.envelope); │ │ │ │ - this.addLayers(props.layerlist, options.layers); │ │ │ │ - this.addImageSize(props.imagesize, options.tileSize); │ │ │ │ - this.addCoordSys(props.featurecoordsys, options.featureCoordSys); │ │ │ │ - this.addCoordSys(props.filtercoordsys, options.filterCoordSys) │ │ │ │ + drawFeature: function(feature, style) { │ │ │ │ + var rendered; │ │ │ │ + if (feature.geometry) { │ │ │ │ + style = this.applyDefaultSymbolizer(style || feature.style); │ │ │ │ + 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) { │ │ │ │ + this.features[feature.id] = [feature, style] │ │ │ │ } else { │ │ │ │ - this.request = null │ │ │ │ + delete this.features[feature.id] │ │ │ │ } │ │ │ │ + this.pendingRedraw = true │ │ │ │ } │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - parseEnvelope: function(env, arr) { │ │ │ │ - if (arr && arr.length == 4) { │ │ │ │ - env.minx = arr[0]; │ │ │ │ - env.miny = arr[1]; │ │ │ │ - env.maxx = arr[2]; │ │ │ │ - env.maxy = arr[3] │ │ │ │ + if (this.pendingRedraw && !this.locked) { │ │ │ │ + this.redraw(); │ │ │ │ + this.pendingRedraw = false │ │ │ │ } │ │ │ │ + return rendered │ │ │ │ }, │ │ │ │ - addLayers: function(ll, lyrs) { │ │ │ │ - for (var lind = 0, len = lyrs.length; lind < len; lind++) { │ │ │ │ - ll.push(lyrs[lind]) │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - }, │ │ │ │ - addImageSize: function(imsize, olsize) { │ │ │ │ - if (olsize !== null) { │ │ │ │ - imsize.width = olsize.w; │ │ │ │ - imsize.height = olsize.h; │ │ │ │ - imsize.printwidth = olsize.w; │ │ │ │ - imsize.printheight = olsize.h │ │ │ │ + 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 │ │ │ │ } │ │ │ │ }, │ │ │ │ - addCoordSys: function(featOrFilt, fsys) { │ │ │ │ - if (typeof fsys == "string") { │ │ │ │ - featOrFilt.id = parseInt(fsys); │ │ │ │ - featOrFilt.string = fsys │ │ │ │ - } else if (typeof fsys == "object" && fsys.proj !== null) { │ │ │ │ - featOrFilt.id = fsys.proj.srsProjNumber; │ │ │ │ - featOrFilt.string = fsys.proj.srsCode │ │ │ │ - } else { │ │ │ │ - featOrFilt = fsys │ │ │ │ + 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 : -(.5 * width); │ │ │ │ + var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.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 / 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 │ │ │ │ }, │ │ │ │ - iserror: function(data) { │ │ │ │ - var ret = null; │ │ │ │ - if (!data) { │ │ │ │ - ret = this.response.error !== "" │ │ │ │ - } else { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ - var errorNodes = data.documentElement.getElementsByTagName("ERROR"); │ │ │ │ - ret = errorNodes !== null && errorNodes.length > 0 │ │ │ │ + drawNamedSymbol: function(geometry, style, featureId) { │ │ │ │ + var x, y, cx, cy, i, symbolBounds, scaling, angle; │ │ │ │ + var unscaledStrokeWidth; │ │ │ │ + var deg2rad = Math.PI / 180; │ │ │ │ + var symbol = OpenLayers.Renderer.symbol[style.graphicName]; │ │ │ │ + if (!symbol) { │ │ │ │ + throw new Error(style.graphicName + " is not a valid symbol name") │ │ │ │ } │ │ │ │ - return ret │ │ │ │ - }, │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ + 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; │ │ │ │ + this.canvas.lineCap = "round"; │ │ │ │ + this.canvas.lineJoin = "round"; │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.lineCap = "round"; │ │ │ │ + this.hitContext.lineJoin = "round" │ │ │ │ } │ │ │ │ - var arcNode = null; │ │ │ │ - if (data && data.documentElement) { │ │ │ │ - if (data.documentElement.nodeName == "ARCXML") { │ │ │ │ - arcNode = data.documentElement │ │ │ │ - } else { │ │ │ │ - arcNode = data.documentElement.getElementsByTagName("ARCXML")[0] │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - if (!arcNode || arcNode.firstChild.nodeName === "parsererror") { │ │ │ │ - var error, source; │ │ │ │ - try { │ │ │ │ - error = data.firstChild.nodeValue; │ │ │ │ - source = data.firstChild.childNodes[1].firstChild.nodeValue │ │ │ │ - } catch (err) {} │ │ │ │ - throw { │ │ │ │ - message: "Error parsing the ArcXML request", │ │ │ │ - error: error, │ │ │ │ - source: source │ │ │ │ - } │ │ │ │ + this.canvas.save(); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.save() │ │ │ │ } │ │ │ │ - var response = this.parseResponse(arcNode); │ │ │ │ - return response │ │ │ │ - }, │ │ │ │ - write: function(request) { │ │ │ │ - if (!request) { │ │ │ │ - request = this.request │ │ │ │ + this.canvas.translate(p0, p1); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.translate(p0, p1) │ │ │ │ } │ │ │ │ - var root = this.createElementNS("", "ARCXML"); │ │ │ │ - root.setAttribute("version", "1.1"); │ │ │ │ - var reqElem = this.createElementNS("", "REQUEST"); │ │ │ │ - if (request.get_image != null) { │ │ │ │ - var getElem = this.createElementNS("", "GET_IMAGE"); │ │ │ │ - reqElem.appendChild(getElem); │ │ │ │ - var propElem = this.createElementNS("", "PROPERTIES"); │ │ │ │ - getElem.appendChild(propElem); │ │ │ │ - var props = request.get_image.properties; │ │ │ │ - if (props.featurecoordsys != null) { │ │ │ │ - var feat = this.createElementNS("", "FEATURECOORDSYS"); │ │ │ │ - propElem.appendChild(feat); │ │ │ │ - if (props.featurecoordsys.id === 0) { │ │ │ │ - feat.setAttribute("string", props.featurecoordsys["string"]) │ │ │ │ - } else { │ │ │ │ - feat.setAttribute("id", props.featurecoordsys.id) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (props.filtercoordsys != null) { │ │ │ │ - var filt = this.createElementNS("", "FILTERCOORDSYS"); │ │ │ │ - propElem.appendChild(filt); │ │ │ │ - if (props.filtercoordsys.id === 0) { │ │ │ │ - filt.setAttribute("string", props.filtercoordsys.string) │ │ │ │ - } else { │ │ │ │ - filt.setAttribute("id", props.filtercoordsys.id) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (props.envelope != null) { │ │ │ │ - var env = this.createElementNS("", "ENVELOPE"); │ │ │ │ - propElem.appendChild(env); │ │ │ │ - env.setAttribute("minx", props.envelope.minx); │ │ │ │ - env.setAttribute("miny", props.envelope.miny); │ │ │ │ - env.setAttribute("maxx", props.envelope.maxx); │ │ │ │ - env.setAttribute("maxy", props.envelope.maxy) │ │ │ │ - } │ │ │ │ - var imagesz = this.createElementNS("", "IMAGESIZE"); │ │ │ │ - propElem.appendChild(imagesz); │ │ │ │ - imagesz.setAttribute("height", props.imagesize.height); │ │ │ │ - imagesz.setAttribute("width", props.imagesize.width); │ │ │ │ - if (props.imagesize.height != props.imagesize.printheight || props.imagesize.width != props.imagesize.printwidth) { │ │ │ │ - imagesz.setAttribute("printheight", props.imagesize.printheight); │ │ │ │ - imagesz.setArrtibute("printwidth", props.imagesize.printwidth) │ │ │ │ + angle = deg2rad * style.rotation; │ │ │ │ + if (!isNaN(angle)) { │ │ │ │ + this.canvas.rotate(angle); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.rotate(angle) │ │ │ │ } │ │ │ │ - if (props.background != null) { │ │ │ │ - var backgrnd = this.createElementNS("", "BACKGROUND"); │ │ │ │ - propElem.appendChild(backgrnd); │ │ │ │ - backgrnd.setAttribute("color", props.background.color.r + "," + props.background.color.g + "," + props.background.color.b); │ │ │ │ - if (props.background.transcolor !== null) { │ │ │ │ - backgrnd.setAttribute("transcolor", props.background.transcolor.r + "," + props.background.transcolor.g + "," + props.background.transcolor.b) │ │ │ │ - } │ │ │ │ + } │ │ │ │ + scaling = 2 * style.pointRadius / Math.max(symbolBounds.getWidth(), symbolBounds.getHeight()); │ │ │ │ + this.canvas.scale(scaling, scaling); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.scale(scaling, scaling) │ │ │ │ + } │ │ │ │ + cx = symbolBounds.getCenterLonLat().lon; │ │ │ │ + cy = symbolBounds.getCenterLonLat().lat; │ │ │ │ + this.canvas.translate(-cx, -cy); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.translate(-cx, -cy) │ │ │ │ + } │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - if (props.layerlist != null && props.layerlist.length > 0) { │ │ │ │ - var layerlst = this.createElementNS("", "LAYERLIST"); │ │ │ │ - propElem.appendChild(layerlst); │ │ │ │ - for (var ld = 0; ld < props.layerlist.length; ld++) { │ │ │ │ - var ldef = this.createElementNS("", "LAYERDEF"); │ │ │ │ - layerlst.appendChild(ldef); │ │ │ │ - ldef.setAttribute("id", props.layerlist[ld].id); │ │ │ │ - ldef.setAttribute("visible", props.layerlist[ld].visible); │ │ │ │ - if (typeof props.layerlist[ld].query == "object") { │ │ │ │ - var query = props.layerlist[ld].query; │ │ │ │ - if (query.where.length < 0) { │ │ │ │ - continue │ │ │ │ - } │ │ │ │ - var queryElem = null; │ │ │ │ - if (typeof query.spatialfilter == "boolean" && query.spatialfilter) { │ │ │ │ - queryElem = this.createElementNS("", "SPATIALQUERY") │ │ │ │ - } else { │ │ │ │ - queryElem = this.createElementNS("", "QUERY") │ │ │ │ - } │ │ │ │ - queryElem.setAttribute("where", query.where); │ │ │ │ - if (typeof query.accuracy == "number" && query.accuracy > 0) { │ │ │ │ - queryElem.setAttribute("accuracy", query.accuracy) │ │ │ │ - } │ │ │ │ - if (typeof query.featurelimit == "number" && query.featurelimit < 2e3) { │ │ │ │ - queryElem.setAttribute("featurelimit", query.featurelimit) │ │ │ │ - } │ │ │ │ - if (typeof query.subfields == "string" && query.subfields != "#ALL#") { │ │ │ │ - queryElem.setAttribute("subfields", query.subfields) │ │ │ │ - } │ │ │ │ - if (typeof query.joinexpression == "string" && query.joinexpression.length > 0) { │ │ │ │ - queryElem.setAttribute("joinexpression", query.joinexpression) │ │ │ │ - } │ │ │ │ - if (typeof query.jointables == "string" && query.jointables.length > 0) { │ │ │ │ - queryElem.setAttribute("jointables", query.jointables) │ │ │ │ - } │ │ │ │ - ldef.appendChild(queryElem) │ │ │ │ - } │ │ │ │ - if (typeof props.layerlist[ld].renderer == "object") { │ │ │ │ - this.addRenderer(ldef, props.layerlist[ld].renderer) │ │ │ │ - } │ │ │ │ + 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() │ │ │ │ } │ │ │ │ - } else if (request.get_feature != null) { │ │ │ │ - var getElem = this.createElementNS("", "GET_FEATURES"); │ │ │ │ - getElem.setAttribute("outputmode", "newxml"); │ │ │ │ - getElem.setAttribute("checkesc", "true"); │ │ │ │ - if (request.get_feature.geometry) { │ │ │ │ - getElem.setAttribute("geometry", request.get_feature.geometry) │ │ │ │ - } else { │ │ │ │ - getElem.setAttribute("geometry", "false") │ │ │ │ - } │ │ │ │ - if (request.get_feature.compact) { │ │ │ │ - getElem.setAttribute("compact", request.get_feature.compact) │ │ │ │ - } │ │ │ │ - if (request.get_feature.featurelimit == "number") { │ │ │ │ - getElem.setAttribute("featurelimit", request.get_feature.featurelimit) │ │ │ │ - } │ │ │ │ - getElem.setAttribute("globalenvelope", "true"); │ │ │ │ - reqElem.appendChild(getElem); │ │ │ │ - if (request.get_feature.layer != null && request.get_feature.layer.length > 0) { │ │ │ │ - var lyrElem = this.createElementNS("", "LAYER"); │ │ │ │ - lyrElem.setAttribute("id", request.get_feature.layer); │ │ │ │ - getElem.appendChild(lyrElem) │ │ │ │ + } │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - var fquery = request.get_feature.query; │ │ │ │ - if (fquery != null) { │ │ │ │ - var qElem = null; │ │ │ │ - if (fquery.isspatial) { │ │ │ │ - qElem = this.createElementNS("", "SPATIALQUERY") │ │ │ │ - } else { │ │ │ │ - qElem = this.createElementNS("", "QUERY") │ │ │ │ - } │ │ │ │ - getElem.appendChild(qElem); │ │ │ │ - if (typeof fquery.accuracy == "number") { │ │ │ │ - qElem.setAttribute("accuracy", fquery.accuracy) │ │ │ │ - } │ │ │ │ - if (fquery.featurecoordsys != null) { │ │ │ │ - var fcsElem1 = this.createElementNS("", "FEATURECOORDSYS"); │ │ │ │ - if (fquery.featurecoordsys.id == 0) { │ │ │ │ - fcsElem1.setAttribute("string", fquery.featurecoordsys.string) │ │ │ │ - } else { │ │ │ │ - fcsElem1.setAttribute("id", fquery.featurecoordsys.id) │ │ │ │ - } │ │ │ │ - qElem.appendChild(fcsElem1) │ │ │ │ - } │ │ │ │ - if (fquery.filtercoordsys != null) { │ │ │ │ - var fcsElem2 = this.createElementNS("", "FILTERCOORDSYS"); │ │ │ │ - if (fquery.filtercoordsys.id === 0) { │ │ │ │ - fcsElem2.setAttribute("string", fquery.filtercoordsys.string) │ │ │ │ - } else { │ │ │ │ - fcsElem2.setAttribute("id", fquery.filtercoordsys.id) │ │ │ │ - } │ │ │ │ - qElem.appendChild(fcsElem2) │ │ │ │ - } │ │ │ │ - if (fquery.buffer > 0) { │ │ │ │ - var bufElem = this.createElementNS("", "BUFFER"); │ │ │ │ - bufElem.setAttribute("distance", fquery.buffer); │ │ │ │ - qElem.appendChild(bufElem) │ │ │ │ - } │ │ │ │ - if (fquery.isspatial) { │ │ │ │ - var spfElem = this.createElementNS("", "SPATIALFILTER"); │ │ │ │ - spfElem.setAttribute("relation", fquery.spatialfilter.relation); │ │ │ │ - qElem.appendChild(spfElem); │ │ │ │ - if (fquery.spatialfilter.envelope) { │ │ │ │ - var envElem = this.createElementNS("", "ENVELOPE"); │ │ │ │ - envElem.setAttribute("minx", fquery.spatialfilter.envelope.minx); │ │ │ │ - envElem.setAttribute("miny", fquery.spatialfilter.envelope.miny); │ │ │ │ - envElem.setAttribute("maxx", fquery.spatialfilter.envelope.maxx); │ │ │ │ - envElem.setAttribute("maxy", fquery.spatialfilter.envelope.maxy); │ │ │ │ - spfElem.appendChild(envElem) │ │ │ │ - } else if (typeof fquery.spatialfilter.polygon == "object") { │ │ │ │ - spfElem.appendChild(this.writePolygonGeometry(fquery.spatialfilter.polygon)) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (fquery.where != null && fquery.where.length > 0) { │ │ │ │ - qElem.setAttribute("where", fquery.where) │ │ │ │ + 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() │ │ │ │ } │ │ │ │ } │ │ │ │ - root.appendChild(reqElem); │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [root]) │ │ │ │ - }, │ │ │ │ - addGroupRenderer: function(ldef, toprenderer) { │ │ │ │ - var topRelem = this.createElementNS("", "GROUPRENDERER"); │ │ │ │ - ldef.appendChild(topRelem); │ │ │ │ - for (var rind = 0; rind < toprenderer.length; rind++) { │ │ │ │ - var renderer = toprenderer[rind]; │ │ │ │ - this.addRenderer(topRelem, renderer) │ │ │ │ + style.strokeWidth = unscaledStrokeWidth; │ │ │ │ + this.canvas.restore(); │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.restore() │ │ │ │ } │ │ │ │ + this.setCanvasStyle("reset") │ │ │ │ }, │ │ │ │ - addRenderer: function(topRelem, renderer) { │ │ │ │ - if (OpenLayers.Util.isArray(renderer)) { │ │ │ │ - this.addGroupRenderer(topRelem, renderer) │ │ │ │ + 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 { │ │ │ │ - var renderElem = this.createElementNS("", renderer.type.toUpperCase() + "RENDERER"); │ │ │ │ - topRelem.appendChild(renderElem); │ │ │ │ - if (renderElem.tagName == "VALUEMAPRENDERER") { │ │ │ │ - this.addValueMapRenderer(renderElem, renderer) │ │ │ │ - } else if (renderElem.tagName == "VALUEMAPLABELRENDERER") { │ │ │ │ - this.addValueMapLabelRenderer(renderElem, renderer) │ │ │ │ - } else if (renderElem.tagName == "SIMPLELABELRENDERER") { │ │ │ │ - this.addSimpleLabelRenderer(renderElem, renderer) │ │ │ │ - } else if (renderElem.tagName == "SCALEDEPENDENTRENDERER") { │ │ │ │ - this.addScaleDependentRenderer(renderElem, renderer) │ │ │ │ - } │ │ │ │ + this.canvas.globalAlpha = 0; │ │ │ │ + this.canvas.lineWidth = 1 │ │ │ │ } │ │ │ │ }, │ │ │ │ - addScaleDependentRenderer: function(renderElem, renderer) { │ │ │ │ - if (typeof renderer.lower == "string" || typeof renderer.lower == "number") { │ │ │ │ - renderElem.setAttribute("lower", renderer.lower) │ │ │ │ - } │ │ │ │ - if (typeof renderer.upper == "string" || typeof renderer.upper == "number") { │ │ │ │ - renderElem.setAttribute("upper", renderer.upper) │ │ │ │ + featureIdToHex: function(featureId) { │ │ │ │ + var id = Number(featureId.split("_").pop()) + 1; │ │ │ │ + if (id >= 16777216) { │ │ │ │ + this.hitOverflow = id - 16777215; │ │ │ │ + id = id % 16777216 + 1 │ │ │ │ } │ │ │ │ - this.addRenderer(renderElem, renderer.renderer) │ │ │ │ + var hex = "000000" + id.toString(16); │ │ │ │ + var len = hex.length; │ │ │ │ + hex = "#" + hex.substring(len - 6, len); │ │ │ │ + return hex │ │ │ │ }, │ │ │ │ - addValueMapLabelRenderer: function(renderElem, renderer) { │ │ │ │ - renderElem.setAttribute("lookupfield", renderer.lookupfield); │ │ │ │ - renderElem.setAttribute("labelfield", renderer.labelfield); │ │ │ │ - if (typeof renderer.exacts == "object") { │ │ │ │ - for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) { │ │ │ │ - var exact = renderer.exacts[ext]; │ │ │ │ - var eelem = this.createElementNS("", "EXACT"); │ │ │ │ - if (typeof exact.value == "string") { │ │ │ │ - eelem.setAttribute("value", exact.value) │ │ │ │ - } │ │ │ │ - if (typeof exact.label == "string") { │ │ │ │ - eelem.setAttribute("label", exact.label) │ │ │ │ - } │ │ │ │ - if (typeof exact.method == "string") { │ │ │ │ - eelem.setAttribute("method", exact.method) │ │ │ │ - } │ │ │ │ - renderElem.appendChild(eelem); │ │ │ │ - if (typeof exact.symbol == "object") { │ │ │ │ - var selem = null; │ │ │ │ - if (exact.symbol.type == "text") { │ │ │ │ - selem = this.createElementNS("", "TEXTSYMBOL") │ │ │ │ - } │ │ │ │ - if (selem != null) { │ │ │ │ - var keys = this.fontStyleKeys; │ │ │ │ - for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ - var key = keys[i]; │ │ │ │ - if (exact.symbol[key]) { │ │ │ │ - selem.setAttribute(key, exact.symbol[key]) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - eelem.appendChild(selem) │ │ │ │ - } │ │ │ │ + setHitContextStyle: function(type, featureId, symbolizer, strokeScaling) { │ │ │ │ + var hex = this.featureIdToHex(featureId); │ │ │ │ + if (type == "fill") { │ │ │ │ + this.hitContext.globalAlpha = 1; │ │ │ │ + this.hitContext.fillStyle = hex │ │ │ │ + } else if (type == "stroke") { │ │ │ │ + this.hitContext.globalAlpha = 1; │ │ │ │ + this.hitContext.strokeStyle = hex; │ │ │ │ + if (typeof strokeScaling === "undefined") { │ │ │ │ + this.hitContext.lineWidth = symbolizer.strokeWidth + 2 │ │ │ │ + } else { │ │ │ │ + if (!isNaN(strokeScaling)) { │ │ │ │ + this.hitContext.lineWidth = symbolizer.strokeWidth + 2 / strokeScaling │ │ │ │ } │ │ │ │ } │ │ │ │ + } else { │ │ │ │ + this.hitContext.globalAlpha = 0; │ │ │ │ + this.hitContext.lineWidth = 1 │ │ │ │ } │ │ │ │ }, │ │ │ │ - addValueMapRenderer: function(renderElem, renderer) { │ │ │ │ - renderElem.setAttribute("lookupfield", renderer.lookupfield); │ │ │ │ - if (typeof renderer.ranges == "object") { │ │ │ │ - for (var rng = 0, rnglen = renderer.ranges.length; rng < rnglen; rng++) { │ │ │ │ - var range = renderer.ranges[rng]; │ │ │ │ - var relem = this.createElementNS("", "RANGE"); │ │ │ │ - relem.setAttribute("lower", range.lower); │ │ │ │ - relem.setAttribute("upper", range.upper); │ │ │ │ - renderElem.appendChild(relem); │ │ │ │ - if (typeof range.symbol == "object") { │ │ │ │ - var selem = null; │ │ │ │ - if (range.symbol.type == "simplepolygon") { │ │ │ │ - selem = this.createElementNS("", "SIMPLEPOLYGONSYMBOL") │ │ │ │ - } │ │ │ │ - if (selem != null) { │ │ │ │ - if (typeof range.symbol.boundarycolor == "string") { │ │ │ │ - selem.setAttribute("boundarycolor", range.symbol.boundarycolor) │ │ │ │ - } │ │ │ │ - if (typeof range.symbol.fillcolor == "string") { │ │ │ │ - selem.setAttribute("fillcolor", range.symbol.fillcolor) │ │ │ │ - } │ │ │ │ - if (typeof range.symbol.filltransparency == "number") { │ │ │ │ - selem.setAttribute("filltransparency", range.symbol.filltransparency) │ │ │ │ + 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() │ │ │ │ } │ │ │ │ - relem.appendChild(selem) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else if (typeof renderer.exacts == "object") { │ │ │ │ - for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) { │ │ │ │ - var exact = renderer.exacts[ext]; │ │ │ │ - var eelem = this.createElementNS("", "EXACT"); │ │ │ │ - if (typeof exact.value == "string") { │ │ │ │ - eelem.setAttribute("value", exact.value) │ │ │ │ - } │ │ │ │ - if (typeof exact.label == "string") { │ │ │ │ - eelem.setAttribute("label", exact.label) │ │ │ │ - } │ │ │ │ - if (typeof exact.method == "string") { │ │ │ │ - eelem.setAttribute("method", exact.method) │ │ │ │ - } │ │ │ │ - renderElem.appendChild(eelem); │ │ │ │ - if (typeof exact.symbol == "object") { │ │ │ │ - var selem = null; │ │ │ │ - if (exact.symbol.type == "simplemarker") { │ │ │ │ - selem = this.createElementNS("", "SIMPLEMARKERSYMBOL") │ │ │ │ } │ │ │ │ - if (selem != null) { │ │ │ │ - if (typeof exact.symbol.antialiasing == "string") { │ │ │ │ - selem.setAttribute("antialiasing", exact.symbol.antialiasing) │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.color == "string") { │ │ │ │ - selem.setAttribute("color", exact.symbol.color) │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.outline == "string") { │ │ │ │ - selem.setAttribute("outline", exact.symbol.outline) │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.overlap == "string") { │ │ │ │ - selem.setAttribute("overlap", exact.symbol.overlap) │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.shadow == "string") { │ │ │ │ - selem.setAttribute("shadow", exact.symbol.shadow) │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.transparency == "number") { │ │ │ │ - selem.setAttribute("transparency", exact.symbol.transparency) │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.usecentroid == "string") { │ │ │ │ - selem.setAttribute("usecentroid", exact.symbol.usecentroid) │ │ │ │ - } │ │ │ │ - if (typeof exact.symbol.width == "number") { │ │ │ │ - selem.setAttribute("width", exact.symbol.width) │ │ │ │ + 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() │ │ │ │ } │ │ │ │ - eelem.appendChild(selem) │ │ │ │ + this.setCanvasStyle("reset") │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ - addSimpleLabelRenderer: function(renderElem, renderer) { │ │ │ │ - renderElem.setAttribute("field", renderer.field); │ │ │ │ - var keys = ["featureweight", "howmanylabels", "labelbufferratio", "labelpriorities", "labelweight", "linelabelposition", "rotationalangles"]; │ │ │ │ - for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ - var key = keys[i]; │ │ │ │ - if (renderer[key]) { │ │ │ │ - renderElem.setAttribute(key, renderer[key]) │ │ │ │ + drawLineString: function(geometry, style, featureId) { │ │ │ │ + style = OpenLayers.Util.applyDefaults({ │ │ │ │ + fill: false │ │ │ │ + }, style); │ │ │ │ + this.drawLinearRing(geometry, style, featureId) │ │ │ │ + }, │ │ │ │ + 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 (renderer.symbol.type == "text") { │ │ │ │ - var symbol = renderer.symbol; │ │ │ │ - var selem = this.createElementNS("", "TEXTSYMBOL"); │ │ │ │ - renderElem.appendChild(selem); │ │ │ │ - var keys = this.fontStyleKeys; │ │ │ │ - for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ - var key = keys[i]; │ │ │ │ - if (symbol[key]) { │ │ │ │ - selem.setAttribute(key, renderer[key]) │ │ │ │ - } │ │ │ │ + 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") │ │ │ │ }, │ │ │ │ - writePolygonGeometry: function(polygon) { │ │ │ │ - if (!(polygon instanceof OpenLayers.Geometry.Polygon)) { │ │ │ │ - throw { │ │ │ │ - message: "Cannot write polygon geometry to ArcXML with an " + polygon.CLASS_NAME + " object.", │ │ │ │ - geometry: polygon │ │ │ │ + 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]) │ │ │ │ } │ │ │ │ - } │ │ │ │ - var polyElem = this.createElementNS("", "POLYGON"); │ │ │ │ - for (var ln = 0, lnlen = polygon.components.length; ln < lnlen; ln++) { │ │ │ │ - var ring = polygon.components[ln]; │ │ │ │ - var ringElem = this.createElementNS("", "RING"); │ │ │ │ - for (var rn = 0, rnlen = ring.components.length; rn < rnlen; rn++) { │ │ │ │ - var point = ring.components[rn]; │ │ │ │ - var pointElem = this.createElementNS("", "POINT"); │ │ │ │ - pointElem.setAttribute("x", point.x); │ │ │ │ - pointElem.setAttribute("y", point.y); │ │ │ │ - ringElem.appendChild(pointElem) │ │ │ │ + if (type === "fill") { │ │ │ │ + context.fill() │ │ │ │ + } else { │ │ │ │ + context.stroke() │ │ │ │ } │ │ │ │ - polyElem.appendChild(ringElem) │ │ │ │ } │ │ │ │ - return polyElem │ │ │ │ }, │ │ │ │ - parseResponse: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - var newData = new OpenLayers.Format.XML; │ │ │ │ - data = newData.read(data) │ │ │ │ - } │ │ │ │ - var response = new OpenLayers.Format.ArcXML.Response; │ │ │ │ - var errorNode = data.getElementsByTagName("ERROR"); │ │ │ │ - if (errorNode != null && errorNode.length > 0) { │ │ │ │ - response.error = this.getChildValue(errorNode, "Unknown error.") │ │ │ │ - } else { │ │ │ │ - var responseNode = data.getElementsByTagName("RESPONSE"); │ │ │ │ - if (responseNode == null || responseNode.length == 0) { │ │ │ │ - response.error = "No RESPONSE tag found in ArcXML response."; │ │ │ │ - return response │ │ │ │ + drawPolygon: function(geometry, style, featureId) { │ │ │ │ + var components = geometry.components; │ │ │ │ + var len = components.length; │ │ │ │ + this.drawLinearRing(components[0], style, featureId); │ │ │ │ + for (var i = 1; i < len; ++i) { │ │ │ │ + this.canvas.globalCompositeOperation = "destination-out"; │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.globalCompositeOperation = "destination-out" │ │ │ │ } │ │ │ │ - var rtype = responseNode[0].firstChild.nodeName; │ │ │ │ - if (rtype == "#text") { │ │ │ │ - rtype = responseNode[0].firstChild.nextSibling.nodeName │ │ │ │ + this.drawLinearRing(components[i], OpenLayers.Util.applyDefaults({ │ │ │ │ + stroke: false, │ │ │ │ + fillOpacity: 1 │ │ │ │ + }, style), featureId); │ │ │ │ + this.canvas.globalCompositeOperation = "source-over"; │ │ │ │ + if (this.hitDetection) { │ │ │ │ + this.hitContext.globalCompositeOperation = "source-over" │ │ │ │ } │ │ │ │ - if (rtype == "IMAGE") { │ │ │ │ - var envelopeNode = data.getElementsByTagName("ENVELOPE"); │ │ │ │ - var outputNode = data.getElementsByTagName("OUTPUT"); │ │ │ │ - if (envelopeNode == null || envelopeNode.length == 0) { │ │ │ │ - response.error = "No ENVELOPE tag found in ArcXML response." │ │ │ │ - } else if (outputNode == null || outputNode.length == 0) { │ │ │ │ - response.error = "No OUTPUT tag found in ArcXML response." │ │ │ │ - } else { │ │ │ │ - var envAttr = this.parseAttributes(envelopeNode[0]); │ │ │ │ - var outputAttr = this.parseAttributes(outputNode[0]); │ │ │ │ - if (typeof outputAttr.type == "string") { │ │ │ │ - response.image = { │ │ │ │ - envelope: envAttr, │ │ │ │ - output: { │ │ │ │ - type: outputAttr.type, │ │ │ │ - data: this.getChildValue(outputNode[0]) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - response.image = { │ │ │ │ - envelope: envAttr, │ │ │ │ - output: outputAttr │ │ │ │ - } │ │ │ │ - } │ │ │ │ + this.drawLinearRing(components[i], OpenLayers.Util.applyDefaults({ │ │ │ │ + fill: false │ │ │ │ + }, style), featureId) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + drawText: function(location, style) { │ │ │ │ + var pt = this.getLocalXY(location); │ │ │ │ + this.setCanvasStyle("reset"); │ │ │ │ + this.canvas.fillStyle = style.fontColor; │ │ │ │ + this.canvas.globalAlpha = style.fontOpacity || 1; │ │ │ │ + var fontStyle = [style.fontStyle ? style.fontStyle : "normal", "normal", 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) { │ │ │ │ + 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; │ │ │ │ + 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() │ │ │ │ } │ │ │ │ - } else if (rtype == "FEATURES") { │ │ │ │ - var features = responseNode[0].getElementsByTagName("FEATURES"); │ │ │ │ - var featureCount = features[0].getElementsByTagName("FEATURECOUNT"); │ │ │ │ - response.features.featurecount = featureCount[0].getAttribute("count"); │ │ │ │ - if (response.features.featurecount > 0) { │ │ │ │ - var envelope = features[0].getElementsByTagName("ENVELOPE"); │ │ │ │ - response.features.envelope = this.parseAttributes(envelope[0], typeof 0); │ │ │ │ - var featureList = features[0].getElementsByTagName("FEATURE"); │ │ │ │ - for (var fn = 0; fn < featureList.length; fn++) { │ │ │ │ - var feature = new OpenLayers.Feature.Vector; │ │ │ │ - var fields = featureList[fn].getElementsByTagName("FIELD"); │ │ │ │ - for (var fdn = 0; fdn < fields.length; fdn++) { │ │ │ │ - var fieldName = fields[fdn].getAttribute("name"); │ │ │ │ - var fieldValue = fields[fdn].getAttribute("value"); │ │ │ │ - feature.attributes[fieldName] = fieldValue │ │ │ │ - } │ │ │ │ - var geom = featureList[fn].getElementsByTagName("POLYGON"); │ │ │ │ - if (geom.length > 0) { │ │ │ │ - var ring = geom[0].getElementsByTagName("RING"); │ │ │ │ - var polys = []; │ │ │ │ - for (var rn = 0; rn < ring.length; rn++) { │ │ │ │ - var linearRings = []; │ │ │ │ - linearRings.push(this.parsePointGeometry(ring[rn])); │ │ │ │ - var holes = ring[rn].getElementsByTagName("HOLE"); │ │ │ │ - for (var hn = 0; hn < holes.length; hn++) { │ │ │ │ - linearRings.push(this.parsePointGeometry(holes[hn])) │ │ │ │ - } │ │ │ │ - holes = null; │ │ │ │ - polys.push(new OpenLayers.Geometry.Polygon(linearRings)); │ │ │ │ - linearRings = null │ │ │ │ - } │ │ │ │ - ring = null; │ │ │ │ - if (polys.length == 1) { │ │ │ │ - feature.geometry = polys[0] │ │ │ │ - } else { │ │ │ │ - feature.geometry = new OpenLayers.Geometry.MultiPolygon(polys) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - response.features.feature.push(feature) │ │ │ │ + this.canvas.fillText(labelRows[i], pt[0], pt[1] + lineHeight * i) │ │ │ │ + } │ │ │ │ + } else if (this.canvas.mozDrawText) { │ │ │ │ + this.canvas.mozTextStyle = fontStyle; │ │ │ │ + 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") │ │ │ │ + }, │ │ │ │ + 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] │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getFeatureIdFromEvent: function(evt) { │ │ │ │ + var featureId, feature; │ │ │ │ + if (this.hitDetection && this.root.style.display !== "none") { │ │ │ │ + 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) { │ │ │ │ + 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) {} │ │ │ │ } │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - response.error = "Unidentified response type." │ │ │ │ } │ │ │ │ } │ │ │ │ - return response │ │ │ │ + return feature │ │ │ │ }, │ │ │ │ - parseAttributes: function(node, type) { │ │ │ │ - var attributes = {}; │ │ │ │ - for (var attr = 0; attr < node.attributes.length; attr++) { │ │ │ │ - if (type == "number") { │ │ │ │ - attributes[node.attributes[attr].nodeName] = parseFloat(node.attributes[attr].nodeValue) │ │ │ │ - } else { │ │ │ │ - attributes[node.attributes[attr].nodeName] = node.attributes[attr].nodeValue │ │ │ │ - } │ │ │ │ + eraseFeatures: function(features) { │ │ │ │ + if (!OpenLayers.Util.isArray(features)) { │ │ │ │ + features = [features] │ │ │ │ } │ │ │ │ - return attributes │ │ │ │ + for (var i = 0; i < features.length; ++i) { │ │ │ │ + delete this.features[features[i].id] │ │ │ │ + } │ │ │ │ + this.redraw() │ │ │ │ }, │ │ │ │ - parsePointGeometry: function(node) { │ │ │ │ - var ringPoints = []; │ │ │ │ - var coords = node.getElementsByTagName("COORDS"); │ │ │ │ - if (coords.length > 0) { │ │ │ │ - var coordArr = this.getChildValue(coords[0]); │ │ │ │ - coordArr = coordArr.split(/;/); │ │ │ │ - for (var cn = 0; cn < coordArr.length; cn++) { │ │ │ │ - var coordItems = coordArr[cn].split(/ /); │ │ │ │ - ringPoints.push(new OpenLayers.Geometry.Point(coordItems[0], coordItems[1])) │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - coords = null │ │ │ │ - } else { │ │ │ │ - var point = node.getElementsByTagName("POINT"); │ │ │ │ - if (point.length > 0) { │ │ │ │ - for (var pn = 0; pn < point.length; pn++) { │ │ │ │ - ringPoints.push(new OpenLayers.Geometry.Point(parseFloat(point[pn].getAttribute("x")), parseFloat(point[pn].getAttribute("y")))) │ │ │ │ + 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]) │ │ │ │ } │ │ │ │ } │ │ │ │ - point = null │ │ │ │ + var item; │ │ │ │ + for (var i = 0, len = labelMap.length; i < len; ++i) { │ │ │ │ + item = labelMap[i]; │ │ │ │ + this.drawText(item[0].geometry.getCentroid(), item[1]) │ │ │ │ + } │ │ │ │ } │ │ │ │ - return new OpenLayers.Geometry.LinearRing(ringPoints) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.ArcXML" │ │ │ │ + CLASS_NAME: "OpenLayers.Renderer.Canvas" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.ArcXML.Request = OpenLayers.Class({ │ │ │ │ - initialize: function(params) { │ │ │ │ - var defaults = { │ │ │ │ - get_image: { │ │ │ │ - properties: { │ │ │ │ - background: null, │ │ │ │ - draw: true, │ │ │ │ - envelope: { │ │ │ │ - minx: 0, │ │ │ │ - miny: 0, │ │ │ │ - maxx: 0, │ │ │ │ - maxy: 0 │ │ │ │ - }, │ │ │ │ - featurecoordsys: { │ │ │ │ - id: 0, │ │ │ │ - string: "", │ │ │ │ - datumtransformid: 0, │ │ │ │ - datumtransformstring: "" │ │ │ │ - }, │ │ │ │ - filtercoordsys: { │ │ │ │ - id: 0, │ │ │ │ - string: "", │ │ │ │ - datumtransformid: 0, │ │ │ │ - datumtransformstring: "" │ │ │ │ - }, │ │ │ │ - imagesize: { │ │ │ │ - height: 0, │ │ │ │ - width: 0, │ │ │ │ - dpi: 96, │ │ │ │ - printheight: 0, │ │ │ │ - printwidth: 0, │ │ │ │ - scalesymbols: false │ │ │ │ - }, │ │ │ │ - layerlist: [], │ │ │ │ - output: { │ │ │ │ - baseurl: "", │ │ │ │ - legendbaseurl: "", │ │ │ │ - legendname: "", │ │ │ │ - legendpath: "", │ │ │ │ - legendurl: "", │ │ │ │ - name: "", │ │ │ │ - path: "", │ │ │ │ - type: "jpg", │ │ │ │ - url: "" │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - get_feature: { │ │ │ │ - layer: "", │ │ │ │ - query: { │ │ │ │ - isspatial: false, │ │ │ │ - featurecoordsys: { │ │ │ │ - id: 0, │ │ │ │ - string: "", │ │ │ │ - datumtransformid: 0, │ │ │ │ - datumtransformstring: "" │ │ │ │ - }, │ │ │ │ - filtercoordsys: { │ │ │ │ - id: 0, │ │ │ │ - string: "", │ │ │ │ - datumtransformid: 0, │ │ │ │ - datumtransformstring: "" │ │ │ │ - }, │ │ │ │ - buffer: 0, │ │ │ │ - where: "", │ │ │ │ - spatialfilter: { │ │ │ │ - relation: "envelope_intersection", │ │ │ │ - envelope: null │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - environment: { │ │ │ │ - separators: { │ │ │ │ - cs: " ", │ │ │ │ - ts: ";" │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - layer: [], │ │ │ │ - workspaces: [] │ │ │ │ - }; │ │ │ │ - return OpenLayers.Util.extend(this, defaults) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.ArcXML.Request" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.ArcXML.Response = OpenLayers.Class({ │ │ │ │ - initialize: function(params) { │ │ │ │ - var defaults = { │ │ │ │ - image: { │ │ │ │ - envelope: null, │ │ │ │ - output: "" │ │ │ │ - }, │ │ │ │ - features: { │ │ │ │ - featurecount: 0, │ │ │ │ - envelope: null, │ │ │ │ - feature: [] │ │ │ │ - }, │ │ │ │ - error: "" │ │ │ │ +OpenLayers.Renderer.Canvas.LABEL_ALIGN = { │ │ │ │ + l: "left", │ │ │ │ + r: "right", │ │ │ │ + t: "top", │ │ │ │ + b: "bottom" │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.Canvas.LABEL_FACTOR = { │ │ │ │ + l: 0, │ │ │ │ + r: -1, │ │ │ │ + t: 0, │ │ │ │ + b: -1 │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.Canvas.drawImageScaleFactor = null; │ │ │ │ +OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ + xmlns: "http://www.w3.org/2000/svg", │ │ │ │ + xlinkns: "http://www.w3.org/1999/xlink", │ │ │ │ + MAX_PIXEL: 15e3, │ │ │ │ + translationParameters: null, │ │ │ │ + symbolMetrics: null, │ │ │ │ + initialize: function(containerID) { │ │ │ │ + if (!this.supported()) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + OpenLayers.Renderer.Elements.prototype.initialize.apply(this, arguments); │ │ │ │ + this.translationParameters = { │ │ │ │ + x: 0, │ │ │ │ + y: 0 │ │ │ │ }; │ │ │ │ - return OpenLayers.Util.extend(this, defaults) │ │ │ │ + this.symbolMetrics = {} │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.ArcXML.Response" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.ArcIMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - DEFAULT_PARAMS: { │ │ │ │ - ClientVersion: "9.2", │ │ │ │ - ServiceName: "" │ │ │ │ + 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")) │ │ │ │ }, │ │ │ │ - featureCoordSys: "4326", │ │ │ │ - filterCoordSys: "4326", │ │ │ │ - layers: null, │ │ │ │ - async: true, │ │ │ │ - name: "ArcIMS", │ │ │ │ - isBaseLayer: true, │ │ │ │ - DEFAULT_OPTIONS: { │ │ │ │ - tileSize: new OpenLayers.Size(512, 512), │ │ │ │ - featureCoordSys: "4326", │ │ │ │ - filterCoordSys: "4326", │ │ │ │ - layers: null, │ │ │ │ - isBaseLayer: true, │ │ │ │ - async: true, │ │ │ │ - name: "ArcIMS" │ │ │ │ + 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 │ │ │ │ }, │ │ │ │ - initialize: function(name, url, options) { │ │ │ │ - this.tileSize = new OpenLayers.Size(512, 512); │ │ │ │ - this.params = OpenLayers.Util.applyDefaults({ │ │ │ │ - ServiceName: options.serviceName │ │ │ │ - }, this.DEFAULT_PARAMS); │ │ │ │ - this.options = OpenLayers.Util.applyDefaults(options, this.DEFAULT_OPTIONS); │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, [name, url, this.params, options]); │ │ │ │ - if (this.transparent) { │ │ │ │ - if (!this.isBaseLayer) { │ │ │ │ - this.isBaseLayer = false │ │ │ │ - } │ │ │ │ - if (this.format == "image/jpeg") { │ │ │ │ - this.format = OpenLayers.Util.alphaHack() ? "image/gif" : "image/png" │ │ │ │ + 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 (resolutionChanged) { │ │ │ │ + this.left = left; │ │ │ │ + this.top = top; │ │ │ │ + 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) { │ │ │ │ + this.setExtent(extent, true) │ │ │ │ } │ │ │ │ - } │ │ │ │ - if (this.options.layers === null) { │ │ │ │ - this.options.layers = [] │ │ │ │ + return coordSysUnchanged && inRange │ │ │ │ } │ │ │ │ }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - var url = ""; │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var axlReq = new OpenLayers.Format.ArcXML(OpenLayers.Util.extend(this.options, { │ │ │ │ - requesttype: "image", │ │ │ │ - envelope: bounds.toArray(), │ │ │ │ - tileSize: this.tileSize │ │ │ │ - })); │ │ │ │ - var req = new OpenLayers.Request.POST({ │ │ │ │ - url: this.getFullRequestString(), │ │ │ │ - data: axlReq.write(), │ │ │ │ - async: false │ │ │ │ - }); │ │ │ │ - if (req != null) { │ │ │ │ - var doc = req.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = req.responseText │ │ │ │ + translate: function(x, y) { │ │ │ │ + if (!this.inValidRange(x, y, true)) { │ │ │ │ + return false │ │ │ │ + } else { │ │ │ │ + var transformString = ""; │ │ │ │ + if (x || y) { │ │ │ │ + transformString = "translate(" + x + "," + y + ")" │ │ │ │ } │ │ │ │ - var axlResp = new OpenLayers.Format.ArcXML; │ │ │ │ - var arcxml = axlResp.read(doc); │ │ │ │ - url = this.getUrlOrImage(arcxml.image.output) │ │ │ │ - } │ │ │ │ - return url │ │ │ │ - }, │ │ │ │ - getURLasync: function(bounds, callback, scope) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var axlReq = new OpenLayers.Format.ArcXML(OpenLayers.Util.extend(this.options, { │ │ │ │ - requesttype: "image", │ │ │ │ - envelope: bounds.toArray(), │ │ │ │ - tileSize: this.tileSize │ │ │ │ - })); │ │ │ │ - OpenLayers.Request.POST({ │ │ │ │ - url: this.getFullRequestString(), │ │ │ │ - async: true, │ │ │ │ - data: axlReq.write(), │ │ │ │ - callback: function(req) { │ │ │ │ - var doc = req.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = req.responseText │ │ │ │ - } │ │ │ │ - var axlResp = new OpenLayers.Format.ArcXML; │ │ │ │ - var arcxml = axlResp.read(doc); │ │ │ │ - callback.call(scope, this.getUrlOrImage(arcxml.image.output)) │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - getUrlOrImage: function(output) { │ │ │ │ - var ret = ""; │ │ │ │ - if (output.url) { │ │ │ │ - ret = output.url │ │ │ │ - } else if (output.data) { │ │ │ │ - ret = "data:image/" + output.type + ";base64," + output.data │ │ │ │ + this.root.setAttributeNS(null, "transform", transformString); │ │ │ │ + this.translationParameters = { │ │ │ │ + x: x, │ │ │ │ + y: y │ │ │ │ + }; │ │ │ │ + return true │ │ │ │ } │ │ │ │ - return ret │ │ │ │ }, │ │ │ │ - setLayerQuery: function(id, querydef) { │ │ │ │ - for (var lyr = 0; lyr < this.options.layers.length; lyr++) { │ │ │ │ - if (id == this.options.layers[lyr].id) { │ │ │ │ - this.options.layers[lyr].query = querydef; │ │ │ │ - return │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.options.layers.push({ │ │ │ │ - id: id, │ │ │ │ - visible: true, │ │ │ │ - query: querydef │ │ │ │ - }) │ │ │ │ + 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) │ │ │ │ }, │ │ │ │ - getFeatureInfo: function(geometry, layer, options) { │ │ │ │ - var buffer = options.buffer || 1; │ │ │ │ - var callback = options.callback || function() {}; │ │ │ │ - var scope = options.scope || window; │ │ │ │ - var requestOptions = {}; │ │ │ │ - OpenLayers.Util.extend(requestOptions, this.options); │ │ │ │ - requestOptions.requesttype = "feature"; │ │ │ │ - if (geometry instanceof OpenLayers.LonLat) { │ │ │ │ - requestOptions.polygon = null; │ │ │ │ - requestOptions.envelope = [geometry.lon - buffer, geometry.lat - buffer, geometry.lon + buffer, geometry.lat + buffer] │ │ │ │ - } else if (geometry instanceof OpenLayers.Geometry.Polygon) { │ │ │ │ - requestOptions.envelope = null; │ │ │ │ - requestOptions.polygon = geometry │ │ │ │ - } │ │ │ │ - var arcxml = new OpenLayers.Format.ArcXML(requestOptions); │ │ │ │ - OpenLayers.Util.extend(arcxml.request.get_feature, options); │ │ │ │ - arcxml.request.get_feature.layer = layer.id; │ │ │ │ - if (typeof layer.query.accuracy == "number") { │ │ │ │ - arcxml.request.get_feature.query.accuracy = layer.query.accuracy │ │ │ │ - } else { │ │ │ │ - var mapCenter = this.map.getCenter(); │ │ │ │ - var viewPx = this.map.getViewPortPxFromLonLat(mapCenter); │ │ │ │ - viewPx.x++; │ │ │ │ - var mapOffCenter = this.map.getLonLatFromPixel(viewPx); │ │ │ │ - arcxml.request.get_feature.query.accuracy = mapOffCenter.lon - mapCenter.lon │ │ │ │ - } │ │ │ │ - arcxml.request.get_feature.query.where = layer.query.where; │ │ │ │ - arcxml.request.get_feature.query.spatialfilter.relation = "area_intersection"; │ │ │ │ - OpenLayers.Request.POST({ │ │ │ │ - url: this.getFullRequestString({ │ │ │ │ - CustomService: "Query" │ │ │ │ - }), │ │ │ │ - data: arcxml.write(), │ │ │ │ - callback: function(request) { │ │ │ │ - var response = arcxml.parseResponse(request.responseText); │ │ │ │ - if (!arcxml.iserror()) { │ │ │ │ - callback.call(scope, response.features) │ │ │ │ + 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 { │ │ │ │ - callback.call(scope, null) │ │ │ │ + nodeType = "circle" │ │ │ │ } │ │ │ │ - } │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.ArcIMS(this.name, this.url, this.getOptions()) │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.ArcIMS" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.ArcGIS93Rest = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - DEFAULT_PARAMS: { │ │ │ │ - format: "png" │ │ │ │ + return nodeType │ │ │ │ }, │ │ │ │ - isBaseLayer: true, │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - var newArguments = []; │ │ │ │ - params = OpenLayers.Util.upperCaseObject(params); │ │ │ │ - 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)); │ │ │ │ - if (this.params.TRANSPARENT && this.params.TRANSPARENT.toString().toLowerCase() == "true") { │ │ │ │ - if (options == null || !options.isBaseLayer) { │ │ │ │ - this.isBaseLayer = false │ │ │ │ - } │ │ │ │ - if (this.params.FORMAT == "jpg") { │ │ │ │ - this.params.FORMAT = OpenLayers.Util.alphaHack() ? "gif" : "png" │ │ │ │ + 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); │ │ │ │ + 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) │ │ │ │ } │ │ │ │ } │ │ │ │ - }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.ArcGIS93Rest(this.name, this.url, this.params, this.getOptions()) │ │ │ │ - } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ - }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var projWords = this.projection.getCode().split(":"); │ │ │ │ - var srid = projWords[projWords.length - 1]; │ │ │ │ - var imageSize = this.getImageSize(); │ │ │ │ - var newParams = { │ │ │ │ - BBOX: bounds.toBBOX(), │ │ │ │ - SIZE: imageSize.w + "," + imageSize.h, │ │ │ │ - F: "image", │ │ │ │ - BBOXSR: srid, │ │ │ │ - IMAGESR: srid │ │ │ │ - }; │ │ │ │ - if (this.layerDefs) { │ │ │ │ - var layerDefStrList = []; │ │ │ │ - var layerID; │ │ │ │ - for (layerID in this.layerDefs) { │ │ │ │ - if (this.layerDefs.hasOwnProperty(layerID)) { │ │ │ │ - if (this.layerDefs[layerID]) { │ │ │ │ - layerDefStrList.push(layerID); │ │ │ │ - layerDefStrList.push(":"); │ │ │ │ - layerDefStrList.push(this.layerDefs[layerID]); │ │ │ │ - layerDefStrList.push(";") │ │ │ │ - } │ │ │ │ + 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 : -(.5 * width); │ │ │ │ + var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.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)) { │ │ │ │ + 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; │ │ │ │ + var parent = node.parentNode; │ │ │ │ + var nextSibling = node.nextSibling; │ │ │ │ + if (parent) { │ │ │ │ + parent.removeChild(node) │ │ │ │ + } │ │ │ │ + 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); │ │ │ │ + if (nextSibling) { │ │ │ │ + parent.insertBefore(node, nextSibling) │ │ │ │ + } else if (parent) { │ │ │ │ + parent.appendChild(node) │ │ │ │ } │ │ │ │ + } else { │ │ │ │ + node.setAttributeNS(null, "r", style.pointRadius) │ │ │ │ } │ │ │ │ - if (layerDefStrList.length > 0) { │ │ │ │ - newParams["LAYERDEFS"] = layerDefStrList.join("") │ │ │ │ + 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] + ")") │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ - var requestString = this.getFullRequestString(newParams); │ │ │ │ - return requestString │ │ │ │ - }, │ │ │ │ - setLayerFilter: function(id, queryDef) { │ │ │ │ - if (!this.layerDefs) { │ │ │ │ - this.layerDefs = {} │ │ │ │ - } │ │ │ │ - if (queryDef) { │ │ │ │ - this.layerDefs[id] = queryDef │ │ │ │ + if (options.isFilled) { │ │ │ │ + node.setAttributeNS(null, "fill", style.fillColor); │ │ │ │ + node.setAttributeNS(null, "fill-opacity", style.fillOpacity) │ │ │ │ } else { │ │ │ │ - delete this.layerDefs[id] │ │ │ │ + node.setAttributeNS(null, "fill", "none") │ │ │ │ } │ │ │ │ - }, │ │ │ │ - clearLayerFilter: function(id) { │ │ │ │ - if (id) { │ │ │ │ - delete this.layerDefs[id] │ │ │ │ + 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"); │ │ │ │ + node.setAttributeNS(null, "stroke-linejoin", "round"); │ │ │ │ + style.strokeDashstyle && node.setAttributeNS(null, "stroke-dasharray", this.dashStyle(style, widthFactor)) │ │ │ │ } else { │ │ │ │ - delete this.layerDefs │ │ │ │ + node.setAttributeNS(null, "stroke", "none") │ │ │ │ } │ │ │ │ - }, │ │ │ │ - mergeNewParams: function(newParams) { │ │ │ │ - var upperParams = OpenLayers.Util.upperCaseObject(newParams); │ │ │ │ - var newArguments = [upperParams]; │ │ │ │ - return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, newArguments) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.ArcGIS93Rest" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ - name: "OpenStreetMap", │ │ │ │ - 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"], │ │ │ │ - attribution: "© <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors", │ │ │ │ - sphericalMercator: true, │ │ │ │ - wrapDateLine: true, │ │ │ │ - tileOptions: null, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.OSM(this.name, this.url, this.getOptions()) │ │ │ │ + if (style.pointerEvents) { │ │ │ │ + node.setAttributeNS(null, "pointer-events", style.pointerEvents) │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.OSM" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.KaMap = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - isBaseLayer: true, │ │ │ │ - DEFAULT_PARAMS: { │ │ │ │ - i: "jpeg", │ │ │ │ - map: "" │ │ │ │ - }, │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ - this.params = OpenLayers.Util.applyDefaults(this.params, this.DEFAULT_PARAMS) │ │ │ │ - }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ - var scale = Math.round(this.map.getScale() * 1e4) / 1e4; │ │ │ │ - var pX = Math.round(bounds.left / mapRes); │ │ │ │ - var pY = -Math.round(bounds.top / mapRes); │ │ │ │ - return this.getFullRequestString({ │ │ │ │ - t: pY, │ │ │ │ - l: pX, │ │ │ │ - s: scale │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - calculateGridLayout: function(bounds, origin, resolution) { │ │ │ │ - var tilelon = resolution * this.tileSize.w; │ │ │ │ - var tilelat = resolution * this.tileSize.h; │ │ │ │ - var offsetlon = bounds.left; │ │ │ │ - var tilecol = Math.floor(offsetlon / tilelon) - this.buffer; │ │ │ │ - var offsetlat = bounds.top; │ │ │ │ - var tilerow = Math.floor(offsetlat / tilelat) + this.buffer; │ │ │ │ - return { │ │ │ │ - tilelon: tilelon, │ │ │ │ - tilelat: tilelat, │ │ │ │ - startcol: tilecol, │ │ │ │ - startrow: tilerow │ │ │ │ + if (style.cursor != null) { │ │ │ │ + node.setAttributeNS(null, "cursor", style.cursor) │ │ │ │ } │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - getTileBoundsForGridIndex: function(row, col) { │ │ │ │ - var origin = this.getTileOrigin(); │ │ │ │ - var tileLayout = this.gridLayout; │ │ │ │ - var tilelon = tileLayout.tilelon; │ │ │ │ - var tilelat = tileLayout.tilelat; │ │ │ │ - var minX = (tileLayout.startcol + col) * tilelon; │ │ │ │ - var minY = (tileLayout.startrow - row) * tilelat; │ │ │ │ - return new OpenLayers.Bounds(minX, minY, minX + tilelon, minY + tilelat) │ │ │ │ - }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.KaMap(this.name, this.url, this.params, this.getOptions()) │ │ │ │ + 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, ",") │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - if (this.tileSize != null) { │ │ │ │ - obj.tileSize = this.tileSize.clone() │ │ │ │ + }, │ │ │ │ + createNode: function(type, id) { │ │ │ │ + var node = document.createElementNS(this.xmlns, type); │ │ │ │ + if (id) { │ │ │ │ + node.setAttributeNS(null, "id", id) │ │ │ │ } │ │ │ │ - obj.grid = []; │ │ │ │ - return obj │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - getTileBounds: function(viewPortPx) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var tileMapWidth = resolution * this.tileSize.w; │ │ │ │ - var tileMapHeight = resolution * this.tileSize.h; │ │ │ │ - var mapPoint = this.getLonLatFromViewPortPx(viewPortPx); │ │ │ │ - var tileLeft = tileMapWidth * Math.floor(mapPoint.lon / tileMapWidth); │ │ │ │ - var tileBottom = tileMapHeight * Math.floor(mapPoint.lat / tileMapHeight); │ │ │ │ - return new OpenLayers.Bounds(tileLeft, tileBottom, tileLeft + tileMapWidth, tileBottom + tileMapHeight) │ │ │ │ + nodeTypeCompare: function(node, type) { │ │ │ │ + return type == node.nodeName │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.KaMap" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.KaMapCache = OpenLayers.Class(OpenLayers.Layer.KaMap, { │ │ │ │ - IMAGE_EXTENSIONS: { │ │ │ │ - jpeg: "jpg", │ │ │ │ - gif: "gif", │ │ │ │ - png: "png", │ │ │ │ - png8: "png", │ │ │ │ - png24: "png", │ │ │ │ - dithered: "png" │ │ │ │ + createRenderRoot: function() { │ │ │ │ + var svg = this.nodeFactory(this.container.id + "_svgRoot", "svg"); │ │ │ │ + svg.style.display = "block"; │ │ │ │ + return svg │ │ │ │ }, │ │ │ │ - DEFAULT_FORMAT: "jpeg", │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - OpenLayers.Layer.KaMap.prototype.initialize.apply(this, arguments); │ │ │ │ - this.extension = this.IMAGE_EXTENSIONS[this.params.i.toLowerCase() || this.DEFAULT_FORMAT] │ │ │ │ + createRoot: function(suffix) { │ │ │ │ + return this.nodeFactory(this.container.id + suffix, "g") │ │ │ │ }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ - var scale = Math.round(this.map.getScale() * 1e4) / 1e4; │ │ │ │ - var pX = Math.round(bounds.left / mapRes); │ │ │ │ - var pY = -Math.round(bounds.top / mapRes); │ │ │ │ - var metaX = Math.floor(pX / this.tileSize.w / this.params.metaTileSize.w) * this.tileSize.w * this.params.metaTileSize.w; │ │ │ │ - var metaY = Math.floor(pY / this.tileSize.h / this.params.metaTileSize.h) * this.tileSize.h * this.params.metaTileSize.h; │ │ │ │ - var components = ["/", this.params.map, "/", scale, "/", this.params.g.replace(/\s/g, "_"), "/def/t", metaY, "/l", metaX, "/t", pY, "l", pX, ".", this.extension]; │ │ │ │ - var url = this.url; │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ - url = this.selectUrl(components.join(""), url) │ │ │ │ - } │ │ │ │ - return url + components.join("") │ │ │ │ + createDefs: function() { │ │ │ │ + var defs = this.nodeFactory(this.container.id + "_defs", "defs"); │ │ │ │ + this.rendererRoot.appendChild(defs); │ │ │ │ + return defs │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.KaMapCache" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.Image = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ - isBaseLayer: true, │ │ │ │ - url: null, │ │ │ │ - extent: null, │ │ │ │ - size: null, │ │ │ │ - tile: null, │ │ │ │ - aspectRatio: null, │ │ │ │ - initialize: function(name, url, extent, size, options) { │ │ │ │ - this.url = url; │ │ │ │ - this.extent = extent; │ │ │ │ - this.maxExtent = extent; │ │ │ │ - this.size = size; │ │ │ │ - OpenLayers.Layer.prototype.initialize.apply(this, [name, options]); │ │ │ │ - this.aspectRatio = this.extent.getHeight() / this.size.h / (this.extent.getWidth() / this.size.w) │ │ │ │ + drawPoint: function(node, geometry) { │ │ │ │ + return this.drawCircle(node, geometry, 1) │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.tile) { │ │ │ │ - this.removeTileMonitoringHooks(this.tile); │ │ │ │ - this.tile.destroy(); │ │ │ │ - this.tile = null │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - OpenLayers.Layer.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.Image(this.name, this.url, this.extent, this.size, this.getOptions()) │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ }, │ │ │ │ - setMap: function(map) { │ │ │ │ - if (this.options.maxResolution == null) { │ │ │ │ - this.options.maxResolution = this.aspectRatio * this.extent.getWidth() / this.size.w │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - OpenLayers.Layer.prototype.setMap.apply(this, arguments) │ │ │ │ }, │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ - var firstRendering = this.tile == null; │ │ │ │ - if (zoomChanged || firstRendering) { │ │ │ │ - this.setTileSize(); │ │ │ │ - var ulPx = this.map.getLayerPxFromLonLat({ │ │ │ │ - lon: this.extent.left, │ │ │ │ - lat: this.extent.top │ │ │ │ - }); │ │ │ │ - if (firstRendering) { │ │ │ │ - this.tile = new OpenLayers.Tile.Image(this, ulPx, this.extent, null, this.tileSize); │ │ │ │ - this.addTileMonitoringHooks(this.tile) │ │ │ │ + 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 { │ │ │ │ - this.tile.size = this.tileSize.clone(); │ │ │ │ - this.tile.position = ulPx.clone() │ │ │ │ + draw = false │ │ │ │ } │ │ │ │ - this.tile.draw() │ │ │ │ + } │ │ │ │ + d += " z"; │ │ │ │ + if (draw) { │ │ │ │ + node.setAttributeNS(null, "d", d); │ │ │ │ + node.setAttributeNS(null, "fill-rule", "evenodd"); │ │ │ │ + return complete ? node : null │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ } │ │ │ │ }, │ │ │ │ - setTileSize: function() { │ │ │ │ - var tileWidth = this.extent.getWidth() / this.map.getResolution(); │ │ │ │ - var tileHeight = this.extent.getHeight() / this.map.getResolution(); │ │ │ │ - this.tileSize = new OpenLayers.Size(tileWidth, tileHeight) │ │ │ │ - }, │ │ │ │ - addTileMonitoringHooks: function(tile) { │ │ │ │ - tile.onLoadStart = function() { │ │ │ │ - this.events.triggerEvent("loadstart") │ │ │ │ - }; │ │ │ │ - tile.events.register("loadstart", this, tile.onLoadStart); │ │ │ │ - tile.onLoadEnd = function() { │ │ │ │ - this.events.triggerEvent("loadend") │ │ │ │ - }; │ │ │ │ - tile.events.register("loadend", this, tile.onLoadEnd); │ │ │ │ - tile.events.register("unload", this, tile.onLoadEnd) │ │ │ │ - }, │ │ │ │ - removeTileMonitoringHooks: function(tile) { │ │ │ │ - tile.unload(); │ │ │ │ - tile.events.un({ │ │ │ │ - loadstart: tile.onLoadStart, │ │ │ │ - loadend: tile.onLoadEnd, │ │ │ │ - unload: tile.onLoadEnd, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - setUrl: function(newUrl) { │ │ │ │ - this.url = newUrl; │ │ │ │ - this.tile.draw() │ │ │ │ - }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - return this.url │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Image" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.WMTS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - isBaseLayer: true, │ │ │ │ - version: "1.0.0", │ │ │ │ - requestEncoding: "KVP", │ │ │ │ - url: null, │ │ │ │ - layer: null, │ │ │ │ - matrixSet: null, │ │ │ │ - style: null, │ │ │ │ - format: "image/jpeg", │ │ │ │ - tileOrigin: null, │ │ │ │ - tileFullExtent: null, │ │ │ │ - formatSuffix: null, │ │ │ │ - matrixIds: null, │ │ │ │ - dimensions: null, │ │ │ │ - params: null, │ │ │ │ - zoomOffset: 0, │ │ │ │ - serverResolutions: null, │ │ │ │ - formatSuffixMap: { │ │ │ │ - "image/png": "png", │ │ │ │ - "image/png8": "png", │ │ │ │ - "image/png24": "png", │ │ │ │ - "image/png32": "png", │ │ │ │ - png: "png", │ │ │ │ - "image/jpeg": "jpg", │ │ │ │ - "image/jpg": "jpg", │ │ │ │ - jpeg: "jpg", │ │ │ │ - jpg: "jpg" │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ }, │ │ │ │ - matrix: null, │ │ │ │ - initialize: function(config) { │ │ │ │ - var required = { │ │ │ │ - url: true, │ │ │ │ - layer: true, │ │ │ │ - style: true, │ │ │ │ - matrixSet: true │ │ │ │ - }; │ │ │ │ - for (var prop in required) { │ │ │ │ - if (!(prop in config)) { │ │ │ │ - throw new Error("Missing property '" + prop + "' in layer configuration.") │ │ │ │ + drawText: function(featureId, style, location) { │ │ │ │ + var drawOutline = !!style.labelOutlineWidth; │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - config.params = OpenLayers.Util.upperCaseObject(config.params); │ │ │ │ - var args = [config.name, config.url, config.params, config]; │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, args); │ │ │ │ - if (!this.formatSuffix) { │ │ │ │ - this.formatSuffix = this.formatSuffixMap[this.format] || this.format.split("/").pop() │ │ │ │ + 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 (this.matrixIds) { │ │ │ │ - var len = this.matrixIds.length; │ │ │ │ - if (len && typeof this.matrixIds[0] === "string") { │ │ │ │ - var ids = this.matrixIds; │ │ │ │ - this.matrixIds = new Array(len); │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ - this.matrixIds[i] = { │ │ │ │ - identifier: ids[i] │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ + if (style.fontStrokeColor) { │ │ │ │ + label.setAttributeNS(null, "stroke", style.fontStrokeColor) │ │ │ │ } │ │ │ │ - }, │ │ │ │ - setMap: function() { │ │ │ │ - OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - updateMatrixProperties: function() { │ │ │ │ - this.matrix = this.getMatrix(); │ │ │ │ - if (this.matrix) { │ │ │ │ - if (this.matrix.topLeftCorner) { │ │ │ │ - this.tileOrigin = this.matrix.topLeftCorner │ │ │ │ - } │ │ │ │ - if (this.matrix.tileWidth && this.matrix.tileHeight) { │ │ │ │ - this.tileSize = new OpenLayers.Size(this.matrix.tileWidth, this.matrix.tileHeight) │ │ │ │ - } │ │ │ │ - if (!this.tileOrigin) { │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat(this.maxExtent.left, this.maxExtent.top) │ │ │ │ - } │ │ │ │ - if (!this.tileFullExtent) { │ │ │ │ - this.tileFullExtent = this.maxExtent │ │ │ │ - } │ │ │ │ + if (style.fontStrokeWidth) { │ │ │ │ + label.setAttributeNS(null, "stroke-width", style.fontStrokeWidth) │ │ │ │ } │ │ │ │ - }, │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ - if (zoomChanged || !this.matrix) { │ │ │ │ - this.updateMatrixProperties() │ │ │ │ + if (style.fontOpacity) { │ │ │ │ + label.setAttributeNS(null, "opacity", style.fontOpacity) │ │ │ │ } │ │ │ │ - return OpenLayers.Layer.Grid.prototype.moveTo.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.WMTS(this.options) │ │ │ │ + if (style.fontFamily) { │ │ │ │ + label.setAttributeNS(null, "font-family", style.fontFamily) │ │ │ │ } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ - }, │ │ │ │ - getIdentifier: function() { │ │ │ │ - return this.getServerZoom() │ │ │ │ - }, │ │ │ │ - getMatrix: function() { │ │ │ │ - var matrix; │ │ │ │ - if (!this.matrixIds || this.matrixIds.length === 0) { │ │ │ │ - matrix = { │ │ │ │ - identifier: this.getIdentifier() │ │ │ │ - } │ │ │ │ + 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 { │ │ │ │ - if ("scaleDenominator" in this.matrixIds[0]) { │ │ │ │ - var denom = OpenLayers.METERS_PER_INCH * OpenLayers.INCHES_PER_UNIT[this.units] * this.getServerResolution() / 28e-5; │ │ │ │ - var diff = Number.POSITIVE_INFINITY; │ │ │ │ - var delta; │ │ │ │ - for (var i = 0, ii = this.matrixIds.length; i < ii; ++i) { │ │ │ │ - delta = Math.abs(1 - this.matrixIds[i].scaleDenominator / denom); │ │ │ │ - if (delta < diff) { │ │ │ │ - diff = delta; │ │ │ │ - matrix = this.matrixIds[i] │ │ │ │ - } │ │ │ │ + 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 { │ │ │ │ - matrix = this.matrixIds[this.getIdentifier()] │ │ │ │ + tspan.setAttribute("dy", "1em") │ │ │ │ + } │ │ │ │ + tspan.textContent = labelRows[i] === "" ? " " : labelRows[i]; │ │ │ │ + if (!tspan.parentNode) { │ │ │ │ + label.appendChild(tspan) │ │ │ │ } │ │ │ │ } │ │ │ │ - return matrix │ │ │ │ - }, │ │ │ │ - getTileInfo: function(loc) { │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ - var fx = (loc.lon - this.tileOrigin.lon) / (res * this.tileSize.w); │ │ │ │ - var fy = (this.tileOrigin.lat - loc.lat) / (res * this.tileSize.h); │ │ │ │ - var col = Math.floor(fx); │ │ │ │ - var row = Math.floor(fy); │ │ │ │ - return { │ │ │ │ - col: col, │ │ │ │ - row: row, │ │ │ │ - i: Math.floor((fx - col) * this.tileSize.w), │ │ │ │ - j: Math.floor((fy - row) * this.tileSize.h) │ │ │ │ + if (!label.parentNode) { │ │ │ │ + this.textRoot.appendChild(label) │ │ │ │ } │ │ │ │ }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ - var url = ""; │ │ │ │ - if (!this.tileFullExtent || this.tileFullExtent.intersectsBounds(bounds)) { │ │ │ │ - var center = bounds.getCenterLonLat(); │ │ │ │ - var info = this.getTileInfo(center); │ │ │ │ - var matrixId = this.matrix.identifier; │ │ │ │ - var dimensions = this.dimensions, │ │ │ │ - params; │ │ │ │ - if (OpenLayers.Util.isArray(this.url)) { │ │ │ │ - url = this.selectUrl([this.version, this.style, this.matrixSet, this.matrix.identifier, info.row, info.col].join(","), this.url) │ │ │ │ + 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 { │ │ │ │ - url = this.url │ │ │ │ - } │ │ │ │ - if (this.requestEncoding.toUpperCase() === "REST") { │ │ │ │ - params = this.params; │ │ │ │ - if (url.indexOf("{") !== -1) { │ │ │ │ - var template = url.replace(/\{/g, "${"); │ │ │ │ - var context = { │ │ │ │ - style: this.style, │ │ │ │ - Style: this.style, │ │ │ │ - TileMatrixSet: this.matrixSet, │ │ │ │ - TileMatrix: this.matrix.identifier, │ │ │ │ - TileRow: info.row, │ │ │ │ - TileCol: info.col │ │ │ │ - }; │ │ │ │ - if (dimensions) { │ │ │ │ - var dimension, i; │ │ │ │ - for (i = dimensions.length - 1; i >= 0; --i) { │ │ │ │ - dimension = dimensions[i]; │ │ │ │ - context[dimension] = params[dimension.toUpperCase()] │ │ │ │ - } │ │ │ │ - } │ │ │ │ - url = OpenLayers.String.format(template, context) │ │ │ │ - } else { │ │ │ │ - var path = this.version + "/" + this.layer + "/" + this.style + "/"; │ │ │ │ - if (dimensions) { │ │ │ │ - for (var i = 0; i < dimensions.length; i++) { │ │ │ │ - if (params[dimensions[i]]) { │ │ │ │ - path = path + params[dimensions[i]] + "/" │ │ │ │ - } │ │ │ │ - } │ │ │ │ + if (i > 0) { │ │ │ │ + if (this.getShortString(components[i - 1])) { │ │ │ │ + strings.push(this.clipLine(components[i], components[i - 1])) │ │ │ │ } │ │ │ │ - path = path + this.matrixSet + "/" + this.matrix.identifier + "/" + info.row + "/" + info.col + "." + this.formatSuffix; │ │ │ │ - if (!url.match(/\/$/)) { │ │ │ │ - url = url + "/" │ │ │ │ + } │ │ │ │ + if (i < len - 1) { │ │ │ │ + if (this.getShortString(components[i + 1])) { │ │ │ │ + strings.push(this.clipLine(components[i], components[i + 1])) │ │ │ │ } │ │ │ │ - url = url + path │ │ │ │ } │ │ │ │ - } else if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ - params = { │ │ │ │ - SERVICE: "WMTS", │ │ │ │ - REQUEST: "GetTile", │ │ │ │ - VERSION: this.version, │ │ │ │ - LAYER: this.layer, │ │ │ │ - STYLE: this.style, │ │ │ │ - TILEMATRIXSET: this.matrixSet, │ │ │ │ - TILEMATRIX: this.matrix.identifier, │ │ │ │ - TILEROW: info.row, │ │ │ │ - TILECOL: info.col, │ │ │ │ - FORMAT: this.format │ │ │ │ - }; │ │ │ │ - url = OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this, [params]) │ │ │ │ + complete = false │ │ │ │ } │ │ │ │ } │ │ │ │ - return url │ │ │ │ - }, │ │ │ │ - mergeNewParams: function(newParams) { │ │ │ │ - if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ - return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, [OpenLayers.Util.upperCaseObject(newParams)]) │ │ │ │ + return { │ │ │ │ + path: strings.join(separator || ","), │ │ │ │ + complete: complete │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.WMTS" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ - isBaseLayer: true, │ │ │ │ - useHttpTile: false, │ │ │ │ - singleTile: false, │ │ │ │ - useOverlay: false, │ │ │ │ - useAsyncOverlay: true, │ │ │ │ - TILE_PARAMS: { │ │ │ │ - operation: "GETTILEIMAGE", │ │ │ │ - version: "1.2.0" │ │ │ │ + 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 │ │ │ │ }, │ │ │ │ - SINGLE_TILE_PARAMS: { │ │ │ │ - operation: "GETMAPIMAGE", │ │ │ │ - format: "PNG", │ │ │ │ - locale: "en", │ │ │ │ - clip: "1", │ │ │ │ - version: "1.0.0" │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ }, │ │ │ │ - OVERLAY_PARAMS: { │ │ │ │ - operation: "GETDYNAMICMAPOVERLAYIMAGE", │ │ │ │ - format: "PNG", │ │ │ │ - locale: "en", │ │ │ │ - clip: "1", │ │ │ │ - version: "2.0.0" │ │ │ │ + getPosition: function(node) { │ │ │ │ + return { │ │ │ │ + x: parseFloat(node.getAttributeNS(null, "cx")), │ │ │ │ + y: parseFloat(node.getAttributeNS(null, "cy")) │ │ │ │ + } │ │ │ │ }, │ │ │ │ - FOLDER_PARAMS: { │ │ │ │ - tileColumnsPerFolder: 30, │ │ │ │ - tileRowsPerFolder: 30, │ │ │ │ - format: "png", │ │ │ │ - querystring: null │ │ │ │ + importSymbol: function(graphicName) { │ │ │ │ + if (!this.defs) { │ │ │ │ + this.defs = this.createDefs() │ │ │ │ + } │ │ │ │ + var id = this.container.id + "-" + graphicName; │ │ │ │ + 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(); │ │ │ │ + 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 │ │ │ │ }, │ │ │ │ - defaultSize: new OpenLayers.Size(300, 300), │ │ │ │ - tileOriginCorner: "tl", │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ - if (options == null || options.isBaseLayer == null) { │ │ │ │ - this.isBaseLayer = this.transparent != "true" && this.transparent != true │ │ │ │ + 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 │ │ │ │ } │ │ │ │ - if (options && options.useOverlay != null) { │ │ │ │ - this.useOverlay = options.useOverlay │ │ │ │ + return featureId │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Renderer.SVG" │ │ │ │ +}); │ │ │ │ +OpenLayers.Renderer.SVG.LABEL_ALIGN = { │ │ │ │ + l: "start", │ │ │ │ + r: "end", │ │ │ │ + b: "bottom", │ │ │ │ + t: "hanging" │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.SVG.LABEL_VSHIFT = { │ │ │ │ + t: "-70%", │ │ │ │ + b: "0" │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.SVG.LABEL_VFACTOR = { │ │ │ │ + t: 0, │ │ │ │ + b: -1 │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.SVG.preventDefault = function(e) { │ │ │ │ + OpenLayers.Event.preventDefault(e) │ │ │ │ +}; │ │ │ │ +OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ + xmlns: "urn:schemas-microsoft-com:vml", │ │ │ │ + symbolCache: {}, │ │ │ │ + offset: null, │ │ │ │ + initialize: function(containerID) { │ │ │ │ + if (!this.supported()) { │ │ │ │ + return │ │ │ │ } │ │ │ │ - if (this.singleTile) { │ │ │ │ - if (this.useOverlay) { │ │ │ │ - OpenLayers.Util.applyDefaults(this.params, this.OVERLAY_PARAMS); │ │ │ │ - if (!this.useAsyncOverlay) { │ │ │ │ - this.params.version = "1.0.0" │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Util.applyDefaults(this.params, this.SINGLE_TILE_PARAMS) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (this.useHttpTile) { │ │ │ │ - OpenLayers.Util.applyDefaults(this.params, this.FOLDER_PARAMS) │ │ │ │ - } else { │ │ │ │ - OpenLayers.Util.applyDefaults(this.params, this.TILE_PARAMS) │ │ │ │ + if (!document.namespaces.olv) { │ │ │ │ + document.namespaces.add("olv", this.xmlns); │ │ │ │ + var style = document.createStyleSheet(); │ │ │ │ + var shapes = ["shape", "rect", "oval", "fill", "stroke", "imagedata", "group", "textbox"]; │ │ │ │ + for (var i = 0, len = shapes.length; i < len; i++) { │ │ │ │ + style.addRule("olv\\:" + shapes[i], "behavior: url(#default#VML); " + "position: absolute; display: inline-block;") │ │ │ │ } │ │ │ │ - this.setTileSize(this.defaultSize) │ │ │ │ } │ │ │ │ + OpenLayers.Renderer.Elements.prototype.initialize.apply(this, arguments) │ │ │ │ }, │ │ │ │ - clone: function(obj) { │ │ │ │ - if (obj == null) { │ │ │ │ - obj = new OpenLayers.Layer.MapGuide(this.name, this.url, this.params, this.getOptions()) │ │ │ │ - } │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ - return obj │ │ │ │ + supported: function() { │ │ │ │ + return !!document.namespaces │ │ │ │ }, │ │ │ │ - getURL: function(bounds) { │ │ │ │ - var url; │ │ │ │ - var center = bounds.getCenterLonLat(); │ │ │ │ - var mapSize = this.map.getSize(); │ │ │ │ - if (this.singleTile) { │ │ │ │ - var params = { │ │ │ │ - setdisplaydpi: OpenLayers.DOTS_PER_INCH, │ │ │ │ - setdisplayheight: mapSize.h * this.ratio, │ │ │ │ - setdisplaywidth: mapSize.w * this.ratio, │ │ │ │ - setviewcenterx: center.lon, │ │ │ │ - setviewcentery: center.lat, │ │ │ │ - setviewscale: this.map.getScale() │ │ │ │ + setExtent: function(extent, resolutionChanged) { │ │ │ │ + var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var left = extent.left / resolution | 0; │ │ │ │ + var top = extent.top / resolution - this.size.h | 0; │ │ │ │ + if (resolutionChanged || !this.offset) { │ │ │ │ + this.offset = { │ │ │ │ + x: left, │ │ │ │ + y: top │ │ │ │ }; │ │ │ │ - if (this.useOverlay && !this.useAsyncOverlay) { │ │ │ │ - var getVisParams = {}; │ │ │ │ - getVisParams = OpenLayers.Util.extend(getVisParams, params); │ │ │ │ - getVisParams.operation = "GETVISIBLEMAPEXTENT"; │ │ │ │ - getVisParams.version = "1.0.0"; │ │ │ │ - getVisParams.session = this.params.session; │ │ │ │ - getVisParams.mapName = this.params.mapName; │ │ │ │ - getVisParams.format = "text/xml"; │ │ │ │ - url = this.getFullRequestString(getVisParams); │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ - url: url, │ │ │ │ - async: false │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - url = this.getFullRequestString(params) │ │ │ │ + left = 0; │ │ │ │ + top = 0 │ │ │ │ } else { │ │ │ │ - var currentRes = this.map.getResolution(); │ │ │ │ - var colidx = Math.floor((bounds.left - this.maxExtent.left) / currentRes); │ │ │ │ - colidx = Math.round(colidx / this.tileSize.w); │ │ │ │ - var rowidx = Math.floor((this.maxExtent.top - bounds.top) / currentRes); │ │ │ │ - rowidx = Math.round(rowidx / this.tileSize.h); │ │ │ │ - if (this.useHttpTile) { │ │ │ │ - url = this.getImageFilePath({ │ │ │ │ - tilecol: colidx, │ │ │ │ - tilerow: rowidx, │ │ │ │ - scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ - }) │ │ │ │ - } else { │ │ │ │ - url = this.getFullRequestString({ │ │ │ │ - tilecol: colidx, │ │ │ │ - tilerow: rowidx, │ │ │ │ - scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ + left = left - this.offset.x; │ │ │ │ + top = top - this.offset.y │ │ │ │ } │ │ │ │ - return url │ │ │ │ - }, │ │ │ │ - getFullRequestString: function(newParams, altUrl) { │ │ │ │ - var url = altUrl == null ? this.url : altUrl; │ │ │ │ - if (typeof url == "object") { │ │ │ │ - url = url[Math.floor(Math.random() * url.length)] │ │ │ │ + var org = left - this.xOffset + " " + top; │ │ │ │ + this.root.coordorigin = org; │ │ │ │ + var roots = [this.root, this.vectorRoot, this.textRoot]; │ │ │ │ + var root; │ │ │ │ + for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ + root = roots[i]; │ │ │ │ + var size = this.size.w + " " + this.size.h; │ │ │ │ + root.coordsize = size │ │ │ │ } │ │ │ │ - var requestString = url; │ │ │ │ - var allParams = OpenLayers.Util.extend({}, this.params); │ │ │ │ - allParams = OpenLayers.Util.extend(allParams, newParams); │ │ │ │ - var urlParams = OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url)); │ │ │ │ - for (var key in allParams) { │ │ │ │ - if (key.toUpperCase() in urlParams) { │ │ │ │ - delete allParams[key] │ │ │ │ - } │ │ │ │ + this.root.style.flip = "y"; │ │ │ │ + return coordSysUnchanged │ │ │ │ + }, │ │ │ │ + setSize: function(size) { │ │ │ │ + OpenLayers.Renderer.prototype.setSize.apply(this, arguments); │ │ │ │ + var roots = [this.rendererRoot, this.root, this.vectorRoot, this.textRoot]; │ │ │ │ + var w = this.size.w + "px"; │ │ │ │ + var h = this.size.h + "px"; │ │ │ │ + var root; │ │ │ │ + for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ + root = roots[i]; │ │ │ │ + root.style.width = w; │ │ │ │ + root.style.height = h │ │ │ │ } │ │ │ │ - var paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ - paramsString = paramsString.replace(/,/g, "+"); │ │ │ │ - if (paramsString != "") { │ │ │ │ - var lastServerChar = url.charAt(url.length - 1); │ │ │ │ - if (lastServerChar == "&" || lastServerChar == "?") { │ │ │ │ - requestString += paramsString │ │ │ │ - } else { │ │ │ │ - if (url.indexOf("?") == -1) { │ │ │ │ - requestString += "?" + paramsString │ │ │ │ + }, │ │ │ │ + getNodeType: function(geometry, style) { │ │ │ │ + var nodeType = null; │ │ │ │ + switch (geometry.CLASS_NAME) { │ │ │ │ + case "OpenLayers.Geometry.Point": │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + nodeType = "olv:rect" │ │ │ │ + } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ + nodeType = "olv:shape" │ │ │ │ } else { │ │ │ │ - requestString += "&" + paramsString │ │ │ │ + nodeType = "olv:oval" │ │ │ │ } │ │ │ │ - } │ │ │ │ + break; │ │ │ │ + case "OpenLayers.Geometry.Rectangle": │ │ │ │ + nodeType = "olv:rect"; │ │ │ │ + break; │ │ │ │ + case "OpenLayers.Geometry.LineString": │ │ │ │ + case "OpenLayers.Geometry.LinearRing": │ │ │ │ + case "OpenLayers.Geometry.Polygon": │ │ │ │ + case "OpenLayers.Geometry.Curve": │ │ │ │ + nodeType = "olv:shape"; │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + break │ │ │ │ } │ │ │ │ - return requestString │ │ │ │ + return nodeType │ │ │ │ }, │ │ │ │ - getImageFilePath: function(newParams, altUrl) { │ │ │ │ - var url = altUrl == null ? this.url : altUrl; │ │ │ │ - if (typeof url == "object") { │ │ │ │ - url = url[Math.floor(Math.random() * url.length)] │ │ │ │ + setStyle: function(node, style, options, geometry) { │ │ │ │ + style = style || node._style; │ │ │ │ + options = options || node._options; │ │ │ │ + var fillColor = style.fillColor; │ │ │ │ + var title = style.title || style.graphicTitle; │ │ │ │ + if (title) { │ │ │ │ + node.title = title │ │ │ │ } │ │ │ │ - var requestString = url; │ │ │ │ - var tileRowGroup = ""; │ │ │ │ - var tileColGroup = ""; │ │ │ │ - if (newParams.tilerow < 0) { │ │ │ │ - tileRowGroup = "-" │ │ │ │ + if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + options.isFilled = true; │ │ │ │ + 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 resolution = this.getResolution(); │ │ │ │ + var xOffset = style.graphicXOffset != undefined ? style.graphicXOffset : -(.5 * width); │ │ │ │ + var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.5 * height); │ │ │ │ + node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x + xOffset | 0) + "px"; │ │ │ │ + node.style.top = (geometry.y / resolution - this.offset.y - (yOffset + height) | 0) + "px"; │ │ │ │ + node.style.width = width + "px"; │ │ │ │ + node.style.height = height + "px"; │ │ │ │ + node.style.flip = "y"; │ │ │ │ + fillColor = "none"; │ │ │ │ + options.isStroked = false │ │ │ │ + } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ + var cache = this.importSymbol(style.graphicName); │ │ │ │ + node.path = cache.path; │ │ │ │ + node.coordorigin = cache.left + "," + cache.bottom; │ │ │ │ + var size = cache.size; │ │ │ │ + node.coordsize = size + "," + size; │ │ │ │ + this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ + node.style.flip = "y" │ │ │ │ + } else { │ │ │ │ + this.drawCircle(node, geometry, style.pointRadius) │ │ │ │ + } │ │ │ │ } │ │ │ │ - if (newParams.tilerow == 0) { │ │ │ │ - tileRowGroup += "0" │ │ │ │ + if (options.isFilled) { │ │ │ │ + node.fillcolor = fillColor │ │ │ │ } else { │ │ │ │ - tileRowGroup += Math.floor(Math.abs(newParams.tilerow / this.params.tileRowsPerFolder)) * this.params.tileRowsPerFolder │ │ │ │ - } │ │ │ │ - if (newParams.tilecol < 0) { │ │ │ │ - tileColGroup = "-" │ │ │ │ + node.filled = "false" │ │ │ │ } │ │ │ │ - if (newParams.tilecol == 0) { │ │ │ │ - tileColGroup += "0" │ │ │ │ + var fills = node.getElementsByTagName("fill"); │ │ │ │ + var fill = fills.length == 0 ? null : fills[0]; │ │ │ │ + if (!options.isFilled) { │ │ │ │ + if (fill) { │ │ │ │ + node.removeChild(fill) │ │ │ │ + } │ │ │ │ } else { │ │ │ │ - tileColGroup += Math.floor(Math.abs(newParams.tilecol / this.params.tileColumnsPerFolder)) * this.params.tileColumnsPerFolder │ │ │ │ - } │ │ │ │ - var tilePath = "/S" + Math.floor(newParams.scaleindex) + "/" + this.params.basemaplayergroupname + "/R" + tileRowGroup + "/C" + tileColGroup + "/" + newParams.tilerow % this.params.tileRowsPerFolder + "_" + newParams.tilecol % this.params.tileColumnsPerFolder + "." + this.params.format; │ │ │ │ - if (this.params.querystring) { │ │ │ │ - tilePath += "?" + this.params.querystring │ │ │ │ - } │ │ │ │ - requestString += tilePath; │ │ │ │ - return requestString │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.MapGuide" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ - displayInLayerSwitcher: false, │ │ │ │ - layers: null, │ │ │ │ - display: function() {}, │ │ │ │ - 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 │ │ │ │ + if (!fill) { │ │ │ │ + fill = this.createNode("olv:fill", node.id + "_fill") │ │ │ │ + } │ │ │ │ + fill.opacity = style.fillOpacity; │ │ │ │ + if (node._geometryClass === "OpenLayers.Geometry.Point" && style.externalGraphic) { │ │ │ │ + if (style.graphicOpacity) { │ │ │ │ + fill.opacity = style.graphicOpacity │ │ │ │ + } │ │ │ │ + fill.src = style.externalGraphic; │ │ │ │ + fill.type = "frame"; │ │ │ │ + if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ + fill.aspect = "atmost" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (fill.parentNode != node) { │ │ │ │ + node.appendChild(fill) │ │ │ │ } │ │ │ │ } │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ - this.collectRoots(); │ │ │ │ - map.events.register("changelayer", this, this.handleChangeLayer) │ │ │ │ - }, │ │ │ │ - removeMap: function(map) { │ │ │ │ - map.events.unregister("changelayer", this, this.handleChangeLayer); │ │ │ │ - this.resetRoots(); │ │ │ │ - OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - collectRoots: function() { │ │ │ │ - var layer; │ │ │ │ - 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) │ │ │ │ + var rotation = style.rotation; │ │ │ │ + if (rotation !== undefined || node._rotation !== undefined) { │ │ │ │ + node._rotation = rotation; │ │ │ │ + if (style.externalGraphic) { │ │ │ │ + this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ + fill.opacity = 0 │ │ │ │ + } else if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ + node.style.rotation = rotation || 0 │ │ │ │ } │ │ │ │ } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ + var strokes = node.getElementsByTagName("stroke"); │ │ │ │ + var stroke = strokes.length == 0 ? null : strokes[0]; │ │ │ │ + if (!options.isStroked) { │ │ │ │ + node.stroked = false; │ │ │ │ + if (stroke) { │ │ │ │ + stroke.on = false │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (!stroke) { │ │ │ │ + stroke = this.createNode("olv:stroke", node.id + "_stroke"); │ │ │ │ + node.appendChild(stroke) │ │ │ │ + } │ │ │ │ + stroke.on = true; │ │ │ │ + stroke.color = style.strokeColor; │ │ │ │ + stroke.weight = style.strokeWidth + "px"; │ │ │ │ + stroke.opacity = style.strokeOpacity; │ │ │ │ + stroke.endcap = style.strokeLinecap == "butt" ? "flat" : style.strokeLinecap || "round"; │ │ │ │ + if (style.strokeDashstyle) { │ │ │ │ + stroke.dashstyle = this.dashStyle(style) │ │ │ │ } │ │ │ │ } │ │ │ │ - }, │ │ │ │ - handleChangeLayer: function(evt) { │ │ │ │ - var layer = evt.layer; │ │ │ │ - if (evt.property == "order" && OpenLayers.Util.indexOf(this.layers, layer) != -1) { │ │ │ │ - this.resetRoots(); │ │ │ │ - this.collectRoots() │ │ │ │ + if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ + node.style.cursor = style.cursor │ │ │ │ } │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Vector.RootContainer" │ │ │ │ -}); │ │ │ │ -OpenLayers.Layer.Google.v3 = { │ │ │ │ - DEFAULTS: { │ │ │ │ - sphericalMercator: true, │ │ │ │ - projection: "EPSG:900913" │ │ │ │ + graphicRotate: function(node, xOffset, yOffset, style) { │ │ │ │ + var style = style || node._style; │ │ │ │ + var rotation = style.rotation || 0; │ │ │ │ + var aspectRatio, size; │ │ │ │ + if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ + var img = new Image; │ │ │ │ + img.onreadystatechange = OpenLayers.Function.bind(function() { │ │ │ │ + if (img.readyState == "complete" || img.readyState == "interactive") { │ │ │ │ + aspectRatio = img.width / img.height; │ │ │ │ + size = Math.max(style.pointRadius * 2, style.graphicWidth || 0, style.graphicHeight || 0); │ │ │ │ + xOffset = xOffset * aspectRatio; │ │ │ │ + style.graphicWidth = size * aspectRatio; │ │ │ │ + style.graphicHeight = size; │ │ │ │ + this.graphicRotate(node, xOffset, yOffset, style) │ │ │ │ + } │ │ │ │ + }, this); │ │ │ │ + img.src = style.externalGraphic; │ │ │ │ + return │ │ │ │ + } else { │ │ │ │ + size = Math.max(style.graphicWidth, style.graphicHeight); │ │ │ │ + aspectRatio = style.graphicWidth / style.graphicHeight │ │ │ │ + } │ │ │ │ + var width = Math.round(style.graphicWidth || size * aspectRatio); │ │ │ │ + var height = Math.round(style.graphicHeight || size); │ │ │ │ + node.style.width = width + "px"; │ │ │ │ + node.style.height = height + "px"; │ │ │ │ + var image = document.getElementById(node.id + "_image"); │ │ │ │ + if (!image) { │ │ │ │ + image = this.createNode("olv:imagedata", node.id + "_image"); │ │ │ │ + node.appendChild(image) │ │ │ │ + } │ │ │ │ + image.style.width = width + "px"; │ │ │ │ + image.style.height = height + "px"; │ │ │ │ + image.src = style.externalGraphic; │ │ │ │ + image.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + "src='', sizingMethod='scale')"; │ │ │ │ + var rot = rotation * Math.PI / 180; │ │ │ │ + var sintheta = Math.sin(rot); │ │ │ │ + var costheta = Math.cos(rot); │ │ │ │ + var filter = "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta + ",M12=" + -sintheta + ",M21=" + sintheta + ",M22=" + costheta + ",SizingMethod='auto expand')\n"; │ │ │ │ + var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ + if (opacity && opacity != 1) { │ │ │ │ + filter += "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + opacity + ")\n" │ │ │ │ + } │ │ │ │ + node.style.filter = filter; │ │ │ │ + var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset); │ │ │ │ + var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry(); │ │ │ │ + imgBox.rotate(style.rotation, centerPoint); │ │ │ │ + var imgBounds = imgBox.getBounds(); │ │ │ │ + node.style.left = Math.round(parseInt(node.style.left) + imgBounds.left) + "px"; │ │ │ │ + node.style.top = Math.round(parseInt(node.style.top) - imgBounds.bottom) + "px" │ │ │ │ }, │ │ │ │ - animationEnabled: true, │ │ │ │ - loadMapObject: function() { │ │ │ │ - if (!this.type) { │ │ │ │ - this.type = google.maps.MapTypeId.ROADMAP │ │ │ │ + postDraw: function(node) { │ │ │ │ + node.style.visibility = "visible"; │ │ │ │ + var fillColor = node._style.fillColor; │ │ │ │ + var strokeColor = node._style.strokeColor; │ │ │ │ + if (fillColor == "none" && node.fillcolor != fillColor) { │ │ │ │ + node.fillcolor = fillColor │ │ │ │ } │ │ │ │ - var mapObject; │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - if (cache) { │ │ │ │ - mapObject = cache.mapObject; │ │ │ │ - ++cache.count │ │ │ │ - } else { │ │ │ │ - var center = this.map.getCenter(); │ │ │ │ - var container = document.createElement("div"); │ │ │ │ - container.className = "olForeignContainer"; │ │ │ │ - container.style.width = "100%"; │ │ │ │ - container.style.height = "100%"; │ │ │ │ - mapObject = new google.maps.Map(container, { │ │ │ │ - center: center ? new google.maps.LatLng(center.lat, center.lon) : new google.maps.LatLng(0, 0), │ │ │ │ - zoom: this.map.getZoom() || 0, │ │ │ │ - mapTypeId: this.type, │ │ │ │ - disableDefaultUI: true, │ │ │ │ - keyboardShortcuts: false, │ │ │ │ - draggable: false, │ │ │ │ - disableDoubleClickZoom: true, │ │ │ │ - scrollwheel: false, │ │ │ │ - streetViewControl: false │ │ │ │ - }); │ │ │ │ - var googleControl = document.createElement("div"); │ │ │ │ - googleControl.style.width = "100%"; │ │ │ │ - googleControl.style.height = "100%"; │ │ │ │ - mapObject.controls[google.maps.ControlPosition.TOP_LEFT].push(googleControl); │ │ │ │ - cache = { │ │ │ │ - googleControl: googleControl, │ │ │ │ - mapObject: mapObject, │ │ │ │ - count: 1 │ │ │ │ - }; │ │ │ │ - OpenLayers.Layer.Google.cache[this.map.id] = cache │ │ │ │ + if (strokeColor == "none" && node.strokecolor != strokeColor) { │ │ │ │ + node.strokecolor = strokeColor │ │ │ │ } │ │ │ │ - this.mapObject = mapObject; │ │ │ │ - this.setGMapVisibility(this.visibility) │ │ │ │ }, │ │ │ │ - onMapResize: function() { │ │ │ │ - if (this.visibility) { │ │ │ │ - google.maps.event.trigger(this.mapObject, "resize") │ │ │ │ + setNodeDimension: function(node, geometry) { │ │ │ │ + var bbox = geometry.getBounds(); │ │ │ │ + if (bbox) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var scaledBox = new OpenLayers.Bounds((bbox.left - this.featureDx) / resolution - this.offset.x | 0, bbox.bottom / resolution - this.offset.y | 0, (bbox.right - this.featureDx) / resolution - this.offset.x | 0, bbox.top / resolution - this.offset.y | 0); │ │ │ │ + node.style.left = scaledBox.left + "px"; │ │ │ │ + node.style.top = scaledBox.top + "px"; │ │ │ │ + node.style.width = scaledBox.getWidth() + "px"; │ │ │ │ + node.style.height = scaledBox.getHeight() + "px"; │ │ │ │ + node.coordorigin = scaledBox.left + " " + scaledBox.top; │ │ │ │ + node.coordsize = scaledBox.getWidth() + " " + scaledBox.getHeight() │ │ │ │ } │ │ │ │ }, │ │ │ │ - setGMapVisibility: function(visible) { │ │ │ │ - var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ - var map = this.map; │ │ │ │ - if (cache) { │ │ │ │ - var type = this.type; │ │ │ │ - var layers = map.layers; │ │ │ │ - var layer; │ │ │ │ - for (var i = layers.length - 1; i >= 0; --i) { │ │ │ │ - layer = layers[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.Google && layer.visibility === true && layer.inRange === true) { │ │ │ │ - type = layer.type; │ │ │ │ - visible = true; │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var container = this.mapObject.getDiv(); │ │ │ │ - if (visible === true) { │ │ │ │ - if (container.parentNode !== map.div) { │ │ │ │ - if (!cache.rendered) { │ │ │ │ - var me = this; │ │ │ │ - google.maps.event.addListenerOnce(this.mapObject, "tilesloaded", function() { │ │ │ │ - cache.rendered = true; │ │ │ │ - me.setGMapVisibility(me.getVisibility()); │ │ │ │ - me.moveTo(me.map.getCenter()) │ │ │ │ - }) │ │ │ │ - } else { │ │ │ │ - map.div.appendChild(container); │ │ │ │ - cache.googleControl.appendChild(map.viewPortDiv); │ │ │ │ - google.maps.event.trigger(this.mapObject, "resize") │ │ │ │ + dashStyle: function(style) { │ │ │ │ + var dash = style.strokeDashstyle; │ │ │ │ + switch (dash) { │ │ │ │ + case "solid": │ │ │ │ + case "dot": │ │ │ │ + case "dash": │ │ │ │ + case "dashdot": │ │ │ │ + case "longdash": │ │ │ │ + case "longdashdot": │ │ │ │ + return dash; │ │ │ │ + default: │ │ │ │ + var parts = dash.split(/[ ,]/); │ │ │ │ + if (parts.length == 2) { │ │ │ │ + if (1 * parts[0] >= 2 * parts[1]) { │ │ │ │ + return "longdash" │ │ │ │ } │ │ │ │ + return parts[0] == 1 || parts[1] == 1 ? "dot" : "dash" │ │ │ │ + } else if (parts.length == 4) { │ │ │ │ + return 1 * parts[0] >= 2 * parts[1] ? "longdashdot" : "dashdot" │ │ │ │ } │ │ │ │ - this.mapObject.setMapTypeId(type) │ │ │ │ - } else if (cache.googleControl.hasChildNodes()) { │ │ │ │ - map.div.appendChild(map.viewPortDiv); │ │ │ │ - map.div.removeChild(container) │ │ │ │ - } │ │ │ │ + return "solid" │ │ │ │ } │ │ │ │ }, │ │ │ │ - getMapContainer: function() { │ │ │ │ - return this.mapObject.getDiv() │ │ │ │ - }, │ │ │ │ - getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ - var moBounds = null; │ │ │ │ - if (olBounds != null) { │ │ │ │ - var sw = this.sphericalMercator ? this.inverseMercator(olBounds.bottom, olBounds.left) : new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ - var ne = this.sphericalMercator ? this.inverseMercator(olBounds.top, olBounds.right) : new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ - moBounds = new google.maps.LatLngBounds(new google.maps.LatLng(sw.lat, sw.lon), new google.maps.LatLng(ne.lat, ne.lon)) │ │ │ │ + createNode: function(type, id) { │ │ │ │ + var node = document.createElement(type); │ │ │ │ + if (id) { │ │ │ │ + node.id = id │ │ │ │ } │ │ │ │ - return moBounds │ │ │ │ + node.unselectable = "on"; │ │ │ │ + node.onselectstart = OpenLayers.Function.False; │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ - var size = this.map.getSize(); │ │ │ │ - var lon = this.getLongitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ - var lat = this.getLatitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - var delta_x = moPixel.x - size.w / 2; │ │ │ │ - var delta_y = moPixel.y - size.h / 2; │ │ │ │ - var lonlat = new OpenLayers.LonLat(lon + delta_x * res, lat - delta_y * res); │ │ │ │ - if (this.wrapDateLine) { │ │ │ │ - lonlat = lonlat.wrapDateLine(this.maxExtent) │ │ │ │ + nodeTypeCompare: function(node, type) { │ │ │ │ + var subType = type; │ │ │ │ + var splitIndex = subType.indexOf(":"); │ │ │ │ + if (splitIndex != -1) { │ │ │ │ + subType = subType.substr(splitIndex + 1) │ │ │ │ } │ │ │ │ - return this.getMapObjectLonLatFromLonLat(lonlat.lon, lonlat.lat) │ │ │ │ - }, │ │ │ │ - getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ - var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); │ │ │ │ - var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - var extent = this.map.getExtent(); │ │ │ │ - return this.getMapObjectPixelFromXY(1 / res * (lon - extent.left), 1 / res * (extent.top - lat)) │ │ │ │ - }, │ │ │ │ - setMapObjectCenter: function(center, zoom) { │ │ │ │ - if (this.animationEnabled === false && zoom != this.mapObject.zoom) { │ │ │ │ - var mapContainer = this.getMapContainer(); │ │ │ │ - google.maps.event.addListenerOnce(this.mapObject, "idle", function() { │ │ │ │ - mapContainer.style.visibility = "" │ │ │ │ - }); │ │ │ │ - mapContainer.style.visibility = "hidden" │ │ │ │ + var nodeName = node.nodeName; │ │ │ │ + splitIndex = nodeName.indexOf(":"); │ │ │ │ + if (splitIndex != -1) { │ │ │ │ + nodeName = nodeName.substr(splitIndex + 1) │ │ │ │ } │ │ │ │ - this.mapObject.setOptions({ │ │ │ │ - center: center, │ │ │ │ - zoom: zoom │ │ │ │ - }) │ │ │ │ + return subType == nodeName │ │ │ │ }, │ │ │ │ - getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ - return this.mapObject.getBoundsZoomLevel(moBounds) │ │ │ │ + createRenderRoot: function() { │ │ │ │ + return this.nodeFactory(this.container.id + "_vmlRoot", "div") │ │ │ │ }, │ │ │ │ - getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ - var gLatLng; │ │ │ │ - if (this.sphericalMercator) { │ │ │ │ - var lonlat = this.inverseMercator(lon, lat); │ │ │ │ - gLatLng = new google.maps.LatLng(lonlat.lat, lonlat.lon) │ │ │ │ - } else { │ │ │ │ - gLatLng = new google.maps.LatLng(lat, lon) │ │ │ │ - } │ │ │ │ - return gLatLng │ │ │ │ + createRoot: function(suffix) { │ │ │ │ + return this.nodeFactory(this.container.id + suffix, "olv:group") │ │ │ │ }, │ │ │ │ - getMapObjectPixelFromXY: function(x, y) { │ │ │ │ - return new google.maps.Point(x, y) │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -OpenLayers.Events.buttonclick = OpenLayers.Class({ │ │ │ │ - target: null, │ │ │ │ - events: ["mousedown", "mouseup", "click", "dblclick", "touchstart", "touchmove", "touchend", "keydown"], │ │ │ │ - startRegEx: /^mousedown|touchstart$/, │ │ │ │ - cancelRegEx: /^touchmove$/, │ │ │ │ - completeRegEx: /^mouseup|touchend$/, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ + drawPoint: function(node, geometry) { │ │ │ │ + return this.drawCircle(node, geometry, 1) │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - for (var i = this.events.length - 1; i >= 0; --i) { │ │ │ │ - this.target.unregister(this.events[i], this, this.buttonClick) │ │ │ │ + drawCircle: function(node, geometry, radius) { │ │ │ │ + if (!isNaN(geometry.x) && !isNaN(geometry.y)) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x | 0) - radius + "px"; │ │ │ │ + node.style.top = (geometry.y / resolution - this.offset.y | 0) - radius + "px"; │ │ │ │ + var diameter = radius * 2; │ │ │ │ + node.style.width = diameter + "px"; │ │ │ │ + node.style.height = diameter + "px"; │ │ │ │ + return node │ │ │ │ } │ │ │ │ - delete this.target │ │ │ │ - }, │ │ │ │ - getPressedButton: function(element) { │ │ │ │ - var depth = 3, │ │ │ │ - button; │ │ │ │ - do { │ │ │ │ - if (OpenLayers.Element.hasClass(element, "olButton")) { │ │ │ │ - button = element; │ │ │ │ - break │ │ │ │ - } │ │ │ │ - element = element.parentNode │ │ │ │ - } while (--depth > 0 && element); │ │ │ │ - return button │ │ │ │ + return false │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + drawLineString: function(node, geometry) { │ │ │ │ + return this.drawLine(node, geometry, false) │ │ │ │ }, │ │ │ │ - buttonClick: function(evt) { │ │ │ │ - var propagate = true, │ │ │ │ - element = OpenLayers.Event.element(evt); │ │ │ │ - if (element && (OpenLayers.Event.isLeftClick(evt) || !~evt.type.indexOf("mouse"))) { │ │ │ │ - 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.Panel = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - controls: null, │ │ │ │ - autoActivate: true, │ │ │ │ - defaultControl: null, │ │ │ │ - saveState: false, │ │ │ │ - allowDepress: false, │ │ │ │ - activeState: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.controls = []; │ │ │ │ - this.activeState = {} │ │ │ │ + drawLinearRing: function(node, geometry) { │ │ │ │ + return this.drawLine(node, geometry, true) │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + drawLine: function(node, geometry, closeLine) { │ │ │ │ + this.setNodeDimension(node, geometry); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var numComponents = geometry.components.length; │ │ │ │ + var parts = new Array(numComponents); │ │ │ │ + var comp, x, y; │ │ │ │ + for (var i = 0; i < numComponents; i++) { │ │ │ │ + comp = geometry.components[i]; │ │ │ │ + x = (comp.x - this.featureDx) / resolution - this.offset.x | 0; │ │ │ │ + y = comp.y / resolution - this.offset.y | 0; │ │ │ │ + parts[i] = " " + x + "," + y + " l " │ │ │ │ } │ │ │ │ - this.activeState = null │ │ │ │ + var end = closeLine ? " x e" : " e"; │ │ │ │ + node.path = "m" + parts.join("") + end; │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - 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() │ │ │ │ + drawPolygon: function(node, geometry) { │ │ │ │ + this.setNodeDimension(node, geometry); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var path = []; │ │ │ │ + var j, jj, points, area, first, second, i, ii, comp, pathComp, x, y; │ │ │ │ + for (j = 0, jj = geometry.components.length; j < jj; j++) { │ │ │ │ + path.push("m"); │ │ │ │ + points = geometry.components[j].components; │ │ │ │ + area = j === 0; │ │ │ │ + first = null; │ │ │ │ + second = null; │ │ │ │ + for (i = 0, ii = points.length; i < ii; i++) { │ │ │ │ + comp = points[i]; │ │ │ │ + x = (comp.x - this.featureDx) / resolution - this.offset.x | 0; │ │ │ │ + y = comp.y / resolution - this.offset.y | 0; │ │ │ │ + pathComp = " " + x + "," + y; │ │ │ │ + path.push(pathComp); │ │ │ │ + if (i == 0) { │ │ │ │ + path.push(" l") │ │ │ │ + } │ │ │ │ + if (!area) { │ │ │ │ + if (!first) { │ │ │ │ + first = pathComp │ │ │ │ + } else if (first != pathComp) { │ │ │ │ + if (!second) { │ │ │ │ + second = pathComp │ │ │ │ + } else if (second != pathComp) { │ │ │ │ + area = true │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ - if (this.saveState === true) { │ │ │ │ - this.defaultControl = null │ │ │ │ - } │ │ │ │ - this.redraw(); │ │ │ │ - return true │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ + path.push(area ? " x " : " ") │ │ │ │ } │ │ │ │ + path.push("e"); │ │ │ │ + node.path = path.join(""); │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + drawRectangle: function(node, geometry) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x | 0) + "px"; │ │ │ │ + node.style.top = (geometry.y / resolution - this.offset.y | 0) + "px"; │ │ │ │ + node.style.width = (geometry.width / resolution | 0) + "px"; │ │ │ │ + node.style.height = (geometry.height / resolution | 0) + "px"; │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - redraw: function() { │ │ │ │ - for (var l = this.div.childNodes.length, i = l - 1; i >= 0; i--) { │ │ │ │ - this.div.removeChild(this.div.childNodes[i]) │ │ │ │ + drawText: function(featureId, style, location) { │ │ │ │ + var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect"); │ │ │ │ + var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox"); │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + label.style.left = ((location.x - this.featureDx) / resolution - this.offset.x | 0) + "px"; │ │ │ │ + label.style.top = (location.y / resolution - this.offset.y | 0) + "px"; │ │ │ │ + label.style.flip = "y"; │ │ │ │ + textbox.innerText = style.label; │ │ │ │ + if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ + textbox.style.cursor = style.cursor │ │ │ │ } │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ + if (style.fontColor) { │ │ │ │ + textbox.style.color = style.fontColor │ │ │ │ } │ │ │ │ - }, │ │ │ │ - activateControl: function(control) { │ │ │ │ - if (!this.active) { │ │ │ │ - return false │ │ │ │ + if (style.fontOpacity) { │ │ │ │ + textbox.style.filter = "alpha(opacity=" + style.fontOpacity * 100 + ")" │ │ │ │ } │ │ │ │ - if (control.type == OpenLayers.Control.TYPE_BUTTON) { │ │ │ │ - control.trigger(); │ │ │ │ - return │ │ │ │ + if (style.fontFamily) { │ │ │ │ + textbox.style.fontFamily = style.fontFamily │ │ │ │ } │ │ │ │ - if (control.type == OpenLayers.Control.TYPE_TOGGLE) { │ │ │ │ - if (control.active) { │ │ │ │ - control.deactivate() │ │ │ │ - } else { │ │ │ │ - control.activate() │ │ │ │ - } │ │ │ │ - return │ │ │ │ + if (style.fontSize) { │ │ │ │ + textbox.style.fontSize = style.fontSize │ │ │ │ } │ │ │ │ - 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() │ │ │ │ + if (style.fontWeight) { │ │ │ │ + textbox.style.fontWeight = style.fontWeight │ │ │ │ } │ │ │ │ - }, │ │ │ │ - addControls: function(controls) { │ │ │ │ - if (!OpenLayers.Util.isArray(controls)) { │ │ │ │ - controls = [controls] │ │ │ │ + if (style.fontStyle) { │ │ │ │ + textbox.style.fontStyle = style.fontStyle │ │ │ │ } │ │ │ │ - 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 (style.labelSelect === true) { │ │ │ │ + label._featureId = featureId; │ │ │ │ + textbox._featureId = featureId; │ │ │ │ + textbox._geometry = location; │ │ │ │ + textbox._geometryClass = location.CLASS_NAME │ │ │ │ } │ │ │ │ - if (this.map) { │ │ │ │ - this.addControlsToMap(controls); │ │ │ │ - this.redraw() │ │ │ │ + textbox.style.whiteSpace = "nowrap"; │ │ │ │ + textbox.inset = "1px,0px,0px,0px"; │ │ │ │ + if (!label.parentNode) { │ │ │ │ + label.appendChild(textbox); │ │ │ │ + this.textRoot.appendChild(label) │ │ │ │ } │ │ │ │ - }, │ │ │ │ - createControlMarkup: function(control) { │ │ │ │ - return document.createElement("div") │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ + var align = style.labelAlign || "cm"; │ │ │ │ + if (align.length == 1) { │ │ │ │ + align += "m" │ │ │ │ } │ │ │ │ + var xshift = textbox.clientWidth * OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0, 1)]; │ │ │ │ + var yshift = textbox.clientHeight * OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1, 1)]; │ │ │ │ + label.style.left = parseInt(label.style.left) - xshift - 1 + "px"; │ │ │ │ + label.style.top = parseInt(label.style.top) + yshift + "px" │ │ │ │ }, │ │ │ │ - iconOn: function() { │ │ │ │ - var d = this.panel_div; │ │ │ │ - var re = new RegExp("\\b(" + this.displayClass + "Item)Inactive\\b"); │ │ │ │ - d.className = d.className.replace(re, "$1Active") │ │ │ │ - }, │ │ │ │ - iconOff: function() { │ │ │ │ - var d = this.panel_div; │ │ │ │ - var re = new RegExp("\\b(" + this.displayClass + "Item)Active\\b"); │ │ │ │ - d.className = d.className.replace(re, "$1Inactive") │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ + moveRoot: function(renderer) { │ │ │ │ + var layer = this.map.getLayer(renderer.container.id); │ │ │ │ + if (layer instanceof OpenLayers.Layer.Vector.RootContainer) { │ │ │ │ + layer = this.map.getLayer(this.container.id) │ │ │ │ } │ │ │ │ + layer && layer.renderer.clear(); │ │ │ │ + OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments); │ │ │ │ + layer && layer.redraw() │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - getControlsByName: function(match) { │ │ │ │ - return this.getControlsBy("name", match) │ │ │ │ - }, │ │ │ │ - getControlsByClass: function(match) { │ │ │ │ - return this.getControlsBy("CLASS_NAME", match) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Panel" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.Snapping = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - DEFAULTS: { │ │ │ │ - tolerance: 10, │ │ │ │ - node: true, │ │ │ │ - edge: true, │ │ │ │ - vertex: true │ │ │ │ - }, │ │ │ │ - greedy: true, │ │ │ │ - precedence: ["node", "vertex", "edge"], │ │ │ │ - resolution: null, │ │ │ │ - geoToleranceCache: null, │ │ │ │ - layer: null, │ │ │ │ - feature: null, │ │ │ │ - point: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.options = options || {}; │ │ │ │ - if (this.options.layer) { │ │ │ │ - this.setLayer(this.options.layer) │ │ │ │ - } │ │ │ │ - var defaults = OpenLayers.Util.extend({}, this.options.defaults); │ │ │ │ - this.defaults = OpenLayers.Util.applyDefaults(defaults, this.DEFAULTS); │ │ │ │ - this.setTargets(this.options.targets); │ │ │ │ - if (this.targets.length === 0 && this.layer) { │ │ │ │ - this.addTargetLayer(this.layer) │ │ │ │ + importSymbol: function(graphicName) { │ │ │ │ + var id = this.container.id + "-" + graphicName; │ │ │ │ + var cache = this.symbolCache[id]; │ │ │ │ + if (cache) { │ │ │ │ + return cache │ │ │ │ } │ │ │ │ - this.geoToleranceCache = {} │ │ │ │ - }, │ │ │ │ - setLayer: function(layer) { │ │ │ │ - if (this.active) { │ │ │ │ - this.deactivate(); │ │ │ │ - this.layer = layer; │ │ │ │ - this.activate() │ │ │ │ - } else { │ │ │ │ - this.layer = layer │ │ │ │ + var symbol = OpenLayers.Renderer.symbol[graphicName]; │ │ │ │ + if (!symbol) { │ │ │ │ + throw new Error(graphicName + " is not a valid symbol name") │ │ │ │ } │ │ │ │ - }, │ │ │ │ - setTargets: function(targets) { │ │ │ │ - this.targets = []; │ │ │ │ - if (targets && targets.length) { │ │ │ │ - var target; │ │ │ │ - for (var i = 0, len = targets.length; i < len; ++i) { │ │ │ │ - target = targets[i]; │ │ │ │ - if (target instanceof OpenLayers.Layer.Vector) { │ │ │ │ - this.addTargetLayer(target) │ │ │ │ - } else { │ │ │ │ - this.addTarget(target) │ │ │ │ - } │ │ │ │ + var symbolExtent = new OpenLayers.Bounds(Number.MAX_VALUE, Number.MAX_VALUE, 0, 0); │ │ │ │ + var pathitems = ["m"]; │ │ │ │ + for (var i = 0; i < symbol.length; i = i + 2) { │ │ │ │ + var x = symbol[i]; │ │ │ │ + var 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); │ │ │ │ + pathitems.push(x); │ │ │ │ + pathitems.push(y); │ │ │ │ + if (i == 0) { │ │ │ │ + pathitems.push("l") │ │ │ │ } │ │ │ │ } │ │ │ │ - }, │ │ │ │ - addTargetLayer: function(layer) { │ │ │ │ - this.addTarget({ │ │ │ │ - layer: layer │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - addTarget: function(target) { │ │ │ │ - target = OpenLayers.Util.applyDefaults(target, this.defaults); │ │ │ │ - target.nodeTolerance = target.nodeTolerance || target.tolerance; │ │ │ │ - target.vertexTolerance = target.vertexTolerance || target.tolerance; │ │ │ │ - target.edgeTolerance = target.edgeTolerance || target.tolerance; │ │ │ │ - this.targets.push(target) │ │ │ │ - }, │ │ │ │ - removeTargetLayer: function(layer) { │ │ │ │ - var target; │ │ │ │ - for (var i = this.targets.length - 1; i >= 0; --i) { │ │ │ │ - target = this.targets[i]; │ │ │ │ - if (target.layer === layer) { │ │ │ │ - this.removeTarget(target) │ │ │ │ - } │ │ │ │ + pathitems.push("x e"); │ │ │ │ + var path = pathitems.join(" "); │ │ │ │ + var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2; │ │ │ │ + if (diff > 0) { │ │ │ │ + symbolExtent.bottom = symbolExtent.bottom - diff; │ │ │ │ + symbolExtent.top = symbolExtent.top + diff │ │ │ │ + } else { │ │ │ │ + symbolExtent.left = symbolExtent.left + diff; │ │ │ │ + symbolExtent.right = symbolExtent.right - diff │ │ │ │ } │ │ │ │ + cache = { │ │ │ │ + path: path, │ │ │ │ + size: symbolExtent.getWidth(), │ │ │ │ + left: symbolExtent.left, │ │ │ │ + bottom: symbolExtent.bottom │ │ │ │ + }; │ │ │ │ + this.symbolCache[id] = cache; │ │ │ │ + return cache │ │ │ │ }, │ │ │ │ - removeTarget: function(target) { │ │ │ │ - return OpenLayers.Util.removeItem(this.targets, target) │ │ │ │ - }, │ │ │ │ + CLASS_NAME: "OpenLayers.Renderer.VML" │ │ │ │ +}); │ │ │ │ +OpenLayers.Renderer.VML.LABEL_SHIFT = { │ │ │ │ + l: 0, │ │ │ │ + c: .5, │ │ │ │ + r: 1, │ │ │ │ + t: 0, │ │ │ │ + m: .5, │ │ │ │ + b: 1 │ │ │ │ +}; │ │ │ │ +OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + distance: 20, │ │ │ │ + threshold: null, │ │ │ │ + features: null, │ │ │ │ + clusters: null, │ │ │ │ + clustering: false, │ │ │ │ + resolution: null, │ │ │ │ activate: function() { │ │ │ │ - var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ if (activated) { │ │ │ │ - if (this.layer && this.layer.events) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - sketchstarted: this.onSketchModified, │ │ │ │ - sketchmodified: this.onSketchModified, │ │ │ │ - vertexmodified: this.onVertexModified, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ + this.layer.events.on({ │ │ │ │ + beforefeaturesadded: this.cacheFeatures, │ │ │ │ + featuresremoved: this.clearCache, │ │ │ │ + moveend: this.cluster, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ } │ │ │ │ return activated │ │ │ │ }, │ │ │ │ deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ if (deactivated) { │ │ │ │ - if (this.layer && this.layer.events) { │ │ │ │ - this.layer.events.un({ │ │ │ │ - sketchstarted: this.onSketchModified, │ │ │ │ - sketchmodified: this.onSketchModified, │ │ │ │ - vertexmodified: this.onVertexModified, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ + this.clearCache(); │ │ │ │ + this.layer.events.un({ │ │ │ │ + beforefeaturesadded: this.cacheFeatures, │ │ │ │ + featuresremoved: this.clearCache, │ │ │ │ + moveend: this.cluster, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ } │ │ │ │ - this.feature = null; │ │ │ │ - this.point = null; │ │ │ │ return deactivated │ │ │ │ }, │ │ │ │ - onSketchModified: function(event) { │ │ │ │ - this.feature = event.feature; │ │ │ │ - this.considerSnapping(event.vertex, event.vertex) │ │ │ │ + cacheFeatures: function(event) { │ │ │ │ + var propagate = true; │ │ │ │ + if (!this.clustering) { │ │ │ │ + this.clearCache(); │ │ │ │ + this.features = event.features; │ │ │ │ + this.cluster(); │ │ │ │ + propagate = false │ │ │ │ + } │ │ │ │ + return propagate │ │ │ │ }, │ │ │ │ - onVertexModified: function(event) { │ │ │ │ - this.feature = event.feature; │ │ │ │ - var loc = this.layer.map.getLonLatFromViewPortPx(event.pixel); │ │ │ │ - this.considerSnapping(event.vertex, new OpenLayers.Geometry.Point(loc.lon, loc.lat)) │ │ │ │ + clearCache: function() { │ │ │ │ + if (!this.clustering) { │ │ │ │ + this.features = null │ │ │ │ + } │ │ │ │ }, │ │ │ │ - considerSnapping: function(point, loc) { │ │ │ │ - var best = { │ │ │ │ - rank: Number.POSITIVE_INFINITY, │ │ │ │ - dist: Number.POSITIVE_INFINITY, │ │ │ │ - x: null, │ │ │ │ - y: null │ │ │ │ - }; │ │ │ │ - var snapped = false; │ │ │ │ - var result, target; │ │ │ │ - for (var i = 0, len = this.targets.length; i < len; ++i) { │ │ │ │ - target = this.targets[i]; │ │ │ │ - result = this.testTarget(target, loc); │ │ │ │ - if (result) { │ │ │ │ - if (this.greedy) { │ │ │ │ - best = result; │ │ │ │ - best.target = target; │ │ │ │ - snapped = true; │ │ │ │ - break │ │ │ │ - } else { │ │ │ │ - if (result.rank < best.rank || result.rank === best.rank && result.dist < best.dist) { │ │ │ │ - best = result; │ │ │ │ - best.target = target; │ │ │ │ - snapped = true │ │ │ │ + cluster: function(event) { │ │ │ │ + if ((!event || event.zoomChanged) && this.features) { │ │ │ │ + var resolution = this.layer.map.getResolution(); │ │ │ │ + if (resolution != this.resolution || !this.clustersExist()) { │ │ │ │ + this.resolution = resolution; │ │ │ │ + var clusters = []; │ │ │ │ + var feature, clustered, cluster; │ │ │ │ + for (var i = 0; i < this.features.length; ++i) { │ │ │ │ + feature = this.features[i]; │ │ │ │ + if (feature.geometry) { │ │ │ │ + clustered = false; │ │ │ │ + for (var j = clusters.length - 1; j >= 0; --j) { │ │ │ │ + cluster = clusters[j]; │ │ │ │ + if (this.shouldCluster(cluster, feature)) { │ │ │ │ + this.addToCluster(cluster, feature); │ │ │ │ + clustered = true; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (!clustered) { │ │ │ │ + clusters.push(this.createCluster(this.features[i])) │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (snapped) { │ │ │ │ - var proceed = this.events.triggerEvent("beforesnap", { │ │ │ │ - point: point, │ │ │ │ - x: best.x, │ │ │ │ - y: best.y, │ │ │ │ - distance: best.dist, │ │ │ │ - layer: best.target.layer, │ │ │ │ - snapType: this.precedence[best.rank] │ │ │ │ - }); │ │ │ │ - if (proceed !== false) { │ │ │ │ - point.x = best.x; │ │ │ │ - point.y = best.y; │ │ │ │ - this.point = point; │ │ │ │ - this.events.triggerEvent("snap", { │ │ │ │ - point: point, │ │ │ │ - snapType: this.precedence[best.rank], │ │ │ │ - layer: best.target.layer, │ │ │ │ - distance: best.dist │ │ │ │ - }) │ │ │ │ - } else { │ │ │ │ - snapped = false │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.point && !snapped) { │ │ │ │ - point.x = loc.x; │ │ │ │ - point.y = loc.y; │ │ │ │ - this.point = null; │ │ │ │ - this.events.triggerEvent("unsnap", { │ │ │ │ - point: point │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - testTarget: function(target, loc) { │ │ │ │ - var resolution = this.layer.map.getResolution(); │ │ │ │ - if ("minResolution" in target) { │ │ │ │ - if (resolution < target.minResolution) { │ │ │ │ - return null │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if ("maxResolution" in target) { │ │ │ │ - if (resolution >= target.maxResolution) { │ │ │ │ - return null │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var tolerance = { │ │ │ │ - node: this.getGeoTolerance(target.nodeTolerance, resolution), │ │ │ │ - vertex: this.getGeoTolerance(target.vertexTolerance, resolution), │ │ │ │ - edge: this.getGeoTolerance(target.edgeTolerance, resolution) │ │ │ │ - }; │ │ │ │ - var maxTolerance = Math.max(tolerance.node, tolerance.vertex, tolerance.edge); │ │ │ │ - var result = { │ │ │ │ - rank: Number.POSITIVE_INFINITY, │ │ │ │ - dist: Number.POSITIVE_INFINITY │ │ │ │ - }; │ │ │ │ - var eligible = false; │ │ │ │ - var features = target.layer.features; │ │ │ │ - var feature, type, vertices, vertex, closest, dist, found; │ │ │ │ - var numTypes = this.precedence.length; │ │ │ │ - var ll = new OpenLayers.LonLat(loc.x, loc.y); │ │ │ │ - for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - if (feature !== this.feature && !feature._sketch && feature.state !== OpenLayers.State.DELETE && (!target.filter || target.filter.evaluate(feature))) { │ │ │ │ - if (feature.atPoint(ll, maxTolerance, maxTolerance)) { │ │ │ │ - for (var j = 0, stop = Math.min(result.rank + 1, numTypes); j < stop; ++j) { │ │ │ │ - type = this.precedence[j]; │ │ │ │ - if (target[type]) { │ │ │ │ - if (type === "edge") { │ │ │ │ - closest = feature.geometry.distanceTo(loc, { │ │ │ │ - details: true │ │ │ │ - }); │ │ │ │ - dist = closest.distance; │ │ │ │ - if (dist <= tolerance[type] && dist < result.dist) { │ │ │ │ - result = { │ │ │ │ - rank: j, │ │ │ │ - dist: dist, │ │ │ │ - x: closest.x0, │ │ │ │ - y: closest.y0 │ │ │ │ - }; │ │ │ │ - eligible = true; │ │ │ │ - break │ │ │ │ - } │ │ │ │ + this.clustering = true; │ │ │ │ + this.layer.removeAllFeatures(); │ │ │ │ + this.clustering = false; │ │ │ │ + if (clusters.length > 0) { │ │ │ │ + if (this.threshold > 1) { │ │ │ │ + var clone = clusters.slice(); │ │ │ │ + clusters = []; │ │ │ │ + var candidate; │ │ │ │ + for (var i = 0, len = clone.length; i < len; ++i) { │ │ │ │ + candidate = clone[i]; │ │ │ │ + if (candidate.attributes.count < this.threshold) { │ │ │ │ + Array.prototype.push.apply(clusters, candidate.cluster) │ │ │ │ } else { │ │ │ │ - vertices = feature.geometry.getVertices(type === "node"); │ │ │ │ - found = false; │ │ │ │ - for (var k = 0, klen = vertices.length; k < klen; ++k) { │ │ │ │ - vertex = vertices[k]; │ │ │ │ - dist = vertex.distanceTo(loc); │ │ │ │ - if (dist <= tolerance[type] && (j < result.rank || j === result.rank && dist < result.dist)) { │ │ │ │ - result = { │ │ │ │ - rank: j, │ │ │ │ - dist: dist, │ │ │ │ - x: vertex.x, │ │ │ │ - y: vertex.y │ │ │ │ - }; │ │ │ │ - eligible = true; │ │ │ │ - found = true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (found) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ + clusters.push(candidate) │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ + this.clustering = true; │ │ │ │ + this.layer.addFeatures(clusters); │ │ │ │ + this.clustering = false │ │ │ │ } │ │ │ │ + this.clusters = clusters │ │ │ │ } │ │ │ │ } │ │ │ │ - return eligible ? result : null │ │ │ │ }, │ │ │ │ - getGeoTolerance: function(tolerance, resolution) { │ │ │ │ - if (resolution !== this.resolution) { │ │ │ │ - this.resolution = resolution; │ │ │ │ - this.geoToleranceCache = {} │ │ │ │ - } │ │ │ │ - var geoTolerance = this.geoToleranceCache[tolerance]; │ │ │ │ - if (geoTolerance === undefined) { │ │ │ │ - geoTolerance = tolerance * resolution; │ │ │ │ - this.geoToleranceCache[tolerance] = geoTolerance │ │ │ │ + clustersExist: function() { │ │ │ │ + var exist = false; │ │ │ │ + if (this.clusters && this.clusters.length > 0 && this.clusters.length == this.layer.features.length) { │ │ │ │ + exist = true; │ │ │ │ + for (var i = 0; i < this.clusters.length; ++i) { │ │ │ │ + if (this.clusters[i] != this.layer.features[i]) { │ │ │ │ + exist = false; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - return geoTolerance │ │ │ │ + return exist │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.active) { │ │ │ │ - this.deactivate() │ │ │ │ - } │ │ │ │ - delete this.layer; │ │ │ │ - delete this.targets; │ │ │ │ - OpenLayers.Control.prototype.destroy.call(this) │ │ │ │ + shouldCluster: function(cluster, feature) { │ │ │ │ + var cc = cluster.geometry.getBounds().getCenterLonLat(); │ │ │ │ + var fc = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ + var distance = Math.sqrt(Math.pow(cc.lon - fc.lon, 2) + Math.pow(cc.lat - fc.lat, 2)) / this.resolution; │ │ │ │ + return distance <= this.distance │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Snapping" │ │ │ │ + addToCluster: function(cluster, feature) { │ │ │ │ + cluster.cluster.push(feature); │ │ │ │ + cluster.attributes.count += 1 │ │ │ │ + }, │ │ │ │ + createCluster: function(feature) { │ │ │ │ + var center = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ + var cluster = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(center.lon, center.lat), { │ │ │ │ + count: 1 │ │ │ │ + }); │ │ │ │ + cluster.cluster = [feature]; │ │ │ │ + return cluster │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Cluster" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - layers: null, │ │ │ │ - imageFormat: "image/png", │ │ │ │ - quotaRegEx: /quota/i, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - var i, layers = this.layers || map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.addLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - if (!this.layers) { │ │ │ │ - map.events.on({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ +OpenLayers.Strategy.Filter = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + filter: null, │ │ │ │ + cache: null, │ │ │ │ + caching: false, │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments); │ │ │ │ + if (activated) { │ │ │ │ + this.cache = []; │ │ │ │ + this.layer.events.on({ │ │ │ │ + beforefeaturesadded: this.handleAdd, │ │ │ │ + beforefeaturesremoved: this.handleRemove, │ │ │ │ scope: this │ │ │ │ }) │ │ │ │ } │ │ │ │ + return activated │ │ │ │ }, │ │ │ │ - addLayer: function(evt) { │ │ │ │ - evt.layer.events.on({ │ │ │ │ - tileloadstart: this.makeSameOrigin, │ │ │ │ - tileloaded: this.onTileLoaded, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - removeLayer: function(evt) { │ │ │ │ - evt.layer.events.un({ │ │ │ │ - tileloadstart: this.makeSameOrigin, │ │ │ │ - tileloaded: this.onTileLoaded, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - makeSameOrigin: function(evt) { │ │ │ │ - if (this.active) { │ │ │ │ - var tile = evt.tile; │ │ │ │ - if (tile instanceof OpenLayers.Tile.Image && !tile.crossOriginKeyword && tile.url.substr(0, 5) !== "data:") { │ │ │ │ - var sameOriginUrl = OpenLayers.Request.makeSameOrigin(tile.url, OpenLayers.ProxyHost); │ │ │ │ - OpenLayers.Control.CacheWrite.urlMap[sameOriginUrl] = tile.url; │ │ │ │ - tile.url = sameOriginUrl │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - onTileLoaded: function(evt) { │ │ │ │ - if (this.active && !evt.aborted && evt.tile instanceof OpenLayers.Tile.Image && evt.tile.url.substr(0, 5) !== "data:") { │ │ │ │ - this.cache({ │ │ │ │ - tile: evt.tile │ │ │ │ - }); │ │ │ │ - delete OpenLayers.Control.CacheWrite.urlMap[evt.tile.url] │ │ │ │ + deactivate: function() { │ │ │ │ + this.cache = null; │ │ │ │ + if (this.layer && this.layer.events) { │ │ │ │ + this.layer.events.un({ │ │ │ │ + beforefeaturesadded: this.handleAdd, │ │ │ │ + beforefeaturesremoved: this.handleRemove, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ } │ │ │ │ + return OpenLayers.Strategy.prototype.deactivate.apply(this, arguments) │ │ │ │ }, │ │ │ │ - cache: function(obj) { │ │ │ │ - if (window.localStorage) { │ │ │ │ - var tile = obj.tile; │ │ │ │ - try { │ │ │ │ - var canvasContext = tile.getCanvasContext(); │ │ │ │ - if (canvasContext) { │ │ │ │ - var urlMap = OpenLayers.Control.CacheWrite.urlMap; │ │ │ │ - var url = urlMap[tile.url] || tile.url; │ │ │ │ - window.localStorage.setItem("olCache_" + url, canvasContext.canvas.toDataURL(this.imageFormat)) │ │ │ │ - } │ │ │ │ - } catch (e) { │ │ │ │ - var reason = e.name || e.message; │ │ │ │ - if (reason && this.quotaRegEx.test(reason)) { │ │ │ │ - this.events.triggerEvent("cachefull", { │ │ │ │ - tile: tile │ │ │ │ - }) │ │ │ │ + handleAdd: function(event) { │ │ │ │ + if (!this.caching && this.filter) { │ │ │ │ + var features = event.features; │ │ │ │ + event.features = []; │ │ │ │ + var feature; │ │ │ │ + for (var i = 0, ii = features.length; i < ii; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + if (this.filter.evaluate(feature)) { │ │ │ │ + event.features.push(feature) │ │ │ │ } else { │ │ │ │ - OpenLayers.Console.error(e.toString()) │ │ │ │ + this.cache.push(feature) │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.layers || this.map) { │ │ │ │ - var i, layers = this.layers || this.map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.removeLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.un({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ + handleRemove: function(event) { │ │ │ │ + if (!this.caching) { │ │ │ │ + this.cache = [] │ │ │ │ } │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.CacheWrite" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.CacheWrite.clearCache = function() { │ │ │ │ - if (!window.localStorage) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - var i, key; │ │ │ │ - for (i = window.localStorage.length - 1; i >= 0; --i) { │ │ │ │ - key = window.localStorage.key(i); │ │ │ │ - if (key.substr(0, 8) === "olCache_") { │ │ │ │ - window.localStorage.removeItem(key) │ │ │ │ + setFilter: function(filter) { │ │ │ │ + this.filter = filter; │ │ │ │ + var previousCache = this.cache; │ │ │ │ + this.cache = []; │ │ │ │ + this.handleAdd({ │ │ │ │ + features: this.layer.features │ │ │ │ + }); │ │ │ │ + if (this.cache.length > 0) { │ │ │ │ + this.caching = true; │ │ │ │ + this.layer.removeFeatures(this.cache.slice()); │ │ │ │ + this.caching = false │ │ │ │ } │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -OpenLayers.Control.CacheWrite.urlMap = {}; │ │ │ │ -OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - started: false, │ │ │ │ - stopDown: true, │ │ │ │ - dragging: false, │ │ │ │ - last: null, │ │ │ │ - start: null, │ │ │ │ - lastMoveEvt: null, │ │ │ │ - oldOnselectstart: null, │ │ │ │ - interval: 0, │ │ │ │ - timeoutId: null, │ │ │ │ - documentDrag: false, │ │ │ │ - documentEvents: null, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ + if (previousCache.length > 0) { │ │ │ │ + var event = { │ │ │ │ + features: previousCache │ │ │ │ }; │ │ │ │ - this._docUp = function(evt) { │ │ │ │ - me.mouseup({ │ │ │ │ - xy: { │ │ │ │ - x: evt.clientX, │ │ │ │ - y: evt.clientY │ │ │ │ - } │ │ │ │ - }) │ │ │ │ + this.handleAdd(event); │ │ │ │ + if (event.features.length > 0) { │ │ │ │ + this.caching = true; │ │ │ │ + this.layer.addFeatures(event.features); │ │ │ │ + this.caching = false │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ - 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]); │ │ │ │ - OpenLayers.Event.preventDefault(evt); │ │ │ │ - if (!this.oldOnselectstart) { │ │ │ │ - this.oldOnselectstart = document.onselectstart ? document.onselectstart : OpenLayers.Function.True │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Filter" │ │ │ │ +}); │ │ │ │ +OpenLayers.Strategy.Refresh = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + force: false, │ │ │ │ + interval: 0, │ │ │ │ + timer: null, │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + if (this.layer.visibility === true) { │ │ │ │ + this.start() │ │ │ │ } │ │ │ │ - document.onselectstart = OpenLayers.Function.False; │ │ │ │ - propagate = !this.stopDown │ │ │ │ - } else { │ │ │ │ - this.started = false; │ │ │ │ - this.start = null; │ │ │ │ - this.last = null │ │ │ │ + this.layer.events.on({ │ │ │ │ + visibilitychanged: this.reset, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ } │ │ │ │ - return propagate │ │ │ │ + return activated │ │ │ │ }, │ │ │ │ - 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); │ │ │ │ - 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 │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.stop(); │ │ │ │ + this.layer.events.un({ │ │ │ │ + visibilitychanged: this.reset, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ } │ │ │ │ - return true │ │ │ │ + return deactivated │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + reset: function() { │ │ │ │ + if (this.layer.visibility === true) { │ │ │ │ + this.start() │ │ │ │ + } else { │ │ │ │ + this.stop() │ │ │ │ } │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - down: function(evt) {}, │ │ │ │ - move: function(evt) {}, │ │ │ │ - up: function(evt) {}, │ │ │ │ - out: function(evt) {}, │ │ │ │ - mousedown: function(evt) { │ │ │ │ - return this.dragstart(evt) │ │ │ │ - }, │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - return this.dragstart(evt) │ │ │ │ - }, │ │ │ │ - mousemove: function(evt) { │ │ │ │ - return this.dragmove(evt) │ │ │ │ - }, │ │ │ │ - touchmove: function(evt) { │ │ │ │ - return this.dragmove(evt) │ │ │ │ }, │ │ │ │ - removeTimeout: function() { │ │ │ │ - this.timeoutId = null; │ │ │ │ - if (this.dragging) { │ │ │ │ - this.mousemove(this.lastMoveEvt) │ │ │ │ + start: function() { │ │ │ │ + if (this.interval && typeof this.interval === "number" && this.interval > 0) { │ │ │ │ + this.timer = window.setInterval(OpenLayers.Function.bind(this.refresh, this), this.interval) │ │ │ │ } │ │ │ │ }, │ │ │ │ - mouseup: function(evt) { │ │ │ │ - return this.dragend(evt) │ │ │ │ - }, │ │ │ │ - touchend: function(evt) { │ │ │ │ - evt.xy = this.last; │ │ │ │ - return this.dragend(evt) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ + refresh: function() { │ │ │ │ + if (this.layer && this.layer.refresh && typeof this.layer.refresh == "function") { │ │ │ │ + this.layer.refresh({ │ │ │ │ + force: this.force │ │ │ │ + }) │ │ │ │ } │ │ │ │ - return true │ │ │ │ }, │ │ │ │ - click: function(evt) { │ │ │ │ - return this.start == this.last │ │ │ │ + stop: function() { │ │ │ │ + if (this.timer !== null) { │ │ │ │ + window.clearInterval(this.timer); │ │ │ │ + this.timer = null │ │ │ │ + } │ │ │ │ }, │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Refresh" │ │ │ │ +}); │ │ │ │ +OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + features: null, │ │ │ │ + length: 10, │ │ │ │ + num: null, │ │ │ │ + paging: false, │ │ │ │ activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.dragging = false; │ │ │ │ - activated = true │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + beforefeaturesadded: this.cacheFeatures, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ } │ │ │ │ return activated │ │ │ │ }, │ │ │ │ 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") │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.clearCache(); │ │ │ │ + this.layer.events.un({ │ │ │ │ + beforefeaturesadded: this.cacheFeatures, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ } │ │ │ │ return deactivated │ │ │ │ }, │ │ │ │ - adjustXY: function(evt) { │ │ │ │ - var pos = OpenLayers.Util.pagePosition(this.map.viewPortDiv); │ │ │ │ - evt.xy.x -= pos[0]; │ │ │ │ - evt.xy.y -= pos[1] │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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.Feature = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - 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" │ │ │ │ + cacheFeatures: function(event) { │ │ │ │ + if (!this.paging) { │ │ │ │ + this.clearCache(); │ │ │ │ + this.features = event.features; │ │ │ │ + this.pageNext(event) │ │ │ │ } │ │ │ │ }, │ │ │ │ - feature: null, │ │ │ │ - lastFeature: null, │ │ │ │ - down: null, │ │ │ │ - up: null, │ │ │ │ - clickTolerance: 4, │ │ │ │ - geometryTypes: null, │ │ │ │ - stopClick: true, │ │ │ │ - stopDown: true, │ │ │ │ - stopUp: false, │ │ │ │ - initialize: function(control, layer, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ - this.layer = layer │ │ │ │ - }, │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - return OpenLayers.Event.isMultiTouch(evt) ? true : this.mousedown(evt) │ │ │ │ - }, │ │ │ │ - touchmove: function(evt) { │ │ │ │ - OpenLayers.Event.preventDefault(evt) │ │ │ │ - }, │ │ │ │ - mousedown: function(evt) { │ │ │ │ - if (OpenLayers.Event.isLeftClick(evt) || OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ - this.down = evt.xy │ │ │ │ + clearCache: function() { │ │ │ │ + if (this.features) { │ │ │ │ + for (var i = 0; i < this.features.length; ++i) { │ │ │ │ + this.features[i].destroy() │ │ │ │ + } │ │ │ │ } │ │ │ │ - return this.handle(evt) ? !this.stopDown : true │ │ │ │ + this.features = null; │ │ │ │ + this.num = null │ │ │ │ }, │ │ │ │ - mouseup: function(evt) { │ │ │ │ - this.up = evt.xy; │ │ │ │ - return this.handle(evt) ? !this.stopUp : true │ │ │ │ + pageCount: function() { │ │ │ │ + var numFeatures = this.features ? this.features.length : 0; │ │ │ │ + return Math.ceil(numFeatures / this.length) │ │ │ │ }, │ │ │ │ - click: function(evt) { │ │ │ │ - return this.handle(evt) ? !this.stopClick : true │ │ │ │ + pageNum: function() { │ │ │ │ + return this.num │ │ │ │ }, │ │ │ │ - mousemove: function(evt) { │ │ │ │ - if (!this.callbacks["over"] && !this.callbacks["out"]) { │ │ │ │ - return true │ │ │ │ + pageLength: function(newLength) { │ │ │ │ + if (newLength && newLength > 0) { │ │ │ │ + this.length = newLength │ │ │ │ } │ │ │ │ - this.handle(evt); │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - dblclick: function(evt) { │ │ │ │ - return !this.handle(evt) │ │ │ │ - }, │ │ │ │ - geometryTypeMatches: function(feature) { │ │ │ │ - return this.geometryTypes == null || OpenLayers.Util.indexOf(this.geometryTypes, feature.geometry.CLASS_NAME) > -1 │ │ │ │ + return this.length │ │ │ │ }, │ │ │ │ - handle: function(evt) { │ │ │ │ - if (this.feature && !this.feature.layer) { │ │ │ │ - this.feature = null │ │ │ │ - } │ │ │ │ - var type = evt.type; │ │ │ │ - var handled = false; │ │ │ │ - var previouslyIn = !!this.feature; │ │ │ │ - var click = type == "click" || type == "dblclick" || type == "touchstart"; │ │ │ │ - this.feature = this.layer.getFeatureFromEvent(evt); │ │ │ │ - if (this.feature && !this.feature.layer) { │ │ │ │ - this.feature = null │ │ │ │ - } │ │ │ │ - if (this.lastFeature && !this.lastFeature.layer) { │ │ │ │ - this.lastFeature = null │ │ │ │ - } │ │ │ │ - if (this.feature) { │ │ │ │ - if (type === "touchstart") { │ │ │ │ - OpenLayers.Event.preventDefault(evt) │ │ │ │ + pageNext: function(event) { │ │ │ │ + var changed = false; │ │ │ │ + if (this.features) { │ │ │ │ + if (this.num === null) { │ │ │ │ + this.num = -1 │ │ │ │ } │ │ │ │ - var inNew = this.feature != this.lastFeature; │ │ │ │ - if (this.geometryTypeMatches(this.feature)) { │ │ │ │ - if (previouslyIn && inNew) { │ │ │ │ - if (this.lastFeature) { │ │ │ │ - this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ - } │ │ │ │ - this.triggerCallback(type, "in", [this.feature]) │ │ │ │ - } else if (!previouslyIn || click) { │ │ │ │ - this.triggerCallback(type, "in", [this.feature]) │ │ │ │ - } │ │ │ │ - this.lastFeature = this.feature; │ │ │ │ - handled = true │ │ │ │ - } else { │ │ │ │ - if (this.lastFeature && (previouslyIn && inNew || click)) { │ │ │ │ - this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ - } │ │ │ │ - this.feature = null │ │ │ │ + var start = (this.num + 1) * this.length; │ │ │ │ + changed = this.page(start, event) │ │ │ │ + } │ │ │ │ + return changed │ │ │ │ + }, │ │ │ │ + pagePrevious: function() { │ │ │ │ + var changed = false; │ │ │ │ + if (this.features) { │ │ │ │ + if (this.num === null) { │ │ │ │ + this.num = this.pageCount() │ │ │ │ } │ │ │ │ - } else if (this.lastFeature && (previouslyIn || click)) { │ │ │ │ - this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ + var start = (this.num - 1) * this.length; │ │ │ │ + changed = this.page(start) │ │ │ │ } │ │ │ │ - return handled │ │ │ │ + return changed │ │ │ │ }, │ │ │ │ - triggerCallback: function(type, mode, args) { │ │ │ │ - var key = this.EVENTMAP[type][mode]; │ │ │ │ - if (key) { │ │ │ │ - if (type == "click" && this.up && this.down) { │ │ │ │ - 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) │ │ │ │ + page: function(start, event) { │ │ │ │ + var changed = false; │ │ │ │ + if (this.features) { │ │ │ │ + if (start >= 0 && start < this.features.length) { │ │ │ │ + var num = Math.floor(start / this.length); │ │ │ │ + if (num != this.num) { │ │ │ │ + this.paging = true; │ │ │ │ + var features = this.features.slice(start, start + this.length); │ │ │ │ + this.layer.removeFeatures(this.layer.features); │ │ │ │ + this.num = num; │ │ │ │ + if (event && event.features) { │ │ │ │ + event.features = features │ │ │ │ + } else { │ │ │ │ + this.layer.addFeatures(features) │ │ │ │ + } │ │ │ │ + this.paging = false; │ │ │ │ + changed = true │ │ │ │ } │ │ │ │ - this.up = this.down = null │ │ │ │ - } else { │ │ │ │ - this.callback(key, args) │ │ │ │ } │ │ │ │ } │ │ │ │ + return changed │ │ │ │ }, │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Paging" │ │ │ │ +}); │ │ │ │ +OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + preload: false, │ │ │ │ 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, │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments); │ │ │ │ + if (activated) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + refresh: this.load, │ │ │ │ scope: this │ │ │ │ }); │ │ │ │ - activated = true │ │ │ │ + if (this.layer.visibility == true || this.preload) { │ │ │ │ + this.load() │ │ │ │ + } else { │ │ │ │ + this.layer.events.on({ │ │ │ │ + visibilitychanged: this.load, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ } │ │ │ │ return activated │ │ │ │ }, │ │ │ │ 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, │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.layer.events.un({ │ │ │ │ + refresh: this.load, │ │ │ │ + visibilitychanged: this.load, │ │ │ │ scope: this │ │ │ │ - }); │ │ │ │ - deactivated = true │ │ │ │ + }) │ │ │ │ } │ │ │ │ return deactivated │ │ │ │ }, │ │ │ │ - handleMapEvents: function(evt) { │ │ │ │ - if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ - this.moveLayerToTop() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - moveLayerToTop: function() { │ │ │ │ - var index = Math.max(this.map.Z_INDEX_BASE["Feature"] - 1, this.layer.getZIndex()) + 1; │ │ │ │ - this.layer.setZIndex(index) │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - 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)) │ │ │ │ + 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.Handler.Feature" │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Fixed" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.DragFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - geometryTypes: null, │ │ │ │ - onStart: function(feature, pixel) {}, │ │ │ │ - onDrag: function(feature, pixel) {}, │ │ │ │ - onComplete: function(feature, pixel) {}, │ │ │ │ - onEnter: function(feature) {}, │ │ │ │ - onLeave: function(feature) {}, │ │ │ │ - documentDrag: false, │ │ │ │ - layer: null, │ │ │ │ - feature: null, │ │ │ │ - dragCallbacks: {}, │ │ │ │ - featureCallbacks: {}, │ │ │ │ - lastPixel: null, │ │ │ │ - initialize: function(layer, options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.layer = layer; │ │ │ │ - this.handlers = { │ │ │ │ - drag: new OpenLayers.Handler.Drag(this, OpenLayers.Util.extend({ │ │ │ │ - down: this.downFeature, │ │ │ │ - move: this.moveFeature, │ │ │ │ - up: this.upFeature, │ │ │ │ - out: this.cancel, │ │ │ │ - done: this.doneDragging │ │ │ │ - }, this.dragCallbacks), { │ │ │ │ - documentDrag: this.documentDrag │ │ │ │ - }), │ │ │ │ - feature: new OpenLayers.Handler.Feature(this, this.layer, OpenLayers.Util.extend({ │ │ │ │ - click: this.clickFeature, │ │ │ │ - clickout: this.clickoutFeature, │ │ │ │ - over: this.overFeature, │ │ │ │ - out: this.outFeature │ │ │ │ - }, this.featureCallbacks), { │ │ │ │ - geometryTypes: this.geometryTypes │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clickFeature: function(feature) { │ │ │ │ - if (this.handlers.feature.touch && !this.over && this.overFeature(feature)) { │ │ │ │ - this.handlers.drag.dragstart(this.handlers.feature.evt); │ │ │ │ - this.handlers.drag.stopDown = false │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clickoutFeature: function(feature) { │ │ │ │ - if (this.handlers.feature.touch && this.over) { │ │ │ │ - this.outFeature(feature); │ │ │ │ - this.handlers.drag.stopDown = true │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.layer = null; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, []) │ │ │ │ +OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + events: null, │ │ │ │ + auto: false, │ │ │ │ + timer: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Strategy.prototype.initialize.apply(this, [options]); │ │ │ │ + this.events = new OpenLayers.Events(this) │ │ │ │ }, │ │ │ │ activate: function() { │ │ │ │ - return this.handlers.feature.activate() && OpenLayers.Control.prototype.activate.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ - this.handlers.feature.deactivate(); │ │ │ │ - this.feature = null; │ │ │ │ - this.dragging = false; │ │ │ │ - this.lastPixel = null; │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - overFeature: function(feature) { │ │ │ │ - var activated = false; │ │ │ │ - if (!this.handlers.drag.dragging) { │ │ │ │ - this.feature = feature; │ │ │ │ - this.handlers.drag.activate(); │ │ │ │ - activated = true; │ │ │ │ - this.over = true; │ │ │ │ - OpenLayers.Element.addClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ - this.onEnter(feature) │ │ │ │ - } else { │ │ │ │ - if (this.feature.id == feature.id) { │ │ │ │ - this.over = true │ │ │ │ - } else { │ │ │ │ - this.over = false │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + if (this.auto) { │ │ │ │ + if (typeof this.auto === "number") { │ │ │ │ + this.timer = window.setInterval(OpenLayers.Function.bind(this.save, this), this.auto * 1e3) │ │ │ │ + } else { │ │ │ │ + this.layer.events.on({ │ │ │ │ + featureadded: this.triggerSave, │ │ │ │ + afterfeaturemodified: this.triggerSave, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ return activated │ │ │ │ }, │ │ │ │ - downFeature: function(pixel) { │ │ │ │ - this.lastPixel = pixel; │ │ │ │ - this.onStart(this.feature, pixel) │ │ │ │ - }, │ │ │ │ - moveFeature: function(pixel) { │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - this.feature.geometry.move(res * (pixel.x - this.lastPixel.x), res * (this.lastPixel.y - pixel.y)); │ │ │ │ - this.layer.drawFeature(this.feature); │ │ │ │ - this.lastPixel = pixel; │ │ │ │ - this.onDrag(this.feature, pixel) │ │ │ │ - }, │ │ │ │ - upFeature: function(pixel) { │ │ │ │ - if (!this.over) { │ │ │ │ - this.handlers.drag.deactivate() │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + if (this.auto) { │ │ │ │ + if (typeof this.auto === "number") { │ │ │ │ + window.clearInterval(this.timer) │ │ │ │ + } else { │ │ │ │ + this.layer.events.un({ │ │ │ │ + featureadded: this.triggerSave, │ │ │ │ + afterfeaturemodified: this.triggerSave, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ + return deactivated │ │ │ │ }, │ │ │ │ - doneDragging: function(pixel) { │ │ │ │ - this.onComplete(this.feature, pixel) │ │ │ │ + triggerSave: function(event) { │ │ │ │ + var feature = event.feature; │ │ │ │ + if (feature.state === OpenLayers.State.INSERT || feature.state === OpenLayers.State.UPDATE || feature.state === OpenLayers.State.DELETE) { │ │ │ │ + this.save([event.feature]) │ │ │ │ + } │ │ │ │ }, │ │ │ │ - outFeature: function(feature) { │ │ │ │ - if (!this.handlers.drag.dragging) { │ │ │ │ - this.over = false; │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ - this.onLeave(feature); │ │ │ │ - this.feature = null │ │ │ │ - } else { │ │ │ │ - if (this.feature.id == feature.id) { │ │ │ │ - this.over = false │ │ │ │ + save: function(features) { │ │ │ │ + if (!features) { │ │ │ │ + features = this.layer.features │ │ │ │ + } │ │ │ │ + this.events.triggerEvent("start", { │ │ │ │ + features: features │ │ │ │ + }); │ │ │ │ + var remote = this.layer.projection; │ │ │ │ + var local = this.layer.map.getProjectionObject(); │ │ │ │ + if (!local.equals(remote)) { │ │ │ │ + var len = features.length; │ │ │ │ + var clones = new Array(len); │ │ │ │ + var orig, clone; │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ + orig = features[i]; │ │ │ │ + clone = orig.clone(); │ │ │ │ + clone.fid = orig.fid; │ │ │ │ + clone.state = orig.state; │ │ │ │ + if (orig.url) { │ │ │ │ + clone.url = orig.url │ │ │ │ + } │ │ │ │ + clone._original = orig; │ │ │ │ + clone.geometry.transform(local, remote); │ │ │ │ + clones[i] = clone │ │ │ │ } │ │ │ │ + features = clones │ │ │ │ } │ │ │ │ + this.layer.protocol.commit(features, { │ │ │ │ + callback: this.onCommit, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - cancel: function() { │ │ │ │ - this.handlers.drag.deactivate(); │ │ │ │ - this.over = false │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - this.handlers.drag.setMap(map); │ │ │ │ - this.handlers.feature.setMap(map); │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.DragFeature" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.RegularPolygon = OpenLayers.Class(OpenLayers.Handler.Drag, { │ │ │ │ - sides: 4, │ │ │ │ - radius: null, │ │ │ │ - snapAngle: null, │ │ │ │ - snapToggle: "shiftKey", │ │ │ │ - layerOptions: null, │ │ │ │ - persist: false, │ │ │ │ - irregular: false, │ │ │ │ - citeCompliant: false, │ │ │ │ - angle: null, │ │ │ │ - fixedRadius: false, │ │ │ │ - feature: null, │ │ │ │ - layer: null, │ │ │ │ - origin: null, │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - if (!(options && options.layerOptions && options.layerOptions.styleMap)) { │ │ │ │ - this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style["default"], {}) │ │ │ │ + onCommit: function(response) { │ │ │ │ + var evt = { │ │ │ │ + response: response │ │ │ │ + }; │ │ │ │ + if (response.success()) { │ │ │ │ + var features = response.reqFeatures; │ │ │ │ + var state, feature; │ │ │ │ + var destroys = []; │ │ │ │ + var insertIds = response.insertIds || []; │ │ │ │ + var j = 0; │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + feature = feature._original || feature; │ │ │ │ + state = feature.state; │ │ │ │ + if (state) { │ │ │ │ + if (state == OpenLayers.State.DELETE) { │ │ │ │ + destroys.push(feature) │ │ │ │ + } else if (state == OpenLayers.State.INSERT) { │ │ │ │ + feature.fid = insertIds[j]; │ │ │ │ + ++j │ │ │ │ + } │ │ │ │ + feature.state = null │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (destroys.length > 0) { │ │ │ │ + this.layer.destroyFeatures(destroys) │ │ │ │ + } │ │ │ │ + this.events.triggerEvent("success", evt) │ │ │ │ + } else { │ │ │ │ + this.events.triggerEvent("fail", evt) │ │ │ │ } │ │ │ │ - OpenLayers.Handler.Drag.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ - this.options = options ? options : {} │ │ │ │ - }, │ │ │ │ - setOptions: function(newOptions) { │ │ │ │ - OpenLayers.Util.extend(this.options, newOptions); │ │ │ │ - OpenLayers.Util.extend(this, newOptions) │ │ │ │ }, │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Save" │ │ │ │ +}); │ │ │ │ +OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ + bounds: null, │ │ │ │ + resolution: null, │ │ │ │ + ratio: 2, │ │ │ │ + resFactor: null, │ │ │ │ + response: null, │ │ │ │ activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (OpenLayers.Handler.Drag.prototype.activate.apply(this, arguments)) { │ │ │ │ - var options = OpenLayers.Util.extend({ │ │ │ │ - displayInLayerSwitcher: false, │ │ │ │ - calculateInRange: OpenLayers.Function.True, │ │ │ │ - wrapDateLine: this.citeCompliant │ │ │ │ - }, this.layerOptions); │ │ │ │ - this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options); │ │ │ │ - this.map.addLayer(this.layer); │ │ │ │ - activated = true │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + moveend: this.update, │ │ │ │ + refresh: this.update, │ │ │ │ + visibilitychanged: this.update, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.update() │ │ │ │ } │ │ │ │ return activated │ │ │ │ }, │ │ │ │ deactivate: function() { │ │ │ │ - var deactivated = false; │ │ │ │ - if (OpenLayers.Handler.Drag.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - if (this.dragging) { │ │ │ │ - this.cancel() │ │ │ │ - } │ │ │ │ - if (this.layer.map != null) { │ │ │ │ - this.layer.destroy(false); │ │ │ │ - if (this.feature) { │ │ │ │ - this.feature.destroy() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.layer = null; │ │ │ │ - this.feature = null; │ │ │ │ - deactivated = true │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + this.layer.events.un({ │ │ │ │ + moveend: this.update, │ │ │ │ + refresh: this.update, │ │ │ │ + visibilitychanged: this.update, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ } │ │ │ │ return deactivated │ │ │ │ }, │ │ │ │ - down: function(evt) { │ │ │ │ - this.fixedRadius = !!this.radius; │ │ │ │ - var maploc = this.layer.getLonLatFromViewPortPx(evt.xy); │ │ │ │ - this.origin = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat); │ │ │ │ - if (!this.fixedRadius || this.irregular) { │ │ │ │ - this.radius = this.map.getResolution() │ │ │ │ - } │ │ │ │ - if (this.persist) { │ │ │ │ - this.clear() │ │ │ │ + update: function(options) { │ │ │ │ + var mapBounds = this.getMapBounds(); │ │ │ │ + if (mapBounds !== null && (options && options.force || this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds))) { │ │ │ │ + this.calculateBounds(mapBounds); │ │ │ │ + this.resolution = this.layer.map.getResolution(); │ │ │ │ + this.triggerRead(options) │ │ │ │ } │ │ │ │ - this.feature = new OpenLayers.Feature.Vector; │ │ │ │ - this.createGeometry(); │ │ │ │ - this.callback("create", [this.origin, this.feature]); │ │ │ │ - this.layer.addFeatures([this.feature], { │ │ │ │ - silent: true │ │ │ │ - }); │ │ │ │ - this.layer.drawFeature(this.feature, this.style) │ │ │ │ }, │ │ │ │ - move: function(evt) { │ │ │ │ - var maploc = this.layer.getLonLatFromViewPortPx(evt.xy); │ │ │ │ - var point = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat); │ │ │ │ - if (this.irregular) { │ │ │ │ - var ry = Math.sqrt(2) * Math.abs(point.y - this.origin.y) / 2; │ │ │ │ - this.radius = Math.max(this.map.getResolution() / 2, ry) │ │ │ │ - } else if (this.fixedRadius) { │ │ │ │ - this.origin = point │ │ │ │ - } else { │ │ │ │ - this.calculateAngle(point, evt); │ │ │ │ - this.radius = Math.max(this.map.getResolution() / 2, point.distanceTo(this.origin)) │ │ │ │ + getMapBounds: function() { │ │ │ │ + if (this.layer.map === null) { │ │ │ │ + return null │ │ │ │ } │ │ │ │ - this.modifyGeometry(); │ │ │ │ - if (this.irregular) { │ │ │ │ - var dx = point.x - this.origin.x; │ │ │ │ - var dy = point.y - this.origin.y; │ │ │ │ - var ratio; │ │ │ │ - if (dy == 0) { │ │ │ │ - ratio = dx / (this.radius * Math.sqrt(2)) │ │ │ │ - } else { │ │ │ │ - ratio = dx / dy │ │ │ │ - } │ │ │ │ - this.feature.geometry.resize(1, this.origin, ratio); │ │ │ │ - this.feature.geometry.move(dx / 2, dy / 2) │ │ │ │ + var bounds = this.layer.map.getExtent(); │ │ │ │ + if (bounds && !this.layer.projection.equals(this.layer.map.getProjectionObject())) { │ │ │ │ + bounds = bounds.clone().transform(this.layer.map.getProjectionObject(), this.layer.projection) │ │ │ │ } │ │ │ │ - this.layer.drawFeature(this.feature, this.style) │ │ │ │ + return bounds │ │ │ │ }, │ │ │ │ - up: function(evt) { │ │ │ │ - this.finalize(); │ │ │ │ - if (this.start == this.last) { │ │ │ │ - this.callback("done", [evt.xy]) │ │ │ │ + invalidBounds: function(mapBounds) { │ │ │ │ + if (!mapBounds) { │ │ │ │ + mapBounds = this.getMapBounds() │ │ │ │ } │ │ │ │ - }, │ │ │ │ - out: function(evt) { │ │ │ │ - this.finalize() │ │ │ │ - }, │ │ │ │ - createGeometry: function() { │ │ │ │ - this.angle = Math.PI * (1 / this.sides - 1 / 2); │ │ │ │ - if (this.snapAngle) { │ │ │ │ - this.angle += this.snapAngle * (Math.PI / 180) │ │ │ │ + var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds); │ │ │ │ + if (!invalid && this.resFactor) { │ │ │ │ + var ratio = this.resolution / this.layer.map.getResolution(); │ │ │ │ + invalid = ratio >= this.resFactor || ratio <= 1 / this.resFactor │ │ │ │ } │ │ │ │ - this.feature.geometry = OpenLayers.Geometry.Polygon.createRegularPolygon(this.origin, this.radius, this.sides, this.snapAngle) │ │ │ │ + return invalid │ │ │ │ }, │ │ │ │ - modifyGeometry: function() { │ │ │ │ - var angle, point; │ │ │ │ - var ring = this.feature.geometry.components[0]; │ │ │ │ - if (ring.components.length != this.sides + 1) { │ │ │ │ - this.createGeometry(); │ │ │ │ - ring = this.feature.geometry.components[0] │ │ │ │ - } │ │ │ │ - for (var i = 0; i < this.sides; ++i) { │ │ │ │ - point = ring.components[i]; │ │ │ │ - angle = this.angle + i * 2 * Math.PI / this.sides; │ │ │ │ - point.x = this.origin.x + this.radius * Math.cos(angle); │ │ │ │ - point.y = this.origin.y + this.radius * Math.sin(angle); │ │ │ │ - point.clearBounds() │ │ │ │ + calculateBounds: function(mapBounds) { │ │ │ │ + if (!mapBounds) { │ │ │ │ + mapBounds = this.getMapBounds() │ │ │ │ } │ │ │ │ + var center = mapBounds.getCenterLonLat(); │ │ │ │ + var dataWidth = mapBounds.getWidth() * this.ratio; │ │ │ │ + var dataHeight = mapBounds.getHeight() * this.ratio; │ │ │ │ + this.bounds = new OpenLayers.Bounds(center.lon - dataWidth / 2, center.lat - dataHeight / 2, center.lon + dataWidth / 2, center.lat + dataHeight / 2) │ │ │ │ }, │ │ │ │ - calculateAngle: function(point, evt) { │ │ │ │ - var alpha = Math.atan2(point.y - this.origin.y, point.x - this.origin.x); │ │ │ │ - if (this.snapAngle && (this.snapToggle && !evt[this.snapToggle])) { │ │ │ │ - var snapAngleRad = Math.PI / 180 * this.snapAngle; │ │ │ │ - this.angle = Math.round(alpha / snapAngleRad) * snapAngleRad │ │ │ │ - } else { │ │ │ │ - this.angle = alpha │ │ │ │ + triggerRead: function(options) { │ │ │ │ + if (this.response && !(options && options.noAbort === true)) { │ │ │ │ + this.layer.protocol.abort(this.response); │ │ │ │ + this.layer.events.triggerEvent("loadend") │ │ │ │ } │ │ │ │ + var evt = { │ │ │ │ + filter: this.createFilter() │ │ │ │ + }; │ │ │ │ + this.layer.events.triggerEvent("loadstart", evt); │ │ │ │ + this.response = this.layer.protocol.read(OpenLayers.Util.applyDefaults({ │ │ │ │ + filter: evt.filter, │ │ │ │ + callback: this.merge, │ │ │ │ + scope: this │ │ │ │ + }, options)) │ │ │ │ }, │ │ │ │ - cancel: function() { │ │ │ │ - this.callback("cancel", null); │ │ │ │ - this.finalize() │ │ │ │ - }, │ │ │ │ - finalize: function() { │ │ │ │ - this.origin = null; │ │ │ │ - this.radius = this.options.radius │ │ │ │ - }, │ │ │ │ - clear: function() { │ │ │ │ - if (this.layer) { │ │ │ │ - this.layer.renderer.clear(); │ │ │ │ - this.layer.destroyFeatures() │ │ │ │ + createFilter: function() { │ │ │ │ + var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ + value: this.bounds, │ │ │ │ + projection: this.layer.projection │ │ │ │ + }); │ │ │ │ + if (this.layer.filter) { │ │ │ │ + filter = new OpenLayers.Filter.Logical({ │ │ │ │ + type: OpenLayers.Filter.Logical.AND, │ │ │ │ + filters: [this.layer.filter, filter] │ │ │ │ + }) │ │ │ │ } │ │ │ │ + return filter │ │ │ │ }, │ │ │ │ - callback: function(name, args) { │ │ │ │ - if (this.callbacks[name]) { │ │ │ │ - this.callbacks[name].apply(this.control, [this.feature.geometry.clone()]) │ │ │ │ - } │ │ │ │ - if (!this.persist && (name == "done" || name == "cancel")) { │ │ │ │ - this.clear() │ │ │ │ + merge: function(resp) { │ │ │ │ + this.layer.destroyFeatures(); │ │ │ │ + if (resp.success()) { │ │ │ │ + var features = resp.features; │ │ │ │ + if (features && features.length > 0) { │ │ │ │ + var remote = this.layer.projection; │ │ │ │ + var local = this.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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.layer.addFeatures(features) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.bounds = null │ │ │ │ } │ │ │ │ + this.response = null; │ │ │ │ + this.layer.events.triggerEvent("loadend", { │ │ │ │ + response: resp │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.RegularPolygon" │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.BBOX" │ │ │ │ }); │ │ │ │ OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ point: null, │ │ │ │ layer: null, │ │ │ │ multi: false, │ │ │ │ citeCompliant: false, │ │ │ │ mouseDown: false, │ │ │ │ @@ -23272,332 +21938,5131 @@ │ │ │ │ if (geometry && this.multi) { │ │ │ │ geometry = new OpenLayers.Geometry.MultiPolygon([geometry]) │ │ │ │ } │ │ │ │ return geometry │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Handler.Polygon" │ │ │ │ }); │ │ │ │ -OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - delay: 300, │ │ │ │ - single: true, │ │ │ │ - double: false, │ │ │ │ - pixelTolerance: 0, │ │ │ │ - dblclickTolerance: 13, │ │ │ │ - stopSingle: false, │ │ │ │ - stopDouble: false, │ │ │ │ +OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + delay: 500, │ │ │ │ + pixelTolerance: null, │ │ │ │ + stopMove: false, │ │ │ │ + px: null, │ │ │ │ timerId: null, │ │ │ │ - down: null, │ │ │ │ - last: null, │ │ │ │ - first: null, │ │ │ │ - rightclickTimerId: null, │ │ │ │ - touchstart: function(evt) { │ │ │ │ - this.startTouch(); │ │ │ │ - this.down = this.getEventInfo(evt); │ │ │ │ - this.last = this.getEventInfo(evt); │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - touchmove: function(evt) { │ │ │ │ - this.last = this.getEventInfo(evt); │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - touchend: function(evt) { │ │ │ │ - if (this.down) { │ │ │ │ - evt.xy = this.last.xy; │ │ │ │ - evt.lastTouches = this.last.touches; │ │ │ │ - this.handleSingle(evt); │ │ │ │ - this.down = null │ │ │ │ + mousemove: function(evt) { │ │ │ │ + if (this.passesTolerance(evt.xy)) { │ │ │ │ + this.clearTimer(); │ │ │ │ + this.callback("move", [evt]); │ │ │ │ + this.px = evt.xy; │ │ │ │ + evt = OpenLayers.Util.extend({}, evt); │ │ │ │ + this.timerId = window.setTimeout(OpenLayers.Function.bind(this.delayedCall, this, evt), this.delay) │ │ │ │ } │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - mousedown: function(evt) { │ │ │ │ - this.down = this.getEventInfo(evt); │ │ │ │ - this.last = this.getEventInfo(evt); │ │ │ │ - return true │ │ │ │ + return !this.stopMove │ │ │ │ }, │ │ │ │ - mouseup: function(evt) { │ │ │ │ - var propagate = true; │ │ │ │ - if (this.checkModifiers(evt) && this.control.handleRightClicks && OpenLayers.Event.isRightClick(evt)) { │ │ │ │ - propagate = this.rightclick(evt) │ │ │ │ + mouseout: function(evt) { │ │ │ │ + if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ + this.clearTimer(); │ │ │ │ + this.callback("move", [evt]) │ │ │ │ } │ │ │ │ - return propagate │ │ │ │ + return true │ │ │ │ }, │ │ │ │ - rightclick: function(evt) { │ │ │ │ - if (this.passesTolerance(evt)) { │ │ │ │ - if (this.rightclickTimerId != null) { │ │ │ │ - this.clearTimer(); │ │ │ │ - this.callback("dblrightclick", [evt]); │ │ │ │ - return !this.stopDouble │ │ │ │ - } else { │ │ │ │ - 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) │ │ │ │ + passesTolerance: function(px) { │ │ │ │ + var passes = true; │ │ │ │ + if (this.pixelTolerance && this.px) { │ │ │ │ + var dpx = Math.sqrt(Math.pow(this.px.x - px.x, 2) + Math.pow(this.px.y - px.y, 2)); │ │ │ │ + if (dpx < this.pixelTolerance) { │ │ │ │ + passes = false │ │ │ │ } │ │ │ │ } │ │ │ │ - return !this.stopSingle │ │ │ │ + return passes │ │ │ │ }, │ │ │ │ - delayedRightCall: function(evt) { │ │ │ │ - this.rightclickTimerId = null; │ │ │ │ - if (evt) { │ │ │ │ - this.callback("rightclick", [evt]) │ │ │ │ + clearTimer: function() { │ │ │ │ + if (this.timerId != null) { │ │ │ │ + window.clearTimeout(this.timerId); │ │ │ │ + this.timerId = null │ │ │ │ } │ │ │ │ }, │ │ │ │ - click: function(evt) { │ │ │ │ - if (!this.last) { │ │ │ │ - this.last = this.getEventInfo(evt) │ │ │ │ + delayedCall: function(evt) { │ │ │ │ + this.callback("pause", [evt]) │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = false; │ │ │ │ + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + this.clearTimer(); │ │ │ │ + deactivated = true │ │ │ │ } │ │ │ │ - this.handleSingle(evt); │ │ │ │ - return !this.stopSingle │ │ │ │ + return deactivated │ │ │ │ }, │ │ │ │ - dblclick: function(evt) { │ │ │ │ - this.handleDouble(evt); │ │ │ │ - return !this.stopDouble │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Hover" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + started: false, │ │ │ │ + stopDown: true, │ │ │ │ + dragging: false, │ │ │ │ + last: null, │ │ │ │ + start: null, │ │ │ │ + lastMoveEvt: null, │ │ │ │ + oldOnselectstart: null, │ │ │ │ + interval: 0, │ │ │ │ + timeoutId: null, │ │ │ │ + documentDrag: false, │ │ │ │ + documentEvents: null, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ - handleDouble: function(evt) { │ │ │ │ - if (this.passesDblclickTolerance(evt)) { │ │ │ │ - if (this["double"]) { │ │ │ │ - this.callback("dblclick", [evt]) │ │ │ │ + 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]); │ │ │ │ + OpenLayers.Event.preventDefault(evt); │ │ │ │ + if (!this.oldOnselectstart) { │ │ │ │ + this.oldOnselectstart = document.onselectstart ? document.onselectstart : OpenLayers.Function.True │ │ │ │ } │ │ │ │ - this.clearTimer() │ │ │ │ + document.onselectstart = OpenLayers.Function.False; │ │ │ │ + propagate = !this.stopDown │ │ │ │ + } else { │ │ │ │ + this.started = false; │ │ │ │ + this.start = null; │ │ │ │ + this.last = null │ │ │ │ } │ │ │ │ + return propagate │ │ │ │ }, │ │ │ │ - handleSingle: function(evt) { │ │ │ │ - if (this.passesTolerance(evt)) { │ │ │ │ - if (this.timerId != null) { │ │ │ │ - if (this.last.touches && this.last.touches.length === 1) { │ │ │ │ - if (this["double"]) { │ │ │ │ - OpenLayers.Event.preventDefault(evt) │ │ │ │ - } │ │ │ │ - this.handleDouble(evt) │ │ │ │ - } │ │ │ │ - if (!this.last.touches || this.last.touches.length !== 2) { │ │ │ │ - this.clearTimer() │ │ │ │ + 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); │ │ │ │ + this.setEvent(evt) │ │ │ │ + } else { │ │ │ │ + this.removeDocumentEvents() │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - this.first = this.getEventInfo(evt); │ │ │ │ - var clickEvent = this.single ? OpenLayers.Util.extend({}, evt) : null; │ │ │ │ - this.queuePotentialClick(clickEvent) │ │ │ │ } │ │ │ │ + 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 │ │ │ │ }, │ │ │ │ - queuePotentialClick: function(evt) { │ │ │ │ - this.timerId = window.setTimeout(OpenLayers.Function.bind(this.delayedCall, this, evt), this.delay) │ │ │ │ - }, │ │ │ │ - passesTolerance: function(evt) { │ │ │ │ - var passes = true; │ │ │ │ - if (this.pixelTolerance != null && this.down && this.down.xy) { │ │ │ │ - passes = this.pixelTolerance >= this.down.xy.distanceTo(evt.xy); │ │ │ │ - if (passes && this.touch && this.down.touches.length === this.last.touches.length) { │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - } │ │ │ │ + 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 passes │ │ │ │ + return true │ │ │ │ }, │ │ │ │ - getTouchDistance: function(from, to) { │ │ │ │ - return Math.sqrt(Math.pow(from.clientX - to.clientX, 2) + Math.pow(from.clientY - to.clientY, 2)) │ │ │ │ + down: function(evt) {}, │ │ │ │ + move: function(evt) {}, │ │ │ │ + up: function(evt) {}, │ │ │ │ + out: function(evt) {}, │ │ │ │ + mousedown: function(evt) { │ │ │ │ + return this.dragstart(evt) │ │ │ │ }, │ │ │ │ - passesDblclickTolerance: function(evt) { │ │ │ │ - var passes = true; │ │ │ │ - if (this.down && this.first) { │ │ │ │ - passes = this.down.xy.distanceTo(this.first.xy) <= this.dblclickTolerance │ │ │ │ - } │ │ │ │ - return passes │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + return this.dragstart(evt) │ │ │ │ }, │ │ │ │ - clearTimer: function() { │ │ │ │ - if (this.timerId != null) { │ │ │ │ - window.clearTimeout(this.timerId); │ │ │ │ - this.timerId = null │ │ │ │ - } │ │ │ │ - if (this.rightclickTimerId != null) { │ │ │ │ - window.clearTimeout(this.rightclickTimerId); │ │ │ │ - this.rightclickTimerId = null │ │ │ │ - } │ │ │ │ + mousemove: function(evt) { │ │ │ │ + return this.dragmove(evt) │ │ │ │ }, │ │ │ │ - delayedCall: function(evt) { │ │ │ │ - this.timerId = null; │ │ │ │ - if (evt) { │ │ │ │ - this.callback("click", [evt]) │ │ │ │ + touchmove: function(evt) { │ │ │ │ + return this.dragmove(evt) │ │ │ │ + }, │ │ │ │ + removeTimeout: function() { │ │ │ │ + this.timeoutId = null; │ │ │ │ + if (this.dragging) { │ │ │ │ + this.mousemove(this.lastMoveEvt) │ │ │ │ } │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + mouseup: function(evt) { │ │ │ │ + return this.dragend(evt) │ │ │ │ + }, │ │ │ │ + touchend: function(evt) { │ │ │ │ + evt.xy = this.last; │ │ │ │ + return this.dragend(evt) │ │ │ │ + }, │ │ │ │ + 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 { │ │ │ │ - xy: evt.xy, │ │ │ │ - touches: touches │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + click: function(evt) { │ │ │ │ + return this.start == this.last │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + var activated = false; │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.dragging = false; │ │ │ │ + activated = true │ │ │ │ } │ │ │ │ + return activated │ │ │ │ }, │ │ │ │ deactivate: function() { │ │ │ │ var deactivated = false; │ │ │ │ if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - this.clearTimer(); │ │ │ │ - this.down = null; │ │ │ │ - this.first = null; │ │ │ │ + this.started = false; │ │ │ │ + this.dragging = false; │ │ │ │ + this.start = null; │ │ │ │ this.last = null; │ │ │ │ - deactivated = true │ │ │ │ + deactivated = true; │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olDragDown") │ │ │ │ } │ │ │ │ return deactivated │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Click" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.SLD = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - profile: null, │ │ │ │ - defaultVersion: "1.0.0", │ │ │ │ - stringifyOutput: true, │ │ │ │ - namedLayersAsArray: false, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SLD" │ │ │ │ + adjustXY: function(evt) { │ │ │ │ + var pos = OpenLayers.Util.pagePosition(this.map.viewPortDiv); │ │ │ │ + evt.xy.x -= pos[0]; │ │ │ │ + evt.xy.y -= pos[1] │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, { │ │ │ │ - schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd", │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]) │ │ │ │ +OpenLayers.Handler.RegularPolygon = OpenLayers.Class(OpenLayers.Handler.Drag, { │ │ │ │ + sides: 4, │ │ │ │ + radius: null, │ │ │ │ + snapAngle: null, │ │ │ │ + snapToggle: "shiftKey", │ │ │ │ + layerOptions: null, │ │ │ │ + persist: false, │ │ │ │ + irregular: false, │ │ │ │ + citeCompliant: false, │ │ │ │ + angle: null, │ │ │ │ + fixedRadius: false, │ │ │ │ + feature: null, │ │ │ │ + layer: null, │ │ │ │ + origin: null, │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + if (!(options && options.layerOptions && options.layerOptions.styleMap)) { │ │ │ │ + this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style["default"], {}) │ │ │ │ + } │ │ │ │ + OpenLayers.Handler.Drag.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ + this.options = options ? options : {} │ │ │ │ }, │ │ │ │ - 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"] │ │ │ │ + setOptions: function(newOptions) { │ │ │ │ + OpenLayers.Util.extend(this.options, newOptions); │ │ │ │ + OpenLayers.Util.extend(this, newOptions) │ │ │ │ }, │ │ │ │ - write: function(features) { │ │ │ │ - var name; │ │ │ │ - if (OpenLayers.Util.isArray(features)) { │ │ │ │ - name = "wfs:FeatureCollection" │ │ │ │ - } else { │ │ │ │ - name = "gml:featureMember" │ │ │ │ + activate: function() { │ │ │ │ + var activated = false; │ │ │ │ + if (OpenLayers.Handler.Drag.prototype.activate.apply(this, arguments)) { │ │ │ │ + var options = OpenLayers.Util.extend({ │ │ │ │ + displayInLayerSwitcher: false, │ │ │ │ + calculateInRange: OpenLayers.Function.True, │ │ │ │ + wrapDateLine: this.citeCompliant │ │ │ │ + }, this.layerOptions); │ │ │ │ + this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options); │ │ │ │ + this.map.addLayer(this.layer); │ │ │ │ + activated = true │ │ │ │ } │ │ │ │ - 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]) │ │ │ │ + return activated │ │ │ │ }, │ │ │ │ - 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) { │ │ │ │ - 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); │ │ │ │ - if (this.srsName) { │ │ │ │ - node.setAttribute("srsName", this.srsName) │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = false; │ │ │ │ + if (OpenLayers.Handler.Drag.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + if (this.dragging) { │ │ │ │ + this.cancel() │ │ │ │ + } │ │ │ │ + if (this.layer.map != null) { │ │ │ │ + this.layer.destroy(false); │ │ │ │ + if (this.feature) { │ │ │ │ + this.feature.destroy() │ │ │ │ } │ │ │ │ - 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.Format.Filter.v1_0_0 = OpenLayers.Class(OpenLayers.Format.GML.v2, OpenLayers.Format.Filter.v1, { │ │ │ │ - VERSION: "1.0.0", │ │ │ │ - schemaLocation: "http://www.opengis.net/ogc/filter/1.0.0/filter.xsd", │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.GML.v2.prototype.initialize.apply(this, [options]) │ │ │ │ + this.layer = null; │ │ │ │ + this.feature = null; │ │ │ │ + deactivated = true │ │ │ │ + } │ │ │ │ + return deactivated │ │ │ │ }, │ │ │ │ - readers: { │ │ │ │ - ogc: OpenLayers.Util.applyDefaults({ │ │ │ │ - PropertyIsEqualTo: function(node, obj) { │ │ │ │ - var filter = new OpenLayers.Filter.Comparison({ │ │ │ │ - type: OpenLayers.Filter.Comparison.EQUAL_TO │ │ │ │ - }); │ │ │ │ + down: function(evt) { │ │ │ │ + this.fixedRadius = !!this.radius; │ │ │ │ + var maploc = this.layer.getLonLatFromViewPortPx(evt.xy); │ │ │ │ + this.origin = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat); │ │ │ │ + if (!this.fixedRadius || this.irregular) { │ │ │ │ + this.radius = this.map.getResolution() │ │ │ │ + } │ │ │ │ + if (this.persist) { │ │ │ │ + this.clear() │ │ │ │ + } │ │ │ │ + this.feature = new OpenLayers.Feature.Vector; │ │ │ │ + this.createGeometry(); │ │ │ │ + this.callback("create", [this.origin, this.feature]); │ │ │ │ + this.layer.addFeatures([this.feature], { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + this.layer.drawFeature(this.feature, this.style) │ │ │ │ + }, │ │ │ │ + move: function(evt) { │ │ │ │ + var maploc = this.layer.getLonLatFromViewPortPx(evt.xy); │ │ │ │ + var point = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat); │ │ │ │ + if (this.irregular) { │ │ │ │ + var ry = Math.sqrt(2) * Math.abs(point.y - this.origin.y) / 2; │ │ │ │ + this.radius = Math.max(this.map.getResolution() / 2, ry) │ │ │ │ + } else if (this.fixedRadius) { │ │ │ │ + this.origin = point │ │ │ │ + } else { │ │ │ │ + this.calculateAngle(point, evt); │ │ │ │ + this.radius = Math.max(this.map.getResolution() / 2, point.distanceTo(this.origin)) │ │ │ │ + } │ │ │ │ + this.modifyGeometry(); │ │ │ │ + if (this.irregular) { │ │ │ │ + var dx = point.x - this.origin.x; │ │ │ │ + var dy = point.y - this.origin.y; │ │ │ │ + var ratio; │ │ │ │ + if (dy == 0) { │ │ │ │ + ratio = dx / (this.radius * Math.sqrt(2)) │ │ │ │ + } else { │ │ │ │ + ratio = dx / dy │ │ │ │ + } │ │ │ │ + this.feature.geometry.resize(1, this.origin, ratio); │ │ │ │ + this.feature.geometry.move(dx / 2, dy / 2) │ │ │ │ + } │ │ │ │ + this.layer.drawFeature(this.feature, this.style) │ │ │ │ + }, │ │ │ │ + up: function(evt) { │ │ │ │ + this.finalize(); │ │ │ │ + if (this.start == this.last) { │ │ │ │ + this.callback("done", [evt.xy]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + out: function(evt) { │ │ │ │ + this.finalize() │ │ │ │ + }, │ │ │ │ + createGeometry: function() { │ │ │ │ + this.angle = Math.PI * (1 / this.sides - 1 / 2); │ │ │ │ + if (this.snapAngle) { │ │ │ │ + this.angle += this.snapAngle * (Math.PI / 180) │ │ │ │ + } │ │ │ │ + this.feature.geometry = OpenLayers.Geometry.Polygon.createRegularPolygon(this.origin, this.radius, this.sides, this.snapAngle) │ │ │ │ + }, │ │ │ │ + modifyGeometry: function() { │ │ │ │ + var angle, point; │ │ │ │ + var ring = this.feature.geometry.components[0]; │ │ │ │ + if (ring.components.length != this.sides + 1) { │ │ │ │ + this.createGeometry(); │ │ │ │ + ring = this.feature.geometry.components[0] │ │ │ │ + } │ │ │ │ + for (var i = 0; i < this.sides; ++i) { │ │ │ │ + point = ring.components[i]; │ │ │ │ + angle = this.angle + i * 2 * Math.PI / this.sides; │ │ │ │ + point.x = this.origin.x + this.radius * Math.cos(angle); │ │ │ │ + point.y = this.origin.y + this.radius * Math.sin(angle); │ │ │ │ + point.clearBounds() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + calculateAngle: function(point, evt) { │ │ │ │ + var alpha = Math.atan2(point.y - this.origin.y, point.x - this.origin.x); │ │ │ │ + if (this.snapAngle && (this.snapToggle && !evt[this.snapToggle])) { │ │ │ │ + var snapAngleRad = Math.PI / 180 * this.snapAngle; │ │ │ │ + this.angle = Math.round(alpha / snapAngleRad) * snapAngleRad │ │ │ │ + } else { │ │ │ │ + this.angle = alpha │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + cancel: function() { │ │ │ │ + this.callback("cancel", null); │ │ │ │ + this.finalize() │ │ │ │ + }, │ │ │ │ + finalize: function() { │ │ │ │ + this.origin = null; │ │ │ │ + this.radius = this.options.radius │ │ │ │ + }, │ │ │ │ + clear: function() { │ │ │ │ + if (this.layer) { │ │ │ │ + this.layer.renderer.clear(); │ │ │ │ + this.layer.destroyFeatures() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + callback: function(name, args) { │ │ │ │ + if (this.callbacks[name]) { │ │ │ │ + this.callbacks[name].apply(this.control, [this.feature.geometry.clone()]) │ │ │ │ + } │ │ │ │ + if (!this.persist && (name == "done" || name == "cancel")) { │ │ │ │ + this.clear() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.RegularPolygon" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + 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" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + feature: null, │ │ │ │ + lastFeature: null, │ │ │ │ + down: null, │ │ │ │ + up: null, │ │ │ │ + clickTolerance: 4, │ │ │ │ + geometryTypes: null, │ │ │ │ + stopClick: true, │ │ │ │ + stopDown: true, │ │ │ │ + stopUp: false, │ │ │ │ + initialize: function(control, layer, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ + this.layer = layer │ │ │ │ + }, │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + return OpenLayers.Event.isMultiTouch(evt) ? true : this.mousedown(evt) │ │ │ │ + }, │ │ │ │ + touchmove: function(evt) { │ │ │ │ + OpenLayers.Event.preventDefault(evt) │ │ │ │ + }, │ │ │ │ + mousedown: function(evt) { │ │ │ │ + if (OpenLayers.Event.isLeftClick(evt) || OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ + this.down = evt.xy │ │ │ │ + } │ │ │ │ + return this.handle(evt) ? !this.stopDown : true │ │ │ │ + }, │ │ │ │ + mouseup: function(evt) { │ │ │ │ + this.up = evt.xy; │ │ │ │ + return this.handle(evt) ? !this.stopUp : true │ │ │ │ + }, │ │ │ │ + click: function(evt) { │ │ │ │ + return this.handle(evt) ? !this.stopClick : true │ │ │ │ + }, │ │ │ │ + mousemove: function(evt) { │ │ │ │ + if (!this.callbacks["over"] && !this.callbacks["out"]) { │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + this.handle(evt); │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + dblclick: function(evt) { │ │ │ │ + return !this.handle(evt) │ │ │ │ + }, │ │ │ │ + geometryTypeMatches: function(feature) { │ │ │ │ + return this.geometryTypes == null || OpenLayers.Util.indexOf(this.geometryTypes, feature.geometry.CLASS_NAME) > -1 │ │ │ │ + }, │ │ │ │ + handle: function(evt) { │ │ │ │ + if (this.feature && !this.feature.layer) { │ │ │ │ + this.feature = null │ │ │ │ + } │ │ │ │ + var type = evt.type; │ │ │ │ + var handled = false; │ │ │ │ + var previouslyIn = !!this.feature; │ │ │ │ + var click = type == "click" || type == "dblclick" || type == "touchstart"; │ │ │ │ + this.feature = this.layer.getFeatureFromEvent(evt); │ │ │ │ + if (this.feature && !this.feature.layer) { │ │ │ │ + this.feature = null │ │ │ │ + } │ │ │ │ + if (this.lastFeature && !this.lastFeature.layer) { │ │ │ │ + this.lastFeature = null │ │ │ │ + } │ │ │ │ + if (this.feature) { │ │ │ │ + if (type === "touchstart") { │ │ │ │ + OpenLayers.Event.preventDefault(evt) │ │ │ │ + } │ │ │ │ + var inNew = this.feature != this.lastFeature; │ │ │ │ + if (this.geometryTypeMatches(this.feature)) { │ │ │ │ + if (previouslyIn && inNew) { │ │ │ │ + if (this.lastFeature) { │ │ │ │ + this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ + } │ │ │ │ + this.triggerCallback(type, "in", [this.feature]) │ │ │ │ + } else if (!previouslyIn || click) { │ │ │ │ + this.triggerCallback(type, "in", [this.feature]) │ │ │ │ + } │ │ │ │ + this.lastFeature = this.feature; │ │ │ │ + handled = true │ │ │ │ + } else { │ │ │ │ + if (this.lastFeature && (previouslyIn && inNew || click)) { │ │ │ │ + this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ + } │ │ │ │ + this.feature = null │ │ │ │ + } │ │ │ │ + } else if (this.lastFeature && (previouslyIn || click)) { │ │ │ │ + this.triggerCallback(type, "out", [this.lastFeature]) │ │ │ │ + } │ │ │ │ + return handled │ │ │ │ + }, │ │ │ │ + triggerCallback: function(type, mode, args) { │ │ │ │ + var key = this.EVENTMAP[type][mode]; │ │ │ │ + if (key) { │ │ │ │ + if (type == "click" && this.up && this.down) { │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + this.up = this.down = null │ │ │ │ + } else { │ │ │ │ + this.callback(key, args) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleMapEvents: function(evt) { │ │ │ │ + if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ + this.moveLayerToTop() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + moveLayerToTop: function() { │ │ │ │ + var index = Math.max(this.map.Z_INDEX_BASE["Feature"] - 1, this.layer.getZIndex()) + 1; │ │ │ │ + this.layer.setZIndex(index) │ │ │ │ + }, │ │ │ │ + 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.Handler.Click = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + delay: 300, │ │ │ │ + single: true, │ │ │ │ + double: false, │ │ │ │ + pixelTolerance: 0, │ │ │ │ + dblclickTolerance: 13, │ │ │ │ + stopSingle: false, │ │ │ │ + stopDouble: false, │ │ │ │ + timerId: null, │ │ │ │ + down: null, │ │ │ │ + last: null, │ │ │ │ + first: null, │ │ │ │ + rightclickTimerId: null, │ │ │ │ + touchstart: function(evt) { │ │ │ │ + this.startTouch(); │ │ │ │ + this.down = this.getEventInfo(evt); │ │ │ │ + this.last = this.getEventInfo(evt); │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + touchmove: function(evt) { │ │ │ │ + this.last = this.getEventInfo(evt); │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + touchend: function(evt) { │ │ │ │ + if (this.down) { │ │ │ │ + evt.xy = this.last.xy; │ │ │ │ + evt.lastTouches = this.last.touches; │ │ │ │ + this.handleSingle(evt); │ │ │ │ + this.down = null │ │ │ │ + } │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + mousedown: function(evt) { │ │ │ │ + this.down = this.getEventInfo(evt); │ │ │ │ + this.last = this.getEventInfo(evt); │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + mouseup: function(evt) { │ │ │ │ + var propagate = true; │ │ │ │ + if (this.checkModifiers(evt) && this.control.handleRightClicks && OpenLayers.Event.isRightClick(evt)) { │ │ │ │ + propagate = this.rightclick(evt) │ │ │ │ + } │ │ │ │ + return propagate │ │ │ │ + }, │ │ │ │ + rightclick: function(evt) { │ │ │ │ + if (this.passesTolerance(evt)) { │ │ │ │ + if (this.rightclickTimerId != null) { │ │ │ │ + this.clearTimer(); │ │ │ │ + this.callback("dblrightclick", [evt]); │ │ │ │ + return !this.stopDouble │ │ │ │ + } else { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + delayedRightCall: function(evt) { │ │ │ │ + this.rightclickTimerId = null; │ │ │ │ + if (evt) { │ │ │ │ + this.callback("rightclick", [evt]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + click: function(evt) { │ │ │ │ + if (!this.last) { │ │ │ │ + this.last = this.getEventInfo(evt) │ │ │ │ + } │ │ │ │ + this.handleSingle(evt); │ │ │ │ + return !this.stopSingle │ │ │ │ + }, │ │ │ │ + dblclick: function(evt) { │ │ │ │ + this.handleDouble(evt); │ │ │ │ + return !this.stopDouble │ │ │ │ + }, │ │ │ │ + handleDouble: function(evt) { │ │ │ │ + if (this.passesDblclickTolerance(evt)) { │ │ │ │ + if (this["double"]) { │ │ │ │ + this.callback("dblclick", [evt]) │ │ │ │ + } │ │ │ │ + this.clearTimer() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + handleSingle: function(evt) { │ │ │ │ + if (this.passesTolerance(evt)) { │ │ │ │ + if (this.timerId != null) { │ │ │ │ + if (this.last.touches && this.last.touches.length === 1) { │ │ │ │ + if (this["double"]) { │ │ │ │ + OpenLayers.Event.preventDefault(evt) │ │ │ │ + } │ │ │ │ + this.handleDouble(evt) │ │ │ │ + } │ │ │ │ + if (!this.last.touches || this.last.touches.length !== 2) { │ │ │ │ + this.clearTimer() │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.first = this.getEventInfo(evt); │ │ │ │ + var clickEvent = this.single ? OpenLayers.Util.extend({}, evt) : null; │ │ │ │ + this.queuePotentialClick(clickEvent) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + queuePotentialClick: function(evt) { │ │ │ │ + this.timerId = window.setTimeout(OpenLayers.Function.bind(this.delayedCall, this, evt), this.delay) │ │ │ │ + }, │ │ │ │ + passesTolerance: function(evt) { │ │ │ │ + var passes = true; │ │ │ │ + if (this.pixelTolerance != null && this.down && this.down.xy) { │ │ │ │ + passes = this.pixelTolerance >= this.down.xy.distanceTo(evt.xy); │ │ │ │ + if (passes && this.touch && this.down.touches.length === this.last.touches.length) { │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + getTouchDistance: function(from, to) { │ │ │ │ + return Math.sqrt(Math.pow(from.clientX - to.clientX, 2) + Math.pow(from.clientY - to.clientY, 2)) │ │ │ │ + }, │ │ │ │ + passesDblclickTolerance: function(evt) { │ │ │ │ + var passes = true; │ │ │ │ + if (this.down && this.first) { │ │ │ │ + passes = this.down.xy.distanceTo(this.first.xy) <= this.dblclickTolerance │ │ │ │ + } │ │ │ │ + return passes │ │ │ │ + }, │ │ │ │ + clearTimer: function() { │ │ │ │ + if (this.timerId != null) { │ │ │ │ + window.clearTimeout(this.timerId); │ │ │ │ + this.timerId = null │ │ │ │ + } │ │ │ │ + if (this.rightclickTimerId != null) { │ │ │ │ + window.clearTimeout(this.rightclickTimerId); │ │ │ │ + this.rightclickTimerId = null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + delayedCall: function(evt) { │ │ │ │ + this.timerId = null; │ │ │ │ + if (evt) { │ │ │ │ + this.callback("click", [evt]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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.Handler.Keyboard = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + KEY_EVENTS: ["keydown", "keyup"], │ │ │ │ + eventListener: null, │ │ │ │ + observeElement: null, │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ + this.eventListener = OpenLayers.Function.bindAsEventListener(this.handleKeyEvent, this) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + this.eventListener = null; │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleKeyEvent: function(evt) { │ │ │ │ + if (this.checkModifiers(evt)) { │ │ │ │ + this.callback(evt.type, [evt]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Keyboard" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + dragHandler: null, │ │ │ │ + boxDivClassName: "olHandlerBoxZoomBox", │ │ │ │ + boxOffsets: null, │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ + this.dragHandler = new OpenLayers.Handler.Drag(this, { │ │ │ │ + down: this.startBox, │ │ │ │ + move: this.moveBox, │ │ │ │ + out: this.removeBox, │ │ │ │ + up: this.endBox │ │ │ │ + }, { │ │ │ │ + keyMask: this.keyMask │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ + if (this.dragHandler) { │ │ │ │ + this.dragHandler.destroy(); │ │ │ │ + this.dragHandler = null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Handler.prototype.setMap.apply(this, arguments); │ │ │ │ + if (this.dragHandler) { │ │ │ │ + this.dragHandler.setMap(map) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + startBox: function(xy) { │ │ │ │ + this.callback("start", []); │ │ │ │ + this.zoomBox = OpenLayers.Util.createDiv("zoomBox", { │ │ │ │ + x: -9999, │ │ │ │ + y: -9999 │ │ │ │ + }); │ │ │ │ + this.zoomBox.className = this.boxDivClassName; │ │ │ │ + this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1; │ │ │ │ + this.map.viewPortDiv.appendChild(this.zoomBox); │ │ │ │ + OpenLayers.Element.addClass(this.map.viewPortDiv, "olDrawBox") │ │ │ │ + }, │ │ │ │ + moveBox: function(xy) { │ │ │ │ + var startX = this.dragHandler.start.x; │ │ │ │ + var startY = this.dragHandler.start.y; │ │ │ │ + var deltaX = Math.abs(startX - xy.x); │ │ │ │ + var deltaY = Math.abs(startY - xy.y); │ │ │ │ + var offset = this.getBoxOffsets(); │ │ │ │ + this.zoomBox.style.width = deltaX + offset.width + 1 + "px"; │ │ │ │ + this.zoomBox.style.height = deltaY + offset.height + 1 + "px"; │ │ │ │ + this.zoomBox.style.left = (xy.x < startX ? startX - deltaX - offset.left : startX - offset.left) + "px"; │ │ │ │ + this.zoomBox.style.top = (xy.y < startY ? startY - deltaY - offset.top : startY - offset.top) + "px" │ │ │ │ + }, │ │ │ │ + endBox: function(end) { │ │ │ │ + var result; │ │ │ │ + if (Math.abs(this.dragHandler.start.x - end.x) > 5 || Math.abs(this.dragHandler.start.y - end.y) > 5) { │ │ │ │ + var start = this.dragHandler.start; │ │ │ │ + var top = Math.min(start.y, end.y); │ │ │ │ + var bottom = Math.max(start.y, end.y); │ │ │ │ + var left = Math.min(start.x, end.x); │ │ │ │ + var right = Math.max(start.x, end.x); │ │ │ │ + result = new OpenLayers.Bounds(left, bottom, right, top) │ │ │ │ + } else { │ │ │ │ + result = this.dragHandler.start.clone() │ │ │ │ + } │ │ │ │ + this.removeBox(); │ │ │ │ + this.callback("done", [result]) │ │ │ │ + }, │ │ │ │ + removeBox: function() { │ │ │ │ + this.map.viewPortDiv.removeChild(this.zoomBox); │ │ │ │ + this.zoomBox = null; │ │ │ │ + this.boxOffsets = null; │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olDrawBox") │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.dragHandler.activate(); │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + if (this.dragHandler.deactivate()) { │ │ │ │ + if (this.zoomBox) { │ │ │ │ + this.removeBox() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getBoxOffsets: function() { │ │ │ │ + if (!this.boxOffsets) { │ │ │ │ + var testDiv = document.createElement("div"); │ │ │ │ + testDiv.style.position = "absolute"; │ │ │ │ + testDiv.style.border = "1px solid black"; │ │ │ │ + testDiv.style.width = "3px"; │ │ │ │ + document.body.appendChild(testDiv); │ │ │ │ + var w3cBoxModel = testDiv.clientWidth == 3; │ │ │ │ + document.body.removeChild(testDiv); │ │ │ │ + var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-left-width")); │ │ │ │ + var right = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-right-width")); │ │ │ │ + var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-top-width")); │ │ │ │ + var bottom = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-bottom-width")); │ │ │ │ + this.boxOffsets = { │ │ │ │ + left: left, │ │ │ │ + right: right, │ │ │ │ + top: top, │ │ │ │ + bottom: bottom, │ │ │ │ + width: w3cBoxModel === false ? left + right : 0, │ │ │ │ + height: w3cBoxModel === false ? top + bottom : 0 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return this.boxOffsets │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Box" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + wheelListener: null, │ │ │ │ + interval: 0, │ │ │ │ + maxDelta: Number.POSITIVE_INFINITY, │ │ │ │ + delta: 0, │ │ │ │ + cumulative: true, │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ + this.wheelListener = OpenLayers.Function.bindAsEventListener(this.onWheelEvent, this) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ + this.wheelListener = null │ │ │ │ + }, │ │ │ │ + onWheelEvent: function(e) { │ │ │ │ + if (!this.map || !this.checkModifiers(e)) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + var overScrollableDiv = false; │ │ │ │ + var allowScroll = false; │ │ │ │ + var overMapDiv = false; │ │ │ │ + var elem = OpenLayers.Event.element(e); │ │ │ │ + while (elem != null && !overMapDiv && !overScrollableDiv) { │ │ │ │ + if (!overScrollableDiv) { │ │ │ │ + try { │ │ │ │ + var overflow; │ │ │ │ + if (elem.currentStyle) { │ │ │ │ + overflow = elem.currentStyle["overflow"] │ │ │ │ + } else { │ │ │ │ + var style = document.defaultView.getComputedStyle(elem, null); │ │ │ │ + overflow = style.getPropertyValue("overflow") │ │ │ │ + } │ │ │ │ + overScrollableDiv = overflow && overflow == "auto" || overflow == "scroll" │ │ │ │ + } catch (err) {} │ │ │ │ + } │ │ │ │ + if (!allowScroll) { │ │ │ │ + allowScroll = OpenLayers.Element.hasClass(elem, "olScrollable"); │ │ │ │ + if (!allowScroll) { │ │ │ │ + for (var i = 0, len = this.map.layers.length; i < len; i++) { │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + if (elem == layer.div || elem == layer.pane) { │ │ │ │ + allowScroll = true; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + overMapDiv = elem == this.map.div; │ │ │ │ + elem = elem.parentNode │ │ │ │ + } │ │ │ │ + if (!overScrollableDiv && overMapDiv) { │ │ │ │ + if (allowScroll) { │ │ │ │ + var delta = 0; │ │ │ │ + if (e.wheelDelta) { │ │ │ │ + delta = e.wheelDelta; │ │ │ │ + if (delta % 160 === 0) { │ │ │ │ + delta = delta * .75 │ │ │ │ + } │ │ │ │ + delta = delta / 120 │ │ │ │ + } else if (e.detail) { │ │ │ │ + delta = -(e.detail / Math.abs(e.detail)) │ │ │ │ + } │ │ │ │ + this.delta += delta; │ │ │ │ + window.clearTimeout(this._timeoutId); │ │ │ │ + if (this.interval && Math.abs(this.delta) < this.maxDelta) { │ │ │ │ + var evt = OpenLayers.Util.extend({}, e); │ │ │ │ + this._timeoutId = window.setTimeout(OpenLayers.Function.bind(function() { │ │ │ │ + this.wheelZoom(evt) │ │ │ │ + }, this), this.interval) │ │ │ │ + } else { │ │ │ │ + this.wheelZoom(e) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + OpenLayers.Event.stop(e) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + wheelZoom: function(e) { │ │ │ │ + var delta = this.delta; │ │ │ │ + this.delta = 0; │ │ │ │ + if (delta) { │ │ │ │ + e.xy = this.map.events.getMousePosition(e); │ │ │ │ + if (delta < 0) { │ │ │ │ + this.callback("down", [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]) │ │ │ │ + } else { │ │ │ │ + this.callback("up", [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + activate: function(evt) { │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + var wheelListener = this.wheelListener; │ │ │ │ + OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener); │ │ │ │ + OpenLayers.Event.observe(window, "mousewheel", wheelListener); │ │ │ │ + OpenLayers.Event.observe(document, "mousewheel", wheelListener); │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + deactivate: function(evt) { │ │ │ │ + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + var wheelListener = this.wheelListener; │ │ │ │ + OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener); │ │ │ │ + OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener); │ │ │ │ + OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener); │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.MouseWheel" │ │ │ │ +}); │ │ │ │ +OpenLayers.Handler.Pinch = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ + started: false, │ │ │ │ + stopDown: false, │ │ │ │ + pinching: false, │ │ │ │ + last: null, │ │ │ │ + start: null, │ │ │ │ + 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) { │ │ │ │ + return false │ │ │ │ + } else { │ │ │ │ + this.started = false; │ │ │ │ + this.start = null; │ │ │ │ + this.last = null │ │ │ │ + } │ │ │ │ + OpenLayers.Event.preventDefault(evt); │ │ │ │ + return 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; │ │ │ │ + OpenLayers.Event.stop(evt) │ │ │ │ + } else if (this.started) { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + return true │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + var activated = false; │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.pinching = false; │ │ │ │ + activated = true │ │ │ │ + } │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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)) │ │ │ │ + }, │ │ │ │ + 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.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + isBaseLayer: true, │ │ │ │ + sphericalMercator: false, │ │ │ │ + zoomOffset: 0, │ │ │ │ + serverResolutions: null, │ │ │ │ + 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]) │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.XYZ(this.name, this.url, this.getOptions()) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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.UTFGrid = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ + isBaseLayer: false, │ │ │ │ + projection: new OpenLayers.Projection("EPSG:900913"), │ │ │ │ + useJSONP: false, │ │ │ │ + tileClass: OpenLayers.Tile.UTFGrid, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, [options.name, options.url, {}, options]); │ │ │ │ + this.tileOptions = OpenLayers.Util.extend({ │ │ │ │ + utfgridResolution: this.utfgridResolution │ │ │ │ + }, this.tileOptions) │ │ │ │ + }, │ │ │ │ + createBackBuffer: function() {}, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.UTFGrid(this.getOptions()) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + getFeatureInfo: function(location) { │ │ │ │ + var info = null; │ │ │ │ + var tileInfo = this.getTileData(location); │ │ │ │ + if (tileInfo && tileInfo.tile) { │ │ │ │ + info = tileInfo.tile.getFeatureInfo(tileInfo.i, tileInfo.j) │ │ │ │ + } │ │ │ │ + return info │ │ │ │ + }, │ │ │ │ + getFeatureId: function(location) { │ │ │ │ + var id = null; │ │ │ │ + var info = this.getTileData(location); │ │ │ │ + if (info.tile) { │ │ │ │ + id = info.tile.getFeatureId(info.i, info.j) │ │ │ │ + } │ │ │ │ + return id │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.UTFGrid" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ + key: null, │ │ │ │ + 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, .5971642833948135, .29858214169740677, .14929107084870338, .07464553542435169], │ │ │ │ + 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>", │ │ │ │ + metadata: null, │ │ │ │ + protocolRegex: /^http:/i, │ │ │ │ + type: "Road", │ │ │ │ + culture: "en-US", │ │ │ │ + metadataParams: null, │ │ │ │ + tileOptions: null, │ │ │ │ + protocol: ~window.location.href.indexOf("http") ? "" : "http:", │ │ │ │ + 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() │ │ │ │ + }, │ │ │ │ + loadMetadata: function() { │ │ │ │ + this._callbackId = "_callback_" + this.id.replace(/\./g, "_"); │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + 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]; │ │ │ │ + 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" │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + setMap: function() { │ │ │ │ + OpenLayers.Layer.XYZ.prototype.setMap.apply(this, arguments); │ │ │ │ + this.map.events.register("moveend", this, this.updateAttribution) │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.Bing(this.options) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + 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" │ │ │ │ +}); │ │ │ │ +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; │ │ │ │ + delete this._callbackId │ │ │ │ +}; │ │ │ │ +OpenLayers.Layer.Image = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ + isBaseLayer: true, │ │ │ │ + url: null, │ │ │ │ + extent: null, │ │ │ │ + size: null, │ │ │ │ + tile: null, │ │ │ │ + aspectRatio: null, │ │ │ │ + initialize: function(name, url, extent, size, options) { │ │ │ │ + this.url = url; │ │ │ │ + this.extent = extent; │ │ │ │ + this.maxExtent = extent; │ │ │ │ + this.size = size; │ │ │ │ + OpenLayers.Layer.prototype.initialize.apply(this, [name, options]); │ │ │ │ + this.aspectRatio = this.extent.getHeight() / this.size.h / (this.extent.getWidth() / this.size.w) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.tile) { │ │ │ │ + this.removeTileMonitoringHooks(this.tile); │ │ │ │ + this.tile.destroy(); │ │ │ │ + this.tile = null │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.Image(this.name, this.url, this.extent, this.size, this.getOptions()) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + if (this.options.maxResolution == null) { │ │ │ │ + this.options.maxResolution = this.aspectRatio * this.extent.getWidth() / this.size.w │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.prototype.setMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ + OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ + var firstRendering = this.tile == null; │ │ │ │ + if (zoomChanged || firstRendering) { │ │ │ │ + this.setTileSize(); │ │ │ │ + var ulPx = this.map.getLayerPxFromLonLat({ │ │ │ │ + lon: this.extent.left, │ │ │ │ + lat: this.extent.top │ │ │ │ + }); │ │ │ │ + if (firstRendering) { │ │ │ │ + this.tile = new OpenLayers.Tile.Image(this, ulPx, this.extent, null, this.tileSize); │ │ │ │ + this.addTileMonitoringHooks(this.tile) │ │ │ │ + } else { │ │ │ │ + this.tile.size = this.tileSize.clone(); │ │ │ │ + this.tile.position = ulPx.clone() │ │ │ │ + } │ │ │ │ + this.tile.draw() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setTileSize: function() { │ │ │ │ + var tileWidth = this.extent.getWidth() / this.map.getResolution(); │ │ │ │ + var tileHeight = this.extent.getHeight() / this.map.getResolution(); │ │ │ │ + this.tileSize = new OpenLayers.Size(tileWidth, tileHeight) │ │ │ │ + }, │ │ │ │ + addTileMonitoringHooks: function(tile) { │ │ │ │ + tile.onLoadStart = function() { │ │ │ │ + this.events.triggerEvent("loadstart") │ │ │ │ + }; │ │ │ │ + tile.events.register("loadstart", this, tile.onLoadStart); │ │ │ │ + tile.onLoadEnd = function() { │ │ │ │ + this.events.triggerEvent("loadend") │ │ │ │ + }; │ │ │ │ + tile.events.register("loadend", this, tile.onLoadEnd); │ │ │ │ + tile.events.register("unload", this, tile.onLoadEnd) │ │ │ │ + }, │ │ │ │ + removeTileMonitoringHooks: function(tile) { │ │ │ │ + tile.unload(); │ │ │ │ + tile.events.un({ │ │ │ │ + loadstart: tile.onLoadStart, │ │ │ │ + loadend: tile.onLoadEnd, │ │ │ │ + unload: tile.onLoadEnd, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + setUrl: function(newUrl) { │ │ │ │ + this.url = newUrl; │ │ │ │ + this.tile.draw() │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + return this.url │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Image" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.KaMap = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + isBaseLayer: true, │ │ │ │ + DEFAULT_PARAMS: { │ │ │ │ + i: "jpeg", │ │ │ │ + map: "" │ │ │ │ + }, │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ + this.params = OpenLayers.Util.applyDefaults(this.params, this.DEFAULT_PARAMS) │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ + var scale = Math.round(this.map.getScale() * 1e4) / 1e4; │ │ │ │ + var pX = Math.round(bounds.left / mapRes); │ │ │ │ + var pY = -Math.round(bounds.top / mapRes); │ │ │ │ + return this.getFullRequestString({ │ │ │ │ + t: pY, │ │ │ │ + l: pX, │ │ │ │ + s: scale │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + calculateGridLayout: function(bounds, origin, resolution) { │ │ │ │ + var tilelon = resolution * this.tileSize.w; │ │ │ │ + var tilelat = resolution * this.tileSize.h; │ │ │ │ + var offsetlon = bounds.left; │ │ │ │ + var tilecol = Math.floor(offsetlon / tilelon) - this.buffer; │ │ │ │ + var offsetlat = bounds.top; │ │ │ │ + var tilerow = Math.floor(offsetlat / tilelat) + this.buffer; │ │ │ │ + return { │ │ │ │ + tilelon: tilelon, │ │ │ │ + tilelat: tilelat, │ │ │ │ + startcol: tilecol, │ │ │ │ + startrow: tilerow │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getTileBoundsForGridIndex: function(row, col) { │ │ │ │ + var origin = this.getTileOrigin(); │ │ │ │ + var tileLayout = this.gridLayout; │ │ │ │ + var tilelon = tileLayout.tilelon; │ │ │ │ + var tilelat = tileLayout.tilelat; │ │ │ │ + var minX = (tileLayout.startcol + col) * tilelon; │ │ │ │ + var minY = (tileLayout.startrow - row) * tilelat; │ │ │ │ + return new OpenLayers.Bounds(minX, minY, minX + tilelon, minY + tilelat) │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.KaMap(this.name, this.url, this.params, this.getOptions()) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + if (this.tileSize != null) { │ │ │ │ + obj.tileSize = this.tileSize.clone() │ │ │ │ + } │ │ │ │ + obj.grid = []; │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + getTileBounds: function(viewPortPx) { │ │ │ │ + var resolution = this.getResolution(); │ │ │ │ + var tileMapWidth = resolution * this.tileSize.w; │ │ │ │ + var tileMapHeight = resolution * this.tileSize.h; │ │ │ │ + var mapPoint = this.getLonLatFromViewPortPx(viewPortPx); │ │ │ │ + var tileLeft = tileMapWidth * Math.floor(mapPoint.lon / tileMapWidth); │ │ │ │ + var tileBottom = tileMapHeight * Math.floor(mapPoint.lat / tileMapHeight); │ │ │ │ + return new OpenLayers.Bounds(tileLeft, tileBottom, tileLeft + tileMapWidth, tileBottom + tileMapHeight) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.KaMap" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.PointGrid = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ + dx: null, │ │ │ │ + dy: null, │ │ │ │ + ratio: 1.5, │ │ │ │ + maxFeatures: 250, │ │ │ │ + rotation: 0, │ │ │ │ + origin: null, │ │ │ │ + gridBounds: null, │ │ │ │ + initialize: function(config) { │ │ │ │ + config = config || {}; │ │ │ │ + OpenLayers.Layer.Vector.prototype.initialize.apply(this, [config.name, config]) │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ + map.events.register("moveend", this, this.onMoveEnd) │ │ │ │ + }, │ │ │ │ + removeMap: function(map) { │ │ │ │ + map.events.unregister("moveend", this, this.onMoveEnd); │ │ │ │ + OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + setRatio: function(ratio) { │ │ │ │ + this.ratio = ratio; │ │ │ │ + this.updateGrid(true) │ │ │ │ + }, │ │ │ │ + setMaxFeatures: function(maxFeatures) { │ │ │ │ + this.maxFeatures = maxFeatures; │ │ │ │ + this.updateGrid(true) │ │ │ │ + }, │ │ │ │ + setSpacing: function(dx, dy) { │ │ │ │ + this.dx = dx; │ │ │ │ + this.dy = dy || dx; │ │ │ │ + this.updateGrid(true) │ │ │ │ + }, │ │ │ │ + setOrigin: function(origin) { │ │ │ │ + this.origin = origin; │ │ │ │ + this.updateGrid(true) │ │ │ │ + }, │ │ │ │ + getOrigin: function() { │ │ │ │ + if (!this.origin) { │ │ │ │ + this.origin = this.map.getExtent().getCenterLonLat() │ │ │ │ + } │ │ │ │ + return this.origin │ │ │ │ + }, │ │ │ │ + setRotation: function(rotation) { │ │ │ │ + this.rotation = rotation; │ │ │ │ + this.updateGrid(true) │ │ │ │ + }, │ │ │ │ + onMoveEnd: function() { │ │ │ │ + this.updateGrid() │ │ │ │ + }, │ │ │ │ + getViewBounds: function() { │ │ │ │ + var bounds = this.map.getExtent(); │ │ │ │ + if (this.rotation) { │ │ │ │ + var origin = this.getOrigin(); │ │ │ │ + var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); │ │ │ │ + var rect = bounds.toGeometry(); │ │ │ │ + rect.rotate(-this.rotation, rotationOrigin); │ │ │ │ + bounds = rect.getBounds() │ │ │ │ + } │ │ │ │ + return bounds │ │ │ │ + }, │ │ │ │ + updateGrid: function(force) { │ │ │ │ + if (force || this.invalidBounds()) { │ │ │ │ + var viewBounds = this.getViewBounds(); │ │ │ │ + var origin = this.getOrigin(); │ │ │ │ + var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat); │ │ │ │ + var viewBoundsWidth = viewBounds.getWidth(); │ │ │ │ + var viewBoundsHeight = viewBounds.getHeight(); │ │ │ │ + var aspectRatio = viewBoundsWidth / viewBoundsHeight; │ │ │ │ + var maxHeight = Math.sqrt(this.dx * this.dy * this.maxFeatures / aspectRatio); │ │ │ │ + var maxWidth = maxHeight * aspectRatio; │ │ │ │ + var gridWidth = Math.min(viewBoundsWidth * this.ratio, maxWidth); │ │ │ │ + var gridHeight = Math.min(viewBoundsHeight * this.ratio, maxHeight); │ │ │ │ + var center = viewBounds.getCenterLonLat(); │ │ │ │ + this.gridBounds = new OpenLayers.Bounds(center.lon - gridWidth / 2, center.lat - gridHeight / 2, center.lon + gridWidth / 2, center.lat + gridHeight / 2); │ │ │ │ + var rows = Math.floor(gridHeight / this.dy); │ │ │ │ + var cols = Math.floor(gridWidth / this.dx); │ │ │ │ + var gridLeft = origin.lon + this.dx * Math.ceil((this.gridBounds.left - origin.lon) / this.dx); │ │ │ │ + var gridBottom = origin.lat + this.dy * Math.ceil((this.gridBounds.bottom - origin.lat) / this.dy); │ │ │ │ + var features = new Array(rows * cols); │ │ │ │ + var x, y, point; │ │ │ │ + for (var i = 0; i < cols; ++i) { │ │ │ │ + x = gridLeft + i * this.dx; │ │ │ │ + for (var j = 0; j < rows; ++j) { │ │ │ │ + y = gridBottom + j * this.dy; │ │ │ │ + point = new OpenLayers.Geometry.Point(x, y); │ │ │ │ + if (this.rotation) { │ │ │ │ + point.rotate(this.rotation, rotationOrigin) │ │ │ │ + } │ │ │ │ + features[i * rows + j] = new OpenLayers.Feature.Vector(point) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.destroyFeatures(this.features, { │ │ │ │ + silent: true │ │ │ │ + }); │ │ │ │ + this.addFeatures(features, { │ │ │ │ + silent: true │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + invalidBounds: function() { │ │ │ │ + return !this.gridBounds || !this.gridBounds.containsBounds(this.getViewBounds()) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.PointGrid" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.ArcGISCache = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ + url: null, │ │ │ │ + tileOrigin: null, │ │ │ │ + tileSize: new OpenLayers.Size(256, 256), │ │ │ │ + useArcGISServer: true, │ │ │ │ + type: "png", │ │ │ │ + useScales: false, │ │ │ │ + overrideDPI: false, │ │ │ │ + initialize: function(name, url, options) { │ │ │ │ + OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments); │ │ │ │ + if (this.resolutions) { │ │ │ │ + this.serverResolutions = this.resolutions; │ │ │ │ + this.maxExtent = this.getMaxExtentForResolution(this.resolutions[0]) │ │ │ │ + } │ │ │ │ + if (this.layerInfo) { │ │ │ │ + var info = this.layerInfo; │ │ │ │ + var startingTileExtent = new OpenLayers.Bounds(info.fullExtent.xmin, info.fullExtent.ymin, info.fullExtent.xmax, info.fullExtent.ymax); │ │ │ │ + this.projection = "EPSG:" + info.spatialReference.wkid; │ │ │ │ + this.sphericalMercator = info.spatialReference.wkid == 102100; │ │ │ │ + this.units = info.units == "esriFeet" ? "ft" : "m"; │ │ │ │ + if (!!info.tileInfo) { │ │ │ │ + this.tileSize = new OpenLayers.Size(info.tileInfo.width || info.tileInfo.cols, info.tileInfo.height || info.tileInfo.rows); │ │ │ │ + this.tileOrigin = new OpenLayers.LonLat(info.tileInfo.origin.x, info.tileInfo.origin.y); │ │ │ │ + var upperLeft = new OpenLayers.Geometry.Point(startingTileExtent.left, startingTileExtent.top); │ │ │ │ + var bottomRight = new OpenLayers.Geometry.Point(startingTileExtent.right, startingTileExtent.bottom); │ │ │ │ + if (this.useScales) { │ │ │ │ + this.scales = [] │ │ │ │ + } else { │ │ │ │ + this.resolutions = [] │ │ │ │ + } │ │ │ │ + this.lods = []; │ │ │ │ + for (var key in info.tileInfo.lods) { │ │ │ │ + if (info.tileInfo.lods.hasOwnProperty(key)) { │ │ │ │ + var lod = info.tileInfo.lods[key]; │ │ │ │ + if (this.useScales) { │ │ │ │ + this.scales.push(lod.scale) │ │ │ │ + } else { │ │ │ │ + this.resolutions.push(lod.resolution) │ │ │ │ + } │ │ │ │ + var start = this.getContainingTileCoords(upperLeft, lod.resolution); │ │ │ │ + lod.startTileCol = start.x; │ │ │ │ + lod.startTileRow = start.y; │ │ │ │ + var end = this.getContainingTileCoords(bottomRight, lod.resolution); │ │ │ │ + lod.endTileCol = end.x; │ │ │ │ + lod.endTileRow = end.y; │ │ │ │ + this.lods.push(lod) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.maxExtent = this.calculateMaxExtentWithLOD(this.lods[0]); │ │ │ │ + this.serverResolutions = this.resolutions; │ │ │ │ + if (this.overrideDPI && info.tileInfo.dpi) { │ │ │ │ + OpenLayers.DOTS_PER_INCH = info.tileInfo.dpi │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getContainingTileCoords: function(point, res) { │ │ │ │ + return new OpenLayers.Pixel(Math.max(Math.floor((point.x - this.tileOrigin.lon) / (this.tileSize.w * res)), 0), Math.max(Math.floor((this.tileOrigin.lat - point.y) / (this.tileSize.h * res)), 0)) │ │ │ │ + }, │ │ │ │ + calculateMaxExtentWithLOD: function(lod) { │ │ │ │ + var numTileCols = lod.endTileCol - lod.startTileCol + 1; │ │ │ │ + var numTileRows = lod.endTileRow - lod.startTileRow + 1; │ │ │ │ + var minX = this.tileOrigin.lon + lod.startTileCol * this.tileSize.w * lod.resolution; │ │ │ │ + var maxX = minX + numTileCols * this.tileSize.w * lod.resolution; │ │ │ │ + var maxY = this.tileOrigin.lat - lod.startTileRow * this.tileSize.h * lod.resolution; │ │ │ │ + var minY = maxY - numTileRows * this.tileSize.h * lod.resolution; │ │ │ │ + return new OpenLayers.Bounds(minX, minY, maxX, maxY) │ │ │ │ + }, │ │ │ │ + calculateMaxExtentWithExtent: function(extent, res) { │ │ │ │ + var upperLeft = new OpenLayers.Geometry.Point(extent.left, extent.top); │ │ │ │ + var bottomRight = new OpenLayers.Geometry.Point(extent.right, extent.bottom); │ │ │ │ + var start = this.getContainingTileCoords(upperLeft, res); │ │ │ │ + var end = this.getContainingTileCoords(bottomRight, res); │ │ │ │ + var lod = { │ │ │ │ + resolution: res, │ │ │ │ + startTileCol: start.x, │ │ │ │ + startTileRow: start.y, │ │ │ │ + endTileCol: end.x, │ │ │ │ + endTileRow: end.y │ │ │ │ + }; │ │ │ │ + return this.calculateMaxExtentWithLOD(lod) │ │ │ │ + }, │ │ │ │ + getUpperLeftTileCoord: function(res) { │ │ │ │ + var upperLeft = new OpenLayers.Geometry.Point(this.maxExtent.left, this.maxExtent.top); │ │ │ │ + return this.getContainingTileCoords(upperLeft, res) │ │ │ │ + }, │ │ │ │ + getLowerRightTileCoord: function(res) { │ │ │ │ + var bottomRight = new OpenLayers.Geometry.Point(this.maxExtent.right, this.maxExtent.bottom); │ │ │ │ + return this.getContainingTileCoords(bottomRight, res) │ │ │ │ + }, │ │ │ │ + getMaxExtentForResolution: function(res) { │ │ │ │ + var start = this.getUpperLeftTileCoord(res); │ │ │ │ + var end = this.getLowerRightTileCoord(res); │ │ │ │ + var numTileCols = end.x - start.x + 1; │ │ │ │ + var numTileRows = end.y - start.y + 1; │ │ │ │ + var minX = this.tileOrigin.lon + start.x * this.tileSize.w * res; │ │ │ │ + var maxX = minX + numTileCols * this.tileSize.w * res; │ │ │ │ + var maxY = this.tileOrigin.lat - start.y * this.tileSize.h * res; │ │ │ │ + var minY = maxY - numTileRows * this.tileSize.h * res; │ │ │ │ + return new OpenLayers.Bounds(minX, minY, maxX, maxY) │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.ArcGISCache(this.name, this.url, this.options) │ │ │ │ + } │ │ │ │ + return OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]) │ │ │ │ + }, │ │ │ │ + initGriddedTiles: function(bounds) { │ │ │ │ + delete this._tileOrigin; │ │ │ │ + OpenLayers.Layer.XYZ.prototype.initGriddedTiles.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + getMaxExtent: function() { │ │ │ │ + var resolution = this.map.getResolution(); │ │ │ │ + return this.maxExtent = this.getMaxExtentForResolution(resolution) │ │ │ │ + }, │ │ │ │ + getTileOrigin: function() { │ │ │ │ + if (!this._tileOrigin) { │ │ │ │ + var extent = this.getMaxExtent(); │ │ │ │ + this._tileOrigin = new OpenLayers.LonLat(extent.left, extent.bottom) │ │ │ │ + } │ │ │ │ + return this._tileOrigin │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + var res = this.getResolution(); │ │ │ │ + var originTileX = this.tileOrigin.lon + res * this.tileSize.w / 2; │ │ │ │ + var originTileY = this.tileOrigin.lat - res * this.tileSize.h / 2; │ │ │ │ + var center = bounds.getCenterLonLat(); │ │ │ │ + var point = { │ │ │ │ + x: center.lon, │ │ │ │ + y: center.lat │ │ │ │ + }; │ │ │ │ + var x = Math.round(Math.abs((center.lon - originTileX) / (res * this.tileSize.w))); │ │ │ │ + var y = Math.round(Math.abs((originTileY - center.lat) / (res * this.tileSize.h))); │ │ │ │ + var z = this.map.getZoom(); │ │ │ │ + if (this.lods) { │ │ │ │ + var lod = this.lods[this.map.getZoom()]; │ │ │ │ + if (x < lod.startTileCol || x > lod.endTileCol || (y < lod.startTileRow || y > lod.endTileRow)) { │ │ │ │ + return null │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + var start = this.getUpperLeftTileCoord(res); │ │ │ │ + var end = this.getLowerRightTileCoord(res); │ │ │ │ + if (x < start.x || x >= end.x || (y < start.y || y >= end.y)) { │ │ │ │ + return null │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var url = this.url; │ │ │ │ + var s = "" + x + y + z; │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(s, url) │ │ │ │ + } │ │ │ │ + if (this.useArcGISServer) { │ │ │ │ + url = url + "/tile/${z}/${y}/${x}" │ │ │ │ + } else { │ │ │ │ + x = "C" + OpenLayers.Number.zeroPad(x, 8, 16); │ │ │ │ + y = "R" + OpenLayers.Number.zeroPad(y, 8, 16); │ │ │ │ + z = "L" + OpenLayers.Number.zeroPad(z, 2, 10); │ │ │ │ + url = url + "/${z}/${y}/${x}." + this.type │ │ │ │ + } │ │ │ │ + url = OpenLayers.String.format(url, { │ │ │ │ + x: x, │ │ │ │ + y: y, │ │ │ │ + z: z │ │ │ │ + }); │ │ │ │ + return OpenLayers.Util.urlAppend(url, OpenLayers.Util.getParameterString(this.params)) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.ArcGISCache" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.Google = OpenLayers.Class(OpenLayers.Layer.EventPane, OpenLayers.Layer.FixedZoomLevels, { │ │ │ │ + MIN_ZOOM_LEVEL: 0, │ │ │ │ + MAX_ZOOM_LEVEL: 21, │ │ │ │ + RESOLUTIONS: [1.40625, .703125, .3515625, .17578125, .087890625, .0439453125, .02197265625, .010986328125, .0054931640625, .00274658203125, .001373291015625, .0006866455078125, .00034332275390625, .000171661376953125, 858306884765625e-19, 4291534423828125e-20, 2145767211914062e-20, 1072883605957031e-20, 536441802978515e-20, 268220901489257e-20, 1341104507446289e-21, 6.705522537231445e-7], │ │ │ │ + type: null, │ │ │ │ + wrapDateLine: true, │ │ │ │ + sphericalMercator: false, │ │ │ │ + version: null, │ │ │ │ + initialize: function(name, options) { │ │ │ │ + options = options || {}; │ │ │ │ + if (!options.version) { │ │ │ │ + options.version = typeof GMap2 === "function" ? "2" : "3" │ │ │ │ + } │ │ │ │ + var mixin = OpenLayers.Layer.Google["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (mixin) { │ │ │ │ + OpenLayers.Util.applyDefaults(options, mixin) │ │ │ │ + } else { │ │ │ │ + throw "Unsupported Google Maps API version: " + options.version │ │ │ │ + } │ │ │ │ + OpenLayers.Util.applyDefaults(options, mixin.DEFAULTS); │ │ │ │ + if (options.maxExtent) { │ │ │ │ + options.maxExtent = options.maxExtent.clone() │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.EventPane.prototype.initialize.apply(this, [name, options]); │ │ │ │ + OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, [name, options]); │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator); │ │ │ │ + this.initMercatorParameters() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + clone: function() { │ │ │ │ + return new OpenLayers.Layer.Google(this.name, this.getOptions()) │ │ │ │ + }, │ │ │ │ + setVisibility: function(visible) { │ │ │ │ + var opacity = this.opacity == null ? 1 : this.opacity; │ │ │ │ + OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this, arguments); │ │ │ │ + this.setOpacity(opacity) │ │ │ │ + }, │ │ │ │ + display: function(visible) { │ │ │ │ + if (!this._dragging) { │ │ │ │ + this.setGMapVisibility(visible) │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.EventPane.prototype.display.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ + this._dragging = dragging; │ │ │ │ + OpenLayers.Layer.EventPane.prototype.moveTo.apply(this, arguments); │ │ │ │ + delete this._dragging │ │ │ │ + }, │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ + if (opacity !== this.opacity) { │ │ │ │ + if (this.map != null) { │ │ │ │ + this.map.events.triggerEvent("changelayer", { │ │ │ │ + layer: this, │ │ │ │ + property: "opacity" │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + this.opacity = opacity │ │ │ │ + } │ │ │ │ + if (this.getVisibility()) { │ │ │ │ + var container = this.getMapContainer(); │ │ │ │ + OpenLayers.Util.modifyDOMElement(container, null, null, null, null, null, null, opacity) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.setGMapVisibility(false); │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache && cache.count <= 1) { │ │ │ │ + this.removeGMapElements() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.EventPane.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + removeGMapElements: function() { │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + var container = this.mapObject && this.getMapContainer(); │ │ │ │ + if (container && container.parentNode) { │ │ │ │ + container.parentNode.removeChild(container) │ │ │ │ + } │ │ │ │ + var termsOfUse = cache.termsOfUse; │ │ │ │ + if (termsOfUse && termsOfUse.parentNode) { │ │ │ │ + termsOfUse.parentNode.removeChild(termsOfUse) │ │ │ │ + } │ │ │ │ + var poweredBy = cache.poweredBy; │ │ │ │ + if (poweredBy && poweredBy.parentNode) { │ │ │ │ + poweredBy.parentNode.removeChild(poweredBy) │ │ │ │ + } │ │ │ │ + if (this.mapObject && window.google && google.maps && google.maps.event && google.maps.event.clearListeners) { │ │ │ │ + google.maps.event.clearListeners(this.mapObject, "tilesloaded") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + removeMap: function(map) { │ │ │ │ + if (this.visibility && this.mapObject) { │ │ │ │ + this.setGMapVisibility(false) │ │ │ │ + } │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[map.id]; │ │ │ │ + if (cache) { │ │ │ │ + if (cache.count <= 1) { │ │ │ │ + this.removeGMapElements(); │ │ │ │ + delete OpenLayers.Layer.Google.cache[map.id] │ │ │ │ + } else { │ │ │ │ + --cache.count │ │ │ │ + } │ │ │ │ + } │ │ │ │ + delete this.termsOfUse; │ │ │ │ + delete this.poweredBy; │ │ │ │ + delete this.mapObject; │ │ │ │ + delete this.dragObject; │ │ │ │ + OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + getOLBoundsFromMapObjectBounds: function(moBounds) { │ │ │ │ + var olBounds = null; │ │ │ │ + if (moBounds != null) { │ │ │ │ + var sw = moBounds.getSouthWest(); │ │ │ │ + var ne = moBounds.getNorthEast(); │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + sw = this.forwardMercator(sw.lng(), sw.lat()); │ │ │ │ + ne = this.forwardMercator(ne.lng(), ne.lat()) │ │ │ │ + } else { │ │ │ │ + sw = new OpenLayers.LonLat(sw.lng(), sw.lat()); │ │ │ │ + ne = new OpenLayers.LonLat(ne.lng(), ne.lat()) │ │ │ │ + } │ │ │ │ + olBounds = new OpenLayers.Bounds(sw.lon, sw.lat, ne.lon, ne.lat) │ │ │ │ + } │ │ │ │ + return olBounds │ │ │ │ + }, │ │ │ │ + getWarningHTML: function() { │ │ │ │ + return OpenLayers.i18n("googleWarning") │ │ │ │ + }, │ │ │ │ + getMapObjectCenter: function() { │ │ │ │ + return this.mapObject.getCenter() │ │ │ │ + }, │ │ │ │ + getMapObjectZoom: function() { │ │ │ │ + return this.mapObject.getZoom() │ │ │ │ + }, │ │ │ │ + getLongitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + return this.sphericalMercator ? this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon : moLonLat.lng() │ │ │ │ + }, │ │ │ │ + getLatitudeFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + var lat = this.sphericalMercator ? this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat : moLonLat.lat(); │ │ │ │ + return lat │ │ │ │ + }, │ │ │ │ + getXFromMapObjectPixel: function(moPixel) { │ │ │ │ + return moPixel.x │ │ │ │ + }, │ │ │ │ + getYFromMapObjectPixel: function(moPixel) { │ │ │ │ + return moPixel.y │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Google" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.Google.cache = {}; │ │ │ │ +OpenLayers.Layer.Google.v2 = { │ │ │ │ + termsOfUse: null, │ │ │ │ + poweredBy: null, │ │ │ │ + dragObject: null, │ │ │ │ + loadMapObject: function() { │ │ │ │ + if (!this.type) { │ │ │ │ + this.type = G_NORMAL_MAP │ │ │ │ + } │ │ │ │ + var mapObject, termsOfUse, poweredBy; │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + mapObject = cache.mapObject; │ │ │ │ + termsOfUse = cache.termsOfUse; │ │ │ │ + poweredBy = cache.poweredBy; │ │ │ │ + ++cache.count │ │ │ │ + } else { │ │ │ │ + var container = this.map.viewPortDiv; │ │ │ │ + var div = document.createElement("div"); │ │ │ │ + div.id = this.map.id + "_GMap2Container"; │ │ │ │ + div.style.position = "absolute"; │ │ │ │ + div.style.width = "100%"; │ │ │ │ + div.style.height = "100%"; │ │ │ │ + container.appendChild(div); │ │ │ │ + try { │ │ │ │ + mapObject = new GMap2(div); │ │ │ │ + termsOfUse = div.lastChild; │ │ │ │ + container.appendChild(termsOfUse); │ │ │ │ + termsOfUse.style.zIndex = "1100"; │ │ │ │ + termsOfUse.style.right = ""; │ │ │ │ + termsOfUse.style.bottom = ""; │ │ │ │ + termsOfUse.className = "olLayerGoogleCopyright"; │ │ │ │ + poweredBy = div.lastChild; │ │ │ │ + container.appendChild(poweredBy); │ │ │ │ + poweredBy.style.zIndex = "1100"; │ │ │ │ + poweredBy.style.right = ""; │ │ │ │ + poweredBy.style.bottom = ""; │ │ │ │ + poweredBy.className = "olLayerGooglePoweredBy gmnoprint" │ │ │ │ + } catch (e) { │ │ │ │ + throw e │ │ │ │ + } │ │ │ │ + OpenLayers.Layer.Google.cache[this.map.id] = { │ │ │ │ + mapObject: mapObject, │ │ │ │ + termsOfUse: termsOfUse, │ │ │ │ + poweredBy: poweredBy, │ │ │ │ + count: 1 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.mapObject = mapObject; │ │ │ │ + this.termsOfUse = termsOfUse; │ │ │ │ + this.poweredBy = poweredBy; │ │ │ │ + if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(), this.type) === -1) { │ │ │ │ + this.mapObject.addMapType(this.type) │ │ │ │ + } │ │ │ │ + if (typeof mapObject.getDragObject == "function") { │ │ │ │ + this.dragObject = mapObject.getDragObject() │ │ │ │ + } else { │ │ │ │ + this.dragPanMapObject = null │ │ │ │ + } │ │ │ │ + if (this.isBaseLayer === false) { │ │ │ │ + this.setGMapVisibility(this.div.style.display !== "none") │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + onMapResize: function() { │ │ │ │ + if (this.visibility && this.mapObject.isLoaded()) { │ │ │ │ + this.mapObject.checkResize() │ │ │ │ + } else { │ │ │ │ + if (!this._resized) { │ │ │ │ + var layer = this; │ │ │ │ + var handle = GEvent.addListener(this.mapObject, "load", function() { │ │ │ │ + GEvent.removeListener(handle); │ │ │ │ + delete layer._resized; │ │ │ │ + layer.mapObject.checkResize(); │ │ │ │ + layer.moveTo(layer.map.getCenter(), layer.map.getZoom()) │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + this._resized = true │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setGMapVisibility: function(visible) { │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + var container = this.mapObject.getContainer(); │ │ │ │ + if (visible === true) { │ │ │ │ + this.mapObject.setMapType(this.type); │ │ │ │ + container.style.display = ""; │ │ │ │ + this.termsOfUse.style.left = ""; │ │ │ │ + this.termsOfUse.style.display = ""; │ │ │ │ + this.poweredBy.style.display = ""; │ │ │ │ + cache.displayed = this.id │ │ │ │ + } else { │ │ │ │ + if (cache.displayed === this.id) { │ │ │ │ + delete cache.displayed │ │ │ │ + } │ │ │ │ + if (!cache.displayed) { │ │ │ │ + container.style.display = "none"; │ │ │ │ + this.termsOfUse.style.display = "none"; │ │ │ │ + this.termsOfUse.style.left = "-9999px"; │ │ │ │ + this.poweredBy.style.display = "none" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getMapContainer: function() { │ │ │ │ + return this.mapObject.getContainer() │ │ │ │ + }, │ │ │ │ + getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ + var moBounds = null; │ │ │ │ + if (olBounds != null) { │ │ │ │ + var sw = this.sphericalMercator ? this.inverseMercator(olBounds.bottom, olBounds.left) : new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ + var ne = this.sphericalMercator ? this.inverseMercator(olBounds.top, olBounds.right) : new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ + moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon), new GLatLng(ne.lat, ne.lon)) │ │ │ │ + } │ │ │ │ + return moBounds │ │ │ │ + }, │ │ │ │ + setMapObjectCenter: function(center, zoom) { │ │ │ │ + this.mapObject.setCenter(center, zoom) │ │ │ │ + }, │ │ │ │ + dragPanMapObject: function(dX, dY) { │ │ │ │ + this.dragObject.moveBy(new GSize(-dX, dY)) │ │ │ │ + }, │ │ │ │ + getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ + return this.mapObject.fromContainerPixelToLatLng(moPixel) │ │ │ │ + }, │ │ │ │ + getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + return this.mapObject.fromLatLngToContainerPixel(moLonLat) │ │ │ │ + }, │ │ │ │ + getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ + return this.mapObject.getBoundsZoomLevel(moBounds) │ │ │ │ + }, │ │ │ │ + getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ + var gLatLng; │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + var lonlat = this.inverseMercator(lon, lat); │ │ │ │ + gLatLng = new GLatLng(lonlat.lat, lonlat.lon) │ │ │ │ + } else { │ │ │ │ + gLatLng = new GLatLng(lat, lon) │ │ │ │ + } │ │ │ │ + return gLatLng │ │ │ │ + }, │ │ │ │ + getMapObjectPixelFromXY: function(x, y) { │ │ │ │ + return new GPoint(x, y) │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.Format.ArcXML = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + fontStyleKeys: ["antialiasing", "blockout", "font", "fontcolor", "fontsize", "fontstyle", "glowing", "interval", "outline", "printmode", "shadow", "transparency"], │ │ │ │ + request: null, │ │ │ │ + response: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + this.request = new OpenLayers.Format.ArcXML.Request; │ │ │ │ + this.response = new OpenLayers.Format.ArcXML.Response; │ │ │ │ + if (options) { │ │ │ │ + if (options.requesttype == "feature") { │ │ │ │ + this.request.get_image = null; │ │ │ │ + var qry = this.request.get_feature.query; │ │ │ │ + this.addCoordSys(qry.featurecoordsys, options.featureCoordSys); │ │ │ │ + this.addCoordSys(qry.filtercoordsys, options.filterCoordSys); │ │ │ │ + if (options.polygon) { │ │ │ │ + qry.isspatial = true; │ │ │ │ + qry.spatialfilter.polygon = options.polygon │ │ │ │ + } else if (options.envelope) { │ │ │ │ + qry.isspatial = true; │ │ │ │ + qry.spatialfilter.envelope = { │ │ │ │ + minx: 0, │ │ │ │ + miny: 0, │ │ │ │ + maxx: 0, │ │ │ │ + maxy: 0 │ │ │ │ + }; │ │ │ │ + this.parseEnvelope(qry.spatialfilter.envelope, options.envelope) │ │ │ │ + } │ │ │ │ + } else if (options.requesttype == "image") { │ │ │ │ + this.request.get_feature = null; │ │ │ │ + var props = this.request.get_image.properties; │ │ │ │ + this.parseEnvelope(props.envelope, options.envelope); │ │ │ │ + this.addLayers(props.layerlist, options.layers); │ │ │ │ + this.addImageSize(props.imagesize, options.tileSize); │ │ │ │ + this.addCoordSys(props.featurecoordsys, options.featureCoordSys); │ │ │ │ + this.addCoordSys(props.filtercoordsys, options.filterCoordSys) │ │ │ │ + } else { │ │ │ │ + this.request = null │ │ │ │ + } │ │ │ │ + } │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + parseEnvelope: function(env, arr) { │ │ │ │ + if (arr && arr.length == 4) { │ │ │ │ + env.minx = arr[0]; │ │ │ │ + env.miny = arr[1]; │ │ │ │ + env.maxx = arr[2]; │ │ │ │ + env.maxy = arr[3] │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + addLayers: function(ll, lyrs) { │ │ │ │ + for (var lind = 0, len = lyrs.length; lind < len; lind++) { │ │ │ │ + ll.push(lyrs[lind]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + addImageSize: function(imsize, olsize) { │ │ │ │ + if (olsize !== null) { │ │ │ │ + imsize.width = olsize.w; │ │ │ │ + imsize.height = olsize.h; │ │ │ │ + imsize.printwidth = olsize.w; │ │ │ │ + imsize.printheight = olsize.h │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + addCoordSys: function(featOrFilt, fsys) { │ │ │ │ + if (typeof fsys == "string") { │ │ │ │ + featOrFilt.id = parseInt(fsys); │ │ │ │ + featOrFilt.string = fsys │ │ │ │ + } else if (typeof fsys == "object" && fsys.proj !== null) { │ │ │ │ + featOrFilt.id = fsys.proj.srsProjNumber; │ │ │ │ + featOrFilt.string = fsys.proj.srsCode │ │ │ │ + } else { │ │ │ │ + featOrFilt = fsys │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + iserror: function(data) { │ │ │ │ + var ret = null; │ │ │ │ + if (!data) { │ │ │ │ + ret = this.response.error !== "" │ │ │ │ + } else { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ + var errorNodes = data.documentElement.getElementsByTagName("ERROR"); │ │ │ │ + ret = errorNodes !== null && errorNodes.length > 0 │ │ │ │ + } │ │ │ │ + return ret │ │ │ │ + }, │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ + } │ │ │ │ + var arcNode = null; │ │ │ │ + if (data && data.documentElement) { │ │ │ │ + if (data.documentElement.nodeName == "ARCXML") { │ │ │ │ + arcNode = data.documentElement │ │ │ │ + } else { │ │ │ │ + arcNode = data.documentElement.getElementsByTagName("ARCXML")[0] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (!arcNode || arcNode.firstChild.nodeName === "parsererror") { │ │ │ │ + var error, source; │ │ │ │ + try { │ │ │ │ + error = data.firstChild.nodeValue; │ │ │ │ + source = data.firstChild.childNodes[1].firstChild.nodeValue │ │ │ │ + } catch (err) {} │ │ │ │ + throw { │ │ │ │ + message: "Error parsing the ArcXML request", │ │ │ │ + error: error, │ │ │ │ + source: source │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var response = this.parseResponse(arcNode); │ │ │ │ + return response │ │ │ │ + }, │ │ │ │ + write: function(request) { │ │ │ │ + if (!request) { │ │ │ │ + request = this.request │ │ │ │ + } │ │ │ │ + var root = this.createElementNS("", "ARCXML"); │ │ │ │ + root.setAttribute("version", "1.1"); │ │ │ │ + var reqElem = this.createElementNS("", "REQUEST"); │ │ │ │ + if (request.get_image != null) { │ │ │ │ + var getElem = this.createElementNS("", "GET_IMAGE"); │ │ │ │ + reqElem.appendChild(getElem); │ │ │ │ + var propElem = this.createElementNS("", "PROPERTIES"); │ │ │ │ + getElem.appendChild(propElem); │ │ │ │ + var props = request.get_image.properties; │ │ │ │ + if (props.featurecoordsys != null) { │ │ │ │ + var feat = this.createElementNS("", "FEATURECOORDSYS"); │ │ │ │ + propElem.appendChild(feat); │ │ │ │ + if (props.featurecoordsys.id === 0) { │ │ │ │ + feat.setAttribute("string", props.featurecoordsys["string"]) │ │ │ │ + } else { │ │ │ │ + feat.setAttribute("id", props.featurecoordsys.id) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (props.filtercoordsys != null) { │ │ │ │ + var filt = this.createElementNS("", "FILTERCOORDSYS"); │ │ │ │ + propElem.appendChild(filt); │ │ │ │ + if (props.filtercoordsys.id === 0) { │ │ │ │ + filt.setAttribute("string", props.filtercoordsys.string) │ │ │ │ + } else { │ │ │ │ + filt.setAttribute("id", props.filtercoordsys.id) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (props.envelope != null) { │ │ │ │ + var env = this.createElementNS("", "ENVELOPE"); │ │ │ │ + propElem.appendChild(env); │ │ │ │ + env.setAttribute("minx", props.envelope.minx); │ │ │ │ + env.setAttribute("miny", props.envelope.miny); │ │ │ │ + env.setAttribute("maxx", props.envelope.maxx); │ │ │ │ + env.setAttribute("maxy", props.envelope.maxy) │ │ │ │ + } │ │ │ │ + var imagesz = this.createElementNS("", "IMAGESIZE"); │ │ │ │ + propElem.appendChild(imagesz); │ │ │ │ + imagesz.setAttribute("height", props.imagesize.height); │ │ │ │ + imagesz.setAttribute("width", props.imagesize.width); │ │ │ │ + if (props.imagesize.height != props.imagesize.printheight || props.imagesize.width != props.imagesize.printwidth) { │ │ │ │ + imagesz.setAttribute("printheight", props.imagesize.printheight); │ │ │ │ + imagesz.setArrtibute("printwidth", props.imagesize.printwidth) │ │ │ │ + } │ │ │ │ + if (props.background != null) { │ │ │ │ + var backgrnd = this.createElementNS("", "BACKGROUND"); │ │ │ │ + propElem.appendChild(backgrnd); │ │ │ │ + backgrnd.setAttribute("color", props.background.color.r + "," + props.background.color.g + "," + props.background.color.b); │ │ │ │ + if (props.background.transcolor !== null) { │ │ │ │ + backgrnd.setAttribute("transcolor", props.background.transcolor.r + "," + props.background.transcolor.g + "," + props.background.transcolor.b) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (props.layerlist != null && props.layerlist.length > 0) { │ │ │ │ + var layerlst = this.createElementNS("", "LAYERLIST"); │ │ │ │ + propElem.appendChild(layerlst); │ │ │ │ + for (var ld = 0; ld < props.layerlist.length; ld++) { │ │ │ │ + var ldef = this.createElementNS("", "LAYERDEF"); │ │ │ │ + layerlst.appendChild(ldef); │ │ │ │ + ldef.setAttribute("id", props.layerlist[ld].id); │ │ │ │ + ldef.setAttribute("visible", props.layerlist[ld].visible); │ │ │ │ + if (typeof props.layerlist[ld].query == "object") { │ │ │ │ + var query = props.layerlist[ld].query; │ │ │ │ + if (query.where.length < 0) { │ │ │ │ + continue │ │ │ │ + } │ │ │ │ + var queryElem = null; │ │ │ │ + if (typeof query.spatialfilter == "boolean" && query.spatialfilter) { │ │ │ │ + queryElem = this.createElementNS("", "SPATIALQUERY") │ │ │ │ + } else { │ │ │ │ + queryElem = this.createElementNS("", "QUERY") │ │ │ │ + } │ │ │ │ + queryElem.setAttribute("where", query.where); │ │ │ │ + if (typeof query.accuracy == "number" && query.accuracy > 0) { │ │ │ │ + queryElem.setAttribute("accuracy", query.accuracy) │ │ │ │ + } │ │ │ │ + if (typeof query.featurelimit == "number" && query.featurelimit < 2e3) { │ │ │ │ + queryElem.setAttribute("featurelimit", query.featurelimit) │ │ │ │ + } │ │ │ │ + if (typeof query.subfields == "string" && query.subfields != "#ALL#") { │ │ │ │ + queryElem.setAttribute("subfields", query.subfields) │ │ │ │ + } │ │ │ │ + if (typeof query.joinexpression == "string" && query.joinexpression.length > 0) { │ │ │ │ + queryElem.setAttribute("joinexpression", query.joinexpression) │ │ │ │ + } │ │ │ │ + if (typeof query.jointables == "string" && query.jointables.length > 0) { │ │ │ │ + queryElem.setAttribute("jointables", query.jointables) │ │ │ │ + } │ │ │ │ + ldef.appendChild(queryElem) │ │ │ │ + } │ │ │ │ + if (typeof props.layerlist[ld].renderer == "object") { │ │ │ │ + this.addRenderer(ldef, props.layerlist[ld].renderer) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else if (request.get_feature != null) { │ │ │ │ + var getElem = this.createElementNS("", "GET_FEATURES"); │ │ │ │ + getElem.setAttribute("outputmode", "newxml"); │ │ │ │ + getElem.setAttribute("checkesc", "true"); │ │ │ │ + if (request.get_feature.geometry) { │ │ │ │ + getElem.setAttribute("geometry", request.get_feature.geometry) │ │ │ │ + } else { │ │ │ │ + getElem.setAttribute("geometry", "false") │ │ │ │ + } │ │ │ │ + if (request.get_feature.compact) { │ │ │ │ + getElem.setAttribute("compact", request.get_feature.compact) │ │ │ │ + } │ │ │ │ + if (request.get_feature.featurelimit == "number") { │ │ │ │ + getElem.setAttribute("featurelimit", request.get_feature.featurelimit) │ │ │ │ + } │ │ │ │ + getElem.setAttribute("globalenvelope", "true"); │ │ │ │ + reqElem.appendChild(getElem); │ │ │ │ + if (request.get_feature.layer != null && request.get_feature.layer.length > 0) { │ │ │ │ + var lyrElem = this.createElementNS("", "LAYER"); │ │ │ │ + lyrElem.setAttribute("id", request.get_feature.layer); │ │ │ │ + getElem.appendChild(lyrElem) │ │ │ │ + } │ │ │ │ + var fquery = request.get_feature.query; │ │ │ │ + if (fquery != null) { │ │ │ │ + var qElem = null; │ │ │ │ + if (fquery.isspatial) { │ │ │ │ + qElem = this.createElementNS("", "SPATIALQUERY") │ │ │ │ + } else { │ │ │ │ + qElem = this.createElementNS("", "QUERY") │ │ │ │ + } │ │ │ │ + getElem.appendChild(qElem); │ │ │ │ + if (typeof fquery.accuracy == "number") { │ │ │ │ + qElem.setAttribute("accuracy", fquery.accuracy) │ │ │ │ + } │ │ │ │ + if (fquery.featurecoordsys != null) { │ │ │ │ + var fcsElem1 = this.createElementNS("", "FEATURECOORDSYS"); │ │ │ │ + if (fquery.featurecoordsys.id == 0) { │ │ │ │ + fcsElem1.setAttribute("string", fquery.featurecoordsys.string) │ │ │ │ + } else { │ │ │ │ + fcsElem1.setAttribute("id", fquery.featurecoordsys.id) │ │ │ │ + } │ │ │ │ + qElem.appendChild(fcsElem1) │ │ │ │ + } │ │ │ │ + if (fquery.filtercoordsys != null) { │ │ │ │ + var fcsElem2 = this.createElementNS("", "FILTERCOORDSYS"); │ │ │ │ + if (fquery.filtercoordsys.id === 0) { │ │ │ │ + fcsElem2.setAttribute("string", fquery.filtercoordsys.string) │ │ │ │ + } else { │ │ │ │ + fcsElem2.setAttribute("id", fquery.filtercoordsys.id) │ │ │ │ + } │ │ │ │ + qElem.appendChild(fcsElem2) │ │ │ │ + } │ │ │ │ + if (fquery.buffer > 0) { │ │ │ │ + var bufElem = this.createElementNS("", "BUFFER"); │ │ │ │ + bufElem.setAttribute("distance", fquery.buffer); │ │ │ │ + qElem.appendChild(bufElem) │ │ │ │ + } │ │ │ │ + if (fquery.isspatial) { │ │ │ │ + var spfElem = this.createElementNS("", "SPATIALFILTER"); │ │ │ │ + spfElem.setAttribute("relation", fquery.spatialfilter.relation); │ │ │ │ + qElem.appendChild(spfElem); │ │ │ │ + if (fquery.spatialfilter.envelope) { │ │ │ │ + var envElem = this.createElementNS("", "ENVELOPE"); │ │ │ │ + envElem.setAttribute("minx", fquery.spatialfilter.envelope.minx); │ │ │ │ + envElem.setAttribute("miny", fquery.spatialfilter.envelope.miny); │ │ │ │ + envElem.setAttribute("maxx", fquery.spatialfilter.envelope.maxx); │ │ │ │ + envElem.setAttribute("maxy", fquery.spatialfilter.envelope.maxy); │ │ │ │ + spfElem.appendChild(envElem) │ │ │ │ + } else if (typeof fquery.spatialfilter.polygon == "object") { │ │ │ │ + spfElem.appendChild(this.writePolygonGeometry(fquery.spatialfilter.polygon)) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (fquery.where != null && fquery.where.length > 0) { │ │ │ │ + qElem.setAttribute("where", fquery.where) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + root.appendChild(reqElem); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [root]) │ │ │ │ + }, │ │ │ │ + addGroupRenderer: function(ldef, toprenderer) { │ │ │ │ + var topRelem = this.createElementNS("", "GROUPRENDERER"); │ │ │ │ + ldef.appendChild(topRelem); │ │ │ │ + for (var rind = 0; rind < toprenderer.length; rind++) { │ │ │ │ + var renderer = toprenderer[rind]; │ │ │ │ + this.addRenderer(topRelem, renderer) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + addRenderer: function(topRelem, renderer) { │ │ │ │ + if (OpenLayers.Util.isArray(renderer)) { │ │ │ │ + this.addGroupRenderer(topRelem, renderer) │ │ │ │ + } else { │ │ │ │ + var renderElem = this.createElementNS("", renderer.type.toUpperCase() + "RENDERER"); │ │ │ │ + topRelem.appendChild(renderElem); │ │ │ │ + if (renderElem.tagName == "VALUEMAPRENDERER") { │ │ │ │ + this.addValueMapRenderer(renderElem, renderer) │ │ │ │ + } else if (renderElem.tagName == "VALUEMAPLABELRENDERER") { │ │ │ │ + this.addValueMapLabelRenderer(renderElem, renderer) │ │ │ │ + } else if (renderElem.tagName == "SIMPLELABELRENDERER") { │ │ │ │ + this.addSimpleLabelRenderer(renderElem, renderer) │ │ │ │ + } else if (renderElem.tagName == "SCALEDEPENDENTRENDERER") { │ │ │ │ + this.addScaleDependentRenderer(renderElem, renderer) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + addScaleDependentRenderer: function(renderElem, renderer) { │ │ │ │ + if (typeof renderer.lower == "string" || typeof renderer.lower == "number") { │ │ │ │ + renderElem.setAttribute("lower", renderer.lower) │ │ │ │ + } │ │ │ │ + if (typeof renderer.upper == "string" || typeof renderer.upper == "number") { │ │ │ │ + renderElem.setAttribute("upper", renderer.upper) │ │ │ │ + } │ │ │ │ + this.addRenderer(renderElem, renderer.renderer) │ │ │ │ + }, │ │ │ │ + addValueMapLabelRenderer: function(renderElem, renderer) { │ │ │ │ + renderElem.setAttribute("lookupfield", renderer.lookupfield); │ │ │ │ + renderElem.setAttribute("labelfield", renderer.labelfield); │ │ │ │ + if (typeof renderer.exacts == "object") { │ │ │ │ + for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) { │ │ │ │ + var exact = renderer.exacts[ext]; │ │ │ │ + var eelem = this.createElementNS("", "EXACT"); │ │ │ │ + if (typeof exact.value == "string") { │ │ │ │ + eelem.setAttribute("value", exact.value) │ │ │ │ + } │ │ │ │ + if (typeof exact.label == "string") { │ │ │ │ + eelem.setAttribute("label", exact.label) │ │ │ │ + } │ │ │ │ + if (typeof exact.method == "string") { │ │ │ │ + eelem.setAttribute("method", exact.method) │ │ │ │ + } │ │ │ │ + renderElem.appendChild(eelem); │ │ │ │ + if (typeof exact.symbol == "object") { │ │ │ │ + var selem = null; │ │ │ │ + if (exact.symbol.type == "text") { │ │ │ │ + selem = this.createElementNS("", "TEXTSYMBOL") │ │ │ │ + } │ │ │ │ + if (selem != null) { │ │ │ │ + var keys = this.fontStyleKeys; │ │ │ │ + for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ + var key = keys[i]; │ │ │ │ + if (exact.symbol[key]) { │ │ │ │ + selem.setAttribute(key, exact.symbol[key]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + eelem.appendChild(selem) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + addValueMapRenderer: function(renderElem, renderer) { │ │ │ │ + renderElem.setAttribute("lookupfield", renderer.lookupfield); │ │ │ │ + if (typeof renderer.ranges == "object") { │ │ │ │ + for (var rng = 0, rnglen = renderer.ranges.length; rng < rnglen; rng++) { │ │ │ │ + var range = renderer.ranges[rng]; │ │ │ │ + var relem = this.createElementNS("", "RANGE"); │ │ │ │ + relem.setAttribute("lower", range.lower); │ │ │ │ + relem.setAttribute("upper", range.upper); │ │ │ │ + renderElem.appendChild(relem); │ │ │ │ + if (typeof range.symbol == "object") { │ │ │ │ + var selem = null; │ │ │ │ + if (range.symbol.type == "simplepolygon") { │ │ │ │ + selem = this.createElementNS("", "SIMPLEPOLYGONSYMBOL") │ │ │ │ + } │ │ │ │ + if (selem != null) { │ │ │ │ + if (typeof range.symbol.boundarycolor == "string") { │ │ │ │ + selem.setAttribute("boundarycolor", range.symbol.boundarycolor) │ │ │ │ + } │ │ │ │ + if (typeof range.symbol.fillcolor == "string") { │ │ │ │ + selem.setAttribute("fillcolor", range.symbol.fillcolor) │ │ │ │ + } │ │ │ │ + if (typeof range.symbol.filltransparency == "number") { │ │ │ │ + selem.setAttribute("filltransparency", range.symbol.filltransparency) │ │ │ │ + } │ │ │ │ + relem.appendChild(selem) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else if (typeof renderer.exacts == "object") { │ │ │ │ + for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) { │ │ │ │ + var exact = renderer.exacts[ext]; │ │ │ │ + var eelem = this.createElementNS("", "EXACT"); │ │ │ │ + if (typeof exact.value == "string") { │ │ │ │ + eelem.setAttribute("value", exact.value) │ │ │ │ + } │ │ │ │ + if (typeof exact.label == "string") { │ │ │ │ + eelem.setAttribute("label", exact.label) │ │ │ │ + } │ │ │ │ + if (typeof exact.method == "string") { │ │ │ │ + eelem.setAttribute("method", exact.method) │ │ │ │ + } │ │ │ │ + renderElem.appendChild(eelem); │ │ │ │ + if (typeof exact.symbol == "object") { │ │ │ │ + var selem = null; │ │ │ │ + if (exact.symbol.type == "simplemarker") { │ │ │ │ + selem = this.createElementNS("", "SIMPLEMARKERSYMBOL") │ │ │ │ + } │ │ │ │ + if (selem != null) { │ │ │ │ + if (typeof exact.symbol.antialiasing == "string") { │ │ │ │ + selem.setAttribute("antialiasing", exact.symbol.antialiasing) │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.color == "string") { │ │ │ │ + selem.setAttribute("color", exact.symbol.color) │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.outline == "string") { │ │ │ │ + selem.setAttribute("outline", exact.symbol.outline) │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.overlap == "string") { │ │ │ │ + selem.setAttribute("overlap", exact.symbol.overlap) │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.shadow == "string") { │ │ │ │ + selem.setAttribute("shadow", exact.symbol.shadow) │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.transparency == "number") { │ │ │ │ + selem.setAttribute("transparency", exact.symbol.transparency) │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.usecentroid == "string") { │ │ │ │ + selem.setAttribute("usecentroid", exact.symbol.usecentroid) │ │ │ │ + } │ │ │ │ + if (typeof exact.symbol.width == "number") { │ │ │ │ + selem.setAttribute("width", exact.symbol.width) │ │ │ │ + } │ │ │ │ + eelem.appendChild(selem) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + addSimpleLabelRenderer: function(renderElem, renderer) { │ │ │ │ + renderElem.setAttribute("field", renderer.field); │ │ │ │ + var keys = ["featureweight", "howmanylabels", "labelbufferratio", "labelpriorities", "labelweight", "linelabelposition", "rotationalangles"]; │ │ │ │ + for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ + var key = keys[i]; │ │ │ │ + if (renderer[key]) { │ │ │ │ + renderElem.setAttribute(key, renderer[key]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (renderer.symbol.type == "text") { │ │ │ │ + var symbol = renderer.symbol; │ │ │ │ + var selem = this.createElementNS("", "TEXTSYMBOL"); │ │ │ │ + renderElem.appendChild(selem); │ │ │ │ + var keys = this.fontStyleKeys; │ │ │ │ + for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ + var key = keys[i]; │ │ │ │ + if (symbol[key]) { │ │ │ │ + selem.setAttribute(key, renderer[key]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + writePolygonGeometry: function(polygon) { │ │ │ │ + if (!(polygon instanceof OpenLayers.Geometry.Polygon)) { │ │ │ │ + throw { │ │ │ │ + message: "Cannot write polygon geometry to ArcXML with an " + polygon.CLASS_NAME + " object.", │ │ │ │ + geometry: polygon │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var polyElem = this.createElementNS("", "POLYGON"); │ │ │ │ + for (var ln = 0, lnlen = polygon.components.length; ln < lnlen; ln++) { │ │ │ │ + var ring = polygon.components[ln]; │ │ │ │ + var ringElem = this.createElementNS("", "RING"); │ │ │ │ + for (var rn = 0, rnlen = ring.components.length; rn < rnlen; rn++) { │ │ │ │ + var point = ring.components[rn]; │ │ │ │ + var pointElem = this.createElementNS("", "POINT"); │ │ │ │ + pointElem.setAttribute("x", point.x); │ │ │ │ + pointElem.setAttribute("y", point.y); │ │ │ │ + ringElem.appendChild(pointElem) │ │ │ │ + } │ │ │ │ + polyElem.appendChild(ringElem) │ │ │ │ + } │ │ │ │ + return polyElem │ │ │ │ + }, │ │ │ │ + parseResponse: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + var newData = new OpenLayers.Format.XML; │ │ │ │ + data = newData.read(data) │ │ │ │ + } │ │ │ │ + var response = new OpenLayers.Format.ArcXML.Response; │ │ │ │ + var errorNode = data.getElementsByTagName("ERROR"); │ │ │ │ + if (errorNode != null && errorNode.length > 0) { │ │ │ │ + response.error = this.getChildValue(errorNode, "Unknown error.") │ │ │ │ + } else { │ │ │ │ + var responseNode = data.getElementsByTagName("RESPONSE"); │ │ │ │ + if (responseNode == null || responseNode.length == 0) { │ │ │ │ + response.error = "No RESPONSE tag found in ArcXML response."; │ │ │ │ + return response │ │ │ │ + } │ │ │ │ + var rtype = responseNode[0].firstChild.nodeName; │ │ │ │ + if (rtype == "#text") { │ │ │ │ + rtype = responseNode[0].firstChild.nextSibling.nodeName │ │ │ │ + } │ │ │ │ + if (rtype == "IMAGE") { │ │ │ │ + var envelopeNode = data.getElementsByTagName("ENVELOPE"); │ │ │ │ + var outputNode = data.getElementsByTagName("OUTPUT"); │ │ │ │ + if (envelopeNode == null || envelopeNode.length == 0) { │ │ │ │ + response.error = "No ENVELOPE tag found in ArcXML response." │ │ │ │ + } else if (outputNode == null || outputNode.length == 0) { │ │ │ │ + response.error = "No OUTPUT tag found in ArcXML response." │ │ │ │ + } else { │ │ │ │ + var envAttr = this.parseAttributes(envelopeNode[0]); │ │ │ │ + var outputAttr = this.parseAttributes(outputNode[0]); │ │ │ │ + if (typeof outputAttr.type == "string") { │ │ │ │ + response.image = { │ │ │ │ + envelope: envAttr, │ │ │ │ + output: { │ │ │ │ + type: outputAttr.type, │ │ │ │ + data: this.getChildValue(outputNode[0]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + response.image = { │ │ │ │ + envelope: envAttr, │ │ │ │ + output: outputAttr │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else if (rtype == "FEATURES") { │ │ │ │ + var features = responseNode[0].getElementsByTagName("FEATURES"); │ │ │ │ + var featureCount = features[0].getElementsByTagName("FEATURECOUNT"); │ │ │ │ + response.features.featurecount = featureCount[0].getAttribute("count"); │ │ │ │ + if (response.features.featurecount > 0) { │ │ │ │ + var envelope = features[0].getElementsByTagName("ENVELOPE"); │ │ │ │ + response.features.envelope = this.parseAttributes(envelope[0], typeof 0); │ │ │ │ + var featureList = features[0].getElementsByTagName("FEATURE"); │ │ │ │ + for (var fn = 0; fn < featureList.length; fn++) { │ │ │ │ + var feature = new OpenLayers.Feature.Vector; │ │ │ │ + var fields = featureList[fn].getElementsByTagName("FIELD"); │ │ │ │ + for (var fdn = 0; fdn < fields.length; fdn++) { │ │ │ │ + var fieldName = fields[fdn].getAttribute("name"); │ │ │ │ + var fieldValue = fields[fdn].getAttribute("value"); │ │ │ │ + feature.attributes[fieldName] = fieldValue │ │ │ │ + } │ │ │ │ + var geom = featureList[fn].getElementsByTagName("POLYGON"); │ │ │ │ + if (geom.length > 0) { │ │ │ │ + var ring = geom[0].getElementsByTagName("RING"); │ │ │ │ + var polys = []; │ │ │ │ + for (var rn = 0; rn < ring.length; rn++) { │ │ │ │ + var linearRings = []; │ │ │ │ + linearRings.push(this.parsePointGeometry(ring[rn])); │ │ │ │ + var holes = ring[rn].getElementsByTagName("HOLE"); │ │ │ │ + for (var hn = 0; hn < holes.length; hn++) { │ │ │ │ + linearRings.push(this.parsePointGeometry(holes[hn])) │ │ │ │ + } │ │ │ │ + holes = null; │ │ │ │ + polys.push(new OpenLayers.Geometry.Polygon(linearRings)); │ │ │ │ + linearRings = null │ │ │ │ + } │ │ │ │ + ring = null; │ │ │ │ + if (polys.length == 1) { │ │ │ │ + feature.geometry = polys[0] │ │ │ │ + } else { │ │ │ │ + feature.geometry = new OpenLayers.Geometry.MultiPolygon(polys) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + response.features.feature.push(feature) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + response.error = "Unidentified response type." │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return response │ │ │ │ + }, │ │ │ │ + parseAttributes: function(node, type) { │ │ │ │ + var attributes = {}; │ │ │ │ + for (var attr = 0; attr < node.attributes.length; attr++) { │ │ │ │ + if (type == "number") { │ │ │ │ + attributes[node.attributes[attr].nodeName] = parseFloat(node.attributes[attr].nodeValue) │ │ │ │ + } else { │ │ │ │ + attributes[node.attributes[attr].nodeName] = node.attributes[attr].nodeValue │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return attributes │ │ │ │ + }, │ │ │ │ + parsePointGeometry: function(node) { │ │ │ │ + var ringPoints = []; │ │ │ │ + var coords = node.getElementsByTagName("COORDS"); │ │ │ │ + if (coords.length > 0) { │ │ │ │ + var coordArr = this.getChildValue(coords[0]); │ │ │ │ + coordArr = coordArr.split(/;/); │ │ │ │ + for (var cn = 0; cn < coordArr.length; cn++) { │ │ │ │ + var coordItems = coordArr[cn].split(/ /); │ │ │ │ + ringPoints.push(new OpenLayers.Geometry.Point(coordItems[0], coordItems[1])) │ │ │ │ + } │ │ │ │ + coords = null │ │ │ │ + } else { │ │ │ │ + var point = node.getElementsByTagName("POINT"); │ │ │ │ + if (point.length > 0) { │ │ │ │ + for (var pn = 0; pn < point.length; pn++) { │ │ │ │ + ringPoints.push(new OpenLayers.Geometry.Point(parseFloat(point[pn].getAttribute("x")), parseFloat(point[pn].getAttribute("y")))) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + point = null │ │ │ │ + } │ │ │ │ + return new OpenLayers.Geometry.LinearRing(ringPoints) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.ArcXML" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.ArcXML.Request = OpenLayers.Class({ │ │ │ │ + initialize: function(params) { │ │ │ │ + var defaults = { │ │ │ │ + get_image: { │ │ │ │ + properties: { │ │ │ │ + background: null, │ │ │ │ + draw: true, │ │ │ │ + envelope: { │ │ │ │ + minx: 0, │ │ │ │ + miny: 0, │ │ │ │ + maxx: 0, │ │ │ │ + maxy: 0 │ │ │ │ + }, │ │ │ │ + featurecoordsys: { │ │ │ │ + id: 0, │ │ │ │ + string: "", │ │ │ │ + datumtransformid: 0, │ │ │ │ + datumtransformstring: "" │ │ │ │ + }, │ │ │ │ + filtercoordsys: { │ │ │ │ + id: 0, │ │ │ │ + string: "", │ │ │ │ + datumtransformid: 0, │ │ │ │ + datumtransformstring: "" │ │ │ │ + }, │ │ │ │ + imagesize: { │ │ │ │ + height: 0, │ │ │ │ + width: 0, │ │ │ │ + dpi: 96, │ │ │ │ + printheight: 0, │ │ │ │ + printwidth: 0, │ │ │ │ + scalesymbols: false │ │ │ │ + }, │ │ │ │ + layerlist: [], │ │ │ │ + output: { │ │ │ │ + baseurl: "", │ │ │ │ + legendbaseurl: "", │ │ │ │ + legendname: "", │ │ │ │ + legendpath: "", │ │ │ │ + legendurl: "", │ │ │ │ + name: "", │ │ │ │ + path: "", │ │ │ │ + type: "jpg", │ │ │ │ + url: "" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + get_feature: { │ │ │ │ + layer: "", │ │ │ │ + query: { │ │ │ │ + isspatial: false, │ │ │ │ + featurecoordsys: { │ │ │ │ + id: 0, │ │ │ │ + string: "", │ │ │ │ + datumtransformid: 0, │ │ │ │ + datumtransformstring: "" │ │ │ │ + }, │ │ │ │ + filtercoordsys: { │ │ │ │ + id: 0, │ │ │ │ + string: "", │ │ │ │ + datumtransformid: 0, │ │ │ │ + datumtransformstring: "" │ │ │ │ + }, │ │ │ │ + buffer: 0, │ │ │ │ + where: "", │ │ │ │ + spatialfilter: { │ │ │ │ + relation: "envelope_intersection", │ │ │ │ + envelope: null │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + environment: { │ │ │ │ + separators: { │ │ │ │ + cs: " ", │ │ │ │ + ts: ";" │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + layer: [], │ │ │ │ + workspaces: [] │ │ │ │ + }; │ │ │ │ + return OpenLayers.Util.extend(this, defaults) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.ArcXML.Request" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.ArcXML.Response = OpenLayers.Class({ │ │ │ │ + initialize: function(params) { │ │ │ │ + var defaults = { │ │ │ │ + image: { │ │ │ │ + envelope: null, │ │ │ │ + output: "" │ │ │ │ + }, │ │ │ │ + features: { │ │ │ │ + featurecount: 0, │ │ │ │ + envelope: null, │ │ │ │ + feature: [] │ │ │ │ + }, │ │ │ │ + error: "" │ │ │ │ + }; │ │ │ │ + return OpenLayers.Util.extend(this, defaults) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.ArcXML.Response" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.ArcIMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + DEFAULT_PARAMS: { │ │ │ │ + ClientVersion: "9.2", │ │ │ │ + ServiceName: "" │ │ │ │ + }, │ │ │ │ + featureCoordSys: "4326", │ │ │ │ + filterCoordSys: "4326", │ │ │ │ + layers: null, │ │ │ │ + async: true, │ │ │ │ + name: "ArcIMS", │ │ │ │ + isBaseLayer: true, │ │ │ │ + DEFAULT_OPTIONS: { │ │ │ │ + tileSize: new OpenLayers.Size(512, 512), │ │ │ │ + featureCoordSys: "4326", │ │ │ │ + filterCoordSys: "4326", │ │ │ │ + layers: null, │ │ │ │ + isBaseLayer: true, │ │ │ │ + async: true, │ │ │ │ + name: "ArcIMS" │ │ │ │ + }, │ │ │ │ + initialize: function(name, url, options) { │ │ │ │ + this.tileSize = new OpenLayers.Size(512, 512); │ │ │ │ + this.params = OpenLayers.Util.applyDefaults({ │ │ │ │ + ServiceName: options.serviceName │ │ │ │ + }, this.DEFAULT_PARAMS); │ │ │ │ + this.options = OpenLayers.Util.applyDefaults(options, this.DEFAULT_OPTIONS); │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, [name, url, this.params, options]); │ │ │ │ + if (this.transparent) { │ │ │ │ + if (!this.isBaseLayer) { │ │ │ │ + this.isBaseLayer = false │ │ │ │ + } │ │ │ │ + if (this.format == "image/jpeg") { │ │ │ │ + this.format = OpenLayers.Util.alphaHack() ? "image/gif" : "image/png" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.options.layers === null) { │ │ │ │ + this.options.layers = [] │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + var url = ""; │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var axlReq = new OpenLayers.Format.ArcXML(OpenLayers.Util.extend(this.options, { │ │ │ │ + requesttype: "image", │ │ │ │ + envelope: bounds.toArray(), │ │ │ │ + tileSize: this.tileSize │ │ │ │ + })); │ │ │ │ + var req = new OpenLayers.Request.POST({ │ │ │ │ + url: this.getFullRequestString(), │ │ │ │ + data: axlReq.write(), │ │ │ │ + async: false │ │ │ │ + }); │ │ │ │ + if (req != null) { │ │ │ │ + var doc = req.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = req.responseText │ │ │ │ + } │ │ │ │ + var axlResp = new OpenLayers.Format.ArcXML; │ │ │ │ + var arcxml = axlResp.read(doc); │ │ │ │ + url = this.getUrlOrImage(arcxml.image.output) │ │ │ │ + } │ │ │ │ + return url │ │ │ │ + }, │ │ │ │ + getURLasync: function(bounds, callback, scope) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var axlReq = new OpenLayers.Format.ArcXML(OpenLayers.Util.extend(this.options, { │ │ │ │ + requesttype: "image", │ │ │ │ + envelope: bounds.toArray(), │ │ │ │ + tileSize: this.tileSize │ │ │ │ + })); │ │ │ │ + OpenLayers.Request.POST({ │ │ │ │ + url: this.getFullRequestString(), │ │ │ │ + async: true, │ │ │ │ + data: axlReq.write(), │ │ │ │ + callback: function(req) { │ │ │ │ + var doc = req.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = req.responseText │ │ │ │ + } │ │ │ │ + var axlResp = new OpenLayers.Format.ArcXML; │ │ │ │ + var arcxml = axlResp.read(doc); │ │ │ │ + callback.call(scope, this.getUrlOrImage(arcxml.image.output)) │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + getUrlOrImage: function(output) { │ │ │ │ + var ret = ""; │ │ │ │ + if (output.url) { │ │ │ │ + ret = output.url │ │ │ │ + } else if (output.data) { │ │ │ │ + ret = "data:image/" + output.type + ";base64," + output.data │ │ │ │ + } │ │ │ │ + return ret │ │ │ │ + }, │ │ │ │ + setLayerQuery: function(id, querydef) { │ │ │ │ + for (var lyr = 0; lyr < this.options.layers.length; lyr++) { │ │ │ │ + if (id == this.options.layers[lyr].id) { │ │ │ │ + this.options.layers[lyr].query = querydef; │ │ │ │ + return │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.options.layers.push({ │ │ │ │ + id: id, │ │ │ │ + visible: true, │ │ │ │ + query: querydef │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + getFeatureInfo: function(geometry, layer, options) { │ │ │ │ + var buffer = options.buffer || 1; │ │ │ │ + var callback = options.callback || function() {}; │ │ │ │ + var scope = options.scope || window; │ │ │ │ + var requestOptions = {}; │ │ │ │ + OpenLayers.Util.extend(requestOptions, this.options); │ │ │ │ + requestOptions.requesttype = "feature"; │ │ │ │ + if (geometry instanceof OpenLayers.LonLat) { │ │ │ │ + requestOptions.polygon = null; │ │ │ │ + requestOptions.envelope = [geometry.lon - buffer, geometry.lat - buffer, geometry.lon + buffer, geometry.lat + buffer] │ │ │ │ + } else if (geometry instanceof OpenLayers.Geometry.Polygon) { │ │ │ │ + requestOptions.envelope = null; │ │ │ │ + requestOptions.polygon = geometry │ │ │ │ + } │ │ │ │ + var arcxml = new OpenLayers.Format.ArcXML(requestOptions); │ │ │ │ + OpenLayers.Util.extend(arcxml.request.get_feature, options); │ │ │ │ + arcxml.request.get_feature.layer = layer.id; │ │ │ │ + if (typeof layer.query.accuracy == "number") { │ │ │ │ + arcxml.request.get_feature.query.accuracy = layer.query.accuracy │ │ │ │ + } else { │ │ │ │ + var mapCenter = this.map.getCenter(); │ │ │ │ + var viewPx = this.map.getViewPortPxFromLonLat(mapCenter); │ │ │ │ + viewPx.x++; │ │ │ │ + var mapOffCenter = this.map.getLonLatFromPixel(viewPx); │ │ │ │ + arcxml.request.get_feature.query.accuracy = mapOffCenter.lon - mapCenter.lon │ │ │ │ + } │ │ │ │ + arcxml.request.get_feature.query.where = layer.query.where; │ │ │ │ + arcxml.request.get_feature.query.spatialfilter.relation = "area_intersection"; │ │ │ │ + OpenLayers.Request.POST({ │ │ │ │ + url: this.getFullRequestString({ │ │ │ │ + CustomService: "Query" │ │ │ │ + }), │ │ │ │ + data: arcxml.write(), │ │ │ │ + callback: function(request) { │ │ │ │ + var response = arcxml.parseResponse(request.responseText); │ │ │ │ + if (!arcxml.iserror()) { │ │ │ │ + callback.call(scope, response.features) │ │ │ │ + } else { │ │ │ │ + callback.call(scope, null) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.ArcIMS(this.name, this.url, this.getOptions()) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.ArcIMS" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.TMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + serviceVersion: "1.0.0", │ │ │ │ + layername: null, │ │ │ │ + type: null, │ │ │ │ + isBaseLayer: true, │ │ │ │ + tileOrigin: null, │ │ │ │ + serverResolutions: null, │ │ │ │ + zoomOffset: 0, │ │ │ │ + initialize: function(name, url, options) { │ │ │ │ + var newArguments = []; │ │ │ │ + newArguments.push(name, url, {}, options); │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments) │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.TMS(this.name, this.url, this.getOptions()) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ + var y = Math.round((bounds.bottom - this.tileOrigin.lat) / (res * this.tileSize.h)); │ │ │ │ + var z = this.getServerZoom(); │ │ │ │ + var path = this.serviceVersion + "/" + this.layername + "/" + z + "/" + x + "/" + y + "." + this.type; │ │ │ │ + var url = this.url; │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(path, url) │ │ │ │ + } │ │ │ │ + return url + path │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); │ │ │ │ + if (!this.tileOrigin) { │ │ │ │ + this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left, this.map.maxExtent.bottom) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.TMS" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.KaMapCache = OpenLayers.Class(OpenLayers.Layer.KaMap, { │ │ │ │ + IMAGE_EXTENSIONS: { │ │ │ │ + jpeg: "jpg", │ │ │ │ + gif: "gif", │ │ │ │ + png: "png", │ │ │ │ + png8: "png", │ │ │ │ + png24: "png", │ │ │ │ + dithered: "png" │ │ │ │ + }, │ │ │ │ + DEFAULT_FORMAT: "jpeg", │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + OpenLayers.Layer.KaMap.prototype.initialize.apply(this, arguments); │ │ │ │ + this.extension = this.IMAGE_EXTENSIONS[this.params.i.toLowerCase() || this.DEFAULT_FORMAT] │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ + var scale = Math.round(this.map.getScale() * 1e4) / 1e4; │ │ │ │ + var pX = Math.round(bounds.left / mapRes); │ │ │ │ + var pY = -Math.round(bounds.top / mapRes); │ │ │ │ + var metaX = Math.floor(pX / this.tileSize.w / this.params.metaTileSize.w) * this.tileSize.w * this.params.metaTileSize.w; │ │ │ │ + var metaY = Math.floor(pY / this.tileSize.h / this.params.metaTileSize.h) * this.tileSize.h * this.params.metaTileSize.h; │ │ │ │ + var components = ["/", this.params.map, "/", scale, "/", this.params.g.replace(/\s/g, "_"), "/def/t", metaY, "/l", metaX, "/t", pY, "l", pX, ".", this.extension]; │ │ │ │ + var url = this.url; │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(components.join(""), url) │ │ │ │ + } │ │ │ │ + return url + components.join("") │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.KaMapCache" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ + name: "OpenStreetMap", │ │ │ │ + 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"], │ │ │ │ + attribution: "© <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors", │ │ │ │ + sphericalMercator: true, │ │ │ │ + wrapDateLine: true, │ │ │ │ + tileOptions: null, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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.Format.Text = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ + defaultStyle: null, │ │ │ │ + extractStyles: true, │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + if (options.extractStyles !== false) { │ │ │ │ + options.defaultStyle = { │ │ │ │ + externalGraphic: OpenLayers.Util.getImageLocation("marker.png"), │ │ │ │ + graphicWidth: 21, │ │ │ │ + graphicHeight: 25, │ │ │ │ + graphicXOffset: -10.5, │ │ │ │ + graphicYOffset: -12.5 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + OpenLayers.Format.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + read: function(text) { │ │ │ │ + var lines = text.split("\n"); │ │ │ │ + var columns; │ │ │ │ + var features = []; │ │ │ │ + for (var lcv = 0; lcv < lines.length - 1; lcv++) { │ │ │ │ + var currLine = lines[lcv].replace(/^\s*/, "").replace(/\s*$/, ""); │ │ │ │ + if (currLine.charAt(0) != "#") { │ │ │ │ + if (!columns) { │ │ │ │ + columns = currLine.split("\t") │ │ │ │ + } else { │ │ │ │ + var vals = currLine.split("\t"); │ │ │ │ + var geometry = new OpenLayers.Geometry.Point(0, 0); │ │ │ │ + var attributes = {}; │ │ │ │ + var style = this.defaultStyle ? OpenLayers.Util.applyDefaults({}, this.defaultStyle) : null; │ │ │ │ + var icon, iconSize, iconOffset, overflow; │ │ │ │ + var set = false; │ │ │ │ + for (var valIndex = 0; valIndex < vals.length; valIndex++) { │ │ │ │ + if (vals[valIndex]) { │ │ │ │ + if (columns[valIndex] == "point") { │ │ │ │ + var coords = vals[valIndex].split(","); │ │ │ │ + geometry.y = parseFloat(coords[0]); │ │ │ │ + geometry.x = parseFloat(coords[1]); │ │ │ │ + set = true │ │ │ │ + } else if (columns[valIndex] == "lat") { │ │ │ │ + geometry.y = parseFloat(vals[valIndex]); │ │ │ │ + set = true │ │ │ │ + } else if (columns[valIndex] == "lon") { │ │ │ │ + geometry.x = parseFloat(vals[valIndex]); │ │ │ │ + set = true │ │ │ │ + } else if (columns[valIndex] == "title") attributes["title"] = vals[valIndex]; │ │ │ │ + else if (columns[valIndex] == "image" || columns[valIndex] == "icon" && style) { │ │ │ │ + style["externalGraphic"] = vals[valIndex] │ │ │ │ + } else if (columns[valIndex] == "iconSize" && style) { │ │ │ │ + var size = vals[valIndex].split(","); │ │ │ │ + style["graphicWidth"] = parseFloat(size[0]); │ │ │ │ + style["graphicHeight"] = parseFloat(size[1]) │ │ │ │ + } else if (columns[valIndex] == "iconOffset" && style) { │ │ │ │ + var offset = vals[valIndex].split(","); │ │ │ │ + style["graphicXOffset"] = parseFloat(offset[0]); │ │ │ │ + style["graphicYOffset"] = parseFloat(offset[1]) │ │ │ │ + } else if (columns[valIndex] == "description") { │ │ │ │ + attributes["description"] = vals[valIndex] │ │ │ │ + } else if (columns[valIndex] == "overflow") { │ │ │ │ + attributes["overflow"] = vals[valIndex] │ │ │ │ + } else { │ │ │ │ + attributes[columns[valIndex]] = vals[valIndex] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (set) { │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + geometry.transform(this.externalProjection, this.internalProjection) │ │ │ │ + } │ │ │ │ + var feature = new OpenLayers.Feature.Vector(geometry, attributes, style); │ │ │ │ + features.push(feature) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return features │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.Text" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.Text = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ + location: null, │ │ │ │ + features: null, │ │ │ │ + formatOptions: null, │ │ │ │ + selectedFeature: null, │ │ │ │ + initialize: function(name, options) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.initialize.apply(this, arguments); │ │ │ │ + this.features = [] │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ + this.clearFeatures(); │ │ │ │ + this.features = null │ │ │ │ + }, │ │ │ │ + loadText: function() { │ │ │ │ + if (!this.loaded) { │ │ │ │ + if (this.location != null) { │ │ │ │ + var onFail = function(e) { │ │ │ │ + this.events.triggerEvent("loadend") │ │ │ │ + }; │ │ │ │ + this.events.triggerEvent("loadstart"); │ │ │ │ + OpenLayers.Request.GET({ │ │ │ │ + url: this.location, │ │ │ │ + success: this.parseData, │ │ │ │ + failure: onFail, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.loaded = true │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ + if (this.visibility && !this.loaded) { │ │ │ │ + this.loadText() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + parseData: function(ajaxRequest) { │ │ │ │ + var text = ajaxRequest.responseText; │ │ │ │ + var options = {}; │ │ │ │ + OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ + if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ + options.externalProjection = this.projection; │ │ │ │ + options.internalProjection = this.map.getProjectionObject() │ │ │ │ + } │ │ │ │ + var parser = new OpenLayers.Format.Text(options); │ │ │ │ + var features = parser.read(text); │ │ │ │ + for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ + var data = {}; │ │ │ │ + var feature = features[i]; │ │ │ │ + var location; │ │ │ │ + var iconSize, iconOffset; │ │ │ │ + location = new OpenLayers.LonLat(feature.geometry.x, feature.geometry.y); │ │ │ │ + if (feature.style.graphicWidth && feature.style.graphicHeight) { │ │ │ │ + iconSize = new OpenLayers.Size(feature.style.graphicWidth, feature.style.graphicHeight) │ │ │ │ + } │ │ │ │ + if (feature.style.graphicXOffset !== undefined && feature.style.graphicYOffset !== undefined) { │ │ │ │ + iconOffset = new OpenLayers.Pixel(feature.style.graphicXOffset, feature.style.graphicYOffset) │ │ │ │ + } │ │ │ │ + if (feature.style.externalGraphic != null) { │ │ │ │ + data.icon = new OpenLayers.Icon(feature.style.externalGraphic, iconSize, iconOffset) │ │ │ │ + } else { │ │ │ │ + data.icon = OpenLayers.Marker.defaultIcon(); │ │ │ │ + if (iconSize != null) { │ │ │ │ + data.icon.setSize(iconSize) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (feature.attributes.title != null && feature.attributes.description != null) { │ │ │ │ + data["popupContentHTML"] = "<h2>" + feature.attributes.title + "</h2>" + "<p>" + feature.attributes.description + "</p>" │ │ │ │ + } │ │ │ │ + data["overflow"] = feature.attributes.overflow || "auto"; │ │ │ │ + var markerFeature = new OpenLayers.Feature(this, location, data); │ │ │ │ + this.features.push(markerFeature); │ │ │ │ + var marker = markerFeature.createMarker(); │ │ │ │ + if (feature.attributes.title != null && feature.attributes.description != null) { │ │ │ │ + marker.events.register("click", markerFeature, this.markerClick) │ │ │ │ + } │ │ │ │ + this.addMarker(marker) │ │ │ │ + } │ │ │ │ + this.events.triggerEvent("loadend") │ │ │ │ + }, │ │ │ │ + markerClick: function(evt) { │ │ │ │ + var sameMarkerClicked = this == this.layer.selectedFeature; │ │ │ │ + this.layer.selectedFeature = !sameMarkerClicked ? this : null; │ │ │ │ + for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ + this.layer.map.removePopup(this.layer.map.popups[i]) │ │ │ │ + } │ │ │ │ + if (!sameMarkerClicked) { │ │ │ │ + this.layer.map.addPopup(this.createPopup()) │ │ │ │ + } │ │ │ │ + OpenLayers.Event.stop(evt) │ │ │ │ + }, │ │ │ │ + clearFeatures: function() { │ │ │ │ + if (this.features != null) { │ │ │ │ + while (this.features.length > 0) { │ │ │ │ + var feature = this.features[0]; │ │ │ │ + OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ + feature.destroy() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Text" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + isBaseLayer: true, │ │ │ │ + useHttpTile: false, │ │ │ │ + singleTile: false, │ │ │ │ + useOverlay: false, │ │ │ │ + useAsyncOverlay: true, │ │ │ │ + TILE_PARAMS: { │ │ │ │ + operation: "GETTILEIMAGE", │ │ │ │ + version: "1.2.0" │ │ │ │ + }, │ │ │ │ + SINGLE_TILE_PARAMS: { │ │ │ │ + operation: "GETMAPIMAGE", │ │ │ │ + format: "PNG", │ │ │ │ + locale: "en", │ │ │ │ + clip: "1", │ │ │ │ + version: "1.0.0" │ │ │ │ + }, │ │ │ │ + OVERLAY_PARAMS: { │ │ │ │ + operation: "GETDYNAMICMAPOVERLAYIMAGE", │ │ │ │ + format: "PNG", │ │ │ │ + locale: "en", │ │ │ │ + clip: "1", │ │ │ │ + version: "2.0.0" │ │ │ │ + }, │ │ │ │ + FOLDER_PARAMS: { │ │ │ │ + tileColumnsPerFolder: 30, │ │ │ │ + tileRowsPerFolder: 30, │ │ │ │ + format: "png", │ │ │ │ + querystring: null │ │ │ │ + }, │ │ │ │ + defaultSize: new OpenLayers.Size(300, 300), │ │ │ │ + tileOriginCorner: "tl", │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments); │ │ │ │ + if (options == null || options.isBaseLayer == null) { │ │ │ │ + this.isBaseLayer = this.transparent != "true" && this.transparent != true │ │ │ │ + } │ │ │ │ + if (options && options.useOverlay != null) { │ │ │ │ + this.useOverlay = options.useOverlay │ │ │ │ + } │ │ │ │ + if (this.singleTile) { │ │ │ │ + if (this.useOverlay) { │ │ │ │ + OpenLayers.Util.applyDefaults(this.params, this.OVERLAY_PARAMS); │ │ │ │ + if (!this.useAsyncOverlay) { │ │ │ │ + this.params.version = "1.0.0" │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Util.applyDefaults(this.params, this.SINGLE_TILE_PARAMS) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if (this.useHttpTile) { │ │ │ │ + OpenLayers.Util.applyDefaults(this.params, this.FOLDER_PARAMS) │ │ │ │ + } else { │ │ │ │ + OpenLayers.Util.applyDefaults(this.params, this.TILE_PARAMS) │ │ │ │ + } │ │ │ │ + this.setTileSize(this.defaultSize) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.MapGuide(this.name, this.url, this.params, this.getOptions()) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + var url; │ │ │ │ + var center = bounds.getCenterLonLat(); │ │ │ │ + var mapSize = this.map.getSize(); │ │ │ │ + if (this.singleTile) { │ │ │ │ + var params = { │ │ │ │ + setdisplaydpi: OpenLayers.DOTS_PER_INCH, │ │ │ │ + setdisplayheight: mapSize.h * this.ratio, │ │ │ │ + setdisplaywidth: mapSize.w * this.ratio, │ │ │ │ + setviewcenterx: center.lon, │ │ │ │ + setviewcentery: center.lat, │ │ │ │ + setviewscale: this.map.getScale() │ │ │ │ + }; │ │ │ │ + if (this.useOverlay && !this.useAsyncOverlay) { │ │ │ │ + var getVisParams = {}; │ │ │ │ + getVisParams = OpenLayers.Util.extend(getVisParams, params); │ │ │ │ + getVisParams.operation = "GETVISIBLEMAPEXTENT"; │ │ │ │ + getVisParams.version = "1.0.0"; │ │ │ │ + getVisParams.session = this.params.session; │ │ │ │ + getVisParams.mapName = this.params.mapName; │ │ │ │ + getVisParams.format = "text/xml"; │ │ │ │ + url = this.getFullRequestString(getVisParams); │ │ │ │ + OpenLayers.Request.GET({ │ │ │ │ + url: url, │ │ │ │ + async: false │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + url = this.getFullRequestString(params) │ │ │ │ + } else { │ │ │ │ + var currentRes = this.map.getResolution(); │ │ │ │ + var colidx = Math.floor((bounds.left - this.maxExtent.left) / currentRes); │ │ │ │ + colidx = Math.round(colidx / this.tileSize.w); │ │ │ │ + var rowidx = Math.floor((this.maxExtent.top - bounds.top) / currentRes); │ │ │ │ + rowidx = Math.round(rowidx / this.tileSize.h); │ │ │ │ + if (this.useHttpTile) { │ │ │ │ + url = this.getImageFilePath({ │ │ │ │ + tilecol: colidx, │ │ │ │ + tilerow: rowidx, │ │ │ │ + scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ + }) │ │ │ │ + } else { │ │ │ │ + url = this.getFullRequestString({ │ │ │ │ + tilecol: colidx, │ │ │ │ + tilerow: rowidx, │ │ │ │ + scaleindex: this.resolutions.length - this.map.zoom - 1 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return url │ │ │ │ + }, │ │ │ │ + getFullRequestString: function(newParams, altUrl) { │ │ │ │ + var url = altUrl == null ? this.url : altUrl; │ │ │ │ + if (typeof url == "object") { │ │ │ │ + url = url[Math.floor(Math.random() * url.length)] │ │ │ │ + } │ │ │ │ + var requestString = url; │ │ │ │ + var allParams = OpenLayers.Util.extend({}, this.params); │ │ │ │ + allParams = OpenLayers.Util.extend(allParams, newParams); │ │ │ │ + var urlParams = OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url)); │ │ │ │ + for (var key in allParams) { │ │ │ │ + if (key.toUpperCase() in urlParams) { │ │ │ │ + delete allParams[key] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ + paramsString = paramsString.replace(/,/g, "+"); │ │ │ │ + if (paramsString != "") { │ │ │ │ + var lastServerChar = url.charAt(url.length - 1); │ │ │ │ + if (lastServerChar == "&" || lastServerChar == "?") { │ │ │ │ + requestString += paramsString │ │ │ │ + } else { │ │ │ │ + if (url.indexOf("?") == -1) { │ │ │ │ + requestString += "?" + paramsString │ │ │ │ + } else { │ │ │ │ + requestString += "&" + paramsString │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return requestString │ │ │ │ + }, │ │ │ │ + getImageFilePath: function(newParams, altUrl) { │ │ │ │ + var url = altUrl == null ? this.url : altUrl; │ │ │ │ + if (typeof url == "object") { │ │ │ │ + url = url[Math.floor(Math.random() * url.length)] │ │ │ │ + } │ │ │ │ + var requestString = url; │ │ │ │ + var tileRowGroup = ""; │ │ │ │ + var tileColGroup = ""; │ │ │ │ + if (newParams.tilerow < 0) { │ │ │ │ + tileRowGroup = "-" │ │ │ │ + } │ │ │ │ + if (newParams.tilerow == 0) { │ │ │ │ + tileRowGroup += "0" │ │ │ │ + } else { │ │ │ │ + tileRowGroup += Math.floor(Math.abs(newParams.tilerow / this.params.tileRowsPerFolder)) * this.params.tileRowsPerFolder │ │ │ │ + } │ │ │ │ + if (newParams.tilecol < 0) { │ │ │ │ + tileColGroup = "-" │ │ │ │ + } │ │ │ │ + if (newParams.tilecol == 0) { │ │ │ │ + tileColGroup += "0" │ │ │ │ + } else { │ │ │ │ + tileColGroup += Math.floor(Math.abs(newParams.tilecol / this.params.tileColumnsPerFolder)) * this.params.tileColumnsPerFolder │ │ │ │ + } │ │ │ │ + var tilePath = "/S" + Math.floor(newParams.scaleindex) + "/" + this.params.basemaplayergroupname + "/R" + tileRowGroup + "/C" + tileColGroup + "/" + newParams.tilerow % this.params.tileRowsPerFolder + "_" + newParams.tilecol % this.params.tileColumnsPerFolder + "." + this.params.format; │ │ │ │ + if (this.params.querystring) { │ │ │ │ + tilePath += "?" + this.params.querystring │ │ │ │ + } │ │ │ │ + requestString += tilePath; │ │ │ │ + return requestString │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.MapGuide" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.Zoomify = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + size: null, │ │ │ │ + isBaseLayer: true, │ │ │ │ + standardTileSize: 256, │ │ │ │ + tileOriginCorner: "tl", │ │ │ │ + numberOfTiers: 0, │ │ │ │ + tileCountUpToTier: null, │ │ │ │ + tierSizeInTiles: null, │ │ │ │ + tierImageSize: null, │ │ │ │ + initialize: function(name, url, size, options) { │ │ │ │ + this.initializeZoomify(size); │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, [name, url, size, {}, options]) │ │ │ │ + }, │ │ │ │ + initializeZoomify: function(size) { │ │ │ │ + var imageSize = size.clone(); │ │ │ │ + this.size = size.clone(); │ │ │ │ + var tiles = new OpenLayers.Size(Math.ceil(imageSize.w / this.standardTileSize), Math.ceil(imageSize.h / this.standardTileSize)); │ │ │ │ + this.tierSizeInTiles = [tiles]; │ │ │ │ + this.tierImageSize = [imageSize]; │ │ │ │ + while (imageSize.w > this.standardTileSize || imageSize.h > this.standardTileSize) { │ │ │ │ + imageSize = new OpenLayers.Size(Math.floor(imageSize.w / 2), Math.floor(imageSize.h / 2)); │ │ │ │ + tiles = new OpenLayers.Size(Math.ceil(imageSize.w / this.standardTileSize), Math.ceil(imageSize.h / this.standardTileSize)); │ │ │ │ + this.tierSizeInTiles.push(tiles); │ │ │ │ + this.tierImageSize.push(imageSize) │ │ │ │ + } │ │ │ │ + this.tierSizeInTiles.reverse(); │ │ │ │ + this.tierImageSize.reverse(); │ │ │ │ + this.numberOfTiers = this.tierSizeInTiles.length; │ │ │ │ + var resolutions = [1]; │ │ │ │ + this.tileCountUpToTier = [0]; │ │ │ │ + for (var i = 1; i < this.numberOfTiers; i++) { │ │ │ │ + resolutions.unshift(Math.pow(2, i)); │ │ │ │ + this.tileCountUpToTier.push(this.tierSizeInTiles[i - 1].w * this.tierSizeInTiles[i - 1].h + this.tileCountUpToTier[i - 1]) │ │ │ │ + } │ │ │ │ + if (!this.serverResolutions) { │ │ │ │ + this.serverResolutions = resolutions │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments); │ │ │ │ + this.tileCountUpToTier.length = 0; │ │ │ │ + this.tierSizeInTiles.length = 0; │ │ │ │ + this.tierImageSize.length = 0 │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.Zoomify(this.name, this.url, this.size, this.options) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ + var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ + var z = this.getZoomForResolution(res); │ │ │ │ + var tileIndex = x + y * this.tierSizeInTiles[z].w + this.tileCountUpToTier[z]; │ │ │ │ + var path = "TileGroup" + Math.floor(tileIndex / 256) + "/" + z + "-" + x + "-" + y + ".jpg"; │ │ │ │ + var url = this.url; │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(path, url) │ │ │ │ + } │ │ │ │ + return url + path │ │ │ │ + }, │ │ │ │ + getImageSize: function() { │ │ │ │ + if (arguments.length > 0) { │ │ │ │ + var bounds = this.adjustBounds(arguments[0]); │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)); │ │ │ │ + var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h)); │ │ │ │ + var z = this.getZoomForResolution(res); │ │ │ │ + var w = this.standardTileSize; │ │ │ │ + var h = this.standardTileSize; │ │ │ │ + if (x == this.tierSizeInTiles[z].w - 1) { │ │ │ │ + var w = this.tierImageSize[z].w % this.standardTileSize │ │ │ │ + } │ │ │ │ + if (y == this.tierSizeInTiles[z].h - 1) { │ │ │ │ + var h = this.tierImageSize[z].h % this.standardTileSize │ │ │ │ + } │ │ │ │ + return new OpenLayers.Size(w, h) │ │ │ │ + } else { │ │ │ │ + return this.tileSize │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); │ │ │ │ + this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left, this.map.maxExtent.top) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Zoomify" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.TileCache = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + isBaseLayer: true, │ │ │ │ + format: "image/png", │ │ │ │ + serverResolutions: null, │ │ │ │ + initialize: function(name, url, layername, options) { │ │ │ │ + this.layername = layername; │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, [name, url, {}, options]); │ │ │ │ + this.extension = this.format.split("/")[1].toLowerCase(); │ │ │ │ + this.extension = this.extension == "jpg" ? "jpeg" : this.extension │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.TileCache(this.name, this.url, this.layername, this.getOptions()) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var bbox = this.maxExtent; │ │ │ │ + var size = this.tileSize; │ │ │ │ + var tileX = Math.round((bounds.left - bbox.left) / (res * size.w)); │ │ │ │ + var tileY = Math.round((bounds.bottom - bbox.bottom) / (res * size.h)); │ │ │ │ + var tileZ = this.serverResolutions != null ? OpenLayers.Util.indexOf(this.serverResolutions, res) : this.map.getZoom(); │ │ │ │ + var components = [this.layername, OpenLayers.Number.zeroPad(tileZ, 2), OpenLayers.Number.zeroPad(parseInt(tileX / 1e6), 3), OpenLayers.Number.zeroPad(parseInt(tileX / 1e3) % 1e3, 3), OpenLayers.Number.zeroPad(parseInt(tileX) % 1e3, 3), OpenLayers.Number.zeroPad(parseInt(tileY / 1e6), 3), OpenLayers.Number.zeroPad(parseInt(tileY / 1e3) % 1e3, 3), OpenLayers.Number.zeroPad(parseInt(tileY) % 1e3, 3) + "." + this.extension]; │ │ │ │ + var path = components.join("/"); │ │ │ │ + var url = this.url; │ │ │ │ + if (OpenLayers.Util.isArray(url)) { │ │ │ │ + url = this.selectUrl(path, url) │ │ │ │ + } │ │ │ │ + url = url.charAt(url.length - 1) == "/" ? url : url + "/"; │ │ │ │ + return url + path │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.TileCache" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.WMTS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + isBaseLayer: true, │ │ │ │ + version: "1.0.0", │ │ │ │ + requestEncoding: "KVP", │ │ │ │ + url: null, │ │ │ │ + layer: null, │ │ │ │ + matrixSet: null, │ │ │ │ + style: null, │ │ │ │ + format: "image/jpeg", │ │ │ │ + tileOrigin: null, │ │ │ │ + tileFullExtent: null, │ │ │ │ + formatSuffix: null, │ │ │ │ + matrixIds: null, │ │ │ │ + dimensions: null, │ │ │ │ + params: null, │ │ │ │ + zoomOffset: 0, │ │ │ │ + serverResolutions: null, │ │ │ │ + formatSuffixMap: { │ │ │ │ + "image/png": "png", │ │ │ │ + "image/png8": "png", │ │ │ │ + "image/png24": "png", │ │ │ │ + "image/png32": "png", │ │ │ │ + png: "png", │ │ │ │ + "image/jpeg": "jpg", │ │ │ │ + "image/jpg": "jpg", │ │ │ │ + jpeg: "jpg", │ │ │ │ + jpg: "jpg" │ │ │ │ + }, │ │ │ │ + matrix: null, │ │ │ │ + initialize: function(config) { │ │ │ │ + var required = { │ │ │ │ + url: true, │ │ │ │ + layer: true, │ │ │ │ + style: true, │ │ │ │ + matrixSet: true │ │ │ │ + }; │ │ │ │ + for (var prop in required) { │ │ │ │ + if (!(prop in config)) { │ │ │ │ + throw new Error("Missing property '" + prop + "' in layer configuration.") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + config.params = OpenLayers.Util.upperCaseObject(config.params); │ │ │ │ + var args = [config.name, config.url, config.params, config]; │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, args); │ │ │ │ + if (!this.formatSuffix) { │ │ │ │ + this.formatSuffix = this.formatSuffixMap[this.format] || this.format.split("/").pop() │ │ │ │ + } │ │ │ │ + if (this.matrixIds) { │ │ │ │ + var len = this.matrixIds.length; │ │ │ │ + if (len && typeof this.matrixIds[0] === "string") { │ │ │ │ + var ids = this.matrixIds; │ │ │ │ + this.matrixIds = new Array(len); │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ + this.matrixIds[i] = { │ │ │ │ + identifier: ids[i] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setMap: function() { │ │ │ │ + OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + updateMatrixProperties: function() { │ │ │ │ + this.matrix = this.getMatrix(); │ │ │ │ + if (this.matrix) { │ │ │ │ + if (this.matrix.topLeftCorner) { │ │ │ │ + this.tileOrigin = this.matrix.topLeftCorner │ │ │ │ + } │ │ │ │ + if (this.matrix.tileWidth && this.matrix.tileHeight) { │ │ │ │ + this.tileSize = new OpenLayers.Size(this.matrix.tileWidth, this.matrix.tileHeight) │ │ │ │ + } │ │ │ │ + if (!this.tileOrigin) { │ │ │ │ + this.tileOrigin = new OpenLayers.LonLat(this.maxExtent.left, this.maxExtent.top) │ │ │ │ + } │ │ │ │ + if (!this.tileFullExtent) { │ │ │ │ + this.tileFullExtent = this.maxExtent │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ + if (zoomChanged || !this.matrix) { │ │ │ │ + this.updateMatrixProperties() │ │ │ │ + } │ │ │ │ + return OpenLayers.Layer.Grid.prototype.moveTo.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.WMTS(this.options) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + getIdentifier: function() { │ │ │ │ + return this.getServerZoom() │ │ │ │ + }, │ │ │ │ + getMatrix: function() { │ │ │ │ + var matrix; │ │ │ │ + if (!this.matrixIds || this.matrixIds.length === 0) { │ │ │ │ + matrix = { │ │ │ │ + identifier: this.getIdentifier() │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + if ("scaleDenominator" in this.matrixIds[0]) { │ │ │ │ + var denom = OpenLayers.METERS_PER_INCH * OpenLayers.INCHES_PER_UNIT[this.units] * this.getServerResolution() / 28e-5; │ │ │ │ + var diff = Number.POSITIVE_INFINITY; │ │ │ │ + var delta; │ │ │ │ + for (var i = 0, ii = this.matrixIds.length; i < ii; ++i) { │ │ │ │ + delta = Math.abs(1 - this.matrixIds[i].scaleDenominator / denom); │ │ │ │ + if (delta < diff) { │ │ │ │ + diff = delta; │ │ │ │ + matrix = this.matrixIds[i] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + matrix = this.matrixIds[this.getIdentifier()] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return matrix │ │ │ │ + }, │ │ │ │ + getTileInfo: function(loc) { │ │ │ │ + var res = this.getServerResolution(); │ │ │ │ + var fx = (loc.lon - this.tileOrigin.lon) / (res * this.tileSize.w); │ │ │ │ + var fy = (this.tileOrigin.lat - loc.lat) / (res * this.tileSize.h); │ │ │ │ + var col = Math.floor(fx); │ │ │ │ + var row = Math.floor(fy); │ │ │ │ + return { │ │ │ │ + col: col, │ │ │ │ + row: row, │ │ │ │ + i: Math.floor((fx - col) * this.tileSize.w), │ │ │ │ + j: Math.floor((fy - row) * this.tileSize.h) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var url = ""; │ │ │ │ + if (!this.tileFullExtent || this.tileFullExtent.intersectsBounds(bounds)) { │ │ │ │ + var center = bounds.getCenterLonLat(); │ │ │ │ + var info = this.getTileInfo(center); │ │ │ │ + var matrixId = this.matrix.identifier; │ │ │ │ + var dimensions = this.dimensions, │ │ │ │ + params; │ │ │ │ + if (OpenLayers.Util.isArray(this.url)) { │ │ │ │ + url = this.selectUrl([this.version, this.style, this.matrixSet, this.matrix.identifier, info.row, info.col].join(","), this.url) │ │ │ │ + } else { │ │ │ │ + url = this.url │ │ │ │ + } │ │ │ │ + if (this.requestEncoding.toUpperCase() === "REST") { │ │ │ │ + params = this.params; │ │ │ │ + if (url.indexOf("{") !== -1) { │ │ │ │ + var template = url.replace(/\{/g, "${"); │ │ │ │ + var context = { │ │ │ │ + style: this.style, │ │ │ │ + Style: this.style, │ │ │ │ + TileMatrixSet: this.matrixSet, │ │ │ │ + TileMatrix: this.matrix.identifier, │ │ │ │ + TileRow: info.row, │ │ │ │ + TileCol: info.col │ │ │ │ + }; │ │ │ │ + if (dimensions) { │ │ │ │ + var dimension, i; │ │ │ │ + for (i = dimensions.length - 1; i >= 0; --i) { │ │ │ │ + dimension = dimensions[i]; │ │ │ │ + context[dimension] = params[dimension.toUpperCase()] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + url = OpenLayers.String.format(template, context) │ │ │ │ + } else { │ │ │ │ + var path = this.version + "/" + this.layer + "/" + this.style + "/"; │ │ │ │ + if (dimensions) { │ │ │ │ + for (var i = 0; i < dimensions.length; i++) { │ │ │ │ + if (params[dimensions[i]]) { │ │ │ │ + path = path + params[dimensions[i]] + "/" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + path = path + this.matrixSet + "/" + this.matrix.identifier + "/" + info.row + "/" + info.col + "." + this.formatSuffix; │ │ │ │ + if (!url.match(/\/$/)) { │ │ │ │ + url = url + "/" │ │ │ │ + } │ │ │ │ + url = url + path │ │ │ │ + } │ │ │ │ + } else if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ + params = { │ │ │ │ + SERVICE: "WMTS", │ │ │ │ + REQUEST: "GetTile", │ │ │ │ + VERSION: this.version, │ │ │ │ + LAYER: this.layer, │ │ │ │ + STYLE: this.style, │ │ │ │ + TILEMATRIXSET: this.matrixSet, │ │ │ │ + TILEMATRIX: this.matrix.identifier, │ │ │ │ + TILEROW: info.row, │ │ │ │ + TILECOL: info.col, │ │ │ │ + FORMAT: this.format │ │ │ │ + }; │ │ │ │ + url = OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this, [params]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return url │ │ │ │ + }, │ │ │ │ + mergeNewParams: function(newParams) { │ │ │ │ + if (this.requestEncoding.toUpperCase() === "KVP") { │ │ │ │ + return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, [OpenLayers.Util.upperCaseObject(newParams)]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.WMTS" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.GeoRSS = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ + location: null, │ │ │ │ + features: null, │ │ │ │ + formatOptions: null, │ │ │ │ + selectedFeature: null, │ │ │ │ + icon: null, │ │ │ │ + popupSize: null, │ │ │ │ + useFeedTitle: true, │ │ │ │ + initialize: function(name, location, options) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.initialize.apply(this, [name, options]); │ │ │ │ + this.location = location; │ │ │ │ + this.features = [] │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ + this.clearFeatures(); │ │ │ │ + this.features = null │ │ │ │ + }, │ │ │ │ + loadRSS: function() { │ │ │ │ + if (!this.loaded) { │ │ │ │ + this.events.triggerEvent("loadstart"); │ │ │ │ + OpenLayers.Request.GET({ │ │ │ │ + url: this.location, │ │ │ │ + success: this.parseData, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.loaded = true │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ + OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ + if (this.visibility && !this.loaded) { │ │ │ │ + this.loadRSS() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + parseData: function(ajaxRequest) { │ │ │ │ + var doc = ajaxRequest.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = OpenLayers.Format.XML.prototype.read(ajaxRequest.responseText) │ │ │ │ + } │ │ │ │ + if (this.useFeedTitle) { │ │ │ │ + var name = null; │ │ │ │ + try { │ │ │ │ + name = doc.getElementsByTagNameNS("*", "title")[0].firstChild.nodeValue │ │ │ │ + } catch (e) { │ │ │ │ + try { │ │ │ │ + name = doc.getElementsByTagName("title")[0].firstChild.nodeValue │ │ │ │ + } catch (e) {} │ │ │ │ + } │ │ │ │ + if (name) { │ │ │ │ + this.setName(name) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var options = {}; │ │ │ │ + OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ + if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ + options.externalProjection = this.projection; │ │ │ │ + options.internalProjection = this.map.getProjectionObject() │ │ │ │ + } │ │ │ │ + var format = new OpenLayers.Format.GeoRSS(options); │ │ │ │ + var features = format.read(doc); │ │ │ │ + for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ + var data = {}; │ │ │ │ + var feature = features[i]; │ │ │ │ + if (!feature.geometry) { │ │ │ │ + continue │ │ │ │ + } │ │ │ │ + var title = feature.attributes.title ? feature.attributes.title : "Untitled"; │ │ │ │ + var description = feature.attributes.description ? feature.attributes.description : "No description."; │ │ │ │ + var link = feature.attributes.link ? feature.attributes.link : ""; │ │ │ │ + var location = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ + data.icon = this.icon == null ? OpenLayers.Marker.defaultIcon() : this.icon.clone(); │ │ │ │ + data.popupSize = this.popupSize ? this.popupSize.clone() : new OpenLayers.Size(250, 120); │ │ │ │ + if (title || description) { │ │ │ │ + data.title = title; │ │ │ │ + data.description = description; │ │ │ │ + var contentHTML = '<div class="olLayerGeoRSSClose">[x]</div>'; │ │ │ │ + contentHTML += '<div class="olLayerGeoRSSTitle">'; │ │ │ │ + if (link) { │ │ │ │ + contentHTML += '<a class="link" href="' + link + '" target="_blank">' │ │ │ │ + } │ │ │ │ + contentHTML += title; │ │ │ │ + if (link) { │ │ │ │ + contentHTML += "</a>" │ │ │ │ + } │ │ │ │ + contentHTML += "</div>"; │ │ │ │ + contentHTML += '<div style="" class="olLayerGeoRSSDescription">'; │ │ │ │ + contentHTML += description; │ │ │ │ + contentHTML += "</div>"; │ │ │ │ + data["popupContentHTML"] = contentHTML │ │ │ │ + } │ │ │ │ + var feature = new OpenLayers.Feature(this, location, data); │ │ │ │ + this.features.push(feature); │ │ │ │ + var marker = feature.createMarker(); │ │ │ │ + marker.events.register("click", feature, this.markerClick); │ │ │ │ + this.addMarker(marker) │ │ │ │ + } │ │ │ │ + this.events.triggerEvent("loadend") │ │ │ │ + }, │ │ │ │ + markerClick: function(evt) { │ │ │ │ + var sameMarkerClicked = this == this.layer.selectedFeature; │ │ │ │ + this.layer.selectedFeature = !sameMarkerClicked ? this : null; │ │ │ │ + for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ + this.layer.map.removePopup(this.layer.map.popups[i]) │ │ │ │ + } │ │ │ │ + if (!sameMarkerClicked) { │ │ │ │ + var popup = this.createPopup(); │ │ │ │ + OpenLayers.Event.observe(popup.div, "click", OpenLayers.Function.bind(function() { │ │ │ │ + for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ + this.layer.map.removePopup(this.layer.map.popups[i]) │ │ │ │ + } │ │ │ │ + }, this)); │ │ │ │ + this.layer.map.addPopup(popup) │ │ │ │ + } │ │ │ │ + OpenLayers.Event.stop(evt) │ │ │ │ + }, │ │ │ │ + clearFeatures: function() { │ │ │ │ + if (this.features != null) { │ │ │ │ + while (this.features.length > 0) { │ │ │ │ + var feature = this.features[0]; │ │ │ │ + OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ + feature.destroy() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.GeoRSS" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.ArcGIS93Rest = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + DEFAULT_PARAMS: { │ │ │ │ + format: "png" │ │ │ │ + }, │ │ │ │ + isBaseLayer: true, │ │ │ │ + initialize: function(name, url, params, options) { │ │ │ │ + var newArguments = []; │ │ │ │ + params = OpenLayers.Util.upperCaseObject(params); │ │ │ │ + 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)); │ │ │ │ + if (this.params.TRANSPARENT && this.params.TRANSPARENT.toString().toLowerCase() == "true") { │ │ │ │ + if (options == null || !options.isBaseLayer) { │ │ │ │ + this.isBaseLayer = false │ │ │ │ + } │ │ │ │ + if (this.params.FORMAT == "jpg") { │ │ │ │ + this.params.FORMAT = OpenLayers.Util.alphaHack() ? "gif" : "png" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + clone: function(obj) { │ │ │ │ + if (obj == null) { │ │ │ │ + obj = new OpenLayers.Layer.ArcGIS93Rest(this.name, this.url, this.params, this.getOptions()) │ │ │ │ + } │ │ │ │ + obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var projWords = this.projection.getCode().split(":"); │ │ │ │ + var srid = projWords[projWords.length - 1]; │ │ │ │ + var imageSize = this.getImageSize(); │ │ │ │ + var newParams = { │ │ │ │ + BBOX: bounds.toBBOX(), │ │ │ │ + SIZE: imageSize.w + "," + imageSize.h, │ │ │ │ + F: "image", │ │ │ │ + BBOXSR: srid, │ │ │ │ + IMAGESR: srid │ │ │ │ + }; │ │ │ │ + if (this.layerDefs) { │ │ │ │ + var layerDefStrList = []; │ │ │ │ + var layerID; │ │ │ │ + for (layerID in this.layerDefs) { │ │ │ │ + if (this.layerDefs.hasOwnProperty(layerID)) { │ │ │ │ + if (this.layerDefs[layerID]) { │ │ │ │ + layerDefStrList.push(layerID); │ │ │ │ + layerDefStrList.push(":"); │ │ │ │ + layerDefStrList.push(this.layerDefs[layerID]); │ │ │ │ + layerDefStrList.push(";") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (layerDefStrList.length > 0) { │ │ │ │ + newParams["LAYERDEFS"] = layerDefStrList.join("") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var requestString = this.getFullRequestString(newParams); │ │ │ │ + return requestString │ │ │ │ + }, │ │ │ │ + setLayerFilter: function(id, queryDef) { │ │ │ │ + if (!this.layerDefs) { │ │ │ │ + this.layerDefs = {} │ │ │ │ + } │ │ │ │ + if (queryDef) { │ │ │ │ + this.layerDefs[id] = queryDef │ │ │ │ + } else { │ │ │ │ + delete this.layerDefs[id] │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + clearLayerFilter: function(id) { │ │ │ │ + if (id) { │ │ │ │ + delete this.layerDefs[id] │ │ │ │ + } else { │ │ │ │ + delete this.layerDefs │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + mergeNewParams: function(newParams) { │ │ │ │ + var upperParams = OpenLayers.Util.upperCaseObject(newParams); │ │ │ │ + var newArguments = [upperParams]; │ │ │ │ + return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, newArguments) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.ArcGIS93Rest" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.Boxes = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ + drawMarker: function(marker) { │ │ │ │ + var topleft = this.map.getLayerPxFromLonLat({ │ │ │ │ + lon: marker.bounds.left, │ │ │ │ + lat: marker.bounds.top │ │ │ │ + }); │ │ │ │ + var botright = this.map.getLayerPxFromLonLat({ │ │ │ │ + lon: marker.bounds.right, │ │ │ │ + lat: marker.bounds.bottom │ │ │ │ + }); │ │ │ │ + if (botright == null || topleft == null) { │ │ │ │ + marker.display(false) │ │ │ │ + } else { │ │ │ │ + var markerDiv = marker.draw(topleft, { │ │ │ │ + w: Math.max(1, botright.x - topleft.x), │ │ │ │ + h: Math.max(1, botright.y - topleft.y) │ │ │ │ + }); │ │ │ │ + if (!marker.drawn) { │ │ │ │ + this.div.appendChild(markerDiv); │ │ │ │ + marker.drawn = true │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + removeMarker: function(marker) { │ │ │ │ + OpenLayers.Util.removeItem(this.markers, marker); │ │ │ │ + if (marker.div != null && marker.div.parentNode == this.div) { │ │ │ │ + this.div.removeChild(marker.div) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.Boxes" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.WorldWind = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ + DEFAULT_PARAMS: {}, │ │ │ │ + isBaseLayer: true, │ │ │ │ + lzd: null, │ │ │ │ + zoomLevels: null, │ │ │ │ + initialize: function(name, url, lzd, zoomLevels, params, options) { │ │ │ │ + this.lzd = lzd; │ │ │ │ + this.zoomLevels = zoomLevels; │ │ │ │ + var newArguments = []; │ │ │ │ + newArguments.push(name, url, params, options); │ │ │ │ + OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments); │ │ │ │ + this.params = OpenLayers.Util.applyDefaults(this.params, this.DEFAULT_PARAMS) │ │ │ │ + }, │ │ │ │ + getZoom: function() { │ │ │ │ + var zoom = this.map.getZoom(); │ │ │ │ + var extent = this.map.getMaxExtent(); │ │ │ │ + zoom = zoom - Math.log(this.maxResolution / (this.lzd / 512)) / Math.log(2); │ │ │ │ + return zoom │ │ │ │ + }, │ │ │ │ + getURL: function(bounds) { │ │ │ │ + bounds = this.adjustBounds(bounds); │ │ │ │ + var zoom = this.getZoom(); │ │ │ │ + var extent = this.map.getMaxExtent(); │ │ │ │ + var deg = this.lzd / Math.pow(2, this.getZoom()); │ │ │ │ + var x = Math.floor((bounds.left - extent.left) / deg); │ │ │ │ + var y = Math.floor((bounds.bottom - extent.bottom) / deg); │ │ │ │ + if (this.map.getResolution() <= this.lzd / 512 && this.getZoom() <= this.zoomLevels) { │ │ │ │ + return this.getFullRequestString({ │ │ │ │ + L: zoom, │ │ │ │ + X: x, │ │ │ │ + Y: y │ │ │ │ + }) │ │ │ │ + } else { │ │ │ │ + return OpenLayers.Util.getImageLocation("blank.gif") │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.WorldWind" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.PointTrack = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ + dataFrom: null, │ │ │ │ + styleFrom: null, │ │ │ │ + addNodes: function(pointFeatures, options) { │ │ │ │ + if (pointFeatures.length < 2) { │ │ │ │ + throw new Error("At least two point features have to be added to " + "create a line from") │ │ │ │ + } │ │ │ │ + var lines = new Array(pointFeatures.length - 1); │ │ │ │ + var pointFeature, startPoint, endPoint; │ │ │ │ + for (var i = 0, len = pointFeatures.length; i < len; i++) { │ │ │ │ + pointFeature = pointFeatures[i]; │ │ │ │ + endPoint = pointFeature.geometry; │ │ │ │ + if (!endPoint) { │ │ │ │ + var lonlat = pointFeature.lonlat; │ │ │ │ + endPoint = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat) │ │ │ │ + } else if (endPoint.CLASS_NAME != "OpenLayers.Geometry.Point") { │ │ │ │ + throw new TypeError("Only features with point geometries are supported.") │ │ │ │ + } │ │ │ │ + if (i > 0) { │ │ │ │ + var attributes = this.dataFrom != null ? pointFeatures[i + this.dataFrom].data || pointFeatures[i + this.dataFrom].attributes : null; │ │ │ │ + var style = this.styleFrom != null ? pointFeatures[i + this.styleFrom].style : null; │ │ │ │ + var line = new OpenLayers.Geometry.LineString([startPoint, endPoint]); │ │ │ │ + lines[i - 1] = new OpenLayers.Feature.Vector(line, attributes, style) │ │ │ │ + } │ │ │ │ + startPoint = endPoint │ │ │ │ + } │ │ │ │ + this.addFeatures(lines, options) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.PointTrack" │ │ │ │ +}); │ │ │ │ +OpenLayers.Layer.PointTrack.SOURCE_NODE = -1; │ │ │ │ +OpenLayers.Layer.PointTrack.TARGET_NODE = 0; │ │ │ │ +OpenLayers.Layer.PointTrack.dataFrom = { │ │ │ │ + SOURCE_NODE: -1, │ │ │ │ + TARGET_NODE: 0 │ │ │ │ +}; │ │ │ │ +OpenLayers.Layer.Google.v3 = { │ │ │ │ + DEFAULTS: { │ │ │ │ + sphericalMercator: true, │ │ │ │ + projection: "EPSG:900913" │ │ │ │ + }, │ │ │ │ + animationEnabled: true, │ │ │ │ + loadMapObject: function() { │ │ │ │ + if (!this.type) { │ │ │ │ + this.type = google.maps.MapTypeId.ROADMAP │ │ │ │ + } │ │ │ │ + var mapObject; │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + if (cache) { │ │ │ │ + mapObject = cache.mapObject; │ │ │ │ + ++cache.count │ │ │ │ + } else { │ │ │ │ + var center = this.map.getCenter(); │ │ │ │ + var container = document.createElement("div"); │ │ │ │ + container.className = "olForeignContainer"; │ │ │ │ + container.style.width = "100%"; │ │ │ │ + container.style.height = "100%"; │ │ │ │ + mapObject = new google.maps.Map(container, { │ │ │ │ + center: center ? new google.maps.LatLng(center.lat, center.lon) : new google.maps.LatLng(0, 0), │ │ │ │ + zoom: this.map.getZoom() || 0, │ │ │ │ + mapTypeId: this.type, │ │ │ │ + disableDefaultUI: true, │ │ │ │ + keyboardShortcuts: false, │ │ │ │ + draggable: false, │ │ │ │ + disableDoubleClickZoom: true, │ │ │ │ + scrollwheel: false, │ │ │ │ + streetViewControl: false │ │ │ │ + }); │ │ │ │ + var googleControl = document.createElement("div"); │ │ │ │ + googleControl.style.width = "100%"; │ │ │ │ + googleControl.style.height = "100%"; │ │ │ │ + mapObject.controls[google.maps.ControlPosition.TOP_LEFT].push(googleControl); │ │ │ │ + cache = { │ │ │ │ + googleControl: googleControl, │ │ │ │ + mapObject: mapObject, │ │ │ │ + count: 1 │ │ │ │ + }; │ │ │ │ + OpenLayers.Layer.Google.cache[this.map.id] = cache │ │ │ │ + } │ │ │ │ + this.mapObject = mapObject; │ │ │ │ + this.setGMapVisibility(this.visibility) │ │ │ │ + }, │ │ │ │ + onMapResize: function() { │ │ │ │ + if (this.visibility) { │ │ │ │ + google.maps.event.trigger(this.mapObject, "resize") │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setGMapVisibility: function(visible) { │ │ │ │ + var cache = OpenLayers.Layer.Google.cache[this.map.id]; │ │ │ │ + var map = this.map; │ │ │ │ + if (cache) { │ │ │ │ + var type = this.type; │ │ │ │ + var layers = map.layers; │ │ │ │ + var layer; │ │ │ │ + for (var i = layers.length - 1; i >= 0; --i) { │ │ │ │ + layer = layers[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.Google && layer.visibility === true && layer.inRange === true) { │ │ │ │ + type = layer.type; │ │ │ │ + visible = true; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var container = this.mapObject.getDiv(); │ │ │ │ + if (visible === true) { │ │ │ │ + if (container.parentNode !== map.div) { │ │ │ │ + if (!cache.rendered) { │ │ │ │ + var me = this; │ │ │ │ + google.maps.event.addListenerOnce(this.mapObject, "tilesloaded", function() { │ │ │ │ + cache.rendered = true; │ │ │ │ + me.setGMapVisibility(me.getVisibility()); │ │ │ │ + me.moveTo(me.map.getCenter()) │ │ │ │ + }) │ │ │ │ + } else { │ │ │ │ + map.div.appendChild(container); │ │ │ │ + cache.googleControl.appendChild(map.viewPortDiv); │ │ │ │ + google.maps.event.trigger(this.mapObject, "resize") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.mapObject.setMapTypeId(type) │ │ │ │ + } else if (cache.googleControl.hasChildNodes()) { │ │ │ │ + map.div.appendChild(map.viewPortDiv); │ │ │ │ + map.div.removeChild(container) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getMapContainer: function() { │ │ │ │ + return this.mapObject.getDiv() │ │ │ │ + }, │ │ │ │ + getMapObjectBoundsFromOLBounds: function(olBounds) { │ │ │ │ + var moBounds = null; │ │ │ │ + if (olBounds != null) { │ │ │ │ + var sw = this.sphericalMercator ? this.inverseMercator(olBounds.bottom, olBounds.left) : new OpenLayers.LonLat(olBounds.bottom, olBounds.left); │ │ │ │ + var ne = this.sphericalMercator ? this.inverseMercator(olBounds.top, olBounds.right) : new OpenLayers.LonLat(olBounds.top, olBounds.right); │ │ │ │ + moBounds = new google.maps.LatLngBounds(new google.maps.LatLng(sw.lat, sw.lon), new google.maps.LatLng(ne.lat, ne.lon)) │ │ │ │ + } │ │ │ │ + return moBounds │ │ │ │ + }, │ │ │ │ + getMapObjectLonLatFromMapObjectPixel: function(moPixel) { │ │ │ │ + var size = this.map.getSize(); │ │ │ │ + var lon = this.getLongitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ + var lat = this.getLatitudeFromMapObjectLonLat(this.mapObject.center); │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ + var delta_x = moPixel.x - size.w / 2; │ │ │ │ + var delta_y = moPixel.y - size.h / 2; │ │ │ │ + var lonlat = new OpenLayers.LonLat(lon + delta_x * res, lat - delta_y * res); │ │ │ │ + if (this.wrapDateLine) { │ │ │ │ + lonlat = lonlat.wrapDateLine(this.maxExtent) │ │ │ │ + } │ │ │ │ + return this.getMapObjectLonLatFromLonLat(lonlat.lon, lonlat.lat) │ │ │ │ + }, │ │ │ │ + getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { │ │ │ │ + var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); │ │ │ │ + var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ + var extent = this.map.getExtent(); │ │ │ │ + return this.getMapObjectPixelFromXY(1 / res * (lon - extent.left), 1 / res * (extent.top - lat)) │ │ │ │ + }, │ │ │ │ + setMapObjectCenter: function(center, zoom) { │ │ │ │ + if (this.animationEnabled === false && zoom != this.mapObject.zoom) { │ │ │ │ + var mapContainer = this.getMapContainer(); │ │ │ │ + google.maps.event.addListenerOnce(this.mapObject, "idle", function() { │ │ │ │ + mapContainer.style.visibility = "" │ │ │ │ + }); │ │ │ │ + mapContainer.style.visibility = "hidden" │ │ │ │ + } │ │ │ │ + this.mapObject.setOptions({ │ │ │ │ + center: center, │ │ │ │ + zoom: zoom │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + getMapObjectZoomFromMapObjectBounds: function(moBounds) { │ │ │ │ + return this.mapObject.getBoundsZoomLevel(moBounds) │ │ │ │ + }, │ │ │ │ + getMapObjectLonLatFromLonLat: function(lon, lat) { │ │ │ │ + var gLatLng; │ │ │ │ + if (this.sphericalMercator) { │ │ │ │ + var lonlat = this.inverseMercator(lon, lat); │ │ │ │ + gLatLng = new google.maps.LatLng(lonlat.lat, lonlat.lon) │ │ │ │ + } else { │ │ │ │ + gLatLng = new google.maps.LatLng(lat, lon) │ │ │ │ + } │ │ │ │ + return gLatLng │ │ │ │ + }, │ │ │ │ + getMapObjectPixelFromXY: function(x, y) { │ │ │ │ + return new google.maps.Point(x, y) │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ + displayInLayerSwitcher: false, │ │ │ │ + layers: null, │ │ │ │ + display: function() {}, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); │ │ │ │ + this.collectRoots(); │ │ │ │ + map.events.register("changelayer", this, this.handleChangeLayer) │ │ │ │ + }, │ │ │ │ + removeMap: function(map) { │ │ │ │ + map.events.unregister("changelayer", this, this.handleChangeLayer); │ │ │ │ + this.resetRoots(); │ │ │ │ + OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + collectRoots: function() { │ │ │ │ + var layer; │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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.Protocol.SOS = function(options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, OpenLayers.Protocol.SOS.DEFAULTS); │ │ │ │ + var cls = OpenLayers.Protocol.SOS["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (!cls) { │ │ │ │ + throw "Unsupported SOS version: " + options.version │ │ │ │ + } │ │ │ │ + return new cls(options) │ │ │ │ +}; │ │ │ │ +OpenLayers.Protocol.SOS.DEFAULTS = { │ │ │ │ + version: "1.0.0" │ │ │ │ +}; │ │ │ │ +OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ + url: null, │ │ │ │ + headers: null, │ │ │ │ + params: null, │ │ │ │ + callback: null, │ │ │ │ + scope: null, │ │ │ │ + readWithPOST: false, │ │ │ │ + updateWithPOST: false, │ │ │ │ + deleteWithPOST: false, │ │ │ │ + wildcarded: false, │ │ │ │ + srsInBBOX: false, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.params = null; │ │ │ │ + this.headers = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleRead: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleCreate: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleUpdate: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleDelete: function(resp, options) { │ │ │ │ + this.handleResponse(resp, options) │ │ │ │ + }, │ │ │ │ + handleResponse: function(resp, options) { │ │ │ │ + var request = resp.priv; │ │ │ │ + if (options.callback) { │ │ │ │ + if (request.status >= 200 && request.status < 300) { │ │ │ │ + if (resp.requestType != "delete") { │ │ │ │ + resp.features = this.parseFeatures(request) │ │ │ │ + } │ │ │ │ + resp.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ + } else { │ │ │ │ + resp.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ + } │ │ │ │ + options.callback.call(options.scope, resp) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + commit: function(features, options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ + var resp = [], │ │ │ │ + nResponses = 0; │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var nRequests = (types[OpenLayers.State.INSERT].length > 0 ? 1 : 0) + types[OpenLayers.State.UPDATE].length + types[OpenLayers.State.DELETE].length; │ │ │ │ + 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]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + response.priv.abort() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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.Protocol.CSW = function(options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, OpenLayers.Protocol.CSW.DEFAULTS); │ │ │ │ + var cls = OpenLayers.Protocol.CSW["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (!cls) { │ │ │ │ + throw "Unsupported CSW version: " + options.version │ │ │ │ + } │ │ │ │ + return new cls(options) │ │ │ │ +}; │ │ │ │ +OpenLayers.Protocol.CSW.DEFAULTS = { │ │ │ │ + version: "2.0.2" │ │ │ │ +}; │ │ │ │ +OpenLayers.Protocol.Script = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ + url: null, │ │ │ │ + params: null, │ │ │ │ + callback: null, │ │ │ │ + callbackTemplate: "OpenLayers.Protocol.Script.registry.${id}", │ │ │ │ + callbackKey: "callback", │ │ │ │ + callbackPrefix: "", │ │ │ │ + scope: null, │ │ │ │ + format: null, │ │ │ │ + pendingRequests: null, │ │ │ │ + srsInBBOX: false, │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + this.params = {}; │ │ │ │ + this.pendingRequests = {}; │ │ │ │ + OpenLayers.Protocol.prototype.initialize.apply(this, arguments); │ │ │ │ + if (!this.format) { │ │ │ │ + this.format = new OpenLayers.Format.GeoJSON │ │ │ │ + } │ │ │ │ + if (!this.filterToParams && OpenLayers.Format.QueryStringFilter) { │ │ │ │ + var format = new OpenLayers.Format.QueryStringFilter({ │ │ │ │ + srsInBBOX: this.srsInBBOX │ │ │ │ + }); │ │ │ │ + this.filterToParams = function(filter, params) { │ │ │ │ + return format.write(filter, params) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + read: function(options) { │ │ │ │ + OpenLayers.Protocol.prototype.read.apply(this, arguments); │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ + options.params = OpenLayers.Util.applyDefaults(options.params, this.options.params); │ │ │ │ + if (options.filter && this.filterToParams) { │ │ │ │ + options.params = this.filterToParams(options.filter, options.params) │ │ │ │ + } │ │ │ │ + var response = new OpenLayers.Protocol.Response({ │ │ │ │ + requestType: "read" │ │ │ │ + }); │ │ │ │ + var request = this.createRequest(options.url, options.params, OpenLayers.Function.bind(function(data) { │ │ │ │ + response.data = data; │ │ │ │ + this.handleRead(response, options) │ │ │ │ + }, this)); │ │ │ │ + response.priv = request; │ │ │ │ + return response │ │ │ │ + }, │ │ │ │ + createRequest: function(url, params, callback) { │ │ │ │ + var id = OpenLayers.Protocol.Script.register(callback); │ │ │ │ + var name = OpenLayers.String.format(this.callbackTemplate, { │ │ │ │ + id: id │ │ │ │ + }); │ │ │ │ + params = OpenLayers.Util.extend({}, params); │ │ │ │ + params[this.callbackKey] = this.callbackPrefix + name; │ │ │ │ + url = OpenLayers.Util.urlAppend(url, OpenLayers.Util.getParameterString(params)); │ │ │ │ + var script = document.createElement("script"); │ │ │ │ + script.type = "text/javascript"; │ │ │ │ + script.src = url; │ │ │ │ + script.id = "OpenLayers_Protocol_Script_" + id; │ │ │ │ + this.pendingRequests[script.id] = script; │ │ │ │ + var head = document.getElementsByTagName("head")[0]; │ │ │ │ + head.appendChild(script); │ │ │ │ + return script │ │ │ │ + }, │ │ │ │ + destroyRequest: function(script) { │ │ │ │ + OpenLayers.Protocol.Script.unregister(script.id.split("_").pop()); │ │ │ │ + delete this.pendingRequests[script.id]; │ │ │ │ + if (script.parentNode) { │ │ │ │ + script.parentNode.removeChild(script) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + handleRead: function(response, options) { │ │ │ │ + this.handleResponse(response, options) │ │ │ │ + }, │ │ │ │ + handleResponse: function(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + if (response.data) { │ │ │ │ + response.features = this.parseFeatures(response.data); │ │ │ │ + response.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ + } else { │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ + } │ │ │ │ + this.destroyRequest(response.priv); │ │ │ │ + options.callback.call(options.scope, response) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + parseFeatures: function(data) { │ │ │ │ + return this.format.read(data) │ │ │ │ + }, │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + this.destroyRequest(response.priv) │ │ │ │ + } else { │ │ │ │ + for (var key in this.pendingRequests) { │ │ │ │ + this.destroyRequest(this.pendingRequests[key]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.abort(); │ │ │ │ + delete this.params; │ │ │ │ + delete this.format; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.Script" │ │ │ │ +}); │ │ │ │ +(function() { │ │ │ │ + var o = OpenLayers.Protocol.Script; │ │ │ │ + var counter = 0; │ │ │ │ + o.registry = {}; │ │ │ │ + o.register = function(callback) { │ │ │ │ + var id = "c" + ++counter; │ │ │ │ + o.registry[id] = function() { │ │ │ │ + callback.apply(this, arguments) │ │ │ │ + }; │ │ │ │ + return id │ │ │ │ + }; │ │ │ │ + o.unregister = function(id) { │ │ │ │ + delete o.registry[id] │ │ │ │ + } │ │ │ │ +})(); │ │ │ │ +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) │ │ │ │ +}; │ │ │ │ +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)) │ │ │ │ +}; │ │ │ │ +OpenLayers.Protocol.WFS.DEFAULTS = { │ │ │ │ + version: "1.0.0" │ │ │ │ +}; │ │ │ │ +OpenLayers.Format.SOSGetFeatureOfInterest = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + VERSION: "1.0.0", │ │ │ │ + namespaces: { │ │ │ │ + sos: "http://www.opengis.net/sos/1.0", │ │ │ │ + gml: "http://www.opengis.net/gml", │ │ │ │ + sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + }, │ │ │ │ + schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosAll.xsd", │ │ │ │ + defaultPrefix: "sos", │ │ │ │ + regExes: { │ │ │ │ + trimSpace: /^\s*|\s*$/g, │ │ │ │ + removeSpace: /\s*/g, │ │ │ │ + splitSpace: /\s+/, │ │ │ │ + trimComma: /\s*,\s*/g │ │ │ │ + }, │ │ │ │ + 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 info = { │ │ │ │ + features: [] │ │ │ │ + }; │ │ │ │ + this.readNode(data, info); │ │ │ │ + var features = []; │ │ │ │ + for (var i = 0, len = info.features.length; i < len; i++) { │ │ │ │ + var container = info.features[i]; │ │ │ │ + if (this.internalProjection && this.externalProjection && container.components[0]) { │ │ │ │ + container.components[0].transform(this.externalProjection, this.internalProjection) │ │ │ │ + } │ │ │ │ + var feature = new OpenLayers.Feature.Vector(container.components[0], container.attributes); │ │ │ │ + features.push(feature) │ │ │ │ + } │ │ │ │ + return features │ │ │ │ + }, │ │ │ │ + readers: { │ │ │ │ + sa: { │ │ │ │ + SamplingPoint: function(node, obj) { │ │ │ │ + if (!obj.attributes) { │ │ │ │ + var feature = { │ │ │ │ + attributes: {} │ │ │ │ + }; │ │ │ │ + obj.features.push(feature); │ │ │ │ + obj = feature │ │ │ │ + } │ │ │ │ + obj.attributes.id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + position: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + gml: OpenLayers.Util.applyDefaults({ │ │ │ │ + FeatureCollection: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + featureMember: function(node, obj) { │ │ │ │ + var feature = { │ │ │ │ + attributes: {} │ │ │ │ + }; │ │ │ │ + obj.features.push(feature); │ │ │ │ + this.readChildNodes(node, feature) │ │ │ │ + }, │ │ │ │ + name: function(node, obj) { │ │ │ │ + obj.attributes.name = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + pos: function(node, obj) { │ │ │ │ + if (!this.externalProjection) { │ │ │ │ + this.externalProjection = new OpenLayers.Projection(node.getAttribute("srsName")) │ │ │ │ + } │ │ │ │ + OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply(this, [node, obj]) │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.GML.v3.prototype.readers.gml) │ │ │ │ + }, │ │ │ │ + writers: { │ │ │ │ + sos: { │ │ │ │ + GetFeatureOfInterest: function(options) { │ │ │ │ + var node = this.createElementNSPlus("GetFeatureOfInterest", { │ │ │ │ + attributes: { │ │ │ │ + version: this.VERSION, │ │ │ │ + service: "SOS", │ │ │ │ + "xsi:schemaLocation": this.schemaLocation │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + for (var i = 0, len = options.fois.length; i < len; i++) { │ │ │ │ + this.writeNode("FeatureOfInterestId", { │ │ │ │ + foi: options.fois[i] │ │ │ │ + }, node) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + FeatureOfInterestId: function(options) { │ │ │ │ + var node = this.createElementNSPlus("FeatureOfInterestId", { │ │ │ │ + value: options.foi │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SOSGetFeatureOfInterest" │ │ │ │ +}); │ │ │ │ +OpenLayers.Protocol.SOS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ + fois: null, │ │ │ │ + formatOptions: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ + if (!options.format) { │ │ │ │ + this.format = new OpenLayers.Format.SOSGetFeatureOfInterest(this.formatOptions) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.options && !this.options.format) { │ │ │ │ + this.format.destroy() │ │ │ │ + } │ │ │ │ + this.format = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ + }, │ │ │ │ + read: function(options) { │ │ │ │ + options = OpenLayers.Util.extend({}, options); │ │ │ │ + OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ + var response = new OpenLayers.Protocol.Response({ │ │ │ │ + requestType: "read" │ │ │ │ + }); │ │ │ │ + var format = this.format; │ │ │ │ + var data = OpenLayers.Format.XML.prototype.write.apply(format, [format.writeNode("sos:GetFeatureOfInterest", { │ │ │ │ + fois: this.fois │ │ │ │ + })]); │ │ │ │ + response.priv = OpenLayers.Request.POST({ │ │ │ │ + url: options.url, │ │ │ │ + callback: this.createCallback(this.handleRead, response, options), │ │ │ │ + data: data │ │ │ │ + }); │ │ │ │ + return response │ │ │ │ + }, │ │ │ │ + handleRead: function(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + var request = response.priv; │ │ │ │ + if (request.status >= 200 && request.status < 300) { │ │ │ │ + response.features = this.parseFeatures(request); │ │ │ │ + response.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ + } else { │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ + } │ │ │ │ + options.callback.call(options.scope, response) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.SOS.v1_0_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ + version: null, │ │ │ │ + srsName: "EPSG:4326", │ │ │ │ + featureType: null, │ │ │ │ + featureNS: null, │ │ │ │ + geometryName: "the_geom", │ │ │ │ + schema: null, │ │ │ │ + featurePrefix: "feature", │ │ │ │ + formatOptions: null, │ │ │ │ + readFormat: null, │ │ │ │ + readOptions: null, │ │ │ │ + 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) { │ │ │ │ + this.setGeometryName(null) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.options && !this.options.format) { │ │ │ │ + this.format.destroy() │ │ │ │ + } │ │ │ │ + this.format = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + setFeatureType: function(featureType) { │ │ │ │ + this.featureType = featureType; │ │ │ │ + this.format.featureType = featureType │ │ │ │ + }, │ │ │ │ + setGeometryName: function(geometryName) { │ │ │ │ + this.geometryName = geometryName; │ │ │ │ + this.format.geometryName = geometryName │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + 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 { │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ + response.error = result │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ + } │ │ │ │ + options.callback.call(options.scope, response) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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; │ │ │ │ + format.autoConfig = false; │ │ │ │ + if (!this.geometryName) { │ │ │ │ + this.setGeometryName(format.geometryName) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return result │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + handleCommit: function(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + var request = response.priv; │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + abort: function(response) { │ │ │ │ + if (response) { │ │ │ │ + response.priv.abort() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.WFS.v1" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, { │ │ │ │ + schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd", │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + 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"] │ │ │ │ + }, │ │ │ │ + write: function(features) { │ │ │ │ + var name; │ │ │ │ + if (OpenLayers.Util.isArray(features)) { │ │ │ │ + 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]) │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + 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); │ │ │ │ + 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.Format.Filter.v1_0_0 = OpenLayers.Class(OpenLayers.Format.GML.v2, OpenLayers.Format.Filter.v1, { │ │ │ │ + VERSION: "1.0.0", │ │ │ │ + schemaLocation: "http://www.opengis.net/ogc/filter/1.0.0/filter.xsd", │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.GML.v2.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ }); │ │ │ │ @@ -23675,14 +27140,1226 @@ │ │ │ │ } │ │ │ │ node.appendChild(child) │ │ │ │ } │ │ │ │ return node │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.Filter.v1_0_0" │ │ │ │ }); │ │ │ │ +OpenLayers.Format.WFST.v1_0_0 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, OpenLayers.Format.WFST.v1, { │ │ │ │ + version: "1.0.0", │ │ │ │ + srsNameInQuery: false, │ │ │ │ + schemaLocations: { │ │ │ │ + wfs: "http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd" │ │ │ │ + }, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this, [options]); │ │ │ │ + OpenLayers.Format.WFST.v1.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + readNode: function(node, obj, first) { │ │ │ │ + return OpenLayers.Format.GML.v2.prototype.readNode.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + 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"] │ │ │ │ + }, │ │ │ │ + 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.Protocol.WFS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ + version: "1.0.0", │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.WFS.v1_0_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Protocol.WFS.v1_1_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ + version: "1.1.0", │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Protocol.WFS.v1.prototype.initialize.apply(this, arguments); │ │ │ │ + if (this.outputFormat && !this.readFormat) { │ │ │ │ + if (this.outputFormat.toLowerCase() == "gml2") { │ │ │ │ + this.readFormat = new OpenLayers.Format.GML.v2({ │ │ │ │ + featureType: this.featureType, │ │ │ │ + featureNS: this.featureNS, │ │ │ │ + geometryName: this.geometryName │ │ │ │ + }) │ │ │ │ + } else if (this.outputFormat.toLowerCase() == "json") { │ │ │ │ + this.readFormat = new OpenLayers.Format.GeoJSON │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.WFS.v1_1_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.CSWGetRecords = function(options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, OpenLayers.Format.CSWGetRecords.DEFAULTS); │ │ │ │ + var cls = OpenLayers.Format.CSWGetRecords["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (!cls) { │ │ │ │ + throw "Unsupported CSWGetRecords version: " + options.version │ │ │ │ + } │ │ │ │ + return new cls(options) │ │ │ │ +}; │ │ │ │ +OpenLayers.Format.CSWGetRecords.DEFAULTS = { │ │ │ │ + version: "2.0.2" │ │ │ │ +}; │ │ │ │ +OpenLayers.Format.CSWGetRecords.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + namespaces: { │ │ │ │ + csw: "http://www.opengis.net/cat/csw/2.0.2", │ │ │ │ + dc: "http://purl.org/dc/elements/1.1/", │ │ │ │ + dct: "http://purl.org/dc/terms/", │ │ │ │ + gmd: "http://www.isotc211.org/2005/gmd", │ │ │ │ + geonet: "http://www.fao.org/geonetwork", │ │ │ │ + ogc: "http://www.opengis.net/ogc", │ │ │ │ + ows: "http://www.opengis.net/ows", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + }, │ │ │ │ + defaultPrefix: "csw", │ │ │ │ + version: "2.0.2", │ │ │ │ + schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ + requestId: null, │ │ │ │ + resultType: null, │ │ │ │ + outputFormat: null, │ │ │ │ + outputSchema: null, │ │ │ │ + startPosition: null, │ │ │ │ + maxRecords: null, │ │ │ │ + DistributedSearch: null, │ │ │ │ + ResponseHandler: null, │ │ │ │ + Query: null, │ │ │ │ + regExes: { │ │ │ │ + trimSpace: /^\s*|\s*$/g, │ │ │ │ + removeSpace: /\s*/g, │ │ │ │ + splitSpace: /\s+/, │ │ │ │ + trimComma: /\s*,\s*/g │ │ │ │ + }, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + 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 obj = {}; │ │ │ │ + this.readNode(data, obj); │ │ │ │ + return obj │ │ │ │ + }, │ │ │ │ + readers: { │ │ │ │ + csw: { │ │ │ │ + GetRecordsResponse: function(node, obj) { │ │ │ │ + obj.records = []; │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + var version = this.getAttributeNS(node, "", "version"); │ │ │ │ + if (version != "") { │ │ │ │ + obj.version = version │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + RequestId: function(node, obj) { │ │ │ │ + obj.RequestId = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + SearchStatus: function(node, obj) { │ │ │ │ + obj.SearchStatus = {}; │ │ │ │ + var timestamp = this.getAttributeNS(node, "", "timestamp"); │ │ │ │ + if (timestamp != "") { │ │ │ │ + obj.SearchStatus.timestamp = timestamp │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + SearchResults: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj); │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var SearchResults = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + if (attrs[i].name == "numberOfRecordsMatched" || attrs[i].name == "numberOfRecordsReturned" || attrs[i].name == "nextRecord") { │ │ │ │ + SearchResults[attrs[i].name] = parseInt(attrs[i].nodeValue) │ │ │ │ + } else { │ │ │ │ + SearchResults[attrs[i].name] = attrs[i].nodeValue │ │ │ │ + } │ │ │ │ + } │ │ │ │ + obj.SearchResults = SearchResults │ │ │ │ + }, │ │ │ │ + SummaryRecord: function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "SummaryRecord" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record) │ │ │ │ + }, │ │ │ │ + BriefRecord: function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "BriefRecord" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record) │ │ │ │ + }, │ │ │ │ + DCMIRecord: function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "DCMIRecord" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record) │ │ │ │ + }, │ │ │ │ + Record: function(node, obj) { │ │ │ │ + var record = { │ │ │ │ + type: "Record" │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, record); │ │ │ │ + obj.records.push(record) │ │ │ │ + }, │ │ │ │ + "*": function(node, obj) { │ │ │ │ + var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ + obj[name] = this.getChildValue(node) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + geonet: { │ │ │ │ + info: function(node, obj) { │ │ │ │ + var gninfo = {}; │ │ │ │ + this.readChildNodes(node, gninfo); │ │ │ │ + obj.gninfo = gninfo │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + dc: { │ │ │ │ + "*": function(node, obj) { │ │ │ │ + var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ + if (!OpenLayers.Util.isArray(obj[name])) { │ │ │ │ + obj[name] = [] │ │ │ │ + } │ │ │ │ + var dc_element = {}; │ │ │ │ + var attrs = node.attributes; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + dc_element[attrs[i].name] = attrs[i].nodeValue │ │ │ │ + } │ │ │ │ + dc_element.value = this.getChildValue(node); │ │ │ │ + if (dc_element.value != "") { │ │ │ │ + obj[name].push(dc_element) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + dct: { │ │ │ │ + "*": function(node, obj) { │ │ │ │ + var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ + if (!OpenLayers.Util.isArray(obj[name])) { │ │ │ │ + obj[name] = [] │ │ │ │ + } │ │ │ │ + obj[name].push(this.getChildValue(node)) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + ows: OpenLayers.Util.applyDefaults({ │ │ │ │ + BoundingBox: function(node, obj) { │ │ │ │ + if (obj.bounds) { │ │ │ │ + obj.BoundingBox = [{ │ │ │ │ + crs: obj.projection, │ │ │ │ + value: [obj.bounds.left, obj.bounds.bottom, obj.bounds.right, obj.bounds.top] │ │ │ │ + }]; │ │ │ │ + delete obj.projection; │ │ │ │ + delete obj.bounds │ │ │ │ + } │ │ │ │ + OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]["BoundingBox"].apply(this, arguments) │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]) │ │ │ │ + }, │ │ │ │ + write: function(options) { │ │ │ │ + var node = this.writeNode("csw:GetRecords", options); │ │ │ │ + node.setAttribute("xmlns:gmd", this.namespaces.gmd); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [node]) │ │ │ │ + }, │ │ │ │ + writers: { │ │ │ │ + csw: { │ │ │ │ + GetRecords: function(options) { │ │ │ │ + if (!options) { │ │ │ │ + options = {} │ │ │ │ + } │ │ │ │ + var node = this.createElementNSPlus("csw:GetRecords", { │ │ │ │ + attributes: { │ │ │ │ + service: "CSW", │ │ │ │ + version: this.version, │ │ │ │ + requestId: options.requestId || this.requestId, │ │ │ │ + resultType: options.resultType || this.resultType, │ │ │ │ + outputFormat: options.outputFormat || this.outputFormat, │ │ │ │ + outputSchema: options.outputSchema || this.outputSchema, │ │ │ │ + startPosition: options.startPosition || this.startPosition, │ │ │ │ + maxRecords: options.maxRecords || this.maxRecords │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (options.DistributedSearch || this.DistributedSearch) { │ │ │ │ + this.writeNode("csw:DistributedSearch", options.DistributedSearch || this.DistributedSearch, node) │ │ │ │ + } │ │ │ │ + var ResponseHandler = options.ResponseHandler || this.ResponseHandler; │ │ │ │ + if (OpenLayers.Util.isArray(ResponseHandler) && ResponseHandler.length > 0) { │ │ │ │ + for (var i = 0, len = ResponseHandler.length; i < len; i++) { │ │ │ │ + this.writeNode("csw:ResponseHandler", ResponseHandler[i], node) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.writeNode("Query", options.Query || this.Query, node); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + DistributedSearch: function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:DistributedSearch", { │ │ │ │ + attributes: { │ │ │ │ + hopCount: options.hopCount │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + ResponseHandler: function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:ResponseHandler", { │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + Query: function(options) { │ │ │ │ + if (!options) { │ │ │ │ + options = {} │ │ │ │ + } │ │ │ │ + var node = this.createElementNSPlus("csw:Query", { │ │ │ │ + attributes: { │ │ │ │ + typeNames: options.typeNames || "csw:Record" │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + var ElementName = options.ElementName; │ │ │ │ + if (OpenLayers.Util.isArray(ElementName) && ElementName.length > 0) { │ │ │ │ + for (var i = 0, len = ElementName.length; i < len; i++) { │ │ │ │ + this.writeNode("csw:ElementName", ElementName[i], node) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + this.writeNode("csw:ElementSetName", options.ElementSetName || { │ │ │ │ + value: "summary" │ │ │ │ + }, node) │ │ │ │ + } │ │ │ │ + if (options.Constraint) { │ │ │ │ + this.writeNode("csw:Constraint", options.Constraint, node) │ │ │ │ + } │ │ │ │ + if (options.SortBy) { │ │ │ │ + this.writeNode("ogc:SortBy", options.SortBy, node) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + ElementName: function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:ElementName", { │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + ElementSetName: function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:ElementSetName", { │ │ │ │ + attributes: { │ │ │ │ + typeNames: options.typeNames │ │ │ │ + }, │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + Constraint: function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:Constraint", { │ │ │ │ + attributes: { │ │ │ │ + version: options.version │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (options.Filter) { │ │ │ │ + var format = new OpenLayers.Format.Filter({ │ │ │ │ + version: options.version │ │ │ │ + }); │ │ │ │ + node.appendChild(format.write(options.Filter)) │ │ │ │ + } else if (options.CqlText) { │ │ │ │ + var child = this.createElementNSPlus("CqlText", { │ │ │ │ + value: options.CqlText.value │ │ │ │ + }); │ │ │ │ + node.appendChild(child) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + ogc: OpenLayers.Format.Filter.v1_1_0.prototype.writers["ogc"] │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.CSWGetRecords.v2_0_2" │ │ │ │ +}); │ │ │ │ +OpenLayers.Protocol.CSW.v2_0_2 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ + formatOptions: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ + if (!options.format) { │ │ │ │ + this.format = new OpenLayers.Format.CSWGetRecords.v2_0_2(OpenLayers.Util.extend({}, this.formatOptions)) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.options && !this.options.format) { │ │ │ │ + this.format.destroy() │ │ │ │ + } │ │ │ │ + this.format = null; │ │ │ │ + OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ + }, │ │ │ │ + read: function(options) { │ │ │ │ + options = OpenLayers.Util.extend({}, options); │ │ │ │ + OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ + var response = new OpenLayers.Protocol.Response({ │ │ │ │ + requestType: "read" │ │ │ │ + }); │ │ │ │ + var data = this.format.write(options.params || 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 │ │ │ │ + }, │ │ │ │ + handleRead: function(response, options) { │ │ │ │ + if (options.callback) { │ │ │ │ + var request = response.priv; │ │ │ │ + if (request.status >= 200 && request.status < 300) { │ │ │ │ + response.data = this.parseData(request); │ │ │ │ + response.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ + } else { │ │ │ │ + response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ + } │ │ │ │ + options.callback.call(options.scope, response) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + parseData: 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) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.CSW.v2_0_2" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.ScaleLine = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + maxWidth: 100, │ │ │ │ + topOutUnits: "km", │ │ │ │ + topInUnits: "m", │ │ │ │ + bottomOutUnits: "mi", │ │ │ │ + bottomInUnits: "ft", │ │ │ │ + eTop: null, │ │ │ │ + eBottom: null, │ │ │ │ + geodesic: false, │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (!this.eTop) { │ │ │ │ + this.eTop = document.createElement("div"); │ │ │ │ + this.eTop.className = this.displayClass + "Top"; │ │ │ │ + var theLen = this.topInUnits.length; │ │ │ │ + this.div.appendChild(this.eTop); │ │ │ │ + if (this.topOutUnits == "" || this.topInUnits == "") { │ │ │ │ + this.eTop.style.visibility = "hidden" │ │ │ │ + } else { │ │ │ │ + this.eTop.style.visibility = "visible" │ │ │ │ + } │ │ │ │ + this.eBottom = document.createElement("div"); │ │ │ │ + this.eBottom.className = this.displayClass + "Bottom"; │ │ │ │ + this.div.appendChild(this.eBottom); │ │ │ │ + if (this.bottomOutUnits == "" || this.bottomInUnits == "") { │ │ │ │ + this.eBottom.style.visibility = "hidden" │ │ │ │ + } else { │ │ │ │ + this.eBottom.style.visibility = "visible" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.map.events.register("moveend", this, this.update); │ │ │ │ + this.update(); │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + getBarLen: function(maxLen) { │ │ │ │ + var digits = parseInt(Math.log(maxLen) / Math.log(10)); │ │ │ │ + var pow10 = Math.pow(10, digits); │ │ │ │ + var firstChar = parseInt(maxLen / pow10); │ │ │ │ + var barLen; │ │ │ │ + if (firstChar > 5) { │ │ │ │ + barLen = 5 │ │ │ │ + } else if (firstChar > 2) { │ │ │ │ + barLen = 2 │ │ │ │ + } else { │ │ │ │ + barLen = 1 │ │ │ │ + } │ │ │ │ + return barLen * pow10 │ │ │ │ + }, │ │ │ │ + update: function() { │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ + if (!res) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + var curMapUnits = this.map.getUnits(); │ │ │ │ + var inches = OpenLayers.INCHES_PER_UNIT; │ │ │ │ + var maxSizeData = this.maxWidth * res * inches[curMapUnits]; │ │ │ │ + var geodesicRatio = 1; │ │ │ │ + if (this.geodesic === true) { │ │ │ │ + var maxSizeGeodesic = (this.map.getGeodesicPixelSize().w || 1e-6) * this.maxWidth; │ │ │ │ + var maxSizeKilometers = maxSizeData / inches["km"]; │ │ │ │ + geodesicRatio = maxSizeGeodesic / maxSizeKilometers; │ │ │ │ + maxSizeData *= geodesicRatio │ │ │ │ + } │ │ │ │ + var topUnits; │ │ │ │ + var bottomUnits; │ │ │ │ + if (maxSizeData > 1e5) { │ │ │ │ + topUnits = this.topOutUnits; │ │ │ │ + bottomUnits = this.bottomOutUnits │ │ │ │ + } else { │ │ │ │ + topUnits = this.topInUnits; │ │ │ │ + bottomUnits = this.bottomInUnits │ │ │ │ + } │ │ │ │ + var topMax = maxSizeData / inches[topUnits]; │ │ │ │ + var bottomMax = maxSizeData / inches[bottomUnits]; │ │ │ │ + var topRounded = this.getBarLen(topMax); │ │ │ │ + var bottomRounded = this.getBarLen(bottomMax); │ │ │ │ + topMax = topRounded / inches[curMapUnits] * inches[topUnits]; │ │ │ │ + bottomMax = bottomRounded / inches[curMapUnits] * inches[bottomUnits]; │ │ │ │ + var topPx = topMax / res / geodesicRatio; │ │ │ │ + var bottomPx = bottomMax / res / geodesicRatio; │ │ │ │ + if (this.eBottom.style.visibility == "visible") { │ │ │ │ + this.eBottom.style.width = Math.round(bottomPx) + "px"; │ │ │ │ + this.eBottom.innerHTML = bottomRounded + " " + bottomUnits │ │ │ │ + } │ │ │ │ + if (this.eTop.style.visibility == "visible") { │ │ │ │ + this.eTop.style.width = Math.round(topPx) + "px"; │ │ │ │ + this.eTop.innerHTML = topRounded + " " + topUnits │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ScaleLine" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ + panned: false, │ │ │ │ + interval: 0, │ │ │ │ + documentDrag: false, │ │ │ │ + kinetic: null, │ │ │ │ + enableKinetic: true, │ │ │ │ + kineticInterval: 10, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + panMapStart: function() { │ │ │ │ + if (this.kinetic) { │ │ │ │ + this.kinetic.begin() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + 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.Button = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + type: OpenLayers.Control.TYPE_BUTTON, │ │ │ │ + trigger: function() {}, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Button" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.ZoomIn = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ + trigger: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.zoomIn() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomIn" │ │ │ │ +}); │ │ │ │ +OpenLayers.Events.buttonclick = OpenLayers.Class({ │ │ │ │ + target: null, │ │ │ │ + events: ["mousedown", "mouseup", "click", "dblclick", "touchstart", "touchmove", "touchend", "keydown"], │ │ │ │ + startRegEx: /^mousedown|touchstart$/, │ │ │ │ + cancelRegEx: /^touchmove$/, │ │ │ │ + completeRegEx: /^mouseup|touchend$/, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + for (var i = this.events.length - 1; i >= 0; --i) { │ │ │ │ + this.target.unregister(this.events[i], this, this.buttonClick) │ │ │ │ + } │ │ │ │ + delete this.target │ │ │ │ + }, │ │ │ │ + getPressedButton: function(element) { │ │ │ │ + var depth = 3, │ │ │ │ + button; │ │ │ │ + do { │ │ │ │ + if (OpenLayers.Element.hasClass(element, "olButton")) { │ │ │ │ + button = element; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + element = element.parentNode │ │ │ │ + } while (--depth > 0 && element); │ │ │ │ + return button │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + buttonClick: function(evt) { │ │ │ │ + var propagate = true, │ │ │ │ + element = OpenLayers.Event.element(evt); │ │ │ │ + if (element && (OpenLayers.Event.isLeftClick(evt) || !~evt.type.indexOf("mouse"))) { │ │ │ │ + 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.Panel = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + controls: null, │ │ │ │ + autoActivate: true, │ │ │ │ + defaultControl: null, │ │ │ │ + saveState: false, │ │ │ │ + allowDepress: false, │ │ │ │ + activeState: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.controls = []; │ │ │ │ + this.activeState = {} │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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) { │ │ │ │ + this.addControlsToMap(controls); │ │ │ │ + this.redraw() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + createControlMarkup: function(control) { │ │ │ │ + return document.createElement("div") │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + iconOn: function() { │ │ │ │ + var d = this.panel_div; │ │ │ │ + var re = new RegExp("\\b(" + this.displayClass + "Item)Inactive\\b"); │ │ │ │ + d.className = d.className.replace(re, "$1Active") │ │ │ │ + }, │ │ │ │ + iconOff: function() { │ │ │ │ + var d = this.panel_div; │ │ │ │ + var re = new RegExp("\\b(" + this.displayClass + "Item)Active\\b"); │ │ │ │ + d.className = d.className.replace(re, "$1Inactive") │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + getControlsByName: function(match) { │ │ │ │ + return this.getControlsBy("name", match) │ │ │ │ + }, │ │ │ │ + getControlsByClass: function(match) { │ │ │ │ + return this.getControlsBy("CLASS_NAME", match) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Panel" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + slideFactor: 50, │ │ │ │ + slideRatio: null, │ │ │ │ + buttons: null, │ │ │ │ + position: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X, OpenLayers.Control.PanZoom.Y); │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.unregister("buttonclick", this, this.onButtonClick) │ │ │ │ + } │ │ │ │ + this.removeButtons(); │ │ │ │ + this.buttons = null; │ │ │ │ + this.position = null; │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + this.map.events.register("buttonclick", this, this.onButtonClick) │ │ │ │ + }, │ │ │ │ + draw: function(px) { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + px = this.position; │ │ │ │ + this.buttons = []; │ │ │ │ + var sz = { │ │ │ │ + w: 18, │ │ │ │ + h: 18 │ │ │ │ + }; │ │ │ │ + var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ + this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ + px.y = centered.y + sz.h; │ │ │ │ + this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ + this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz); │ │ │ │ + this._addButton("pandown", "south-mini.png", centered.add(0, sz.h * 2), sz); │ │ │ │ + this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ + this._addButton("zoomworld", "zoom-world-mini.png", centered.add(0, sz.h * 4 + 5), sz); │ │ │ │ + this._addButton("zoomout", "zoom-minus-mini.png", centered.add(0, sz.h * 5 + 5), sz); │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + _addButton: function(id, img, xy, sz) { │ │ │ │ + var imgLocation = OpenLayers.Util.getImageLocation(img); │ │ │ │ + var btn = OpenLayers.Util.createAlphaImageDiv(this.id + "_" + id, xy, sz, imgLocation, "absolute"); │ │ │ │ + btn.style.cursor = "pointer"; │ │ │ │ + this.div.appendChild(btn); │ │ │ │ + btn.action = id; │ │ │ │ + btn.className = "olButton"; │ │ │ │ + this.buttons.push(btn); │ │ │ │ + return btn │ │ │ │ + }, │ │ │ │ + _removeButton: function(btn) { │ │ │ │ + this.div.removeChild(btn); │ │ │ │ + OpenLayers.Util.removeItem(this.buttons, btn) │ │ │ │ + }, │ │ │ │ + removeButtons: function() { │ │ │ │ + for (var i = this.buttons.length - 1; i >= 0; --i) { │ │ │ │ + this._removeButton(this.buttons[i]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + var btn = evt.buttonElement; │ │ │ │ + switch (btn.action) { │ │ │ │ + case "panup": │ │ │ │ + this.map.pan(0, -this.getSlideFactor("h")); │ │ │ │ + break; │ │ │ │ + case "pandown": │ │ │ │ + this.map.pan(0, this.getSlideFactor("h")); │ │ │ │ + break; │ │ │ │ + case "panleft": │ │ │ │ + this.map.pan(-this.getSlideFactor("w"), 0); │ │ │ │ + break; │ │ │ │ + case "panright": │ │ │ │ + this.map.pan(this.getSlideFactor("w"), 0); │ │ │ │ + break; │ │ │ │ + case "zoomin": │ │ │ │ + this.map.zoomIn(); │ │ │ │ + break; │ │ │ │ + case "zoomout": │ │ │ │ + this.map.zoomOut(); │ │ │ │ + break; │ │ │ │ + case "zoomworld": │ │ │ │ + this.map.zoomToMaxExtent(); │ │ │ │ + break │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getSlideFactor: function(dim) { │ │ │ │ + return this.slideRatio ? this.map.getSize()[dim] * this.slideRatio : this.slideFactor │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.PanZoom" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.PanZoom.X = 4; │ │ │ │ +OpenLayers.Control.PanZoom.Y = 4; │ │ │ │ +OpenLayers.Control.PanZoomBar = OpenLayers.Class(OpenLayers.Control.PanZoom, { │ │ │ │ + zoomStopWidth: 18, │ │ │ │ + zoomStopHeight: 11, │ │ │ │ + slider: null, │ │ │ │ + sliderEvents: null, │ │ │ │ + zoombarDiv: null, │ │ │ │ + zoomWorldIcon: false, │ │ │ │ + panIcons: true, │ │ │ │ + forceFixedZoomLevel: false, │ │ │ │ + mouseDragStart: null, │ │ │ │ + deltaY: null, │ │ │ │ + zoomStart: null, │ │ │ │ + destroy: function() { │ │ │ │ + this._removeZoomBar(); │ │ │ │ + this.map.events.un({ │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ + updatesize: this.redraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments); │ │ │ │ + delete this.mouseDragStart; │ │ │ │ + delete this.zoomStart │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments); │ │ │ │ + this.map.events.on({ │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ + updatesize: this.redraw, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + redraw: function() { │ │ │ │ + if (this.div != null) { │ │ │ │ + this.removeButtons(); │ │ │ │ + this._removeZoomBar() │ │ │ │ + } │ │ │ │ + this.draw() │ │ │ │ + }, │ │ │ │ + draw: function(px) { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + px = this.position.clone(); │ │ │ │ + this.buttons = []; │ │ │ │ + var sz = { │ │ │ │ + w: 18, │ │ │ │ + h: 18 │ │ │ │ + }; │ │ │ │ + if (this.panIcons) { │ │ │ │ + var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ + var wposition = sz.w; │ │ │ │ + if (this.zoomWorldIcon) { │ │ │ │ + centered = new OpenLayers.Pixel(px.x + sz.w, px.y) │ │ │ │ + } │ │ │ │ + this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ + px.y = centered.y + sz.h; │ │ │ │ + this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ + if (this.zoomWorldIcon) { │ │ │ │ + this._addButton("zoomworld", "zoom-world-mini.png", px.add(sz.w, 0), sz); │ │ │ │ + wposition *= 2 │ │ │ │ + } │ │ │ │ + this._addButton("panright", "east-mini.png", px.add(wposition, 0), sz); │ │ │ │ + this._addButton("pandown", "south-mini.png", centered.add(0, sz.h * 2), sz); │ │ │ │ + this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ + centered = this._addZoomBar(centered.add(0, sz.h * 4 + 5)); │ │ │ │ + this._addButton("zoomout", "zoom-minus-mini.png", centered, sz) │ │ │ │ + } else { │ │ │ │ + this._addButton("zoomin", "zoom-plus-mini.png", px, sz); │ │ │ │ + centered = this._addZoomBar(px.add(0, sz.h)); │ │ │ │ + this._addButton("zoomout", "zoom-minus-mini.png", centered, sz); │ │ │ │ + if (this.zoomWorldIcon) { │ │ │ │ + centered = centered.add(0, sz.h + 3); │ │ │ │ + this._addButton("zoomworld", "zoom-world-mini.png", centered, sz) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + _addZoomBar: function(centered) { │ │ │ │ + var imgLocation = OpenLayers.Util.getImageLocation("slider.png"); │ │ │ │ + var id = this.id + "_" + this.map.id; │ │ │ │ + var minZoom = this.map.getMinZoom(); │ │ │ │ + var zoomsToEnd = this.map.getNumZoomLevels() - 1 - this.map.getZoom(); │ │ │ │ + var slider = OpenLayers.Util.createAlphaImageDiv(id, centered.add(-1, zoomsToEnd * this.zoomStopHeight), { │ │ │ │ + w: 20, │ │ │ │ + h: 9 │ │ │ │ + }, imgLocation, "absolute"); │ │ │ │ + slider.style.cursor = "move"; │ │ │ │ + this.slider = slider; │ │ │ │ + this.sliderEvents = new OpenLayers.Events(this, slider, null, true, { │ │ │ │ + includeXY: true │ │ │ │ + }); │ │ │ │ + this.sliderEvents.on({ │ │ │ │ + touchstart: this.zoomBarDown, │ │ │ │ + touchmove: this.zoomBarDrag, │ │ │ │ + touchend: this.zoomBarUp, │ │ │ │ + mousedown: this.zoomBarDown, │ │ │ │ + mousemove: this.zoomBarDrag, │ │ │ │ + mouseup: this.zoomBarUp │ │ │ │ + }); │ │ │ │ + var sz = { │ │ │ │ + w: this.zoomStopWidth, │ │ │ │ + h: this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom) │ │ │ │ + }; │ │ │ │ + var imgLocation = OpenLayers.Util.getImageLocation("zoombar.png"); │ │ │ │ + var div = null; │ │ │ │ + if (OpenLayers.Util.alphaHack()) { │ │ │ │ + var id = this.id + "_" + this.map.id; │ │ │ │ + div = OpenLayers.Util.createAlphaImageDiv(id, centered, { │ │ │ │ + w: sz.w, │ │ │ │ + h: this.zoomStopHeight │ │ │ │ + }, imgLocation, "absolute", null, "crop"); │ │ │ │ + div.style.height = sz.h + "px" │ │ │ │ + } else { │ │ │ │ + div = OpenLayers.Util.createDiv("OpenLayers_Control_PanZoomBar_Zoombar" + this.map.id, centered, sz, imgLocation) │ │ │ │ + } │ │ │ │ + div.style.cursor = "pointer"; │ │ │ │ + div.className = "olButton"; │ │ │ │ + this.zoombarDiv = div; │ │ │ │ + this.div.appendChild(div); │ │ │ │ + this.startTop = parseInt(div.style.top); │ │ │ │ + this.div.appendChild(slider); │ │ │ │ + this.map.events.register("zoomend", this, this.moveZoomBar); │ │ │ │ + centered = centered.add(0, this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom)); │ │ │ │ + return centered │ │ │ │ + }, │ │ │ │ + _removeZoomBar: function() { │ │ │ │ + this.sliderEvents.un({ │ │ │ │ + touchstart: this.zoomBarDown, │ │ │ │ + touchmove: this.zoomBarDrag, │ │ │ │ + touchend: this.zoomBarUp, │ │ │ │ + mousedown: this.zoomBarDown, │ │ │ │ + mousemove: this.zoomBarDrag, │ │ │ │ + mouseup: this.zoomBarUp │ │ │ │ + }); │ │ │ │ + this.sliderEvents.destroy(); │ │ │ │ + this.div.removeChild(this.zoombarDiv); │ │ │ │ + this.zoombarDiv = null; │ │ │ │ + this.div.removeChild(this.slider); │ │ │ │ + this.slider = null; │ │ │ │ + this.map.events.unregister("zoomend", this, this.moveZoomBar) │ │ │ │ + }, │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this, arguments); │ │ │ │ + if (evt.buttonElement === this.zoombarDiv) { │ │ │ │ + var levels = evt.buttonXY.y / this.zoomStopHeight; │ │ │ │ + if (this.forceFixedZoomLevel || !this.map.fractionalZoom) { │ │ │ │ + levels = Math.floor(levels) │ │ │ │ + } │ │ │ │ + var zoom = this.map.getNumZoomLevels() - 1 - levels; │ │ │ │ + zoom = Math.min(Math.max(zoom, 0), this.map.getNumZoomLevels() - 1); │ │ │ │ + this.map.zoomTo(zoom) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + passEventToSlider: function(evt) { │ │ │ │ + this.sliderEvents.handleBrowserEvent(evt) │ │ │ │ + }, │ │ │ │ + zoomBarDown: function(evt) { │ │ │ │ + if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + this.map.events.on({ │ │ │ │ + touchmove: this.passEventToSlider, │ │ │ │ + mousemove: this.passEventToSlider, │ │ │ │ + mouseup: this.passEventToSlider, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.mouseDragStart = evt.xy.clone(); │ │ │ │ + this.zoomStart = evt.xy.clone(); │ │ │ │ + this.div.style.cursor = "move"; │ │ │ │ + this.zoombarDiv.offsets = null; │ │ │ │ + OpenLayers.Event.stop(evt) │ │ │ │ + }, │ │ │ │ + zoomBarDrag: function(evt) { │ │ │ │ + if (this.mouseDragStart != null) { │ │ │ │ + var deltaY = this.mouseDragStart.y - evt.xy.y; │ │ │ │ + var offsets = OpenLayers.Util.pagePosition(this.zoombarDiv); │ │ │ │ + if (evt.clientY - offsets[1] > 0 && evt.clientY - offsets[1] < parseInt(this.zoombarDiv.style.height) - 2) { │ │ │ │ + var newTop = parseInt(this.slider.style.top) - deltaY; │ │ │ │ + this.slider.style.top = newTop + "px"; │ │ │ │ + this.mouseDragStart = evt.xy.clone() │ │ │ │ + } │ │ │ │ + this.deltaY = this.zoomStart.y - evt.xy.y; │ │ │ │ + OpenLayers.Event.stop(evt) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + zoomBarUp: function(evt) { │ │ │ │ + if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + if (this.mouseDragStart) { │ │ │ │ + this.div.style.cursor = ""; │ │ │ │ + this.map.events.un({ │ │ │ │ + touchmove: this.passEventToSlider, │ │ │ │ + mouseup: this.passEventToSlider, │ │ │ │ + mousemove: this.passEventToSlider, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + var zoomLevel = this.map.zoom; │ │ │ │ + if (!this.forceFixedZoomLevel && this.map.fractionalZoom) { │ │ │ │ + zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ + zoomLevel = Math.min(Math.max(zoomLevel, 0), this.map.getNumZoomLevels() - 1) │ │ │ │ + } else { │ │ │ │ + zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ + zoomLevel = Math.max(Math.round(zoomLevel), 0) │ │ │ │ + } │ │ │ │ + this.map.zoomTo(zoomLevel); │ │ │ │ + this.mouseDragStart = null; │ │ │ │ + this.zoomStart = null; │ │ │ │ + this.deltaY = 0; │ │ │ │ + OpenLayers.Event.stop(evt) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + moveZoomBar: function() { │ │ │ │ + var newTop = (this.map.getNumZoomLevels() - 1 - this.map.getZoom()) * this.zoomStopHeight + this.startTop + 1; │ │ │ │ + this.slider.style.top = newTop + "px" │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.PanZoomBar" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.SLD = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + profile: null, │ │ │ │ + defaultVersion: "1.0.0", │ │ │ │ + stringifyOutput: true, │ │ │ │ + namedLayersAsArray: false, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SLD" │ │ │ │ +}); │ │ │ │ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { │ │ │ │ namespaces: { │ │ │ │ sld: "http://www.opengis.net/sld", │ │ │ │ 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" │ │ │ │ @@ -24989,204 +29666,14 @@ │ │ │ │ break │ │ │ │ } │ │ │ │ } │ │ │ │ canApply && this._queue.call(this) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.SLDSelect" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.Button = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - type: OpenLayers.Control.TYPE_BUTTON, │ │ │ │ - trigger: function() {}, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Button" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.NavigationHistory = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - type: OpenLayers.Control.TYPE_TOGGLE, │ │ │ │ - previous: null, │ │ │ │ - previousOptions: null, │ │ │ │ - next: null, │ │ │ │ - nextOptions: null, │ │ │ │ - limit: 50, │ │ │ │ - autoActivate: true, │ │ │ │ - clearOnDeactivate: false, │ │ │ │ - registry: null, │ │ │ │ - nextStack: null, │ │ │ │ - previousStack: null, │ │ │ │ - listeners: null, │ │ │ │ - restoring: false, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.registry = OpenLayers.Util.extend({ │ │ │ │ - moveend: this.getState │ │ │ │ - }, this.registry); │ │ │ │ - var previousOptions = { │ │ │ │ - trigger: OpenLayers.Function.bind(this.previousTrigger, this), │ │ │ │ - displayClass: this.displayClass + " " + this.displayClass + "Previous" │ │ │ │ - }; │ │ │ │ - OpenLayers.Util.extend(previousOptions, this.previousOptions); │ │ │ │ - this.previous = new OpenLayers.Control.Button(previousOptions); │ │ │ │ - var nextOptions = { │ │ │ │ - trigger: OpenLayers.Function.bind(this.nextTrigger, this), │ │ │ │ - displayClass: this.displayClass + " " + this.displayClass + "Next" │ │ │ │ - }; │ │ │ │ - OpenLayers.Util.extend(nextOptions, this.nextOptions); │ │ │ │ - this.next = new OpenLayers.Control.Button(nextOptions); │ │ │ │ - this.clear() │ │ │ │ - }, │ │ │ │ - onPreviousChange: function(state, length) { │ │ │ │ - if (state && !this.previous.active) { │ │ │ │ - this.previous.activate() │ │ │ │ - } else if (!state && this.previous.active) { │ │ │ │ - this.previous.deactivate() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - onNextChange: function(state, length) { │ │ │ │ - if (state && !this.next.active) { │ │ │ │ - this.next.activate() │ │ │ │ - } else if (!state && this.next.active) { │ │ │ │ - this.next.deactivate() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this); │ │ │ │ - this.previous.destroy(); │ │ │ │ - this.next.destroy(); │ │ │ │ - this.deactivate(); │ │ │ │ - for (var prop in this) { │ │ │ │ - this[prop] = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - this.map = map; │ │ │ │ - this.next.setMap(map); │ │ │ │ - this.previous.setMap(map) │ │ │ │ - }, │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - this.next.draw(); │ │ │ │ - this.previous.draw() │ │ │ │ - }, │ │ │ │ - previousTrigger: function() { │ │ │ │ - var current = this.previousStack.shift(); │ │ │ │ - var state = this.previousStack.shift(); │ │ │ │ - if (state != undefined) { │ │ │ │ - this.nextStack.unshift(current); │ │ │ │ - this.previousStack.unshift(state); │ │ │ │ - this.restoring = true; │ │ │ │ - this.restore(state); │ │ │ │ - this.restoring = false; │ │ │ │ - this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ - this.onPreviousChange(this.previousStack[1], this.previousStack.length - 1) │ │ │ │ - } else { │ │ │ │ - this.previousStack.unshift(current) │ │ │ │ - } │ │ │ │ - return state │ │ │ │ - }, │ │ │ │ - nextTrigger: function() { │ │ │ │ - var state = this.nextStack.shift(); │ │ │ │ - if (state != undefined) { │ │ │ │ - this.previousStack.unshift(state); │ │ │ │ - this.restoring = true; │ │ │ │ - this.restore(state); │ │ │ │ - this.restoring = false; │ │ │ │ - this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ - this.onPreviousChange(this.previousStack[1], this.previousStack.length - 1) │ │ │ │ - } │ │ │ │ - return state │ │ │ │ - }, │ │ │ │ - clear: function() { │ │ │ │ - this.previousStack = []; │ │ │ │ - this.previous.deactivate(); │ │ │ │ - this.nextStack = []; │ │ │ │ - this.next.deactivate() │ │ │ │ - }, │ │ │ │ - getState: function() { │ │ │ │ - return { │ │ │ │ - center: this.map.getCenter(), │ │ │ │ - resolution: this.map.getResolution(), │ │ │ │ - projection: this.map.getProjectionObject(), │ │ │ │ - units: this.map.getProjectionObject().getUnits() || this.map.units || this.map.baseLayer.units │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - restore: function(state) { │ │ │ │ - var center, zoom; │ │ │ │ - if (this.map.getProjectionObject() == state.projection) { │ │ │ │ - zoom = this.map.getZoomForResolution(state.resolution); │ │ │ │ - center = state.center │ │ │ │ - } else { │ │ │ │ - center = state.center.clone(); │ │ │ │ - center.transform(state.projection, this.map.getProjectionObject()); │ │ │ │ - var sourceUnits = state.units; │ │ │ │ - var targetUnits = this.map.getProjectionObject().getUnits() || this.map.units || this.map.baseLayer.units; │ │ │ │ - var resolutionFactor = sourceUnits && targetUnits ? OpenLayers.INCHES_PER_UNIT[sourceUnits] / OpenLayers.INCHES_PER_UNIT[targetUnits] : 1; │ │ │ │ - zoom = this.map.getZoomForResolution(resolutionFactor * state.resolution) │ │ │ │ - } │ │ │ │ - this.map.setCenter(center, zoom) │ │ │ │ - }, │ │ │ │ - setListeners: function() { │ │ │ │ - this.listeners = {}; │ │ │ │ - for (var type in this.registry) { │ │ │ │ - this.listeners[type] = OpenLayers.Function.bind(function() { │ │ │ │ - if (!this.restoring) { │ │ │ │ - var state = this.registry[type].apply(this, arguments); │ │ │ │ - this.previousStack.unshift(state); │ │ │ │ - if (this.previousStack.length > 1) { │ │ │ │ - this.onPreviousChange(this.previousStack[1], this.previousStack.length - 1) │ │ │ │ - } │ │ │ │ - if (this.previousStack.length > this.limit + 1) { │ │ │ │ - this.previousStack.pop() │ │ │ │ - } │ │ │ │ - if (this.nextStack.length > 0) { │ │ │ │ - this.nextStack = []; │ │ │ │ - this.onNextChange(null, 0) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return true │ │ │ │ - }, this) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (this.map) { │ │ │ │ - if (OpenLayers.Control.prototype.activate.apply(this)) { │ │ │ │ - if (this.listeners == null) { │ │ │ │ - this.setListeners() │ │ │ │ - } │ │ │ │ - for (var type in this.listeners) { │ │ │ │ - this.map.events.register(type, this, this.listeners[type]) │ │ │ │ - } │ │ │ │ - activated = true; │ │ │ │ - if (this.previousStack.length == 0) { │ │ │ │ - this.initStack() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - initStack: function() { │ │ │ │ - if (this.map.getCenter()) { │ │ │ │ - this.listeners.moveend() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = false; │ │ │ │ - if (this.map) { │ │ │ │ - if (OpenLayers.Control.prototype.deactivate.apply(this)) { │ │ │ │ - for (var type in this.listeners) { │ │ │ │ - this.map.events.unregister(type, this, this.listeners[type]) │ │ │ │ - } │ │ │ │ - if (this.clearOnDeactivate) { │ │ │ │ - this.clear() │ │ │ │ - } │ │ │ │ - deactivated = true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.NavigationHistory" │ │ │ │ -}); │ │ │ │ OpenLayers.Control.Geolocate = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ geolocation: null, │ │ │ │ available: "geolocation" in navigator, │ │ │ │ bind: true, │ │ │ │ watch: false, │ │ │ │ geolocationOptions: null, │ │ │ │ destroy: function() { │ │ │ │ @@ -25237,604 +29724,395 @@ │ │ │ │ failure: function(error) { │ │ │ │ this.events.triggerEvent("locationfailed", { │ │ │ │ error: error │ │ │ │ }) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.Geolocate" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - slideFactor: 50, │ │ │ │ - slideRatio: null, │ │ │ │ - buttons: null, │ │ │ │ - position: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X, OpenLayers.Control.PanZoom.Y); │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.unregister("buttonclick", this, this.onButtonClick) │ │ │ │ - } │ │ │ │ - this.removeButtons(); │ │ │ │ - this.buttons = null; │ │ │ │ - this.position = null; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - this.map.events.register("buttonclick", this, this.onButtonClick) │ │ │ │ - }, │ │ │ │ - draw: function(px) { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - px = this.position; │ │ │ │ - this.buttons = []; │ │ │ │ - var sz = { │ │ │ │ - w: 18, │ │ │ │ - h: 18 │ │ │ │ - }; │ │ │ │ - var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ - this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ - px.y = centered.y + sz.h; │ │ │ │ - this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ - this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz); │ │ │ │ - this._addButton("pandown", "south-mini.png", centered.add(0, sz.h * 2), sz); │ │ │ │ - this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ - this._addButton("zoomworld", "zoom-world-mini.png", centered.add(0, sz.h * 4 + 5), sz); │ │ │ │ - this._addButton("zoomout", "zoom-minus-mini.png", centered.add(0, sz.h * 5 + 5), sz); │ │ │ │ - return this.div │ │ │ │ - }, │ │ │ │ - _addButton: function(id, img, xy, sz) { │ │ │ │ - var imgLocation = OpenLayers.Util.getImageLocation(img); │ │ │ │ - var btn = OpenLayers.Util.createAlphaImageDiv(this.id + "_" + id, xy, sz, imgLocation, "absolute"); │ │ │ │ - btn.style.cursor = "pointer"; │ │ │ │ - this.div.appendChild(btn); │ │ │ │ - btn.action = id; │ │ │ │ - btn.className = "olButton"; │ │ │ │ - this.buttons.push(btn); │ │ │ │ - return btn │ │ │ │ - }, │ │ │ │ - _removeButton: function(btn) { │ │ │ │ - this.div.removeChild(btn); │ │ │ │ - OpenLayers.Util.removeItem(this.buttons, btn) │ │ │ │ - }, │ │ │ │ - removeButtons: function() { │ │ │ │ - for (var i = this.buttons.length - 1; i >= 0; --i) { │ │ │ │ - this._removeButton(this.buttons[i]) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - var btn = evt.buttonElement; │ │ │ │ - switch (btn.action) { │ │ │ │ - case "panup": │ │ │ │ - this.map.pan(0, -this.getSlideFactor("h")); │ │ │ │ - break; │ │ │ │ - case "pandown": │ │ │ │ - this.map.pan(0, this.getSlideFactor("h")); │ │ │ │ - break; │ │ │ │ - case "panleft": │ │ │ │ - this.map.pan(-this.getSlideFactor("w"), 0); │ │ │ │ - break; │ │ │ │ - case "panright": │ │ │ │ - this.map.pan(this.getSlideFactor("w"), 0); │ │ │ │ - break; │ │ │ │ - case "zoomin": │ │ │ │ - this.map.zoomIn(); │ │ │ │ - break; │ │ │ │ - case "zoomout": │ │ │ │ - this.map.zoomOut(); │ │ │ │ - break; │ │ │ │ - case "zoomworld": │ │ │ │ - this.map.zoomToMaxExtent(); │ │ │ │ - break │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getSlideFactor: function(dim) { │ │ │ │ - return this.slideRatio ? this.map.getSize()[dim] * this.slideRatio : this.slideFactor │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.PanZoom" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.PanZoom.X = 4; │ │ │ │ -OpenLayers.Control.PanZoom.Y = 4; │ │ │ │ -OpenLayers.Control.PanZoomBar = OpenLayers.Class(OpenLayers.Control.PanZoom, { │ │ │ │ - zoomStopWidth: 18, │ │ │ │ - zoomStopHeight: 11, │ │ │ │ - slider: null, │ │ │ │ - sliderEvents: null, │ │ │ │ - zoombarDiv: null, │ │ │ │ - zoomWorldIcon: false, │ │ │ │ - panIcons: true, │ │ │ │ - forceFixedZoomLevel: false, │ │ │ │ - mouseDragStart: null, │ │ │ │ - deltaY: null, │ │ │ │ - zoomStart: null, │ │ │ │ - destroy: function() { │ │ │ │ - this._removeZoomBar(); │ │ │ │ - this.map.events.un({ │ │ │ │ - changebaselayer: this.redraw, │ │ │ │ - updatesize: this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments); │ │ │ │ - delete this.mouseDragStart; │ │ │ │ - delete this.zoomStart │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments); │ │ │ │ - this.map.events.on({ │ │ │ │ - changebaselayer: this.redraw, │ │ │ │ - updatesize: this.redraw, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - redraw: function() { │ │ │ │ - if (this.div != null) { │ │ │ │ - this.removeButtons(); │ │ │ │ - this._removeZoomBar() │ │ │ │ - } │ │ │ │ - this.draw() │ │ │ │ - }, │ │ │ │ - draw: function(px) { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - px = this.position.clone(); │ │ │ │ - this.buttons = []; │ │ │ │ - var sz = { │ │ │ │ - w: 18, │ │ │ │ - h: 18 │ │ │ │ - }; │ │ │ │ - if (this.panIcons) { │ │ │ │ - var centered = new OpenLayers.Pixel(px.x + sz.w / 2, px.y); │ │ │ │ - var wposition = sz.w; │ │ │ │ - if (this.zoomWorldIcon) { │ │ │ │ - centered = new OpenLayers.Pixel(px.x + sz.w, px.y) │ │ │ │ - } │ │ │ │ - this._addButton("panup", "north-mini.png", centered, sz); │ │ │ │ - px.y = centered.y + sz.h; │ │ │ │ - this._addButton("panleft", "west-mini.png", px, sz); │ │ │ │ - if (this.zoomWorldIcon) { │ │ │ │ - this._addButton("zoomworld", "zoom-world-mini.png", px.add(sz.w, 0), sz); │ │ │ │ - wposition *= 2 │ │ │ │ - } │ │ │ │ - this._addButton("panright", "east-mini.png", px.add(wposition, 0), sz); │ │ │ │ - this._addButton("pandown", "south-mini.png", centered.add(0, sz.h * 2), sz); │ │ │ │ - this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, sz.h * 3 + 5), sz); │ │ │ │ - centered = this._addZoomBar(centered.add(0, sz.h * 4 + 5)); │ │ │ │ - this._addButton("zoomout", "zoom-minus-mini.png", centered, sz) │ │ │ │ - } else { │ │ │ │ - this._addButton("zoomin", "zoom-plus-mini.png", px, sz); │ │ │ │ - centered = this._addZoomBar(px.add(0, sz.h)); │ │ │ │ - this._addButton("zoomout", "zoom-minus-mini.png", centered, sz); │ │ │ │ - if (this.zoomWorldIcon) { │ │ │ │ - centered = centered.add(0, sz.h + 3); │ │ │ │ - this._addButton("zoomworld", "zoom-world-mini.png", centered, sz) │ │ │ │ - } │ │ │ │ +OpenLayers.Control.Zoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + zoomInText: "+", │ │ │ │ + zoomInId: "olZoomInLink", │ │ │ │ + zoomOutText: "−", │ │ │ │ + zoomOutId: "olZoomOutLink", │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - return this.div │ │ │ │ + eventsInstance.register("buttonclick", this, this.onZoomClick); │ │ │ │ + this.zoomInLink = zoomIn; │ │ │ │ + this.zoomOutLink = zoomOut; │ │ │ │ + return div │ │ │ │ }, │ │ │ │ - _addZoomBar: function(centered) { │ │ │ │ - var imgLocation = OpenLayers.Util.getImageLocation("slider.png"); │ │ │ │ - var id = this.id + "_" + this.map.id; │ │ │ │ - var minZoom = this.map.getMinZoom(); │ │ │ │ - var zoomsToEnd = this.map.getNumZoomLevels() - 1 - this.map.getZoom(); │ │ │ │ - var slider = OpenLayers.Util.createAlphaImageDiv(id, centered.add(-1, zoomsToEnd * this.zoomStopHeight), { │ │ │ │ - w: 20, │ │ │ │ - h: 9 │ │ │ │ - }, imgLocation, "absolute"); │ │ │ │ - slider.style.cursor = "move"; │ │ │ │ - this.slider = slider; │ │ │ │ - this.sliderEvents = new OpenLayers.Events(this, slider, null, true, { │ │ │ │ - includeXY: true │ │ │ │ - }); │ │ │ │ - this.sliderEvents.on({ │ │ │ │ - touchstart: this.zoomBarDown, │ │ │ │ - touchmove: this.zoomBarDrag, │ │ │ │ - touchend: this.zoomBarUp, │ │ │ │ - mousedown: this.zoomBarDown, │ │ │ │ - mousemove: this.zoomBarDrag, │ │ │ │ - mouseup: this.zoomBarUp │ │ │ │ - }); │ │ │ │ - var sz = { │ │ │ │ - w: this.zoomStopWidth, │ │ │ │ - h: this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom) │ │ │ │ - }; │ │ │ │ - var imgLocation = OpenLayers.Util.getImageLocation("zoombar.png"); │ │ │ │ - var div = null; │ │ │ │ - if (OpenLayers.Util.alphaHack()) { │ │ │ │ - var id = this.id + "_" + this.map.id; │ │ │ │ - div = OpenLayers.Util.createAlphaImageDiv(id, centered, { │ │ │ │ - w: sz.w, │ │ │ │ - h: this.zoomStopHeight │ │ │ │ - }, imgLocation, "absolute", null, "crop"); │ │ │ │ - div.style.height = sz.h + "px" │ │ │ │ - } else { │ │ │ │ - div = OpenLayers.Util.createDiv("OpenLayers_Control_PanZoomBar_Zoombar" + this.map.id, centered, sz, imgLocation) │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - div.style.cursor = "pointer"; │ │ │ │ - div.className = "olButton"; │ │ │ │ - this.zoombarDiv = div; │ │ │ │ - this.div.appendChild(div); │ │ │ │ - this.startTop = parseInt(div.style.top); │ │ │ │ - this.div.appendChild(slider); │ │ │ │ - this.map.events.register("zoomend", this, this.moveZoomBar); │ │ │ │ - centered = centered.add(0, this.zoomStopHeight * (this.map.getNumZoomLevels() - minZoom)); │ │ │ │ - return centered │ │ │ │ - }, │ │ │ │ - _removeZoomBar: function() { │ │ │ │ - this.sliderEvents.un({ │ │ │ │ - touchstart: this.zoomBarDown, │ │ │ │ - touchmove: this.zoomBarDrag, │ │ │ │ - touchend: this.zoomBarUp, │ │ │ │ - mousedown: this.zoomBarDown, │ │ │ │ - mousemove: this.zoomBarDrag, │ │ │ │ - mouseup: this.zoomBarUp │ │ │ │ - }); │ │ │ │ - this.sliderEvents.destroy(); │ │ │ │ - this.div.removeChild(this.zoombarDiv); │ │ │ │ - this.zoombarDiv = null; │ │ │ │ - this.div.removeChild(this.slider); │ │ │ │ - this.slider = null; │ │ │ │ - this.map.events.unregister("zoomend", this, this.moveZoomBar) │ │ │ │ - }, │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this, arguments); │ │ │ │ - if (evt.buttonElement === this.zoombarDiv) { │ │ │ │ - var levels = evt.buttonXY.y / this.zoomStopHeight; │ │ │ │ - if (this.forceFixedZoomLevel || !this.map.fractionalZoom) { │ │ │ │ - levels = Math.floor(levels) │ │ │ │ - } │ │ │ │ - var zoom = this.map.getNumZoomLevels() - 1 - levels; │ │ │ │ - zoom = Math.min(Math.max(zoom, 0), this.map.getNumZoomLevels() - 1); │ │ │ │ - this.map.zoomTo(zoom) │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - }, │ │ │ │ - passEventToSlider: function(evt) { │ │ │ │ - this.sliderEvents.handleBrowserEvent(evt) │ │ │ │ - }, │ │ │ │ - zoomBarDown: function(evt) { │ │ │ │ - if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ - return │ │ │ │ + OpenLayers.Element.addClass(zoomOut, "olButton"); │ │ │ │ + return { │ │ │ │ + zoomIn: zoomIn, │ │ │ │ + zoomOut: zoomOut │ │ │ │ } │ │ │ │ - this.map.events.on({ │ │ │ │ - touchmove: this.passEventToSlider, │ │ │ │ - mousemove: this.passEventToSlider, │ │ │ │ - mouseup: this.passEventToSlider, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.mouseDragStart = evt.xy.clone(); │ │ │ │ - this.zoomStart = evt.xy.clone(); │ │ │ │ - this.div.style.cursor = "move"; │ │ │ │ - this.zoombarDiv.offsets = null; │ │ │ │ - OpenLayers.Event.stop(evt) │ │ │ │ }, │ │ │ │ - zoomBarDrag: function(evt) { │ │ │ │ - if (this.mouseDragStart != null) { │ │ │ │ - var deltaY = this.mouseDragStart.y - evt.xy.y; │ │ │ │ - var offsets = OpenLayers.Util.pagePosition(this.zoombarDiv); │ │ │ │ - if (evt.clientY - offsets[1] > 0 && evt.clientY - offsets[1] < parseInt(this.zoombarDiv.style.height) - 2) { │ │ │ │ - var newTop = parseInt(this.slider.style.top) - deltaY; │ │ │ │ - this.slider.style.top = newTop + "px"; │ │ │ │ - this.mouseDragStart = evt.xy.clone() │ │ │ │ - } │ │ │ │ - this.deltaY = this.zoomStart.y - evt.xy.y; │ │ │ │ - OpenLayers.Event.stop(evt) │ │ │ │ + onZoomClick: function(evt) { │ │ │ │ + var button = evt.buttonElement; │ │ │ │ + if (button === this.zoomInLink) { │ │ │ │ + this.map.zoomIn() │ │ │ │ + } else if (button === this.zoomOutLink) { │ │ │ │ + this.map.zoomOut() │ │ │ │ } │ │ │ │ }, │ │ │ │ - zoomBarUp: function(evt) { │ │ │ │ - if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - if (this.mouseDragStart) { │ │ │ │ - this.div.style.cursor = ""; │ │ │ │ - this.map.events.un({ │ │ │ │ - touchmove: this.passEventToSlider, │ │ │ │ - mouseup: this.passEventToSlider, │ │ │ │ - mousemove: this.passEventToSlider, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - var zoomLevel = this.map.zoom; │ │ │ │ - if (!this.forceFixedZoomLevel && this.map.fractionalZoom) { │ │ │ │ - zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ - zoomLevel = Math.min(Math.max(zoomLevel, 0), this.map.getNumZoomLevels() - 1) │ │ │ │ - } else { │ │ │ │ - zoomLevel += this.deltaY / this.zoomStopHeight; │ │ │ │ - zoomLevel = Math.max(Math.round(zoomLevel), 0) │ │ │ │ - } │ │ │ │ - this.map.zoomTo(zoomLevel); │ │ │ │ - this.mouseDragStart = null; │ │ │ │ - this.zoomStart = null; │ │ │ │ - this.deltaY = 0; │ │ │ │ - OpenLayers.Event.stop(evt) │ │ │ │ + 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) │ │ │ │ }, │ │ │ │ - moveZoomBar: function() { │ │ │ │ - var newTop = (this.map.getNumZoomLevels() - 1 - this.map.getZoom()) * this.zoomStopHeight + this.startTop + 1; │ │ │ │ - this.slider.style.top = newTop + "px" │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.PanZoomBar" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Zoom" │ │ │ │ }); │ │ │ │ -OpenLayers.Handler.Pinch = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - started: false, │ │ │ │ - stopDown: false, │ │ │ │ - pinching: false, │ │ │ │ - last: null, │ │ │ │ - start: null, │ │ │ │ - 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) { │ │ │ │ - return false │ │ │ │ - } else { │ │ │ │ - this.started = false; │ │ │ │ - this.start = null; │ │ │ │ - this.last = null │ │ │ │ - } │ │ │ │ - OpenLayers.Event.preventDefault(evt); │ │ │ │ - return 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; │ │ │ │ - OpenLayers.Event.stop(evt) │ │ │ │ - } else if (this.started) { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - return true │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ +OpenLayers.Control.UTFGrid = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + autoActivate: true, │ │ │ │ + layers: null, │ │ │ │ + defaultHandlerOptions: { │ │ │ │ + delay: 300, │ │ │ │ + pixelTolerance: 4, │ │ │ │ + stopMove: false, │ │ │ │ + single: true, │ │ │ │ + double: false, │ │ │ │ + stopSingle: false, │ │ │ │ + stopDouble: false │ │ │ │ }, │ │ │ │ - activate: function() { │ │ │ │ - var activated = false; │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.pinching = false; │ │ │ │ - activated = true │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ + handlerMode: "click", │ │ │ │ + setHandler: function(hm) { │ │ │ │ + this.handlerMode = hm; │ │ │ │ + this.resetHandler() │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + resetHandler: function() { │ │ │ │ + if (this.handler) { │ │ │ │ + this.handler.deactivate(); │ │ │ │ + this.handler.destroy(); │ │ │ │ + this.handler = null │ │ │ │ } │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - 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)) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ + if (this.handlerMode == "hover") { │ │ │ │ + this.handler = new OpenLayers.Handler.Hover(this, { │ │ │ │ + pause: this.handleEvent, │ │ │ │ + move: this.reset │ │ │ │ + }, this.handlerOptions) │ │ │ │ + } else if (this.handlerMode == "click") { │ │ │ │ + this.handler = new OpenLayers.Handler.Click(this, { │ │ │ │ + click: this.handleEvent │ │ │ │ + }, this.handlerOptions) │ │ │ │ + } else if (this.handlerMode == "move") { │ │ │ │ + this.handler = new OpenLayers.Handler.Hover(this, { │ │ │ │ + pause: this.handleEvent, │ │ │ │ + move: this.handleEvent │ │ │ │ + }, this.handlerOptions) │ │ │ │ + } │ │ │ │ + if (this.handler) { │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Pinch" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ - pinchOrigin: null, │ │ │ │ - currentCenter: null, │ │ │ │ - autoActivate: true, │ │ │ │ - preserveCenter: false, │ │ │ │ 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) │ │ │ │ - }, │ │ │ │ - pinchStart: function(evt, pinchData) { │ │ │ │ - var xy = this.preserveCenter ? this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; │ │ │ │ - this.pinchOrigin = xy; │ │ │ │ - this.currentCenter = xy │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ + options = options || {}; │ │ │ │ + options.handlerOptions = options.handlerOptions || this.defaultHandlerOptions; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.resetHandler() │ │ │ │ }, │ │ │ │ - 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); │ │ │ │ - this.map.div.clientWidth = this.map.div.clientWidth; │ │ │ │ - this.map.setCenter(location, zoom) │ │ │ │ + handleEvent: function(evt) { │ │ │ │ + if (evt == null) { │ │ │ │ + this.reset(); │ │ │ │ + return │ │ │ │ + } │ │ │ │ + var lonLat = this.map.getLonLatFromPixel(evt.xy); │ │ │ │ + if (!lonLat) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + var layers = this.findLayers(); │ │ │ │ + if (layers.length > 0) { │ │ │ │ + var infoLookup = {}; │ │ │ │ + var layer, idx; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + layer = layers[i]; │ │ │ │ + idx = OpenLayers.Util.indexOf(this.map.layers, layer); │ │ │ │ + infoLookup[idx] = layer.getFeatureInfo(lonLat) │ │ │ │ + } │ │ │ │ + this.callback(infoLookup, lonLat, evt.xy) │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.PinchZoom" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.ZoomIn = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ - trigger: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.zoomIn() │ │ │ │ + callback: function(infoLookup) {}, │ │ │ │ + reset: function(evt) { │ │ │ │ + this.callback(null) │ │ │ │ + }, │ │ │ │ + findLayers: function() { │ │ │ │ + var candidates = this.layers || this.map.layers; │ │ │ │ + var layers = []; │ │ │ │ + var layer; │ │ │ │ + for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ + layer = candidates[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.UTFGrid) { │ │ │ │ + layers.push(layer) │ │ │ │ + } │ │ │ │ } │ │ │ │ + return layers │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomIn" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.UTFGrid" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.ScaleLine = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - maxWidth: 100, │ │ │ │ - topOutUnits: "km", │ │ │ │ - topInUnits: "m", │ │ │ │ - bottomOutUnits: "mi", │ │ │ │ - bottomInUnits: "ft", │ │ │ │ - eTop: null, │ │ │ │ - eBottom: null, │ │ │ │ - geodesic: false, │ │ │ │ +OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ + out: false, │ │ │ │ + keyMask: null, │ │ │ │ + alwaysZoom: false, │ │ │ │ + zoomOnClick: true, │ │ │ │ draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (!this.eTop) { │ │ │ │ - this.eTop = document.createElement("div"); │ │ │ │ - this.eTop.className = this.displayClass + "Top"; │ │ │ │ - var theLen = this.topInUnits.length; │ │ │ │ - this.div.appendChild(this.eTop); │ │ │ │ - if (this.topOutUnits == "" || this.topInUnits == "") { │ │ │ │ - this.eTop.style.visibility = "hidden" │ │ │ │ + this.handler = new OpenLayers.Handler.Box(this, { │ │ │ │ + done: this.zoomBox │ │ │ │ + }, { │ │ │ │ + keyMask: this.keyMask │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + zoomBox: function(position) { │ │ │ │ + if (position instanceof OpenLayers.Bounds) { │ │ │ │ + var bounds, targetCenterPx = position.getCenterPixel(); │ │ │ │ + if (!this.out) { │ │ │ │ + var minXY = this.map.getLonLatFromPixel({ │ │ │ │ + x: position.left, │ │ │ │ + y: position.bottom │ │ │ │ + }); │ │ │ │ + var maxXY = this.map.getLonLatFromPixel({ │ │ │ │ + x: position.right, │ │ │ │ + y: position.top │ │ │ │ + }); │ │ │ │ + bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat, maxXY.lon, maxXY.lat) │ │ │ │ } else { │ │ │ │ - this.eTop.style.visibility = "visible" │ │ │ │ + var pixWidth = position.right - position.left; │ │ │ │ + var pixHeight = position.bottom - position.top; │ │ │ │ + var zoomFactor = Math.min(this.map.size.h / pixHeight, this.map.size.w / pixWidth); │ │ │ │ + var extent = this.map.getExtent(); │ │ │ │ + var center = this.map.getLonLatFromPixel(targetCenterPx); │ │ │ │ + var xmin = center.lon - extent.getWidth() / 2 * zoomFactor; │ │ │ │ + var xmax = center.lon + extent.getWidth() / 2 * zoomFactor; │ │ │ │ + var ymin = center.lat - extent.getHeight() / 2 * zoomFactor; │ │ │ │ + var ymax = center.lat + extent.getHeight() / 2 * zoomFactor; │ │ │ │ + bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax) │ │ │ │ } │ │ │ │ - this.eBottom = document.createElement("div"); │ │ │ │ - this.eBottom.className = this.displayClass + "Bottom"; │ │ │ │ - this.div.appendChild(this.eBottom); │ │ │ │ - if (this.bottomOutUnits == "" || this.bottomInUnits == "") { │ │ │ │ - this.eBottom.style.visibility = "hidden" │ │ │ │ + var lastZoom = this.map.getZoom(), │ │ │ │ + size = this.map.getSize(), │ │ │ │ + centerPx = { │ │ │ │ + x: size.w / 2, │ │ │ │ + y: size.h / 2 │ │ │ │ + }, │ │ │ │ + zoom = this.map.getZoomForExtent(bounds), │ │ │ │ + oldRes = this.map.getResolution(), │ │ │ │ + newRes = this.map.getResolutionForZoom(zoom); │ │ │ │ + if (oldRes == newRes) { │ │ │ │ + this.map.setCenter(this.map.getLonLatFromPixel(targetCenterPx)) │ │ │ │ } else { │ │ │ │ - this.eBottom.style.visibility = "visible" │ │ │ │ + var zoomOriginPx = { │ │ │ │ + x: (oldRes * targetCenterPx.x - newRes * centerPx.x) / (oldRes - newRes), │ │ │ │ + y: (oldRes * targetCenterPx.y - newRes * centerPx.y) / (oldRes - newRes) │ │ │ │ + }; │ │ │ │ + this.map.zoomTo(zoom, zoomOriginPx) │ │ │ │ + } │ │ │ │ + if (lastZoom == this.map.getZoom() && this.alwaysZoom == true) { │ │ │ │ + this.map.zoomTo(lastZoom + (this.out ? -1 : 1)) │ │ │ │ + } │ │ │ │ + } else if (this.zoomOnClick) { │ │ │ │ + if (!this.out) { │ │ │ │ + this.map.zoomTo(this.map.getZoom() + 1, position) │ │ │ │ + } else { │ │ │ │ + this.map.zoomTo(this.map.getZoom() - 1, position) │ │ │ │ } │ │ │ │ } │ │ │ │ - this.map.events.register("moveend", this, this.update); │ │ │ │ - this.update(); │ │ │ │ - return this.div │ │ │ │ }, │ │ │ │ - getBarLen: function(maxLen) { │ │ │ │ - var digits = parseInt(Math.log(maxLen) / Math.log(10)); │ │ │ │ - var pow10 = Math.pow(10, digits); │ │ │ │ - var firstChar = parseInt(maxLen / pow10); │ │ │ │ - var barLen; │ │ │ │ - if (firstChar > 5) { │ │ │ │ - barLen = 5 │ │ │ │ - } else if (firstChar > 2) { │ │ │ │ - barLen = 2 │ │ │ │ - } else { │ │ │ │ - barLen = 1 │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomBox" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + dragPan: null, │ │ │ │ + dragPanOptions: null, │ │ │ │ + pinchZoom: null, │ │ │ │ + pinchZoomOptions: null, │ │ │ │ + documentDrag: false, │ │ │ │ + zoomBox: null, │ │ │ │ + zoomBoxEnabled: true, │ │ │ │ + zoomWheelEnabled: true, │ │ │ │ + mouseWheelOptions: null, │ │ │ │ + handleRightClicks: false, │ │ │ │ + zoomBoxKeyMask: OpenLayers.Handler.MOD_SHIFT, │ │ │ │ + autoActivate: true, │ │ │ │ + initialize: function(options) { │ │ │ │ + this.handlers = {}; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + if (this.dragPan) { │ │ │ │ + this.dragPan.destroy() │ │ │ │ } │ │ │ │ - return barLen * pow10 │ │ │ │ + this.dragPan = null; │ │ │ │ + if (this.zoomBox) { │ │ │ │ + this.zoomBox.destroy() │ │ │ │ + } │ │ │ │ + this.zoomBox = null; │ │ │ │ + if (this.pinchZoom) { │ │ │ │ + this.pinchZoom.destroy() │ │ │ │ + } │ │ │ │ + this.pinchZoom = null; │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ - update: function() { │ │ │ │ - var res = this.map.getResolution(); │ │ │ │ - if (!res) { │ │ │ │ - return │ │ │ │ + activate: function() { │ │ │ │ + this.dragPan.activate(); │ │ │ │ + if (this.zoomWheelEnabled) { │ │ │ │ + this.handlers.wheel.activate() │ │ │ │ } │ │ │ │ - var curMapUnits = this.map.getUnits(); │ │ │ │ - var inches = OpenLayers.INCHES_PER_UNIT; │ │ │ │ - var maxSizeData = this.maxWidth * res * inches[curMapUnits]; │ │ │ │ - var geodesicRatio = 1; │ │ │ │ - if (this.geodesic === true) { │ │ │ │ - var maxSizeGeodesic = (this.map.getGeodesicPixelSize().w || 1e-6) * this.maxWidth; │ │ │ │ - var maxSizeKilometers = maxSizeData / inches["km"]; │ │ │ │ - geodesicRatio = maxSizeGeodesic / maxSizeKilometers; │ │ │ │ - maxSizeData *= geodesicRatio │ │ │ │ + this.handlers.click.activate(); │ │ │ │ + if (this.zoomBoxEnabled) { │ │ │ │ + this.zoomBox.activate() │ │ │ │ } │ │ │ │ - var topUnits; │ │ │ │ - var bottomUnits; │ │ │ │ - if (maxSizeData > 1e5) { │ │ │ │ - topUnits = this.topOutUnits; │ │ │ │ - bottomUnits = this.bottomOutUnits │ │ │ │ - } else { │ │ │ │ - topUnits = this.topInUnits; │ │ │ │ - bottomUnits = this.bottomInUnits │ │ │ │ + if (this.pinchZoom) { │ │ │ │ + this.pinchZoom.activate() │ │ │ │ } │ │ │ │ - var topMax = maxSizeData / inches[topUnits]; │ │ │ │ - var bottomMax = maxSizeData / inches[bottomUnits]; │ │ │ │ - var topRounded = this.getBarLen(topMax); │ │ │ │ - var bottomRounded = this.getBarLen(bottomMax); │ │ │ │ - topMax = topRounded / inches[curMapUnits] * inches[topUnits]; │ │ │ │ - bottomMax = bottomRounded / inches[curMapUnits] * inches[bottomUnits]; │ │ │ │ - var topPx = topMax / res / geodesicRatio; │ │ │ │ - var bottomPx = bottomMax / res / geodesicRatio; │ │ │ │ - if (this.eBottom.style.visibility == "visible") { │ │ │ │ - this.eBottom.style.width = Math.round(bottomPx) + "px"; │ │ │ │ - this.eBottom.innerHTML = bottomRounded + " " + bottomUnits │ │ │ │ + return OpenLayers.Control.prototype.activate.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (this.pinchZoom) { │ │ │ │ + this.pinchZoom.deactivate() │ │ │ │ } │ │ │ │ - if (this.eTop.style.visibility == "visible") { │ │ │ │ - this.eTop.style.width = Math.round(topPx) + "px"; │ │ │ │ - this.eTop.innerHTML = topRounded + " " + topUnits │ │ │ │ + this.zoomBox.deactivate(); │ │ │ │ + this.dragPan.deactivate(); │ │ │ │ + this.handlers.click.deactivate(); │ │ │ │ + this.handlers.wheel.deactivate(); │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + draw: function() { │ │ │ │ + if (this.handleRightClicks) { │ │ │ │ + this.map.viewPortDiv.oncontextmenu = OpenLayers.Function.False │ │ │ │ + } │ │ │ │ + var clickCallbacks = { │ │ │ │ + click: this.defaultClick, │ │ │ │ + dblclick: this.defaultDblClick, │ │ │ │ + dblrightclick: this.defaultDblRightClick │ │ │ │ + }; │ │ │ │ + var clickOptions = { │ │ │ │ + double: true, │ │ │ │ + stopDouble: true │ │ │ │ + }; │ │ │ │ + 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.zoomBox = new OpenLayers.Control.ZoomBox({ │ │ │ │ + map: this.map, │ │ │ │ + keyMask: this.zoomBoxKeyMask │ │ │ │ + }); │ │ │ │ + this.dragPan.draw(); │ │ │ │ + this.zoomBox.draw(); │ │ │ │ + var wheelOptions = this.map.fractionalZoom ? {} : { │ │ │ │ + cumulative: false, │ │ │ │ + interval: 50, │ │ │ │ + maxDelta: 6 │ │ │ │ + }; │ │ │ │ + this.handlers.wheel = new OpenLayers.Handler.MouseWheel(this, { │ │ │ │ + up: this.wheelUp, │ │ │ │ + down: this.wheelDown │ │ │ │ + }, OpenLayers.Util.extend(wheelOptions, this.mouseWheelOptions)); │ │ │ │ + if (OpenLayers.Control.PinchZoom) { │ │ │ │ + this.pinchZoom = new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({ │ │ │ │ + map: this.map │ │ │ │ + }, this.pinchZoomOptions)) │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ScaleLine" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - delay: 500, │ │ │ │ - pixelTolerance: null, │ │ │ │ - stopMove: false, │ │ │ │ - px: null, │ │ │ │ - timerId: null, │ │ │ │ - mousemove: function(evt) { │ │ │ │ - if (this.passesTolerance(evt.xy)) { │ │ │ │ - this.clearTimer(); │ │ │ │ - this.callback("move", [evt]); │ │ │ │ - this.px = evt.xy; │ │ │ │ - evt = OpenLayers.Util.extend({}, evt); │ │ │ │ - this.timerId = window.setTimeout(OpenLayers.Function.bind(this.delayedCall, this, evt), this.delay) │ │ │ │ + defaultClick: function(evt) { │ │ │ │ + if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ + this.map.zoomOut() │ │ │ │ } │ │ │ │ - return !this.stopMove │ │ │ │ }, │ │ │ │ - mouseout: function(evt) { │ │ │ │ - if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ - this.clearTimer(); │ │ │ │ - this.callback("move", [evt]) │ │ │ │ + defaultDblClick: function(evt) { │ │ │ │ + this.map.zoomTo(this.map.zoom + 1, evt.xy) │ │ │ │ + }, │ │ │ │ + defaultDblRightClick: function(evt) { │ │ │ │ + this.map.zoomTo(this.map.zoom - 1, evt.xy) │ │ │ │ + }, │ │ │ │ + wheelChange: function(evt, deltaZ) { │ │ │ │ + if (!this.map.fractionalZoom) { │ │ │ │ + deltaZ = Math.round(deltaZ) │ │ │ │ } │ │ │ │ - return true │ │ │ │ + var currentZoom = this.map.getZoom(), │ │ │ │ + newZoom = currentZoom + deltaZ; │ │ │ │ + newZoom = Math.max(newZoom, 0); │ │ │ │ + newZoom = Math.min(newZoom, this.map.getNumZoomLevels()); │ │ │ │ + if (newZoom === currentZoom) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + this.map.zoomTo(newZoom, evt.xy) │ │ │ │ }, │ │ │ │ - passesTolerance: function(px) { │ │ │ │ - var passes = true; │ │ │ │ - if (this.pixelTolerance && this.px) { │ │ │ │ - var dpx = Math.sqrt(Math.pow(this.px.x - px.x, 2) + Math.pow(this.px.y - px.y, 2)); │ │ │ │ - if (dpx < this.pixelTolerance) { │ │ │ │ - passes = false │ │ │ │ - } │ │ │ │ + wheelUp: function(evt, delta) { │ │ │ │ + this.wheelChange(evt, delta || 1) │ │ │ │ + }, │ │ │ │ + wheelDown: function(evt, delta) { │ │ │ │ + this.wheelChange(evt, delta || -1) │ │ │ │ + }, │ │ │ │ + disableZoomBox: function() { │ │ │ │ + this.zoomBoxEnabled = false; │ │ │ │ + this.zoomBox.deactivate() │ │ │ │ + }, │ │ │ │ + enableZoomBox: function() { │ │ │ │ + this.zoomBoxEnabled = true; │ │ │ │ + if (this.active) { │ │ │ │ + this.zoomBox.activate() │ │ │ │ } │ │ │ │ - return passes │ │ │ │ }, │ │ │ │ - clearTimer: function() { │ │ │ │ - if (this.timerId != null) { │ │ │ │ - window.clearTimeout(this.timerId); │ │ │ │ - this.timerId = null │ │ │ │ + disableZoomWheel: function() { │ │ │ │ + this.zoomWheelEnabled = false; │ │ │ │ + this.handlers.wheel.deactivate() │ │ │ │ + }, │ │ │ │ + enableZoomWheel: function() { │ │ │ │ + this.zoomWheelEnabled = true; │ │ │ │ + if (this.active) { │ │ │ │ + this.handlers.wheel.activate() │ │ │ │ } │ │ │ │ }, │ │ │ │ - delayedCall: function(evt) { │ │ │ │ - this.callback("pause", [evt]) │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Navigation" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.NavToolbar = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ + this.addControls([new OpenLayers.Control.Navigation, new OpenLayers.Control.ZoomBox]) │ │ │ │ }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = false; │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - this.clearTimer(); │ │ │ │ - deactivated = true │ │ │ │ + draw: function() { │ │ │ │ + var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments); │ │ │ │ + if (this.defaultControl === null) { │ │ │ │ + this.defaultControl = this.controls[0] │ │ │ │ } │ │ │ │ - return deactivated │ │ │ │ + return div │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Hover" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.NavToolbar" │ │ │ │ }); │ │ │ │ OpenLayers.Format.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ layerIdentifier: "_layer", │ │ │ │ featureIdentifier: "_feature", │ │ │ │ regExes: { │ │ │ │ trimSpace: /^\s*|\s*$/g, │ │ │ │ removeSpace: /\s*/g, │ │ │ │ @@ -26209,380 +30487,138 @@ │ │ │ │ delete this._requestCount; │ │ │ │ delete this._numRequests │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.WMSGetFeatureInfo" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - element: null, │ │ │ │ - ovmap: null, │ │ │ │ - size: { │ │ │ │ - w: 180, │ │ │ │ - h: 90 │ │ │ │ - }, │ │ │ │ - layers: null, │ │ │ │ - minRectSize: 15, │ │ │ │ - minRectDisplayClass: "RectReplacement", │ │ │ │ - minRatio: 8, │ │ │ │ - maxRatio: 32, │ │ │ │ - mapOptions: null, │ │ │ │ - autoPan: false, │ │ │ │ - handlers: null, │ │ │ │ - resolutionFactor: 1, │ │ │ │ - maximized: false, │ │ │ │ - maximizeTitle: "", │ │ │ │ - minimizeTitle: "", │ │ │ │ - initialize: function(options) { │ │ │ │ - this.layers = []; │ │ │ │ - this.handlers = {}; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (!this.mapDiv) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - if (this.handlers.click) { │ │ │ │ - this.handlers.click.destroy() │ │ │ │ - } │ │ │ │ - if (this.handlers.drag) { │ │ │ │ - this.handlers.drag.destroy() │ │ │ │ - } │ │ │ │ - this.ovmap && this.ovmap.viewPortDiv.removeChild(this.extentRectangle); │ │ │ │ - this.extentRectangle = null; │ │ │ │ - if (this.rectEvents) { │ │ │ │ - this.rectEvents.destroy(); │ │ │ │ - this.rectEvents = null │ │ │ │ - } │ │ │ │ - if (this.ovmap) { │ │ │ │ - this.ovmap.destroy(); │ │ │ │ - this.ovmap = null │ │ │ │ - } │ │ │ │ - this.element.removeChild(this.mapDiv); │ │ │ │ - this.mapDiv = null; │ │ │ │ - this.div.removeChild(this.element); │ │ │ │ - this.element = null; │ │ │ │ - if (this.maximizeDiv) { │ │ │ │ - this.div.removeChild(this.maximizeDiv); │ │ │ │ - this.maximizeDiv = null │ │ │ │ - } │ │ │ │ - if (this.minimizeDiv) { │ │ │ │ - this.div.removeChild(this.minimizeDiv); │ │ │ │ - this.minimizeDiv = null │ │ │ │ - } │ │ │ │ - this.map.events.un({ │ │ │ │ - buttonclick: this.onButtonClick, │ │ │ │ - moveend: this.update, │ │ │ │ - changebaselayer: this.baseLayerDraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (this.layers.length === 0) { │ │ │ │ - if (this.map.baseLayer) { │ │ │ │ - var layer = this.map.baseLayer.clone(); │ │ │ │ - this.layers = [layer] │ │ │ │ - } else { │ │ │ │ - this.map.events.register("changebaselayer", this, this.baseLayerDraw); │ │ │ │ - return this.div │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.element = document.createElement("div"); │ │ │ │ - this.element.className = this.displayClass + "Element"; │ │ │ │ - this.element.style.display = "none"; │ │ │ │ - this.mapDiv = document.createElement("div"); │ │ │ │ - this.mapDiv.style.width = this.size.w + "px"; │ │ │ │ - this.mapDiv.style.height = this.size.h + "px"; │ │ │ │ - this.mapDiv.style.position = "relative"; │ │ │ │ - this.mapDiv.style.overflow = "hidden"; │ │ │ │ - this.mapDiv.id = OpenLayers.Util.createUniqueID("overviewMap"); │ │ │ │ - this.extentRectangle = document.createElement("div"); │ │ │ │ - this.extentRectangle.style.position = "absolute"; │ │ │ │ - this.extentRectangle.style.zIndex = 1e3; │ │ │ │ - this.extentRectangle.className = this.displayClass + "ExtentRectangle"; │ │ │ │ - this.element.appendChild(this.mapDiv); │ │ │ │ - this.div.appendChild(this.element); │ │ │ │ - if (!this.outsideViewport) { │ │ │ │ - this.div.className += " " + this.displayClass + "Container"; │ │ │ │ - var img = OpenLayers.Util.getImageLocation("layer-switcher-maximize.png"); │ │ │ │ - this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(this.displayClass + "MaximizeButton", null, null, img, "absolute"); │ │ │ │ - this.maximizeDiv.style.display = "none"; │ │ │ │ - this.maximizeDiv.className = this.displayClass + "MaximizeButton olButton"; │ │ │ │ - if (this.maximizeTitle) { │ │ │ │ - this.maximizeDiv.title = this.maximizeTitle │ │ │ │ - } │ │ │ │ - this.div.appendChild(this.maximizeDiv); │ │ │ │ - var img = OpenLayers.Util.getImageLocation("layer-switcher-minimize.png"); │ │ │ │ - this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_minimizeDiv", null, null, img, "absolute"); │ │ │ │ - this.minimizeDiv.style.display = "none"; │ │ │ │ - this.minimizeDiv.className = this.displayClass + "MinimizeButton olButton"; │ │ │ │ - if (this.minimizeTitle) { │ │ │ │ - this.minimizeDiv.title = this.minimizeTitle │ │ │ │ - } │ │ │ │ - this.div.appendChild(this.minimizeDiv); │ │ │ │ - this.minimizeControl() │ │ │ │ - } else { │ │ │ │ - this.element.style.display = "" │ │ │ │ - } │ │ │ │ - if (this.map.getExtent()) { │ │ │ │ - this.update() │ │ │ │ - } │ │ │ │ - this.map.events.on({ │ │ │ │ - buttonclick: this.onButtonClick, │ │ │ │ - moveend: this.update, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - if (this.maximized) { │ │ │ │ - this.maximizeControl() │ │ │ │ - } │ │ │ │ - return this.div │ │ │ │ - }, │ │ │ │ - baseLayerDraw: function() { │ │ │ │ - this.draw(); │ │ │ │ - this.map.events.unregister("changebaselayer", this, this.baseLayerDraw) │ │ │ │ - }, │ │ │ │ - rectDrag: function(px) { │ │ │ │ - var deltaX = this.handlers.drag.last.x - px.x; │ │ │ │ - var deltaY = this.handlers.drag.last.y - px.y; │ │ │ │ - if (deltaX != 0 || deltaY != 0) { │ │ │ │ - var rectTop = this.rectPxBounds.top; │ │ │ │ - var rectLeft = this.rectPxBounds.left; │ │ │ │ - var rectHeight = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ - var rectWidth = this.rectPxBounds.getWidth(); │ │ │ │ - var newTop = Math.max(0, rectTop - deltaY); │ │ │ │ - newTop = Math.min(newTop, this.ovmap.size.h - this.hComp - rectHeight); │ │ │ │ - var newLeft = Math.max(0, rectLeft - deltaX); │ │ │ │ - newLeft = Math.min(newLeft, this.ovmap.size.w - this.wComp - rectWidth); │ │ │ │ - this.setRectPxBounds(new OpenLayers.Bounds(newLeft, newTop + rectHeight, newLeft + rectWidth, newTop)) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - mapDivClick: function(evt) { │ │ │ │ - var pxCenter = this.rectPxBounds.getCenterPixel(); │ │ │ │ - var deltaX = evt.xy.x - pxCenter.x; │ │ │ │ - var deltaY = evt.xy.y - pxCenter.y; │ │ │ │ - var top = this.rectPxBounds.top; │ │ │ │ - var left = this.rectPxBounds.left; │ │ │ │ - var height = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ - var width = this.rectPxBounds.getWidth(); │ │ │ │ - var newTop = Math.max(0, top + deltaY); │ │ │ │ - newTop = Math.min(newTop, this.ovmap.size.h - height); │ │ │ │ - var newLeft = Math.max(0, left + deltaX); │ │ │ │ - newLeft = Math.min(newLeft, this.ovmap.size.w - width); │ │ │ │ - this.setRectPxBounds(new OpenLayers.Bounds(newLeft, newTop + height, newLeft + width, newTop)); │ │ │ │ - this.updateMapToRect() │ │ │ │ - }, │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - if (evt.buttonElement === this.minimizeDiv) { │ │ │ │ - this.minimizeControl() │ │ │ │ - } else if (evt.buttonElement === this.maximizeDiv) { │ │ │ │ - this.maximizeControl() │ │ │ │ +OpenLayers.Control.DragFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + geometryTypes: null, │ │ │ │ + onStart: function(feature, pixel) {}, │ │ │ │ + onDrag: function(feature, pixel) {}, │ │ │ │ + onComplete: function(feature, pixel) {}, │ │ │ │ + onEnter: function(feature) {}, │ │ │ │ + onLeave: function(feature) {}, │ │ │ │ + documentDrag: false, │ │ │ │ + layer: null, │ │ │ │ + feature: null, │ │ │ │ + dragCallbacks: {}, │ │ │ │ + featureCallbacks: {}, │ │ │ │ + lastPixel: null, │ │ │ │ + initialize: function(layer, options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.layer = layer; │ │ │ │ + this.handlers = { │ │ │ │ + drag: new OpenLayers.Handler.Drag(this, OpenLayers.Util.extend({ │ │ │ │ + down: this.downFeature, │ │ │ │ + move: this.moveFeature, │ │ │ │ + up: this.upFeature, │ │ │ │ + out: this.cancel, │ │ │ │ + done: this.doneDragging │ │ │ │ + }, this.dragCallbacks), { │ │ │ │ + documentDrag: this.documentDrag │ │ │ │ + }), │ │ │ │ + feature: new OpenLayers.Handler.Feature(this, this.layer, OpenLayers.Util.extend({ │ │ │ │ + click: this.clickFeature, │ │ │ │ + clickout: this.clickoutFeature, │ │ │ │ + over: this.overFeature, │ │ │ │ + out: this.outFeature │ │ │ │ + }, this.featureCallbacks), { │ │ │ │ + geometryTypes: this.geometryTypes │ │ │ │ + }) │ │ │ │ } │ │ │ │ }, │ │ │ │ - maximizeControl: function(e) { │ │ │ │ - this.element.style.display = ""; │ │ │ │ - this.showToggle(false); │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e) │ │ │ │ + clickFeature: function(feature) { │ │ │ │ + if (this.handlers.feature.touch && !this.over && this.overFeature(feature)) { │ │ │ │ + this.handlers.drag.dragstart(this.handlers.feature.evt); │ │ │ │ + this.handlers.drag.stopDown = false │ │ │ │ } │ │ │ │ }, │ │ │ │ - minimizeControl: function(e) { │ │ │ │ - this.element.style.display = "none"; │ │ │ │ - this.showToggle(true); │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e) │ │ │ │ + clickoutFeature: function(feature) { │ │ │ │ + if (this.handlers.feature.touch && this.over) { │ │ │ │ + this.outFeature(feature); │ │ │ │ + this.handlers.drag.stopDown = true │ │ │ │ } │ │ │ │ }, │ │ │ │ - showToggle: function(minimize) { │ │ │ │ - if (this.maximizeDiv) { │ │ │ │ - this.maximizeDiv.style.display = minimize ? "" : "none" │ │ │ │ - } │ │ │ │ - if (this.minimizeDiv) { │ │ │ │ - this.minimizeDiv.style.display = minimize ? "none" : "" │ │ │ │ - } │ │ │ │ + destroy: function() { │ │ │ │ + this.layer = null; │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, []) │ │ │ │ }, │ │ │ │ - update: function() { │ │ │ │ - if (this.ovmap == null) { │ │ │ │ - this.createMap() │ │ │ │ - } │ │ │ │ - if (this.autoPan || !this.isSuitableOverview()) { │ │ │ │ - this.updateOverview() │ │ │ │ - } │ │ │ │ - this.updateRectToMap() │ │ │ │ + activate: function() { │ │ │ │ + return this.handlers.feature.activate() && OpenLayers.Control.prototype.activate.apply(this, arguments) │ │ │ │ }, │ │ │ │ - isSuitableOverview: function() { │ │ │ │ - var mapExtent = this.map.getExtent(); │ │ │ │ - var maxExtent = this.map.getMaxExtent(); │ │ │ │ - var testExtent = new OpenLayers.Bounds(Math.max(mapExtent.left, maxExtent.left), Math.max(mapExtent.bottom, maxExtent.bottom), Math.min(mapExtent.right, maxExtent.right), Math.min(mapExtent.top, maxExtent.top)); │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - testExtent = testExtent.transform(this.map.getProjectionObject(), this.ovmap.getProjectionObject()) │ │ │ │ - } │ │ │ │ - var resRatio = this.ovmap.getResolution() / this.map.getResolution(); │ │ │ │ - return resRatio > this.minRatio && resRatio <= this.maxRatio && this.ovmap.getExtent().containsBounds(testExtent) │ │ │ │ + deactivate: function() { │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ + this.handlers.feature.deactivate(); │ │ │ │ + this.feature = null; │ │ │ │ + this.dragging = false; │ │ │ │ + this.lastPixel = null; │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ }, │ │ │ │ - updateOverview: function() { │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ - var targetRes = this.ovmap.getResolution(); │ │ │ │ - var resRatio = targetRes / mapRes; │ │ │ │ - if (resRatio > this.maxRatio) { │ │ │ │ - targetRes = this.minRatio * mapRes │ │ │ │ - } else if (resRatio <= this.minRatio) { │ │ │ │ - targetRes = this.maxRatio * mapRes │ │ │ │ - } │ │ │ │ - var center; │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - center = this.map.center.clone(); │ │ │ │ - center.transform(this.map.getProjectionObject(), this.ovmap.getProjectionObject()) │ │ │ │ + overFeature: function(feature) { │ │ │ │ + var activated = false; │ │ │ │ + if (!this.handlers.drag.dragging) { │ │ │ │ + this.feature = feature; │ │ │ │ + this.handlers.drag.activate(); │ │ │ │ + activated = true; │ │ │ │ + this.over = true; │ │ │ │ + OpenLayers.Element.addClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ + this.onEnter(feature) │ │ │ │ } else { │ │ │ │ - center = this.map.center │ │ │ │ - } │ │ │ │ - this.ovmap.setCenter(center, this.ovmap.getZoomForResolution(targetRes * this.resolutionFactor)); │ │ │ │ - this.updateRectToMap() │ │ │ │ - }, │ │ │ │ - createMap: function() { │ │ │ │ - var options = OpenLayers.Util.extend({ │ │ │ │ - controls: [], │ │ │ │ - maxResolution: "auto", │ │ │ │ - fallThrough: false │ │ │ │ - }, this.mapOptions); │ │ │ │ - this.ovmap = new OpenLayers.Map(this.mapDiv, options); │ │ │ │ - this.ovmap.viewPortDiv.appendChild(this.extentRectangle); │ │ │ │ - OpenLayers.Event.stopObserving(window, "unload", this.ovmap.unloadDestroy); │ │ │ │ - this.ovmap.addLayers(this.layers); │ │ │ │ - this.ovmap.zoomToMaxExtent(); │ │ │ │ - this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-left-width")) + parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-right-width")); │ │ │ │ - this.wComp = this.wComp ? this.wComp : 2; │ │ │ │ - this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-top-width")) + parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-bottom-width")); │ │ │ │ - this.hComp = this.hComp ? this.hComp : 2; │ │ │ │ - this.handlers.drag = new OpenLayers.Handler.Drag(this, { │ │ │ │ - move: this.rectDrag, │ │ │ │ - done: this.updateMapToRect │ │ │ │ - }, { │ │ │ │ - map: this.ovmap │ │ │ │ - }); │ │ │ │ - this.handlers.click = new OpenLayers.Handler.Click(this, { │ │ │ │ - click: this.mapDivClick │ │ │ │ - }, { │ │ │ │ - single: true, │ │ │ │ - double: false, │ │ │ │ - stopSingle: true, │ │ │ │ - stopDouble: true, │ │ │ │ - pixelTolerance: 1, │ │ │ │ - map: this.ovmap │ │ │ │ - }); │ │ │ │ - this.handlers.click.activate(); │ │ │ │ - this.rectEvents = new OpenLayers.Events(this, this.extentRectangle, null, true); │ │ │ │ - this.rectEvents.register("mouseover", this, function(e) { │ │ │ │ - if (!this.handlers.drag.active && !this.map.dragging) { │ │ │ │ - this.handlers.drag.activate() │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.rectEvents.register("mouseout", this, function(e) { │ │ │ │ - if (!this.handlers.drag.dragging) { │ │ │ │ - this.handlers.drag.deactivate() │ │ │ │ + if (this.feature.id == feature.id) { │ │ │ │ + this.over = true │ │ │ │ + } else { │ │ │ │ + this.over = false │ │ │ │ } │ │ │ │ - }); │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - var sourceUnits = this.map.getProjectionObject().getUnits() || this.map.units || this.map.baseLayer.units; │ │ │ │ - var targetUnits = this.ovmap.getProjectionObject().getUnits() || this.ovmap.units || this.ovmap.baseLayer.units; │ │ │ │ - this.resolutionFactor = sourceUnits && targetUnits ? OpenLayers.INCHES_PER_UNIT[sourceUnits] / OpenLayers.INCHES_PER_UNIT[targetUnits] : 1 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - updateRectToMap: function() { │ │ │ │ - var bounds; │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - bounds = this.map.getExtent().transform(this.map.getProjectionObject(), this.ovmap.getProjectionObject()) │ │ │ │ - } else { │ │ │ │ - bounds = this.map.getExtent() │ │ │ │ - } │ │ │ │ - var pxBounds = this.getRectBoundsFromMapBounds(bounds); │ │ │ │ - if (pxBounds) { │ │ │ │ - this.setRectPxBounds(pxBounds) │ │ │ │ } │ │ │ │ + return activated │ │ │ │ }, │ │ │ │ - updateMapToRect: function() { │ │ │ │ - var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds); │ │ │ │ - if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ - lonLatBounds = lonLatBounds.transform(this.ovmap.getProjectionObject(), this.map.getProjectionObject()) │ │ │ │ - } │ │ │ │ - this.map.panTo(lonLatBounds.getCenterLonLat()) │ │ │ │ + downFeature: function(pixel) { │ │ │ │ + this.lastPixel = pixel; │ │ │ │ + this.onStart(this.feature, pixel) │ │ │ │ }, │ │ │ │ - setRectPxBounds: function(pxBounds) { │ │ │ │ - var top = Math.max(pxBounds.top, 0); │ │ │ │ - var left = Math.max(pxBounds.left, 0); │ │ │ │ - var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()), this.ovmap.size.h - this.hComp); │ │ │ │ - var right = Math.min(pxBounds.left + pxBounds.getWidth(), this.ovmap.size.w - this.wComp); │ │ │ │ - var width = Math.max(right - left, 0); │ │ │ │ - var height = Math.max(bottom - top, 0); │ │ │ │ - if (width < this.minRectSize || height < this.minRectSize) { │ │ │ │ - this.extentRectangle.className = this.displayClass + this.minRectDisplayClass; │ │ │ │ - var rLeft = left + width / 2 - this.minRectSize / 2; │ │ │ │ - var rTop = top + height / 2 - this.minRectSize / 2; │ │ │ │ - this.extentRectangle.style.top = Math.round(rTop) + "px"; │ │ │ │ - this.extentRectangle.style.left = Math.round(rLeft) + "px"; │ │ │ │ - this.extentRectangle.style.height = this.minRectSize + "px"; │ │ │ │ - this.extentRectangle.style.width = this.minRectSize + "px" │ │ │ │ - } else { │ │ │ │ - this.extentRectangle.className = this.displayClass + "ExtentRectangle"; │ │ │ │ - this.extentRectangle.style.top = Math.round(top) + "px"; │ │ │ │ - this.extentRectangle.style.left = Math.round(left) + "px"; │ │ │ │ - this.extentRectangle.style.height = Math.round(height) + "px"; │ │ │ │ - this.extentRectangle.style.width = Math.round(width) + "px" │ │ │ │ - } │ │ │ │ - this.rectPxBounds = new OpenLayers.Bounds(Math.round(left), Math.round(bottom), Math.round(right), Math.round(top)) │ │ │ │ + moveFeature: function(pixel) { │ │ │ │ + var res = this.map.getResolution(); │ │ │ │ + this.feature.geometry.move(res * (pixel.x - this.lastPixel.x), res * (this.lastPixel.y - pixel.y)); │ │ │ │ + this.layer.drawFeature(this.feature); │ │ │ │ + this.lastPixel = pixel; │ │ │ │ + this.onDrag(this.feature, pixel) │ │ │ │ }, │ │ │ │ - getRectBoundsFromMapBounds: function(lonLatBounds) { │ │ │ │ - var leftBottomPx = this.getOverviewPxFromLonLat({ │ │ │ │ - lon: lonLatBounds.left, │ │ │ │ - lat: lonLatBounds.bottom │ │ │ │ - }); │ │ │ │ - var rightTopPx = this.getOverviewPxFromLonLat({ │ │ │ │ - lon: lonLatBounds.right, │ │ │ │ - lat: lonLatBounds.top │ │ │ │ - }); │ │ │ │ - var bounds = null; │ │ │ │ - if (leftBottomPx && rightTopPx) { │ │ │ │ - bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y, rightTopPx.x, rightTopPx.y) │ │ │ │ + upFeature: function(pixel) { │ │ │ │ + if (!this.over) { │ │ │ │ + this.handlers.drag.deactivate() │ │ │ │ } │ │ │ │ - return bounds │ │ │ │ - }, │ │ │ │ - getMapBoundsFromRectBounds: function(pxBounds) { │ │ │ │ - var leftBottomLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ - x: pxBounds.left, │ │ │ │ - y: pxBounds.bottom │ │ │ │ - }); │ │ │ │ - var rightTopLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ - x: pxBounds.right, │ │ │ │ - y: pxBounds.top │ │ │ │ - }); │ │ │ │ - return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat, rightTopLonLat.lon, rightTopLonLat.lat) │ │ │ │ }, │ │ │ │ - getLonLatFromOverviewPx: function(overviewMapPx) { │ │ │ │ - var size = this.ovmap.size; │ │ │ │ - var res = this.ovmap.getResolution(); │ │ │ │ - var center = this.ovmap.getExtent().getCenterLonLat(); │ │ │ │ - var deltaX = overviewMapPx.x - size.w / 2; │ │ │ │ - var deltaY = overviewMapPx.y - size.h / 2; │ │ │ │ - return { │ │ │ │ - lon: center.lon + deltaX * res, │ │ │ │ - lat: center.lat - deltaY * res │ │ │ │ - } │ │ │ │ + doneDragging: function(pixel) { │ │ │ │ + this.onComplete(this.feature, pixel) │ │ │ │ }, │ │ │ │ - getOverviewPxFromLonLat: function(lonlat) { │ │ │ │ - var res = this.ovmap.getResolution(); │ │ │ │ - var extent = this.ovmap.getExtent(); │ │ │ │ - if (extent) { │ │ │ │ - return { │ │ │ │ - x: Math.round(1 / res * (lonlat.lon - extent.left)), │ │ │ │ - y: Math.round(1 / res * (extent.top - lonlat.lat)) │ │ │ │ + outFeature: function(feature) { │ │ │ │ + if (!this.handlers.drag.dragging) { │ │ │ │ + this.over = false; │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, this.displayClass + "Over"); │ │ │ │ + this.onLeave(feature); │ │ │ │ + this.feature = null │ │ │ │ + } else { │ │ │ │ + if (this.feature.id == feature.id) { │ │ │ │ + this.over = false │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.OverviewMap" │ │ │ │ + cancel: function() { │ │ │ │ + this.handlers.drag.deactivate(); │ │ │ │ + this.over = false │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + this.handlers.drag.setMap(map); │ │ │ │ + this.handlers.feature.setMap(map); │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.DragFeature" │ │ │ │ }); │ │ │ │ OpenLayers.Control.Scale = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ element: null, │ │ │ │ geodesic: false, │ │ │ │ initialize: function(element, options) { │ │ │ │ OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ this.element = OpenLayers.Util.getElement(element) │ │ │ │ @@ -26621,1105 +30657,425 @@ │ │ │ │ } │ │ │ │ this.element.innerHTML = OpenLayers.i18n("Scale = 1 : ${scaleDenom}", { │ │ │ │ scaleDenom: scale │ │ │ │ }) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.Scale" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.Graticule = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ + pinchOrigin: null, │ │ │ │ + currentCenter: null, │ │ │ │ autoActivate: true, │ │ │ │ - intervals: [45, 30, 20, 10, 5, 2, 1, .5, .2, .1, .05, .01, .005, .002, .001], │ │ │ │ - displayInLayerSwitcher: true, │ │ │ │ - visible: true, │ │ │ │ - numPoints: 50, │ │ │ │ - targetSize: 200, │ │ │ │ - layerName: null, │ │ │ │ - labelled: true, │ │ │ │ - labelFormat: "dm", │ │ │ │ - lineSymbolizer: { │ │ │ │ - strokeColor: "#333", │ │ │ │ - strokeWidth: 1, │ │ │ │ - strokeOpacity: .5 │ │ │ │ + preserveCenter: false, │ │ │ │ + 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) │ │ │ │ }, │ │ │ │ - labelSymbolizer: {}, │ │ │ │ - gratLayer: null, │ │ │ │ + pinchStart: function(evt, pinchData) { │ │ │ │ + var xy = this.preserveCenter ? this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; │ │ │ │ + this.pinchOrigin = xy; │ │ │ │ + this.currentCenter = xy │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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); │ │ │ │ + this.map.div.clientWidth = this.map.div.clientWidth; │ │ │ │ + this.map.setCenter(location, zoom) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.PinchZoom" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.TouchNavigation = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + dragPan: null, │ │ │ │ + dragPanOptions: null, │ │ │ │ + pinchZoom: null, │ │ │ │ + pinchZoomOptions: null, │ │ │ │ + clickHandlerOptions: null, │ │ │ │ + documentDrag: false, │ │ │ │ + autoActivate: true, │ │ │ │ initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.layerName = options.layerName || OpenLayers.i18n("Graticule"); │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.labelSymbolizer.stroke = false; │ │ │ │ - this.labelSymbolizer.fill = false; │ │ │ │ - this.labelSymbolizer.label = "${label}"; │ │ │ │ - this.labelSymbolizer.labelAlign = "${labelAlign}"; │ │ │ │ - this.labelSymbolizer.labelXOffset = "${xOffset}"; │ │ │ │ - this.labelSymbolizer.labelYOffset = "${yOffset}" │ │ │ │ + this.handlers = {}; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments) │ │ │ │ }, │ │ │ │ destroy: function() { │ │ │ │ this.deactivate(); │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ - if (this.gratLayer) { │ │ │ │ - this.gratLayer.destroy(); │ │ │ │ - this.gratLayer = null │ │ │ │ + if (this.dragPan) { │ │ │ │ + this.dragPan.destroy() │ │ │ │ } │ │ │ │ - }, │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (!this.gratLayer) { │ │ │ │ - var gratStyle = new OpenLayers.Style({}, { │ │ │ │ - rules: [new OpenLayers.Rule({ │ │ │ │ - symbolizer: { │ │ │ │ - Point: this.labelSymbolizer, │ │ │ │ - Line: this.lineSymbolizer │ │ │ │ - } │ │ │ │ - })] │ │ │ │ - }); │ │ │ │ - this.gratLayer = new OpenLayers.Layer.Vector(this.layerName, { │ │ │ │ - styleMap: new OpenLayers.StyleMap({ │ │ │ │ - default: gratStyle │ │ │ │ - }), │ │ │ │ - visibility: this.visible, │ │ │ │ - displayInLayerSwitcher: this.displayInLayerSwitcher │ │ │ │ - }) │ │ │ │ + this.dragPan = null; │ │ │ │ + if (this.pinchZoom) { │ │ │ │ + this.pinchZoom.destroy(); │ │ │ │ + delete this.pinchZoom │ │ │ │ } │ │ │ │ - return this.div │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ activate: function() { │ │ │ │ if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.map.addLayer(this.gratLayer); │ │ │ │ - this.map.events.register("moveend", this, this.update); │ │ │ │ - this.update(); │ │ │ │ + this.dragPan.activate(); │ │ │ │ + this.handlers.click.activate(); │ │ │ │ + this.pinchZoom.activate(); │ │ │ │ return true │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ } │ │ │ │ + return false │ │ │ │ }, │ │ │ │ deactivate: function() { │ │ │ │ if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - this.map.events.unregister("moveend", this, this.update); │ │ │ │ - this.map.removeLayer(this.gratLayer); │ │ │ │ + this.dragPan.deactivate(); │ │ │ │ + this.handlers.click.deactivate(); │ │ │ │ + this.pinchZoom.deactivate(); │ │ │ │ return true │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - update: function() { │ │ │ │ - var mapBounds = this.map.getExtent(); │ │ │ │ - if (!mapBounds) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - this.gratLayer.destroyFeatures(); │ │ │ │ - var llProj = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ - var mapProj = this.map.getProjectionObject(); │ │ │ │ - var mapRes = this.map.getResolution(); │ │ │ │ - if (mapProj.proj && mapProj.proj.projName == "longlat") { │ │ │ │ - this.numPoints = 1 │ │ │ │ - } │ │ │ │ - var mapCenter = this.map.getCenter(); │ │ │ │ - var mapCenterLL = new OpenLayers.Pixel(mapCenter.lon, mapCenter.lat); │ │ │ │ - OpenLayers.Projection.transform(mapCenterLL, mapProj, llProj); │ │ │ │ - var testSq = this.targetSize * mapRes; │ │ │ │ - testSq *= testSq; │ │ │ │ - var llInterval; │ │ │ │ - for (var i = 0; i < this.intervals.length; ++i) { │ │ │ │ - llInterval = this.intervals[i]; │ │ │ │ - var delta = llInterval / 2; │ │ │ │ - var p1 = mapCenterLL.offset({ │ │ │ │ - x: -delta, │ │ │ │ - y: -delta │ │ │ │ - }); │ │ │ │ - var p2 = mapCenterLL.offset({ │ │ │ │ - x: delta, │ │ │ │ - y: delta │ │ │ │ - }); │ │ │ │ - OpenLayers.Projection.transform(p1, llProj, mapProj); │ │ │ │ - OpenLayers.Projection.transform(p2, llProj, mapProj); │ │ │ │ - var distSq = (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y); │ │ │ │ - if (distSq <= testSq) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - mapCenterLL.x = Math.floor(mapCenterLL.x / llInterval) * llInterval; │ │ │ │ - mapCenterLL.y = Math.floor(mapCenterLL.y / llInterval) * llInterval; │ │ │ │ - var iter = 0; │ │ │ │ - var centerLonPoints = [mapCenterLL.clone()]; │ │ │ │ - var newPoint = mapCenterLL.clone(); │ │ │ │ - var mapXY; │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: 0, │ │ │ │ - y: llInterval │ │ │ │ - }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLonPoints.unshift(newPoint) │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ - newPoint = mapCenterLL.clone(); │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: 0, │ │ │ │ - y: -llInterval │ │ │ │ - }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLonPoints.push(newPoint) │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ - iter = 0; │ │ │ │ - var centerLatPoints = [mapCenterLL.clone()]; │ │ │ │ - newPoint = mapCenterLL.clone(); │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: -llInterval, │ │ │ │ - y: 0 │ │ │ │ - }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLatPoints.unshift(newPoint) │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ - newPoint = mapCenterLL.clone(); │ │ │ │ - do { │ │ │ │ - newPoint = newPoint.offset({ │ │ │ │ - x: llInterval, │ │ │ │ - y: 0 │ │ │ │ - }); │ │ │ │ - mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ - centerLatPoints.push(newPoint) │ │ │ │ - } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ - var lines = []; │ │ │ │ - for (var i = 0; i < centerLatPoints.length; ++i) { │ │ │ │ - var lon = centerLatPoints[i].x; │ │ │ │ - var pointList = []; │ │ │ │ - var labelPoint = null; │ │ │ │ - var latEnd = Math.min(centerLonPoints[0].y, 90); │ │ │ │ - var latStart = Math.max(centerLonPoints[centerLonPoints.length - 1].y, -90); │ │ │ │ - var latDelta = (latEnd - latStart) / this.numPoints; │ │ │ │ - var lat = latStart; │ │ │ │ - for (var j = 0; j <= this.numPoints; ++j) { │ │ │ │ - var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ - gridPoint.transform(llProj, mapProj); │ │ │ │ - pointList.push(gridPoint); │ │ │ │ - lat += latDelta; │ │ │ │ - if (gridPoint.y >= mapBounds.bottom && !labelPoint) { │ │ │ │ - labelPoint = gridPoint │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.labelled) { │ │ │ │ - var labelPos = new OpenLayers.Geometry.Point(labelPoint.x, mapBounds.bottom); │ │ │ │ - var labelAttrs = { │ │ │ │ - value: lon, │ │ │ │ - label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lon, "lon", this.labelFormat) : "", │ │ │ │ - labelAlign: "cb", │ │ │ │ - xOffset: 0, │ │ │ │ - yOffset: 2 │ │ │ │ - }; │ │ │ │ - this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)) │ │ │ │ - } │ │ │ │ - var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ - lines.push(new OpenLayers.Feature.Vector(geom)) │ │ │ │ - } │ │ │ │ - for (var j = 0; j < centerLonPoints.length; ++j) { │ │ │ │ - lat = centerLonPoints[j].y; │ │ │ │ - if (lat < -90 || lat > 90) { │ │ │ │ - continue │ │ │ │ - } │ │ │ │ - var pointList = []; │ │ │ │ - var lonStart = centerLatPoints[0].x; │ │ │ │ - var lonEnd = centerLatPoints[centerLatPoints.length - 1].x; │ │ │ │ - var lonDelta = (lonEnd - lonStart) / this.numPoints; │ │ │ │ - var lon = lonStart; │ │ │ │ - var labelPoint = null; │ │ │ │ - for (var i = 0; i <= this.numPoints; ++i) { │ │ │ │ - var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ - gridPoint.transform(llProj, mapProj); │ │ │ │ - pointList.push(gridPoint); │ │ │ │ - lon += lonDelta; │ │ │ │ - if (gridPoint.x < mapBounds.right) { │ │ │ │ - labelPoint = gridPoint │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.labelled) { │ │ │ │ - var labelPos = new OpenLayers.Geometry.Point(mapBounds.right, labelPoint.y); │ │ │ │ - var labelAttrs = { │ │ │ │ - value: lat, │ │ │ │ - label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lat, "lat", this.labelFormat) : "", │ │ │ │ - labelAlign: "rb", │ │ │ │ - xOffset: -2, │ │ │ │ - yOffset: 2 │ │ │ │ - }; │ │ │ │ - this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)) │ │ │ │ - } │ │ │ │ - var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ - lines.push(new OpenLayers.Feature.Vector(geom)) │ │ │ │ - } │ │ │ │ - this.gratLayer.addFeatures(lines) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Graticule" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - center: null, │ │ │ │ - zoom: null, │ │ │ │ - layers: null, │ │ │ │ - displayProjection: null, │ │ │ │ - getParameters: function(url) { │ │ │ │ - url = url || window.location.href; │ │ │ │ - var parameters = OpenLayers.Util.getParameters(url); │ │ │ │ - var index = url.indexOf("#"); │ │ │ │ - if (index > 0) { │ │ │ │ - url = "?" + url.substring(index + 1, url.length); │ │ │ │ - OpenLayers.Util.extend(parameters, OpenLayers.Util.getParameters(url)) │ │ │ │ - } │ │ │ │ - return parameters │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ - var control = this.map.controls[i]; │ │ │ │ - if (control != this && control.CLASS_NAME == "OpenLayers.Control.ArgParser") { │ │ │ │ - if (control.displayProjection != this.displayProjection) { │ │ │ │ - this.displayProjection = control.displayProjection │ │ │ │ - } │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (i == this.map.controls.length) { │ │ │ │ - var args = this.getParameters(); │ │ │ │ - if (args.layers) { │ │ │ │ - this.layers = args.layers; │ │ │ │ - this.map.events.register("addlayer", this, this.configureLayers); │ │ │ │ - this.configureLayers() │ │ │ │ - } │ │ │ │ - if (args.lat && args.lon) { │ │ │ │ - this.center = new OpenLayers.LonLat(parseFloat(args.lon), parseFloat(args.lat)); │ │ │ │ - if (args.zoom) { │ │ │ │ - this.zoom = parseFloat(args.zoom) │ │ │ │ - } │ │ │ │ - this.map.events.register("changebaselayer", this, this.setCenter); │ │ │ │ - this.setCenter() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setCenter: function() { │ │ │ │ - if (this.map.baseLayer) { │ │ │ │ - this.map.events.unregister("changebaselayer", this, this.setCenter); │ │ │ │ - if (this.displayProjection) { │ │ │ │ - this.center.transform(this.displayProjection, this.map.getProjectionObject()) │ │ │ │ - } │ │ │ │ - this.map.setCenter(this.center, this.zoom) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - configureLayers: function() { │ │ │ │ - if (this.layers.length == this.map.layers.length) { │ │ │ │ - this.map.events.unregister("addlayer", this, this.configureLayers); │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - var c = this.layers.charAt(i); │ │ │ │ - if (c == "B") { │ │ │ │ - this.map.setBaseLayer(layer) │ │ │ │ - } else if (c == "T" || c == "F") { │ │ │ │ - layer.setVisibility(c == "T") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ArgParser" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - argParserClass: OpenLayers.Control.ArgParser, │ │ │ │ - element: null, │ │ │ │ - anchor: false, │ │ │ │ - base: "", │ │ │ │ - displayProjection: null, │ │ │ │ - initialize: function(element, base, options) { │ │ │ │ - if (element !== null && typeof element == "object" && !OpenLayers.Util.isElement(element)) { │ │ │ │ - options = element; │ │ │ │ - this.base = document.location.href; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - if (this.element != null) { │ │ │ │ - this.element = OpenLayers.Util.getElement(this.element) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.element = OpenLayers.Util.getElement(element); │ │ │ │ - this.base = base || document.location.href │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.element && this.element.parentNode == this.div) { │ │ │ │ - this.div.removeChild(this.element); │ │ │ │ - this.element = null │ │ │ │ - } │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.unregister("moveend", this, this.updateLink) │ │ │ │ - } │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ - var control = this.map.controls[i]; │ │ │ │ - if (control.CLASS_NAME == this.argParserClass.CLASS_NAME) { │ │ │ │ - if (control.displayProjection != this.displayProjection) { │ │ │ │ - this.displayProjection = control.displayProjection │ │ │ │ - } │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (i == this.map.controls.length) { │ │ │ │ - this.map.addControl(new this.argParserClass({ │ │ │ │ - displayProjection: this.displayProjection │ │ │ │ - })) │ │ │ │ } │ │ │ │ + return false │ │ │ │ }, │ │ │ │ draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (!this.element && !this.anchor) { │ │ │ │ - this.element = document.createElement("a"); │ │ │ │ - this.element.innerHTML = OpenLayers.i18n("Permalink"); │ │ │ │ - this.element.href = ""; │ │ │ │ - this.div.appendChild(this.element) │ │ │ │ - } │ │ │ │ - this.map.events.on({ │ │ │ │ - moveend: this.updateLink, │ │ │ │ - changelayer: this.updateLink, │ │ │ │ - changebaselayer: this.updateLink, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.updateLink(); │ │ │ │ - return this.div │ │ │ │ + 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)) │ │ │ │ }, │ │ │ │ - updateLink: function() { │ │ │ │ - var separator = this.anchor ? "#" : "?"; │ │ │ │ - var href = this.base; │ │ │ │ - var anchor = null; │ │ │ │ - if (href.indexOf("#") != -1 && this.anchor == false) { │ │ │ │ - anchor = href.substring(href.indexOf("#"), href.length) │ │ │ │ - } │ │ │ │ - if (href.indexOf(separator) != -1) { │ │ │ │ - href = href.substring(0, href.indexOf(separator)) │ │ │ │ - } │ │ │ │ - var splits = href.split("#"); │ │ │ │ - href = splits[0] + separator + OpenLayers.Util.getParameterString(this.createParams()); │ │ │ │ - if (anchor) { │ │ │ │ - href += anchor │ │ │ │ - } │ │ │ │ - if (this.anchor && !this.element) { │ │ │ │ - window.location.href = href │ │ │ │ - } else { │ │ │ │ - this.element.href = href │ │ │ │ + defaultClick: function(evt) { │ │ │ │ + if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ + this.map.zoomOut() │ │ │ │ } │ │ │ │ }, │ │ │ │ - createParams: function(center, zoom, layers) { │ │ │ │ - center = center || this.map.getCenter(); │ │ │ │ - var params = OpenLayers.Util.getParameters(this.base); │ │ │ │ - if (center) { │ │ │ │ - params.zoom = zoom || this.map.getZoom(); │ │ │ │ - var lat = center.lat; │ │ │ │ - var lon = center.lon; │ │ │ │ - if (this.displayProjection) { │ │ │ │ - var mapPosition = OpenLayers.Projection.transform({ │ │ │ │ - x: lon, │ │ │ │ - y: lat │ │ │ │ - }, this.map.getProjectionObject(), this.displayProjection); │ │ │ │ - lon = mapPosition.x; │ │ │ │ - lat = mapPosition.y │ │ │ │ - } │ │ │ │ - params.lat = Math.round(lat * 1e5) / 1e5; │ │ │ │ - params.lon = Math.round(lon * 1e5) / 1e5; │ │ │ │ - layers = layers || this.map.layers; │ │ │ │ - params.layers = ""; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - var layer = layers[i]; │ │ │ │ - if (layer.isBaseLayer) { │ │ │ │ - params.layers += layer == this.map.baseLayer ? "B" : "0" │ │ │ │ - } else { │ │ │ │ - params.layers += layer.getVisibility() ? "T" : "F" │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return params │ │ │ │ + defaultDblClick: function(evt) { │ │ │ │ + this.map.zoomTo(this.map.zoom + 1, evt.xy) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Permalink" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.TouchNavigation" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + multipleKey: null, │ │ │ │ + toggleKey: null, │ │ │ │ + multiple: false, │ │ │ │ + clickout: true, │ │ │ │ + toggle: false, │ │ │ │ + hover: false, │ │ │ │ + highlightOnly: false, │ │ │ │ + box: false, │ │ │ │ + onBeforeSelect: function() {}, │ │ │ │ + onSelect: function() {}, │ │ │ │ + onUnselect: function() {}, │ │ │ │ + scope: null, │ │ │ │ + geometryTypes: null, │ │ │ │ + layer: null, │ │ │ │ + layers: null, │ │ │ │ callbacks: null, │ │ │ │ - displaySystem: "metric", │ │ │ │ - geodesic: false, │ │ │ │ - displaySystemUnits: { │ │ │ │ - geographic: ["dd"], │ │ │ │ - english: ["mi", "ft", "in"], │ │ │ │ - metric: ["km", "m"] │ │ │ │ - }, │ │ │ │ - partialDelay: 300, │ │ │ │ - delayedTrigger: null, │ │ │ │ - persist: false, │ │ │ │ - immediate: false, │ │ │ │ - initialize: function(handler, options) { │ │ │ │ + selectStyle: null, │ │ │ │ + renderIntent: "select", │ │ │ │ + handlers: null, │ │ │ │ + initialize: function(layers, options) { │ │ │ │ OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + if (this.scope === null) { │ │ │ │ + this.scope = this │ │ │ │ + } │ │ │ │ + this.initLayer(layers); │ │ │ │ var callbacks = { │ │ │ │ - done: this.measureComplete, │ │ │ │ - point: this.measurePartial │ │ │ │ + click: this.clickFeature, │ │ │ │ + clickout: this.clickoutFeature │ │ │ │ }; │ │ │ │ - if (this.immediate) { │ │ │ │ - callbacks.modify = this.measureImmediate │ │ │ │ + if (this.hover) { │ │ │ │ + callbacks.over = this.overFeature; │ │ │ │ + callbacks.out = this.outFeature │ │ │ │ } │ │ │ │ this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks); │ │ │ │ - this.handlerOptions = OpenLayers.Util.extend({ │ │ │ │ - persist: this.persist │ │ │ │ - }, this.handlerOptions); │ │ │ │ - this.handler = new handler(this, this.callbacks, this.handlerOptions) │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - this.cancelDelay(); │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - cancel: function() { │ │ │ │ - this.cancelDelay(); │ │ │ │ - this.handler.cancel() │ │ │ │ - }, │ │ │ │ - setImmediate: function(immediate) { │ │ │ │ - this.immediate = immediate; │ │ │ │ - if (this.immediate) { │ │ │ │ - this.callbacks.modify = this.measureImmediate │ │ │ │ - } else { │ │ │ │ - delete this.callbacks.modify │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - updateHandler: function(handler, options) { │ │ │ │ - var active = this.active; │ │ │ │ - if (active) { │ │ │ │ - this.deactivate() │ │ │ │ - } │ │ │ │ - this.handler = new handler(this, this.callbacks, options); │ │ │ │ - if (active) { │ │ │ │ - this.activate() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - measureComplete: function(geometry) { │ │ │ │ - this.cancelDelay(); │ │ │ │ - this.measure(geometry, "measure") │ │ │ │ - }, │ │ │ │ - measurePartial: function(point, geometry) { │ │ │ │ - this.cancelDelay(); │ │ │ │ - geometry = geometry.clone(); │ │ │ │ - if (this.handler.freehandMode(this.handler.evt)) { │ │ │ │ - this.measure(geometry, "measurepartial") │ │ │ │ - } else { │ │ │ │ - this.delayedTrigger = window.setTimeout(OpenLayers.Function.bind(function() { │ │ │ │ - this.delayedTrigger = null; │ │ │ │ - this.measure(geometry, "measurepartial") │ │ │ │ - }, this), this.partialDelay) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - measureImmediate: function(point, feature, drawing) { │ │ │ │ - if (drawing && !this.handler.freehandMode(this.handler.evt)) { │ │ │ │ - this.cancelDelay(); │ │ │ │ - this.measure(feature.geometry, "measurepartial") │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - cancelDelay: function() { │ │ │ │ - if (this.delayedTrigger !== null) { │ │ │ │ - window.clearTimeout(this.delayedTrigger); │ │ │ │ - this.delayedTrigger = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - measure: function(geometry, eventType) { │ │ │ │ - var stat, order; │ │ │ │ - if (geometry.CLASS_NAME.indexOf("LineString") > -1) { │ │ │ │ - stat = this.getBestLength(geometry); │ │ │ │ - order = 1 │ │ │ │ - } else { │ │ │ │ - stat = this.getBestArea(geometry); │ │ │ │ - order = 2 │ │ │ │ - } │ │ │ │ - this.events.triggerEvent(eventType, { │ │ │ │ - measure: stat[0], │ │ │ │ - units: stat[1], │ │ │ │ - order: order, │ │ │ │ - geometry: geometry │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - getBestArea: function(geometry) { │ │ │ │ - var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ - var unit, area; │ │ │ │ - for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ - unit = units[i]; │ │ │ │ - area = this.getArea(geometry, unit); │ │ │ │ - if (area > 1) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return [area, unit] │ │ │ │ - }, │ │ │ │ - getArea: function(geometry, units) { │ │ │ │ - var area, geomUnits; │ │ │ │ - if (this.geodesic) { │ │ │ │ - area = geometry.getGeodesicArea(this.map.getProjectionObject()); │ │ │ │ - geomUnits = "m" │ │ │ │ - } else { │ │ │ │ - area = geometry.getArea(); │ │ │ │ - geomUnits = this.map.getUnits() │ │ │ │ - } │ │ │ │ - var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ - if (inPerDisplayUnit) { │ │ │ │ - var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ - area *= Math.pow(inPerMapUnit / inPerDisplayUnit, 2) │ │ │ │ - } │ │ │ │ - return area │ │ │ │ - }, │ │ │ │ - getBestLength: function(geometry) { │ │ │ │ - var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ - var unit, length; │ │ │ │ - for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ - unit = units[i]; │ │ │ │ - length = this.getLength(geometry, unit); │ │ │ │ - if (length > 1) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ + 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" │ │ │ │ + }) │ │ │ │ } │ │ │ │ - return [length, unit] │ │ │ │ }, │ │ │ │ - getLength: function(geometry, units) { │ │ │ │ - var length, geomUnits; │ │ │ │ - if (this.geodesic) { │ │ │ │ - length = geometry.getGeodesicLength(this.map.getProjectionObject()); │ │ │ │ - geomUnits = "m" │ │ │ │ + initLayer: function(layers) { │ │ │ │ + if (OpenLayers.Util.isArray(layers)) { │ │ │ │ + this.layers = layers; │ │ │ │ + this.layer = new OpenLayers.Layer.Vector.RootContainer(this.id + "_container", { │ │ │ │ + layers: layers │ │ │ │ + }) │ │ │ │ } else { │ │ │ │ - length = geometry.getLength(); │ │ │ │ - geomUnits = this.map.getUnits() │ │ │ │ - } │ │ │ │ - var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ - if (inPerDisplayUnit) { │ │ │ │ - var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ - length *= inPerMapUnit / inPerDisplayUnit │ │ │ │ + this.layer = layers │ │ │ │ } │ │ │ │ - return length │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Measure" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - dragHandler: null, │ │ │ │ - boxDivClassName: "olHandlerBoxZoomBox", │ │ │ │ - boxOffsets: null, │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ - this.dragHandler = new OpenLayers.Handler.Drag(this, { │ │ │ │ - down: this.startBox, │ │ │ │ - move: this.moveBox, │ │ │ │ - out: this.removeBox, │ │ │ │ - up: this.endBox │ │ │ │ - }, { │ │ │ │ - keyMask: this.keyMask │ │ │ │ - }) │ │ │ │ }, │ │ │ │ destroy: function() { │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ - if (this.dragHandler) { │ │ │ │ - this.dragHandler.destroy(); │ │ │ │ - this.dragHandler = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Handler.prototype.setMap.apply(this, arguments); │ │ │ │ - if (this.dragHandler) { │ │ │ │ - this.dragHandler.setMap(map) │ │ │ │ + if (this.active && this.layers) { │ │ │ │ + this.map.removeLayer(this.layer) │ │ │ │ } │ │ │ │ - }, │ │ │ │ - startBox: function(xy) { │ │ │ │ - this.callback("start", []); │ │ │ │ - this.zoomBox = OpenLayers.Util.createDiv("zoomBox", { │ │ │ │ - x: -9999, │ │ │ │ - y: -9999 │ │ │ │ - }); │ │ │ │ - this.zoomBox.className = this.boxDivClassName; │ │ │ │ - this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1; │ │ │ │ - this.map.viewPortDiv.appendChild(this.zoomBox); │ │ │ │ - OpenLayers.Element.addClass(this.map.viewPortDiv, "olDrawBox") │ │ │ │ - }, │ │ │ │ - moveBox: function(xy) { │ │ │ │ - var startX = this.dragHandler.start.x; │ │ │ │ - var startY = this.dragHandler.start.y; │ │ │ │ - var deltaX = Math.abs(startX - xy.x); │ │ │ │ - var deltaY = Math.abs(startY - xy.y); │ │ │ │ - var offset = this.getBoxOffsets(); │ │ │ │ - this.zoomBox.style.width = deltaX + offset.width + 1 + "px"; │ │ │ │ - this.zoomBox.style.height = deltaY + offset.height + 1 + "px"; │ │ │ │ - this.zoomBox.style.left = (xy.x < startX ? startX - deltaX - offset.left : startX - offset.left) + "px"; │ │ │ │ - this.zoomBox.style.top = (xy.y < startY ? startY - deltaY - offset.top : startY - offset.top) + "px" │ │ │ │ - }, │ │ │ │ - endBox: function(end) { │ │ │ │ - var result; │ │ │ │ - if (Math.abs(this.dragHandler.start.x - end.x) > 5 || Math.abs(this.dragHandler.start.y - end.y) > 5) { │ │ │ │ - var start = this.dragHandler.start; │ │ │ │ - var top = Math.min(start.y, end.y); │ │ │ │ - var bottom = Math.max(start.y, end.y); │ │ │ │ - var left = Math.min(start.x, end.x); │ │ │ │ - var right = Math.max(start.x, end.x); │ │ │ │ - result = new OpenLayers.Bounds(left, bottom, right, top) │ │ │ │ - } else { │ │ │ │ - result = this.dragHandler.start.clone() │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + if (this.layers) { │ │ │ │ + this.layer.destroy() │ │ │ │ } │ │ │ │ - this.removeBox(); │ │ │ │ - this.callback("done", [result]) │ │ │ │ - }, │ │ │ │ - removeBox: function() { │ │ │ │ - this.map.viewPortDiv.removeChild(this.zoomBox); │ │ │ │ - this.zoomBox = null; │ │ │ │ - this.boxOffsets = null; │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olDrawBox") │ │ │ │ }, │ │ │ │ activate: function() { │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.dragHandler.activate(); │ │ │ │ - return true │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ + 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) │ │ │ │ }, │ │ │ │ deactivate: function() { │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - if (this.dragHandler.deactivate()) { │ │ │ │ - if (this.zoomBox) { │ │ │ │ - this.removeBox() │ │ │ │ - } │ │ │ │ + if (this.active) { │ │ │ │ + this.handlers.feature.deactivate(); │ │ │ │ + if (this.handlers.box) { │ │ │ │ + this.handlers.box.deactivate() │ │ │ │ + } │ │ │ │ + if (this.layers) { │ │ │ │ + this.map.removeLayer(this.layer) │ │ │ │ } │ │ │ │ - return true │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ } │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ }, │ │ │ │ - getBoxOffsets: function() { │ │ │ │ - if (!this.boxOffsets) { │ │ │ │ - var testDiv = document.createElement("div"); │ │ │ │ - testDiv.style.position = "absolute"; │ │ │ │ - testDiv.style.border = "1px solid black"; │ │ │ │ - testDiv.style.width = "3px"; │ │ │ │ - document.body.appendChild(testDiv); │ │ │ │ - var w3cBoxModel = testDiv.clientWidth == 3; │ │ │ │ - document.body.removeChild(testDiv); │ │ │ │ - var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-left-width")); │ │ │ │ - var right = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-right-width")); │ │ │ │ - var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-top-width")); │ │ │ │ - var bottom = parseInt(OpenLayers.Element.getStyle(this.zoomBox, "border-bottom-width")); │ │ │ │ - this.boxOffsets = { │ │ │ │ - left: left, │ │ │ │ - right: right, │ │ │ │ - top: top, │ │ │ │ - bottom: bottom, │ │ │ │ - width: w3cBoxModel === false ? left + right : 0, │ │ │ │ - height: w3cBoxModel === false ? top + bottom : 0 │ │ │ │ + unselectAll: function(options) { │ │ │ │ + var layers = this.layers || [this.layer], │ │ │ │ + layer, feature, l, numExcept; │ │ │ │ + for (l = 0; l < layers.length; ++l) { │ │ │ │ + layer = layers[l]; │ │ │ │ + numExcept = 0; │ │ │ │ + if (layer.selectedFeatures != null) { │ │ │ │ + while (layer.selectedFeatures.length > numExcept) { │ │ │ │ + feature = layer.selectedFeatures[numExcept]; │ │ │ │ + if (!options || options.except != feature) { │ │ │ │ + this.unselect(feature) │ │ │ │ + } else { │ │ │ │ + ++numExcept │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ - return this.boxOffsets │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Box" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ - out: false, │ │ │ │ - keyMask: null, │ │ │ │ - alwaysZoom: false, │ │ │ │ - zoomOnClick: true, │ │ │ │ - draw: function() { │ │ │ │ - this.handler = new OpenLayers.Handler.Box(this, { │ │ │ │ - done: this.zoomBox │ │ │ │ - }, { │ │ │ │ - keyMask: this.keyMask │ │ │ │ - }) │ │ │ │ }, │ │ │ │ - zoomBox: function(position) { │ │ │ │ - if (position instanceof OpenLayers.Bounds) { │ │ │ │ - var bounds, targetCenterPx = position.getCenterPixel(); │ │ │ │ - if (!this.out) { │ │ │ │ - var minXY = this.map.getLonLatFromPixel({ │ │ │ │ - x: position.left, │ │ │ │ - y: position.bottom │ │ │ │ - }); │ │ │ │ - var maxXY = this.map.getLonLatFromPixel({ │ │ │ │ - x: position.right, │ │ │ │ - y: position.top │ │ │ │ - }); │ │ │ │ - bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat, maxXY.lon, maxXY.lat) │ │ │ │ - } else { │ │ │ │ - var pixWidth = position.right - position.left; │ │ │ │ - var pixHeight = position.bottom - position.top; │ │ │ │ - var zoomFactor = Math.min(this.map.size.h / pixHeight, this.map.size.w / pixWidth); │ │ │ │ - var extent = this.map.getExtent(); │ │ │ │ - var center = this.map.getLonLatFromPixel(targetCenterPx); │ │ │ │ - var xmin = center.lon - extent.getWidth() / 2 * zoomFactor; │ │ │ │ - var xmax = center.lon + extent.getWidth() / 2 * zoomFactor; │ │ │ │ - var ymin = center.lat - extent.getHeight() / 2 * zoomFactor; │ │ │ │ - var ymax = center.lat + extent.getHeight() / 2 * zoomFactor; │ │ │ │ - bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax) │ │ │ │ - } │ │ │ │ - var lastZoom = this.map.getZoom(), │ │ │ │ - size = this.map.getSize(), │ │ │ │ - centerPx = { │ │ │ │ - x: size.w / 2, │ │ │ │ - y: size.h / 2 │ │ │ │ - }, │ │ │ │ - zoom = this.map.getZoomForExtent(bounds), │ │ │ │ - oldRes = this.map.getResolution(), │ │ │ │ - newRes = this.map.getResolutionForZoom(zoom); │ │ │ │ - if (oldRes == newRes) { │ │ │ │ - this.map.setCenter(this.map.getLonLatFromPixel(targetCenterPx)) │ │ │ │ - } else { │ │ │ │ - var zoomOriginPx = { │ │ │ │ - x: (oldRes * targetCenterPx.x - newRes * centerPx.x) / (oldRes - newRes), │ │ │ │ - y: (oldRes * targetCenterPx.y - newRes * centerPx.y) / (oldRes - newRes) │ │ │ │ - }; │ │ │ │ - this.map.zoomTo(zoom, zoomOriginPx) │ │ │ │ - } │ │ │ │ - if (lastZoom == this.map.getZoom() && this.alwaysZoom == true) { │ │ │ │ - this.map.zoomTo(lastZoom + (this.out ? -1 : 1)) │ │ │ │ - } │ │ │ │ - } else if (this.zoomOnClick) { │ │ │ │ - if (!this.out) { │ │ │ │ - this.map.zoomTo(this.map.getZoom() + 1, position) │ │ │ │ + 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 { │ │ │ │ - this.map.zoomTo(this.map.getZoom() - 1, position) │ │ │ │ + if (!this.multipleSelect()) { │ │ │ │ + this.unselectAll({ │ │ │ │ + except: feature │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + this.select(feature) │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomBox" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ - panned: false, │ │ │ │ - interval: 0, │ │ │ │ - documentDrag: false, │ │ │ │ - kinetic: null, │ │ │ │ - enableKinetic: true, │ │ │ │ - kineticInterval: 10, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ + multipleSelect: function() { │ │ │ │ + return this.multiple || this.handlers.feature.evt && this.handlers.feature.evt[this.multipleKey] │ │ │ │ }, │ │ │ │ - panMapStart: function() { │ │ │ │ - if (this.kinetic) { │ │ │ │ - this.kinetic.begin() │ │ │ │ - } │ │ │ │ + toggleSelect: function() { │ │ │ │ + return this.toggle || this.handlers.feature.evt && this.handlers.feature.evt[this.toggleKey] │ │ │ │ }, │ │ │ │ - panMap: function(xy) { │ │ │ │ - if (this.kinetic) { │ │ │ │ - this.kinetic.update(xy) │ │ │ │ + clickoutFeature: function(feature) { │ │ │ │ + if (!this.hover && this.clickout) { │ │ │ │ + this.unselectAll() │ │ │ │ } │ │ │ │ - this.panned = true; │ │ │ │ - this.map.pan(this.handler.last.x - xy.x, this.handler.last.y - xy.y, { │ │ │ │ - dragging: true, │ │ │ │ - animate: false │ │ │ │ - }) │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }) │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - this.panned = false │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.DragPan" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - wheelListener: null, │ │ │ │ - interval: 0, │ │ │ │ - maxDelta: Number.POSITIVE_INFINITY, │ │ │ │ - delta: 0, │ │ │ │ - cumulative: true, │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ - this.wheelListener = OpenLayers.Function.bindAsEventListener(this.onWheelEvent, this) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ - this.wheelListener = null │ │ │ │ - }, │ │ │ │ - onWheelEvent: function(e) { │ │ │ │ - if (!this.map || !this.checkModifiers(e)) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - var overScrollableDiv = false; │ │ │ │ - var allowScroll = false; │ │ │ │ - var overMapDiv = false; │ │ │ │ - var elem = OpenLayers.Event.element(e); │ │ │ │ - while (elem != null && !overMapDiv && !overScrollableDiv) { │ │ │ │ - if (!overScrollableDiv) { │ │ │ │ - try { │ │ │ │ - var overflow; │ │ │ │ - if (elem.currentStyle) { │ │ │ │ - overflow = elem.currentStyle["overflow"] │ │ │ │ - } else { │ │ │ │ - var style = document.defaultView.getComputedStyle(elem, null); │ │ │ │ - overflow = style.getPropertyValue("overflow") │ │ │ │ - } │ │ │ │ - overScrollableDiv = overflow && overflow == "auto" || overflow == "scroll" │ │ │ │ - } catch (err) {} │ │ │ │ - } │ │ │ │ - if (!allowScroll) { │ │ │ │ - allowScroll = OpenLayers.Element.hasClass(elem, "olScrollable"); │ │ │ │ - if (!allowScroll) { │ │ │ │ - for (var i = 0, len = this.map.layers.length; i < len; i++) { │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - if (elem == layer.div || elem == layer.pane) { │ │ │ │ - allowScroll = true; │ │ │ │ - break │ │ │ │ + outFeature: function(feature) { │ │ │ │ + if (this.hover) { │ │ │ │ + if (this.highlightOnly) { │ │ │ │ + if (feature._lastHighlighter == this.id) { │ │ │ │ + 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) │ │ │ │ } │ │ │ │ } │ │ │ │ - } │ │ │ │ - overMapDiv = elem == this.map.div; │ │ │ │ - elem = elem.parentNode │ │ │ │ - } │ │ │ │ - if (!overScrollableDiv && overMapDiv) { │ │ │ │ - if (allowScroll) { │ │ │ │ - var delta = 0; │ │ │ │ - if (e.wheelDelta) { │ │ │ │ - delta = e.wheelDelta; │ │ │ │ - if (delta % 160 === 0) { │ │ │ │ - delta = delta * .75 │ │ │ │ - } │ │ │ │ - delta = delta / 120 │ │ │ │ - } else if (e.detail) { │ │ │ │ - delta = -(e.detail / Math.abs(e.detail)) │ │ │ │ - } │ │ │ │ - this.delta += delta; │ │ │ │ - window.clearTimeout(this._timeoutId); │ │ │ │ - if (this.interval && Math.abs(this.delta) < this.maxDelta) { │ │ │ │ - var evt = OpenLayers.Util.extend({}, e); │ │ │ │ - this._timeoutId = window.setTimeout(OpenLayers.Function.bind(function() { │ │ │ │ - this.wheelZoom(evt) │ │ │ │ - }, this), this.interval) │ │ │ │ - } else { │ │ │ │ - this.wheelZoom(e) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - OpenLayers.Event.stop(e) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - wheelZoom: function(e) { │ │ │ │ - var delta = this.delta; │ │ │ │ - this.delta = 0; │ │ │ │ - if (delta) { │ │ │ │ - e.xy = this.map.events.getMousePosition(e); │ │ │ │ - if (delta < 0) { │ │ │ │ - this.callback("down", [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]) │ │ │ │ } else { │ │ │ │ - this.callback("up", [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]) │ │ │ │ + this.unselect(feature) │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ - activate: function(evt) { │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ - var wheelListener = this.wheelListener; │ │ │ │ - OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener); │ │ │ │ - OpenLayers.Event.observe(window, "mousewheel", wheelListener); │ │ │ │ - OpenLayers.Event.observe(document, "mousewheel", wheelListener); │ │ │ │ - return true │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ } │ │ │ │ }, │ │ │ │ - deactivate: function(evt) { │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - var wheelListener = this.wheelListener; │ │ │ │ - OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener); │ │ │ │ - OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener); │ │ │ │ - OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener); │ │ │ │ - return true │ │ │ │ + unhighlight: function(feature) { │ │ │ │ + var layer = feature.layer; │ │ │ │ + if (feature._prevHighlighter == undefined) { │ │ │ │ + delete feature._lastHighlighter │ │ │ │ + } else if (feature._prevHighlighter == this.id) { │ │ │ │ + delete feature._prevHighlighter │ │ │ │ } else { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.MouseWheel" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - dragPan: null, │ │ │ │ - dragPanOptions: null, │ │ │ │ - pinchZoom: null, │ │ │ │ - pinchZoomOptions: null, │ │ │ │ - documentDrag: false, │ │ │ │ - zoomBox: null, │ │ │ │ - zoomBoxEnabled: true, │ │ │ │ - zoomWheelEnabled: true, │ │ │ │ - mouseWheelOptions: null, │ │ │ │ - handleRightClicks: false, │ │ │ │ - zoomBoxKeyMask: OpenLayers.Handler.MOD_SHIFT, │ │ │ │ - autoActivate: true, │ │ │ │ - initialize: function(options) { │ │ │ │ - this.handlers = {}; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - if (this.dragPan) { │ │ │ │ - this.dragPan.destroy() │ │ │ │ - } │ │ │ │ - this.dragPan = null; │ │ │ │ - if (this.zoomBox) { │ │ │ │ - this.zoomBox.destroy() │ │ │ │ - } │ │ │ │ - this.zoomBox = null; │ │ │ │ - if (this.pinchZoom) { │ │ │ │ - this.pinchZoom.destroy() │ │ │ │ - } │ │ │ │ - this.pinchZoom = null; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - this.dragPan.activate(); │ │ │ │ - if (this.zoomWheelEnabled) { │ │ │ │ - this.handlers.wheel.activate() │ │ │ │ - } │ │ │ │ - this.handlers.click.activate(); │ │ │ │ - if (this.zoomBoxEnabled) { │ │ │ │ - this.zoomBox.activate() │ │ │ │ - } │ │ │ │ - if (this.pinchZoom) { │ │ │ │ - this.pinchZoom.activate() │ │ │ │ + feature._lastHighlighter = feature._prevHighlighter; │ │ │ │ + delete feature._prevHighlighter │ │ │ │ } │ │ │ │ - return OpenLayers.Control.prototype.activate.apply(this, arguments) │ │ │ │ + layer.drawFeature(feature, feature.style || feature.layer.style || "default"); │ │ │ │ + this.events.triggerEvent("featureunhighlighted", { │ │ │ │ + feature: feature │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (this.pinchZoom) { │ │ │ │ - this.pinchZoom.deactivate() │ │ │ │ + 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 (!this.handlers.feature.lastFeature) { │ │ │ │ + this.handlers.feature.lastFeature = layer.selectedFeatures[0] │ │ │ │ + } │ │ │ │ + layer.events.triggerEvent("featureselected", { │ │ │ │ + feature: feature │ │ │ │ + }); │ │ │ │ + this.onSelect.call(this.scope, feature) │ │ │ │ + } │ │ │ │ } │ │ │ │ - this.zoomBox.deactivate(); │ │ │ │ - this.dragPan.deactivate(); │ │ │ │ - this.handlers.click.deactivate(); │ │ │ │ - this.handlers.wheel.deactivate(); │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ }, │ │ │ │ - draw: function() { │ │ │ │ - if (this.handleRightClicks) { │ │ │ │ - this.map.viewPortDiv.oncontextmenu = OpenLayers.Function.False │ │ │ │ - } │ │ │ │ - var clickCallbacks = { │ │ │ │ - click: this.defaultClick, │ │ │ │ - dblclick: this.defaultDblClick, │ │ │ │ - dblrightclick: this.defaultDblRightClick │ │ │ │ - }; │ │ │ │ - var clickOptions = { │ │ │ │ - double: true, │ │ │ │ - stopDouble: true │ │ │ │ - }; │ │ │ │ - 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.zoomBox = new OpenLayers.Control.ZoomBox({ │ │ │ │ - map: this.map, │ │ │ │ - keyMask: this.zoomBoxKeyMask │ │ │ │ + unselect: function(feature) { │ │ │ │ + var layer = feature.layer; │ │ │ │ + this.unhighlight(feature); │ │ │ │ + OpenLayers.Util.removeItem(layer.selectedFeatures, feature); │ │ │ │ + layer.events.triggerEvent("featureunselected", { │ │ │ │ + feature: feature │ │ │ │ }); │ │ │ │ - this.dragPan.draw(); │ │ │ │ - this.zoomBox.draw(); │ │ │ │ - var wheelOptions = this.map.fractionalZoom ? {} : { │ │ │ │ - cumulative: false, │ │ │ │ - interval: 50, │ │ │ │ - maxDelta: 6 │ │ │ │ - }; │ │ │ │ - this.handlers.wheel = new OpenLayers.Handler.MouseWheel(this, { │ │ │ │ - up: this.wheelUp, │ │ │ │ - down: this.wheelDown │ │ │ │ - }, OpenLayers.Util.extend(wheelOptions, this.mouseWheelOptions)); │ │ │ │ - if (OpenLayers.Control.PinchZoom) { │ │ │ │ - this.pinchZoom = new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({ │ │ │ │ - map: this.map │ │ │ │ - }, this.pinchZoomOptions)) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - defaultClick: function(evt) { │ │ │ │ - if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ - this.map.zoomOut() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - defaultDblClick: function(evt) { │ │ │ │ - this.map.zoomTo(this.map.zoom + 1, evt.xy) │ │ │ │ - }, │ │ │ │ - defaultDblRightClick: function(evt) { │ │ │ │ - this.map.zoomTo(this.map.zoom - 1, evt.xy) │ │ │ │ + this.onUnselect.call(this.scope, feature) │ │ │ │ }, │ │ │ │ - wheelChange: function(evt, deltaZ) { │ │ │ │ - if (!this.map.fractionalZoom) { │ │ │ │ - deltaZ = Math.round(deltaZ) │ │ │ │ - } │ │ │ │ - var currentZoom = this.map.getZoom(), │ │ │ │ - newZoom = currentZoom + deltaZ; │ │ │ │ - newZoom = Math.max(newZoom, 0); │ │ │ │ - newZoom = Math.min(newZoom, this.map.getNumZoomLevels()); │ │ │ │ - if (newZoom === currentZoom) { │ │ │ │ - return │ │ │ │ + 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 (!this.multipleSelect()) { │ │ │ │ + this.unselectAll() │ │ │ │ + } │ │ │ │ + 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]; │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ } │ │ │ │ - this.map.zoomTo(newZoom, evt.xy) │ │ │ │ - }, │ │ │ │ - wheelUp: function(evt, delta) { │ │ │ │ - this.wheelChange(evt, delta || 1) │ │ │ │ - }, │ │ │ │ - wheelDown: function(evt, delta) { │ │ │ │ - this.wheelChange(evt, delta || -1) │ │ │ │ - }, │ │ │ │ - disableZoomBox: function() { │ │ │ │ - this.zoomBoxEnabled = false; │ │ │ │ - this.zoomBox.deactivate() │ │ │ │ }, │ │ │ │ - enableZoomBox: function() { │ │ │ │ - this.zoomBoxEnabled = true; │ │ │ │ - if (this.active) { │ │ │ │ - this.zoomBox.activate() │ │ │ │ + setMap: function(map) { │ │ │ │ + this.handlers.feature.setMap(map); │ │ │ │ + if (this.box) { │ │ │ │ + this.handlers.box.setMap(map) │ │ │ │ } │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ }, │ │ │ │ - disableZoomWheel: function() { │ │ │ │ - this.zoomWheelEnabled = false; │ │ │ │ - this.handlers.wheel.deactivate() │ │ │ │ - }, │ │ │ │ - enableZoomWheel: function() { │ │ │ │ - this.zoomWheelEnabled = true; │ │ │ │ - if (this.active) { │ │ │ │ - this.handlers.wheel.activate() │ │ │ │ + setLayer: function(layers) { │ │ │ │ + var isActive = this.active; │ │ │ │ + this.unselectAll(); │ │ │ │ + this.deactivate(); │ │ │ │ + if (this.layers) { │ │ │ │ + this.layer.destroy(); │ │ │ │ + this.layers = null │ │ │ │ } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Navigation" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.NavToolbar = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ - this.addControls([new OpenLayers.Control.Navigation, new OpenLayers.Control.ZoomBox]) │ │ │ │ - }, │ │ │ │ - draw: function() { │ │ │ │ - var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments); │ │ │ │ - if (this.defaultControl === null) { │ │ │ │ - this.defaultControl = this.controls[0] │ │ │ │ + this.initLayer(layers); │ │ │ │ + this.handlers.feature.layer = this.layer; │ │ │ │ + if (isActive) { │ │ │ │ + this.activate() │ │ │ │ } │ │ │ │ - return div │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.NavToolbar" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.SelectFeature" │ │ │ │ }); │ │ │ │ OpenLayers.Control.TransformFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ geometryTypes: null, │ │ │ │ layer: null, │ │ │ │ preserveAspectRatio: false, │ │ │ │ rotate: true, │ │ │ │ feature: null, │ │ │ │ @@ -28045,14 +31401,1673 @@ │ │ │ │ this.layer = null; │ │ │ │ this.dragControl.destroy(); │ │ │ │ this.dragControl = null; │ │ │ │ OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.TransformFeature" │ │ │ │ }); │ │ │ │ +OpenLayers.Control.KeyboardDefaults = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + autoActivate: true, │ │ │ │ + slideFactor: 75, │ │ │ │ + observeElement: null, │ │ │ │ + draw: function() { │ │ │ │ + var observeElement = this.observeElement || document; │ │ │ │ + this.handler = new OpenLayers.Handler.Keyboard(this, { │ │ │ │ + keydown: this.defaultKeyPress │ │ │ │ + }, { │ │ │ │ + observeElement: observeElement │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + defaultKeyPress: function(evt) { │ │ │ │ + var size, handled = true; │ │ │ │ + var target = OpenLayers.Event.element(evt); │ │ │ │ + if (target && (target.tagName == "INPUT" || target.tagName == "TEXTAREA" || target.tagName == "SELECT")) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + switch (evt.keyCode) { │ │ │ │ + case OpenLayers.Event.KEY_LEFT: │ │ │ │ + this.map.pan(-this.slideFactor, 0); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Event.KEY_RIGHT: │ │ │ │ + this.map.pan(this.slideFactor, 0); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Event.KEY_UP: │ │ │ │ + this.map.pan(0, -this.slideFactor); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Event.KEY_DOWN: │ │ │ │ + this.map.pan(0, this.slideFactor); │ │ │ │ + break; │ │ │ │ + case 33: │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(0, -.75 * size.h); │ │ │ │ + break; │ │ │ │ + case 34: │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(0, .75 * size.h); │ │ │ │ + break; │ │ │ │ + case 35: │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(.75 * size.w, 0); │ │ │ │ + break; │ │ │ │ + case 36: │ │ │ │ + size = this.map.getSize(); │ │ │ │ + this.map.pan(-.75 * size.w, 0); │ │ │ │ + break; │ │ │ │ + case 43: │ │ │ │ + case 61: │ │ │ │ + case 187: │ │ │ │ + case 107: │ │ │ │ + this.map.zoomIn(); │ │ │ │ + break; │ │ │ │ + case 45: │ │ │ │ + case 109: │ │ │ │ + case 189: │ │ │ │ + case 95: │ │ │ │ + this.map.zoomOut(); │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + handled = false │ │ │ │ + } │ │ │ │ + if (handled) { │ │ │ │ + OpenLayers.Event.stop(evt) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.KeyboardDefaults" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.ZoomToMaxExtent = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ + trigger: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.zoomToMaxExtent() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomToMaxExtent" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.WMTSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + hover: false, │ │ │ │ + requestEncoding: "KVP", │ │ │ │ + drillDown: false, │ │ │ │ + maxFeatures: 10, │ │ │ │ + clickCallback: "click", │ │ │ │ + layers: null, │ │ │ │ + queryVisible: true, │ │ │ │ + infoFormat: "text/html", │ │ │ │ + vendorParams: {}, │ │ │ │ + format: null, │ │ │ │ + formatOptions: null, │ │ │ │ + handler: null, │ │ │ │ + hoverRequest: null, │ │ │ │ + pending: 0, │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + options.handlerOptions = options.handlerOptions || {}; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + if (!this.format) { │ │ │ │ + this.format = new OpenLayers.Format.WMSGetFeatureInfo(options.formatOptions) │ │ │ │ + } │ │ │ │ + if (this.drillDown === true) { │ │ │ │ + this.hover = false │ │ │ │ + } │ │ │ │ + if (this.hover) { │ │ │ │ + this.handler = new OpenLayers.Handler.Hover(this, { │ │ │ │ + move: this.cancelHover, │ │ │ │ + pause: this.getInfoForHover │ │ │ │ + }, OpenLayers.Util.extend(this.handlerOptions.hover || {}, { │ │ │ │ + delay: 250 │ │ │ │ + })) │ │ │ │ + } else { │ │ │ │ + var callbacks = {}; │ │ │ │ + callbacks[this.clickCallback] = this.getInfoForClick; │ │ │ │ + this.handler = new OpenLayers.Handler.Click(this, callbacks, this.handlerOptions.click || {}) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + getInfoForClick: function(evt) { │ │ │ │ + this.request(evt.xy, {}) │ │ │ │ + }, │ │ │ │ + getInfoForHover: function(evt) { │ │ │ │ + this.request(evt.xy, { │ │ │ │ + hover: true │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + cancelHover: function() { │ │ │ │ + if (this.hoverRequest) { │ │ │ │ + --this.pending; │ │ │ │ + if (this.pending <= 0) { │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + this.pending = 0 │ │ │ │ + } │ │ │ │ + this.hoverRequest.abort(); │ │ │ │ + this.hoverRequest = null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + findLayers: function() { │ │ │ │ + var candidates = this.layers || this.map.layers; │ │ │ │ + var layers = []; │ │ │ │ + var layer; │ │ │ │ + for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ + layer = candidates[i]; │ │ │ │ + if (layer instanceof OpenLayers.Layer.WMTS && layer.requestEncoding === this.requestEncoding && (!this.queryVisible || layer.getVisibility())) { │ │ │ │ + layers.push(layer); │ │ │ │ + if (!this.drillDown || this.hover) { │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return layers │ │ │ │ + }, │ │ │ │ + buildRequestOptions: function(layer, xy) { │ │ │ │ + var loc = this.map.getLonLatFromPixel(xy); │ │ │ │ + var getTileUrl = layer.getURL(new OpenLayers.Bounds(loc.lon, loc.lat, loc.lon, loc.lat)); │ │ │ │ + var params = OpenLayers.Util.getParameters(getTileUrl); │ │ │ │ + var tileInfo = layer.getTileInfo(loc); │ │ │ │ + OpenLayers.Util.extend(params, { │ │ │ │ + service: "WMTS", │ │ │ │ + version: layer.version, │ │ │ │ + request: "GetFeatureInfo", │ │ │ │ + infoFormat: this.infoFormat, │ │ │ │ + i: tileInfo.i, │ │ │ │ + j: tileInfo.j │ │ │ │ + }); │ │ │ │ + OpenLayers.Util.applyDefaults(params, this.vendorParams); │ │ │ │ + return { │ │ │ │ + url: OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url, │ │ │ │ + params: OpenLayers.Util.upperCaseObject(params), │ │ │ │ + callback: function(request) { │ │ │ │ + this.handleResponse(xy, request, layer) │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + request: function(xy, options) { │ │ │ │ + options = options || {}; │ │ │ │ + var layers = this.findLayers(); │ │ │ │ + if (layers.length > 0) { │ │ │ │ + var issue, layer; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + layer = layers[i]; │ │ │ │ + issue = this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ + xy: xy, │ │ │ │ + layer: layer │ │ │ │ + }); │ │ │ │ + if (issue !== false) { │ │ │ │ + ++this.pending; │ │ │ │ + var requestOptions = this.buildRequestOptions(layer, xy); │ │ │ │ + var request = OpenLayers.Request.GET(requestOptions); │ │ │ │ + if (options.hover === true) { │ │ │ │ + this.hoverRequest = request │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.pending > 0) { │ │ │ │ + OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + handleResponse: function(xy, request, layer) { │ │ │ │ + --this.pending; │ │ │ │ + if (this.pending <= 0) { │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + this.pending = 0 │ │ │ │ + } │ │ │ │ + if (request.status && (request.status < 200 || request.status >= 300)) { │ │ │ │ + this.events.triggerEvent("exception", { │ │ │ │ + xy: xy, │ │ │ │ + request: request, │ │ │ │ + layer: layer │ │ │ │ + }) │ │ │ │ + } else { │ │ │ │ + var doc = request.responseXML; │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ + doc = request.responseText │ │ │ │ + } │ │ │ │ + var features, except; │ │ │ │ + try { │ │ │ │ + features = this.format.read(doc) │ │ │ │ + } catch (error) { │ │ │ │ + except = true; │ │ │ │ + this.events.triggerEvent("exception", { │ │ │ │ + xy: xy, │ │ │ │ + request: request, │ │ │ │ + error: error, │ │ │ │ + layer: layer │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + if (!except) { │ │ │ │ + this.events.triggerEvent("getfeatureinfo", { │ │ │ │ + text: request.responseText, │ │ │ │ + features: features, │ │ │ │ + request: request, │ │ │ │ + xy: xy, │ │ │ │ + layer: layer │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.WMTSGetFeatureInfo" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Pan = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ + slideFactor: 50, │ │ │ │ + slideRatio: null, │ │ │ │ + direction: null, │ │ │ │ + initialize: function(direction, options) { │ │ │ │ + this.direction = direction; │ │ │ │ + this.CLASS_NAME += this.direction; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + trigger: function() { │ │ │ │ + if (this.map) { │ │ │ │ + var getSlideFactor = OpenLayers.Function.bind(function(dim) { │ │ │ │ + return this.slideRatio ? this.map.getSize()[dim] * this.slideRatio : this.slideFactor │ │ │ │ + }, this); │ │ │ │ + switch (this.direction) { │ │ │ │ + case OpenLayers.Control.Pan.NORTH: │ │ │ │ + this.map.pan(0, -getSlideFactor("h")); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Control.Pan.SOUTH: │ │ │ │ + this.map.pan(0, getSlideFactor("h")); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Control.Pan.WEST: │ │ │ │ + this.map.pan(-getSlideFactor("w"), 0); │ │ │ │ + break; │ │ │ │ + case OpenLayers.Control.Pan.EAST: │ │ │ │ + this.map.pan(getSlideFactor("w"), 0); │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Pan" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Pan.NORTH = "North"; │ │ │ │ +OpenLayers.Control.Pan.SOUTH = "South"; │ │ │ │ +OpenLayers.Control.Pan.EAST = "East"; │ │ │ │ +OpenLayers.Control.Pan.WEST = "West"; │ │ │ │ +OpenLayers.Control.PanPanel = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ + slideFactor: 50, │ │ │ │ + slideRatio: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ + var options = { │ │ │ │ + slideFactor: this.slideFactor, │ │ │ │ + slideRatio: this.slideRatio │ │ │ │ + }; │ │ │ │ + this.addControls([new OpenLayers.Control.Pan(OpenLayers.Control.Pan.NORTH, options), new OpenLayers.Control.Pan(OpenLayers.Control.Pan.SOUTH, options), new OpenLayers.Control.Pan(OpenLayers.Control.Pan.EAST, options), new OpenLayers.Control.Pan(OpenLayers.Control.Pan.WEST, options)]) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.PanPanel" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + center: null, │ │ │ │ + zoom: null, │ │ │ │ + layers: null, │ │ │ │ + displayProjection: null, │ │ │ │ + getParameters: function(url) { │ │ │ │ + url = url || window.location.href; │ │ │ │ + var parameters = OpenLayers.Util.getParameters(url); │ │ │ │ + var index = url.indexOf("#"); │ │ │ │ + if (index > 0) { │ │ │ │ + url = "?" + url.substring(index + 1, url.length); │ │ │ │ + OpenLayers.Util.extend(parameters, OpenLayers.Util.getParameters(url)) │ │ │ │ + } │ │ │ │ + return parameters │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ + var control = this.map.controls[i]; │ │ │ │ + if (control != this && control.CLASS_NAME == "OpenLayers.Control.ArgParser") { │ │ │ │ + if (control.displayProjection != this.displayProjection) { │ │ │ │ + this.displayProjection = control.displayProjection │ │ │ │ + } │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (i == this.map.controls.length) { │ │ │ │ + var args = this.getParameters(); │ │ │ │ + if (args.layers) { │ │ │ │ + this.layers = args.layers; │ │ │ │ + this.map.events.register("addlayer", this, this.configureLayers); │ │ │ │ + this.configureLayers() │ │ │ │ + } │ │ │ │ + if (args.lat && args.lon) { │ │ │ │ + this.center = new OpenLayers.LonLat(parseFloat(args.lon), parseFloat(args.lat)); │ │ │ │ + if (args.zoom) { │ │ │ │ + this.zoom = parseFloat(args.zoom) │ │ │ │ + } │ │ │ │ + this.map.events.register("changebaselayer", this, this.setCenter); │ │ │ │ + this.setCenter() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setCenter: function() { │ │ │ │ + if (this.map.baseLayer) { │ │ │ │ + this.map.events.unregister("changebaselayer", this, this.setCenter); │ │ │ │ + if (this.displayProjection) { │ │ │ │ + this.center.transform(this.displayProjection, this.map.getProjectionObject()) │ │ │ │ + } │ │ │ │ + this.map.setCenter(this.center, this.zoom) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + configureLayers: function() { │ │ │ │ + if (this.layers.length == this.map.layers.length) { │ │ │ │ + this.map.events.unregister("addlayer", this, this.configureLayers); │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + var c = this.layers.charAt(i); │ │ │ │ + if (c == "B") { │ │ │ │ + this.map.setBaseLayer(layer) │ │ │ │ + } else if (c == "T" || c == "F") { │ │ │ │ + layer.setVisibility(c == "T") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ArgParser" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + argParserClass: OpenLayers.Control.ArgParser, │ │ │ │ + element: null, │ │ │ │ + anchor: false, │ │ │ │ + base: "", │ │ │ │ + displayProjection: null, │ │ │ │ + initialize: function(element, base, options) { │ │ │ │ + if (element !== null && typeof element == "object" && !OpenLayers.Util.isElement(element)) { │ │ │ │ + options = element; │ │ │ │ + this.base = document.location.href; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + if (this.element != null) { │ │ │ │ + this.element = OpenLayers.Util.getElement(this.element) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.element = OpenLayers.Util.getElement(element); │ │ │ │ + this.base = base || document.location.href │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.element && this.element.parentNode == this.div) { │ │ │ │ + this.div.removeChild(this.element); │ │ │ │ + this.element = null │ │ │ │ + } │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.unregister("moveend", this, this.updateLink) │ │ │ │ + } │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ + var control = this.map.controls[i]; │ │ │ │ + if (control.CLASS_NAME == this.argParserClass.CLASS_NAME) { │ │ │ │ + if (control.displayProjection != this.displayProjection) { │ │ │ │ + this.displayProjection = control.displayProjection │ │ │ │ + } │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (i == this.map.controls.length) { │ │ │ │ + this.map.addControl(new this.argParserClass({ │ │ │ │ + displayProjection: this.displayProjection │ │ │ │ + })) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (!this.element && !this.anchor) { │ │ │ │ + this.element = document.createElement("a"); │ │ │ │ + this.element.innerHTML = OpenLayers.i18n("Permalink"); │ │ │ │ + this.element.href = ""; │ │ │ │ + this.div.appendChild(this.element) │ │ │ │ + } │ │ │ │ + this.map.events.on({ │ │ │ │ + moveend: this.updateLink, │ │ │ │ + changelayer: this.updateLink, │ │ │ │ + changebaselayer: this.updateLink, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.updateLink(); │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + updateLink: function() { │ │ │ │ + var separator = this.anchor ? "#" : "?"; │ │ │ │ + var href = this.base; │ │ │ │ + var anchor = null; │ │ │ │ + if (href.indexOf("#") != -1 && this.anchor == false) { │ │ │ │ + anchor = href.substring(href.indexOf("#"), href.length) │ │ │ │ + } │ │ │ │ + if (href.indexOf(separator) != -1) { │ │ │ │ + href = href.substring(0, href.indexOf(separator)) │ │ │ │ + } │ │ │ │ + var splits = href.split("#"); │ │ │ │ + href = splits[0] + separator + OpenLayers.Util.getParameterString(this.createParams()); │ │ │ │ + if (anchor) { │ │ │ │ + href += anchor │ │ │ │ + } │ │ │ │ + if (this.anchor && !this.element) { │ │ │ │ + window.location.href = href │ │ │ │ + } else { │ │ │ │ + this.element.href = href │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + createParams: function(center, zoom, layers) { │ │ │ │ + center = center || this.map.getCenter(); │ │ │ │ + var params = OpenLayers.Util.getParameters(this.base); │ │ │ │ + if (center) { │ │ │ │ + params.zoom = zoom || this.map.getZoom(); │ │ │ │ + var lat = center.lat; │ │ │ │ + var lon = center.lon; │ │ │ │ + if (this.displayProjection) { │ │ │ │ + var mapPosition = OpenLayers.Projection.transform({ │ │ │ │ + x: lon, │ │ │ │ + y: lat │ │ │ │ + }, this.map.getProjectionObject(), this.displayProjection); │ │ │ │ + lon = mapPosition.x; │ │ │ │ + lat = mapPosition.y │ │ │ │ + } │ │ │ │ + params.lat = Math.round(lat * 1e5) / 1e5; │ │ │ │ + params.lon = Math.round(lon * 1e5) / 1e5; │ │ │ │ + layers = layers || this.map.layers; │ │ │ │ + params.layers = ""; │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + var layer = layers[i]; │ │ │ │ + if (layer.isBaseLayer) { │ │ │ │ + params.layers += layer == this.map.baseLayer ? "B" : "0" │ │ │ │ + } else { │ │ │ │ + params.layers += layer.getVisibility() ? "T" : "F" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return params │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Permalink" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.GetFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + protocol: null, │ │ │ │ + multipleKey: null, │ │ │ │ + toggleKey: null, │ │ │ │ + modifiers: null, │ │ │ │ + multiple: false, │ │ │ │ + click: true, │ │ │ │ + single: true, │ │ │ │ + clickout: true, │ │ │ │ + toggle: false, │ │ │ │ + clickTolerance: 5, │ │ │ │ + hover: false, │ │ │ │ + box: false, │ │ │ │ + maxFeatures: 10, │ │ │ │ + features: null, │ │ │ │ + hoverFeature: null, │ │ │ │ + handlers: null, │ │ │ │ + hoverResponse: null, │ │ │ │ + filterType: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ + initialize: function(options) { │ │ │ │ + options.handlerOptions = options.handlerOptions || {}; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.features = {}; │ │ │ │ + this.handlers = {}; │ │ │ │ + if (this.click) { │ │ │ │ + this.handlers.click = new OpenLayers.Handler.Click(this, { │ │ │ │ + click: this.selectClick │ │ │ │ + }, this.handlerOptions.click || {}) │ │ │ │ + } │ │ │ │ + if (this.box) { │ │ │ │ + this.handlers.box = new OpenLayers.Handler.Box(this, { │ │ │ │ + done: this.selectBox │ │ │ │ + }, OpenLayers.Util.extend(this.handlerOptions.box, { │ │ │ │ + boxDivClassName: "olHandlerBoxSelectFeature" │ │ │ │ + })) │ │ │ │ + } │ │ │ │ + if (this.hover) { │ │ │ │ + this.handlers.hover = new OpenLayers.Handler.Hover(this, { │ │ │ │ + move: this.cancelHover, │ │ │ │ + pause: this.selectHover │ │ │ │ + }, OpenLayers.Util.extend(this.handlerOptions.hover, { │ │ │ │ + delay: 250, │ │ │ │ + pixelTolerance: 2 │ │ │ │ + })) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (!this.active) { │ │ │ │ + for (var i in this.handlers) { │ │ │ │ + this.handlers[i].activate() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return OpenLayers.Control.prototype.activate.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (this.active) { │ │ │ │ + for (var i in this.handlers) { │ │ │ │ + this.handlers[i].deactivate() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + selectClick: function(evt) { │ │ │ │ + var bounds = this.pixelToBounds(evt.xy); │ │ │ │ + this.setModifiers(evt); │ │ │ │ + this.request(bounds, { │ │ │ │ + single: this.single │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + selectBox: function(position) { │ │ │ │ + var bounds; │ │ │ │ + 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 │ │ │ │ + }); │ │ │ │ + bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat, maxXY.lon, maxXY.lat) │ │ │ │ + } else { │ │ │ │ + if (this.click) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + bounds = this.pixelToBounds(position) │ │ │ │ + } │ │ │ │ + this.setModifiers(this.handlers.box.dragHandler.evt); │ │ │ │ + this.request(bounds) │ │ │ │ + }, │ │ │ │ + selectHover: function(evt) { │ │ │ │ + var bounds = this.pixelToBounds(evt.xy); │ │ │ │ + this.request(bounds, { │ │ │ │ + single: true, │ │ │ │ + hover: true │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + cancelHover: function() { │ │ │ │ + if (this.hoverResponse) { │ │ │ │ + this.protocol.abort(this.hoverResponse); │ │ │ │ + this.hoverResponse = null; │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait") │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + request: function(bounds, options) { │ │ │ │ + options = options || {}; │ │ │ │ + var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ + type: this.filterType, │ │ │ │ + value: bounds │ │ │ │ + }); │ │ │ │ + OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ + var response = this.protocol.read({ │ │ │ │ + maxFeatures: options.single == true ? this.maxFeatures : undefined, │ │ │ │ + filter: filter, │ │ │ │ + callback: function(result) { │ │ │ │ + if (result.success()) { │ │ │ │ + if (result.features.length) { │ │ │ │ + if (options.single == true) { │ │ │ │ + this.selectBestFeature(result.features, bounds.getCenterLonLat(), options) │ │ │ │ + } else { │ │ │ │ + this.select(result.features) │ │ │ │ + } │ │ │ │ + } else if (options.hover) { │ │ │ │ + this.hoverSelect() │ │ │ │ + } else { │ │ │ │ + this.events.triggerEvent("clickout"); │ │ │ │ + if (this.clickout) { │ │ │ │ + this.unselectAll() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait") │ │ │ │ + }, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + if (options.hover == true) { │ │ │ │ + this.hoverResponse = response │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + selectBestFeature: function(features, clickPosition, options) { │ │ │ │ + options = options || {}; │ │ │ │ + if (features.length) { │ │ │ │ + var point = new OpenLayers.Geometry.Point(clickPosition.lon, clickPosition.lat); │ │ │ │ + var feature, resultFeature, dist; │ │ │ │ + var minDist = Number.MAX_VALUE; │ │ │ │ + for (var i = 0; i < features.length; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + if (feature.geometry) { │ │ │ │ + dist = point.distanceTo(feature.geometry, { │ │ │ │ + edge: false │ │ │ │ + }); │ │ │ │ + if (dist < minDist) { │ │ │ │ + minDist = dist; │ │ │ │ + resultFeature = feature; │ │ │ │ + if (minDist == 0) { │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (options.hover == true) { │ │ │ │ + this.hoverSelect(resultFeature) │ │ │ │ + } else { │ │ │ │ + this.select(resultFeature || features) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setModifiers: function(evt) { │ │ │ │ + this.modifiers = { │ │ │ │ + multiple: this.multiple || this.multipleKey && evt[this.multipleKey], │ │ │ │ + toggle: this.toggle || this.toggleKey && evt[this.toggleKey] │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + select: function(features) { │ │ │ │ + if (!this.modifiers.multiple && !this.modifiers.toggle) { │ │ │ │ + this.unselectAll() │ │ │ │ + } │ │ │ │ + if (!OpenLayers.Util.isArray(features)) { │ │ │ │ + features = [features] │ │ │ │ + } │ │ │ │ + var cont = this.events.triggerEvent("beforefeaturesselected", { │ │ │ │ + features: features │ │ │ │ + }); │ │ │ │ + if (cont !== false) { │ │ │ │ + var selectedFeatures = []; │ │ │ │ + var feature; │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + if (this.features[feature.fid || feature.id]) { │ │ │ │ + if (this.modifiers.toggle) { │ │ │ │ + this.unselect(this.features[feature.fid || feature.id]) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + cont = this.events.triggerEvent("beforefeatureselected", { │ │ │ │ + feature: feature │ │ │ │ + }); │ │ │ │ + if (cont !== false) { │ │ │ │ + this.features[feature.fid || feature.id] = feature; │ │ │ │ + selectedFeatures.push(feature); │ │ │ │ + this.events.triggerEvent("featureselected", { │ │ │ │ + feature: feature │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.events.triggerEvent("featuresselected", { │ │ │ │ + features: selectedFeatures │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + hoverSelect: function(feature) { │ │ │ │ + var fid = feature ? feature.fid || feature.id : null; │ │ │ │ + var hfid = this.hoverFeature ? this.hoverFeature.fid || this.hoverFeature.id : null; │ │ │ │ + if (hfid && hfid != fid) { │ │ │ │ + this.events.triggerEvent("outfeature", { │ │ │ │ + feature: this.hoverFeature │ │ │ │ + }); │ │ │ │ + this.hoverFeature = null │ │ │ │ + } │ │ │ │ + if (fid && fid != hfid) { │ │ │ │ + this.events.triggerEvent("hoverfeature", { │ │ │ │ + feature: feature │ │ │ │ + }); │ │ │ │ + this.hoverFeature = feature │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + unselect: function(feature) { │ │ │ │ + delete this.features[feature.fid || feature.id]; │ │ │ │ + this.events.triggerEvent("featureunselected", { │ │ │ │ + feature: feature │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + unselectAll: function() { │ │ │ │ + for (var fid in this.features) { │ │ │ │ + this.unselect(this.features[fid]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + for (var i in this.handlers) { │ │ │ │ + this.handlers[i].setMap(map) │ │ │ │ + } │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + pixelToBounds: function(pixel) { │ │ │ │ + var llPx = pixel.add(-this.clickTolerance / 2, this.clickTolerance / 2); │ │ │ │ + var urPx = pixel.add(this.clickTolerance / 2, -this.clickTolerance / 2); │ │ │ │ + var ll = this.map.getLonLatFromPixel(llPx); │ │ │ │ + var ur = this.map.getLonLatFromPixel(urPx); │ │ │ │ + return new OpenLayers.Bounds(ll.lon, ll.lat, ur.lon, ur.lat) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.GetFeature" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Graticule = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + autoActivate: true, │ │ │ │ + intervals: [45, 30, 20, 10, 5, 2, 1, .5, .2, .1, .05, .01, .005, .002, .001], │ │ │ │ + displayInLayerSwitcher: true, │ │ │ │ + visible: true, │ │ │ │ + numPoints: 50, │ │ │ │ + targetSize: 200, │ │ │ │ + layerName: null, │ │ │ │ + labelled: true, │ │ │ │ + labelFormat: "dm", │ │ │ │ + lineSymbolizer: { │ │ │ │ + strokeColor: "#333", │ │ │ │ + strokeWidth: 1, │ │ │ │ + strokeOpacity: .5 │ │ │ │ + }, │ │ │ │ + labelSymbolizer: {}, │ │ │ │ + gratLayer: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + options = options || {}; │ │ │ │ + options.layerName = options.layerName || OpenLayers.i18n("Graticule"); │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.labelSymbolizer.stroke = false; │ │ │ │ + this.labelSymbolizer.fill = false; │ │ │ │ + this.labelSymbolizer.label = "${label}"; │ │ │ │ + this.labelSymbolizer.labelAlign = "${labelAlign}"; │ │ │ │ + this.labelSymbolizer.labelXOffset = "${xOffset}"; │ │ │ │ + this.labelSymbolizer.labelYOffset = "${yOffset}" │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ + if (this.gratLayer) { │ │ │ │ + this.gratLayer.destroy(); │ │ │ │ + this.gratLayer = null │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (!this.gratLayer) { │ │ │ │ + var gratStyle = new OpenLayers.Style({}, { │ │ │ │ + rules: [new OpenLayers.Rule({ │ │ │ │ + symbolizer: { │ │ │ │ + Point: this.labelSymbolizer, │ │ │ │ + Line: this.lineSymbolizer │ │ │ │ + } │ │ │ │ + })] │ │ │ │ + }); │ │ │ │ + this.gratLayer = new OpenLayers.Layer.Vector(this.layerName, { │ │ │ │ + styleMap: new OpenLayers.StyleMap({ │ │ │ │ + default: gratStyle │ │ │ │ + }), │ │ │ │ + visibility: this.visible, │ │ │ │ + displayInLayerSwitcher: this.displayInLayerSwitcher │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.map.addLayer(this.gratLayer); │ │ │ │ + this.map.events.register("moveend", this, this.update); │ │ │ │ + this.update(); │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + this.map.events.unregister("moveend", this, this.update); │ │ │ │ + this.map.removeLayer(this.gratLayer); │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + update: function() { │ │ │ │ + var mapBounds = this.map.getExtent(); │ │ │ │ + if (!mapBounds) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + this.gratLayer.destroyFeatures(); │ │ │ │ + var llProj = new OpenLayers.Projection("EPSG:4326"); │ │ │ │ + var mapProj = this.map.getProjectionObject(); │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ + if (mapProj.proj && mapProj.proj.projName == "longlat") { │ │ │ │ + this.numPoints = 1 │ │ │ │ + } │ │ │ │ + var mapCenter = this.map.getCenter(); │ │ │ │ + var mapCenterLL = new OpenLayers.Pixel(mapCenter.lon, mapCenter.lat); │ │ │ │ + OpenLayers.Projection.transform(mapCenterLL, mapProj, llProj); │ │ │ │ + var testSq = this.targetSize * mapRes; │ │ │ │ + testSq *= testSq; │ │ │ │ + var llInterval; │ │ │ │ + for (var i = 0; i < this.intervals.length; ++i) { │ │ │ │ + llInterval = this.intervals[i]; │ │ │ │ + var delta = llInterval / 2; │ │ │ │ + var p1 = mapCenterLL.offset({ │ │ │ │ + x: -delta, │ │ │ │ + y: -delta │ │ │ │ + }); │ │ │ │ + var p2 = mapCenterLL.offset({ │ │ │ │ + x: delta, │ │ │ │ + y: delta │ │ │ │ + }); │ │ │ │ + OpenLayers.Projection.transform(p1, llProj, mapProj); │ │ │ │ + OpenLayers.Projection.transform(p2, llProj, mapProj); │ │ │ │ + var distSq = (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y); │ │ │ │ + if (distSq <= testSq) { │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + mapCenterLL.x = Math.floor(mapCenterLL.x / llInterval) * llInterval; │ │ │ │ + mapCenterLL.y = Math.floor(mapCenterLL.y / llInterval) * llInterval; │ │ │ │ + var iter = 0; │ │ │ │ + var centerLonPoints = [mapCenterLL.clone()]; │ │ │ │ + var newPoint = mapCenterLL.clone(); │ │ │ │ + var mapXY; │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: 0, │ │ │ │ + y: llInterval │ │ │ │ + }); │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLonPoints.unshift(newPoint) │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ + newPoint = mapCenterLL.clone(); │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: 0, │ │ │ │ + y: -llInterval │ │ │ │ + }); │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLonPoints.push(newPoint) │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ + iter = 0; │ │ │ │ + var centerLatPoints = [mapCenterLL.clone()]; │ │ │ │ + newPoint = mapCenterLL.clone(); │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: -llInterval, │ │ │ │ + y: 0 │ │ │ │ + }); │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLatPoints.unshift(newPoint) │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ + newPoint = mapCenterLL.clone(); │ │ │ │ + do { │ │ │ │ + newPoint = newPoint.offset({ │ │ │ │ + x: llInterval, │ │ │ │ + y: 0 │ │ │ │ + }); │ │ │ │ + mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); │ │ │ │ + centerLatPoints.push(newPoint) │ │ │ │ + } while (mapBounds.containsPixel(mapXY) && ++iter < 1e3); │ │ │ │ + var lines = []; │ │ │ │ + for (var i = 0; i < centerLatPoints.length; ++i) { │ │ │ │ + var lon = centerLatPoints[i].x; │ │ │ │ + var pointList = []; │ │ │ │ + var labelPoint = null; │ │ │ │ + var latEnd = Math.min(centerLonPoints[0].y, 90); │ │ │ │ + var latStart = Math.max(centerLonPoints[centerLonPoints.length - 1].y, -90); │ │ │ │ + var latDelta = (latEnd - latStart) / this.numPoints; │ │ │ │ + var lat = latStart; │ │ │ │ + for (var j = 0; j <= this.numPoints; ++j) { │ │ │ │ + var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ + gridPoint.transform(llProj, mapProj); │ │ │ │ + pointList.push(gridPoint); │ │ │ │ + lat += latDelta; │ │ │ │ + if (gridPoint.y >= mapBounds.bottom && !labelPoint) { │ │ │ │ + labelPoint = gridPoint │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.labelled) { │ │ │ │ + var labelPos = new OpenLayers.Geometry.Point(labelPoint.x, mapBounds.bottom); │ │ │ │ + var labelAttrs = { │ │ │ │ + value: lon, │ │ │ │ + label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lon, "lon", this.labelFormat) : "", │ │ │ │ + labelAlign: "cb", │ │ │ │ + xOffset: 0, │ │ │ │ + yOffset: 2 │ │ │ │ + }; │ │ │ │ + this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)) │ │ │ │ + } │ │ │ │ + var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ + lines.push(new OpenLayers.Feature.Vector(geom)) │ │ │ │ + } │ │ │ │ + for (var j = 0; j < centerLonPoints.length; ++j) { │ │ │ │ + lat = centerLonPoints[j].y; │ │ │ │ + if (lat < -90 || lat > 90) { │ │ │ │ + continue │ │ │ │ + } │ │ │ │ + var pointList = []; │ │ │ │ + var lonStart = centerLatPoints[0].x; │ │ │ │ + var lonEnd = centerLatPoints[centerLatPoints.length - 1].x; │ │ │ │ + var lonDelta = (lonEnd - lonStart) / this.numPoints; │ │ │ │ + var lon = lonStart; │ │ │ │ + var labelPoint = null; │ │ │ │ + for (var i = 0; i <= this.numPoints; ++i) { │ │ │ │ + var gridPoint = new OpenLayers.Geometry.Point(lon, lat); │ │ │ │ + gridPoint.transform(llProj, mapProj); │ │ │ │ + pointList.push(gridPoint); │ │ │ │ + lon += lonDelta; │ │ │ │ + if (gridPoint.x < mapBounds.right) { │ │ │ │ + labelPoint = gridPoint │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.labelled) { │ │ │ │ + var labelPos = new OpenLayers.Geometry.Point(mapBounds.right, labelPoint.y); │ │ │ │ + var labelAttrs = { │ │ │ │ + value: lat, │ │ │ │ + label: this.labelled ? OpenLayers.Util.getFormattedLonLat(lat, "lat", this.labelFormat) : "", │ │ │ │ + labelAlign: "rb", │ │ │ │ + xOffset: -2, │ │ │ │ + yOffset: 2 │ │ │ │ + }; │ │ │ │ + this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos, labelAttrs)) │ │ │ │ + } │ │ │ │ + var geom = new OpenLayers.Geometry.LineString(pointList); │ │ │ │ + lines.push(new OpenLayers.Feature.Vector(geom)) │ │ │ │ + } │ │ │ │ + this.gratLayer.addFeatures(lines) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Graticule" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Snapping = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + DEFAULTS: { │ │ │ │ + tolerance: 10, │ │ │ │ + node: true, │ │ │ │ + edge: true, │ │ │ │ + vertex: true │ │ │ │ + }, │ │ │ │ + greedy: true, │ │ │ │ + precedence: ["node", "vertex", "edge"], │ │ │ │ + resolution: null, │ │ │ │ + geoToleranceCache: null, │ │ │ │ + layer: null, │ │ │ │ + feature: null, │ │ │ │ + point: null, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + this.options = options || {}; │ │ │ │ + if (this.options.layer) { │ │ │ │ + this.setLayer(this.options.layer) │ │ │ │ + } │ │ │ │ + var defaults = OpenLayers.Util.extend({}, this.options.defaults); │ │ │ │ + this.defaults = OpenLayers.Util.applyDefaults(defaults, this.DEFAULTS); │ │ │ │ + this.setTargets(this.options.targets); │ │ │ │ + if (this.targets.length === 0 && this.layer) { │ │ │ │ + this.addTargetLayer(this.layer) │ │ │ │ + } │ │ │ │ + this.geoToleranceCache = {} │ │ │ │ + }, │ │ │ │ + setLayer: function(layer) { │ │ │ │ + if (this.active) { │ │ │ │ + this.deactivate(); │ │ │ │ + this.layer = layer; │ │ │ │ + this.activate() │ │ │ │ + } else { │ │ │ │ + this.layer = layer │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + setTargets: function(targets) { │ │ │ │ + this.targets = []; │ │ │ │ + if (targets && targets.length) { │ │ │ │ + var target; │ │ │ │ + for (var i = 0, len = targets.length; i < len; ++i) { │ │ │ │ + target = targets[i]; │ │ │ │ + if (target instanceof OpenLayers.Layer.Vector) { │ │ │ │ + this.addTargetLayer(target) │ │ │ │ + } else { │ │ │ │ + this.addTarget(target) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + addTargetLayer: function(layer) { │ │ │ │ + this.addTarget({ │ │ │ │ + layer: layer │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + addTarget: function(target) { │ │ │ │ + target = OpenLayers.Util.applyDefaults(target, this.defaults); │ │ │ │ + target.nodeTolerance = target.nodeTolerance || target.tolerance; │ │ │ │ + target.vertexTolerance = target.vertexTolerance || target.tolerance; │ │ │ │ + target.edgeTolerance = target.edgeTolerance || target.tolerance; │ │ │ │ + this.targets.push(target) │ │ │ │ + }, │ │ │ │ + removeTargetLayer: function(layer) { │ │ │ │ + var target; │ │ │ │ + for (var i = this.targets.length - 1; i >= 0; --i) { │ │ │ │ + target = this.targets[i]; │ │ │ │ + if (target.layer === layer) { │ │ │ │ + this.removeTarget(target) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + removeTarget: function(target) { │ │ │ │ + return OpenLayers.Util.removeItem(this.targets, target) │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ + if (activated) { │ │ │ │ + if (this.layer && this.layer.events) { │ │ │ │ + this.layer.events.on({ │ │ │ │ + sketchstarted: this.onSketchModified, │ │ │ │ + sketchmodified: this.onSketchModified, │ │ │ │ + vertexmodified: this.onVertexModified, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ + if (deactivated) { │ │ │ │ + if (this.layer && this.layer.events) { │ │ │ │ + this.layer.events.un({ │ │ │ │ + sketchstarted: this.onSketchModified, │ │ │ │ + sketchmodified: this.onSketchModified, │ │ │ │ + vertexmodified: this.onVertexModified, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.feature = null; │ │ │ │ + this.point = null; │ │ │ │ + return deactivated │ │ │ │ + }, │ │ │ │ + onSketchModified: function(event) { │ │ │ │ + this.feature = event.feature; │ │ │ │ + this.considerSnapping(event.vertex, event.vertex) │ │ │ │ + }, │ │ │ │ + onVertexModified: function(event) { │ │ │ │ + this.feature = event.feature; │ │ │ │ + var loc = this.layer.map.getLonLatFromViewPortPx(event.pixel); │ │ │ │ + this.considerSnapping(event.vertex, new OpenLayers.Geometry.Point(loc.lon, loc.lat)) │ │ │ │ + }, │ │ │ │ + considerSnapping: function(point, loc) { │ │ │ │ + var best = { │ │ │ │ + rank: Number.POSITIVE_INFINITY, │ │ │ │ + dist: Number.POSITIVE_INFINITY, │ │ │ │ + x: null, │ │ │ │ + y: null │ │ │ │ + }; │ │ │ │ + var snapped = false; │ │ │ │ + var result, target; │ │ │ │ + for (var i = 0, len = this.targets.length; i < len; ++i) { │ │ │ │ + target = this.targets[i]; │ │ │ │ + result = this.testTarget(target, loc); │ │ │ │ + if (result) { │ │ │ │ + if (this.greedy) { │ │ │ │ + best = result; │ │ │ │ + best.target = target; │ │ │ │ + snapped = true; │ │ │ │ + break │ │ │ │ + } else { │ │ │ │ + if (result.rank < best.rank || result.rank === best.rank && result.dist < best.dist) { │ │ │ │ + best = result; │ │ │ │ + best.target = target; │ │ │ │ + snapped = true │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (snapped) { │ │ │ │ + var proceed = this.events.triggerEvent("beforesnap", { │ │ │ │ + point: point, │ │ │ │ + x: best.x, │ │ │ │ + y: best.y, │ │ │ │ + distance: best.dist, │ │ │ │ + layer: best.target.layer, │ │ │ │ + snapType: this.precedence[best.rank] │ │ │ │ + }); │ │ │ │ + if (proceed !== false) { │ │ │ │ + point.x = best.x; │ │ │ │ + point.y = best.y; │ │ │ │ + this.point = point; │ │ │ │ + this.events.triggerEvent("snap", { │ │ │ │ + point: point, │ │ │ │ + snapType: this.precedence[best.rank], │ │ │ │ + layer: best.target.layer, │ │ │ │ + distance: best.dist │ │ │ │ + }) │ │ │ │ + } else { │ │ │ │ + snapped = false │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.point && !snapped) { │ │ │ │ + point.x = loc.x; │ │ │ │ + point.y = loc.y; │ │ │ │ + this.point = null; │ │ │ │ + this.events.triggerEvent("unsnap", { │ │ │ │ + point: point │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + testTarget: function(target, loc) { │ │ │ │ + var resolution = this.layer.map.getResolution(); │ │ │ │ + if ("minResolution" in target) { │ │ │ │ + if (resolution < target.minResolution) { │ │ │ │ + return null │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if ("maxResolution" in target) { │ │ │ │ + if (resolution >= target.maxResolution) { │ │ │ │ + return null │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var tolerance = { │ │ │ │ + node: this.getGeoTolerance(target.nodeTolerance, resolution), │ │ │ │ + vertex: this.getGeoTolerance(target.vertexTolerance, resolution), │ │ │ │ + edge: this.getGeoTolerance(target.edgeTolerance, resolution) │ │ │ │ + }; │ │ │ │ + var maxTolerance = Math.max(tolerance.node, tolerance.vertex, tolerance.edge); │ │ │ │ + var result = { │ │ │ │ + rank: Number.POSITIVE_INFINITY, │ │ │ │ + dist: Number.POSITIVE_INFINITY │ │ │ │ + }; │ │ │ │ + var eligible = false; │ │ │ │ + var features = target.layer.features; │ │ │ │ + var feature, type, vertices, vertex, closest, dist, found; │ │ │ │ + var numTypes = this.precedence.length; │ │ │ │ + var ll = new OpenLayers.LonLat(loc.x, loc.y); │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ + feature = features[i]; │ │ │ │ + if (feature !== this.feature && !feature._sketch && feature.state !== OpenLayers.State.DELETE && (!target.filter || target.filter.evaluate(feature))) { │ │ │ │ + if (feature.atPoint(ll, maxTolerance, maxTolerance)) { │ │ │ │ + for (var j = 0, stop = Math.min(result.rank + 1, numTypes); j < stop; ++j) { │ │ │ │ + type = this.precedence[j]; │ │ │ │ + if (target[type]) { │ │ │ │ + if (type === "edge") { │ │ │ │ + closest = feature.geometry.distanceTo(loc, { │ │ │ │ + details: true │ │ │ │ + }); │ │ │ │ + dist = closest.distance; │ │ │ │ + if (dist <= tolerance[type] && dist < result.dist) { │ │ │ │ + result = { │ │ │ │ + rank: j, │ │ │ │ + dist: dist, │ │ │ │ + x: closest.x0, │ │ │ │ + y: closest.y0 │ │ │ │ + }; │ │ │ │ + eligible = true; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + vertices = feature.geometry.getVertices(type === "node"); │ │ │ │ + found = false; │ │ │ │ + for (var k = 0, klen = vertices.length; k < klen; ++k) { │ │ │ │ + vertex = vertices[k]; │ │ │ │ + dist = vertex.distanceTo(loc); │ │ │ │ + if (dist <= tolerance[type] && (j < result.rank || j === result.rank && dist < result.dist)) { │ │ │ │ + result = { │ │ │ │ + rank: j, │ │ │ │ + dist: dist, │ │ │ │ + x: vertex.x, │ │ │ │ + y: vertex.y │ │ │ │ + }; │ │ │ │ + eligible = true; │ │ │ │ + found = true │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (found) { │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return eligible ? result : null │ │ │ │ + }, │ │ │ │ + getGeoTolerance: function(tolerance, resolution) { │ │ │ │ + if (resolution !== this.resolution) { │ │ │ │ + this.resolution = resolution; │ │ │ │ + this.geoToleranceCache = {} │ │ │ │ + } │ │ │ │ + var geoTolerance = this.geoToleranceCache[tolerance]; │ │ │ │ + if (geoTolerance === undefined) { │ │ │ │ + geoTolerance = tolerance * resolution; │ │ │ │ + this.geoToleranceCache[tolerance] = geoTolerance │ │ │ │ + } │ │ │ │ + return geoTolerance │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.active) { │ │ │ │ + this.deactivate() │ │ │ │ + } │ │ │ │ + delete this.layer; │ │ │ │ + delete this.targets; │ │ │ │ + OpenLayers.Control.prototype.destroy.call(this) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Snapping" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.MousePosition = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + autoActivate: true, │ │ │ │ + element: null, │ │ │ │ + prefix: "", │ │ │ │ + separator: ", ", │ │ │ │ + suffix: "", │ │ │ │ + numDigits: 5, │ │ │ │ + granularity: 10, │ │ │ │ + emptyString: null, │ │ │ │ + lastXy: null, │ │ │ │ + displayProjection: null, │ │ │ │ + destroy: function() { │ │ │ │ + this.deactivate(); │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + activate: function() { │ │ │ │ + if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ + this.map.events.register("mousemove", this, this.redraw); │ │ │ │ + this.map.events.register("mouseout", this, this.reset); │ │ │ │ + this.redraw(); │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ + this.map.events.unregister("mousemove", this, this.redraw); │ │ │ │ + this.map.events.unregister("mouseout", this, this.reset); │ │ │ │ + this.element.innerHTML = ""; │ │ │ │ + return true │ │ │ │ + } else { │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (!this.element) { │ │ │ │ + this.div.left = ""; │ │ │ │ + this.div.top = ""; │ │ │ │ + this.element = this.div │ │ │ │ + } │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + redraw: function(evt) { │ │ │ │ + var lonLat; │ │ │ │ + if (evt == null) { │ │ │ │ + this.reset(); │ │ │ │ + return │ │ │ │ + } else { │ │ │ │ + if (this.lastXy == null || Math.abs(evt.xy.x - this.lastXy.x) > this.granularity || Math.abs(evt.xy.y - this.lastXy.y) > this.granularity) { │ │ │ │ + this.lastXy = evt.xy; │ │ │ │ + return │ │ │ │ + } │ │ │ │ + lonLat = this.map.getLonLatFromPixel(evt.xy); │ │ │ │ + if (!lonLat) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + if (this.displayProjection) { │ │ │ │ + lonLat.transform(this.map.getProjectionObject(), this.displayProjection) │ │ │ │ + } │ │ │ │ + this.lastXy = evt.xy │ │ │ │ + } │ │ │ │ + var newHtml = this.formatOutput(lonLat); │ │ │ │ + if (newHtml != this.element.innerHTML) { │ │ │ │ + this.element.innerHTML = newHtml │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + reset: function(evt) { │ │ │ │ + if (this.emptyString != null) { │ │ │ │ + this.element.innerHTML = this.emptyString │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + formatOutput: function(lonLat) { │ │ │ │ + var digits = parseInt(this.numDigits); │ │ │ │ + var newHtml = this.prefix + lonLat.lon.toFixed(digits) + this.separator + lonLat.lat.toFixed(digits) + this.suffix; │ │ │ │ + return newHtml │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.MousePosition" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.Attribution = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + separator: ", ", │ │ │ │ + template: "${layers}", │ │ │ │ + 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) │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + 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()) { │ │ │ │ + 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.Control.LayerSwitcher = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + layerStates: null, │ │ │ │ + layersDiv: null, │ │ │ │ + baseLayersDiv: null, │ │ │ │ + baseLayers: null, │ │ │ │ + dataLbl: null, │ │ │ │ + dataLayersDiv: null, │ │ │ │ + dataLayers: null, │ │ │ │ + minimizeDiv: null, │ │ │ │ + maximizeDiv: null, │ │ │ │ + ascending: true, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ + this.layerStates = [] │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.clearLayersArray("base"); │ │ │ │ + this.clearLayersArray("data"); │ │ │ │ + this.map.events.un({ │ │ │ │ + buttonclick: this.onButtonClick, │ │ │ │ + addlayer: this.redraw, │ │ │ │ + changelayer: this.redraw, │ │ │ │ + removelayer: this.redraw, │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + this.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + this.map.events.on({ │ │ │ │ + addlayer: this.redraw, │ │ │ │ + changelayer: this.redraw, │ │ │ │ + removelayer: this.redraw, │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + if (this.outsideViewport) { │ │ │ │ + this.events.attachToElement(this.div); │ │ │ │ + this.events.register("buttonclick", this, this.onButtonClick) │ │ │ │ + } else { │ │ │ │ + this.map.events.register("buttonclick", this, this.onButtonClick) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this); │ │ │ │ + this.loadContents(); │ │ │ │ + if (!this.outsideViewport) { │ │ │ │ + this.minimizeControl() │ │ │ │ + } │ │ │ │ + this.redraw(); │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + var button = evt.buttonElement; │ │ │ │ + if (button === this.minimizeDiv) { │ │ │ │ + this.minimizeControl() │ │ │ │ + } else if (button === this.maximizeDiv) { │ │ │ │ + this.maximizeControl() │ │ │ │ + } else if (button._layerSwitcher === this.id) { │ │ │ │ + if (button["for"]) { │ │ │ │ + button = document.getElementById(button["for"]) │ │ │ │ + } │ │ │ │ + if (!button.disabled) { │ │ │ │ + if (button.type == "radio") { │ │ │ │ + button.checked = true; │ │ │ │ + this.map.setBaseLayer(this.map.getLayer(button._layer)) │ │ │ │ + } else { │ │ │ │ + button.checked = !button.checked; │ │ │ │ + this.updateMap() │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + clearLayersArray: function(layersType) { │ │ │ │ + this[layersType + "LayersDiv"].innerHTML = ""; │ │ │ │ + this[layersType + "Layers"] = [] │ │ │ │ + }, │ │ │ │ + checkRedraw: function() { │ │ │ │ + if (!this.layerStates.length || this.map.layers.length != this.layerStates.length) { │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + for (var i = 0, len = this.layerStates.length; i < len; i++) { │ │ │ │ + var layerState = this.layerStates[i]; │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + if (layerState.name != layer.name || layerState.inRange != layer.inRange || layerState.id != layer.id || layerState.visibility != layer.visibility) { │ │ │ │ + return true │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return false │ │ │ │ + }, │ │ │ │ + redraw: function() { │ │ │ │ + if (!this.checkRedraw()) { │ │ │ │ + return this.div │ │ │ │ + } │ │ │ │ + this.clearLayersArray("base"); │ │ │ │ + this.clearLayersArray("data"); │ │ │ │ + var containsOverlays = false; │ │ │ │ + var containsBaseLayers = false; │ │ │ │ + var len = this.map.layers.length; │ │ │ │ + this.layerStates = new Array(len); │ │ │ │ + for (var i = 0; i < len; i++) { │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ + this.layerStates[i] = { │ │ │ │ + name: layer.name, │ │ │ │ + visibility: layer.visibility, │ │ │ │ + inRange: layer.inRange, │ │ │ │ + id: layer.id │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var layers = this.map.layers.slice(); │ │ │ │ + if (!this.ascending) { │ │ │ │ + layers.reverse() │ │ │ │ + } │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ + var layer = layers[i]; │ │ │ │ + var baseLayer = layer.isBaseLayer; │ │ │ │ + if (layer.displayInLayerSwitcher) { │ │ │ │ + if (baseLayer) { │ │ │ │ + containsBaseLayers = true │ │ │ │ + } else { │ │ │ │ + containsOverlays = true │ │ │ │ + } │ │ │ │ + var checked = baseLayer ? layer == this.map.baseLayer : layer.getVisibility(); │ │ │ │ + var inputElem = document.createElement("input"), │ │ │ │ + inputId = OpenLayers.Util.createUniqueID(this.id + "_input_"); │ │ │ │ + inputElem.id = inputId; │ │ │ │ + inputElem.name = baseLayer ? this.id + "_baseLayers" : layer.name; │ │ │ │ + inputElem.type = baseLayer ? "radio" : "checkbox"; │ │ │ │ + inputElem.value = layer.name; │ │ │ │ + inputElem.checked = checked; │ │ │ │ + inputElem.defaultChecked = checked; │ │ │ │ + inputElem.className = "olButton"; │ │ │ │ + inputElem._layer = layer.id; │ │ │ │ + inputElem._layerSwitcher = this.id; │ │ │ │ + if (!baseLayer && !layer.inRange) { │ │ │ │ + inputElem.disabled = true │ │ │ │ + } │ │ │ │ + var labelSpan = document.createElement("label"); │ │ │ │ + labelSpan["for"] = inputElem.id; │ │ │ │ + OpenLayers.Element.addClass(labelSpan, "labelSpan olButton"); │ │ │ │ + labelSpan._layer = layer.id; │ │ │ │ + labelSpan._layerSwitcher = this.id; │ │ │ │ + if (!baseLayer && !layer.inRange) { │ │ │ │ + labelSpan.style.color = "gray" │ │ │ │ + } │ │ │ │ + labelSpan.innerHTML = layer.name; │ │ │ │ + labelSpan.style.verticalAlign = baseLayer ? "bottom" : "baseline"; │ │ │ │ + var br = document.createElement("br"); │ │ │ │ + var groupArray = baseLayer ? this.baseLayers : this.dataLayers; │ │ │ │ + groupArray.push({ │ │ │ │ + layer: layer, │ │ │ │ + inputElem: inputElem, │ │ │ │ + labelSpan: labelSpan │ │ │ │ + }); │ │ │ │ + var groupDiv = baseLayer ? this.baseLayersDiv : this.dataLayersDiv; │ │ │ │ + groupDiv.appendChild(inputElem); │ │ │ │ + groupDiv.appendChild(labelSpan); │ │ │ │ + groupDiv.appendChild(br) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.dataLbl.style.display = containsOverlays ? "" : "none"; │ │ │ │ + this.baseLbl.style.display = containsBaseLayers ? "" : "none"; │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + updateMap: function() { │ │ │ │ + for (var i = 0, len = this.baseLayers.length; i < len; i++) { │ │ │ │ + var layerEntry = this.baseLayers[i]; │ │ │ │ + if (layerEntry.inputElem.checked) { │ │ │ │ + this.map.setBaseLayer(layerEntry.layer, false) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + for (var i = 0, len = this.dataLayers.length; i < len; i++) { │ │ │ │ + var layerEntry = this.dataLayers[i]; │ │ │ │ + layerEntry.layer.setVisibility(layerEntry.inputElem.checked) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + maximizeControl: function(e) { │ │ │ │ + this.div.style.width = ""; │ │ │ │ + this.div.style.height = ""; │ │ │ │ + this.showControls(false); │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + minimizeControl: function(e) { │ │ │ │ + this.div.style.width = "0px"; │ │ │ │ + this.div.style.height = "0px"; │ │ │ │ + this.showControls(true); │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + showControls: function(minimize) { │ │ │ │ + this.maximizeDiv.style.display = minimize ? "" : "none"; │ │ │ │ + this.minimizeDiv.style.display = minimize ? "none" : ""; │ │ │ │ + this.layersDiv.style.display = minimize ? "none" : "" │ │ │ │ + }, │ │ │ │ + loadContents: function() { │ │ │ │ + this.layersDiv = document.createElement("div"); │ │ │ │ + this.layersDiv.id = this.id + "_layersDiv"; │ │ │ │ + OpenLayers.Element.addClass(this.layersDiv, "layersDiv"); │ │ │ │ + this.baseLbl = document.createElement("div"); │ │ │ │ + this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer"); │ │ │ │ + OpenLayers.Element.addClass(this.baseLbl, "baseLbl"); │ │ │ │ + this.baseLayersDiv = document.createElement("div"); │ │ │ │ + OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv"); │ │ │ │ + this.dataLbl = document.createElement("div"); │ │ │ │ + this.dataLbl.innerHTML = OpenLayers.i18n("Overlays"); │ │ │ │ + OpenLayers.Element.addClass(this.dataLbl, "dataLbl"); │ │ │ │ + this.dataLayersDiv = document.createElement("div"); │ │ │ │ + OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv"); │ │ │ │ + if (this.ascending) { │ │ │ │ + this.layersDiv.appendChild(this.baseLbl); │ │ │ │ + this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ + this.layersDiv.appendChild(this.dataLbl); │ │ │ │ + this.layersDiv.appendChild(this.dataLayersDiv) │ │ │ │ + } else { │ │ │ │ + this.layersDiv.appendChild(this.dataLbl); │ │ │ │ + this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ + this.layersDiv.appendChild(this.baseLbl); │ │ │ │ + this.layersDiv.appendChild(this.baseLayersDiv) │ │ │ │ + } │ │ │ │ + this.div.appendChild(this.layersDiv); │ │ │ │ + var img = OpenLayers.Util.getImageLocation("layer-switcher-maximize.png"); │ │ │ │ + this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MaximizeDiv", null, null, img, "absolute"); │ │ │ │ + OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv olButton"); │ │ │ │ + this.maximizeDiv.style.display = "none"; │ │ │ │ + this.div.appendChild(this.maximizeDiv); │ │ │ │ + var img = OpenLayers.Util.getImageLocation("layer-switcher-minimize.png"); │ │ │ │ + this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MinimizeDiv", null, null, img, "absolute"); │ │ │ │ + OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton"); │ │ │ │ + this.minimizeDiv.style.display = "none"; │ │ │ │ + this.div.appendChild(this.minimizeDiv) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.LayerSwitcher" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.ZoomOut = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ + trigger: function() { │ │ │ │ + if (this.map) { │ │ │ │ + this.map.zoomOut() │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomOut" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.ZoomPanel = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ + this.addControls([new OpenLayers.Control.ZoomIn, new OpenLayers.Control.ZoomToMaxExtent, new OpenLayers.Control.ZoomOut]) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomPanel" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.CacheRead = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + fetchEvent: "tileloadstart", │ │ │ │ + layers: null, │ │ │ │ + autoActivate: true, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + var i, layers = this.layers || map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.addLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + if (!this.layers) { │ │ │ │ + map.events.on({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + addLayer: function(evt) { │ │ │ │ + evt.layer.events.register(this.fetchEvent, this, this.fetch) │ │ │ │ + }, │ │ │ │ + removeLayer: function(evt) { │ │ │ │ + evt.layer.events.unregister(this.fetchEvent, this, this.fetch) │ │ │ │ + }, │ │ │ │ + fetch: function(evt) { │ │ │ │ + if (this.active && window.localStorage && evt.tile instanceof OpenLayers.Tile.Image) { │ │ │ │ + var tile = evt.tile, │ │ │ │ + url = tile.url; │ │ │ │ + if (!tile.layer.crossOriginKeyword && OpenLayers.ProxyHost && url.indexOf(OpenLayers.ProxyHost) === 0) { │ │ │ │ + url = OpenLayers.Control.CacheWrite.urlMap[url] │ │ │ │ + } │ │ │ │ + var dataURI = window.localStorage.getItem("olCache_" + url); │ │ │ │ + if (dataURI) { │ │ │ │ + tile.url = dataURI; │ │ │ │ + if (evt.type === "tileerror") { │ │ │ │ + tile.setImgSrc(dataURI) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (this.layers || this.map) { │ │ │ │ + var i, layers = this.layers || this.map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.removeLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (this.map) { │ │ │ │ + this.map.events.un({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.CacheRead" │ │ │ │ +}); │ │ │ │ OpenLayers.Control.DrawFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ layer: null, │ │ │ │ callbacks: null, │ │ │ │ multi: false, │ │ │ │ featureAdded: function() {}, │ │ │ │ initialize: function(layer, handler, options) { │ │ │ │ OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ @@ -28086,293 +33101,616 @@ │ │ │ │ styleMap: new OpenLayers.StyleMap({ │ │ │ │ default: sketchStyle │ │ │ │ }) │ │ │ │ }) │ │ │ │ } │ │ │ │ this.handler = new handler(this, this.callbacks, this.handlerOptions) │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ + 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 │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + insertXY: function(x, y) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertXY(x, y) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + insertDeltaXY: function(dx, dy) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertDeltaXY(dx, dy) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + insertDirectionLength: function(direction, length) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertDirectionLength(direction, length) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + insertDeflectionLength: function(deflection, length) { │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ + this.handler.insertDeflectionLength(deflection, length) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + undo: function() { │ │ │ │ + return this.handler.undo && this.handler.undo() │ │ │ │ + }, │ │ │ │ + redo: function() { │ │ │ │ + return this.handler.redo && this.handler.redo() │ │ │ │ + }, │ │ │ │ + finishSketch: function() { │ │ │ │ + this.handler.finishGeometry() │ │ │ │ + }, │ │ │ │ + cancel: function() { │ │ │ │ + this.handler.cancel() │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.DrawFeature" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.EditingToolbar = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ + citeCompliant: false, │ │ │ │ + initialize: function(layer, options) { │ │ │ │ + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ + this.addControls([new OpenLayers.Control.Navigation]); │ │ │ │ + var controls = [new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Point, { │ │ │ │ + displayClass: "olControlDrawFeaturePoint", │ │ │ │ + handlerOptions: { │ │ │ │ + citeCompliant: this.citeCompliant │ │ │ │ + } │ │ │ │ + }), new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Path, { │ │ │ │ + displayClass: "olControlDrawFeaturePath", │ │ │ │ + handlerOptions: { │ │ │ │ + citeCompliant: this.citeCompliant │ │ │ │ + } │ │ │ │ + }), new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Polygon, { │ │ │ │ + displayClass: "olControlDrawFeaturePolygon", │ │ │ │ + handlerOptions: { │ │ │ │ + citeCompliant: this.citeCompliant │ │ │ │ + } │ │ │ │ + })]; │ │ │ │ + this.addControls(controls) │ │ │ │ + }, │ │ │ │ + draw: function() { │ │ │ │ + var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments); │ │ │ │ + if (this.defaultControl === null) { │ │ │ │ + this.defaultControl = this.controls[0] │ │ │ │ + } │ │ │ │ + return div │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.EditingToolbar" │ │ │ │ +}); │ │ │ │ +OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + element: null, │ │ │ │ + ovmap: null, │ │ │ │ + size: { │ │ │ │ + w: 180, │ │ │ │ + h: 90 │ │ │ │ + }, │ │ │ │ + layers: null, │ │ │ │ + minRectSize: 15, │ │ │ │ + minRectDisplayClass: "RectReplacement", │ │ │ │ + minRatio: 8, │ │ │ │ + maxRatio: 32, │ │ │ │ + mapOptions: null, │ │ │ │ + autoPan: false, │ │ │ │ + handlers: null, │ │ │ │ + resolutionFactor: 1, │ │ │ │ + maximized: false, │ │ │ │ + maximizeTitle: "", │ │ │ │ + minimizeTitle: "", │ │ │ │ + initialize: function(options) { │ │ │ │ + this.layers = []; │ │ │ │ + this.handlers = {}; │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + if (!this.mapDiv) { │ │ │ │ + return │ │ │ │ + } │ │ │ │ + if (this.handlers.click) { │ │ │ │ + this.handlers.click.destroy() │ │ │ │ + } │ │ │ │ + if (this.handlers.drag) { │ │ │ │ + this.handlers.drag.destroy() │ │ │ │ + } │ │ │ │ + this.ovmap && this.ovmap.viewPortDiv.removeChild(this.extentRectangle); │ │ │ │ + this.extentRectangle = null; │ │ │ │ + if (this.rectEvents) { │ │ │ │ + this.rectEvents.destroy(); │ │ │ │ + this.rectEvents = null │ │ │ │ + } │ │ │ │ + if (this.ovmap) { │ │ │ │ + this.ovmap.destroy(); │ │ │ │ + this.ovmap = null │ │ │ │ + } │ │ │ │ + this.element.removeChild(this.mapDiv); │ │ │ │ + this.mapDiv = null; │ │ │ │ + this.div.removeChild(this.element); │ │ │ │ + this.element = null; │ │ │ │ + if (this.maximizeDiv) { │ │ │ │ + this.div.removeChild(this.maximizeDiv); │ │ │ │ + this.maximizeDiv = null │ │ │ │ + } │ │ │ │ + if (this.minimizeDiv) { │ │ │ │ + this.div.removeChild(this.minimizeDiv); │ │ │ │ + this.minimizeDiv = null │ │ │ │ + } │ │ │ │ + this.map.events.un({ │ │ │ │ + buttonclick: this.onButtonClick, │ │ │ │ + moveend: this.update, │ │ │ │ + changebaselayer: this.baseLayerDraw, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + draw: function() { │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ + if (this.layers.length === 0) { │ │ │ │ + if (this.map.baseLayer) { │ │ │ │ + var layer = this.map.baseLayer.clone(); │ │ │ │ + this.layers = [layer] │ │ │ │ + } else { │ │ │ │ + this.map.events.register("changebaselayer", this, this.baseLayerDraw); │ │ │ │ + return this.div │ │ │ │ + } │ │ │ │ + } │ │ │ │ + this.element = document.createElement("div"); │ │ │ │ + this.element.className = this.displayClass + "Element"; │ │ │ │ + this.element.style.display = "none"; │ │ │ │ + this.mapDiv = document.createElement("div"); │ │ │ │ + this.mapDiv.style.width = this.size.w + "px"; │ │ │ │ + this.mapDiv.style.height = this.size.h + "px"; │ │ │ │ + this.mapDiv.style.position = "relative"; │ │ │ │ + this.mapDiv.style.overflow = "hidden"; │ │ │ │ + this.mapDiv.id = OpenLayers.Util.createUniqueID("overviewMap"); │ │ │ │ + this.extentRectangle = document.createElement("div"); │ │ │ │ + this.extentRectangle.style.position = "absolute"; │ │ │ │ + this.extentRectangle.style.zIndex = 1e3; │ │ │ │ + this.extentRectangle.className = this.displayClass + "ExtentRectangle"; │ │ │ │ + this.element.appendChild(this.mapDiv); │ │ │ │ + this.div.appendChild(this.element); │ │ │ │ + if (!this.outsideViewport) { │ │ │ │ + this.div.className += " " + this.displayClass + "Container"; │ │ │ │ + var img = OpenLayers.Util.getImageLocation("layer-switcher-maximize.png"); │ │ │ │ + this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(this.displayClass + "MaximizeButton", null, null, img, "absolute"); │ │ │ │ + this.maximizeDiv.style.display = "none"; │ │ │ │ + this.maximizeDiv.className = this.displayClass + "MaximizeButton olButton"; │ │ │ │ + if (this.maximizeTitle) { │ │ │ │ + this.maximizeDiv.title = this.maximizeTitle │ │ │ │ + } │ │ │ │ + this.div.appendChild(this.maximizeDiv); │ │ │ │ + var img = OpenLayers.Util.getImageLocation("layer-switcher-minimize.png"); │ │ │ │ + this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_minimizeDiv", null, null, img, "absolute"); │ │ │ │ + this.minimizeDiv.style.display = "none"; │ │ │ │ + this.minimizeDiv.className = this.displayClass + "MinimizeButton olButton"; │ │ │ │ + if (this.minimizeTitle) { │ │ │ │ + this.minimizeDiv.title = this.minimizeTitle │ │ │ │ + } │ │ │ │ + this.div.appendChild(this.minimizeDiv); │ │ │ │ + this.minimizeControl() │ │ │ │ + } else { │ │ │ │ + this.element.style.display = "" │ │ │ │ + } │ │ │ │ + if (this.map.getExtent()) { │ │ │ │ + this.update() │ │ │ │ + } │ │ │ │ + this.map.events.on({ │ │ │ │ + buttonclick: this.onButtonClick, │ │ │ │ + moveend: this.update, │ │ │ │ + scope: this │ │ │ │ + }); │ │ │ │ + if (this.maximized) { │ │ │ │ + this.maximizeControl() │ │ │ │ + } │ │ │ │ + return this.div │ │ │ │ + }, │ │ │ │ + baseLayerDraw: function() { │ │ │ │ + this.draw(); │ │ │ │ + this.map.events.unregister("changebaselayer", this, this.baseLayerDraw) │ │ │ │ + }, │ │ │ │ + rectDrag: function(px) { │ │ │ │ + var deltaX = this.handlers.drag.last.x - px.x; │ │ │ │ + var deltaY = this.handlers.drag.last.y - px.y; │ │ │ │ + if (deltaX != 0 || deltaY != 0) { │ │ │ │ + var rectTop = this.rectPxBounds.top; │ │ │ │ + var rectLeft = this.rectPxBounds.left; │ │ │ │ + var rectHeight = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ + var rectWidth = this.rectPxBounds.getWidth(); │ │ │ │ + var newTop = Math.max(0, rectTop - deltaY); │ │ │ │ + newTop = Math.min(newTop, this.ovmap.size.h - this.hComp - rectHeight); │ │ │ │ + var newLeft = Math.max(0, rectLeft - deltaX); │ │ │ │ + newLeft = Math.min(newLeft, this.ovmap.size.w - this.wComp - rectWidth); │ │ │ │ + this.setRectPxBounds(new OpenLayers.Bounds(newLeft, newTop + rectHeight, newLeft + rectWidth, newTop)) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + mapDivClick: function(evt) { │ │ │ │ + var pxCenter = this.rectPxBounds.getCenterPixel(); │ │ │ │ + var deltaX = evt.xy.x - pxCenter.x; │ │ │ │ + var deltaY = evt.xy.y - pxCenter.y; │ │ │ │ + var top = this.rectPxBounds.top; │ │ │ │ + var left = this.rectPxBounds.left; │ │ │ │ + var height = Math.abs(this.rectPxBounds.getHeight()); │ │ │ │ + var width = this.rectPxBounds.getWidth(); │ │ │ │ + var newTop = Math.max(0, top + deltaY); │ │ │ │ + newTop = Math.min(newTop, this.ovmap.size.h - height); │ │ │ │ + var newLeft = Math.max(0, left + deltaX); │ │ │ │ + newLeft = Math.min(newLeft, this.ovmap.size.w - width); │ │ │ │ + this.setRectPxBounds(new OpenLayers.Bounds(newLeft, newTop + height, newLeft + width, newTop)); │ │ │ │ + this.updateMapToRect() │ │ │ │ + }, │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ + if (evt.buttonElement === this.minimizeDiv) { │ │ │ │ + this.minimizeControl() │ │ │ │ + } else if (evt.buttonElement === this.maximizeDiv) { │ │ │ │ + this.maximizeControl() │ │ │ │ } │ │ │ │ }, │ │ │ │ - insertXY: function(x, y) { │ │ │ │ - if (this.handler && this.handler.line) { │ │ │ │ - this.handler.insertXY(x, y) │ │ │ │ + maximizeControl: function(e) { │ │ │ │ + this.element.style.display = ""; │ │ │ │ + this.showToggle(false); │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e) │ │ │ │ } │ │ │ │ }, │ │ │ │ - insertDeltaXY: function(dx, dy) { │ │ │ │ - if (this.handler && this.handler.line) { │ │ │ │ - this.handler.insertDeltaXY(dx, dy) │ │ │ │ + minimizeControl: function(e) { │ │ │ │ + this.element.style.display = "none"; │ │ │ │ + this.showToggle(true); │ │ │ │ + if (e != null) { │ │ │ │ + OpenLayers.Event.stop(e) │ │ │ │ } │ │ │ │ }, │ │ │ │ - insertDirectionLength: function(direction, length) { │ │ │ │ - if (this.handler && this.handler.line) { │ │ │ │ - this.handler.insertDirectionLength(direction, length) │ │ │ │ + showToggle: function(minimize) { │ │ │ │ + if (this.maximizeDiv) { │ │ │ │ + this.maximizeDiv.style.display = minimize ? "" : "none" │ │ │ │ } │ │ │ │ - }, │ │ │ │ - insertDeflectionLength: function(deflection, length) { │ │ │ │ - if (this.handler && this.handler.line) { │ │ │ │ - this.handler.insertDeflectionLength(deflection, length) │ │ │ │ + if (this.minimizeDiv) { │ │ │ │ + this.minimizeDiv.style.display = minimize ? "none" : "" │ │ │ │ } │ │ │ │ }, │ │ │ │ - undo: function() { │ │ │ │ - return this.handler.undo && this.handler.undo() │ │ │ │ - }, │ │ │ │ - redo: function() { │ │ │ │ - return this.handler.redo && this.handler.redo() │ │ │ │ - }, │ │ │ │ - finishSketch: function() { │ │ │ │ - this.handler.finishGeometry() │ │ │ │ - }, │ │ │ │ - cancel: function() { │ │ │ │ - this.handler.cancel() │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.DrawFeature" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.ZoomOut = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ - trigger: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.zoomOut() │ │ │ │ + update: function() { │ │ │ │ + if (this.ovmap == null) { │ │ │ │ + this.createMap() │ │ │ │ } │ │ │ │ + if (this.autoPan || !this.isSuitableOverview()) { │ │ │ │ + this.updateOverview() │ │ │ │ + } │ │ │ │ + this.updateRectToMap() │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomOut" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.UTFGrid = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - autoActivate: true, │ │ │ │ - layers: null, │ │ │ │ - defaultHandlerOptions: { │ │ │ │ - delay: 300, │ │ │ │ - pixelTolerance: 4, │ │ │ │ - stopMove: false, │ │ │ │ - single: true, │ │ │ │ - double: false, │ │ │ │ - stopSingle: false, │ │ │ │ - stopDouble: false │ │ │ │ - }, │ │ │ │ - handlerMode: "click", │ │ │ │ - setHandler: function(hm) { │ │ │ │ - this.handlerMode = hm; │ │ │ │ - this.resetHandler() │ │ │ │ - }, │ │ │ │ - resetHandler: function() { │ │ │ │ - if (this.handler) { │ │ │ │ - this.handler.deactivate(); │ │ │ │ - this.handler.destroy(); │ │ │ │ - this.handler = null │ │ │ │ + isSuitableOverview: function() { │ │ │ │ + var mapExtent = this.map.getExtent(); │ │ │ │ + var maxExtent = this.map.getMaxExtent(); │ │ │ │ + var testExtent = new OpenLayers.Bounds(Math.max(mapExtent.left, maxExtent.left), Math.max(mapExtent.bottom, maxExtent.bottom), Math.min(mapExtent.right, maxExtent.right), Math.min(mapExtent.top, maxExtent.top)); │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + testExtent = testExtent.transform(this.map.getProjectionObject(), this.ovmap.getProjectionObject()) │ │ │ │ } │ │ │ │ - if (this.handlerMode == "hover") { │ │ │ │ - this.handler = new OpenLayers.Handler.Hover(this, { │ │ │ │ - pause: this.handleEvent, │ │ │ │ - move: this.reset │ │ │ │ - }, this.handlerOptions) │ │ │ │ - } else if (this.handlerMode == "click") { │ │ │ │ - this.handler = new OpenLayers.Handler.Click(this, { │ │ │ │ - click: this.handleEvent │ │ │ │ - }, this.handlerOptions) │ │ │ │ - } else if (this.handlerMode == "move") { │ │ │ │ - this.handler = new OpenLayers.Handler.Hover(this, { │ │ │ │ - pause: this.handleEvent, │ │ │ │ - move: this.handleEvent │ │ │ │ - }, this.handlerOptions) │ │ │ │ + var resRatio = this.ovmap.getResolution() / this.map.getResolution(); │ │ │ │ + return resRatio > this.minRatio && resRatio <= this.maxRatio && this.ovmap.getExtent().containsBounds(testExtent) │ │ │ │ + }, │ │ │ │ + updateOverview: function() { │ │ │ │ + var mapRes = this.map.getResolution(); │ │ │ │ + var targetRes = this.ovmap.getResolution(); │ │ │ │ + var resRatio = targetRes / mapRes; │ │ │ │ + if (resRatio > this.maxRatio) { │ │ │ │ + targetRes = this.minRatio * mapRes │ │ │ │ + } else if (resRatio <= this.minRatio) { │ │ │ │ + targetRes = this.maxRatio * mapRes │ │ │ │ } │ │ │ │ - if (this.handler) { │ │ │ │ - return true │ │ │ │ + var center; │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + center = this.map.center.clone(); │ │ │ │ + center.transform(this.map.getProjectionObject(), this.ovmap.getProjectionObject()) │ │ │ │ } else { │ │ │ │ - return false │ │ │ │ + center = this.map.center │ │ │ │ } │ │ │ │ + this.ovmap.setCenter(center, this.ovmap.getZoomForResolution(targetRes * this.resolutionFactor)); │ │ │ │ + this.updateRectToMap() │ │ │ │ }, │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.handlerOptions = options.handlerOptions || this.defaultHandlerOptions; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.resetHandler() │ │ │ │ + createMap: function() { │ │ │ │ + var options = OpenLayers.Util.extend({ │ │ │ │ + controls: [], │ │ │ │ + maxResolution: "auto", │ │ │ │ + fallThrough: false │ │ │ │ + }, this.mapOptions); │ │ │ │ + this.ovmap = new OpenLayers.Map(this.mapDiv, options); │ │ │ │ + this.ovmap.viewPortDiv.appendChild(this.extentRectangle); │ │ │ │ + OpenLayers.Event.stopObserving(window, "unload", this.ovmap.unloadDestroy); │ │ │ │ + this.ovmap.addLayers(this.layers); │ │ │ │ + this.ovmap.zoomToMaxExtent(); │ │ │ │ + this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-left-width")) + parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-right-width")); │ │ │ │ + this.wComp = this.wComp ? this.wComp : 2; │ │ │ │ + this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-top-width")) + parseInt(OpenLayers.Element.getStyle(this.extentRectangle, "border-bottom-width")); │ │ │ │ + this.hComp = this.hComp ? this.hComp : 2; │ │ │ │ + this.handlers.drag = new OpenLayers.Handler.Drag(this, { │ │ │ │ + move: this.rectDrag, │ │ │ │ + done: this.updateMapToRect │ │ │ │ + }, { │ │ │ │ + map: this.ovmap │ │ │ │ + }); │ │ │ │ + this.handlers.click = new OpenLayers.Handler.Click(this, { │ │ │ │ + click: this.mapDivClick │ │ │ │ + }, { │ │ │ │ + single: true, │ │ │ │ + double: false, │ │ │ │ + stopSingle: true, │ │ │ │ + stopDouble: true, │ │ │ │ + pixelTolerance: 1, │ │ │ │ + map: this.ovmap │ │ │ │ + }); │ │ │ │ + this.handlers.click.activate(); │ │ │ │ + this.rectEvents = new OpenLayers.Events(this, this.extentRectangle, null, true); │ │ │ │ + this.rectEvents.register("mouseover", this, function(e) { │ │ │ │ + if (!this.handlers.drag.active && !this.map.dragging) { │ │ │ │ + this.handlers.drag.activate() │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.rectEvents.register("mouseout", this, function(e) { │ │ │ │ + if (!this.handlers.drag.dragging) { │ │ │ │ + this.handlers.drag.deactivate() │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + var sourceUnits = this.map.getProjectionObject().getUnits() || this.map.units || this.map.baseLayer.units; │ │ │ │ + var targetUnits = this.ovmap.getProjectionObject().getUnits() || this.ovmap.units || this.ovmap.baseLayer.units; │ │ │ │ + this.resolutionFactor = sourceUnits && targetUnits ? OpenLayers.INCHES_PER_UNIT[sourceUnits] / OpenLayers.INCHES_PER_UNIT[targetUnits] : 1 │ │ │ │ + } │ │ │ │ }, │ │ │ │ - handleEvent: function(evt) { │ │ │ │ - if (evt == null) { │ │ │ │ - this.reset(); │ │ │ │ - return │ │ │ │ + updateRectToMap: function() { │ │ │ │ + var bounds; │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + bounds = this.map.getExtent().transform(this.map.getProjectionObject(), this.ovmap.getProjectionObject()) │ │ │ │ + } else { │ │ │ │ + bounds = this.map.getExtent() │ │ │ │ } │ │ │ │ - var lonLat = this.map.getLonLatFromPixel(evt.xy); │ │ │ │ - if (!lonLat) { │ │ │ │ - return │ │ │ │ + var pxBounds = this.getRectBoundsFromMapBounds(bounds); │ │ │ │ + if (pxBounds) { │ │ │ │ + this.setRectPxBounds(pxBounds) │ │ │ │ } │ │ │ │ - var layers = this.findLayers(); │ │ │ │ - if (layers.length > 0) { │ │ │ │ - var infoLookup = {}; │ │ │ │ - var layer, idx; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - layer = layers[i]; │ │ │ │ - idx = OpenLayers.Util.indexOf(this.map.layers, layer); │ │ │ │ - infoLookup[idx] = layer.getFeatureInfo(lonLat) │ │ │ │ - } │ │ │ │ - this.callback(infoLookup, lonLat, evt.xy) │ │ │ │ + }, │ │ │ │ + updateMapToRect: function() { │ │ │ │ + var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds); │ │ │ │ + if (this.ovmap.getProjection() != this.map.getProjection()) { │ │ │ │ + lonLatBounds = lonLatBounds.transform(this.ovmap.getProjectionObject(), this.map.getProjectionObject()) │ │ │ │ } │ │ │ │ + this.map.panTo(lonLatBounds.getCenterLonLat()) │ │ │ │ }, │ │ │ │ - callback: function(infoLookup) {}, │ │ │ │ - reset: function(evt) { │ │ │ │ - this.callback(null) │ │ │ │ + setRectPxBounds: function(pxBounds) { │ │ │ │ + var top = Math.max(pxBounds.top, 0); │ │ │ │ + var left = Math.max(pxBounds.left, 0); │ │ │ │ + var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()), this.ovmap.size.h - this.hComp); │ │ │ │ + var right = Math.min(pxBounds.left + pxBounds.getWidth(), this.ovmap.size.w - this.wComp); │ │ │ │ + var width = Math.max(right - left, 0); │ │ │ │ + var height = Math.max(bottom - top, 0); │ │ │ │ + if (width < this.minRectSize || height < this.minRectSize) { │ │ │ │ + this.extentRectangle.className = this.displayClass + this.minRectDisplayClass; │ │ │ │ + var rLeft = left + width / 2 - this.minRectSize / 2; │ │ │ │ + var rTop = top + height / 2 - this.minRectSize / 2; │ │ │ │ + this.extentRectangle.style.top = Math.round(rTop) + "px"; │ │ │ │ + this.extentRectangle.style.left = Math.round(rLeft) + "px"; │ │ │ │ + this.extentRectangle.style.height = this.minRectSize + "px"; │ │ │ │ + this.extentRectangle.style.width = this.minRectSize + "px" │ │ │ │ + } else { │ │ │ │ + this.extentRectangle.className = this.displayClass + "ExtentRectangle"; │ │ │ │ + this.extentRectangle.style.top = Math.round(top) + "px"; │ │ │ │ + this.extentRectangle.style.left = Math.round(left) + "px"; │ │ │ │ + this.extentRectangle.style.height = Math.round(height) + "px"; │ │ │ │ + this.extentRectangle.style.width = Math.round(width) + "px" │ │ │ │ + } │ │ │ │ + this.rectPxBounds = new OpenLayers.Bounds(Math.round(left), Math.round(bottom), Math.round(right), Math.round(top)) │ │ │ │ }, │ │ │ │ - findLayers: function() { │ │ │ │ - var candidates = this.layers || this.map.layers; │ │ │ │ - var layers = []; │ │ │ │ - var layer; │ │ │ │ - for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ - layer = candidates[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.UTFGrid) { │ │ │ │ - layers.push(layer) │ │ │ │ - } │ │ │ │ + getRectBoundsFromMapBounds: function(lonLatBounds) { │ │ │ │ + var leftBottomPx = this.getOverviewPxFromLonLat({ │ │ │ │ + lon: lonLatBounds.left, │ │ │ │ + lat: lonLatBounds.bottom │ │ │ │ + }); │ │ │ │ + var rightTopPx = this.getOverviewPxFromLonLat({ │ │ │ │ + lon: lonLatBounds.right, │ │ │ │ + lat: lonLatBounds.top │ │ │ │ + }); │ │ │ │ + var bounds = null; │ │ │ │ + if (leftBottomPx && rightTopPx) { │ │ │ │ + bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y, rightTopPx.x, rightTopPx.y) │ │ │ │ } │ │ │ │ - return layers │ │ │ │ + return bounds │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.UTFGrid" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.EditingToolbar = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ - citeCompliant: false, │ │ │ │ - initialize: function(layer, options) { │ │ │ │ - OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ - this.addControls([new OpenLayers.Control.Navigation]); │ │ │ │ - var controls = [new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Point, { │ │ │ │ - displayClass: "olControlDrawFeaturePoint", │ │ │ │ - handlerOptions: { │ │ │ │ - citeCompliant: this.citeCompliant │ │ │ │ - } │ │ │ │ - }), new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Path, { │ │ │ │ - displayClass: "olControlDrawFeaturePath", │ │ │ │ - handlerOptions: { │ │ │ │ - citeCompliant: this.citeCompliant │ │ │ │ - } │ │ │ │ - }), new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Polygon, { │ │ │ │ - displayClass: "olControlDrawFeaturePolygon", │ │ │ │ - handlerOptions: { │ │ │ │ - citeCompliant: this.citeCompliant │ │ │ │ - } │ │ │ │ - })]; │ │ │ │ - this.addControls(controls) │ │ │ │ + getMapBoundsFromRectBounds: function(pxBounds) { │ │ │ │ + var leftBottomLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ + x: pxBounds.left, │ │ │ │ + y: pxBounds.bottom │ │ │ │ + }); │ │ │ │ + var rightTopLonLat = this.getLonLatFromOverviewPx({ │ │ │ │ + x: pxBounds.right, │ │ │ │ + y: pxBounds.top │ │ │ │ + }); │ │ │ │ + return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat, rightTopLonLat.lon, rightTopLonLat.lat) │ │ │ │ }, │ │ │ │ - draw: function() { │ │ │ │ - var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments); │ │ │ │ - if (this.defaultControl === null) { │ │ │ │ - this.defaultControl = this.controls[0] │ │ │ │ + getLonLatFromOverviewPx: function(overviewMapPx) { │ │ │ │ + var size = this.ovmap.size; │ │ │ │ + var res = this.ovmap.getResolution(); │ │ │ │ + var center = this.ovmap.getExtent().getCenterLonLat(); │ │ │ │ + var deltaX = overviewMapPx.x - size.w / 2; │ │ │ │ + var deltaY = overviewMapPx.y - size.h / 2; │ │ │ │ + return { │ │ │ │ + lon: center.lon + deltaX * res, │ │ │ │ + lat: center.lat - deltaY * res │ │ │ │ } │ │ │ │ - return div │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.EditingToolbar" │ │ │ │ + getOverviewPxFromLonLat: function(lonlat) { │ │ │ │ + var res = this.ovmap.getResolution(); │ │ │ │ + var extent = this.ovmap.getExtent(); │ │ │ │ + if (extent) { │ │ │ │ + return { │ │ │ │ + x: Math.round(1 / res * (lonlat.lon - extent.left)), │ │ │ │ + y: Math.round(1 / res * (extent.top - lonlat.lat)) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Control.OverviewMap" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.Zoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - zoomInText: "+", │ │ │ │ - zoomInId: "olZoomInLink", │ │ │ │ - zoomOutText: "−", │ │ │ │ - zoomOutId: "olZoomOutLink", │ │ │ │ - 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) │ │ │ │ +OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + callbacks: null, │ │ │ │ + displaySystem: "metric", │ │ │ │ + geodesic: false, │ │ │ │ + displaySystemUnits: { │ │ │ │ + geographic: ["dd"], │ │ │ │ + english: ["mi", "ft", "in"], │ │ │ │ + metric: ["km", "m"] │ │ │ │ + }, │ │ │ │ + partialDelay: 300, │ │ │ │ + delayedTrigger: null, │ │ │ │ + persist: false, │ │ │ │ + immediate: false, │ │ │ │ + initialize: function(handler, options) { │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ + var callbacks = { │ │ │ │ + done: this.measureComplete, │ │ │ │ + point: this.measurePartial │ │ │ │ + }; │ │ │ │ + if (this.immediate) { │ │ │ │ + callbacks.modify = this.measureImmediate │ │ │ │ } │ │ │ │ - eventsInstance.register("buttonclick", this, this.onZoomClick); │ │ │ │ - this.zoomInLink = zoomIn; │ │ │ │ - this.zoomOutLink = zoomOut; │ │ │ │ - return div │ │ │ │ + this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks); │ │ │ │ + this.handlerOptions = OpenLayers.Util.extend({ │ │ │ │ + persist: this.persist │ │ │ │ + }, this.handlerOptions); │ │ │ │ + this.handler = new handler(this, this.callbacks, this.handlerOptions) │ │ │ │ }, │ │ │ │ - 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) │ │ │ │ + deactivate: function() { │ │ │ │ + this.cancelDelay(); │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ + }, │ │ │ │ + cancel: function() { │ │ │ │ + this.cancelDelay(); │ │ │ │ + this.handler.cancel() │ │ │ │ + }, │ │ │ │ + setImmediate: function(immediate) { │ │ │ │ + this.immediate = immediate; │ │ │ │ + if (this.immediate) { │ │ │ │ + this.callbacks.modify = this.measureImmediate │ │ │ │ + } else { │ │ │ │ + delete this.callbacks.modify │ │ │ │ } │ │ │ │ - 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) │ │ │ │ + }, │ │ │ │ + updateHandler: function(handler, options) { │ │ │ │ + var active = this.active; │ │ │ │ + if (active) { │ │ │ │ + this.deactivate() │ │ │ │ } │ │ │ │ - OpenLayers.Element.addClass(zoomOut, "olButton"); │ │ │ │ - return { │ │ │ │ - zoomIn: zoomIn, │ │ │ │ - zoomOut: zoomOut │ │ │ │ + this.handler = new handler(this, this.callbacks, options); │ │ │ │ + if (active) { │ │ │ │ + this.activate() │ │ │ │ } │ │ │ │ }, │ │ │ │ - onZoomClick: function(evt) { │ │ │ │ - var button = evt.buttonElement; │ │ │ │ - if (button === this.zoomInLink) { │ │ │ │ - this.map.zoomIn() │ │ │ │ - } else if (button === this.zoomOutLink) { │ │ │ │ - this.map.zoomOut() │ │ │ │ + measureComplete: function(geometry) { │ │ │ │ + this.cancelDelay(); │ │ │ │ + this.measure(geometry, "measure") │ │ │ │ + }, │ │ │ │ + measurePartial: function(point, geometry) { │ │ │ │ + this.cancelDelay(); │ │ │ │ + geometry = geometry.clone(); │ │ │ │ + if (this.handler.freehandMode(this.handler.evt)) { │ │ │ │ + this.measure(geometry, "measurepartial") │ │ │ │ + } else { │ │ │ │ + this.delayedTrigger = window.setTimeout(OpenLayers.Function.bind(function() { │ │ │ │ + this.delayedTrigger = null; │ │ │ │ + this.measure(geometry, "measurepartial") │ │ │ │ + }, this), this.partialDelay) │ │ │ │ } │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.unregister("buttonclick", this, this.onZoomClick) │ │ │ │ + measureImmediate: function(point, feature, drawing) { │ │ │ │ + if (drawing && !this.handler.freehandMode(this.handler.evt)) { │ │ │ │ + this.cancelDelay(); │ │ │ │ + this.measure(feature.geometry, "measurepartial") │ │ │ │ } │ │ │ │ - delete this.zoomInLink; │ │ │ │ - delete this.zoomOutLink; │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Zoom" │ │ │ │ -}); │ │ │ │ -OpenLayers.Handler.Keyboard = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ - KEY_EVENTS: ["keydown", "keyup"], │ │ │ │ - eventListener: null, │ │ │ │ - observeElement: null, │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ - this.eventListener = OpenLayers.Function.bindAsEventListener(this.handleKeyEvent, this) │ │ │ │ + cancelDelay: function() { │ │ │ │ + if (this.delayedTrigger !== null) { │ │ │ │ + window.clearTimeout(this.delayedTrigger); │ │ │ │ + this.delayedTrigger = null │ │ │ │ + } │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - this.deactivate(); │ │ │ │ - this.eventListener = null; │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments) │ │ │ │ + measure: function(geometry, eventType) { │ │ │ │ + var stat, order; │ │ │ │ + if (geometry.CLASS_NAME.indexOf("LineString") > -1) { │ │ │ │ + stat = this.getBestLength(geometry); │ │ │ │ + order = 1 │ │ │ │ + } else { │ │ │ │ + stat = this.getBestArea(geometry); │ │ │ │ + order = 2 │ │ │ │ + } │ │ │ │ + this.events.triggerEvent(eventType, { │ │ │ │ + measure: stat[0], │ │ │ │ + units: stat[1], │ │ │ │ + order: order, │ │ │ │ + geometry: geometry │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - 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) │ │ │ │ + getBestArea: function(geometry) { │ │ │ │ + var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ + var unit, area; │ │ │ │ + for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ + unit = units[i]; │ │ │ │ + area = this.getArea(geometry, unit); │ │ │ │ + if (area > 1) { │ │ │ │ + break │ │ │ │ } │ │ │ │ - return true │ │ │ │ + } │ │ │ │ + return [area, unit] │ │ │ │ + }, │ │ │ │ + getArea: function(geometry, units) { │ │ │ │ + var area, geomUnits; │ │ │ │ + if (this.geodesic) { │ │ │ │ + area = geometry.getGeodesicArea(this.map.getProjectionObject()); │ │ │ │ + geomUnits = "m" │ │ │ │ } else { │ │ │ │ - return false │ │ │ │ + area = geometry.getArea(); │ │ │ │ + geomUnits = this.map.getUnits() │ │ │ │ + } │ │ │ │ + var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ + if (inPerDisplayUnit) { │ │ │ │ + var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ + area *= Math.pow(inPerMapUnit / inPerDisplayUnit, 2) │ │ │ │ } │ │ │ │ + return area │ │ │ │ }, │ │ │ │ - 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) │ │ │ │ + getBestLength: function(geometry) { │ │ │ │ + var units = this.displaySystemUnits[this.displaySystem]; │ │ │ │ + var unit, length; │ │ │ │ + for (var i = 0, len = units.length; i < len; ++i) { │ │ │ │ + unit = units[i]; │ │ │ │ + length = this.getLength(geometry, unit); │ │ │ │ + if (length > 1) { │ │ │ │ + break │ │ │ │ } │ │ │ │ - deactivated = true │ │ │ │ } │ │ │ │ - return deactivated │ │ │ │ + return [length, unit] │ │ │ │ }, │ │ │ │ - handleKeyEvent: function(evt) { │ │ │ │ - if (this.checkModifiers(evt)) { │ │ │ │ - this.callback(evt.type, [evt]) │ │ │ │ + getLength: function(geometry, units) { │ │ │ │ + var length, geomUnits; │ │ │ │ + if (this.geodesic) { │ │ │ │ + length = geometry.getGeodesicLength(this.map.getProjectionObject()); │ │ │ │ + geomUnits = "m" │ │ │ │ + } else { │ │ │ │ + length = geometry.getLength(); │ │ │ │ + geomUnits = this.map.getUnits() │ │ │ │ + } │ │ │ │ + var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units]; │ │ │ │ + if (inPerDisplayUnit) { │ │ │ │ + var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits]; │ │ │ │ + length *= inPerMapUnit / inPerDisplayUnit │ │ │ │ } │ │ │ │ + return length │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Keyboard" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Measure" │ │ │ │ }); │ │ │ │ OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ documentDrag: false, │ │ │ │ geometryTypes: null, │ │ │ │ clickout: true, │ │ │ │ toggle: true, │ │ │ │ standalone: false, │ │ │ │ @@ -28824,835 +34162,14 @@ │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.ModifyFeature" │ │ │ │ }); │ │ │ │ OpenLayers.Control.ModifyFeature.RESHAPE = 1; │ │ │ │ OpenLayers.Control.ModifyFeature.RESIZE = 2; │ │ │ │ OpenLayers.Control.ModifyFeature.ROTATE = 4; │ │ │ │ OpenLayers.Control.ModifyFeature.DRAG = 8; │ │ │ │ -OpenLayers.Control.Pan = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ - slideFactor: 50, │ │ │ │ - slideRatio: null, │ │ │ │ - direction: null, │ │ │ │ - initialize: function(direction, options) { │ │ │ │ - this.direction = direction; │ │ │ │ - this.CLASS_NAME += this.direction; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - trigger: function() { │ │ │ │ - if (this.map) { │ │ │ │ - var getSlideFactor = OpenLayers.Function.bind(function(dim) { │ │ │ │ - return this.slideRatio ? this.map.getSize()[dim] * this.slideRatio : this.slideFactor │ │ │ │ - }, this); │ │ │ │ - switch (this.direction) { │ │ │ │ - case OpenLayers.Control.Pan.NORTH: │ │ │ │ - this.map.pan(0, -getSlideFactor("h")); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Control.Pan.SOUTH: │ │ │ │ - this.map.pan(0, getSlideFactor("h")); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Control.Pan.WEST: │ │ │ │ - this.map.pan(-getSlideFactor("w"), 0); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Control.Pan.EAST: │ │ │ │ - this.map.pan(getSlideFactor("w"), 0); │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.Pan" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.Pan.NORTH = "North"; │ │ │ │ -OpenLayers.Control.Pan.SOUTH = "South"; │ │ │ │ -OpenLayers.Control.Pan.EAST = "East"; │ │ │ │ -OpenLayers.Control.Pan.WEST = "West"; │ │ │ │ -OpenLayers.Control.PanPanel = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ - slideFactor: 50, │ │ │ │ - slideRatio: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ - var options = { │ │ │ │ - slideFactor: this.slideFactor, │ │ │ │ - slideRatio: this.slideRatio │ │ │ │ - }; │ │ │ │ - this.addControls([new OpenLayers.Control.Pan(OpenLayers.Control.Pan.NORTH, options), new OpenLayers.Control.Pan(OpenLayers.Control.Pan.SOUTH, options), new OpenLayers.Control.Pan(OpenLayers.Control.Pan.EAST, options), new OpenLayers.Control.Pan(OpenLayers.Control.Pan.WEST, options)]) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.PanPanel" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.GetFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - protocol: null, │ │ │ │ - multipleKey: null, │ │ │ │ - toggleKey: null, │ │ │ │ - modifiers: null, │ │ │ │ - multiple: false, │ │ │ │ - click: true, │ │ │ │ - single: true, │ │ │ │ - clickout: true, │ │ │ │ - toggle: false, │ │ │ │ - clickTolerance: 5, │ │ │ │ - hover: false, │ │ │ │ - box: false, │ │ │ │ - maxFeatures: 10, │ │ │ │ - features: null, │ │ │ │ - hoverFeature: null, │ │ │ │ - handlers: null, │ │ │ │ - hoverResponse: null, │ │ │ │ - filterType: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ - initialize: function(options) { │ │ │ │ - options.handlerOptions = options.handlerOptions || {}; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - this.features = {}; │ │ │ │ - this.handlers = {}; │ │ │ │ - if (this.click) { │ │ │ │ - this.handlers.click = new OpenLayers.Handler.Click(this, { │ │ │ │ - click: this.selectClick │ │ │ │ - }, this.handlerOptions.click || {}) │ │ │ │ - } │ │ │ │ - if (this.box) { │ │ │ │ - this.handlers.box = new OpenLayers.Handler.Box(this, { │ │ │ │ - done: this.selectBox │ │ │ │ - }, OpenLayers.Util.extend(this.handlerOptions.box, { │ │ │ │ - boxDivClassName: "olHandlerBoxSelectFeature" │ │ │ │ - })) │ │ │ │ - } │ │ │ │ - if (this.hover) { │ │ │ │ - this.handlers.hover = new OpenLayers.Handler.Hover(this, { │ │ │ │ - move: this.cancelHover, │ │ │ │ - pause: this.selectHover │ │ │ │ - }, OpenLayers.Util.extend(this.handlerOptions.hover, { │ │ │ │ - delay: 250, │ │ │ │ - pixelTolerance: 2 │ │ │ │ - })) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (!this.active) { │ │ │ │ - for (var i in this.handlers) { │ │ │ │ - this.handlers[i].activate() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return OpenLayers.Control.prototype.activate.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (this.active) { │ │ │ │ - for (var i in this.handlers) { │ │ │ │ - this.handlers[i].deactivate() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return OpenLayers.Control.prototype.deactivate.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - selectClick: function(evt) { │ │ │ │ - var bounds = this.pixelToBounds(evt.xy); │ │ │ │ - this.setModifiers(evt); │ │ │ │ - this.request(bounds, { │ │ │ │ - single: this.single │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - selectBox: function(position) { │ │ │ │ - var bounds; │ │ │ │ - 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 │ │ │ │ - }); │ │ │ │ - bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat, maxXY.lon, maxXY.lat) │ │ │ │ - } else { │ │ │ │ - if (this.click) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - bounds = this.pixelToBounds(position) │ │ │ │ - } │ │ │ │ - this.setModifiers(this.handlers.box.dragHandler.evt); │ │ │ │ - this.request(bounds) │ │ │ │ - }, │ │ │ │ - selectHover: function(evt) { │ │ │ │ - var bounds = this.pixelToBounds(evt.xy); │ │ │ │ - this.request(bounds, { │ │ │ │ - single: true, │ │ │ │ - hover: true │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - cancelHover: function() { │ │ │ │ - if (this.hoverResponse) { │ │ │ │ - this.protocol.abort(this.hoverResponse); │ │ │ │ - this.hoverResponse = null; │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait") │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - request: function(bounds, options) { │ │ │ │ - options = options || {}; │ │ │ │ - var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: this.filterType, │ │ │ │ - value: bounds │ │ │ │ - }); │ │ │ │ - OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - var response = this.protocol.read({ │ │ │ │ - maxFeatures: options.single == true ? this.maxFeatures : undefined, │ │ │ │ - filter: filter, │ │ │ │ - callback: function(result) { │ │ │ │ - if (result.success()) { │ │ │ │ - if (result.features.length) { │ │ │ │ - if (options.single == true) { │ │ │ │ - this.selectBestFeature(result.features, bounds.getCenterLonLat(), options) │ │ │ │ - } else { │ │ │ │ - this.select(result.features) │ │ │ │ - } │ │ │ │ - } else if (options.hover) { │ │ │ │ - this.hoverSelect() │ │ │ │ - } else { │ │ │ │ - this.events.triggerEvent("clickout"); │ │ │ │ - if (this.clickout) { │ │ │ │ - this.unselectAll() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait") │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - if (options.hover == true) { │ │ │ │ - this.hoverResponse = response │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - selectBestFeature: function(features, clickPosition, options) { │ │ │ │ - options = options || {}; │ │ │ │ - if (features.length) { │ │ │ │ - var point = new OpenLayers.Geometry.Point(clickPosition.lon, clickPosition.lat); │ │ │ │ - var feature, resultFeature, dist; │ │ │ │ - var minDist = Number.MAX_VALUE; │ │ │ │ - for (var i = 0; i < features.length; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - if (feature.geometry) { │ │ │ │ - dist = point.distanceTo(feature.geometry, { │ │ │ │ - edge: false │ │ │ │ - }); │ │ │ │ - if (dist < minDist) { │ │ │ │ - minDist = dist; │ │ │ │ - resultFeature = feature; │ │ │ │ - if (minDist == 0) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (options.hover == true) { │ │ │ │ - this.hoverSelect(resultFeature) │ │ │ │ - } else { │ │ │ │ - this.select(resultFeature || features) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setModifiers: function(evt) { │ │ │ │ - this.modifiers = { │ │ │ │ - multiple: this.multiple || this.multipleKey && evt[this.multipleKey], │ │ │ │ - toggle: this.toggle || this.toggleKey && evt[this.toggleKey] │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - select: function(features) { │ │ │ │ - if (!this.modifiers.multiple && !this.modifiers.toggle) { │ │ │ │ - this.unselectAll() │ │ │ │ - } │ │ │ │ - if (!OpenLayers.Util.isArray(features)) { │ │ │ │ - features = [features] │ │ │ │ - } │ │ │ │ - var cont = this.events.triggerEvent("beforefeaturesselected", { │ │ │ │ - features: features │ │ │ │ - }); │ │ │ │ - if (cont !== false) { │ │ │ │ - var selectedFeatures = []; │ │ │ │ - var feature; │ │ │ │ - for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - if (this.features[feature.fid || feature.id]) { │ │ │ │ - if (this.modifiers.toggle) { │ │ │ │ - this.unselect(this.features[feature.fid || feature.id]) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - cont = this.events.triggerEvent("beforefeatureselected", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - if (cont !== false) { │ │ │ │ - this.features[feature.fid || feature.id] = feature; │ │ │ │ - selectedFeatures.push(feature); │ │ │ │ - this.events.triggerEvent("featureselected", { │ │ │ │ - feature: feature │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.events.triggerEvent("featuresselected", { │ │ │ │ - features: selectedFeatures │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - hoverSelect: function(feature) { │ │ │ │ - var fid = feature ? feature.fid || feature.id : null; │ │ │ │ - var hfid = this.hoverFeature ? this.hoverFeature.fid || this.hoverFeature.id : null; │ │ │ │ - if (hfid && hfid != fid) { │ │ │ │ - this.events.triggerEvent("outfeature", { │ │ │ │ - feature: this.hoverFeature │ │ │ │ - }); │ │ │ │ - this.hoverFeature = null │ │ │ │ - } │ │ │ │ - if (fid && fid != hfid) { │ │ │ │ - this.events.triggerEvent("hoverfeature", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - this.hoverFeature = feature │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - unselect: function(feature) { │ │ │ │ - delete this.features[feature.fid || feature.id]; │ │ │ │ - this.events.triggerEvent("featureunselected", { │ │ │ │ - feature: feature │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - unselectAll: function() { │ │ │ │ - for (var fid in this.features) { │ │ │ │ - this.unselect(this.features[fid]) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - for (var i in this.handlers) { │ │ │ │ - this.handlers[i].setMap(map) │ │ │ │ - } │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - pixelToBounds: function(pixel) { │ │ │ │ - var llPx = pixel.add(-this.clickTolerance / 2, this.clickTolerance / 2); │ │ │ │ - var urPx = pixel.add(this.clickTolerance / 2, -this.clickTolerance / 2); │ │ │ │ - var ll = this.map.getLonLatFromPixel(llPx); │ │ │ │ - var ur = this.map.getLonLatFromPixel(urPx); │ │ │ │ - return new OpenLayers.Bounds(ll.lon, ll.lat, ur.lon, ur.lat) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.GetFeature" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.ZoomToMaxExtent = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ - trigger: function() { │ │ │ │ - if (this.map) { │ │ │ │ - this.map.zoomToMaxExtent() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomToMaxExtent" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.CacheRead = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - fetchEvent: "tileloadstart", │ │ │ │ - layers: null, │ │ │ │ - autoActivate: true, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - var i, layers = this.layers || map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.addLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - if (!this.layers) { │ │ │ │ - map.events.on({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - addLayer: function(evt) { │ │ │ │ - evt.layer.events.register(this.fetchEvent, this, this.fetch) │ │ │ │ - }, │ │ │ │ - removeLayer: function(evt) { │ │ │ │ - evt.layer.events.unregister(this.fetchEvent, this, this.fetch) │ │ │ │ - }, │ │ │ │ - fetch: function(evt) { │ │ │ │ - if (this.active && window.localStorage && evt.tile instanceof OpenLayers.Tile.Image) { │ │ │ │ - var tile = evt.tile, │ │ │ │ - url = tile.url; │ │ │ │ - if (!tile.layer.crossOriginKeyword && OpenLayers.ProxyHost && url.indexOf(OpenLayers.ProxyHost) === 0) { │ │ │ │ - url = OpenLayers.Control.CacheWrite.urlMap[url] │ │ │ │ - } │ │ │ │ - var dataURI = window.localStorage.getItem("olCache_" + url); │ │ │ │ - if (dataURI) { │ │ │ │ - tile.url = dataURI; │ │ │ │ - if (evt.type === "tileerror") { │ │ │ │ - tile.setImgSrc(dataURI) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.layers || this.map) { │ │ │ │ - var i, layers = this.layers || this.map.layers; │ │ │ │ - for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ - this.removeLayer({ │ │ │ │ - layer: layers[i] │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.map) { │ │ │ │ - this.map.events.un({ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ - removeLayer: this.removeLayer, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.CacheRead" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.LayerSwitcher = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - layerStates: null, │ │ │ │ - layersDiv: null, │ │ │ │ - baseLayersDiv: null, │ │ │ │ - baseLayers: null, │ │ │ │ - dataLbl: null, │ │ │ │ - dataLayersDiv: null, │ │ │ │ - dataLayers: null, │ │ │ │ - minimizeDiv: null, │ │ │ │ - maximizeDiv: null, │ │ │ │ - ascending: true, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ - this.layerStates = [] │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.clearLayersArray("base"); │ │ │ │ - this.clearLayersArray("data"); │ │ │ │ - this.map.events.un({ │ │ │ │ - buttonclick: this.onButtonClick, │ │ │ │ - addlayer: this.redraw, │ │ │ │ - changelayer: this.redraw, │ │ │ │ - removelayer: this.redraw, │ │ │ │ - changebaselayer: this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - setMap: function(map) { │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ - this.map.events.on({ │ │ │ │ - addlayer: this.redraw, │ │ │ │ - changelayer: this.redraw, │ │ │ │ - removelayer: this.redraw, │ │ │ │ - changebaselayer: this.redraw, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - if (this.outsideViewport) { │ │ │ │ - this.events.attachToElement(this.div); │ │ │ │ - this.events.register("buttonclick", this, this.onButtonClick) │ │ │ │ - } else { │ │ │ │ - this.map.events.register("buttonclick", this, this.onButtonClick) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - draw: function() { │ │ │ │ - OpenLayers.Control.prototype.draw.apply(this); │ │ │ │ - this.loadContents(); │ │ │ │ - if (!this.outsideViewport) { │ │ │ │ - this.minimizeControl() │ │ │ │ - } │ │ │ │ - this.redraw(); │ │ │ │ - return this.div │ │ │ │ - }, │ │ │ │ - onButtonClick: function(evt) { │ │ │ │ - var button = evt.buttonElement; │ │ │ │ - if (button === this.minimizeDiv) { │ │ │ │ - this.minimizeControl() │ │ │ │ - } else if (button === this.maximizeDiv) { │ │ │ │ - this.maximizeControl() │ │ │ │ - } else if (button._layerSwitcher === this.id) { │ │ │ │ - if (button["for"]) { │ │ │ │ - button = document.getElementById(button["for"]) │ │ │ │ - } │ │ │ │ - if (!button.disabled) { │ │ │ │ - if (button.type == "radio") { │ │ │ │ - button.checked = true; │ │ │ │ - this.map.setBaseLayer(this.map.getLayer(button._layer)) │ │ │ │ - } else { │ │ │ │ - button.checked = !button.checked; │ │ │ │ - this.updateMap() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clearLayersArray: function(layersType) { │ │ │ │ - this[layersType + "LayersDiv"].innerHTML = ""; │ │ │ │ - this[layersType + "Layers"] = [] │ │ │ │ - }, │ │ │ │ - checkRedraw: function() { │ │ │ │ - if (!this.layerStates.length || this.map.layers.length != this.layerStates.length) { │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - for (var i = 0, len = this.layerStates.length; i < len; i++) { │ │ │ │ - var layerState = this.layerStates[i]; │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - if (layerState.name != layer.name || layerState.inRange != layer.inRange || layerState.id != layer.id || layerState.visibility != layer.visibility) { │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - redraw: function() { │ │ │ │ - if (!this.checkRedraw()) { │ │ │ │ - return this.div │ │ │ │ - } │ │ │ │ - this.clearLayersArray("base"); │ │ │ │ - this.clearLayersArray("data"); │ │ │ │ - var containsOverlays = false; │ │ │ │ - var containsBaseLayers = false; │ │ │ │ - var len = this.map.layers.length; │ │ │ │ - this.layerStates = new Array(len); │ │ │ │ - for (var i = 0; i < len; i++) { │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ - this.layerStates[i] = { │ │ │ │ - name: layer.name, │ │ │ │ - visibility: layer.visibility, │ │ │ │ - inRange: layer.inRange, │ │ │ │ - id: layer.id │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var layers = this.map.layers.slice(); │ │ │ │ - if (!this.ascending) { │ │ │ │ - layers.reverse() │ │ │ │ - } │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - var layer = layers[i]; │ │ │ │ - var baseLayer = layer.isBaseLayer; │ │ │ │ - if (layer.displayInLayerSwitcher) { │ │ │ │ - if (baseLayer) { │ │ │ │ - containsBaseLayers = true │ │ │ │ - } else { │ │ │ │ - containsOverlays = true │ │ │ │ - } │ │ │ │ - var checked = baseLayer ? layer == this.map.baseLayer : layer.getVisibility(); │ │ │ │ - var inputElem = document.createElement("input"), │ │ │ │ - inputId = OpenLayers.Util.createUniqueID(this.id + "_input_"); │ │ │ │ - inputElem.id = inputId; │ │ │ │ - inputElem.name = baseLayer ? this.id + "_baseLayers" : layer.name; │ │ │ │ - inputElem.type = baseLayer ? "radio" : "checkbox"; │ │ │ │ - inputElem.value = layer.name; │ │ │ │ - inputElem.checked = checked; │ │ │ │ - inputElem.defaultChecked = checked; │ │ │ │ - inputElem.className = "olButton"; │ │ │ │ - inputElem._layer = layer.id; │ │ │ │ - inputElem._layerSwitcher = this.id; │ │ │ │ - if (!baseLayer && !layer.inRange) { │ │ │ │ - inputElem.disabled = true │ │ │ │ - } │ │ │ │ - var labelSpan = document.createElement("label"); │ │ │ │ - labelSpan["for"] = inputElem.id; │ │ │ │ - OpenLayers.Element.addClass(labelSpan, "labelSpan olButton"); │ │ │ │ - labelSpan._layer = layer.id; │ │ │ │ - labelSpan._layerSwitcher = this.id; │ │ │ │ - if (!baseLayer && !layer.inRange) { │ │ │ │ - labelSpan.style.color = "gray" │ │ │ │ - } │ │ │ │ - labelSpan.innerHTML = layer.name; │ │ │ │ - labelSpan.style.verticalAlign = baseLayer ? "bottom" : "baseline"; │ │ │ │ - var br = document.createElement("br"); │ │ │ │ - var groupArray = baseLayer ? this.baseLayers : this.dataLayers; │ │ │ │ - groupArray.push({ │ │ │ │ - layer: layer, │ │ │ │ - inputElem: inputElem, │ │ │ │ - labelSpan: labelSpan │ │ │ │ - }); │ │ │ │ - var groupDiv = baseLayer ? this.baseLayersDiv : this.dataLayersDiv; │ │ │ │ - groupDiv.appendChild(inputElem); │ │ │ │ - groupDiv.appendChild(labelSpan); │ │ │ │ - groupDiv.appendChild(br) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.dataLbl.style.display = containsOverlays ? "" : "none"; │ │ │ │ - this.baseLbl.style.display = containsBaseLayers ? "" : "none"; │ │ │ │ - return this.div │ │ │ │ - }, │ │ │ │ - updateMap: function() { │ │ │ │ - for (var i = 0, len = this.baseLayers.length; i < len; i++) { │ │ │ │ - var layerEntry = this.baseLayers[i]; │ │ │ │ - if (layerEntry.inputElem.checked) { │ │ │ │ - this.map.setBaseLayer(layerEntry.layer, false) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - for (var i = 0, len = this.dataLayers.length; i < len; i++) { │ │ │ │ - var layerEntry = this.dataLayers[i]; │ │ │ │ - layerEntry.layer.setVisibility(layerEntry.inputElem.checked) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - maximizeControl: function(e) { │ │ │ │ - this.div.style.width = ""; │ │ │ │ - this.div.style.height = ""; │ │ │ │ - this.showControls(false); │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - minimizeControl: function(e) { │ │ │ │ - this.div.style.width = "0px"; │ │ │ │ - this.div.style.height = "0px"; │ │ │ │ - this.showControls(true); │ │ │ │ - if (e != null) { │ │ │ │ - OpenLayers.Event.stop(e) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - showControls: function(minimize) { │ │ │ │ - this.maximizeDiv.style.display = minimize ? "" : "none"; │ │ │ │ - this.minimizeDiv.style.display = minimize ? "none" : ""; │ │ │ │ - this.layersDiv.style.display = minimize ? "none" : "" │ │ │ │ - }, │ │ │ │ - loadContents: function() { │ │ │ │ - this.layersDiv = document.createElement("div"); │ │ │ │ - this.layersDiv.id = this.id + "_layersDiv"; │ │ │ │ - OpenLayers.Element.addClass(this.layersDiv, "layersDiv"); │ │ │ │ - this.baseLbl = document.createElement("div"); │ │ │ │ - this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer"); │ │ │ │ - OpenLayers.Element.addClass(this.baseLbl, "baseLbl"); │ │ │ │ - this.baseLayersDiv = document.createElement("div"); │ │ │ │ - OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv"); │ │ │ │ - this.dataLbl = document.createElement("div"); │ │ │ │ - this.dataLbl.innerHTML = OpenLayers.i18n("Overlays"); │ │ │ │ - OpenLayers.Element.addClass(this.dataLbl, "dataLbl"); │ │ │ │ - this.dataLayersDiv = document.createElement("div"); │ │ │ │ - OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv"); │ │ │ │ - if (this.ascending) { │ │ │ │ - this.layersDiv.appendChild(this.baseLbl); │ │ │ │ - this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ - this.layersDiv.appendChild(this.dataLbl); │ │ │ │ - this.layersDiv.appendChild(this.dataLayersDiv) │ │ │ │ - } else { │ │ │ │ - this.layersDiv.appendChild(this.dataLbl); │ │ │ │ - this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ - this.layersDiv.appendChild(this.baseLbl); │ │ │ │ - this.layersDiv.appendChild(this.baseLayersDiv) │ │ │ │ - } │ │ │ │ - this.div.appendChild(this.layersDiv); │ │ │ │ - var img = OpenLayers.Util.getImageLocation("layer-switcher-maximize.png"); │ │ │ │ - this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MaximizeDiv", null, null, img, "absolute"); │ │ │ │ - OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv olButton"); │ │ │ │ - this.maximizeDiv.style.display = "none"; │ │ │ │ - this.div.appendChild(this.maximizeDiv); │ │ │ │ - var img = OpenLayers.Util.getImageLocation("layer-switcher-minimize.png"); │ │ │ │ - this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MinimizeDiv", null, null, img, "absolute"); │ │ │ │ - OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton"); │ │ │ │ - this.minimizeDiv.style.display = "none"; │ │ │ │ - this.div.appendChild(this.minimizeDiv) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.LayerSwitcher" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.ZoomPanel = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ - this.addControls([new OpenLayers.Control.ZoomIn, new OpenLayers.Control.ZoomToMaxExtent, new OpenLayers.Control.ZoomOut]) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.ZoomPanel" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.WMTSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - hover: false, │ │ │ │ - requestEncoding: "KVP", │ │ │ │ - drillDown: false, │ │ │ │ - maxFeatures: 10, │ │ │ │ - clickCallback: "click", │ │ │ │ - layers: null, │ │ │ │ - queryVisible: true, │ │ │ │ - infoFormat: "text/html", │ │ │ │ - vendorParams: {}, │ │ │ │ - format: null, │ │ │ │ - formatOptions: null, │ │ │ │ - handler: null, │ │ │ │ - hoverRequest: null, │ │ │ │ - pending: 0, │ │ │ │ - initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - options.handlerOptions = options.handlerOptions || {}; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ - if (!this.format) { │ │ │ │ - this.format = new OpenLayers.Format.WMSGetFeatureInfo(options.formatOptions) │ │ │ │ - } │ │ │ │ - if (this.drillDown === true) { │ │ │ │ - this.hover = false │ │ │ │ - } │ │ │ │ - if (this.hover) { │ │ │ │ - this.handler = new OpenLayers.Handler.Hover(this, { │ │ │ │ - move: this.cancelHover, │ │ │ │ - pause: this.getInfoForHover │ │ │ │ - }, OpenLayers.Util.extend(this.handlerOptions.hover || {}, { │ │ │ │ - delay: 250 │ │ │ │ - })) │ │ │ │ - } else { │ │ │ │ - var callbacks = {}; │ │ │ │ - callbacks[this.clickCallback] = this.getInfoForClick; │ │ │ │ - this.handler = new OpenLayers.Handler.Click(this, callbacks, this.handlerOptions.click || {}) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getInfoForClick: function(evt) { │ │ │ │ - this.request(evt.xy, {}) │ │ │ │ - }, │ │ │ │ - getInfoForHover: function(evt) { │ │ │ │ - this.request(evt.xy, { │ │ │ │ - hover: true │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - cancelHover: function() { │ │ │ │ - if (this.hoverRequest) { │ │ │ │ - --this.pending; │ │ │ │ - if (this.pending <= 0) { │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - this.pending = 0 │ │ │ │ - } │ │ │ │ - this.hoverRequest.abort(); │ │ │ │ - this.hoverRequest = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - findLayers: function() { │ │ │ │ - var candidates = this.layers || this.map.layers; │ │ │ │ - var layers = []; │ │ │ │ - var layer; │ │ │ │ - for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ - layer = candidates[i]; │ │ │ │ - if (layer instanceof OpenLayers.Layer.WMTS && layer.requestEncoding === this.requestEncoding && (!this.queryVisible || layer.getVisibility())) { │ │ │ │ - layers.push(layer); │ │ │ │ - if (!this.drillDown || this.hover) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return layers │ │ │ │ - }, │ │ │ │ - buildRequestOptions: function(layer, xy) { │ │ │ │ - var loc = this.map.getLonLatFromPixel(xy); │ │ │ │ - var getTileUrl = layer.getURL(new OpenLayers.Bounds(loc.lon, loc.lat, loc.lon, loc.lat)); │ │ │ │ - var params = OpenLayers.Util.getParameters(getTileUrl); │ │ │ │ - var tileInfo = layer.getTileInfo(loc); │ │ │ │ - OpenLayers.Util.extend(params, { │ │ │ │ - service: "WMTS", │ │ │ │ - version: layer.version, │ │ │ │ - request: "GetFeatureInfo", │ │ │ │ - infoFormat: this.infoFormat, │ │ │ │ - i: tileInfo.i, │ │ │ │ - j: tileInfo.j │ │ │ │ - }); │ │ │ │ - OpenLayers.Util.applyDefaults(params, this.vendorParams); │ │ │ │ - return { │ │ │ │ - url: OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url, │ │ │ │ - params: OpenLayers.Util.upperCaseObject(params), │ │ │ │ - callback: function(request) { │ │ │ │ - this.handleResponse(xy, request, layer) │ │ │ │ - }, │ │ │ │ - scope: this │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - request: function(xy, options) { │ │ │ │ - options = options || {}; │ │ │ │ - var layers = this.findLayers(); │ │ │ │ - if (layers.length > 0) { │ │ │ │ - var issue, layer; │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ - layer = layers[i]; │ │ │ │ - issue = this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ - xy: xy, │ │ │ │ - layer: layer │ │ │ │ - }); │ │ │ │ - if (issue !== false) { │ │ │ │ - ++this.pending; │ │ │ │ - var requestOptions = this.buildRequestOptions(layer, xy); │ │ │ │ - var request = OpenLayers.Request.GET(requestOptions); │ │ │ │ - if (options.hover === true) { │ │ │ │ - this.hoverRequest = request │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (this.pending > 0) { │ │ │ │ - OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - handleResponse: function(xy, request, layer) { │ │ │ │ - --this.pending; │ │ │ │ - if (this.pending <= 0) { │ │ │ │ - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ - this.pending = 0 │ │ │ │ - } │ │ │ │ - if (request.status && (request.status < 200 || request.status >= 300)) { │ │ │ │ - this.events.triggerEvent("exception", { │ │ │ │ - xy: xy, │ │ │ │ - request: request, │ │ │ │ - layer: layer │ │ │ │ - }) │ │ │ │ - } else { │ │ │ │ - var doc = request.responseXML; │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ - doc = request.responseText │ │ │ │ - } │ │ │ │ - var features, except; │ │ │ │ - try { │ │ │ │ - features = this.format.read(doc) │ │ │ │ - } catch (error) { │ │ │ │ - except = true; │ │ │ │ - this.events.triggerEvent("exception", { │ │ │ │ - xy: xy, │ │ │ │ - request: request, │ │ │ │ - error: error, │ │ │ │ - layer: layer │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - if (!except) { │ │ │ │ - this.events.triggerEvent("getfeatureinfo", { │ │ │ │ - text: request.responseText, │ │ │ │ - features: features, │ │ │ │ - request: request, │ │ │ │ - xy: xy, │ │ │ │ - layer: layer │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.WMTSGetFeatureInfo" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.Attribution = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - separator: ", ", │ │ │ │ - template: "${layers}", │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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()) { │ │ │ │ - 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.Control.Split = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ layer: null, │ │ │ │ source: null, │ │ │ │ sourceOptions: null, │ │ │ │ tolerance: null, │ │ │ │ edge: true, │ │ │ │ deferDelete: false, │ │ │ │ @@ -29870,2916 +34387,306 @@ │ │ │ │ if (this.active) { │ │ │ │ this.deactivate() │ │ │ │ } │ │ │ │ OpenLayers.Control.prototype.destroy.call(this) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Control.Split" │ │ │ │ }); │ │ │ │ -OpenLayers.Control.KeyboardDefaults = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ +OpenLayers.Control.NavigationHistory = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + type: OpenLayers.Control.TYPE_TOGGLE, │ │ │ │ + previous: null, │ │ │ │ + previousOptions: null, │ │ │ │ + next: null, │ │ │ │ + nextOptions: null, │ │ │ │ + limit: 50, │ │ │ │ autoActivate: true, │ │ │ │ - slideFactor: 75, │ │ │ │ - observeElement: null, │ │ │ │ - draw: function() { │ │ │ │ - var observeElement = this.observeElement || document; │ │ │ │ - this.handler = new OpenLayers.Handler.Keyboard(this, { │ │ │ │ - keydown: this.defaultKeyPress │ │ │ │ - }, { │ │ │ │ - observeElement: observeElement │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - defaultKeyPress: function(evt) { │ │ │ │ - var size, handled = true; │ │ │ │ - var target = OpenLayers.Event.element(evt); │ │ │ │ - if (target && (target.tagName == "INPUT" || target.tagName == "TEXTAREA" || target.tagName == "SELECT")) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - switch (evt.keyCode) { │ │ │ │ - case OpenLayers.Event.KEY_LEFT: │ │ │ │ - this.map.pan(-this.slideFactor, 0); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Event.KEY_RIGHT: │ │ │ │ - this.map.pan(this.slideFactor, 0); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Event.KEY_UP: │ │ │ │ - this.map.pan(0, -this.slideFactor); │ │ │ │ - break; │ │ │ │ - case OpenLayers.Event.KEY_DOWN: │ │ │ │ - this.map.pan(0, this.slideFactor); │ │ │ │ - break; │ │ │ │ - case 33: │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(0, -.75 * size.h); │ │ │ │ - break; │ │ │ │ - case 34: │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(0, .75 * size.h); │ │ │ │ - break; │ │ │ │ - case 35: │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(.75 * size.w, 0); │ │ │ │ - break; │ │ │ │ - case 36: │ │ │ │ - size = this.map.getSize(); │ │ │ │ - this.map.pan(-.75 * size.w, 0); │ │ │ │ - break; │ │ │ │ - case 43: │ │ │ │ - case 61: │ │ │ │ - case 187: │ │ │ │ - case 107: │ │ │ │ - this.map.zoomIn(); │ │ │ │ - break; │ │ │ │ - case 45: │ │ │ │ - case 109: │ │ │ │ - case 189: │ │ │ │ - case 95: │ │ │ │ - this.map.zoomOut(); │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - handled = false │ │ │ │ - } │ │ │ │ - if (handled) { │ │ │ │ - OpenLayers.Event.stop(evt) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.KeyboardDefaults" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - multipleKey: null, │ │ │ │ - toggleKey: null, │ │ │ │ - multiple: false, │ │ │ │ - clickout: true, │ │ │ │ - toggle: false, │ │ │ │ - hover: false, │ │ │ │ - highlightOnly: false, │ │ │ │ - box: false, │ │ │ │ - onBeforeSelect: function() {}, │ │ │ │ - onSelect: function() {}, │ │ │ │ - onUnselect: function() {}, │ │ │ │ - scope: null, │ │ │ │ - geometryTypes: null, │ │ │ │ - layer: null, │ │ │ │ - layers: null, │ │ │ │ - callbacks: null, │ │ │ │ - selectStyle: null, │ │ │ │ - renderIntent: "select", │ │ │ │ - handlers: null, │ │ │ │ - initialize: function(layers, options) { │ │ │ │ + clearOnDeactivate: false, │ │ │ │ + registry: null, │ │ │ │ + nextStack: null, │ │ │ │ + previousStack: null, │ │ │ │ + listeners: null, │ │ │ │ + restoring: false, │ │ │ │ + initialize: function(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 │ │ │ │ + this.registry = OpenLayers.Util.extend({ │ │ │ │ + moveend: this.getState │ │ │ │ + }, this.registry); │ │ │ │ + var previousOptions = { │ │ │ │ + trigger: OpenLayers.Function.bind(this.previousTrigger, this), │ │ │ │ + displayClass: this.displayClass + " " + this.displayClass + "Previous" │ │ │ │ }; │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ + OpenLayers.Util.extend(previousOptions, this.previousOptions); │ │ │ │ + this.previous = new OpenLayers.Control.Button(previousOptions); │ │ │ │ + var nextOptions = { │ │ │ │ + trigger: OpenLayers.Function.bind(this.nextTrigger, this), │ │ │ │ + displayClass: this.displayClass + " " + this.displayClass + "Next" │ │ │ │ }; │ │ │ │ - if (this.box) { │ │ │ │ - this.handlers.box = new OpenLayers.Handler.Box(this, { │ │ │ │ - done: this.selectBox │ │ │ │ - }, { │ │ │ │ - boxDivClassName: "olHandlerBoxSelectFeature" │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - unselectAll: function(options) { │ │ │ │ - var layers = this.layers || [this.layer], │ │ │ │ - layer, feature, l, numExcept; │ │ │ │ - for (l = 0; l < layers.length; ++l) { │ │ │ │ - layer = layers[l]; │ │ │ │ - numExcept = 0; │ │ │ │ - if (layer.selectedFeatures != null) { │ │ │ │ - while (layer.selectedFeatures.length > numExcept) { │ │ │ │ - feature = layer.selectedFeatures[numExcept]; │ │ │ │ - if (!options || options.except != feature) { │ │ │ │ - this.unselect(feature) │ │ │ │ - } else { │ │ │ │ - ++numExcept │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - multipleSelect: function() { │ │ │ │ - return this.multiple || this.handlers.feature.evt && this.handlers.feature.evt[this.multipleKey] │ │ │ │ - }, │ │ │ │ - toggleSelect: function() { │ │ │ │ - return this.toggle || this.handlers.feature.evt && this.handlers.feature.evt[this.toggleKey] │ │ │ │ - }, │ │ │ │ - clickoutFeature: function(feature) { │ │ │ │ - if (!this.hover && this.clickout) { │ │ │ │ - this.unselectAll() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - outFeature: function(feature) { │ │ │ │ - if (this.hover) { │ │ │ │ - if (this.highlightOnly) { │ │ │ │ - if (feature._lastHighlighter == this.id) { │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - unhighlight: function(feature) { │ │ │ │ - var layer = feature.layer; │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - 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 (!this.handlers.feature.lastFeature) { │ │ │ │ - this.handlers.feature.lastFeature = layer.selectedFeatures[0] │ │ │ │ - } │ │ │ │ - layer.events.triggerEvent("featureselected", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - this.onSelect.call(this.scope, feature) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - unselect: function(feature) { │ │ │ │ - var layer = feature.layer; │ │ │ │ - this.unhighlight(feature); │ │ │ │ - OpenLayers.Util.removeItem(layer.selectedFeatures, feature); │ │ │ │ - layer.events.triggerEvent("featureunselected", { │ │ │ │ - feature: feature │ │ │ │ - }); │ │ │ │ - this.onUnselect.call(this.scope, feature) │ │ │ │ - }, │ │ │ │ - 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 (!this.multipleSelect()) { │ │ │ │ - this.unselectAll() │ │ │ │ - } │ │ │ │ - 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]; │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - } │ │ │ │ + OpenLayers.Util.extend(nextOptions, this.nextOptions); │ │ │ │ + this.next = new OpenLayers.Control.Button(nextOptions); │ │ │ │ + this.clear() │ │ │ │ }, │ │ │ │ - setMap: function(map) { │ │ │ │ - this.handlers.feature.setMap(map); │ │ │ │ - if (this.box) { │ │ │ │ - this.handlers.box.setMap(map) │ │ │ │ + onPreviousChange: function(state, length) { │ │ │ │ + if (state && !this.previous.active) { │ │ │ │ + this.previous.activate() │ │ │ │ + } else if (!state && this.previous.active) { │ │ │ │ + this.previous.deactivate() │ │ │ │ } │ │ │ │ - OpenLayers.Control.prototype.setMap.apply(this, arguments) │ │ │ │ }, │ │ │ │ - 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() │ │ │ │ + onNextChange: function(state, length) { │ │ │ │ + if (state && !this.next.active) { │ │ │ │ + this.next.activate() │ │ │ │ + } else if (!state && this.next.active) { │ │ │ │ + this.next.deactivate() │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.SelectFeature" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.MousePosition = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - autoActivate: true, │ │ │ │ - element: null, │ │ │ │ - prefix: "", │ │ │ │ - separator: ", ", │ │ │ │ - suffix: "", │ │ │ │ - numDigits: 5, │ │ │ │ - granularity: 10, │ │ │ │ - emptyString: null, │ │ │ │ - lastXy: null, │ │ │ │ - displayProjection: null, │ │ │ │ destroy: function() { │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this); │ │ │ │ + this.previous.destroy(); │ │ │ │ + this.next.destroy(); │ │ │ │ this.deactivate(); │ │ │ │ - OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.map.events.register("mousemove", this, this.redraw); │ │ │ │ - this.map.events.register("mouseout", this, this.reset); │ │ │ │ - this.redraw(); │ │ │ │ - return true │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ + for (var prop in this) { │ │ │ │ + this[prop] = null │ │ │ │ } │ │ │ │ }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - this.map.events.unregister("mousemove", this, this.redraw); │ │ │ │ - this.map.events.unregister("mouseout", this, this.reset); │ │ │ │ - this.element.innerHTML = ""; │ │ │ │ - return true │ │ │ │ - } else { │ │ │ │ - return false │ │ │ │ - } │ │ │ │ + setMap: function(map) { │ │ │ │ + this.map = map; │ │ │ │ + this.next.setMap(map); │ │ │ │ + this.previous.setMap(map) │ │ │ │ }, │ │ │ │ draw: function() { │ │ │ │ OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ - if (!this.element) { │ │ │ │ - this.div.left = ""; │ │ │ │ - this.div.top = ""; │ │ │ │ - this.element = this.div │ │ │ │ - } │ │ │ │ - return this.div │ │ │ │ - }, │ │ │ │ - redraw: function(evt) { │ │ │ │ - var lonLat; │ │ │ │ - if (evt == null) { │ │ │ │ - this.reset(); │ │ │ │ - return │ │ │ │ - } else { │ │ │ │ - if (this.lastXy == null || Math.abs(evt.xy.x - this.lastXy.x) > this.granularity || Math.abs(evt.xy.y - this.lastXy.y) > this.granularity) { │ │ │ │ - this.lastXy = evt.xy; │ │ │ │ - return │ │ │ │ - } │ │ │ │ - lonLat = this.map.getLonLatFromPixel(evt.xy); │ │ │ │ - if (!lonLat) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - if (this.displayProjection) { │ │ │ │ - lonLat.transform(this.map.getProjectionObject(), this.displayProjection) │ │ │ │ - } │ │ │ │ - this.lastXy = evt.xy │ │ │ │ - } │ │ │ │ - var newHtml = this.formatOutput(lonLat); │ │ │ │ - if (newHtml != this.element.innerHTML) { │ │ │ │ - this.element.innerHTML = newHtml │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - reset: function(evt) { │ │ │ │ - if (this.emptyString != null) { │ │ │ │ - this.element.innerHTML = this.emptyString │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - formatOutput: function(lonLat) { │ │ │ │ - var digits = parseInt(this.numDigits); │ │ │ │ - var newHtml = this.prefix + lonLat.lon.toFixed(digits) + this.separator + lonLat.lat.toFixed(digits) + this.suffix; │ │ │ │ - return newHtml │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.MousePosition" │ │ │ │ -}); │ │ │ │ -OpenLayers.Control.TouchNavigation = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ - dragPan: null, │ │ │ │ - dragPanOptions: null, │ │ │ │ - pinchZoom: null, │ │ │ │ - pinchZoomOptions: null, │ │ │ │ - clickHandlerOptions: null, │ │ │ │ - documentDrag: false, │ │ │ │ - autoActivate: true, │ │ │ │ - initialize: function(options) { │ │ │ │ - this.handlers = {}; │ │ │ │ - OpenLayers.Control.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ - this.dragPan.activate(); │ │ │ │ - this.handlers.click.activate(); │ │ │ │ - this.pinchZoom.activate(); │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ - this.dragPan.deactivate(); │ │ │ │ - this.handlers.click.deactivate(); │ │ │ │ - this.pinchZoom.deactivate(); │ │ │ │ - return true │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - 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)) │ │ │ │ - }, │ │ │ │ - defaultClick: function(evt) { │ │ │ │ - if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ - this.map.zoomOut() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - defaultDblClick: function(evt) { │ │ │ │ - this.map.zoomTo(this.map.zoom + 1, evt.xy) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Control.TouchNavigation" │ │ │ │ -}); │ │ │ │ -OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - distance: 20, │ │ │ │ - threshold: null, │ │ │ │ - features: null, │ │ │ │ - clusters: null, │ │ │ │ - clustering: false, │ │ │ │ - resolution: null, │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - beforefeaturesadded: this.cacheFeatures, │ │ │ │ - featuresremoved: this.clearCache, │ │ │ │ - moveend: this.cluster, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.layer.events.un({ │ │ │ │ - beforefeaturesadded: this.cacheFeatures, │ │ │ │ - featuresremoved: this.clearCache, │ │ │ │ - moveend: this.cluster, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - cacheFeatures: function(event) { │ │ │ │ - var propagate = true; │ │ │ │ - if (!this.clustering) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.features = event.features; │ │ │ │ - this.cluster(); │ │ │ │ - propagate = false │ │ │ │ - } │ │ │ │ - return propagate │ │ │ │ - }, │ │ │ │ - clearCache: function() { │ │ │ │ - if (!this.clustering) { │ │ │ │ - this.features = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - cluster: function(event) { │ │ │ │ - if ((!event || event.zoomChanged) && this.features) { │ │ │ │ - var resolution = this.layer.map.getResolution(); │ │ │ │ - if (resolution != this.resolution || !this.clustersExist()) { │ │ │ │ - this.resolution = resolution; │ │ │ │ - var clusters = []; │ │ │ │ - var feature, clustered, cluster; │ │ │ │ - for (var i = 0; i < this.features.length; ++i) { │ │ │ │ - feature = this.features[i]; │ │ │ │ - if (feature.geometry) { │ │ │ │ - clustered = false; │ │ │ │ - for (var j = clusters.length - 1; j >= 0; --j) { │ │ │ │ - cluster = clusters[j]; │ │ │ │ - if (this.shouldCluster(cluster, feature)) { │ │ │ │ - this.addToCluster(cluster, feature); │ │ │ │ - clustered = true; │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (!clustered) { │ │ │ │ - clusters.push(this.createCluster(this.features[i])) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.clustering = true; │ │ │ │ - this.layer.removeAllFeatures(); │ │ │ │ - this.clustering = false; │ │ │ │ - if (clusters.length > 0) { │ │ │ │ - if (this.threshold > 1) { │ │ │ │ - var clone = clusters.slice(); │ │ │ │ - clusters = []; │ │ │ │ - var candidate; │ │ │ │ - for (var i = 0, len = clone.length; i < len; ++i) { │ │ │ │ - candidate = clone[i]; │ │ │ │ - if (candidate.attributes.count < this.threshold) { │ │ │ │ - Array.prototype.push.apply(clusters, candidate.cluster) │ │ │ │ - } else { │ │ │ │ - clusters.push(candidate) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.clustering = true; │ │ │ │ - this.layer.addFeatures(clusters); │ │ │ │ - this.clustering = false │ │ │ │ - } │ │ │ │ - this.clusters = clusters │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clustersExist: function() { │ │ │ │ - var exist = false; │ │ │ │ - if (this.clusters && this.clusters.length > 0 && this.clusters.length == this.layer.features.length) { │ │ │ │ - exist = true; │ │ │ │ - for (var i = 0; i < this.clusters.length; ++i) { │ │ │ │ - if (this.clusters[i] != this.layer.features[i]) { │ │ │ │ - exist = false; │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return exist │ │ │ │ - }, │ │ │ │ - shouldCluster: function(cluster, feature) { │ │ │ │ - var cc = cluster.geometry.getBounds().getCenterLonLat(); │ │ │ │ - var fc = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ - var distance = Math.sqrt(Math.pow(cc.lon - fc.lon, 2) + Math.pow(cc.lat - fc.lat, 2)) / this.resolution; │ │ │ │ - return distance <= this.distance │ │ │ │ - }, │ │ │ │ - addToCluster: function(cluster, feature) { │ │ │ │ - cluster.cluster.push(feature); │ │ │ │ - cluster.attributes.count += 1 │ │ │ │ - }, │ │ │ │ - createCluster: function(feature) { │ │ │ │ - var center = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ - var cluster = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(center.lon, center.lat), { │ │ │ │ - count: 1 │ │ │ │ - }); │ │ │ │ - cluster.cluster = [feature]; │ │ │ │ - return cluster │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Cluster" │ │ │ │ -}); │ │ │ │ -OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - bounds: null, │ │ │ │ - resolution: null, │ │ │ │ - ratio: 2, │ │ │ │ - resFactor: null, │ │ │ │ - response: null, │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - moveend: this.update, │ │ │ │ - refresh: this.update, │ │ │ │ - visibilitychanged: this.update, │ │ │ │ - scope: this │ │ │ │ - }); │ │ │ │ - this.update() │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.layer.events.un({ │ │ │ │ - moveend: this.update, │ │ │ │ - refresh: this.update, │ │ │ │ - visibilitychanged: this.update, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - update: function(options) { │ │ │ │ - var mapBounds = this.getMapBounds(); │ │ │ │ - if (mapBounds !== null && (options && options.force || this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds))) { │ │ │ │ - this.calculateBounds(mapBounds); │ │ │ │ - this.resolution = this.layer.map.getResolution(); │ │ │ │ - this.triggerRead(options) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getMapBounds: function() { │ │ │ │ - if (this.layer.map === null) { │ │ │ │ - return null │ │ │ │ - } │ │ │ │ - var bounds = this.layer.map.getExtent(); │ │ │ │ - if (bounds && !this.layer.projection.equals(this.layer.map.getProjectionObject())) { │ │ │ │ - bounds = bounds.clone().transform(this.layer.map.getProjectionObject(), this.layer.projection) │ │ │ │ - } │ │ │ │ - return bounds │ │ │ │ - }, │ │ │ │ - invalidBounds: function(mapBounds) { │ │ │ │ - if (!mapBounds) { │ │ │ │ - mapBounds = this.getMapBounds() │ │ │ │ - } │ │ │ │ - var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds); │ │ │ │ - if (!invalid && this.resFactor) { │ │ │ │ - var ratio = this.resolution / this.layer.map.getResolution(); │ │ │ │ - invalid = ratio >= this.resFactor || ratio <= 1 / this.resFactor │ │ │ │ - } │ │ │ │ - return invalid │ │ │ │ - }, │ │ │ │ - calculateBounds: function(mapBounds) { │ │ │ │ - if (!mapBounds) { │ │ │ │ - mapBounds = this.getMapBounds() │ │ │ │ - } │ │ │ │ - var center = mapBounds.getCenterLonLat(); │ │ │ │ - var dataWidth = mapBounds.getWidth() * this.ratio; │ │ │ │ - var dataHeight = mapBounds.getHeight() * this.ratio; │ │ │ │ - this.bounds = new OpenLayers.Bounds(center.lon - dataWidth / 2, center.lat - dataHeight / 2, center.lon + dataWidth / 2, center.lat + dataHeight / 2) │ │ │ │ - }, │ │ │ │ - triggerRead: function(options) { │ │ │ │ - if (this.response && !(options && options.noAbort === true)) { │ │ │ │ - this.layer.protocol.abort(this.response); │ │ │ │ - this.layer.events.triggerEvent("loadend") │ │ │ │ - } │ │ │ │ - var evt = { │ │ │ │ - filter: this.createFilter() │ │ │ │ - }; │ │ │ │ - this.layer.events.triggerEvent("loadstart", evt); │ │ │ │ - this.response = this.layer.protocol.read(OpenLayers.Util.applyDefaults({ │ │ │ │ - filter: evt.filter, │ │ │ │ - callback: this.merge, │ │ │ │ - scope: this │ │ │ │ - }, options)) │ │ │ │ - }, │ │ │ │ - createFilter: function() { │ │ │ │ - var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ - value: this.bounds, │ │ │ │ - projection: this.layer.projection │ │ │ │ - }); │ │ │ │ - if (this.layer.filter) { │ │ │ │ - filter = new OpenLayers.Filter.Logical({ │ │ │ │ - type: OpenLayers.Filter.Logical.AND, │ │ │ │ - filters: [this.layer.filter, filter] │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return filter │ │ │ │ - }, │ │ │ │ - merge: function(resp) { │ │ │ │ - this.layer.destroyFeatures(); │ │ │ │ - if (resp.success()) { │ │ │ │ - var features = resp.features; │ │ │ │ - if (features && features.length > 0) { │ │ │ │ - var remote = this.layer.projection; │ │ │ │ - var local = this.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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.layer.addFeatures(features) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.bounds = null │ │ │ │ - } │ │ │ │ - this.response = null; │ │ │ │ - this.layer.events.triggerEvent("loadend", { │ │ │ │ - response: resp │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.BBOX" │ │ │ │ -}); │ │ │ │ -OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - events: null, │ │ │ │ - auto: false, │ │ │ │ - timer: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Strategy.prototype.initialize.apply(this, [options]); │ │ │ │ - this.events = new OpenLayers.Events(this) │ │ │ │ - }, │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - if (this.auto) { │ │ │ │ - if (typeof this.auto === "number") { │ │ │ │ - this.timer = window.setInterval(OpenLayers.Function.bind(this.save, this), this.auto * 1e3) │ │ │ │ - } else { │ │ │ │ - this.layer.events.on({ │ │ │ │ - featureadded: this.triggerSave, │ │ │ │ - afterfeaturemodified: this.triggerSave, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - if (this.auto) { │ │ │ │ - if (typeof this.auto === "number") { │ │ │ │ - window.clearInterval(this.timer) │ │ │ │ - } else { │ │ │ │ - this.layer.events.un({ │ │ │ │ - featureadded: this.triggerSave, │ │ │ │ - afterfeaturemodified: this.triggerSave, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - triggerSave: function(event) { │ │ │ │ - var feature = event.feature; │ │ │ │ - if (feature.state === OpenLayers.State.INSERT || feature.state === OpenLayers.State.UPDATE || feature.state === OpenLayers.State.DELETE) { │ │ │ │ - this.save([event.feature]) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - save: function(features) { │ │ │ │ - if (!features) { │ │ │ │ - features = this.layer.features │ │ │ │ - } │ │ │ │ - this.events.triggerEvent("start", { │ │ │ │ - features: features │ │ │ │ - }); │ │ │ │ - var remote = this.layer.projection; │ │ │ │ - var local = this.layer.map.getProjectionObject(); │ │ │ │ - if (!local.equals(remote)) { │ │ │ │ - var len = features.length; │ │ │ │ - var clones = new Array(len); │ │ │ │ - var orig, clone; │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ - orig = features[i]; │ │ │ │ - clone = orig.clone(); │ │ │ │ - clone.fid = orig.fid; │ │ │ │ - clone.state = orig.state; │ │ │ │ - if (orig.url) { │ │ │ │ - clone.url = orig.url │ │ │ │ - } │ │ │ │ - clone._original = orig; │ │ │ │ - clone.geometry.transform(local, remote); │ │ │ │ - clones[i] = clone │ │ │ │ - } │ │ │ │ - features = clones │ │ │ │ - } │ │ │ │ - this.layer.protocol.commit(features, { │ │ │ │ - callback: this.onCommit, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - onCommit: function(response) { │ │ │ │ - var evt = { │ │ │ │ - response: response │ │ │ │ - }; │ │ │ │ - if (response.success()) { │ │ │ │ - var features = response.reqFeatures; │ │ │ │ - var state, feature; │ │ │ │ - var destroys = []; │ │ │ │ - var insertIds = response.insertIds || []; │ │ │ │ - var j = 0; │ │ │ │ - for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - feature = feature._original || feature; │ │ │ │ - state = feature.state; │ │ │ │ - if (state) { │ │ │ │ - if (state == OpenLayers.State.DELETE) { │ │ │ │ - destroys.push(feature) │ │ │ │ - } else if (state == OpenLayers.State.INSERT) { │ │ │ │ - feature.fid = insertIds[j]; │ │ │ │ - ++j │ │ │ │ - } │ │ │ │ - feature.state = null │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (destroys.length > 0) { │ │ │ │ - this.layer.destroyFeatures(destroys) │ │ │ │ - } │ │ │ │ - this.events.triggerEvent("success", evt) │ │ │ │ - } else { │ │ │ │ - this.events.triggerEvent("fail", evt) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Save" │ │ │ │ -}); │ │ │ │ -OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - preload: false, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - 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.Strategy.Refresh = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - force: false, │ │ │ │ - interval: 0, │ │ │ │ - timer: null, │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - if (this.layer.visibility === true) { │ │ │ │ - this.start() │ │ │ │ - } │ │ │ │ - this.layer.events.on({ │ │ │ │ - visibilitychanged: this.reset, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.stop(); │ │ │ │ - this.layer.events.un({ │ │ │ │ - visibilitychanged: this.reset, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - reset: function() { │ │ │ │ - if (this.layer.visibility === true) { │ │ │ │ - this.start() │ │ │ │ - } else { │ │ │ │ - this.stop() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - start: function() { │ │ │ │ - if (this.interval && typeof this.interval === "number" && this.interval > 0) { │ │ │ │ - this.timer = window.setInterval(OpenLayers.Function.bind(this.refresh, this), this.interval) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - refresh: function() { │ │ │ │ - if (this.layer && this.layer.refresh && typeof this.layer.refresh == "function") { │ │ │ │ - this.layer.refresh({ │ │ │ │ - force: this.force │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - stop: function() { │ │ │ │ - if (this.timer !== null) { │ │ │ │ - window.clearInterval(this.timer); │ │ │ │ - this.timer = null │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Refresh" │ │ │ │ -}); │ │ │ │ -OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - features: null, │ │ │ │ - length: 10, │ │ │ │ - num: null, │ │ │ │ - paging: false, │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ - if (activated) { │ │ │ │ - this.layer.events.on({ │ │ │ │ - beforefeaturesadded: this.cacheFeatures, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ - if (deactivated) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.layer.events.un({ │ │ │ │ - beforefeaturesadded: this.cacheFeatures, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return deactivated │ │ │ │ - }, │ │ │ │ - cacheFeatures: function(event) { │ │ │ │ - if (!this.paging) { │ │ │ │ - this.clearCache(); │ │ │ │ - this.features = event.features; │ │ │ │ - this.pageNext(event) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - clearCache: function() { │ │ │ │ - if (this.features) { │ │ │ │ - for (var i = 0; i < this.features.length; ++i) { │ │ │ │ - this.features[i].destroy() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.features = null; │ │ │ │ - this.num = null │ │ │ │ - }, │ │ │ │ - pageCount: function() { │ │ │ │ - var numFeatures = this.features ? this.features.length : 0; │ │ │ │ - return Math.ceil(numFeatures / this.length) │ │ │ │ - }, │ │ │ │ - pageNum: function() { │ │ │ │ - return this.num │ │ │ │ - }, │ │ │ │ - pageLength: function(newLength) { │ │ │ │ - if (newLength && newLength > 0) { │ │ │ │ - this.length = newLength │ │ │ │ - } │ │ │ │ - return this.length │ │ │ │ - }, │ │ │ │ - pageNext: function(event) { │ │ │ │ - var changed = false; │ │ │ │ - if (this.features) { │ │ │ │ - if (this.num === null) { │ │ │ │ - this.num = -1 │ │ │ │ - } │ │ │ │ - var start = (this.num + 1) * this.length; │ │ │ │ - changed = this.page(start, event) │ │ │ │ - } │ │ │ │ - return changed │ │ │ │ - }, │ │ │ │ - pagePrevious: function() { │ │ │ │ - var changed = false; │ │ │ │ - if (this.features) { │ │ │ │ - if (this.num === null) { │ │ │ │ - this.num = this.pageCount() │ │ │ │ - } │ │ │ │ - var start = (this.num - 1) * this.length; │ │ │ │ - changed = this.page(start) │ │ │ │ - } │ │ │ │ - return changed │ │ │ │ - }, │ │ │ │ - page: function(start, event) { │ │ │ │ - var changed = false; │ │ │ │ - if (this.features) { │ │ │ │ - if (start >= 0 && start < this.features.length) { │ │ │ │ - var num = Math.floor(start / this.length); │ │ │ │ - if (num != this.num) { │ │ │ │ - this.paging = true; │ │ │ │ - var features = this.features.slice(start, start + this.length); │ │ │ │ - this.layer.removeFeatures(this.layer.features); │ │ │ │ - this.num = num; │ │ │ │ - if (event && event.features) { │ │ │ │ - event.features = features │ │ │ │ - } else { │ │ │ │ - this.layer.addFeatures(features) │ │ │ │ - } │ │ │ │ - this.paging = false; │ │ │ │ - changed = true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return changed │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Paging" │ │ │ │ -}); │ │ │ │ -OpenLayers.Strategy.Filter = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ - filter: null, │ │ │ │ - cache: null, │ │ │ │ - caching: false, │ │ │ │ - activate: function() { │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments); │ │ │ │ - if (activated) { │ │ │ │ - this.cache = []; │ │ │ │ - this.layer.events.on({ │ │ │ │ - beforefeaturesadded: this.handleAdd, │ │ │ │ - beforefeaturesremoved: this.handleRemove, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return activated │ │ │ │ - }, │ │ │ │ - deactivate: function() { │ │ │ │ - this.cache = null; │ │ │ │ - if (this.layer && this.layer.events) { │ │ │ │ - this.layer.events.un({ │ │ │ │ - beforefeaturesadded: this.handleAdd, │ │ │ │ - beforefeaturesremoved: this.handleRemove, │ │ │ │ - scope: this │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - return OpenLayers.Strategy.prototype.deactivate.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - handleAdd: function(event) { │ │ │ │ - if (!this.caching && this.filter) { │ │ │ │ - var features = event.features; │ │ │ │ - event.features = []; │ │ │ │ - var feature; │ │ │ │ - for (var i = 0, ii = features.length; i < ii; ++i) { │ │ │ │ - feature = features[i]; │ │ │ │ - if (this.filter.evaluate(feature)) { │ │ │ │ - event.features.push(feature) │ │ │ │ - } else { │ │ │ │ - this.cache.push(feature) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - handleRemove: function(event) { │ │ │ │ - if (!this.caching) { │ │ │ │ - this.cache = [] │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setFilter: function(filter) { │ │ │ │ - this.filter = filter; │ │ │ │ - var previousCache = this.cache; │ │ │ │ - this.cache = []; │ │ │ │ - this.handleAdd({ │ │ │ │ - features: this.layer.features │ │ │ │ - }); │ │ │ │ - if (this.cache.length > 0) { │ │ │ │ - this.caching = true; │ │ │ │ - this.layer.removeFeatures(this.cache.slice()); │ │ │ │ - this.caching = false │ │ │ │ - } │ │ │ │ - if (previousCache.length > 0) { │ │ │ │ - var event = { │ │ │ │ - features: previousCache │ │ │ │ - }; │ │ │ │ - this.handleAdd(event); │ │ │ │ - if (event.features.length > 0) { │ │ │ │ - this.caching = true; │ │ │ │ - this.layer.addFeatures(event.features); │ │ │ │ - this.caching = false │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Filter" │ │ │ │ -}); │ │ │ │ -OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ - xmlns: "http://www.w3.org/2000/svg", │ │ │ │ - xlinkns: "http://www.w3.org/1999/xlink", │ │ │ │ - MAX_PIXEL: 15e3, │ │ │ │ - translationParameters: null, │ │ │ │ - symbolMetrics: null, │ │ │ │ - initialize: function(containerID) { │ │ │ │ - if (!this.supported()) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - OpenLayers.Renderer.Elements.prototype.initialize.apply(this, arguments); │ │ │ │ - this.translationParameters = { │ │ │ │ - x: 0, │ │ │ │ - y: 0 │ │ │ │ - }; │ │ │ │ - this.symbolMetrics = {} │ │ │ │ - }, │ │ │ │ - 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")) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 (resolutionChanged) { │ │ │ │ - this.left = left; │ │ │ │ - this.top = top; │ │ │ │ - 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) { │ │ │ │ - this.setExtent(extent, true) │ │ │ │ - } │ │ │ │ - return coordSysUnchanged && inRange │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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); │ │ │ │ - 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 : -(.5 * width); │ │ │ │ - var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.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)) { │ │ │ │ - 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; │ │ │ │ - var parent = node.parentNode; │ │ │ │ - var nextSibling = node.nextSibling; │ │ │ │ - if (parent) { │ │ │ │ - parent.removeChild(node) │ │ │ │ - } │ │ │ │ - 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); │ │ │ │ - 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"); │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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, ",") │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - createNode: function(type, id) { │ │ │ │ - var node = document.createElementNS(this.xmlns, type); │ │ │ │ - if (id) { │ │ │ │ - node.setAttributeNS(null, "id", id) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - nodeTypeCompare: function(node, type) { │ │ │ │ - return type == node.nodeName │ │ │ │ - }, │ │ │ │ - createRenderRoot: function() { │ │ │ │ - var svg = this.nodeFactory(this.container.id + "_svgRoot", "svg"); │ │ │ │ - svg.style.display = "block"; │ │ │ │ - return svg │ │ │ │ - }, │ │ │ │ - createRoot: function(suffix) { │ │ │ │ - return this.nodeFactory(this.container.id + suffix, "g") │ │ │ │ - }, │ │ │ │ - createDefs: function() { │ │ │ │ - var defs = this.nodeFactory(this.container.id + "_defs", "defs"); │ │ │ │ - this.rendererRoot.appendChild(defs); │ │ │ │ - return defs │ │ │ │ - }, │ │ │ │ - drawPoint: function(node, geometry) { │ │ │ │ - return this.drawCircle(node, geometry, 1) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawText: function(featureId, style, location) { │ │ │ │ - var drawOutline = !!style.labelOutlineWidth; │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 { │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getPosition: function(node) { │ │ │ │ - return { │ │ │ │ - x: parseFloat(node.getAttributeNS(null, "cx")), │ │ │ │ - y: parseFloat(node.getAttributeNS(null, "cy")) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - importSymbol: function(graphicName) { │ │ │ │ - if (!this.defs) { │ │ │ │ - this.defs = this.createDefs() │ │ │ │ - } │ │ │ │ - var id = this.container.id + "-" + graphicName; │ │ │ │ - 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(); │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -OpenLayers.Renderer.SVG.LABEL_ALIGN = { │ │ │ │ - l: "start", │ │ │ │ - r: "end", │ │ │ │ - b: "bottom", │ │ │ │ - t: "hanging" │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.SVG.LABEL_VSHIFT = { │ │ │ │ - t: "-70%", │ │ │ │ - b: "0" │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.SVG.LABEL_VFACTOR = { │ │ │ │ - t: 0, │ │ │ │ - b: -1 │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.SVG.preventDefault = function(e) { │ │ │ │ - OpenLayers.Event.preventDefault(e) │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { │ │ │ │ - hitDetection: true, │ │ │ │ - hitOverflow: 0, │ │ │ │ - canvas: null, │ │ │ │ - features: null, │ │ │ │ - pendingRedraw: false, │ │ │ │ - cachedSymbolBounds: {}, │ │ │ │ - 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") │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setExtent: function() { │ │ │ │ - OpenLayers.Renderer.prototype.setExtent.apply(this, arguments); │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - eraseGeometry: function(geometry, featureId) { │ │ │ │ - this.eraseFeatures(this.features[featureId][0]) │ │ │ │ - }, │ │ │ │ - supported: function() { │ │ │ │ - return OpenLayers.CANVAS_SUPPORTED │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawFeature: function(feature, style) { │ │ │ │ - var rendered; │ │ │ │ - if (feature.geometry) { │ │ │ │ - style = this.applyDefaultSymbolizer(style || feature.style); │ │ │ │ - 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) { │ │ │ │ - this.features[feature.id] = [feature, style] │ │ │ │ - } else { │ │ │ │ - delete this.features[feature.id] │ │ │ │ - } │ │ │ │ - this.pendingRedraw = true │ │ │ │ - } │ │ │ │ - if (this.pendingRedraw && !this.locked) { │ │ │ │ - this.redraw(); │ │ │ │ - this.pendingRedraw = false │ │ │ │ - } │ │ │ │ - return rendered │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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 : -(.5 * width); │ │ │ │ - var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.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 / 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 │ │ │ │ - }, │ │ │ │ - drawNamedSymbol: function(geometry, style, featureId) { │ │ │ │ - var x, y, cx, cy, i, symbolBounds, scaling, angle; │ │ │ │ - var unscaledStrokeWidth; │ │ │ │ - var deg2rad = Math.PI / 180; │ │ │ │ - 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; │ │ │ │ - this.canvas.lineCap = "round"; │ │ │ │ - this.canvas.lineJoin = "round"; │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.lineCap = "round"; │ │ │ │ - this.hitContext.lineJoin = "round" │ │ │ │ - } │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - this.canvas.save(); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.save() │ │ │ │ - } │ │ │ │ - this.canvas.translate(p0, p1); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.translate(p0, p1) │ │ │ │ - } │ │ │ │ - angle = deg2rad * style.rotation; │ │ │ │ - if (!isNaN(angle)) { │ │ │ │ - this.canvas.rotate(angle); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.rotate(angle) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - scaling = 2 * style.pointRadius / Math.max(symbolBounds.getWidth(), symbolBounds.getHeight()); │ │ │ │ - this.canvas.scale(scaling, scaling); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.scale(scaling, scaling) │ │ │ │ - } │ │ │ │ - cx = symbolBounds.getCenterLonLat().lon; │ │ │ │ - cy = symbolBounds.getCenterLonLat().lat; │ │ │ │ - this.canvas.translate(-cx, -cy); │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.translate(-cx, -cy) │ │ │ │ - } │ │ │ │ - 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") │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - featureIdToHex: function(featureId) { │ │ │ │ - var id = Number(featureId.split("_").pop()) + 1; │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - setHitContextStyle: function(type, featureId, symbolizer, strokeScaling) { │ │ │ │ - var hex = this.featureIdToHex(featureId); │ │ │ │ - if (type == "fill") { │ │ │ │ - this.hitContext.globalAlpha = 1; │ │ │ │ - this.hitContext.fillStyle = hex │ │ │ │ - } else if (type == "stroke") { │ │ │ │ - this.hitContext.globalAlpha = 1; │ │ │ │ - this.hitContext.strokeStyle = hex; │ │ │ │ - if (typeof strokeScaling === "undefined") { │ │ │ │ - this.hitContext.lineWidth = symbolizer.strokeWidth + 2 │ │ │ │ - } else { │ │ │ │ - if (!isNaN(strokeScaling)) { │ │ │ │ - this.hitContext.lineWidth = symbolizer.strokeWidth + 2 / strokeScaling │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - this.hitContext.globalAlpha = 0; │ │ │ │ - this.hitContext.lineWidth = 1 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawLineString: function(geometry, style, featureId) { │ │ │ │ - style = OpenLayers.Util.applyDefaults({ │ │ │ │ - fill: false │ │ │ │ - }, style); │ │ │ │ - this.drawLinearRing(geometry, style, featureId) │ │ │ │ - }, │ │ │ │ - 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") │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawPolygon: function(geometry, style, featureId) { │ │ │ │ - var components = geometry.components; │ │ │ │ - var len = components.length; │ │ │ │ - this.drawLinearRing(components[0], style, featureId); │ │ │ │ - for (var i = 1; i < len; ++i) { │ │ │ │ - this.canvas.globalCompositeOperation = "destination-out"; │ │ │ │ - if (this.hitDetection) { │ │ │ │ - this.hitContext.globalCompositeOperation = "destination-out" │ │ │ │ - } │ │ │ │ - this.drawLinearRing(components[i], OpenLayers.Util.applyDefaults({ │ │ │ │ - stroke: false, │ │ │ │ - fillOpacity: 1 │ │ │ │ - }, 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - drawText: function(location, style) { │ │ │ │ - var pt = this.getLocalXY(location); │ │ │ │ - this.setCanvasStyle("reset"); │ │ │ │ - this.canvas.fillStyle = style.fontColor; │ │ │ │ - this.canvas.globalAlpha = style.fontOpacity || 1; │ │ │ │ - var fontStyle = [style.fontStyle ? style.fontStyle : "normal", "normal", 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) { │ │ │ │ - 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; │ │ │ │ - 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) { │ │ │ │ - this.canvas.mozTextStyle = fontStyle; │ │ │ │ - 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") │ │ │ │ - }, │ │ │ │ - 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] │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getFeatureIdFromEvent: function(evt) { │ │ │ │ - var featureId, feature; │ │ │ │ - if (this.hitDetection && this.root.style.display !== "none") { │ │ │ │ - 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) { │ │ │ │ - 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) {} │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return feature │ │ │ │ - }, │ │ │ │ - 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() │ │ │ │ - }, │ │ │ │ - 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" │ │ │ │ -}); │ │ │ │ -OpenLayers.Renderer.Canvas.LABEL_ALIGN = { │ │ │ │ - l: "left", │ │ │ │ - r: "right", │ │ │ │ - t: "top", │ │ │ │ - b: "bottom" │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.Canvas.LABEL_FACTOR = { │ │ │ │ - l: 0, │ │ │ │ - r: -1, │ │ │ │ - t: 0, │ │ │ │ - b: -1 │ │ │ │ -}; │ │ │ │ -OpenLayers.Renderer.Canvas.drawImageScaleFactor = null; │ │ │ │ -OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { │ │ │ │ - xmlns: "urn:schemas-microsoft-com:vml", │ │ │ │ - symbolCache: {}, │ │ │ │ - offset: null, │ │ │ │ - initialize: function(containerID) { │ │ │ │ - if (!this.supported()) { │ │ │ │ - return │ │ │ │ - } │ │ │ │ - if (!document.namespaces.olv) { │ │ │ │ - document.namespaces.add("olv", this.xmlns); │ │ │ │ - var style = document.createStyleSheet(); │ │ │ │ - var shapes = ["shape", "rect", "oval", "fill", "stroke", "imagedata", "group", "textbox"]; │ │ │ │ - for (var i = 0, len = shapes.length; i < len; i++) { │ │ │ │ - style.addRule("olv\\:" + shapes[i], "behavior: url(#default#VML); " + "position: absolute; display: inline-block;") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - OpenLayers.Renderer.Elements.prototype.initialize.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - supported: function() { │ │ │ │ - return !!document.namespaces │ │ │ │ - }, │ │ │ │ - setExtent: function(extent, resolutionChanged) { │ │ │ │ - var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments); │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var left = extent.left / resolution | 0; │ │ │ │ - var top = extent.top / resolution - this.size.h | 0; │ │ │ │ - if (resolutionChanged || !this.offset) { │ │ │ │ - this.offset = { │ │ │ │ - x: left, │ │ │ │ - y: top │ │ │ │ - }; │ │ │ │ - left = 0; │ │ │ │ - top = 0 │ │ │ │ - } else { │ │ │ │ - left = left - this.offset.x; │ │ │ │ - top = top - this.offset.y │ │ │ │ - } │ │ │ │ - var org = left - this.xOffset + " " + top; │ │ │ │ - this.root.coordorigin = org; │ │ │ │ - var roots = [this.root, this.vectorRoot, this.textRoot]; │ │ │ │ - var root; │ │ │ │ - for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ - root = roots[i]; │ │ │ │ - var size = this.size.w + " " + this.size.h; │ │ │ │ - root.coordsize = size │ │ │ │ - } │ │ │ │ - this.root.style.flip = "y"; │ │ │ │ - return coordSysUnchanged │ │ │ │ - }, │ │ │ │ - setSize: function(size) { │ │ │ │ - OpenLayers.Renderer.prototype.setSize.apply(this, arguments); │ │ │ │ - var roots = [this.rendererRoot, this.root, this.vectorRoot, this.textRoot]; │ │ │ │ - var w = this.size.w + "px"; │ │ │ │ - var h = this.size.h + "px"; │ │ │ │ - var root; │ │ │ │ - for (var i = 0, len = roots.length; i < len; ++i) { │ │ │ │ - root = roots[i]; │ │ │ │ - root.style.width = w; │ │ │ │ - root.style.height = h │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - getNodeType: function(geometry, style) { │ │ │ │ - var nodeType = null; │ │ │ │ - switch (geometry.CLASS_NAME) { │ │ │ │ - case "OpenLayers.Geometry.Point": │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - nodeType = "olv:rect" │ │ │ │ - } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ - nodeType = "olv:shape" │ │ │ │ - } else { │ │ │ │ - nodeType = "olv:oval" │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "OpenLayers.Geometry.Rectangle": │ │ │ │ - nodeType = "olv:rect"; │ │ │ │ - break; │ │ │ │ - case "OpenLayers.Geometry.LineString": │ │ │ │ - case "OpenLayers.Geometry.LinearRing": │ │ │ │ - case "OpenLayers.Geometry.Polygon": │ │ │ │ - case "OpenLayers.Geometry.Curve": │ │ │ │ - nodeType = "olv:shape"; │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - break │ │ │ │ - } │ │ │ │ - return nodeType │ │ │ │ - }, │ │ │ │ - setStyle: function(node, style, options, geometry) { │ │ │ │ - style = style || node._style; │ │ │ │ - options = options || node._options; │ │ │ │ - var fillColor = style.fillColor; │ │ │ │ - var title = style.title || style.graphicTitle; │ │ │ │ - if (title) { │ │ │ │ - node.title = title │ │ │ │ - } │ │ │ │ - if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - options.isFilled = true; │ │ │ │ - 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 resolution = this.getResolution(); │ │ │ │ - var xOffset = style.graphicXOffset != undefined ? style.graphicXOffset : -(.5 * width); │ │ │ │ - var yOffset = style.graphicYOffset != undefined ? style.graphicYOffset : -(.5 * height); │ │ │ │ - node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x + xOffset | 0) + "px"; │ │ │ │ - node.style.top = (geometry.y / resolution - this.offset.y - (yOffset + height) | 0) + "px"; │ │ │ │ - node.style.width = width + "px"; │ │ │ │ - node.style.height = height + "px"; │ │ │ │ - node.style.flip = "y"; │ │ │ │ - fillColor = "none"; │ │ │ │ - options.isStroked = false │ │ │ │ - } else if (this.isComplexSymbol(style.graphicName)) { │ │ │ │ - var cache = this.importSymbol(style.graphicName); │ │ │ │ - node.path = cache.path; │ │ │ │ - node.coordorigin = cache.left + "," + cache.bottom; │ │ │ │ - var size = cache.size; │ │ │ │ - node.coordsize = size + "," + size; │ │ │ │ - this.drawCircle(node, geometry, style.pointRadius); │ │ │ │ - node.style.flip = "y" │ │ │ │ - } else { │ │ │ │ - this.drawCircle(node, geometry, style.pointRadius) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (options.isFilled) { │ │ │ │ - node.fillcolor = fillColor │ │ │ │ - } else { │ │ │ │ - node.filled = "false" │ │ │ │ - } │ │ │ │ - var fills = node.getElementsByTagName("fill"); │ │ │ │ - var fill = fills.length == 0 ? null : fills[0]; │ │ │ │ - if (!options.isFilled) { │ │ │ │ - if (fill) { │ │ │ │ - node.removeChild(fill) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (!fill) { │ │ │ │ - fill = this.createNode("olv:fill", node.id + "_fill") │ │ │ │ - } │ │ │ │ - fill.opacity = style.fillOpacity; │ │ │ │ - if (node._geometryClass === "OpenLayers.Geometry.Point" && style.externalGraphic) { │ │ │ │ - if (style.graphicOpacity) { │ │ │ │ - fill.opacity = style.graphicOpacity │ │ │ │ - } │ │ │ │ - fill.src = style.externalGraphic; │ │ │ │ - fill.type = "frame"; │ │ │ │ - if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ - fill.aspect = "atmost" │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (fill.parentNode != node) { │ │ │ │ - node.appendChild(fill) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var rotation = style.rotation; │ │ │ │ - if (rotation !== undefined || node._rotation !== undefined) { │ │ │ │ - node._rotation = rotation; │ │ │ │ - if (style.externalGraphic) { │ │ │ │ - this.graphicRotate(node, xOffset, yOffset, style); │ │ │ │ - fill.opacity = 0 │ │ │ │ - } else if (node._geometryClass === "OpenLayers.Geometry.Point") { │ │ │ │ - node.style.rotation = rotation || 0 │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var strokes = node.getElementsByTagName("stroke"); │ │ │ │ - var stroke = strokes.length == 0 ? null : strokes[0]; │ │ │ │ - if (!options.isStroked) { │ │ │ │ - node.stroked = false; │ │ │ │ - if (stroke) { │ │ │ │ - stroke.on = false │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - if (!stroke) { │ │ │ │ - stroke = this.createNode("olv:stroke", node.id + "_stroke"); │ │ │ │ - node.appendChild(stroke) │ │ │ │ - } │ │ │ │ - stroke.on = true; │ │ │ │ - stroke.color = style.strokeColor; │ │ │ │ - stroke.weight = style.strokeWidth + "px"; │ │ │ │ - stroke.opacity = style.strokeOpacity; │ │ │ │ - stroke.endcap = style.strokeLinecap == "butt" ? "flat" : style.strokeLinecap || "round"; │ │ │ │ - if (style.strokeDashstyle) { │ │ │ │ - stroke.dashstyle = this.dashStyle(style) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ - node.style.cursor = style.cursor │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - graphicRotate: function(node, xOffset, yOffset, style) { │ │ │ │ - var style = style || node._style; │ │ │ │ - var rotation = style.rotation || 0; │ │ │ │ - var aspectRatio, size; │ │ │ │ - if (!(style.graphicWidth && style.graphicHeight)) { │ │ │ │ - var img = new Image; │ │ │ │ - img.onreadystatechange = OpenLayers.Function.bind(function() { │ │ │ │ - if (img.readyState == "complete" || img.readyState == "interactive") { │ │ │ │ - aspectRatio = img.width / img.height; │ │ │ │ - size = Math.max(style.pointRadius * 2, style.graphicWidth || 0, style.graphicHeight || 0); │ │ │ │ - xOffset = xOffset * aspectRatio; │ │ │ │ - style.graphicWidth = size * aspectRatio; │ │ │ │ - style.graphicHeight = size; │ │ │ │ - this.graphicRotate(node, xOffset, yOffset, style) │ │ │ │ - } │ │ │ │ - }, this); │ │ │ │ - img.src = style.externalGraphic; │ │ │ │ - return │ │ │ │ - } else { │ │ │ │ - size = Math.max(style.graphicWidth, style.graphicHeight); │ │ │ │ - aspectRatio = style.graphicWidth / style.graphicHeight │ │ │ │ - } │ │ │ │ - var width = Math.round(style.graphicWidth || size * aspectRatio); │ │ │ │ - var height = Math.round(style.graphicHeight || size); │ │ │ │ - node.style.width = width + "px"; │ │ │ │ - node.style.height = height + "px"; │ │ │ │ - var image = document.getElementById(node.id + "_image"); │ │ │ │ - if (!image) { │ │ │ │ - image = this.createNode("olv:imagedata", node.id + "_image"); │ │ │ │ - node.appendChild(image) │ │ │ │ - } │ │ │ │ - image.style.width = width + "px"; │ │ │ │ - image.style.height = height + "px"; │ │ │ │ - image.src = style.externalGraphic; │ │ │ │ - image.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + "src='', sizingMethod='scale')"; │ │ │ │ - var rot = rotation * Math.PI / 180; │ │ │ │ - var sintheta = Math.sin(rot); │ │ │ │ - var costheta = Math.cos(rot); │ │ │ │ - var filter = "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta + ",M12=" + -sintheta + ",M21=" + sintheta + ",M22=" + costheta + ",SizingMethod='auto expand')\n"; │ │ │ │ - var opacity = style.graphicOpacity || style.fillOpacity; │ │ │ │ - if (opacity && opacity != 1) { │ │ │ │ - filter += "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + opacity + ")\n" │ │ │ │ - } │ │ │ │ - node.style.filter = filter; │ │ │ │ - var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset); │ │ │ │ - var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry(); │ │ │ │ - imgBox.rotate(style.rotation, centerPoint); │ │ │ │ - var imgBounds = imgBox.getBounds(); │ │ │ │ - node.style.left = Math.round(parseInt(node.style.left) + imgBounds.left) + "px"; │ │ │ │ - node.style.top = Math.round(parseInt(node.style.top) - imgBounds.bottom) + "px" │ │ │ │ - }, │ │ │ │ - postDraw: function(node) { │ │ │ │ - node.style.visibility = "visible"; │ │ │ │ - var fillColor = node._style.fillColor; │ │ │ │ - var strokeColor = node._style.strokeColor; │ │ │ │ - if (fillColor == "none" && node.fillcolor != fillColor) { │ │ │ │ - node.fillcolor = fillColor │ │ │ │ - } │ │ │ │ - if (strokeColor == "none" && node.strokecolor != strokeColor) { │ │ │ │ - node.strokecolor = strokeColor │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - setNodeDimension: function(node, geometry) { │ │ │ │ - var bbox = geometry.getBounds(); │ │ │ │ - if (bbox) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var scaledBox = new OpenLayers.Bounds((bbox.left - this.featureDx) / resolution - this.offset.x | 0, bbox.bottom / resolution - this.offset.y | 0, (bbox.right - this.featureDx) / resolution - this.offset.x | 0, bbox.top / resolution - this.offset.y | 0); │ │ │ │ - node.style.left = scaledBox.left + "px"; │ │ │ │ - node.style.top = scaledBox.top + "px"; │ │ │ │ - node.style.width = scaledBox.getWidth() + "px"; │ │ │ │ - node.style.height = scaledBox.getHeight() + "px"; │ │ │ │ - node.coordorigin = scaledBox.left + " " + scaledBox.top; │ │ │ │ - node.coordsize = scaledBox.getWidth() + " " + scaledBox.getHeight() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - dashStyle: function(style) { │ │ │ │ - var dash = style.strokeDashstyle; │ │ │ │ - switch (dash) { │ │ │ │ - case "solid": │ │ │ │ - case "dot": │ │ │ │ - case "dash": │ │ │ │ - case "dashdot": │ │ │ │ - case "longdash": │ │ │ │ - case "longdashdot": │ │ │ │ - return dash; │ │ │ │ - default: │ │ │ │ - var parts = dash.split(/[ ,]/); │ │ │ │ - if (parts.length == 2) { │ │ │ │ - if (1 * parts[0] >= 2 * parts[1]) { │ │ │ │ - return "longdash" │ │ │ │ - } │ │ │ │ - return parts[0] == 1 || parts[1] == 1 ? "dot" : "dash" │ │ │ │ - } else if (parts.length == 4) { │ │ │ │ - return 1 * parts[0] >= 2 * parts[1] ? "longdashdot" : "dashdot" │ │ │ │ - } │ │ │ │ - return "solid" │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - createNode: function(type, id) { │ │ │ │ - var node = document.createElement(type); │ │ │ │ - if (id) { │ │ │ │ - node.id = id │ │ │ │ - } │ │ │ │ - node.unselectable = "on"; │ │ │ │ - node.onselectstart = OpenLayers.Function.False; │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - nodeTypeCompare: function(node, type) { │ │ │ │ - var subType = type; │ │ │ │ - var splitIndex = subType.indexOf(":"); │ │ │ │ - if (splitIndex != -1) { │ │ │ │ - subType = subType.substr(splitIndex + 1) │ │ │ │ - } │ │ │ │ - var nodeName = node.nodeName; │ │ │ │ - splitIndex = nodeName.indexOf(":"); │ │ │ │ - if (splitIndex != -1) { │ │ │ │ - nodeName = nodeName.substr(splitIndex + 1) │ │ │ │ - } │ │ │ │ - return subType == nodeName │ │ │ │ - }, │ │ │ │ - createRenderRoot: function() { │ │ │ │ - return this.nodeFactory(this.container.id + "_vmlRoot", "div") │ │ │ │ - }, │ │ │ │ - createRoot: function(suffix) { │ │ │ │ - return this.nodeFactory(this.container.id + suffix, "olv:group") │ │ │ │ - }, │ │ │ │ - drawPoint: function(node, geometry) { │ │ │ │ - return this.drawCircle(node, geometry, 1) │ │ │ │ - }, │ │ │ │ - drawCircle: function(node, geometry, radius) { │ │ │ │ - if (!isNaN(geometry.x) && !isNaN(geometry.y)) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x | 0) - radius + "px"; │ │ │ │ - node.style.top = (geometry.y / resolution - this.offset.y | 0) - radius + "px"; │ │ │ │ - var diameter = radius * 2; │ │ │ │ - node.style.width = diameter + "px"; │ │ │ │ - node.style.height = diameter + "px"; │ │ │ │ - return node │ │ │ │ - } │ │ │ │ - return false │ │ │ │ - }, │ │ │ │ - drawLineString: function(node, geometry) { │ │ │ │ - return this.drawLine(node, geometry, false) │ │ │ │ - }, │ │ │ │ - drawLinearRing: function(node, geometry) { │ │ │ │ - return this.drawLine(node, geometry, true) │ │ │ │ - }, │ │ │ │ - drawLine: function(node, geometry, closeLine) { │ │ │ │ - this.setNodeDimension(node, geometry); │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var numComponents = geometry.components.length; │ │ │ │ - var parts = new Array(numComponents); │ │ │ │ - var comp, x, y; │ │ │ │ - for (var i = 0; i < numComponents; i++) { │ │ │ │ - comp = geometry.components[i]; │ │ │ │ - x = (comp.x - this.featureDx) / resolution - this.offset.x | 0; │ │ │ │ - y = comp.y / resolution - this.offset.y | 0; │ │ │ │ - parts[i] = " " + x + "," + y + " l " │ │ │ │ - } │ │ │ │ - var end = closeLine ? " x e" : " e"; │ │ │ │ - node.path = "m" + parts.join("") + end; │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - drawPolygon: function(node, geometry) { │ │ │ │ - this.setNodeDimension(node, geometry); │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - var path = []; │ │ │ │ - var j, jj, points, area, first, second, i, ii, comp, pathComp, x, y; │ │ │ │ - for (j = 0, jj = geometry.components.length; j < jj; j++) { │ │ │ │ - path.push("m"); │ │ │ │ - points = geometry.components[j].components; │ │ │ │ - area = j === 0; │ │ │ │ - first = null; │ │ │ │ - second = null; │ │ │ │ - for (i = 0, ii = points.length; i < ii; i++) { │ │ │ │ - comp = points[i]; │ │ │ │ - x = (comp.x - this.featureDx) / resolution - this.offset.x | 0; │ │ │ │ - y = comp.y / resolution - this.offset.y | 0; │ │ │ │ - pathComp = " " + x + "," + y; │ │ │ │ - path.push(pathComp); │ │ │ │ - if (i == 0) { │ │ │ │ - path.push(" l") │ │ │ │ - } │ │ │ │ - if (!area) { │ │ │ │ - if (!first) { │ │ │ │ - first = pathComp │ │ │ │ - } else if (first != pathComp) { │ │ │ │ - if (!second) { │ │ │ │ - second = pathComp │ │ │ │ - } else if (second != pathComp) { │ │ │ │ - area = true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - path.push(area ? " x " : " ") │ │ │ │ - } │ │ │ │ - path.push("e"); │ │ │ │ - node.path = path.join(""); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - drawRectangle: function(node, geometry) { │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - node.style.left = ((geometry.x - this.featureDx) / resolution - this.offset.x | 0) + "px"; │ │ │ │ - node.style.top = (geometry.y / resolution - this.offset.y | 0) + "px"; │ │ │ │ - node.style.width = (geometry.width / resolution | 0) + "px"; │ │ │ │ - node.style.height = (geometry.height / resolution | 0) + "px"; │ │ │ │ - return node │ │ │ │ + this.next.draw(); │ │ │ │ + this.previous.draw() │ │ │ │ }, │ │ │ │ - drawText: function(featureId, style, location) { │ │ │ │ - var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect"); │ │ │ │ - var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox"); │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ - label.style.left = ((location.x - this.featureDx) / resolution - this.offset.x | 0) + "px"; │ │ │ │ - label.style.top = (location.y / resolution - this.offset.y | 0) + "px"; │ │ │ │ - label.style.flip = "y"; │ │ │ │ - textbox.innerText = style.label; │ │ │ │ - if (style.cursor != "inherit" && style.cursor != null) { │ │ │ │ - textbox.style.cursor = style.cursor │ │ │ │ - } │ │ │ │ - if (style.fontColor) { │ │ │ │ - textbox.style.color = style.fontColor │ │ │ │ - } │ │ │ │ - if (style.fontOpacity) { │ │ │ │ - textbox.style.filter = "alpha(opacity=" + style.fontOpacity * 100 + ")" │ │ │ │ - } │ │ │ │ - if (style.fontFamily) { │ │ │ │ - textbox.style.fontFamily = style.fontFamily │ │ │ │ - } │ │ │ │ - if (style.fontSize) { │ │ │ │ - textbox.style.fontSize = style.fontSize │ │ │ │ - } │ │ │ │ - if (style.fontWeight) { │ │ │ │ - textbox.style.fontWeight = style.fontWeight │ │ │ │ - } │ │ │ │ - if (style.fontStyle) { │ │ │ │ - textbox.style.fontStyle = style.fontStyle │ │ │ │ + previousTrigger: function() { │ │ │ │ + var current = this.previousStack.shift(); │ │ │ │ + var state = this.previousStack.shift(); │ │ │ │ + if (state != undefined) { │ │ │ │ + this.nextStack.unshift(current); │ │ │ │ + this.previousStack.unshift(state); │ │ │ │ + this.restoring = true; │ │ │ │ + this.restore(state); │ │ │ │ + this.restoring = false; │ │ │ │ + this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ + this.onPreviousChange(this.previousStack[1], this.previousStack.length - 1) │ │ │ │ + } else { │ │ │ │ + this.previousStack.unshift(current) │ │ │ │ } │ │ │ │ - if (style.labelSelect === true) { │ │ │ │ - label._featureId = featureId; │ │ │ │ - textbox._featureId = featureId; │ │ │ │ - textbox._geometry = location; │ │ │ │ - textbox._geometryClass = location.CLASS_NAME │ │ │ │ + return state │ │ │ │ + }, │ │ │ │ + nextTrigger: function() { │ │ │ │ + var state = this.nextStack.shift(); │ │ │ │ + if (state != undefined) { │ │ │ │ + this.previousStack.unshift(state); │ │ │ │ + this.restoring = true; │ │ │ │ + this.restore(state); │ │ │ │ + this.restoring = false; │ │ │ │ + this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ + this.onPreviousChange(this.previousStack[1], this.previousStack.length - 1) │ │ │ │ } │ │ │ │ - textbox.style.whiteSpace = "nowrap"; │ │ │ │ - textbox.inset = "1px,0px,0px,0px"; │ │ │ │ - if (!label.parentNode) { │ │ │ │ - label.appendChild(textbox); │ │ │ │ - this.textRoot.appendChild(label) │ │ │ │ + return state │ │ │ │ + }, │ │ │ │ + clear: function() { │ │ │ │ + this.previousStack = []; │ │ │ │ + this.previous.deactivate(); │ │ │ │ + this.nextStack = []; │ │ │ │ + this.next.deactivate() │ │ │ │ + }, │ │ │ │ + getState: function() { │ │ │ │ + return { │ │ │ │ + center: this.map.getCenter(), │ │ │ │ + resolution: this.map.getResolution(), │ │ │ │ + projection: this.map.getProjectionObject(), │ │ │ │ + units: this.map.getProjectionObject().getUnits() || this.map.units || this.map.baseLayer.units │ │ │ │ } │ │ │ │ - var align = style.labelAlign || "cm"; │ │ │ │ - if (align.length == 1) { │ │ │ │ - align += "m" │ │ │ │ + }, │ │ │ │ + restore: function(state) { │ │ │ │ + var center, zoom; │ │ │ │ + if (this.map.getProjectionObject() == state.projection) { │ │ │ │ + zoom = this.map.getZoomForResolution(state.resolution); │ │ │ │ + center = state.center │ │ │ │ + } else { │ │ │ │ + center = state.center.clone(); │ │ │ │ + center.transform(state.projection, this.map.getProjectionObject()); │ │ │ │ + var sourceUnits = state.units; │ │ │ │ + var targetUnits = this.map.getProjectionObject().getUnits() || this.map.units || this.map.baseLayer.units; │ │ │ │ + var resolutionFactor = sourceUnits && targetUnits ? OpenLayers.INCHES_PER_UNIT[sourceUnits] / OpenLayers.INCHES_PER_UNIT[targetUnits] : 1; │ │ │ │ + zoom = this.map.getZoomForResolution(resolutionFactor * state.resolution) │ │ │ │ } │ │ │ │ - var xshift = textbox.clientWidth * OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0, 1)]; │ │ │ │ - var yshift = textbox.clientHeight * OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1, 1)]; │ │ │ │ - label.style.left = parseInt(label.style.left) - xshift - 1 + "px"; │ │ │ │ - label.style.top = parseInt(label.style.top) + yshift + "px" │ │ │ │ + this.map.setCenter(center, zoom) │ │ │ │ }, │ │ │ │ - moveRoot: function(renderer) { │ │ │ │ - var layer = this.map.getLayer(renderer.container.id); │ │ │ │ - if (layer instanceof OpenLayers.Layer.Vector.RootContainer) { │ │ │ │ - layer = this.map.getLayer(this.container.id) │ │ │ │ + setListeners: function() { │ │ │ │ + this.listeners = {}; │ │ │ │ + for (var type in this.registry) { │ │ │ │ + this.listeners[type] = OpenLayers.Function.bind(function() { │ │ │ │ + if (!this.restoring) { │ │ │ │ + var state = this.registry[type].apply(this, arguments); │ │ │ │ + this.previousStack.unshift(state); │ │ │ │ + if (this.previousStack.length > 1) { │ │ │ │ + this.onPreviousChange(this.previousStack[1], this.previousStack.length - 1) │ │ │ │ + } │ │ │ │ + if (this.previousStack.length > this.limit + 1) { │ │ │ │ + this.previousStack.pop() │ │ │ │ + } │ │ │ │ + if (this.nextStack.length > 0) { │ │ │ │ + this.nextStack = []; │ │ │ │ + this.onNextChange(null, 0) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return true │ │ │ │ + }, this) │ │ │ │ } │ │ │ │ - layer && layer.renderer.clear(); │ │ │ │ - OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments); │ │ │ │ - layer && layer.redraw() │ │ │ │ }, │ │ │ │ - importSymbol: function(graphicName) { │ │ │ │ - var id = this.container.id + "-" + graphicName; │ │ │ │ - var cache = this.symbolCache[id]; │ │ │ │ - if (cache) { │ │ │ │ - return cache │ │ │ │ + activate: function() { │ │ │ │ + var activated = false; │ │ │ │ + if (this.map) { │ │ │ │ + if (OpenLayers.Control.prototype.activate.apply(this)) { │ │ │ │ + if (this.listeners == null) { │ │ │ │ + this.setListeners() │ │ │ │ + } │ │ │ │ + for (var type in this.listeners) { │ │ │ │ + this.map.events.register(type, this, this.listeners[type]) │ │ │ │ + } │ │ │ │ + activated = true; │ │ │ │ + if (this.previousStack.length == 0) { │ │ │ │ + this.initStack() │ │ │ │ + } │ │ │ │ + } │ │ │ │ } │ │ │ │ - var symbol = OpenLayers.Renderer.symbol[graphicName]; │ │ │ │ - if (!symbol) { │ │ │ │ - throw new Error(graphicName + " is not a valid symbol name") │ │ │ │ + return activated │ │ │ │ + }, │ │ │ │ + initStack: function() { │ │ │ │ + if (this.map.getCenter()) { │ │ │ │ + this.listeners.moveend() │ │ │ │ } │ │ │ │ - var symbolExtent = new OpenLayers.Bounds(Number.MAX_VALUE, Number.MAX_VALUE, 0, 0); │ │ │ │ - var pathitems = ["m"]; │ │ │ │ - for (var i = 0; i < symbol.length; i = i + 2) { │ │ │ │ - var x = symbol[i]; │ │ │ │ - var 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); │ │ │ │ - pathitems.push(x); │ │ │ │ - pathitems.push(y); │ │ │ │ - if (i == 0) { │ │ │ │ - pathitems.push("l") │ │ │ │ + }, │ │ │ │ + deactivate: function() { │ │ │ │ + var deactivated = false; │ │ │ │ + if (this.map) { │ │ │ │ + if (OpenLayers.Control.prototype.deactivate.apply(this)) { │ │ │ │ + for (var type in this.listeners) { │ │ │ │ + this.map.events.unregister(type, this, this.listeners[type]) │ │ │ │ + } │ │ │ │ + if (this.clearOnDeactivate) { │ │ │ │ + this.clear() │ │ │ │ + } │ │ │ │ + deactivated = true │ │ │ │ } │ │ │ │ } │ │ │ │ - pathitems.push("x e"); │ │ │ │ - var path = pathitems.join(" "); │ │ │ │ - var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2; │ │ │ │ - if (diff > 0) { │ │ │ │ - symbolExtent.bottom = symbolExtent.bottom - diff; │ │ │ │ - symbolExtent.top = symbolExtent.top + diff │ │ │ │ - } else { │ │ │ │ - symbolExtent.left = symbolExtent.left + diff; │ │ │ │ - symbolExtent.right = symbolExtent.right - diff │ │ │ │ - } │ │ │ │ - cache = { │ │ │ │ - path: path, │ │ │ │ - size: symbolExtent.getWidth(), │ │ │ │ - left: symbolExtent.left, │ │ │ │ - bottom: symbolExtent.bottom │ │ │ │ - }; │ │ │ │ - this.symbolCache[id] = cache; │ │ │ │ - return cache │ │ │ │ + return deactivated │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Renderer.VML" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.NavigationHistory" │ │ │ │ }); │ │ │ │ -OpenLayers.Renderer.VML.LABEL_SHIFT = { │ │ │ │ - l: 0, │ │ │ │ - c: .5, │ │ │ │ - r: 1, │ │ │ │ - t: 0, │ │ │ │ - m: .5, │ │ │ │ - b: 1 │ │ │ │ -}; │ │ │ │ -OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, { │ │ │ │ - bounds: null, │ │ │ │ - div: null, │ │ │ │ - initialize: function(bounds, borderColor, borderWidth) { │ │ │ │ - this.bounds = bounds; │ │ │ │ - this.div = OpenLayers.Util.createDiv(); │ │ │ │ - this.div.style.overflow = "hidden"; │ │ │ │ - this.events = new OpenLayers.Events(this, this.div); │ │ │ │ - this.setBorder(borderColor, borderWidth) │ │ │ │ +OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ + layers: null, │ │ │ │ + imageFormat: "image/png", │ │ │ │ + quotaRegEx: /quota/i, │ │ │ │ + setMap: function(map) { │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ + var i, layers = this.layers || map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.addLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + if (!this.layers) { │ │ │ │ + map.events.on({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + } │ │ │ │ }, │ │ │ │ - destroy: function() { │ │ │ │ - this.bounds = null; │ │ │ │ - this.div = null; │ │ │ │ - OpenLayers.Marker.prototype.destroy.apply(this, arguments) │ │ │ │ + addLayer: function(evt) { │ │ │ │ + evt.layer.events.on({ │ │ │ │ + tileloadstart: this.makeSameOrigin, │ │ │ │ + tileloaded: this.onTileLoaded, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - setBorder: function(color, width) { │ │ │ │ - if (!color) { │ │ │ │ - color = "red" │ │ │ │ + removeLayer: function(evt) { │ │ │ │ + evt.layer.events.un({ │ │ │ │ + tileloadstart: this.makeSameOrigin, │ │ │ │ + tileloaded: this.onTileLoaded, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + makeSameOrigin: function(evt) { │ │ │ │ + if (this.active) { │ │ │ │ + var tile = evt.tile; │ │ │ │ + if (tile instanceof OpenLayers.Tile.Image && !tile.crossOriginKeyword && tile.url.substr(0, 5) !== "data:") { │ │ │ │ + var sameOriginUrl = OpenLayers.Request.makeSameOrigin(tile.url, OpenLayers.ProxyHost); │ │ │ │ + OpenLayers.Control.CacheWrite.urlMap[sameOriginUrl] = tile.url; │ │ │ │ + tile.url = sameOriginUrl │ │ │ │ + } │ │ │ │ } │ │ │ │ - if (!width) { │ │ │ │ - width = 2 │ │ │ │ + }, │ │ │ │ + onTileLoaded: function(evt) { │ │ │ │ + if (this.active && !evt.aborted && evt.tile instanceof OpenLayers.Tile.Image && evt.tile.url.substr(0, 5) !== "data:") { │ │ │ │ + this.cache({ │ │ │ │ + tile: evt.tile │ │ │ │ + }); │ │ │ │ + delete OpenLayers.Control.CacheWrite.urlMap[evt.tile.url] │ │ │ │ } │ │ │ │ - this.div.style.border = width + "px solid " + color │ │ │ │ }, │ │ │ │ - draw: function(px, sz) { │ │ │ │ - OpenLayers.Util.modifyDOMElement(this.div, null, px, sz); │ │ │ │ - return this.div │ │ │ │ + cache: function(obj) { │ │ │ │ + if (window.localStorage) { │ │ │ │ + var tile = obj.tile; │ │ │ │ + try { │ │ │ │ + var canvasContext = tile.getCanvasContext(); │ │ │ │ + if (canvasContext) { │ │ │ │ + var urlMap = OpenLayers.Control.CacheWrite.urlMap; │ │ │ │ + var url = urlMap[tile.url] || tile.url; │ │ │ │ + window.localStorage.setItem("olCache_" + url, canvasContext.canvas.toDataURL(this.imageFormat)) │ │ │ │ + } │ │ │ │ + } catch (e) { │ │ │ │ + var reason = e.name || e.message; │ │ │ │ + if (reason && this.quotaRegEx.test(reason)) { │ │ │ │ + this.events.triggerEvent("cachefull", { │ │ │ │ + tile: tile │ │ │ │ + }) │ │ │ │ + } else { │ │ │ │ + OpenLayers.Console.error(e.toString()) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ }, │ │ │ │ - onScreen: function() { │ │ │ │ - var onScreen = false; │ │ │ │ + destroy: function() { │ │ │ │ + if (this.layers || this.map) { │ │ │ │ + var i, layers = this.layers || this.map.layers; │ │ │ │ + for (i = layers.length - 1; i >= 0; --i) { │ │ │ │ + this.removeLayer({ │ │ │ │ + layer: layers[i] │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + } │ │ │ │ if (this.map) { │ │ │ │ - var screenBounds = this.map.getExtent(); │ │ │ │ - onScreen = screenBounds.containsBounds(this.bounds, true, true) │ │ │ │ + this.map.events.un({ │ │ │ │ + addlayer: this.addLayer, │ │ │ │ + removeLayer: this.removeLayer, │ │ │ │ + scope: this │ │ │ │ + }) │ │ │ │ } │ │ │ │ - return onScreen │ │ │ │ - }, │ │ │ │ - display: function(display) { │ │ │ │ - this.div.style.display = display ? "" : "none" │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Marker.Box" │ │ │ │ + CLASS_NAME: "OpenLayers.Control.CacheWrite" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.QueryStringFilter = function() { │ │ │ │ - var cmpToStr = {}; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.EQUAL_TO] = "eq"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.NOT_EQUAL_TO] = "ne"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN] = "lt"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO] = "lte"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN] = "gt"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO] = "gte"; │ │ │ │ - cmpToStr[OpenLayers.Filter.Comparison.LIKE] = "ilike"; │ │ │ │ - │ │ │ │ - function regex2value(value) { │ │ │ │ - value = value.replace(/%/g, "\\%"); │ │ │ │ - value = value.replace(/\\\\\.(\*)?/g, function($0, $1) { │ │ │ │ - return $1 ? $0 : "\\\\_" │ │ │ │ - }); │ │ │ │ - value = value.replace(/\\\\\.\*/g, "\\\\%"); │ │ │ │ - value = value.replace(/(\\)?\.(\*)?/g, function($0, $1, $2) { │ │ │ │ - return $1 || $2 ? $0 : "_" │ │ │ │ - }); │ │ │ │ - value = value.replace(/(\\)?\.\*/g, function($0, $1) { │ │ │ │ - return $1 ? $0 : "%" │ │ │ │ - }); │ │ │ │ - value = value.replace(/\\\./g, "."); │ │ │ │ - value = value.replace(/(\\)?\\\*/g, function($0, $1) { │ │ │ │ - return $1 ? $0 : "*" │ │ │ │ - }); │ │ │ │ - return value │ │ │ │ +OpenLayers.Control.CacheWrite.clearCache = function() { │ │ │ │ + if (!window.localStorage) { │ │ │ │ + return │ │ │ │ } │ │ │ │ - return OpenLayers.Class(OpenLayers.Format, { │ │ │ │ - wildcarded: false, │ │ │ │ - srsInBBOX: false, │ │ │ │ - write: function(filter, params) { │ │ │ │ - params = params || {}; │ │ │ │ - var className = filter.CLASS_NAME; │ │ │ │ - var filterType = className.substring(className.lastIndexOf(".") + 1); │ │ │ │ - switch (filterType) { │ │ │ │ - case "Spatial": │ │ │ │ - switch (filter.type) { │ │ │ │ - case OpenLayers.Filter.Spatial.BBOX: │ │ │ │ - params.bbox = filter.value.toArray(); │ │ │ │ - if (this.srsInBBOX && filter.projection) { │ │ │ │ - params.bbox.push(filter.projection.getCode()) │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case OpenLayers.Filter.Spatial.DWITHIN: │ │ │ │ - params.tolerance = filter.distance; │ │ │ │ - case OpenLayers.Filter.Spatial.WITHIN: │ │ │ │ - params.lon = filter.value.x; │ │ │ │ - params.lat = filter.value.y; │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - OpenLayers.Console.warn("Unknown spatial filter type " + filter.type) │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "Comparison": │ │ │ │ - var op = cmpToStr[filter.type]; │ │ │ │ - if (op !== undefined) { │ │ │ │ - var value = filter.value; │ │ │ │ - if (filter.type == OpenLayers.Filter.Comparison.LIKE) { │ │ │ │ - value = regex2value(value); │ │ │ │ - if (this.wildcarded) { │ │ │ │ - value = "%" + value + "%" │ │ │ │ - } │ │ │ │ - } │ │ │ │ - params[filter.property + "__" + op] = value; │ │ │ │ - params.queryable = params.queryable || []; │ │ │ │ - params.queryable.push(filter.property) │ │ │ │ - } else { │ │ │ │ - OpenLayers.Console.warn("Unknown comparison filter type " + filter.type) │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - case "Logical": │ │ │ │ - if (filter.type === OpenLayers.Filter.Logical.AND) { │ │ │ │ - for (var i = 0, len = filter.filters.length; i < len; i++) { │ │ │ │ - params = this.write(filter.filters[i], params) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Console.warn("Unsupported logical filter type " + filter.type) │ │ │ │ - } │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - OpenLayers.Console.warn("Unknown filter type " + filterType) │ │ │ │ - } │ │ │ │ - return params │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.QueryStringFilter" │ │ │ │ - }) │ │ │ │ -}(); │ │ │ │ + var i, key; │ │ │ │ + for (i = window.localStorage.length - 1; i >= 0; --i) { │ │ │ │ + key = window.localStorage.key(i); │ │ │ │ + if (key.substr(0, 8) === "olCache_") { │ │ │ │ + window.localStorage.removeItem(key) │ │ │ │ + } │ │ │ │ + } │ │ │ │ +}; │ │ │ │ +OpenLayers.Control.CacheWrite.urlMap = {}; │ │ │ │ OpenLayers.Format.WFSDescribeFeatureType = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ regExes: { │ │ │ │ trimSpace: /^\s*|\s*$/g │ │ │ │ }, │ │ │ │ namespaces: { │ │ │ │ xsd: "http://www.w3.org/2001/XMLSchema" │ │ │ │ }, │ │ │ │ @@ -32929,256 +34836,14 @@ │ │ │ │ } else { │ │ │ │ this.readNode(data, schema) │ │ │ │ } │ │ │ │ return schema │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.WFSDescribeFeatureType" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.WFS = OpenLayers.Class(OpenLayers.Format.GML, { │ │ │ │ - layer: null, │ │ │ │ - wfsns: "http://www.opengis.net/wfs", │ │ │ │ - ogcns: "http://www.opengis.net/ogc", │ │ │ │ - initialize: function(options, layer) { │ │ │ │ - OpenLayers.Format.GML.prototype.initialize.apply(this, [options]); │ │ │ │ - this.layer = layer; │ │ │ │ - if (this.layer.featureNS) { │ │ │ │ - this.featureNS = this.layer.featureNS │ │ │ │ - } │ │ │ │ - if (this.layer.options.geometry_column) { │ │ │ │ - this.geometryName = this.layer.options.geometry_column │ │ │ │ - } │ │ │ │ - if (this.layer.options.typename) { │ │ │ │ - this.featureName = this.layer.options.typename │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - write: function(features) { │ │ │ │ - var transaction = this.createElementNS(this.wfsns, "wfs:Transaction"); │ │ │ │ - transaction.setAttribute("version", "1.0.0"); │ │ │ │ - transaction.setAttribute("service", "WFS"); │ │ │ │ - for (var i = 0; i < features.length; i++) { │ │ │ │ - switch (features[i].state) { │ │ │ │ - case OpenLayers.State.INSERT: │ │ │ │ - transaction.appendChild(this.insert(features[i])); │ │ │ │ - break; │ │ │ │ - case OpenLayers.State.UPDATE: │ │ │ │ - transaction.appendChild(this.update(features[i])); │ │ │ │ - break; │ │ │ │ - case OpenLayers.State.DELETE: │ │ │ │ - transaction.appendChild(this.remove(features[i])); │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [transaction]) │ │ │ │ - }, │ │ │ │ - createFeatureXML: function(feature) { │ │ │ │ - var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ - var geomContainer = this.createElementNS(this.featureNS, "feature:" + this.geometryName); │ │ │ │ - geomContainer.appendChild(geometryNode); │ │ │ │ - var featureContainer = this.createElementNS(this.featureNS, "feature:" + this.featureName); │ │ │ │ - featureContainer.appendChild(geomContainer); │ │ │ │ - for (var attr in feature.attributes) { │ │ │ │ - var attrText = this.createTextNode(feature.attributes[attr]); │ │ │ │ - var nodename = attr; │ │ │ │ - if (attr.search(":") != -1) { │ │ │ │ - nodename = attr.split(":")[1] │ │ │ │ - } │ │ │ │ - var attrContainer = this.createElementNS(this.featureNS, "feature:" + nodename); │ │ │ │ - attrContainer.appendChild(attrText); │ │ │ │ - featureContainer.appendChild(attrContainer) │ │ │ │ - } │ │ │ │ - return featureContainer │ │ │ │ - }, │ │ │ │ - insert: function(feature) { │ │ │ │ - var insertNode = this.createElementNS(this.wfsns, "wfs:Insert"); │ │ │ │ - insertNode.appendChild(this.createFeatureXML(feature)); │ │ │ │ - return insertNode │ │ │ │ - }, │ │ │ │ - update: function(feature) { │ │ │ │ - if (!feature.fid) { │ │ │ │ - OpenLayers.Console.userError(OpenLayers.i18n("noFID")) │ │ │ │ - } │ │ │ │ - var updateNode = this.createElementNS(this.wfsns, "wfs:Update"); │ │ │ │ - updateNode.setAttribute("typeName", this.featurePrefix + ":" + this.featureName); │ │ │ │ - updateNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ - var propertyNode = this.createElementNS(this.wfsns, "wfs:Property"); │ │ │ │ - var nameNode = this.createElementNS(this.wfsns, "wfs:Name"); │ │ │ │ - var txtNode = this.createTextNode(this.geometryName); │ │ │ │ - nameNode.appendChild(txtNode); │ │ │ │ - propertyNode.appendChild(nameNode); │ │ │ │ - var valueNode = this.createElementNS(this.wfsns, "wfs:Value"); │ │ │ │ - var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ - if (feature.layer) { │ │ │ │ - geometryNode.setAttribute("srsName", feature.layer.projection.getCode()) │ │ │ │ - } │ │ │ │ - valueNode.appendChild(geometryNode); │ │ │ │ - propertyNode.appendChild(valueNode); │ │ │ │ - updateNode.appendChild(propertyNode); │ │ │ │ - for (var propName in feature.attributes) { │ │ │ │ - propertyNode = this.createElementNS(this.wfsns, "wfs:Property"); │ │ │ │ - nameNode = this.createElementNS(this.wfsns, "wfs:Name"); │ │ │ │ - nameNode.appendChild(this.createTextNode(propName)); │ │ │ │ - propertyNode.appendChild(nameNode); │ │ │ │ - valueNode = this.createElementNS(this.wfsns, "wfs:Value"); │ │ │ │ - valueNode.appendChild(this.createTextNode(feature.attributes[propName])); │ │ │ │ - propertyNode.appendChild(valueNode); │ │ │ │ - updateNode.appendChild(propertyNode) │ │ │ │ - } │ │ │ │ - var filterNode = this.createElementNS(this.ogcns, "ogc:Filter"); │ │ │ │ - var filterIdNode = this.createElementNS(this.ogcns, "ogc:FeatureId"); │ │ │ │ - filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ - filterNode.appendChild(filterIdNode); │ │ │ │ - updateNode.appendChild(filterNode); │ │ │ │ - return updateNode │ │ │ │ - }, │ │ │ │ - remove: function(feature) { │ │ │ │ - if (!feature.fid) { │ │ │ │ - OpenLayers.Console.userError(OpenLayers.i18n("noFID")); │ │ │ │ - return false │ │ │ │ - } │ │ │ │ - var deleteNode = this.createElementNS(this.wfsns, "wfs:Delete"); │ │ │ │ - deleteNode.setAttribute("typeName", this.featurePrefix + ":" + this.featureName); │ │ │ │ - deleteNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ - var filterNode = this.createElementNS(this.ogcns, "ogc:Filter"); │ │ │ │ - var filterIdNode = this.createElementNS(this.ogcns, "ogc:FeatureId"); │ │ │ │ - filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ - filterNode.appendChild(filterIdNode); │ │ │ │ - deleteNode.appendChild(filterNode); │ │ │ │ - return deleteNode │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.layer = null │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFS" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMTSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.0.0", │ │ │ │ - yx: { │ │ │ │ - "urn:ogc:def:crs:EPSG::4326": true │ │ │ │ - }, │ │ │ │ - createLayer: function(capabilities, config) { │ │ │ │ - var layer; │ │ │ │ - if (!("layer" in config)) { │ │ │ │ - throw new Error("Missing property 'layer' in configuration.") │ │ │ │ - } │ │ │ │ - var contents = capabilities.contents; │ │ │ │ - var layers = contents.layers; │ │ │ │ - var layerDef; │ │ │ │ - for (var i = 0, ii = contents.layers.length; i < ii; ++i) { │ │ │ │ - if (contents.layers[i].identifier === config.layer) { │ │ │ │ - layerDef = contents.layers[i]; │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - if (!layerDef) { │ │ │ │ - throw new Error("Layer not found") │ │ │ │ - } │ │ │ │ - var format = config.format; │ │ │ │ - if (!format && layerDef.formats && layerDef.formats.length) { │ │ │ │ - format = layerDef.formats[0] │ │ │ │ - } │ │ │ │ - var matrixSet; │ │ │ │ - if (config.matrixSet) { │ │ │ │ - matrixSet = contents.tileMatrixSets[config.matrixSet] │ │ │ │ - } else if (layerDef.tileMatrixSetLinks.length >= 1) { │ │ │ │ - matrixSet = contents.tileMatrixSets[layerDef.tileMatrixSetLinks[0].tileMatrixSet] │ │ │ │ - } │ │ │ │ - if (!matrixSet) { │ │ │ │ - throw new Error("matrixSet not found") │ │ │ │ - } │ │ │ │ - var style; │ │ │ │ - for (var i = 0, ii = layerDef.styles.length; i < ii; ++i) { │ │ │ │ - style = layerDef.styles[i]; │ │ │ │ - if (style.isDefault) { │ │ │ │ - break │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var requestEncoding = config.requestEncoding; │ │ │ │ - if (!requestEncoding) { │ │ │ │ - requestEncoding = "KVP"; │ │ │ │ - if (capabilities.operationsMetadata.GetTile.dcp.http) { │ │ │ │ - var http = capabilities.operationsMetadata.GetTile.dcp.http; │ │ │ │ - if (http.get[0].constraints) { │ │ │ │ - var constraints = http.get[0].constraints; │ │ │ │ - var allowedValues = constraints.GetEncoding.allowedValues; │ │ │ │ - if (!allowedValues.KVP && (allowedValues.REST || allowedValues.RESTful)) { │ │ │ │ - requestEncoding = "REST" │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var dimensions = []; │ │ │ │ - var params = config.params || {}; │ │ │ │ - delete config.params; │ │ │ │ - for (var id = 0, ld = layerDef.dimensions.length; id < ld; id++) { │ │ │ │ - var dimension = layerDef.dimensions[id]; │ │ │ │ - dimensions.push(dimension.identifier); │ │ │ │ - if (!params.hasOwnProperty(dimension.identifier)) { │ │ │ │ - params[dimension.identifier] = dimension["default"] │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var projection = config.projection || matrixSet.supportedCRS.replace(/urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, "$1:$3"); │ │ │ │ - var units = config.units || (projection === "EPSG:4326" ? "degrees" : "m"); │ │ │ │ - var resolutions = []; │ │ │ │ - for (var mid in matrixSet.matrixIds) { │ │ │ │ - if (matrixSet.matrixIds.hasOwnProperty(mid)) { │ │ │ │ - resolutions.push(matrixSet.matrixIds[mid].scaleDenominator * 28e-5 / OpenLayers.METERS_PER_INCH / OpenLayers.INCHES_PER_UNIT[units]) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var url; │ │ │ │ - if (requestEncoding === "REST" && layerDef.resourceUrls) { │ │ │ │ - url = []; │ │ │ │ - var resourceUrls = layerDef.resourceUrls, │ │ │ │ - resourceUrl; │ │ │ │ - for (var t = 0, tt = layerDef.resourceUrls.length; t < tt; ++t) { │ │ │ │ - resourceUrl = layerDef.resourceUrls[t]; │ │ │ │ - if (resourceUrl.format === format && resourceUrl.resourceType === "tile") { │ │ │ │ - url.push(resourceUrl.template) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - var httpGet = capabilities.operationsMetadata.GetTile.dcp.http.get; │ │ │ │ - url = []; │ │ │ │ - var constraint; │ │ │ │ - for (var i = 0, ii = httpGet.length; i < ii; i++) { │ │ │ │ - constraint = httpGet[i].constraints; │ │ │ │ - if (!constraint || constraint && constraint.GetEncoding.allowedValues[requestEncoding]) { │ │ │ │ - url.push(httpGet[i].url) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return new OpenLayers.Layer.WMTS(OpenLayers.Util.applyDefaults(config, { │ │ │ │ - url: url, │ │ │ │ - requestEncoding: requestEncoding, │ │ │ │ - name: layerDef.title, │ │ │ │ - style: style.identifier, │ │ │ │ - format: format, │ │ │ │ - matrixIds: matrixSet.matrixIds, │ │ │ │ - matrixSet: matrixSet.identifier, │ │ │ │ - projection: projection, │ │ │ │ - units: units, │ │ │ │ - resolutions: config.isBaseLayer === false ? undefined : resolutions, │ │ │ │ - serverResolutions: resolutions, │ │ │ │ - tileFullExtent: matrixSet.bounds, │ │ │ │ - dimensions: dimensions, │ │ │ │ - params: params │ │ │ │ - })) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMTSCapabilities" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.CSWGetRecords = function(options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, OpenLayers.Format.CSWGetRecords.DEFAULTS); │ │ │ │ - var cls = OpenLayers.Format.CSWGetRecords["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (!cls) { │ │ │ │ - throw "Unsupported CSWGetRecords version: " + options.version │ │ │ │ - } │ │ │ │ - return new cls(options) │ │ │ │ -}; │ │ │ │ -OpenLayers.Format.CSWGetRecords.DEFAULTS = { │ │ │ │ - version: "2.0.2" │ │ │ │ -}; │ │ │ │ OpenLayers.Format.Context = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ layerOptions: null, │ │ │ │ layerParams: null, │ │ │ │ read: function(data, options) { │ │ │ │ var context = OpenLayers.Format.XML.VersionedOGC.prototype.read.apply(this, arguments); │ │ │ │ var map; │ │ │ │ if (options && options.map) { │ │ │ │ @@ -33339,702 +35004,14 @@ │ │ │ │ WFS: "urn:ogc:serviceType:WFS", │ │ │ │ WCS: "urn:ogc:serviceType:WCS", │ │ │ │ GML: "urn:ogc:serviceType:GML", │ │ │ │ SLD: "urn:ogc:serviceType:SLD", │ │ │ │ FES: "urn:ogc:serviceType:FES", │ │ │ │ KML: "urn:ogc:serviceType:KML" │ │ │ │ }; │ │ │ │ -OpenLayers.Format.SOSGetFeatureOfInterest = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - VERSION: "1.0.0", │ │ │ │ - namespaces: { │ │ │ │ - sos: "http://www.opengis.net/sos/1.0", │ │ │ │ - gml: "http://www.opengis.net/gml", │ │ │ │ - sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ - schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosAll.xsd", │ │ │ │ - defaultPrefix: "sos", │ │ │ │ - regExes: { │ │ │ │ - trimSpace: /^\s*|\s*$/g, │ │ │ │ - removeSpace: /\s*/g, │ │ │ │ - splitSpace: /\s+/, │ │ │ │ - trimComma: /\s*,\s*/g │ │ │ │ - }, │ │ │ │ - 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 info = { │ │ │ │ - features: [] │ │ │ │ - }; │ │ │ │ - this.readNode(data, info); │ │ │ │ - var features = []; │ │ │ │ - for (var i = 0, len = info.features.length; i < len; i++) { │ │ │ │ - var container = info.features[i]; │ │ │ │ - if (this.internalProjection && this.externalProjection && container.components[0]) { │ │ │ │ - container.components[0].transform(this.externalProjection, this.internalProjection) │ │ │ │ - } │ │ │ │ - var feature = new OpenLayers.Feature.Vector(container.components[0], container.attributes); │ │ │ │ - features.push(feature) │ │ │ │ - } │ │ │ │ - return features │ │ │ │ - }, │ │ │ │ - readers: { │ │ │ │ - sa: { │ │ │ │ - SamplingPoint: function(node, obj) { │ │ │ │ - if (!obj.attributes) { │ │ │ │ - var feature = { │ │ │ │ - attributes: {} │ │ │ │ - }; │ │ │ │ - obj.features.push(feature); │ │ │ │ - obj = feature │ │ │ │ - } │ │ │ │ - obj.attributes.id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - position: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - gml: OpenLayers.Util.applyDefaults({ │ │ │ │ - FeatureCollection: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - featureMember: function(node, obj) { │ │ │ │ - var feature = { │ │ │ │ - attributes: {} │ │ │ │ - }; │ │ │ │ - obj.features.push(feature); │ │ │ │ - this.readChildNodes(node, feature) │ │ │ │ - }, │ │ │ │ - name: function(node, obj) { │ │ │ │ - obj.attributes.name = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - pos: function(node, obj) { │ │ │ │ - if (!this.externalProjection) { │ │ │ │ - this.externalProjection = new OpenLayers.Projection(node.getAttribute("srsName")) │ │ │ │ - } │ │ │ │ - OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply(this, [node, obj]) │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.GML.v3.prototype.readers.gml) │ │ │ │ - }, │ │ │ │ - writers: { │ │ │ │ - sos: { │ │ │ │ - GetFeatureOfInterest: function(options) { │ │ │ │ - var node = this.createElementNSPlus("GetFeatureOfInterest", { │ │ │ │ - attributes: { │ │ │ │ - version: this.VERSION, │ │ │ │ - service: "SOS", │ │ │ │ - "xsi:schemaLocation": this.schemaLocation │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - for (var i = 0, len = options.fois.length; i < len; i++) { │ │ │ │ - this.writeNode("FeatureOfInterestId", { │ │ │ │ - foi: options.fois[i] │ │ │ │ - }, node) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - FeatureOfInterestId: function(options) { │ │ │ │ - var node = this.createElementNSPlus("FeatureOfInterestId", { │ │ │ │ - value: options.foi │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SOSGetFeatureOfInterest" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.SOSGetObservation = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - namespaces: { │ │ │ │ - ows: "http://www.opengis.net/ows", │ │ │ │ - gml: "http://www.opengis.net/gml", │ │ │ │ - sos: "http://www.opengis.net/sos/1.0", │ │ │ │ - ogc: "http://www.opengis.net/ogc", │ │ │ │ - om: "http://www.opengis.net/om/1.0", │ │ │ │ - sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ - regExes: { │ │ │ │ - trimSpace: /^\s*|\s*$/g, │ │ │ │ - removeSpace: /\s*/g, │ │ │ │ - splitSpace: /\s+/, │ │ │ │ - trimComma: /\s*,\s*/g │ │ │ │ - }, │ │ │ │ - VERSION: "1.0.0", │ │ │ │ - schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosGetObservation.xsd", │ │ │ │ - defaultPrefix: "sos", │ │ │ │ - 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 info = { │ │ │ │ - measurements: [], │ │ │ │ - observations: [] │ │ │ │ - }; │ │ │ │ - this.readNode(data, info); │ │ │ │ - return info │ │ │ │ - }, │ │ │ │ - write: function(options) { │ │ │ │ - var node = this.writeNode("sos:GetObservation", options); │ │ │ │ - node.setAttribute("xmlns:om", this.namespaces.om); │ │ │ │ - node.setAttribute("xmlns:ogc", this.namespaces.ogc); │ │ │ │ - this.setAttributeNS(node, this.namespaces.xsi, "xsi:schemaLocation", this.schemaLocation); │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [node]) │ │ │ │ - }, │ │ │ │ - readers: { │ │ │ │ - om: { │ │ │ │ - ObservationCollection: function(node, obj) { │ │ │ │ - obj.id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - member: function(node, observationCollection) { │ │ │ │ - this.readChildNodes(node, observationCollection) │ │ │ │ - }, │ │ │ │ - Measurement: function(node, observationCollection) { │ │ │ │ - var measurement = {}; │ │ │ │ - observationCollection.measurements.push(measurement); │ │ │ │ - this.readChildNodes(node, measurement) │ │ │ │ - }, │ │ │ │ - Observation: function(node, observationCollection) { │ │ │ │ - var observation = {}; │ │ │ │ - observationCollection.observations.push(observation); │ │ │ │ - this.readChildNodes(node, observation) │ │ │ │ - }, │ │ │ │ - samplingTime: function(node, measurement) { │ │ │ │ - var samplingTime = {}; │ │ │ │ - measurement.samplingTime = samplingTime; │ │ │ │ - this.readChildNodes(node, samplingTime) │ │ │ │ - }, │ │ │ │ - observedProperty: function(node, measurement) { │ │ │ │ - measurement.observedProperty = this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ - this.readChildNodes(node, measurement) │ │ │ │ - }, │ │ │ │ - procedure: function(node, measurement) { │ │ │ │ - measurement.procedure = this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ - this.readChildNodes(node, measurement) │ │ │ │ - }, │ │ │ │ - featureOfInterest: function(node, observation) { │ │ │ │ - var foi = { │ │ │ │ - features: [] │ │ │ │ - }; │ │ │ │ - observation.fois = []; │ │ │ │ - observation.fois.push(foi); │ │ │ │ - this.readChildNodes(node, foi); │ │ │ │ - var features = []; │ │ │ │ - for (var i = 0, len = foi.features.length; i < len; i++) { │ │ │ │ - var feature = foi.features[i]; │ │ │ │ - features.push(new OpenLayers.Feature.Vector(feature.components[0], feature.attributes)) │ │ │ │ - } │ │ │ │ - foi.features = features │ │ │ │ - }, │ │ │ │ - result: function(node, measurement) { │ │ │ │ - var result = {}; │ │ │ │ - measurement.result = result; │ │ │ │ - if (this.getChildValue(node) !== "") { │ │ │ │ - result.value = this.getChildValue(node); │ │ │ │ - result.uom = node.getAttribute("uom") │ │ │ │ - } else { │ │ │ │ - this.readChildNodes(node, result) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - sa: OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.sa, │ │ │ │ - gml: OpenLayers.Util.applyDefaults({ │ │ │ │ - TimeInstant: function(node, samplingTime) { │ │ │ │ - var timeInstant = {}; │ │ │ │ - samplingTime.timeInstant = timeInstant; │ │ │ │ - this.readChildNodes(node, timeInstant) │ │ │ │ - }, │ │ │ │ - timePosition: function(node, timeInstant) { │ │ │ │ - timeInstant.timePosition = this.getChildValue(node) │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.gml) │ │ │ │ - }, │ │ │ │ - writers: { │ │ │ │ - sos: { │ │ │ │ - GetObservation: function(options) { │ │ │ │ - var node = this.createElementNSPlus("GetObservation", { │ │ │ │ - attributes: { │ │ │ │ - version: this.VERSION, │ │ │ │ - service: "SOS" │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.writeNode("offering", options, node); │ │ │ │ - if (options.eventTime) { │ │ │ │ - this.writeNode("eventTime", options, node) │ │ │ │ - } │ │ │ │ - for (var procedure in options.procedures) { │ │ │ │ - this.writeNode("procedure", options.procedures[procedure], node) │ │ │ │ - } │ │ │ │ - for (var observedProperty in options.observedProperties) { │ │ │ │ - this.writeNode("observedProperty", options.observedProperties[observedProperty], node) │ │ │ │ - } │ │ │ │ - if (options.foi) { │ │ │ │ - this.writeNode("featureOfInterest", options.foi, node) │ │ │ │ - } │ │ │ │ - this.writeNode("responseFormat", options, node); │ │ │ │ - if (options.resultModel) { │ │ │ │ - this.writeNode("resultModel", options, node) │ │ │ │ - } │ │ │ │ - if (options.responseMode) { │ │ │ │ - this.writeNode("responseMode", options, node) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - featureOfInterest: function(foi) { │ │ │ │ - var node = this.createElementNSPlus("featureOfInterest"); │ │ │ │ - this.writeNode("ObjectID", foi.objectId, node); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - ObjectID: function(options) { │ │ │ │ - return this.createElementNSPlus("ObjectID", { │ │ │ │ - value: options │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - responseFormat: function(options) { │ │ │ │ - return this.createElementNSPlus("responseFormat", { │ │ │ │ - value: options.responseFormat │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - procedure: function(procedure) { │ │ │ │ - return this.createElementNSPlus("procedure", { │ │ │ │ - value: procedure │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - offering: function(options) { │ │ │ │ - return this.createElementNSPlus("offering", { │ │ │ │ - value: options.offering │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - observedProperty: function(observedProperty) { │ │ │ │ - return this.createElementNSPlus("observedProperty", { │ │ │ │ - value: observedProperty │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - eventTime: function(options) { │ │ │ │ - var node = this.createElementNSPlus("eventTime"); │ │ │ │ - if (options.eventTime === "latest") { │ │ │ │ - this.writeNode("ogc:TM_Equals", options, node) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - resultModel: function(options) { │ │ │ │ - return this.createElementNSPlus("resultModel", { │ │ │ │ - value: options.resultModel │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - responseMode: function(options) { │ │ │ │ - return this.createElementNSPlus("responseMode", { │ │ │ │ - value: options.responseMode │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - ogc: { │ │ │ │ - TM_Equals: function(options) { │ │ │ │ - var node = this.createElementNSPlus("ogc:TM_Equals"); │ │ │ │ - this.writeNode("ogc:PropertyName", { │ │ │ │ - property: "urn:ogc:data:time:iso8601" │ │ │ │ - }, node); │ │ │ │ - if (options.eventTime === "latest") { │ │ │ │ - this.writeNode("gml:TimeInstant", { │ │ │ │ - value: "latest" │ │ │ │ - }, node) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - PropertyName: function(options) { │ │ │ │ - return this.createElementNSPlus("ogc:PropertyName", { │ │ │ │ - value: options.property │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - gml: { │ │ │ │ - TimeInstant: function(options) { │ │ │ │ - var node = this.createElementNSPlus("gml:TimeInstant"); │ │ │ │ - this.writeNode("gml:timePosition", options, node); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - timePosition: function(options) { │ │ │ │ - var node = this.createElementNSPlus("gml:timePosition", { │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SOSGetObservation" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.1.1", │ │ │ │ - profile: null, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.CQL = function() { │ │ │ │ - var tokens = ["PROPERTY", "COMPARISON", "VALUE", "LOGICAL"], │ │ │ │ - patterns = { │ │ │ │ - PROPERTY: /^[_a-zA-Z]\w*/, │ │ │ │ - COMPARISON: /^(=|<>|<=|<|>=|>|LIKE)/i, │ │ │ │ - IS_NULL: /^IS NULL/i, │ │ │ │ - COMMA: /^,/, │ │ │ │ - LOGICAL: /^(AND|OR)/i, │ │ │ │ - VALUE: /^('([^']|'')*'|\d+(\.\d*)?|\.\d+)/, │ │ │ │ - LPAREN: /^\(/, │ │ │ │ - RPAREN: /^\)/, │ │ │ │ - SPATIAL: /^(BBOX|INTERSECTS|DWITHIN|WITHIN|CONTAINS)/i, │ │ │ │ - NOT: /^NOT/i, │ │ │ │ - BETWEEN: /^BETWEEN/i, │ │ │ │ - GEOMETRY: function(text) { │ │ │ │ - var type = /^(POINT|LINESTRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)/.exec(text); │ │ │ │ - if (type) { │ │ │ │ - var len = text.length; │ │ │ │ - var idx = text.indexOf("(", type[0].length); │ │ │ │ - if (idx > -1) { │ │ │ │ - var depth = 1; │ │ │ │ - while (idx < len && depth > 0) { │ │ │ │ - idx++; │ │ │ │ - switch (text.charAt(idx)) { │ │ │ │ - case "(": │ │ │ │ - depth++; │ │ │ │ - break; │ │ │ │ - case ")": │ │ │ │ - depth--; │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return [text.substr(0, idx + 1)] │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - END: /^$/ │ │ │ │ - }, │ │ │ │ - follows = { │ │ │ │ - LPAREN: ["GEOMETRY", "SPATIAL", "PROPERTY", "VALUE", "LPAREN"], │ │ │ │ - RPAREN: ["NOT", "LOGICAL", "END", "RPAREN"], │ │ │ │ - PROPERTY: ["COMPARISON", "BETWEEN", "COMMA", "IS_NULL"], │ │ │ │ - BETWEEN: ["VALUE"], │ │ │ │ - IS_NULL: ["END"], │ │ │ │ - COMPARISON: ["VALUE"], │ │ │ │ - COMMA: ["GEOMETRY", "VALUE", "PROPERTY"], │ │ │ │ - VALUE: ["LOGICAL", "COMMA", "RPAREN", "END"], │ │ │ │ - SPATIAL: ["LPAREN"], │ │ │ │ - LOGICAL: ["NOT", "VALUE", "SPATIAL", "PROPERTY", "LPAREN"], │ │ │ │ - NOT: ["PROPERTY", "LPAREN"], │ │ │ │ - GEOMETRY: ["COMMA", "RPAREN"] │ │ │ │ - }, │ │ │ │ - operators = { │ │ │ │ - "=": OpenLayers.Filter.Comparison.EQUAL_TO, │ │ │ │ - "<>": OpenLayers.Filter.Comparison.NOT_EQUAL_TO, │ │ │ │ - "<": OpenLayers.Filter.Comparison.LESS_THAN, │ │ │ │ - "<=": OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO, │ │ │ │ - ">": OpenLayers.Filter.Comparison.GREATER_THAN, │ │ │ │ - ">=": OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO, │ │ │ │ - LIKE: OpenLayers.Filter.Comparison.LIKE, │ │ │ │ - BETWEEN: OpenLayers.Filter.Comparison.BETWEEN, │ │ │ │ - "IS NULL": OpenLayers.Filter.Comparison.IS_NULL │ │ │ │ - }, │ │ │ │ - operatorReverse = {}, │ │ │ │ - logicals = { │ │ │ │ - AND: OpenLayers.Filter.Logical.AND, │ │ │ │ - OR: OpenLayers.Filter.Logical.OR │ │ │ │ - }, │ │ │ │ - logicalReverse = {}, │ │ │ │ - precedence = { │ │ │ │ - RPAREN: 3, │ │ │ │ - LOGICAL: 2, │ │ │ │ - COMPARISON: 1 │ │ │ │ - }; │ │ │ │ - var i; │ │ │ │ - for (i in operators) { │ │ │ │ - if (operators.hasOwnProperty(i)) { │ │ │ │ - operatorReverse[operators[i]] = i │ │ │ │ - } │ │ │ │ - } │ │ │ │ - for (i in logicals) { │ │ │ │ - if (logicals.hasOwnProperty(i)) { │ │ │ │ - logicalReverse[logicals[i]] = i │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - function tryToken(text, pattern) { │ │ │ │ - if (pattern instanceof RegExp) { │ │ │ │ - return pattern.exec(text) │ │ │ │ - } else { │ │ │ │ - return pattern(text) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - │ │ │ │ - function nextToken(text, tokens) { │ │ │ │ - var i, token, len = tokens.length; │ │ │ │ - for (i = 0; i < len; i++) { │ │ │ │ - token = tokens[i]; │ │ │ │ - var pat = patterns[token]; │ │ │ │ - var matches = tryToken(text, pat); │ │ │ │ - if (matches) { │ │ │ │ - var match = matches[0]; │ │ │ │ - var remainder = text.substr(match.length).replace(/^\s*/, ""); │ │ │ │ - return { │ │ │ │ - type: token, │ │ │ │ - text: match, │ │ │ │ - remainder: remainder │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var msg = "ERROR: In parsing: [" + text + "], expected one of: "; │ │ │ │ - for (i = 0; i < len; i++) { │ │ │ │ - token = tokens[i]; │ │ │ │ - msg += "\n " + token + ": " + patterns[token] │ │ │ │ - } │ │ │ │ - throw new Error(msg) │ │ │ │ - } │ │ │ │ - │ │ │ │ - function tokenize(text) { │ │ │ │ - var results = []; │ │ │ │ - var token, expect = ["NOT", "GEOMETRY", "SPATIAL", "PROPERTY", "LPAREN"]; │ │ │ │ - do { │ │ │ │ - token = nextToken(text, expect); │ │ │ │ - text = token.remainder; │ │ │ │ - expect = follows[token.type]; │ │ │ │ - if (token.type != "END" && !expect) { │ │ │ │ - throw new Error("No follows list for " + token.type) │ │ │ │ - } │ │ │ │ - results.push(token) │ │ │ │ - } while (token.type != "END"); │ │ │ │ - return results │ │ │ │ - } │ │ │ │ - │ │ │ │ - function buildAst(tokens) { │ │ │ │ - var operatorStack = [], │ │ │ │ - postfix = []; │ │ │ │ - while (tokens.length) { │ │ │ │ - var tok = tokens.shift(); │ │ │ │ - switch (tok.type) { │ │ │ │ - case "PROPERTY": │ │ │ │ - case "GEOMETRY": │ │ │ │ - case "VALUE": │ │ │ │ - postfix.push(tok); │ │ │ │ - break; │ │ │ │ - case "COMPARISON": │ │ │ │ - case "BETWEEN": │ │ │ │ - case "IS_NULL": │ │ │ │ - case "LOGICAL": │ │ │ │ - var p = precedence[tok.type]; │ │ │ │ - while (operatorStack.length > 0 && precedence[operatorStack[operatorStack.length - 1].type] <= p) { │ │ │ │ - postfix.push(operatorStack.pop()) │ │ │ │ - } │ │ │ │ - operatorStack.push(tok); │ │ │ │ - break; │ │ │ │ - case "SPATIAL": │ │ │ │ - case "NOT": │ │ │ │ - case "LPAREN": │ │ │ │ - operatorStack.push(tok); │ │ │ │ - break; │ │ │ │ - case "RPAREN": │ │ │ │ - while (operatorStack.length > 0 && operatorStack[operatorStack.length - 1].type != "LPAREN") { │ │ │ │ - postfix.push(operatorStack.pop()) │ │ │ │ - } │ │ │ │ - operatorStack.pop(); │ │ │ │ - if (operatorStack.length > 0 && operatorStack[operatorStack.length - 1].type == "SPATIAL") { │ │ │ │ - postfix.push(operatorStack.pop()) │ │ │ │ - } │ │ │ │ - case "COMMA": │ │ │ │ - case "END": │ │ │ │ - break; │ │ │ │ - default: │ │ │ │ - throw new Error("Unknown token type " + tok.type) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - while (operatorStack.length > 0) { │ │ │ │ - postfix.push(operatorStack.pop()) │ │ │ │ - } │ │ │ │ - │ │ │ │ - function buildTree() { │ │ │ │ - var tok = postfix.pop(); │ │ │ │ - switch (tok.type) { │ │ │ │ - case "LOGICAL": │ │ │ │ - var rhs = buildTree(), │ │ │ │ - lhs = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Logical({ │ │ │ │ - filters: [lhs, rhs], │ │ │ │ - type: logicals[tok.text.toUpperCase()] │ │ │ │ - }); │ │ │ │ - case "NOT": │ │ │ │ - var operand = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Logical({ │ │ │ │ - filters: [operand], │ │ │ │ - type: OpenLayers.Filter.Logical.NOT │ │ │ │ - }); │ │ │ │ - case "BETWEEN": │ │ │ │ - var min, max, property; │ │ │ │ - postfix.pop(); │ │ │ │ - max = buildTree(); │ │ │ │ - min = buildTree(); │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Comparison({ │ │ │ │ - property: property, │ │ │ │ - lowerBoundary: min, │ │ │ │ - upperBoundary: max, │ │ │ │ - type: OpenLayers.Filter.Comparison.BETWEEN │ │ │ │ - }); │ │ │ │ - case "COMPARISON": │ │ │ │ - var value = buildTree(), │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Comparison({ │ │ │ │ - property: property, │ │ │ │ - value: value, │ │ │ │ - type: operators[tok.text.toUpperCase()] │ │ │ │ - }); │ │ │ │ - case "IS_NULL": │ │ │ │ - var property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Comparison({ │ │ │ │ - property: property, │ │ │ │ - type: operators[tok.text.toUpperCase()] │ │ │ │ - }); │ │ │ │ - case "VALUE": │ │ │ │ - var match = tok.text.match(/^'(.*)'$/); │ │ │ │ - if (match) { │ │ │ │ - return match[1].replace(/''/g, "'") │ │ │ │ - } else { │ │ │ │ - return Number(tok.text) │ │ │ │ - } │ │ │ │ - case "SPATIAL": │ │ │ │ - switch (tok.text.toUpperCase()) { │ │ │ │ - case "BBOX": │ │ │ │ - var maxy = buildTree(), │ │ │ │ - maxx = buildTree(), │ │ │ │ - miny = buildTree(), │ │ │ │ - minx = buildTree(), │ │ │ │ - prop = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ - property: prop, │ │ │ │ - value: OpenLayers.Bounds.fromArray([minx, miny, maxx, maxy]) │ │ │ │ - }); │ │ │ │ - case "INTERSECTS": │ │ │ │ - var value = buildTree(), │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ - property: property, │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - case "WITHIN": │ │ │ │ - var value = buildTree(), │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.WITHIN, │ │ │ │ - property: property, │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - case "CONTAINS": │ │ │ │ - var value = buildTree(), │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.CONTAINS, │ │ │ │ - property: property, │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - case "DWITHIN": │ │ │ │ - var distance = buildTree(), │ │ │ │ - value = buildTree(), │ │ │ │ - property = buildTree(); │ │ │ │ - return new OpenLayers.Filter.Spatial({ │ │ │ │ - type: OpenLayers.Filter.Spatial.DWITHIN, │ │ │ │ - value: value, │ │ │ │ - property: property, │ │ │ │ - distance: Number(distance) │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - case "GEOMETRY": │ │ │ │ - return OpenLayers.Geometry.fromWKT(tok.text); │ │ │ │ - default: │ │ │ │ - return tok.text │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var result = buildTree(); │ │ │ │ - if (postfix.length > 0) { │ │ │ │ - var msg = "Remaining tokens after building AST: \n"; │ │ │ │ - for (var i = postfix.length - 1; i >= 0; i--) { │ │ │ │ - msg += postfix[i].type + ": " + postfix[i].text + "\n" │ │ │ │ - } │ │ │ │ - throw new Error(msg) │ │ │ │ - } │ │ │ │ - return result │ │ │ │ - } │ │ │ │ - return OpenLayers.Class(OpenLayers.Format, { │ │ │ │ - read: function(text) { │ │ │ │ - var result = buildAst(tokenize(text)); │ │ │ │ - if (this.keepData) { │ │ │ │ - this.data = result │ │ │ │ - } │ │ │ │ - return result │ │ │ │ - }, │ │ │ │ - write: function(filter) { │ │ │ │ - if (filter instanceof OpenLayers.Geometry) { │ │ │ │ - return filter.toString() │ │ │ │ - } │ │ │ │ - switch (filter.CLASS_NAME) { │ │ │ │ - case "OpenLayers.Filter.Spatial": │ │ │ │ - switch (filter.type) { │ │ │ │ - case OpenLayers.Filter.Spatial.BBOX: │ │ │ │ - return "BBOX(" + filter.property + "," + filter.value.toBBOX() + ")"; │ │ │ │ - case OpenLayers.Filter.Spatial.DWITHIN: │ │ │ │ - return "DWITHIN(" + filter.property + ", " + this.write(filter.value) + ", " + filter.distance + ")"; │ │ │ │ - case OpenLayers.Filter.Spatial.WITHIN: │ │ │ │ - return "WITHIN(" + filter.property + ", " + this.write(filter.value) + ")"; │ │ │ │ - case OpenLayers.Filter.Spatial.INTERSECTS: │ │ │ │ - return "INTERSECTS(" + filter.property + ", " + this.write(filter.value) + ")"; │ │ │ │ - case OpenLayers.Filter.Spatial.CONTAINS: │ │ │ │ - return "CONTAINS(" + filter.property + ", " + this.write(filter.value) + ")"; │ │ │ │ - default: │ │ │ │ - throw new Error("Unknown spatial filter type: " + filter.type) │ │ │ │ - } │ │ │ │ - case "OpenLayers.Filter.Logical": │ │ │ │ - if (filter.type == OpenLayers.Filter.Logical.NOT) { │ │ │ │ - return "NOT (" + this.write(filter.filters[0]) + ")" │ │ │ │ - } else { │ │ │ │ - var res = "("; │ │ │ │ - var first = true; │ │ │ │ - for (var i = 0; i < filter.filters.length; i++) { │ │ │ │ - if (first) { │ │ │ │ - first = false │ │ │ │ - } else { │ │ │ │ - res += ") " + logicalReverse[filter.type] + " (" │ │ │ │ - } │ │ │ │ - res += this.write(filter.filters[i]) │ │ │ │ - } │ │ │ │ - return res + ")" │ │ │ │ - } │ │ │ │ - case "OpenLayers.Filter.Comparison": │ │ │ │ - if (filter.type == OpenLayers.Filter.Comparison.BETWEEN) { │ │ │ │ - return filter.property + " BETWEEN " + this.write(filter.lowerBoundary) + " AND " + this.write(filter.upperBoundary) │ │ │ │ - } else { │ │ │ │ - return filter.value !== null ? filter.property + " " + operatorReverse[filter.type] + " " + this.write(filter.value) : filter.property + " " + operatorReverse[filter.type] │ │ │ │ - } │ │ │ │ - case undefined: │ │ │ │ - if (typeof filter === "string") { │ │ │ │ - return "'" + filter.replace(/'/g, "''") + "'" │ │ │ │ - } else if (typeof filter === "number") { │ │ │ │ - return String(filter) │ │ │ │ - } │ │ │ │ - default: │ │ │ │ - throw new Error("Can't encode: " + filter.CLASS_NAME + " " + filter) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.CQL" │ │ │ │ - }) │ │ │ │ -}(); │ │ │ │ OpenLayers.Format.WMC = OpenLayers.Class(OpenLayers.Format.Context, { │ │ │ │ defaultVersion: "1.1.0", │ │ │ │ layerToContext: function(layer) { │ │ │ │ var parser = this.getParser(); │ │ │ │ var layerContext = { │ │ │ │ queryable: layer.queryable, │ │ │ │ visibility: layer.visibility, │ │ │ │ @@ -34136,230 +35113,106 @@ │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ return context │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.WMC" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.WPSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.0.0", │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WPSCapabilities" │ │ │ │ +OpenLayers.Format.WCSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.1.0", │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ - geometryType: "linestring", │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - read: function(encoded) { │ │ │ │ - var geomType; │ │ │ │ - if (this.geometryType == "linestring") geomType = OpenLayers.Geometry.LineString; │ │ │ │ - else if (this.geometryType == "linearring") geomType = OpenLayers.Geometry.LinearRing; │ │ │ │ - else if (this.geometryType == "multipoint") geomType = OpenLayers.Geometry.MultiPoint; │ │ │ │ - else if (this.geometryType != "point" && this.geometryType != "polygon") return null; │ │ │ │ - var flatPoints = this.decodeDeltas(encoded, 2); │ │ │ │ - var flatPointsLength = flatPoints.length; │ │ │ │ - var pointGeometries = []; │ │ │ │ - for (var i = 0; i + 1 < flatPointsLength;) { │ │ │ │ - var y = flatPoints[i++], │ │ │ │ - x = flatPoints[i++]; │ │ │ │ - pointGeometries.push(new OpenLayers.Geometry.Point(x, y)) │ │ │ │ - } │ │ │ │ - if (this.geometryType == "point") return new OpenLayers.Feature.Vector(pointGeometries[0]); │ │ │ │ - if (this.geometryType == "polygon") return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(pointGeometries)])); │ │ │ │ - return new OpenLayers.Feature.Vector(new geomType(pointGeometries)) │ │ │ │ - }, │ │ │ │ - decode: function(encoded, dims, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var flatPoints = this.decodeDeltas(encoded, dims, factor); │ │ │ │ - var flatPointsLength = flatPoints.length; │ │ │ │ - var points = []; │ │ │ │ - for (var i = 0; i + (dims - 1) < flatPointsLength;) { │ │ │ │ - var point = []; │ │ │ │ - for (var dim = 0; dim < dims; ++dim) { │ │ │ │ - point.push(flatPoints[i++]) │ │ │ │ - } │ │ │ │ - points.push(point) │ │ │ │ - } │ │ │ │ - return points │ │ │ │ - }, │ │ │ │ - write: function(features) { │ │ │ │ - var feature; │ │ │ │ - if (features.constructor == Array) feature = features[0]; │ │ │ │ - else feature = features; │ │ │ │ - var geometry = feature.geometry; │ │ │ │ - var type = geometry.CLASS_NAME.split(".")[2].toLowerCase(); │ │ │ │ - var pointGeometries; │ │ │ │ - if (type == "point") pointGeometries = new Array(geometry); │ │ │ │ - else if (type == "linestring" || type == "linearring" || type == "multipoint") pointGeometries = geometry.components; │ │ │ │ - else if (type == "polygon") pointGeometries = geometry.components[0].components; │ │ │ │ - else return null; │ │ │ │ - var flatPoints = []; │ │ │ │ - var pointGeometriesLength = pointGeometries.length; │ │ │ │ - for (var i = 0; i < pointGeometriesLength; ++i) { │ │ │ │ - var pointGeometry = pointGeometries[i]; │ │ │ │ - flatPoints.push(pointGeometry.y); │ │ │ │ - flatPoints.push(pointGeometry.x) │ │ │ │ - } │ │ │ │ - return this.encodeDeltas(flatPoints, 2) │ │ │ │ - }, │ │ │ │ - encode: function(points, dims, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var flatPoints = []; │ │ │ │ - var pointsLength = points.length; │ │ │ │ - for (var i = 0; i < pointsLength; ++i) { │ │ │ │ - var point = points[i]; │ │ │ │ - for (var dim = 0; dim < dims; ++dim) { │ │ │ │ - flatPoints.push(point[dim]) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return this.encodeDeltas(flatPoints, dims, factor) │ │ │ │ - }, │ │ │ │ - encodeDeltas: function(numbers, dimension, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var d; │ │ │ │ - var lastNumbers = new Array(dimension); │ │ │ │ - for (d = 0; d < dimension; ++d) { │ │ │ │ - lastNumbers[d] = 0 │ │ │ │ - } │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength;) { │ │ │ │ - for (d = 0; d < dimension; ++d, ++i) { │ │ │ │ - var num = numbers[i]; │ │ │ │ - var delta = num - lastNumbers[d]; │ │ │ │ - lastNumbers[d] = num; │ │ │ │ - numbers[i] = delta │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return this.encodeFloats(numbers, factor) │ │ │ │ - }, │ │ │ │ - decodeDeltas: function(encoded, dimension, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var d; │ │ │ │ - var lastNumbers = new Array(dimension); │ │ │ │ - for (d = 0; d < dimension; ++d) { │ │ │ │ - lastNumbers[d] = 0 │ │ │ │ - } │ │ │ │ - var numbers = this.decodeFloats(encoded, factor); │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength;) { │ │ │ │ - for (d = 0; d < dimension; ++d, ++i) { │ │ │ │ - lastNumbers[d] += numbers[i]; │ │ │ │ - numbers[i] = lastNumbers[d] │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return numbers │ │ │ │ - }, │ │ │ │ - encodeFloats: function(numbers, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength; ++i) { │ │ │ │ - numbers[i] = Math.round(numbers[i] * factor) │ │ │ │ - } │ │ │ │ - return this.encodeSignedIntegers(numbers) │ │ │ │ - }, │ │ │ │ - decodeFloats: function(encoded, opt_factor) { │ │ │ │ - var factor = opt_factor || 1e5; │ │ │ │ - var numbers = this.decodeSignedIntegers(encoded); │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength; ++i) { │ │ │ │ - numbers[i] /= factor │ │ │ │ - } │ │ │ │ - return numbers │ │ │ │ - }, │ │ │ │ - encodeSignedIntegers: function(numbers) { │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength; ++i) { │ │ │ │ - var num = numbers[i]; │ │ │ │ - var signedNum = num << 1; │ │ │ │ - if (num < 0) { │ │ │ │ - signedNum = ~signedNum │ │ │ │ - } │ │ │ │ - numbers[i] = signedNum │ │ │ │ - } │ │ │ │ - return this.encodeUnsignedIntegers(numbers) │ │ │ │ - }, │ │ │ │ - decodeSignedIntegers: function(encoded) { │ │ │ │ - var numbers = this.decodeUnsignedIntegers(encoded); │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength; ++i) { │ │ │ │ - var num = numbers[i]; │ │ │ │ - numbers[i] = num & 1 ? ~(num >> 1) : num >> 1 │ │ │ │ - } │ │ │ │ - return numbers │ │ │ │ - }, │ │ │ │ - encodeUnsignedIntegers: function(numbers) { │ │ │ │ - var encoded = ""; │ │ │ │ - var numbersLength = numbers.length; │ │ │ │ - for (var i = 0; i < numbersLength; ++i) { │ │ │ │ - encoded += this.encodeUnsignedInteger(numbers[i]) │ │ │ │ - } │ │ │ │ - return encoded │ │ │ │ - }, │ │ │ │ - decodeUnsignedIntegers: function(encoded) { │ │ │ │ - var numbers = []; │ │ │ │ - var current = 0; │ │ │ │ - var shift = 0; │ │ │ │ - var encodedLength = encoded.length; │ │ │ │ - for (var i = 0; i < encodedLength; ++i) { │ │ │ │ - var b = encoded.charCodeAt(i) - 63; │ │ │ │ - current |= (b & 31) << shift; │ │ │ │ - if (b < 32) { │ │ │ │ - numbers.push(current); │ │ │ │ - current = 0; │ │ │ │ - shift = 0 │ │ │ │ - } else { │ │ │ │ - shift += 5 │ │ │ │ +OpenLayers.Format.QueryStringFilter = function() { │ │ │ │ + var cmpToStr = {}; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.EQUAL_TO] = "eq"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.NOT_EQUAL_TO] = "ne"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN] = "lt"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO] = "lte"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN] = "gt"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO] = "gte"; │ │ │ │ + cmpToStr[OpenLayers.Filter.Comparison.LIKE] = "ilike"; │ │ │ │ + │ │ │ │ + function regex2value(value) { │ │ │ │ + value = value.replace(/%/g, "\\%"); │ │ │ │ + value = value.replace(/\\\\\.(\*)?/g, function($0, $1) { │ │ │ │ + return $1 ? $0 : "\\\\_" │ │ │ │ + }); │ │ │ │ + value = value.replace(/\\\\\.\*/g, "\\\\%"); │ │ │ │ + value = value.replace(/(\\)?\.(\*)?/g, function($0, $1, $2) { │ │ │ │ + return $1 || $2 ? $0 : "_" │ │ │ │ + }); │ │ │ │ + value = value.replace(/(\\)?\.\*/g, function($0, $1) { │ │ │ │ + return $1 ? $0 : "%" │ │ │ │ + }); │ │ │ │ + value = value.replace(/\\\./g, "."); │ │ │ │ + value = value.replace(/(\\)?\\\*/g, function($0, $1) { │ │ │ │ + return $1 ? $0 : "*" │ │ │ │ + }); │ │ │ │ + return value │ │ │ │ + } │ │ │ │ + return OpenLayers.Class(OpenLayers.Format, { │ │ │ │ + wildcarded: false, │ │ │ │ + srsInBBOX: false, │ │ │ │ + write: function(filter, params) { │ │ │ │ + params = params || {}; │ │ │ │ + var className = filter.CLASS_NAME; │ │ │ │ + var filterType = className.substring(className.lastIndexOf(".") + 1); │ │ │ │ + switch (filterType) { │ │ │ │ + case "Spatial": │ │ │ │ + switch (filter.type) { │ │ │ │ + case OpenLayers.Filter.Spatial.BBOX: │ │ │ │ + params.bbox = filter.value.toArray(); │ │ │ │ + if (this.srsInBBOX && filter.projection) { │ │ │ │ + params.bbox.push(filter.projection.getCode()) │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case OpenLayers.Filter.Spatial.DWITHIN: │ │ │ │ + params.tolerance = filter.distance; │ │ │ │ + case OpenLayers.Filter.Spatial.WITHIN: │ │ │ │ + params.lon = filter.value.x; │ │ │ │ + params.lat = filter.value.y; │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + OpenLayers.Console.warn("Unknown spatial filter type " + filter.type) │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case "Comparison": │ │ │ │ + var op = cmpToStr[filter.type]; │ │ │ │ + if (op !== undefined) { │ │ │ │ + var value = filter.value; │ │ │ │ + if (filter.type == OpenLayers.Filter.Comparison.LIKE) { │ │ │ │ + value = regex2value(value); │ │ │ │ + if (this.wildcarded) { │ │ │ │ + value = "%" + value + "%" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + params[filter.property + "__" + op] = value; │ │ │ │ + params.queryable = params.queryable || []; │ │ │ │ + params.queryable.push(filter.property) │ │ │ │ + } else { │ │ │ │ + OpenLayers.Console.warn("Unknown comparison filter type " + filter.type) │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + case "Logical": │ │ │ │ + if (filter.type === OpenLayers.Filter.Logical.AND) { │ │ │ │ + for (var i = 0, len = filter.filters.length; i < len; i++) { │ │ │ │ + params = this.write(filter.filters[i], params) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + OpenLayers.Console.warn("Unsupported logical filter type " + filter.type) │ │ │ │ + } │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + OpenLayers.Console.warn("Unknown filter type " + filterType) │ │ │ │ } │ │ │ │ - } │ │ │ │ - return numbers │ │ │ │ - }, │ │ │ │ - encodeFloat: function(num, opt_factor) { │ │ │ │ - num = Math.round(num * (opt_factor || 1e5)); │ │ │ │ - return this.encodeSignedInteger(num) │ │ │ │ - }, │ │ │ │ - decodeFloat: function(encoded, opt_factor) { │ │ │ │ - var result = this.decodeSignedInteger(encoded); │ │ │ │ - return result / (opt_factor || 1e5) │ │ │ │ - }, │ │ │ │ - encodeSignedInteger: function(num) { │ │ │ │ - var signedNum = num << 1; │ │ │ │ - if (num < 0) { │ │ │ │ - signedNum = ~signedNum │ │ │ │ - } │ │ │ │ - return this.encodeUnsignedInteger(signedNum) │ │ │ │ - }, │ │ │ │ - decodeSignedInteger: function(encoded) { │ │ │ │ - var result = this.decodeUnsignedInteger(encoded); │ │ │ │ - return result & 1 ? ~(result >> 1) : result >> 1 │ │ │ │ - }, │ │ │ │ - encodeUnsignedInteger: function(num) { │ │ │ │ - var value, encoded = ""; │ │ │ │ - while (num >= 32) { │ │ │ │ - value = (32 | num & 31) + 63; │ │ │ │ - encoded += String.fromCharCode(value); │ │ │ │ - num >>= 5 │ │ │ │ - } │ │ │ │ - value = num + 63; │ │ │ │ - encoded += String.fromCharCode(value); │ │ │ │ - return encoded │ │ │ │ - }, │ │ │ │ - decodeUnsignedInteger: function(encoded) { │ │ │ │ - var result = 0; │ │ │ │ - var shift = 0; │ │ │ │ - var encodedLength = encoded.length; │ │ │ │ - for (var i = 0; i < encodedLength; ++i) { │ │ │ │ - var b = encoded.charCodeAt(i) - 63; │ │ │ │ - result |= (b & 31) << shift; │ │ │ │ - if (b < 32) break; │ │ │ │ - shift += 5 │ │ │ │ - } │ │ │ │ - return result │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.EncodedPolyline" │ │ │ │ -}); │ │ │ │ + return params │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.QueryStringFilter" │ │ │ │ + }) │ │ │ │ +}(); │ │ │ │ OpenLayers.Format.Atom = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ namespaces: { │ │ │ │ atom: "http://www.w3.org/2005/Atom", │ │ │ │ georss: "http://www.georss.org/georss" │ │ │ │ }, │ │ │ │ feedTitle: "untitled", │ │ │ │ defaultEntryTitle: "untitled", │ │ │ │ @@ -34717,232 +35570,239 @@ │ │ │ │ } │ │ │ │ if (persons.length > 0) { │ │ │ │ data[name + "s"] = persons │ │ │ │ } │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.Atom" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.GeoRSS = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - rssns: "http://backend.userland.com/rss2", │ │ │ │ - featureNS: "http://mapserver.gis.umn.edu/mapserver", │ │ │ │ - georssns: "http://www.georss.org/georss", │ │ │ │ - geons: "http://www.w3.org/2003/01/geo/wgs84_pos#", │ │ │ │ - featureTitle: "Untitled", │ │ │ │ - featureDescription: "No Description", │ │ │ │ - gmlParser: null, │ │ │ │ - xy: false, │ │ │ │ - createGeometryFromItem: function(item) { │ │ │ │ - var point = this.getElementsByTagNameNS(item, this.georssns, "point"); │ │ │ │ - var lat = this.getElementsByTagNameNS(item, this.geons, "lat"); │ │ │ │ - var lon = this.getElementsByTagNameNS(item, this.geons, "long"); │ │ │ │ - var line = this.getElementsByTagNameNS(item, this.georssns, "line"); │ │ │ │ - var polygon = this.getElementsByTagNameNS(item, this.georssns, "polygon"); │ │ │ │ - var where = this.getElementsByTagNameNS(item, this.georssns, "where"); │ │ │ │ - var box = this.getElementsByTagNameNS(item, this.georssns, "box"); │ │ │ │ - if (point.length > 0 || lat.length > 0 && lon.length > 0) { │ │ │ │ - var location; │ │ │ │ - if (point.length > 0) { │ │ │ │ - location = OpenLayers.String.trim(point[0].firstChild.nodeValue).split(/\s+/); │ │ │ │ - if (location.length != 2) { │ │ │ │ - location = OpenLayers.String.trim(point[0].firstChild.nodeValue).split(/\s*,\s*/) │ │ │ │ - } │ │ │ │ - } else { │ │ │ │ - location = [parseFloat(lat[0].firstChild.nodeValue), parseFloat(lon[0].firstChild.nodeValue)] │ │ │ │ - } │ │ │ │ - var geometry = new OpenLayers.Geometry.Point(location[1], location[0]) │ │ │ │ - } else if (line.length > 0) { │ │ │ │ - var coords = OpenLayers.String.trim(this.getChildValue(line[0])).split(/\s+/); │ │ │ │ - var components = []; │ │ │ │ - var point; │ │ │ │ - for (var i = 0, len = coords.length; i < len; i += 2) { │ │ │ │ - point = new OpenLayers.Geometry.Point(coords[i + 1], coords[i]); │ │ │ │ - components.push(point) │ │ │ │ - } │ │ │ │ - geometry = new OpenLayers.Geometry.LineString(components) │ │ │ │ - } else if (polygon.length > 0) { │ │ │ │ - var coords = OpenLayers.String.trim(this.getChildValue(polygon[0])).split(/\s+/); │ │ │ │ - var components = []; │ │ │ │ - var point; │ │ │ │ - for (var i = 0, len = coords.length; i < len; i += 2) { │ │ │ │ - point = new OpenLayers.Geometry.Point(coords[i + 1], coords[i]); │ │ │ │ - components.push(point) │ │ │ │ - } │ │ │ │ - geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]) │ │ │ │ - } else if (where.length > 0) { │ │ │ │ - if (!this.gmlParser) { │ │ │ │ - this.gmlParser = new OpenLayers.Format.GML({ │ │ │ │ - xy: this.xy │ │ │ │ - }) │ │ │ │ - } │ │ │ │ - var feature = this.gmlParser.parseFeature(where[0]); │ │ │ │ - geometry = feature.geometry │ │ │ │ - } else if (box.length > 0) { │ │ │ │ - var coords = OpenLayers.String.trim(box[0].firstChild.nodeValue).split(/\s+/); │ │ │ │ - var components = []; │ │ │ │ - var point; │ │ │ │ - if (coords.length > 3) { │ │ │ │ - point = new OpenLayers.Geometry.Point(coords[1], coords[0]); │ │ │ │ - components.push(point); │ │ │ │ - point = new OpenLayers.Geometry.Point(coords[1], coords[2]); │ │ │ │ - components.push(point); │ │ │ │ - point = new OpenLayers.Geometry.Point(coords[3], coords[2]); │ │ │ │ - components.push(point); │ │ │ │ - point = new OpenLayers.Geometry.Point(coords[3], coords[0]); │ │ │ │ - components.push(point); │ │ │ │ - point = new OpenLayers.Geometry.Point(coords[1], coords[0]); │ │ │ │ - components.push(point) │ │ │ │ +OpenLayers.Format.WMSDescribeLayer = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.1.1", │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.SOSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.0.0", │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SOSCapabilities" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WMSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.1.1", │ │ │ │ + profile: null, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ + geometryType: "linestring", │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + read: function(encoded) { │ │ │ │ + var geomType; │ │ │ │ + if (this.geometryType == "linestring") geomType = OpenLayers.Geometry.LineString; │ │ │ │ + else if (this.geometryType == "linearring") geomType = OpenLayers.Geometry.LinearRing; │ │ │ │ + else if (this.geometryType == "multipoint") geomType = OpenLayers.Geometry.MultiPoint; │ │ │ │ + else if (this.geometryType != "point" && this.geometryType != "polygon") return null; │ │ │ │ + var flatPoints = this.decodeDeltas(encoded, 2); │ │ │ │ + var flatPointsLength = flatPoints.length; │ │ │ │ + var pointGeometries = []; │ │ │ │ + for (var i = 0; i + 1 < flatPointsLength;) { │ │ │ │ + var y = flatPoints[i++], │ │ │ │ + x = flatPoints[i++]; │ │ │ │ + pointGeometries.push(new OpenLayers.Geometry.Point(x, y)) │ │ │ │ + } │ │ │ │ + if (this.geometryType == "point") return new OpenLayers.Feature.Vector(pointGeometries[0]); │ │ │ │ + if (this.geometryType == "polygon") return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(pointGeometries)])); │ │ │ │ + return new OpenLayers.Feature.Vector(new geomType(pointGeometries)) │ │ │ │ + }, │ │ │ │ + decode: function(encoded, dims, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var flatPoints = this.decodeDeltas(encoded, dims, factor); │ │ │ │ + var flatPointsLength = flatPoints.length; │ │ │ │ + var points = []; │ │ │ │ + for (var i = 0; i + (dims - 1) < flatPointsLength;) { │ │ │ │ + var point = []; │ │ │ │ + for (var dim = 0; dim < dims; ++dim) { │ │ │ │ + point.push(flatPoints[i++]) │ │ │ │ } │ │ │ │ - geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]) │ │ │ │ + points.push(point) │ │ │ │ } │ │ │ │ - if (geometry && this.internalProjection && this.externalProjection) { │ │ │ │ - geometry.transform(this.externalProjection, this.internalProjection) │ │ │ │ + return points │ │ │ │ + }, │ │ │ │ + write: function(features) { │ │ │ │ + var feature; │ │ │ │ + if (features.constructor == Array) feature = features[0]; │ │ │ │ + else feature = features; │ │ │ │ + var geometry = feature.geometry; │ │ │ │ + var type = geometry.CLASS_NAME.split(".")[2].toLowerCase(); │ │ │ │ + var pointGeometries; │ │ │ │ + if (type == "point") pointGeometries = new Array(geometry); │ │ │ │ + else if (type == "linestring" || type == "linearring" || type == "multipoint") pointGeometries = geometry.components; │ │ │ │ + else if (type == "polygon") pointGeometries = geometry.components[0].components; │ │ │ │ + else return null; │ │ │ │ + var flatPoints = []; │ │ │ │ + var pointGeometriesLength = pointGeometries.length; │ │ │ │ + for (var i = 0; i < pointGeometriesLength; ++i) { │ │ │ │ + var pointGeometry = pointGeometries[i]; │ │ │ │ + flatPoints.push(pointGeometry.y); │ │ │ │ + flatPoints.push(pointGeometry.x) │ │ │ │ } │ │ │ │ - return geometry │ │ │ │ + return this.encodeDeltas(flatPoints, 2) │ │ │ │ }, │ │ │ │ - createFeatureFromItem: function(item) { │ │ │ │ - var geometry = this.createGeometryFromItem(item); │ │ │ │ - var title = this._getChildValue(item, "*", "title", this.featureTitle); │ │ │ │ - var description = this._getChildValue(item, "*", "description", this._getChildValue(item, "*", "content", this._getChildValue(item, "*", "summary", this.featureDescription))); │ │ │ │ - var link = this._getChildValue(item, "*", "link"); │ │ │ │ - if (!link) { │ │ │ │ - try { │ │ │ │ - link = this.getElementsByTagNameNS(item, "*", "link")[0].getAttribute("href") │ │ │ │ - } catch (e) { │ │ │ │ - link = null │ │ │ │ + encode: function(points, dims, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var flatPoints = []; │ │ │ │ + var pointsLength = points.length; │ │ │ │ + for (var i = 0; i < pointsLength; ++i) { │ │ │ │ + var point = points[i]; │ │ │ │ + for (var dim = 0; dim < dims; ++dim) { │ │ │ │ + flatPoints.push(point[dim]) │ │ │ │ } │ │ │ │ } │ │ │ │ - var id = this._getChildValue(item, "*", "id", null); │ │ │ │ - var data = { │ │ │ │ - title: title, │ │ │ │ - description: description, │ │ │ │ - link: link │ │ │ │ - }; │ │ │ │ - var feature = new OpenLayers.Feature.Vector(geometry, data); │ │ │ │ - feature.fid = id; │ │ │ │ - return feature │ │ │ │ + return this.encodeDeltas(flatPoints, dims, factor) │ │ │ │ }, │ │ │ │ - _getChildValue: function(node, nsuri, name, def) { │ │ │ │ - var value; │ │ │ │ - var eles = this.getElementsByTagNameNS(node, nsuri, name); │ │ │ │ - if (eles && eles[0] && eles[0].firstChild && eles[0].firstChild.nodeValue) { │ │ │ │ - value = this.getChildValue(eles[0]) │ │ │ │ - } else { │ │ │ │ - value = def == undefined ? "" : def │ │ │ │ + encodeDeltas: function(numbers, dimension, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var d; │ │ │ │ + var lastNumbers = new Array(dimension); │ │ │ │ + for (d = 0; d < dimension; ++d) { │ │ │ │ + lastNumbers[d] = 0 │ │ │ │ } │ │ │ │ - return value │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength;) { │ │ │ │ + for (d = 0; d < dimension; ++d, ++i) { │ │ │ │ + var num = numbers[i]; │ │ │ │ + var delta = num - lastNumbers[d]; │ │ │ │ + lastNumbers[d] = num; │ │ │ │ + numbers[i] = delta │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return this.encodeFloats(numbers, factor) │ │ │ │ }, │ │ │ │ - read: function(doc) { │ │ │ │ - if (typeof doc == "string") { │ │ │ │ - doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]) │ │ │ │ + decodeDeltas: function(encoded, dimension, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var d; │ │ │ │ + var lastNumbers = new Array(dimension); │ │ │ │ + for (d = 0; d < dimension; ++d) { │ │ │ │ + lastNumbers[d] = 0 │ │ │ │ } │ │ │ │ - var itemlist = null; │ │ │ │ - itemlist = this.getElementsByTagNameNS(doc, "*", "item"); │ │ │ │ - if (itemlist.length == 0) { │ │ │ │ - itemlist = this.getElementsByTagNameNS(doc, "*", "entry") │ │ │ │ + var numbers = this.decodeFloats(encoded, factor); │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength;) { │ │ │ │ + for (d = 0; d < dimension; ++d, ++i) { │ │ │ │ + lastNumbers[d] += numbers[i]; │ │ │ │ + numbers[i] = lastNumbers[d] │ │ │ │ + } │ │ │ │ } │ │ │ │ - var numItems = itemlist.length; │ │ │ │ - var features = new Array(numItems); │ │ │ │ - for (var i = 0; i < numItems; i++) { │ │ │ │ - features[i] = this.createFeatureFromItem(itemlist[i]) │ │ │ │ + return numbers │ │ │ │ + }, │ │ │ │ + encodeFloats: function(numbers, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength; ++i) { │ │ │ │ + numbers[i] = Math.round(numbers[i] * factor) │ │ │ │ } │ │ │ │ - return features │ │ │ │ + return this.encodeSignedIntegers(numbers) │ │ │ │ }, │ │ │ │ - write: function(features) { │ │ │ │ - var georss; │ │ │ │ - if (OpenLayers.Util.isArray(features)) { │ │ │ │ - georss = this.createElementNS(this.rssns, "rss"); │ │ │ │ - for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ - georss.appendChild(this.createFeatureXML(features[i])) │ │ │ │ + decodeFloats: function(encoded, opt_factor) { │ │ │ │ + var factor = opt_factor || 1e5; │ │ │ │ + var numbers = this.decodeSignedIntegers(encoded); │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength; ++i) { │ │ │ │ + numbers[i] /= factor │ │ │ │ + } │ │ │ │ + return numbers │ │ │ │ + }, │ │ │ │ + encodeSignedIntegers: function(numbers) { │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength; ++i) { │ │ │ │ + var num = numbers[i]; │ │ │ │ + var signedNum = num << 1; │ │ │ │ + if (num < 0) { │ │ │ │ + signedNum = ~signedNum │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - georss = this.createFeatureXML(features) │ │ │ │ + numbers[i] = signedNum │ │ │ │ } │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [georss]) │ │ │ │ + return this.encodeUnsignedIntegers(numbers) │ │ │ │ }, │ │ │ │ - createFeatureXML: function(feature) { │ │ │ │ - var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ - var featureNode = this.createElementNS(this.rssns, "item"); │ │ │ │ - var titleNode = this.createElementNS(this.rssns, "title"); │ │ │ │ - titleNode.appendChild(this.createTextNode(feature.attributes.title ? feature.attributes.title : "")); │ │ │ │ - var descNode = this.createElementNS(this.rssns, "description"); │ │ │ │ - descNode.appendChild(this.createTextNode(feature.attributes.description ? feature.attributes.description : "")); │ │ │ │ - featureNode.appendChild(titleNode); │ │ │ │ - featureNode.appendChild(descNode); │ │ │ │ - if (feature.attributes.link) { │ │ │ │ - var linkNode = this.createElementNS(this.rssns, "link"); │ │ │ │ - linkNode.appendChild(this.createTextNode(feature.attributes.link)); │ │ │ │ - featureNode.appendChild(linkNode) │ │ │ │ + decodeSignedIntegers: function(encoded) { │ │ │ │ + var numbers = this.decodeUnsignedIntegers(encoded); │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength; ++i) { │ │ │ │ + var num = numbers[i]; │ │ │ │ + numbers[i] = num & 1 ? ~(num >> 1) : num >> 1 │ │ │ │ } │ │ │ │ - for (var attr in feature.attributes) { │ │ │ │ - if (attr == "link" || attr == "title" || attr == "description") { │ │ │ │ - continue │ │ │ │ - } │ │ │ │ - var attrText = this.createTextNode(feature.attributes[attr]); │ │ │ │ - var nodename = attr; │ │ │ │ - if (attr.search(":") != -1) { │ │ │ │ - nodename = attr.split(":")[1] │ │ │ │ - } │ │ │ │ - var attrContainer = this.createElementNS(this.featureNS, "feature:" + nodename); │ │ │ │ - attrContainer.appendChild(attrText); │ │ │ │ - featureNode.appendChild(attrContainer) │ │ │ │ + return numbers │ │ │ │ + }, │ │ │ │ + encodeUnsignedIntegers: function(numbers) { │ │ │ │ + var encoded = ""; │ │ │ │ + var numbersLength = numbers.length; │ │ │ │ + for (var i = 0; i < numbersLength; ++i) { │ │ │ │ + encoded += this.encodeUnsignedInteger(numbers[i]) │ │ │ │ } │ │ │ │ - featureNode.appendChild(geometryNode); │ │ │ │ - return featureNode │ │ │ │ + return encoded │ │ │ │ }, │ │ │ │ - buildGeometryNode: function(geometry) { │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - geometry = geometry.clone(); │ │ │ │ - geometry.transform(this.internalProjection, this.externalProjection) │ │ │ │ + decodeUnsignedIntegers: function(encoded) { │ │ │ │ + var numbers = []; │ │ │ │ + var current = 0; │ │ │ │ + var shift = 0; │ │ │ │ + var encodedLength = encoded.length; │ │ │ │ + for (var i = 0; i < encodedLength; ++i) { │ │ │ │ + var b = encoded.charCodeAt(i) - 63; │ │ │ │ + current |= (b & 31) << shift; │ │ │ │ + if (b < 32) { │ │ │ │ + numbers.push(current); │ │ │ │ + current = 0; │ │ │ │ + shift = 0 │ │ │ │ + } else { │ │ │ │ + shift += 5 │ │ │ │ + } │ │ │ │ } │ │ │ │ - var node; │ │ │ │ - if (geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") { │ │ │ │ - node = this.createElementNS(this.georssns, "georss:polygon"); │ │ │ │ - node.appendChild(this.buildCoordinatesNode(geometry.components[0])) │ │ │ │ - } else if (geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") { │ │ │ │ - node = this.createElementNS(this.georssns, "georss:line"); │ │ │ │ - node.appendChild(this.buildCoordinatesNode(geometry)) │ │ │ │ - } else if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { │ │ │ │ - node = this.createElementNS(this.georssns, "georss:point"); │ │ │ │ - node.appendChild(this.buildCoordinatesNode(geometry)) │ │ │ │ - } else { │ │ │ │ - throw "Couldn't parse " + geometry.CLASS_NAME │ │ │ │ + return numbers │ │ │ │ + }, │ │ │ │ + encodeFloat: function(num, opt_factor) { │ │ │ │ + num = Math.round(num * (opt_factor || 1e5)); │ │ │ │ + return this.encodeSignedInteger(num) │ │ │ │ + }, │ │ │ │ + decodeFloat: function(encoded, opt_factor) { │ │ │ │ + var result = this.decodeSignedInteger(encoded); │ │ │ │ + return result / (opt_factor || 1e5) │ │ │ │ + }, │ │ │ │ + encodeSignedInteger: function(num) { │ │ │ │ + var signedNum = num << 1; │ │ │ │ + if (num < 0) { │ │ │ │ + signedNum = ~signedNum │ │ │ │ } │ │ │ │ - return node │ │ │ │ + return this.encodeUnsignedInteger(signedNum) │ │ │ │ }, │ │ │ │ - buildCoordinatesNode: function(geometry) { │ │ │ │ - var points = null; │ │ │ │ - if (geometry.components) { │ │ │ │ - points = geometry.components │ │ │ │ + decodeSignedInteger: function(encoded) { │ │ │ │ + var result = this.decodeUnsignedInteger(encoded); │ │ │ │ + return result & 1 ? ~(result >> 1) : result >> 1 │ │ │ │ + }, │ │ │ │ + encodeUnsignedInteger: function(num) { │ │ │ │ + var value, encoded = ""; │ │ │ │ + while (num >= 32) { │ │ │ │ + value = (32 | num & 31) + 63; │ │ │ │ + encoded += String.fromCharCode(value); │ │ │ │ + num >>= 5 │ │ │ │ } │ │ │ │ - var path; │ │ │ │ - if (points) { │ │ │ │ - var numPoints = points.length; │ │ │ │ - var parts = new Array(numPoints); │ │ │ │ - for (var i = 0; i < numPoints; i++) { │ │ │ │ - parts[i] = points[i].y + " " + points[i].x │ │ │ │ - } │ │ │ │ - path = parts.join(" ") │ │ │ │ - } else { │ │ │ │ - path = geometry.y + " " + geometry.x │ │ │ │ + value = num + 63; │ │ │ │ + encoded += String.fromCharCode(value); │ │ │ │ + return encoded │ │ │ │ + }, │ │ │ │ + decodeUnsignedInteger: function(encoded) { │ │ │ │ + var result = 0; │ │ │ │ + var shift = 0; │ │ │ │ + var encodedLength = encoded.length; │ │ │ │ + for (var i = 0; i < encodedLength; ++i) { │ │ │ │ + var b = encoded.charCodeAt(i) - 63; │ │ │ │ + result |= (b & 31) << shift; │ │ │ │ + if (b < 32) break; │ │ │ │ + shift += 5 │ │ │ │ } │ │ │ │ - return this.createTextNode(path) │ │ │ │ + return result │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.GeoRSS" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.EncodedPolyline" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.CSWGetDomain = function(options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, OpenLayers.Format.CSWGetDomain.DEFAULTS); │ │ │ │ - var cls = OpenLayers.Format.CSWGetDomain["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (!cls) { │ │ │ │ - throw "Unsupported CSWGetDomain version: " + options.version │ │ │ │ - } │ │ │ │ - return new cls(options) │ │ │ │ -}; │ │ │ │ -OpenLayers.Format.CSWGetDomain.DEFAULTS = { │ │ │ │ - version: "2.0.2" │ │ │ │ -}; │ │ │ │ OpenLayers.Format.OSM = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ checkTags: false, │ │ │ │ interestingTagsExclude: null, │ │ │ │ areaTags: null, │ │ │ │ initialize: function(options) { │ │ │ │ var layer_defaults = { │ │ │ │ interestingTagsExclude: ["source", "source_ref", "source:ref", "history", "attribution", "created_by"], │ │ │ │ @@ -35202,14 +36062,957 @@ │ │ │ │ if (state) { │ │ │ │ node.setAttribute("action", state) │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.OSM" │ │ │ │ }); │ │ │ │ +OpenLayers.Format.CQL = function() { │ │ │ │ + var tokens = ["PROPERTY", "COMPARISON", "VALUE", "LOGICAL"], │ │ │ │ + patterns = { │ │ │ │ + PROPERTY: /^[_a-zA-Z]\w*/, │ │ │ │ + COMPARISON: /^(=|<>|<=|<|>=|>|LIKE)/i, │ │ │ │ + IS_NULL: /^IS NULL/i, │ │ │ │ + COMMA: /^,/, │ │ │ │ + LOGICAL: /^(AND|OR)/i, │ │ │ │ + VALUE: /^('([^']|'')*'|\d+(\.\d*)?|\.\d+)/, │ │ │ │ + LPAREN: /^\(/, │ │ │ │ + RPAREN: /^\)/, │ │ │ │ + SPATIAL: /^(BBOX|INTERSECTS|DWITHIN|WITHIN|CONTAINS)/i, │ │ │ │ + NOT: /^NOT/i, │ │ │ │ + BETWEEN: /^BETWEEN/i, │ │ │ │ + GEOMETRY: function(text) { │ │ │ │ + var type = /^(POINT|LINESTRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)/.exec(text); │ │ │ │ + if (type) { │ │ │ │ + var len = text.length; │ │ │ │ + var idx = text.indexOf("(", type[0].length); │ │ │ │ + if (idx > -1) { │ │ │ │ + var depth = 1; │ │ │ │ + while (idx < len && depth > 0) { │ │ │ │ + idx++; │ │ │ │ + switch (text.charAt(idx)) { │ │ │ │ + case "(": │ │ │ │ + depth++; │ │ │ │ + break; │ │ │ │ + case ")": │ │ │ │ + depth--; │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return [text.substr(0, idx + 1)] │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + END: /^$/ │ │ │ │ + }, │ │ │ │ + follows = { │ │ │ │ + LPAREN: ["GEOMETRY", "SPATIAL", "PROPERTY", "VALUE", "LPAREN"], │ │ │ │ + RPAREN: ["NOT", "LOGICAL", "END", "RPAREN"], │ │ │ │ + PROPERTY: ["COMPARISON", "BETWEEN", "COMMA", "IS_NULL"], │ │ │ │ + BETWEEN: ["VALUE"], │ │ │ │ + IS_NULL: ["END"], │ │ │ │ + COMPARISON: ["VALUE"], │ │ │ │ + COMMA: ["GEOMETRY", "VALUE", "PROPERTY"], │ │ │ │ + VALUE: ["LOGICAL", "COMMA", "RPAREN", "END"], │ │ │ │ + SPATIAL: ["LPAREN"], │ │ │ │ + LOGICAL: ["NOT", "VALUE", "SPATIAL", "PROPERTY", "LPAREN"], │ │ │ │ + NOT: ["PROPERTY", "LPAREN"], │ │ │ │ + GEOMETRY: ["COMMA", "RPAREN"] │ │ │ │ + }, │ │ │ │ + operators = { │ │ │ │ + "=": OpenLayers.Filter.Comparison.EQUAL_TO, │ │ │ │ + "<>": OpenLayers.Filter.Comparison.NOT_EQUAL_TO, │ │ │ │ + "<": OpenLayers.Filter.Comparison.LESS_THAN, │ │ │ │ + "<=": OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO, │ │ │ │ + ">": OpenLayers.Filter.Comparison.GREATER_THAN, │ │ │ │ + ">=": OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO, │ │ │ │ + LIKE: OpenLayers.Filter.Comparison.LIKE, │ │ │ │ + BETWEEN: OpenLayers.Filter.Comparison.BETWEEN, │ │ │ │ + "IS NULL": OpenLayers.Filter.Comparison.IS_NULL │ │ │ │ + }, │ │ │ │ + operatorReverse = {}, │ │ │ │ + logicals = { │ │ │ │ + AND: OpenLayers.Filter.Logical.AND, │ │ │ │ + OR: OpenLayers.Filter.Logical.OR │ │ │ │ + }, │ │ │ │ + logicalReverse = {}, │ │ │ │ + precedence = { │ │ │ │ + RPAREN: 3, │ │ │ │ + LOGICAL: 2, │ │ │ │ + COMPARISON: 1 │ │ │ │ + }; │ │ │ │ + var i; │ │ │ │ + for (i in operators) { │ │ │ │ + if (operators.hasOwnProperty(i)) { │ │ │ │ + operatorReverse[operators[i]] = i │ │ │ │ + } │ │ │ │ + } │ │ │ │ + for (i in logicals) { │ │ │ │ + if (logicals.hasOwnProperty(i)) { │ │ │ │ + logicalReverse[logicals[i]] = i │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + function tryToken(text, pattern) { │ │ │ │ + if (pattern instanceof RegExp) { │ │ │ │ + return pattern.exec(text) │ │ │ │ + } else { │ │ │ │ + return pattern(text) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + │ │ │ │ + function nextToken(text, tokens) { │ │ │ │ + var i, token, len = tokens.length; │ │ │ │ + for (i = 0; i < len; i++) { │ │ │ │ + token = tokens[i]; │ │ │ │ + var pat = patterns[token]; │ │ │ │ + var matches = tryToken(text, pat); │ │ │ │ + if (matches) { │ │ │ │ + var match = matches[0]; │ │ │ │ + var remainder = text.substr(match.length).replace(/^\s*/, ""); │ │ │ │ + return { │ │ │ │ + type: token, │ │ │ │ + text: match, │ │ │ │ + remainder: remainder │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var msg = "ERROR: In parsing: [" + text + "], expected one of: "; │ │ │ │ + for (i = 0; i < len; i++) { │ │ │ │ + token = tokens[i]; │ │ │ │ + msg += "\n " + token + ": " + patterns[token] │ │ │ │ + } │ │ │ │ + throw new Error(msg) │ │ │ │ + } │ │ │ │ + │ │ │ │ + function tokenize(text) { │ │ │ │ + var results = []; │ │ │ │ + var token, expect = ["NOT", "GEOMETRY", "SPATIAL", "PROPERTY", "LPAREN"]; │ │ │ │ + do { │ │ │ │ + token = nextToken(text, expect); │ │ │ │ + text = token.remainder; │ │ │ │ + expect = follows[token.type]; │ │ │ │ + if (token.type != "END" && !expect) { │ │ │ │ + throw new Error("No follows list for " + token.type) │ │ │ │ + } │ │ │ │ + results.push(token) │ │ │ │ + } while (token.type != "END"); │ │ │ │ + return results │ │ │ │ + } │ │ │ │ + │ │ │ │ + function buildAst(tokens) { │ │ │ │ + var operatorStack = [], │ │ │ │ + postfix = []; │ │ │ │ + while (tokens.length) { │ │ │ │ + var tok = tokens.shift(); │ │ │ │ + switch (tok.type) { │ │ │ │ + case "PROPERTY": │ │ │ │ + case "GEOMETRY": │ │ │ │ + case "VALUE": │ │ │ │ + postfix.push(tok); │ │ │ │ + break; │ │ │ │ + case "COMPARISON": │ │ │ │ + case "BETWEEN": │ │ │ │ + case "IS_NULL": │ │ │ │ + case "LOGICAL": │ │ │ │ + var p = precedence[tok.type]; │ │ │ │ + while (operatorStack.length > 0 && precedence[operatorStack[operatorStack.length - 1].type] <= p) { │ │ │ │ + postfix.push(operatorStack.pop()) │ │ │ │ + } │ │ │ │ + operatorStack.push(tok); │ │ │ │ + break; │ │ │ │ + case "SPATIAL": │ │ │ │ + case "NOT": │ │ │ │ + case "LPAREN": │ │ │ │ + operatorStack.push(tok); │ │ │ │ + break; │ │ │ │ + case "RPAREN": │ │ │ │ + while (operatorStack.length > 0 && operatorStack[operatorStack.length - 1].type != "LPAREN") { │ │ │ │ + postfix.push(operatorStack.pop()) │ │ │ │ + } │ │ │ │ + operatorStack.pop(); │ │ │ │ + if (operatorStack.length > 0 && operatorStack[operatorStack.length - 1].type == "SPATIAL") { │ │ │ │ + postfix.push(operatorStack.pop()) │ │ │ │ + } │ │ │ │ + case "COMMA": │ │ │ │ + case "END": │ │ │ │ + break; │ │ │ │ + default: │ │ │ │ + throw new Error("Unknown token type " + tok.type) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + while (operatorStack.length > 0) { │ │ │ │ + postfix.push(operatorStack.pop()) │ │ │ │ + } │ │ │ │ + │ │ │ │ + function buildTree() { │ │ │ │ + var tok = postfix.pop(); │ │ │ │ + switch (tok.type) { │ │ │ │ + case "LOGICAL": │ │ │ │ + var rhs = buildTree(), │ │ │ │ + lhs = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Logical({ │ │ │ │ + filters: [lhs, rhs], │ │ │ │ + type: logicals[tok.text.toUpperCase()] │ │ │ │ + }); │ │ │ │ + case "NOT": │ │ │ │ + var operand = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Logical({ │ │ │ │ + filters: [operand], │ │ │ │ + type: OpenLayers.Filter.Logical.NOT │ │ │ │ + }); │ │ │ │ + case "BETWEEN": │ │ │ │ + var min, max, property; │ │ │ │ + postfix.pop(); │ │ │ │ + max = buildTree(); │ │ │ │ + min = buildTree(); │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Comparison({ │ │ │ │ + property: property, │ │ │ │ + lowerBoundary: min, │ │ │ │ + upperBoundary: max, │ │ │ │ + type: OpenLayers.Filter.Comparison.BETWEEN │ │ │ │ + }); │ │ │ │ + case "COMPARISON": │ │ │ │ + var value = buildTree(), │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Comparison({ │ │ │ │ + property: property, │ │ │ │ + value: value, │ │ │ │ + type: operators[tok.text.toUpperCase()] │ │ │ │ + }); │ │ │ │ + case "IS_NULL": │ │ │ │ + var property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Comparison({ │ │ │ │ + property: property, │ │ │ │ + type: operators[tok.text.toUpperCase()] │ │ │ │ + }); │ │ │ │ + case "VALUE": │ │ │ │ + var match = tok.text.match(/^'(.*)'$/); │ │ │ │ + if (match) { │ │ │ │ + return match[1].replace(/''/g, "'") │ │ │ │ + } else { │ │ │ │ + return Number(tok.text) │ │ │ │ + } │ │ │ │ + case "SPATIAL": │ │ │ │ + switch (tok.text.toUpperCase()) { │ │ │ │ + case "BBOX": │ │ │ │ + var maxy = buildTree(), │ │ │ │ + maxx = buildTree(), │ │ │ │ + miny = buildTree(), │ │ │ │ + minx = buildTree(), │ │ │ │ + prop = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ + property: prop, │ │ │ │ + value: OpenLayers.Bounds.fromArray([minx, miny, maxx, maxy]) │ │ │ │ + }); │ │ │ │ + case "INTERSECTS": │ │ │ │ + var value = buildTree(), │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.INTERSECTS, │ │ │ │ + property: property, │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + case "WITHIN": │ │ │ │ + var value = buildTree(), │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.WITHIN, │ │ │ │ + property: property, │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + case "CONTAINS": │ │ │ │ + var value = buildTree(), │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.CONTAINS, │ │ │ │ + property: property, │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + case "DWITHIN": │ │ │ │ + var distance = buildTree(), │ │ │ │ + value = buildTree(), │ │ │ │ + property = buildTree(); │ │ │ │ + return new OpenLayers.Filter.Spatial({ │ │ │ │ + type: OpenLayers.Filter.Spatial.DWITHIN, │ │ │ │ + value: value, │ │ │ │ + property: property, │ │ │ │ + distance: Number(distance) │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + case "GEOMETRY": │ │ │ │ + return OpenLayers.Geometry.fromWKT(tok.text); │ │ │ │ + default: │ │ │ │ + return tok.text │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var result = buildTree(); │ │ │ │ + if (postfix.length > 0) { │ │ │ │ + var msg = "Remaining tokens after building AST: \n"; │ │ │ │ + for (var i = postfix.length - 1; i >= 0; i--) { │ │ │ │ + msg += postfix[i].type + ": " + postfix[i].text + "\n" │ │ │ │ + } │ │ │ │ + throw new Error(msg) │ │ │ │ + } │ │ │ │ + return result │ │ │ │ + } │ │ │ │ + return OpenLayers.Class(OpenLayers.Format, { │ │ │ │ + read: function(text) { │ │ │ │ + var result = buildAst(tokenize(text)); │ │ │ │ + if (this.keepData) { │ │ │ │ + this.data = result │ │ │ │ + } │ │ │ │ + return result │ │ │ │ + }, │ │ │ │ + write: function(filter) { │ │ │ │ + if (filter instanceof OpenLayers.Geometry) { │ │ │ │ + return filter.toString() │ │ │ │ + } │ │ │ │ + switch (filter.CLASS_NAME) { │ │ │ │ + case "OpenLayers.Filter.Spatial": │ │ │ │ + switch (filter.type) { │ │ │ │ + case OpenLayers.Filter.Spatial.BBOX: │ │ │ │ + return "BBOX(" + filter.property + "," + filter.value.toBBOX() + ")"; │ │ │ │ + case OpenLayers.Filter.Spatial.DWITHIN: │ │ │ │ + return "DWITHIN(" + filter.property + ", " + this.write(filter.value) + ", " + filter.distance + ")"; │ │ │ │ + case OpenLayers.Filter.Spatial.WITHIN: │ │ │ │ + return "WITHIN(" + filter.property + ", " + this.write(filter.value) + ")"; │ │ │ │ + case OpenLayers.Filter.Spatial.INTERSECTS: │ │ │ │ + return "INTERSECTS(" + filter.property + ", " + this.write(filter.value) + ")"; │ │ │ │ + case OpenLayers.Filter.Spatial.CONTAINS: │ │ │ │ + return "CONTAINS(" + filter.property + ", " + this.write(filter.value) + ")"; │ │ │ │ + default: │ │ │ │ + throw new Error("Unknown spatial filter type: " + filter.type) │ │ │ │ + } │ │ │ │ + case "OpenLayers.Filter.Logical": │ │ │ │ + if (filter.type == OpenLayers.Filter.Logical.NOT) { │ │ │ │ + return "NOT (" + this.write(filter.filters[0]) + ")" │ │ │ │ + } else { │ │ │ │ + var res = "("; │ │ │ │ + var first = true; │ │ │ │ + for (var i = 0; i < filter.filters.length; i++) { │ │ │ │ + if (first) { │ │ │ │ + first = false │ │ │ │ + } else { │ │ │ │ + res += ") " + logicalReverse[filter.type] + " (" │ │ │ │ + } │ │ │ │ + res += this.write(filter.filters[i]) │ │ │ │ + } │ │ │ │ + return res + ")" │ │ │ │ + } │ │ │ │ + case "OpenLayers.Filter.Comparison": │ │ │ │ + if (filter.type == OpenLayers.Filter.Comparison.BETWEEN) { │ │ │ │ + return filter.property + " BETWEEN " + this.write(filter.lowerBoundary) + " AND " + this.write(filter.upperBoundary) │ │ │ │ + } else { │ │ │ │ + return filter.value !== null ? filter.property + " " + operatorReverse[filter.type] + " " + this.write(filter.value) : filter.property + " " + operatorReverse[filter.type] │ │ │ │ + } │ │ │ │ + case undefined: │ │ │ │ + if (typeof filter === "string") { │ │ │ │ + return "'" + filter.replace(/'/g, "''") + "'" │ │ │ │ + } else if (typeof filter === "number") { │ │ │ │ + return String(filter) │ │ │ │ + } │ │ │ │ + default: │ │ │ │ + throw new Error("Can't encode: " + filter.CLASS_NAME + " " + filter) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.CQL" │ │ │ │ + }) │ │ │ │ +}(); │ │ │ │ +OpenLayers.Format.XLS = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.1.0", │ │ │ │ + stringifyOutput: true, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.XLS" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.OWSContext = OpenLayers.Class(OpenLayers.Format.Context, { │ │ │ │ + defaultVersion: "0.3.1", │ │ │ │ + getVersion: function(root, options) { │ │ │ │ + var version = OpenLayers.Format.XML.VersionedOGC.prototype.getVersion.apply(this, arguments); │ │ │ │ + if (version === "0.3.0") { │ │ │ │ + version = this.defaultVersion │ │ │ │ + } │ │ │ │ + return version │ │ │ │ + }, │ │ │ │ + toContext: function(obj) { │ │ │ │ + var context = {}; │ │ │ │ + if (obj.CLASS_NAME == "OpenLayers.Map") { │ │ │ │ + context.bounds = obj.getExtent(); │ │ │ │ + context.maxExtent = obj.maxExtent; │ │ │ │ + context.projection = obj.projection; │ │ │ │ + context.size = obj.getSize(); │ │ │ │ + context.layers = obj.layers │ │ │ │ + } │ │ │ │ + return context │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.OWSContext" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.SOSGetObservation = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + namespaces: { │ │ │ │ + ows: "http://www.opengis.net/ows", │ │ │ │ + gml: "http://www.opengis.net/gml", │ │ │ │ + sos: "http://www.opengis.net/sos/1.0", │ │ │ │ + ogc: "http://www.opengis.net/ogc", │ │ │ │ + om: "http://www.opengis.net/om/1.0", │ │ │ │ + sa: "http://www.opengis.net/sampling/1.0", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + }, │ │ │ │ + regExes: { │ │ │ │ + trimSpace: /^\s*|\s*$/g, │ │ │ │ + removeSpace: /\s*/g, │ │ │ │ + splitSpace: /\s+/, │ │ │ │ + trimComma: /\s*,\s*/g │ │ │ │ + }, │ │ │ │ + VERSION: "1.0.0", │ │ │ │ + schemaLocation: "http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosGetObservation.xsd", │ │ │ │ + defaultPrefix: "sos", │ │ │ │ + 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 info = { │ │ │ │ + measurements: [], │ │ │ │ + observations: [] │ │ │ │ + }; │ │ │ │ + this.readNode(data, info); │ │ │ │ + return info │ │ │ │ + }, │ │ │ │ + write: function(options) { │ │ │ │ + var node = this.writeNode("sos:GetObservation", options); │ │ │ │ + node.setAttribute("xmlns:om", this.namespaces.om); │ │ │ │ + node.setAttribute("xmlns:ogc", this.namespaces.ogc); │ │ │ │ + this.setAttributeNS(node, this.namespaces.xsi, "xsi:schemaLocation", this.schemaLocation); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [node]) │ │ │ │ + }, │ │ │ │ + readers: { │ │ │ │ + om: { │ │ │ │ + ObservationCollection: function(node, obj) { │ │ │ │ + obj.id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + member: function(node, observationCollection) { │ │ │ │ + this.readChildNodes(node, observationCollection) │ │ │ │ + }, │ │ │ │ + Measurement: function(node, observationCollection) { │ │ │ │ + var measurement = {}; │ │ │ │ + observationCollection.measurements.push(measurement); │ │ │ │ + this.readChildNodes(node, measurement) │ │ │ │ + }, │ │ │ │ + Observation: function(node, observationCollection) { │ │ │ │ + var observation = {}; │ │ │ │ + observationCollection.observations.push(observation); │ │ │ │ + this.readChildNodes(node, observation) │ │ │ │ + }, │ │ │ │ + samplingTime: function(node, measurement) { │ │ │ │ + var samplingTime = {}; │ │ │ │ + measurement.samplingTime = samplingTime; │ │ │ │ + this.readChildNodes(node, samplingTime) │ │ │ │ + }, │ │ │ │ + observedProperty: function(node, measurement) { │ │ │ │ + measurement.observedProperty = this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ + this.readChildNodes(node, measurement) │ │ │ │ + }, │ │ │ │ + procedure: function(node, measurement) { │ │ │ │ + measurement.procedure = this.getAttributeNS(node, this.namespaces.xlink, "href"); │ │ │ │ + this.readChildNodes(node, measurement) │ │ │ │ + }, │ │ │ │ + featureOfInterest: function(node, observation) { │ │ │ │ + var foi = { │ │ │ │ + features: [] │ │ │ │ + }; │ │ │ │ + observation.fois = []; │ │ │ │ + observation.fois.push(foi); │ │ │ │ + this.readChildNodes(node, foi); │ │ │ │ + var features = []; │ │ │ │ + for (var i = 0, len = foi.features.length; i < len; i++) { │ │ │ │ + var feature = foi.features[i]; │ │ │ │ + features.push(new OpenLayers.Feature.Vector(feature.components[0], feature.attributes)) │ │ │ │ + } │ │ │ │ + foi.features = features │ │ │ │ + }, │ │ │ │ + result: function(node, measurement) { │ │ │ │ + var result = {}; │ │ │ │ + measurement.result = result; │ │ │ │ + if (this.getChildValue(node) !== "") { │ │ │ │ + result.value = this.getChildValue(node); │ │ │ │ + result.uom = node.getAttribute("uom") │ │ │ │ + } else { │ │ │ │ + this.readChildNodes(node, result) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + sa: OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.sa, │ │ │ │ + gml: OpenLayers.Util.applyDefaults({ │ │ │ │ + TimeInstant: function(node, samplingTime) { │ │ │ │ + var timeInstant = {}; │ │ │ │ + samplingTime.timeInstant = timeInstant; │ │ │ │ + this.readChildNodes(node, timeInstant) │ │ │ │ + }, │ │ │ │ + timePosition: function(node, timeInstant) { │ │ │ │ + timeInstant.timePosition = this.getChildValue(node) │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.gml) │ │ │ │ + }, │ │ │ │ + writers: { │ │ │ │ + sos: { │ │ │ │ + GetObservation: function(options) { │ │ │ │ + var node = this.createElementNSPlus("GetObservation", { │ │ │ │ + attributes: { │ │ │ │ + version: this.VERSION, │ │ │ │ + service: "SOS" │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.writeNode("offering", options, node); │ │ │ │ + if (options.eventTime) { │ │ │ │ + this.writeNode("eventTime", options, node) │ │ │ │ + } │ │ │ │ + for (var procedure in options.procedures) { │ │ │ │ + this.writeNode("procedure", options.procedures[procedure], node) │ │ │ │ + } │ │ │ │ + for (var observedProperty in options.observedProperties) { │ │ │ │ + this.writeNode("observedProperty", options.observedProperties[observedProperty], node) │ │ │ │ + } │ │ │ │ + if (options.foi) { │ │ │ │ + this.writeNode("featureOfInterest", options.foi, node) │ │ │ │ + } │ │ │ │ + this.writeNode("responseFormat", options, node); │ │ │ │ + if (options.resultModel) { │ │ │ │ + this.writeNode("resultModel", options, node) │ │ │ │ + } │ │ │ │ + if (options.responseMode) { │ │ │ │ + this.writeNode("responseMode", options, node) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + featureOfInterest: function(foi) { │ │ │ │ + var node = this.createElementNSPlus("featureOfInterest"); │ │ │ │ + this.writeNode("ObjectID", foi.objectId, node); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + ObjectID: function(options) { │ │ │ │ + return this.createElementNSPlus("ObjectID", { │ │ │ │ + value: options │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + responseFormat: function(options) { │ │ │ │ + return this.createElementNSPlus("responseFormat", { │ │ │ │ + value: options.responseFormat │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + procedure: function(procedure) { │ │ │ │ + return this.createElementNSPlus("procedure", { │ │ │ │ + value: procedure │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + offering: function(options) { │ │ │ │ + return this.createElementNSPlus("offering", { │ │ │ │ + value: options.offering │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + observedProperty: function(observedProperty) { │ │ │ │ + return this.createElementNSPlus("observedProperty", { │ │ │ │ + value: observedProperty │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + eventTime: function(options) { │ │ │ │ + var node = this.createElementNSPlus("eventTime"); │ │ │ │ + if (options.eventTime === "latest") { │ │ │ │ + this.writeNode("ogc:TM_Equals", options, node) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + resultModel: function(options) { │ │ │ │ + return this.createElementNSPlus("resultModel", { │ │ │ │ + value: options.resultModel │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + responseMode: function(options) { │ │ │ │ + return this.createElementNSPlus("responseMode", { │ │ │ │ + value: options.responseMode │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + ogc: { │ │ │ │ + TM_Equals: function(options) { │ │ │ │ + var node = this.createElementNSPlus("ogc:TM_Equals"); │ │ │ │ + this.writeNode("ogc:PropertyName", { │ │ │ │ + property: "urn:ogc:data:time:iso8601" │ │ │ │ + }, node); │ │ │ │ + if (options.eventTime === "latest") { │ │ │ │ + this.writeNode("gml:TimeInstant", { │ │ │ │ + value: "latest" │ │ │ │ + }, node) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + PropertyName: function(options) { │ │ │ │ + return this.createElementNSPlus("ogc:PropertyName", { │ │ │ │ + value: options.property │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + gml: { │ │ │ │ + TimeInstant: function(options) { │ │ │ │ + var node = this.createElementNSPlus("gml:TimeInstant"); │ │ │ │ + this.writeNode("gml:timePosition", options, node); │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + timePosition: function(options) { │ │ │ │ + var node = this.createElementNSPlus("gml:timePosition", { │ │ │ │ + value: options.value │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SOSGetObservation" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WMTSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.0.0", │ │ │ │ + yx: { │ │ │ │ + "urn:ogc:def:crs:EPSG::4326": true │ │ │ │ + }, │ │ │ │ + createLayer: function(capabilities, config) { │ │ │ │ + var layer; │ │ │ │ + if (!("layer" in config)) { │ │ │ │ + throw new Error("Missing property 'layer' in configuration.") │ │ │ │ + } │ │ │ │ + var contents = capabilities.contents; │ │ │ │ + var layers = contents.layers; │ │ │ │ + var layerDef; │ │ │ │ + for (var i = 0, ii = contents.layers.length; i < ii; ++i) { │ │ │ │ + if (contents.layers[i].identifier === config.layer) { │ │ │ │ + layerDef = contents.layers[i]; │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + if (!layerDef) { │ │ │ │ + throw new Error("Layer not found") │ │ │ │ + } │ │ │ │ + var format = config.format; │ │ │ │ + if (!format && layerDef.formats && layerDef.formats.length) { │ │ │ │ + format = layerDef.formats[0] │ │ │ │ + } │ │ │ │ + var matrixSet; │ │ │ │ + if (config.matrixSet) { │ │ │ │ + matrixSet = contents.tileMatrixSets[config.matrixSet] │ │ │ │ + } else if (layerDef.tileMatrixSetLinks.length >= 1) { │ │ │ │ + matrixSet = contents.tileMatrixSets[layerDef.tileMatrixSetLinks[0].tileMatrixSet] │ │ │ │ + } │ │ │ │ + if (!matrixSet) { │ │ │ │ + throw new Error("matrixSet not found") │ │ │ │ + } │ │ │ │ + var style; │ │ │ │ + for (var i = 0, ii = layerDef.styles.length; i < ii; ++i) { │ │ │ │ + style = layerDef.styles[i]; │ │ │ │ + if (style.isDefault) { │ │ │ │ + break │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var requestEncoding = config.requestEncoding; │ │ │ │ + if (!requestEncoding) { │ │ │ │ + requestEncoding = "KVP"; │ │ │ │ + if (capabilities.operationsMetadata.GetTile.dcp.http) { │ │ │ │ + var http = capabilities.operationsMetadata.GetTile.dcp.http; │ │ │ │ + if (http.get[0].constraints) { │ │ │ │ + var constraints = http.get[0].constraints; │ │ │ │ + var allowedValues = constraints.GetEncoding.allowedValues; │ │ │ │ + if (!allowedValues.KVP && (allowedValues.REST || allowedValues.RESTful)) { │ │ │ │ + requestEncoding = "REST" │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var dimensions = []; │ │ │ │ + var params = config.params || {}; │ │ │ │ + delete config.params; │ │ │ │ + for (var id = 0, ld = layerDef.dimensions.length; id < ld; id++) { │ │ │ │ + var dimension = layerDef.dimensions[id]; │ │ │ │ + dimensions.push(dimension.identifier); │ │ │ │ + if (!params.hasOwnProperty(dimension.identifier)) { │ │ │ │ + params[dimension.identifier] = dimension["default"] │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var projection = config.projection || matrixSet.supportedCRS.replace(/urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, "$1:$3"); │ │ │ │ + var units = config.units || (projection === "EPSG:4326" ? "degrees" : "m"); │ │ │ │ + var resolutions = []; │ │ │ │ + for (var mid in matrixSet.matrixIds) { │ │ │ │ + if (matrixSet.matrixIds.hasOwnProperty(mid)) { │ │ │ │ + resolutions.push(matrixSet.matrixIds[mid].scaleDenominator * 28e-5 / OpenLayers.METERS_PER_INCH / OpenLayers.INCHES_PER_UNIT[units]) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var url; │ │ │ │ + if (requestEncoding === "REST" && layerDef.resourceUrls) { │ │ │ │ + url = []; │ │ │ │ + var resourceUrls = layerDef.resourceUrls, │ │ │ │ + resourceUrl; │ │ │ │ + for (var t = 0, tt = layerDef.resourceUrls.length; t < tt; ++t) { │ │ │ │ + resourceUrl = layerDef.resourceUrls[t]; │ │ │ │ + if (resourceUrl.format === format && resourceUrl.resourceType === "tile") { │ │ │ │ + url.push(resourceUrl.template) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + var httpGet = capabilities.operationsMetadata.GetTile.dcp.http.get; │ │ │ │ + url = []; │ │ │ │ + var constraint; │ │ │ │ + for (var i = 0, ii = httpGet.length; i < ii; i++) { │ │ │ │ + constraint = httpGet[i].constraints; │ │ │ │ + if (!constraint || constraint && constraint.GetEncoding.allowedValues[requestEncoding]) { │ │ │ │ + url.push(httpGet[i].url) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return new OpenLayers.Layer.WMTS(OpenLayers.Util.applyDefaults(config, { │ │ │ │ + url: url, │ │ │ │ + requestEncoding: requestEncoding, │ │ │ │ + name: layerDef.title, │ │ │ │ + style: style.identifier, │ │ │ │ + format: format, │ │ │ │ + matrixIds: matrixSet.matrixIds, │ │ │ │ + matrixSet: matrixSet.identifier, │ │ │ │ + projection: projection, │ │ │ │ + units: units, │ │ │ │ + resolutions: config.isBaseLayer === false ? undefined : resolutions, │ │ │ │ + serverResolutions: resolutions, │ │ │ │ + tileFullExtent: matrixSet.bounds, │ │ │ │ + dimensions: dimensions, │ │ │ │ + params: params │ │ │ │ + })) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMTSCapabilities" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.GeoRSS = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + rssns: "http://backend.userland.com/rss2", │ │ │ │ + featureNS: "http://mapserver.gis.umn.edu/mapserver", │ │ │ │ + georssns: "http://www.georss.org/georss", │ │ │ │ + geons: "http://www.w3.org/2003/01/geo/wgs84_pos#", │ │ │ │ + featureTitle: "Untitled", │ │ │ │ + featureDescription: "No Description", │ │ │ │ + gmlParser: null, │ │ │ │ + xy: false, │ │ │ │ + createGeometryFromItem: function(item) { │ │ │ │ + var point = this.getElementsByTagNameNS(item, this.georssns, "point"); │ │ │ │ + var lat = this.getElementsByTagNameNS(item, this.geons, "lat"); │ │ │ │ + var lon = this.getElementsByTagNameNS(item, this.geons, "long"); │ │ │ │ + var line = this.getElementsByTagNameNS(item, this.georssns, "line"); │ │ │ │ + var polygon = this.getElementsByTagNameNS(item, this.georssns, "polygon"); │ │ │ │ + var where = this.getElementsByTagNameNS(item, this.georssns, "where"); │ │ │ │ + var box = this.getElementsByTagNameNS(item, this.georssns, "box"); │ │ │ │ + if (point.length > 0 || lat.length > 0 && lon.length > 0) { │ │ │ │ + var location; │ │ │ │ + if (point.length > 0) { │ │ │ │ + location = OpenLayers.String.trim(point[0].firstChild.nodeValue).split(/\s+/); │ │ │ │ + if (location.length != 2) { │ │ │ │ + location = OpenLayers.String.trim(point[0].firstChild.nodeValue).split(/\s*,\s*/) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + location = [parseFloat(lat[0].firstChild.nodeValue), parseFloat(lon[0].firstChild.nodeValue)] │ │ │ │ + } │ │ │ │ + var geometry = new OpenLayers.Geometry.Point(location[1], location[0]) │ │ │ │ + } else if (line.length > 0) { │ │ │ │ + var coords = OpenLayers.String.trim(this.getChildValue(line[0])).split(/\s+/); │ │ │ │ + var components = []; │ │ │ │ + var point; │ │ │ │ + for (var i = 0, len = coords.length; i < len; i += 2) { │ │ │ │ + point = new OpenLayers.Geometry.Point(coords[i + 1], coords[i]); │ │ │ │ + components.push(point) │ │ │ │ + } │ │ │ │ + geometry = new OpenLayers.Geometry.LineString(components) │ │ │ │ + } else if (polygon.length > 0) { │ │ │ │ + var coords = OpenLayers.String.trim(this.getChildValue(polygon[0])).split(/\s+/); │ │ │ │ + var components = []; │ │ │ │ + var point; │ │ │ │ + for (var i = 0, len = coords.length; i < len; i += 2) { │ │ │ │ + point = new OpenLayers.Geometry.Point(coords[i + 1], coords[i]); │ │ │ │ + components.push(point) │ │ │ │ + } │ │ │ │ + geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]) │ │ │ │ + } else if (where.length > 0) { │ │ │ │ + if (!this.gmlParser) { │ │ │ │ + this.gmlParser = new OpenLayers.Format.GML({ │ │ │ │ + xy: this.xy │ │ │ │ + }) │ │ │ │ + } │ │ │ │ + var feature = this.gmlParser.parseFeature(where[0]); │ │ │ │ + geometry = feature.geometry │ │ │ │ + } else if (box.length > 0) { │ │ │ │ + var coords = OpenLayers.String.trim(box[0].firstChild.nodeValue).split(/\s+/); │ │ │ │ + var components = []; │ │ │ │ + var point; │ │ │ │ + if (coords.length > 3) { │ │ │ │ + point = new OpenLayers.Geometry.Point(coords[1], coords[0]); │ │ │ │ + components.push(point); │ │ │ │ + point = new OpenLayers.Geometry.Point(coords[1], coords[2]); │ │ │ │ + components.push(point); │ │ │ │ + point = new OpenLayers.Geometry.Point(coords[3], coords[2]); │ │ │ │ + components.push(point); │ │ │ │ + point = new OpenLayers.Geometry.Point(coords[3], coords[0]); │ │ │ │ + components.push(point); │ │ │ │ + point = new OpenLayers.Geometry.Point(coords[1], coords[0]); │ │ │ │ + components.push(point) │ │ │ │ + } │ │ │ │ + geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]) │ │ │ │ + } │ │ │ │ + if (geometry && this.internalProjection && this.externalProjection) { │ │ │ │ + geometry.transform(this.externalProjection, this.internalProjection) │ │ │ │ + } │ │ │ │ + return geometry │ │ │ │ + }, │ │ │ │ + createFeatureFromItem: function(item) { │ │ │ │ + var geometry = this.createGeometryFromItem(item); │ │ │ │ + var title = this._getChildValue(item, "*", "title", this.featureTitle); │ │ │ │ + var description = this._getChildValue(item, "*", "description", this._getChildValue(item, "*", "content", this._getChildValue(item, "*", "summary", this.featureDescription))); │ │ │ │ + var link = this._getChildValue(item, "*", "link"); │ │ │ │ + if (!link) { │ │ │ │ + try { │ │ │ │ + link = this.getElementsByTagNameNS(item, "*", "link")[0].getAttribute("href") │ │ │ │ + } catch (e) { │ │ │ │ + link = null │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var id = this._getChildValue(item, "*", "id", null); │ │ │ │ + var data = { │ │ │ │ + title: title, │ │ │ │ + description: description, │ │ │ │ + link: link │ │ │ │ + }; │ │ │ │ + var feature = new OpenLayers.Feature.Vector(geometry, data); │ │ │ │ + feature.fid = id; │ │ │ │ + return feature │ │ │ │ + }, │ │ │ │ + _getChildValue: function(node, nsuri, name, def) { │ │ │ │ + var value; │ │ │ │ + var eles = this.getElementsByTagNameNS(node, nsuri, name); │ │ │ │ + if (eles && eles[0] && eles[0].firstChild && eles[0].firstChild.nodeValue) { │ │ │ │ + value = this.getChildValue(eles[0]) │ │ │ │ + } else { │ │ │ │ + value = def == undefined ? "" : def │ │ │ │ + } │ │ │ │ + return value │ │ │ │ + }, │ │ │ │ + read: function(doc) { │ │ │ │ + if (typeof doc == "string") { │ │ │ │ + doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]) │ │ │ │ + } │ │ │ │ + var itemlist = null; │ │ │ │ + itemlist = this.getElementsByTagNameNS(doc, "*", "item"); │ │ │ │ + if (itemlist.length == 0) { │ │ │ │ + itemlist = this.getElementsByTagNameNS(doc, "*", "entry") │ │ │ │ + } │ │ │ │ + var numItems = itemlist.length; │ │ │ │ + var features = new Array(numItems); │ │ │ │ + for (var i = 0; i < numItems; i++) { │ │ │ │ + features[i] = this.createFeatureFromItem(itemlist[i]) │ │ │ │ + } │ │ │ │ + return features │ │ │ │ + }, │ │ │ │ + write: function(features) { │ │ │ │ + var georss; │ │ │ │ + if (OpenLayers.Util.isArray(features)) { │ │ │ │ + georss = this.createElementNS(this.rssns, "rss"); │ │ │ │ + for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ + georss.appendChild(this.createFeatureXML(features[i])) │ │ │ │ + } │ │ │ │ + } else { │ │ │ │ + georss = this.createFeatureXML(features) │ │ │ │ + } │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [georss]) │ │ │ │ + }, │ │ │ │ + createFeatureXML: function(feature) { │ │ │ │ + var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ + var featureNode = this.createElementNS(this.rssns, "item"); │ │ │ │ + var titleNode = this.createElementNS(this.rssns, "title"); │ │ │ │ + titleNode.appendChild(this.createTextNode(feature.attributes.title ? feature.attributes.title : "")); │ │ │ │ + var descNode = this.createElementNS(this.rssns, "description"); │ │ │ │ + descNode.appendChild(this.createTextNode(feature.attributes.description ? feature.attributes.description : "")); │ │ │ │ + featureNode.appendChild(titleNode); │ │ │ │ + featureNode.appendChild(descNode); │ │ │ │ + if (feature.attributes.link) { │ │ │ │ + var linkNode = this.createElementNS(this.rssns, "link"); │ │ │ │ + linkNode.appendChild(this.createTextNode(feature.attributes.link)); │ │ │ │ + featureNode.appendChild(linkNode) │ │ │ │ + } │ │ │ │ + for (var attr in feature.attributes) { │ │ │ │ + if (attr == "link" || attr == "title" || attr == "description") { │ │ │ │ + continue │ │ │ │ + } │ │ │ │ + var attrText = this.createTextNode(feature.attributes[attr]); │ │ │ │ + var nodename = attr; │ │ │ │ + if (attr.search(":") != -1) { │ │ │ │ + nodename = attr.split(":")[1] │ │ │ │ + } │ │ │ │ + var attrContainer = this.createElementNS(this.featureNS, "feature:" + nodename); │ │ │ │ + attrContainer.appendChild(attrText); │ │ │ │ + featureNode.appendChild(attrContainer) │ │ │ │ + } │ │ │ │ + featureNode.appendChild(geometryNode); │ │ │ │ + return featureNode │ │ │ │ + }, │ │ │ │ + buildGeometryNode: function(geometry) { │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + geometry = geometry.clone(); │ │ │ │ + geometry.transform(this.internalProjection, this.externalProjection) │ │ │ │ + } │ │ │ │ + var node; │ │ │ │ + if (geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") { │ │ │ │ + node = this.createElementNS(this.georssns, "georss:polygon"); │ │ │ │ + node.appendChild(this.buildCoordinatesNode(geometry.components[0])) │ │ │ │ + } else if (geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") { │ │ │ │ + node = this.createElementNS(this.georssns, "georss:line"); │ │ │ │ + node.appendChild(this.buildCoordinatesNode(geometry)) │ │ │ │ + } else if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { │ │ │ │ + node = this.createElementNS(this.georssns, "georss:point"); │ │ │ │ + node.appendChild(this.buildCoordinatesNode(geometry)) │ │ │ │ + } else { │ │ │ │ + throw "Couldn't parse " + geometry.CLASS_NAME │ │ │ │ + } │ │ │ │ + return node │ │ │ │ + }, │ │ │ │ + buildCoordinatesNode: function(geometry) { │ │ │ │ + var points = null; │ │ │ │ + if (geometry.components) { │ │ │ │ + points = geometry.components │ │ │ │ + } │ │ │ │ + var path; │ │ │ │ + if (points) { │ │ │ │ + var numPoints = points.length; │ │ │ │ + var parts = new Array(numPoints); │ │ │ │ + for (var i = 0; i < numPoints; i++) { │ │ │ │ + parts[i] = points[i].y + " " + points[i].x │ │ │ │ + } │ │ │ │ + path = parts.join(" ") │ │ │ │ + } else { │ │ │ │ + path = geometry.y + " " + geometry.x │ │ │ │ + } │ │ │ │ + return this.createTextNode(path) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.GeoRSS" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WFSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.1.0", │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.CSWGetDomain = function(options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, OpenLayers.Format.CSWGetDomain.DEFAULTS); │ │ │ │ + var cls = OpenLayers.Format.CSWGetDomain["v" + options.version.replace(/\./g, "_")]; │ │ │ │ + if (!cls) { │ │ │ │ + throw "Unsupported CSWGetDomain version: " + options.version │ │ │ │ + } │ │ │ │ + return new cls(options) │ │ │ │ +}; │ │ │ │ +OpenLayers.Format.CSWGetDomain.DEFAULTS = { │ │ │ │ + version: "2.0.2" │ │ │ │ +}; │ │ │ │ OpenLayers.Format.GPX = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ defaultDesc: "No description available", │ │ │ │ extractWaypoints: true, │ │ │ │ extractTracks: true, │ │ │ │ extractRoutes: true, │ │ │ │ extractAttributes: true, │ │ │ │ namespaces: { │ │ │ │ @@ -35381,43 +37184,129 @@ │ │ │ │ node.appendChild(name); │ │ │ │ var desc = this.createElementNS(this.namespaces.gpx, "desc"); │ │ │ │ desc.appendChild(this.createTextNode(feature.attributes.description || this.defaultDesc)); │ │ │ │ node.appendChild(desc) │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.GPX" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.WCSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.1.0", │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.OWSContext = OpenLayers.Class(OpenLayers.Format.Context, { │ │ │ │ - defaultVersion: "0.3.1", │ │ │ │ - getVersion: function(root, options) { │ │ │ │ - var version = OpenLayers.Format.XML.VersionedOGC.prototype.getVersion.apply(this, arguments); │ │ │ │ - if (version === "0.3.0") { │ │ │ │ - version = this.defaultVersion │ │ │ │ +OpenLayers.Format.WFS = OpenLayers.Class(OpenLayers.Format.GML, { │ │ │ │ + layer: null, │ │ │ │ + wfsns: "http://www.opengis.net/wfs", │ │ │ │ + ogcns: "http://www.opengis.net/ogc", │ │ │ │ + initialize: function(options, layer) { │ │ │ │ + OpenLayers.Format.GML.prototype.initialize.apply(this, [options]); │ │ │ │ + this.layer = layer; │ │ │ │ + if (this.layer.featureNS) { │ │ │ │ + this.featureNS = this.layer.featureNS │ │ │ │ + } │ │ │ │ + if (this.layer.options.geometry_column) { │ │ │ │ + this.geometryName = this.layer.options.geometry_column │ │ │ │ + } │ │ │ │ + if (this.layer.options.typename) { │ │ │ │ + this.featureName = this.layer.options.typename │ │ │ │ } │ │ │ │ - return version │ │ │ │ }, │ │ │ │ - toContext: function(obj) { │ │ │ │ - var context = {}; │ │ │ │ - if (obj.CLASS_NAME == "OpenLayers.Map") { │ │ │ │ - context.bounds = obj.getExtent(); │ │ │ │ - context.maxExtent = obj.maxExtent; │ │ │ │ - context.projection = obj.projection; │ │ │ │ - context.size = obj.getSize(); │ │ │ │ - context.layers = obj.layers │ │ │ │ + write: function(features) { │ │ │ │ + var transaction = this.createElementNS(this.wfsns, "wfs:Transaction"); │ │ │ │ + transaction.setAttribute("version", "1.0.0"); │ │ │ │ + transaction.setAttribute("service", "WFS"); │ │ │ │ + for (var i = 0; i < features.length; i++) { │ │ │ │ + switch (features[i].state) { │ │ │ │ + case OpenLayers.State.INSERT: │ │ │ │ + transaction.appendChild(this.insert(features[i])); │ │ │ │ + break; │ │ │ │ + case OpenLayers.State.UPDATE: │ │ │ │ + transaction.appendChild(this.update(features[i])); │ │ │ │ + break; │ │ │ │ + case OpenLayers.State.DELETE: │ │ │ │ + transaction.appendChild(this.remove(features[i])); │ │ │ │ + break │ │ │ │ + } │ │ │ │ } │ │ │ │ - return context │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [transaction]) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.OWSContext" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WFSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.1.0", │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities" │ │ │ │ + createFeatureXML: function(feature) { │ │ │ │ + var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ + var geomContainer = this.createElementNS(this.featureNS, "feature:" + this.geometryName); │ │ │ │ + geomContainer.appendChild(geometryNode); │ │ │ │ + var featureContainer = this.createElementNS(this.featureNS, "feature:" + this.featureName); │ │ │ │ + featureContainer.appendChild(geomContainer); │ │ │ │ + for (var attr in feature.attributes) { │ │ │ │ + var attrText = this.createTextNode(feature.attributes[attr]); │ │ │ │ + var nodename = attr; │ │ │ │ + if (attr.search(":") != -1) { │ │ │ │ + nodename = attr.split(":")[1] │ │ │ │ + } │ │ │ │ + var attrContainer = this.createElementNS(this.featureNS, "feature:" + nodename); │ │ │ │ + attrContainer.appendChild(attrText); │ │ │ │ + featureContainer.appendChild(attrContainer) │ │ │ │ + } │ │ │ │ + return featureContainer │ │ │ │ + }, │ │ │ │ + insert: function(feature) { │ │ │ │ + var insertNode = this.createElementNS(this.wfsns, "wfs:Insert"); │ │ │ │ + insertNode.appendChild(this.createFeatureXML(feature)); │ │ │ │ + return insertNode │ │ │ │ + }, │ │ │ │ + update: function(feature) { │ │ │ │ + if (!feature.fid) { │ │ │ │ + OpenLayers.Console.userError(OpenLayers.i18n("noFID")) │ │ │ │ + } │ │ │ │ + var updateNode = this.createElementNS(this.wfsns, "wfs:Update"); │ │ │ │ + updateNode.setAttribute("typeName", this.featurePrefix + ":" + this.featureName); │ │ │ │ + updateNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ + var propertyNode = this.createElementNS(this.wfsns, "wfs:Property"); │ │ │ │ + var nameNode = this.createElementNS(this.wfsns, "wfs:Name"); │ │ │ │ + var txtNode = this.createTextNode(this.geometryName); │ │ │ │ + nameNode.appendChild(txtNode); │ │ │ │ + propertyNode.appendChild(nameNode); │ │ │ │ + var valueNode = this.createElementNS(this.wfsns, "wfs:Value"); │ │ │ │ + var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ + if (feature.layer) { │ │ │ │ + geometryNode.setAttribute("srsName", feature.layer.projection.getCode()) │ │ │ │ + } │ │ │ │ + valueNode.appendChild(geometryNode); │ │ │ │ + propertyNode.appendChild(valueNode); │ │ │ │ + updateNode.appendChild(propertyNode); │ │ │ │ + for (var propName in feature.attributes) { │ │ │ │ + propertyNode = this.createElementNS(this.wfsns, "wfs:Property"); │ │ │ │ + nameNode = this.createElementNS(this.wfsns, "wfs:Name"); │ │ │ │ + nameNode.appendChild(this.createTextNode(propName)); │ │ │ │ + propertyNode.appendChild(nameNode); │ │ │ │ + valueNode = this.createElementNS(this.wfsns, "wfs:Value"); │ │ │ │ + valueNode.appendChild(this.createTextNode(feature.attributes[propName])); │ │ │ │ + propertyNode.appendChild(valueNode); │ │ │ │ + updateNode.appendChild(propertyNode) │ │ │ │ + } │ │ │ │ + var filterNode = this.createElementNS(this.ogcns, "ogc:Filter"); │ │ │ │ + var filterIdNode = this.createElementNS(this.ogcns, "ogc:FeatureId"); │ │ │ │ + filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ + filterNode.appendChild(filterIdNode); │ │ │ │ + updateNode.appendChild(filterNode); │ │ │ │ + return updateNode │ │ │ │ + }, │ │ │ │ + remove: function(feature) { │ │ │ │ + if (!feature.fid) { │ │ │ │ + OpenLayers.Console.userError(OpenLayers.i18n("noFID")); │ │ │ │ + return false │ │ │ │ + } │ │ │ │ + var deleteNode = this.createElementNS(this.wfsns, "wfs:Delete"); │ │ │ │ + deleteNode.setAttribute("typeName", this.featurePrefix + ":" + this.featureName); │ │ │ │ + deleteNode.setAttribute("xmlns:" + this.featurePrefix, this.featureNS); │ │ │ │ + var filterNode = this.createElementNS(this.ogcns, "ogc:Filter"); │ │ │ │ + var filterIdNode = this.createElementNS(this.ogcns, "ogc:FeatureId"); │ │ │ │ + filterIdNode.setAttribute("fid", feature.fid); │ │ │ │ + filterNode.appendChild(filterIdNode); │ │ │ │ + deleteNode.appendChild(filterNode); │ │ │ │ + return deleteNode │ │ │ │ + }, │ │ │ │ + destroy: function() { │ │ │ │ + this.layer = null │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFS" │ │ │ │ }); │ │ │ │ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ namespaces: { │ │ │ │ kml: "http://www.opengis.net/kml/2.2", │ │ │ │ gx: "http://www.google.com/kml/ext/2.2" │ │ │ │ }, │ │ │ │ kmlns: "http://earth.google.com/kml/2.0", │ │ │ │ @@ -36068,1550 +37957,328 @@ │ │ │ │ placemarkNode.appendChild(placemarkName); │ │ │ │ placemarkNode.appendChild(placemarkDesc); │ │ │ │ var geometryNode = this.buildGeometryNode(feature.geometry); │ │ │ │ placemarkNode.appendChild(geometryNode); │ │ │ │ if (feature.attributes) { │ │ │ │ var edNode = this.buildExtendedData(feature.attributes); │ │ │ │ if (edNode) { │ │ │ │ - placemarkNode.appendChild(edNode) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return placemarkNode │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - buildGeometry: { │ │ │ │ - point: function(geometry) { │ │ │ │ - var kml = this.createElementNS(this.kmlns, "Point"); │ │ │ │ - kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ - return kml │ │ │ │ - }, │ │ │ │ - multipoint: function(geometry) { │ │ │ │ - return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ - }, │ │ │ │ - linestring: function(geometry) { │ │ │ │ - var kml = this.createElementNS(this.kmlns, "LineString"); │ │ │ │ - kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ - return kml │ │ │ │ - }, │ │ │ │ - multilinestring: function(geometry) { │ │ │ │ - return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ - }, │ │ │ │ - linearring: function(geometry) { │ │ │ │ - var kml = this.createElementNS(this.kmlns, "LinearRing"); │ │ │ │ - kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ - return kml │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - multipolygon: function(geometry) { │ │ │ │ - return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - buildCoordinatesNode: function(geometry) { │ │ │ │ - var coordinatesNode = this.createElementNS(this.kmlns, "coordinates"); │ │ │ │ - var path; │ │ │ │ - var points = geometry.components; │ │ │ │ - if (points) { │ │ │ │ - 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 { │ │ │ │ - path = this.buildCoordinates(geometry) │ │ │ │ - } │ │ │ │ - var txtNode = this.createTextNode(path); │ │ │ │ - coordinatesNode.appendChild(txtNode); │ │ │ │ - return coordinatesNode │ │ │ │ - }, │ │ │ │ - buildCoordinates: function(point) { │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ - point = point.clone(); │ │ │ │ - point.transform(this.internalProjection, this.externalProjection) │ │ │ │ - } │ │ │ │ - return point.x + "," + point.y │ │ │ │ - }, │ │ │ │ - buildExtendedData: function(attributes) { │ │ │ │ - var extendedData = this.createElementNS(this.kmlns, "ExtendedData"); │ │ │ │ - for (var attributeName in attributes) { │ │ │ │ - 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") { │ │ │ │ - if (attributes[attributeName].value) { │ │ │ │ - value.appendChild(this.createTextNode(attributes[attributeName].value)) │ │ │ │ - } │ │ │ │ - if (attributes[attributeName].displayName) { │ │ │ │ - var displayName = this.createElementNS(this.kmlns, "displayName"); │ │ │ │ - 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.Format.WMSDescribeLayer = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.1.1", │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.XLS = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.1.0", │ │ │ │ - stringifyOutput: true, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.XLS" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.SOSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ - defaultVersion: "1.0.0", │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SOSCapabilities" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WFST.v1_0_0 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, OpenLayers.Format.WFST.v1, { │ │ │ │ - version: "1.0.0", │ │ │ │ - srsNameInQuery: false, │ │ │ │ - schemaLocations: { │ │ │ │ - wfs: "http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd" │ │ │ │ - }, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this, [options]); │ │ │ │ - OpenLayers.Format.WFST.v1.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - readNode: function(node, obj, first) { │ │ │ │ - return OpenLayers.Format.GML.v2.prototype.readNode.apply(this, arguments) │ │ │ │ - }, │ │ │ │ - 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"] │ │ │ │ - }, │ │ │ │ - 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.Format.ArcXML.Features = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - read: function(data) { │ │ │ │ - var axl = new OpenLayers.Format.ArcXML; │ │ │ │ - var parsed = axl.read(data); │ │ │ │ - return parsed.features.feature │ │ │ │ - } │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSDescribeLayer.v1_1_1 = OpenLayers.Class(OpenLayers.Format.WMSDescribeLayer, { │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.WMSDescribeLayer.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ - } │ │ │ │ - var root = data.documentElement; │ │ │ │ - var children = root.childNodes; │ │ │ │ - var describelayer = { │ │ │ │ - layerDescriptions: [] │ │ │ │ - }; │ │ │ │ - var childNode, nodeName; │ │ │ │ - for (var i = 0; i < children.length; ++i) { │ │ │ │ - childNode = children[i]; │ │ │ │ - nodeName = childNode.nodeName; │ │ │ │ - if (nodeName == "LayerDescription") { │ │ │ │ - var layerName = childNode.getAttribute("name"); │ │ │ │ - var owsType = ""; │ │ │ │ - var owsURL = ""; │ │ │ │ - var typeName = ""; │ │ │ │ - if (childNode.getAttribute("owsType")) { │ │ │ │ - owsType = childNode.getAttribute("owsType"); │ │ │ │ - owsURL = childNode.getAttribute("owsURL") │ │ │ │ - } else { │ │ │ │ - if (childNode.getAttribute("wfs") != "") { │ │ │ │ - owsType = "WFS"; │ │ │ │ - owsURL = childNode.getAttribute("wfs") │ │ │ │ - } else if (childNode.getAttribute("wcs") != "") { │ │ │ │ - owsType = "WCS"; │ │ │ │ - owsURL = childNode.getAttribute("wcs") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var query = childNode.getElementsByTagName("Query"); │ │ │ │ - if (query.length > 0) { │ │ │ │ - typeName = query[0].getAttribute("typeName"); │ │ │ │ - if (!typeName) { │ │ │ │ - typeName = query[0].getAttribute("typename") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var layerDescription = { │ │ │ │ - layerName: layerName, │ │ │ │ - owsType: owsType, │ │ │ │ - owsURL: owsURL, │ │ │ │ - typeName: typeName │ │ │ │ - }; │ │ │ │ - describelayer.layerDescriptions.push(layerDescription); │ │ │ │ - describelayer.length = describelayer.layerDescriptions.length; │ │ │ │ - describelayer[describelayer.length - 1] = layerDescription │ │ │ │ - } else if (nodeName == "ServiceException") { │ │ │ │ - var parser = new OpenLayers.Format.OGCExceptionReport; │ │ │ │ - return { │ │ │ │ - error: parser.read(data) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return describelayer │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer.v1_1_1" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSDescribeLayer.v1_1_0 = OpenLayers.Format.WMSDescribeLayer.v1_1_1; │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - namespaces: { │ │ │ │ - wms: "http://www.opengis.net/wms", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ - defaultPrefix: "wms", │ │ │ │ - read: function(data) { │ │ │ │ - if (typeof data == "string") { │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ - } │ │ │ │ - var raw = data; │ │ │ │ - if (data && data.nodeType == 9) { │ │ │ │ - data = data.documentElement │ │ │ │ - } │ │ │ │ - var capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - if (capabilities.service === undefined) { │ │ │ │ - var parser = new OpenLayers.Format.OGCExceptionReport; │ │ │ │ - capabilities.error = parser.read(raw) │ │ │ │ - } │ │ │ │ - return capabilities │ │ │ │ - }, │ │ │ │ - readers: { │ │ │ │ - wms: { │ │ │ │ - Service: function(node, obj) { │ │ │ │ - obj.service = {}; │ │ │ │ - this.readChildNodes(node, obj.service) │ │ │ │ - }, │ │ │ │ - Name: function(node, obj) { │ │ │ │ - obj.name = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - Title: function(node, obj) { │ │ │ │ - obj.title = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - Abstract: function(node, obj) { │ │ │ │ - obj["abstract"] = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - BoundingBox: function(node, obj) { │ │ │ │ - var bbox = {}; │ │ │ │ - bbox.bbox = [parseFloat(node.getAttribute("minx")), parseFloat(node.getAttribute("miny")), parseFloat(node.getAttribute("maxx")), parseFloat(node.getAttribute("maxy"))]; │ │ │ │ - var res = { │ │ │ │ - x: parseFloat(node.getAttribute("resx")), │ │ │ │ - y: parseFloat(node.getAttribute("resy")) │ │ │ │ - }; │ │ │ │ - if (!(isNaN(res.x) && isNaN(res.y))) { │ │ │ │ - bbox.res = res │ │ │ │ - } │ │ │ │ - return bbox │ │ │ │ - }, │ │ │ │ - OnlineResource: function(node, obj) { │ │ │ │ - obj.href = this.getAttributeNS(node, this.namespaces.xlink, "href") │ │ │ │ - }, │ │ │ │ - ContactInformation: function(node, obj) { │ │ │ │ - obj.contactInformation = {}; │ │ │ │ - this.readChildNodes(node, obj.contactInformation) │ │ │ │ - }, │ │ │ │ - ContactPersonPrimary: function(node, obj) { │ │ │ │ - obj.personPrimary = {}; │ │ │ │ - this.readChildNodes(node, obj.personPrimary) │ │ │ │ - }, │ │ │ │ - ContactPerson: function(node, obj) { │ │ │ │ - obj.person = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - ContactOrganization: function(node, obj) { │ │ │ │ - obj.organization = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - ContactPosition: function(node, obj) { │ │ │ │ - obj.position = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - ContactAddress: function(node, obj) { │ │ │ │ - obj.contactAddress = {}; │ │ │ │ - this.readChildNodes(node, obj.contactAddress) │ │ │ │ - }, │ │ │ │ - AddressType: function(node, obj) { │ │ │ │ - obj.type = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - Address: function(node, obj) { │ │ │ │ - obj.address = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - City: function(node, obj) { │ │ │ │ - obj.city = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - StateOrProvince: function(node, obj) { │ │ │ │ - obj.stateOrProvince = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - PostCode: function(node, obj) { │ │ │ │ - obj.postcode = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - Country: function(node, obj) { │ │ │ │ - obj.country = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - ContactVoiceTelephone: function(node, obj) { │ │ │ │ - obj.phone = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - ContactFacsimileTelephone: function(node, obj) { │ │ │ │ - obj.fax = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - ContactElectronicMailAddress: function(node, obj) { │ │ │ │ - obj.email = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - Fees: function(node, obj) { │ │ │ │ - var fees = this.getChildValue(node); │ │ │ │ - if (fees && fees.toLowerCase() != "none") { │ │ │ │ - obj.fees = fees │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - AccessConstraints: function(node, obj) { │ │ │ │ - var constraints = this.getChildValue(node); │ │ │ │ - if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ - obj.accessConstraints = constraints │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - Capability: function(node, obj) { │ │ │ │ - obj.capability = { │ │ │ │ - nestedLayers: [], │ │ │ │ - layers: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.capability) │ │ │ │ - }, │ │ │ │ - Request: function(node, obj) { │ │ │ │ - obj.request = {}; │ │ │ │ - this.readChildNodes(node, obj.request) │ │ │ │ - }, │ │ │ │ - GetCapabilities: function(node, obj) { │ │ │ │ - obj.getcapabilities = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getcapabilities) │ │ │ │ - }, │ │ │ │ - Format: function(node, obj) { │ │ │ │ - if (OpenLayers.Util.isArray(obj.formats)) { │ │ │ │ - obj.formats.push(this.getChildValue(node)) │ │ │ │ - } else { │ │ │ │ - obj.format = this.getChildValue(node) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - DCPType: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - HTTP: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - Get: function(node, obj) { │ │ │ │ - obj.get = {}; │ │ │ │ - this.readChildNodes(node, obj.get); │ │ │ │ - if (!obj.href) { │ │ │ │ - obj.href = obj.get.href │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - Post: function(node, obj) { │ │ │ │ - obj.post = {}; │ │ │ │ - this.readChildNodes(node, obj.post); │ │ │ │ - if (!obj.href) { │ │ │ │ - obj.href = obj.get.href │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - GetMap: function(node, obj) { │ │ │ │ - obj.getmap = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getmap) │ │ │ │ - }, │ │ │ │ - GetFeatureInfo: function(node, obj) { │ │ │ │ - obj.getfeatureinfo = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getfeatureinfo) │ │ │ │ - }, │ │ │ │ - Exception: function(node, obj) { │ │ │ │ - obj.exception = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.exception) │ │ │ │ - }, │ │ │ │ - Layer: function(node, obj) { │ │ │ │ - var parentLayer, capability; │ │ │ │ - if (obj.capability) { │ │ │ │ - capability = obj.capability; │ │ │ │ - parentLayer = obj │ │ │ │ - } else { │ │ │ │ - capability = obj │ │ │ │ - } │ │ │ │ - var attrNode = node.getAttributeNode("queryable"); │ │ │ │ - var queryable = attrNode && attrNode.specified ? node.getAttribute("queryable") : null; │ │ │ │ - attrNode = node.getAttributeNode("cascaded"); │ │ │ │ - var cascaded = attrNode && attrNode.specified ? node.getAttribute("cascaded") : null; │ │ │ │ - attrNode = node.getAttributeNode("opaque"); │ │ │ │ - var opaque = attrNode && attrNode.specified ? node.getAttribute("opaque") : null; │ │ │ │ - var noSubsets = node.getAttribute("noSubsets"); │ │ │ │ - var fixedWidth = node.getAttribute("fixedWidth"); │ │ │ │ - var fixedHeight = node.getAttribute("fixedHeight"); │ │ │ │ - var parent = parentLayer || {}, │ │ │ │ - extend = OpenLayers.Util.extend; │ │ │ │ - var layer = { │ │ │ │ - nestedLayers: [], │ │ │ │ - styles: parentLayer ? [].concat(parentLayer.styles) : [], │ │ │ │ - srs: parentLayer ? extend({}, parent.srs) : {}, │ │ │ │ - metadataURLs: [], │ │ │ │ - bbox: parentLayer ? extend({}, parent.bbox) : {}, │ │ │ │ - llbbox: parent.llbbox, │ │ │ │ - dimensions: parentLayer ? extend({}, parent.dimensions) : {}, │ │ │ │ - authorityURLs: parentLayer ? extend({}, parent.authorityURLs) : {}, │ │ │ │ - identifiers: {}, │ │ │ │ - keywords: [], │ │ │ │ - queryable: queryable && queryable !== "" ? queryable === "1" || queryable === "true" : parent.queryable || false, │ │ │ │ - cascaded: cascaded !== null ? parseInt(cascaded) : parent.cascaded || 0, │ │ │ │ - opaque: opaque ? opaque === "1" || opaque === "true" : parent.opaque || false, │ │ │ │ - noSubsets: noSubsets !== null ? noSubsets === "1" || noSubsets === "true" : parent.noSubsets || false, │ │ │ │ - fixedWidth: fixedWidth != null ? parseInt(fixedWidth) : parent.fixedWidth || 0, │ │ │ │ - fixedHeight: fixedHeight != null ? parseInt(fixedHeight) : parent.fixedHeight || 0, │ │ │ │ - minScale: parent.minScale, │ │ │ │ - maxScale: parent.maxScale, │ │ │ │ - attribution: parent.attribution │ │ │ │ - }; │ │ │ │ - obj.nestedLayers.push(layer); │ │ │ │ - layer.capability = capability; │ │ │ │ - this.readChildNodes(node, layer); │ │ │ │ - delete layer.capability; │ │ │ │ - if (layer.name) { │ │ │ │ - var parts = layer.name.split(":"), │ │ │ │ - request = capability.request, │ │ │ │ - gfi = request.getfeatureinfo; │ │ │ │ - if (parts.length > 0) { │ │ │ │ - layer.prefix = parts[0] │ │ │ │ - } │ │ │ │ - capability.layers.push(layer); │ │ │ │ - if (layer.formats === undefined) { │ │ │ │ - layer.formats = request.getmap.formats │ │ │ │ - } │ │ │ │ - if (layer.infoFormats === undefined && gfi) { │ │ │ │ - layer.infoFormats = gfi.formats │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - Attribution: function(node, obj) { │ │ │ │ - obj.attribution = {}; │ │ │ │ - this.readChildNodes(node, obj.attribution) │ │ │ │ - }, │ │ │ │ - LogoURL: function(node, obj) { │ │ │ │ - obj.logo = { │ │ │ │ - width: node.getAttribute("width"), │ │ │ │ - height: node.getAttribute("height") │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.logo) │ │ │ │ - }, │ │ │ │ - Style: function(node, obj) { │ │ │ │ - var style = {}; │ │ │ │ - obj.styles.push(style); │ │ │ │ - this.readChildNodes(node, style) │ │ │ │ - }, │ │ │ │ - LegendURL: function(node, obj) { │ │ │ │ - var legend = { │ │ │ │ - width: node.getAttribute("width"), │ │ │ │ - height: node.getAttribute("height") │ │ │ │ - }; │ │ │ │ - obj.legend = legend; │ │ │ │ - this.readChildNodes(node, legend) │ │ │ │ - }, │ │ │ │ - MetadataURL: function(node, obj) { │ │ │ │ - var metadataURL = { │ │ │ │ - type: node.getAttribute("type") │ │ │ │ - }; │ │ │ │ - obj.metadataURLs.push(metadataURL); │ │ │ │ - this.readChildNodes(node, metadataURL) │ │ │ │ - }, │ │ │ │ - DataURL: function(node, obj) { │ │ │ │ - obj.dataURL = {}; │ │ │ │ - this.readChildNodes(node, obj.dataURL) │ │ │ │ - }, │ │ │ │ - FeatureListURL: function(node, obj) { │ │ │ │ - obj.featureListURL = {}; │ │ │ │ - this.readChildNodes(node, obj.featureListURL) │ │ │ │ - }, │ │ │ │ - AuthorityURL: function(node, obj) { │ │ │ │ - var name = node.getAttribute("name"); │ │ │ │ - var authority = {}; │ │ │ │ - this.readChildNodes(node, authority); │ │ │ │ - obj.authorityURLs[name] = authority.href │ │ │ │ - }, │ │ │ │ - Identifier: function(node, obj) { │ │ │ │ - var authority = node.getAttribute("authority"); │ │ │ │ - obj.identifiers[authority] = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - KeywordList: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - SRS: function(node, obj) { │ │ │ │ - obj.srs[this.getChildValue(node)] = true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ - readers: { │ │ │ │ - wms: OpenLayers.Util.applyDefaults({ │ │ │ │ - WMT_MS_Capabilities: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - Keyword: function(node, obj) { │ │ │ │ - if (obj.keywords) { │ │ │ │ - obj.keywords.push(this.getChildValue(node)) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - DescribeLayer: function(node, obj) { │ │ │ │ - obj.describelayer = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.describelayer) │ │ │ │ - }, │ │ │ │ - GetLegendGraphic: function(node, obj) { │ │ │ │ - obj.getlegendgraphic = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getlegendgraphic) │ │ │ │ - }, │ │ │ │ - GetStyles: function(node, obj) { │ │ │ │ - obj.getstyles = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.getstyles) │ │ │ │ - }, │ │ │ │ - PutStyles: function(node, obj) { │ │ │ │ - obj.putstyles = { │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.putstyles) │ │ │ │ - }, │ │ │ │ - UserDefinedSymbolization: function(node, obj) { │ │ │ │ - var userSymbols = { │ │ │ │ - supportSLD: parseInt(node.getAttribute("SupportSLD")) == 1, │ │ │ │ - userLayer: parseInt(node.getAttribute("UserLayer")) == 1, │ │ │ │ - userStyle: parseInt(node.getAttribute("UserStyle")) == 1, │ │ │ │ - remoteWFS: parseInt(node.getAttribute("RemoteWFS")) == 1 │ │ │ │ - }; │ │ │ │ - obj.userSymbols = userSymbols │ │ │ │ - }, │ │ │ │ - LatLonBoundingBox: function(node, obj) { │ │ │ │ - obj.llbbox = [parseFloat(node.getAttribute("minx")), parseFloat(node.getAttribute("miny")), parseFloat(node.getAttribute("maxx")), parseFloat(node.getAttribute("maxy"))] │ │ │ │ - }, │ │ │ │ - BoundingBox: function(node, obj) { │ │ │ │ - var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ - bbox.srs = node.getAttribute("SRS"); │ │ │ │ - obj.bbox[bbox.srs] = bbox │ │ │ │ - }, │ │ │ │ - ScaleHint: function(node, obj) { │ │ │ │ - var min = node.getAttribute("min"); │ │ │ │ - var max = node.getAttribute("max"); │ │ │ │ - var rad2 = Math.pow(2, .5); │ │ │ │ - var ipm = OpenLayers.INCHES_PER_UNIT["m"]; │ │ │ │ - if (min != 0) { │ │ │ │ - obj.maxScale = parseFloat((min / rad2 * ipm * OpenLayers.DOTS_PER_INCH).toPrecision(13)) │ │ │ │ - } │ │ │ │ - if (max != Number.POSITIVE_INFINITY) { │ │ │ │ - obj.minScale = parseFloat((max / rad2 * ipm * OpenLayers.DOTS_PER_INCH).toPrecision(13)) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - Dimension: function(node, obj) { │ │ │ │ - var name = node.getAttribute("name").toLowerCase(); │ │ │ │ - var dim = { │ │ │ │ - name: name, │ │ │ │ - units: node.getAttribute("units"), │ │ │ │ - unitsymbol: node.getAttribute("unitSymbol") │ │ │ │ - }; │ │ │ │ - obj.dimensions[dim.name] = dim │ │ │ │ - }, │ │ │ │ - Extent: function(node, obj) { │ │ │ │ - var name = node.getAttribute("name").toLowerCase(); │ │ │ │ - if (name in obj["dimensions"]) { │ │ │ │ - var extent = obj.dimensions[name]; │ │ │ │ - extent.nearestVal = node.getAttribute("nearestValue") === "1"; │ │ │ │ - extent.multipleVal = node.getAttribute("multipleValues") === "1"; │ │ │ │ - extent.current = node.getAttribute("current") === "1"; │ │ │ │ - extent["default"] = node.getAttribute("default") || ""; │ │ │ │ - var values = this.getChildValue(node); │ │ │ │ - extent.values = values.split(",") │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_3 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ - readers: { │ │ │ │ - wms: OpenLayers.Util.applyDefaults({ │ │ │ │ - WMS_Capabilities: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - LayerLimit: function(node, obj) { │ │ │ │ - obj.layerLimit = parseInt(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - MaxWidth: function(node, obj) { │ │ │ │ - obj.maxWidth = parseInt(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - MaxHeight: function(node, obj) { │ │ │ │ - obj.maxHeight = parseInt(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - BoundingBox: function(node, obj) { │ │ │ │ - var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ - bbox.srs = node.getAttribute("CRS"); │ │ │ │ - obj.bbox[bbox.srs] = bbox │ │ │ │ - }, │ │ │ │ - CRS: function(node, obj) { │ │ │ │ - this.readers.wms.SRS.apply(this, [node, obj]) │ │ │ │ - }, │ │ │ │ - EX_GeographicBoundingBox: function(node, obj) { │ │ │ │ - obj.llbbox = []; │ │ │ │ - this.readChildNodes(node, obj.llbbox) │ │ │ │ - }, │ │ │ │ - westBoundLongitude: function(node, obj) { │ │ │ │ - obj[0] = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - eastBoundLongitude: function(node, obj) { │ │ │ │ - obj[2] = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - southBoundLatitude: function(node, obj) { │ │ │ │ - obj[1] = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - northBoundLatitude: function(node, obj) { │ │ │ │ - obj[3] = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - MinScaleDenominator: function(node, obj) { │ │ │ │ - obj.maxScale = parseFloat(this.getChildValue(node)).toPrecision(16) │ │ │ │ - }, │ │ │ │ - MaxScaleDenominator: function(node, obj) { │ │ │ │ - obj.minScale = parseFloat(this.getChildValue(node)).toPrecision(16) │ │ │ │ - }, │ │ │ │ - Dimension: function(node, obj) { │ │ │ │ - var name = node.getAttribute("name").toLowerCase(); │ │ │ │ - var dim = { │ │ │ │ - name: name, │ │ │ │ - units: node.getAttribute("units"), │ │ │ │ - unitsymbol: node.getAttribute("unitSymbol"), │ │ │ │ - nearestVal: node.getAttribute("nearestValue") === "1", │ │ │ │ - multipleVal: node.getAttribute("multipleValues") === "1", │ │ │ │ - default: node.getAttribute("default") || "", │ │ │ │ - current: node.getAttribute("current") === "1", │ │ │ │ - values: this.getChildValue(node).split(",") │ │ │ │ - }; │ │ │ │ - obj.dimensions[dim.name] = dim │ │ │ │ - }, │ │ │ │ - Keyword: function(node, obj) { │ │ │ │ - var keyword = { │ │ │ │ - value: this.getChildValue(node), │ │ │ │ - vocabulary: node.getAttribute("vocabulary") │ │ │ │ - }; │ │ │ │ - if (obj.keywords) { │ │ │ │ - obj.keywords.push(keyword) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]), │ │ │ │ - sld: { │ │ │ │ - UserDefinedSymbolization: function(node, obj) { │ │ │ │ - this.readers.wms.UserDefinedSymbolization.apply(this, [node, obj]); │ │ │ │ - obj.userSymbols.inlineFeature = parseInt(node.getAttribute("InlineFeature")) == 1; │ │ │ │ - obj.userSymbols.remoteWCS = parseInt(node.getAttribute("RemoteWCS")) == 1 │ │ │ │ - }, │ │ │ │ - DescribeLayer: function(node, obj) { │ │ │ │ - this.readers.wms.DescribeLayer.apply(this, [node, obj]) │ │ │ │ - }, │ │ │ │ - GetLegendGraphic: function(node, obj) { │ │ │ │ - this.readers.wms.GetLegendGraphic.apply(this, [node, obj]) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_3_0 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_3, { │ │ │ │ - version: "1.3.0", │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3_0" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1_0 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ - version: "1.1.0", │ │ │ │ - readers: { │ │ │ │ - wms: OpenLayers.Util.applyDefaults({ │ │ │ │ - SRS: function(node, obj) { │ │ │ │ - var srs = this.getChildValue(node); │ │ │ │ - var values = srs.split(/ +/); │ │ │ │ - for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ - obj.srs[values[i]] = true │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_0" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1_1 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ - version: "1.1.1", │ │ │ │ - readers: { │ │ │ │ - wms: OpenLayers.Util.applyDefaults({ │ │ │ │ - SRS: function(node, obj) { │ │ │ │ - obj.srs[this.getChildValue(node)] = true │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1_1, { │ │ │ │ - version: "1.1.1", │ │ │ │ - profile: "WMSC", │ │ │ │ - readers: { │ │ │ │ - wms: OpenLayers.Util.applyDefaults({ │ │ │ │ - VendorSpecificCapabilities: function(node, obj) { │ │ │ │ - obj.vendorSpecific = { │ │ │ │ - tileSets: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, obj.vendorSpecific) │ │ │ │ - }, │ │ │ │ - TileSet: function(node, vendorSpecific) { │ │ │ │ - var tileset = { │ │ │ │ - srs: {}, │ │ │ │ - bbox: {}, │ │ │ │ - resolutions: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, tileset); │ │ │ │ - vendorSpecific.tileSets.push(tileset) │ │ │ │ - }, │ │ │ │ - Resolutions: function(node, tileset) { │ │ │ │ - var res = this.getChildValue(node).split(" "); │ │ │ │ - for (var i = 0, len = res.length; i < len; i++) { │ │ │ │ - if (res[i] != "") { │ │ │ │ - tileset.resolutions.push(parseFloat(res[i])) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - Width: function(node, tileset) { │ │ │ │ - tileset.width = parseInt(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - Height: function(node, tileset) { │ │ │ │ - tileset.height = parseInt(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - Layers: function(node, tileset) { │ │ │ │ - tileset.layers = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - Styles: function(node, tileset) { │ │ │ │ - tileset.styles = this.getChildValue(node) │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WMSCapabilities.v1_1_1.prototype.readers["wms"]) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WPSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - namespaces: { │ │ │ │ - ows: "http://www.opengis.net/ows/1.1", │ │ │ │ - wps: "http://www.opengis.net/wps/1.0.0", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink" │ │ │ │ - }, │ │ │ │ - regExes: { │ │ │ │ - trimSpace: /^\s*|\s*$/g, │ │ │ │ - removeSpace: /\s*/g, │ │ │ │ - splitSpace: /\s+/, │ │ │ │ - trimComma: /\s*,\s*/g │ │ │ │ - }, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - 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 capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - return capabilities │ │ │ │ - }, │ │ │ │ - readers: { │ │ │ │ - wps: { │ │ │ │ - Capabilities: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - ProcessOfferings: function(node, obj) { │ │ │ │ - obj.processOfferings = {}; │ │ │ │ - this.readChildNodes(node, obj.processOfferings) │ │ │ │ - }, │ │ │ │ - Process: function(node, processOfferings) { │ │ │ │ - var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); │ │ │ │ - var process = { │ │ │ │ - processVersion: processVersion │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, process); │ │ │ │ - processOfferings[process.identifier] = process │ │ │ │ - }, │ │ │ │ - Languages: function(node, obj) { │ │ │ │ - obj.languages = []; │ │ │ │ - this.readChildNodes(node, obj.languages) │ │ │ │ - }, │ │ │ │ - Default: function(node, languages) { │ │ │ │ - var language = { │ │ │ │ - isDefault: true │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, language); │ │ │ │ - languages.push(language) │ │ │ │ - }, │ │ │ │ - Supported: function(node, languages) { │ │ │ │ - var language = {}; │ │ │ │ - this.readChildNodes(node, language); │ │ │ │ - languages.push(language) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - ows: OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WPSCapabilities.v1_0_0" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.CSWGetRecords.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - namespaces: { │ │ │ │ - csw: "http://www.opengis.net/cat/csw/2.0.2", │ │ │ │ - dc: "http://purl.org/dc/elements/1.1/", │ │ │ │ - dct: "http://purl.org/dc/terms/", │ │ │ │ - gmd: "http://www.isotc211.org/2005/gmd", │ │ │ │ - geonet: "http://www.fao.org/geonetwork", │ │ │ │ - ogc: "http://www.opengis.net/ogc", │ │ │ │ - ows: "http://www.opengis.net/ows", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ - }, │ │ │ │ - defaultPrefix: "csw", │ │ │ │ - version: "2.0.2", │ │ │ │ - schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ - requestId: null, │ │ │ │ - resultType: null, │ │ │ │ - outputFormat: null, │ │ │ │ - outputSchema: null, │ │ │ │ - startPosition: null, │ │ │ │ - maxRecords: null, │ │ │ │ - DistributedSearch: null, │ │ │ │ - ResponseHandler: null, │ │ │ │ - Query: null, │ │ │ │ - regExes: { │ │ │ │ - trimSpace: /^\s*|\s*$/g, │ │ │ │ - removeSpace: /\s*/g, │ │ │ │ - splitSpace: /\s+/, │ │ │ │ - trimComma: /\s*,\s*/g │ │ │ │ - }, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - 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 obj = {}; │ │ │ │ - this.readNode(data, obj); │ │ │ │ - return obj │ │ │ │ - }, │ │ │ │ - readers: { │ │ │ │ - csw: { │ │ │ │ - GetRecordsResponse: function(node, obj) { │ │ │ │ - obj.records = []; │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - var version = this.getAttributeNS(node, "", "version"); │ │ │ │ - if (version != "") { │ │ │ │ - obj.version = version │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - RequestId: function(node, obj) { │ │ │ │ - obj.RequestId = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - SearchStatus: function(node, obj) { │ │ │ │ - obj.SearchStatus = {}; │ │ │ │ - var timestamp = this.getAttributeNS(node, "", "timestamp"); │ │ │ │ - if (timestamp != "") { │ │ │ │ - obj.SearchStatus.timestamp = timestamp │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - SearchResults: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj); │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var SearchResults = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - if (attrs[i].name == "numberOfRecordsMatched" || attrs[i].name == "numberOfRecordsReturned" || attrs[i].name == "nextRecord") { │ │ │ │ - SearchResults[attrs[i].name] = parseInt(attrs[i].nodeValue) │ │ │ │ - } else { │ │ │ │ - SearchResults[attrs[i].name] = attrs[i].nodeValue │ │ │ │ - } │ │ │ │ - } │ │ │ │ - obj.SearchResults = SearchResults │ │ │ │ - }, │ │ │ │ - SummaryRecord: function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "SummaryRecord" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record) │ │ │ │ - }, │ │ │ │ - BriefRecord: function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "BriefRecord" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record) │ │ │ │ - }, │ │ │ │ - DCMIRecord: function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "DCMIRecord" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record) │ │ │ │ - }, │ │ │ │ - Record: function(node, obj) { │ │ │ │ - var record = { │ │ │ │ - type: "Record" │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, record); │ │ │ │ - obj.records.push(record) │ │ │ │ - }, │ │ │ │ - "*": function(node, obj) { │ │ │ │ - var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ - obj[name] = this.getChildValue(node) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - geonet: { │ │ │ │ - info: function(node, obj) { │ │ │ │ - var gninfo = {}; │ │ │ │ - this.readChildNodes(node, gninfo); │ │ │ │ - obj.gninfo = gninfo │ │ │ │ + placemarkNode.appendChild(edNode) │ │ │ │ } │ │ │ │ + } │ │ │ │ + return placemarkNode │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ + }, │ │ │ │ + buildGeometry: { │ │ │ │ + point: function(geometry) { │ │ │ │ + var kml = this.createElementNS(this.kmlns, "Point"); │ │ │ │ + kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ + return kml │ │ │ │ }, │ │ │ │ - dc: { │ │ │ │ - "*": function(node, obj) { │ │ │ │ - var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ - if (!OpenLayers.Util.isArray(obj[name])) { │ │ │ │ - obj[name] = [] │ │ │ │ - } │ │ │ │ - var dc_element = {}; │ │ │ │ - var attrs = node.attributes; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - dc_element[attrs[i].name] = attrs[i].nodeValue │ │ │ │ - } │ │ │ │ - dc_element.value = this.getChildValue(node); │ │ │ │ - if (dc_element.value != "") { │ │ │ │ - obj[name].push(dc_element) │ │ │ │ - } │ │ │ │ - } │ │ │ │ + multipoint: function(geometry) { │ │ │ │ + return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ }, │ │ │ │ - dct: { │ │ │ │ - "*": function(node, obj) { │ │ │ │ - var name = node.localName || node.nodeName.split(":").pop(); │ │ │ │ - if (!OpenLayers.Util.isArray(obj[name])) { │ │ │ │ - obj[name] = [] │ │ │ │ - } │ │ │ │ - obj[name].push(this.getChildValue(node)) │ │ │ │ + linestring: function(geometry) { │ │ │ │ + var kml = this.createElementNS(this.kmlns, "LineString"); │ │ │ │ + kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ + return kml │ │ │ │ + }, │ │ │ │ + multilinestring: function(geometry) { │ │ │ │ + return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ + }, │ │ │ │ + linearring: function(geometry) { │ │ │ │ + var kml = this.createElementNS(this.kmlns, "LinearRing"); │ │ │ │ + kml.appendChild(this.buildCoordinatesNode(geometry)); │ │ │ │ + return kml │ │ │ │ + }, │ │ │ │ + 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 │ │ │ │ }, │ │ │ │ - ows: OpenLayers.Util.applyDefaults({ │ │ │ │ - BoundingBox: function(node, obj) { │ │ │ │ - if (obj.bounds) { │ │ │ │ - obj.BoundingBox = [{ │ │ │ │ - crs: obj.projection, │ │ │ │ - value: [obj.bounds.left, obj.bounds.bottom, obj.bounds.right, obj.bounds.top] │ │ │ │ - }]; │ │ │ │ - delete obj.projection; │ │ │ │ - delete obj.bounds │ │ │ │ + multipolygon: function(geometry) { │ │ │ │ + return this.buildGeometry.collection.apply(this, [geometry]) │ │ │ │ + }, │ │ │ │ + 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) │ │ │ │ } │ │ │ │ - OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]["BoundingBox"].apply(this, arguments) │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"]) │ │ │ │ + return kml │ │ │ │ + } │ │ │ │ }, │ │ │ │ - write: function(options) { │ │ │ │ - var node = this.writeNode("csw:GetRecords", options); │ │ │ │ - node.setAttribute("xmlns:gmd", this.namespaces.gmd); │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [node]) │ │ │ │ + buildCoordinatesNode: function(geometry) { │ │ │ │ + var coordinatesNode = this.createElementNS(this.kmlns, "coordinates"); │ │ │ │ + var path; │ │ │ │ + var points = geometry.components; │ │ │ │ + if (points) { │ │ │ │ + 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 { │ │ │ │ + path = this.buildCoordinates(geometry) │ │ │ │ + } │ │ │ │ + var txtNode = this.createTextNode(path); │ │ │ │ + coordinatesNode.appendChild(txtNode); │ │ │ │ + return coordinatesNode │ │ │ │ }, │ │ │ │ - writers: { │ │ │ │ - csw: { │ │ │ │ - GetRecords: function(options) { │ │ │ │ - if (!options) { │ │ │ │ - options = {} │ │ │ │ - } │ │ │ │ - var node = this.createElementNSPlus("csw:GetRecords", { │ │ │ │ - attributes: { │ │ │ │ - service: "CSW", │ │ │ │ - version: this.version, │ │ │ │ - requestId: options.requestId || this.requestId, │ │ │ │ - resultType: options.resultType || this.resultType, │ │ │ │ - outputFormat: options.outputFormat || this.outputFormat, │ │ │ │ - outputSchema: options.outputSchema || this.outputSchema, │ │ │ │ - startPosition: options.startPosition || this.startPosition, │ │ │ │ - maxRecords: options.maxRecords || this.maxRecords │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (options.DistributedSearch || this.DistributedSearch) { │ │ │ │ - this.writeNode("csw:DistributedSearch", options.DistributedSearch || this.DistributedSearch, node) │ │ │ │ - } │ │ │ │ - var ResponseHandler = options.ResponseHandler || this.ResponseHandler; │ │ │ │ - if (OpenLayers.Util.isArray(ResponseHandler) && ResponseHandler.length > 0) { │ │ │ │ - for (var i = 0, len = ResponseHandler.length; i < len; i++) { │ │ │ │ - this.writeNode("csw:ResponseHandler", ResponseHandler[i], node) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - this.writeNode("Query", options.Query || this.Query, node); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - DistributedSearch: function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:DistributedSearch", { │ │ │ │ - attributes: { │ │ │ │ - hopCount: options.hopCount │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - ResponseHandler: function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:ResponseHandler", { │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - Query: function(options) { │ │ │ │ - if (!options) { │ │ │ │ - options = {} │ │ │ │ - } │ │ │ │ - var node = this.createElementNSPlus("csw:Query", { │ │ │ │ - attributes: { │ │ │ │ - typeNames: options.typeNames || "csw:Record" │ │ │ │ + buildCoordinates: function(point) { │ │ │ │ + if (this.internalProjection && this.externalProjection) { │ │ │ │ + point = point.clone(); │ │ │ │ + point.transform(this.internalProjection, this.externalProjection) │ │ │ │ + } │ │ │ │ + return point.x + "," + point.y │ │ │ │ + }, │ │ │ │ + buildExtendedData: function(attributes) { │ │ │ │ + var extendedData = this.createElementNS(this.kmlns, "ExtendedData"); │ │ │ │ + for (var attributeName in attributes) { │ │ │ │ + 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") { │ │ │ │ + if (attributes[attributeName].value) { │ │ │ │ + value.appendChild(this.createTextNode(attributes[attributeName].value)) │ │ │ │ } │ │ │ │ - }); │ │ │ │ - var ElementName = options.ElementName; │ │ │ │ - if (OpenLayers.Util.isArray(ElementName) && ElementName.length > 0) { │ │ │ │ - for (var i = 0, len = ElementName.length; i < len; i++) { │ │ │ │ - this.writeNode("csw:ElementName", ElementName[i], node) │ │ │ │ + if (attributes[attributeName].displayName) { │ │ │ │ + var displayName = this.createElementNS(this.kmlns, "displayName"); │ │ │ │ + displayName.appendChild(this.getXMLDoc().createCDATASection(attributes[attributeName].displayName)); │ │ │ │ + data.appendChild(displayName) │ │ │ │ } │ │ │ │ } else { │ │ │ │ - this.writeNode("csw:ElementSetName", options.ElementSetName || { │ │ │ │ - value: "summary" │ │ │ │ - }, node) │ │ │ │ - } │ │ │ │ - if (options.Constraint) { │ │ │ │ - this.writeNode("csw:Constraint", options.Constraint, node) │ │ │ │ - } │ │ │ │ - if (options.SortBy) { │ │ │ │ - this.writeNode("ogc:SortBy", options.SortBy, node) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - ElementName: function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:ElementName", { │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - ElementSetName: function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:ElementSetName", { │ │ │ │ - attributes: { │ │ │ │ - typeNames: options.typeNames │ │ │ │ - }, │ │ │ │ - value: options.value │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ - }, │ │ │ │ - Constraint: function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:Constraint", { │ │ │ │ - attributes: { │ │ │ │ - version: options.version │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (options.Filter) { │ │ │ │ - var format = new OpenLayers.Format.Filter({ │ │ │ │ - version: options.version │ │ │ │ - }); │ │ │ │ - node.appendChild(format.write(options.Filter)) │ │ │ │ - } else if (options.CqlText) { │ │ │ │ - var child = this.createElementNSPlus("CqlText", { │ │ │ │ - value: options.CqlText.value │ │ │ │ - }); │ │ │ │ - node.appendChild(child) │ │ │ │ - } │ │ │ │ - return node │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - ogc: OpenLayers.Format.Filter.v1_1_0.prototype.writers["ogc"] │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.CSWGetRecords.v2_0_2" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class(OpenLayers.Format.SLD.v1_0_0, { │ │ │ │ - version: "1.0.0", │ │ │ │ - profile: "GeoServer", │ │ │ │ - readers: OpenLayers.Util.applyDefaults({ │ │ │ │ - sld: OpenLayers.Util.applyDefaults({ │ │ │ │ - Priority: function(node, obj) { │ │ │ │ - var value = this.readers.ogc._expression.call(this, node); │ │ │ │ - if (value) { │ │ │ │ - obj.priority = value │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - VendorOption: function(node, obj) { │ │ │ │ - if (!obj.vendorOptions) { │ │ │ │ - obj.vendorOptions = {} │ │ │ │ - } │ │ │ │ - obj.vendorOptions[node.getAttribute("name")] = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - TextSymbolizer: function(node, rule) { │ │ │ │ - OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld.TextSymbolizer.apply(this, arguments); │ │ │ │ - var symbolizer = this.multipleSymbolizers ? rule.symbolizers[rule.symbolizers.length - 1] : rule.symbolizer["Text"]; │ │ │ │ - if (symbolizer.graphic === undefined) { │ │ │ │ - symbolizer.graphic = false │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.readers["sld"]) │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.readers), │ │ │ │ - writers: OpenLayers.Util.applyDefaults({ │ │ │ │ - sld: OpenLayers.Util.applyDefaults({ │ │ │ │ - Priority: function(priority) { │ │ │ │ - return this.writers.sld._OGCExpression.call(this, "sld:Priority", priority) │ │ │ │ - }, │ │ │ │ - VendorOption: function(option) { │ │ │ │ - return this.createElementNSPlus("sld:VendorOption", { │ │ │ │ - attributes: { │ │ │ │ - name: option.name │ │ │ │ - }, │ │ │ │ - value: option.value │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - TextSymbolizer: function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["TextSymbolizer"].apply(this, arguments); │ │ │ │ - if (symbolizer.graphic !== false && (symbolizer.externalGraphic || symbolizer.graphicName)) { │ │ │ │ - this.writeNode("Graphic", symbolizer, node) │ │ │ │ - } │ │ │ │ - if ("priority" in symbolizer) { │ │ │ │ - this.writeNode("Priority", symbolizer.priority, node) │ │ │ │ + value.appendChild(this.createTextNode(attributes[attributeName])) │ │ │ │ } │ │ │ │ - return this.addVendorOptions(node, symbolizer) │ │ │ │ - }, │ │ │ │ - PointSymbolizer: function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["PointSymbolizer"].apply(this, arguments); │ │ │ │ - return this.addVendorOptions(node, symbolizer) │ │ │ │ - }, │ │ │ │ - LineSymbolizer: function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["LineSymbolizer"].apply(this, arguments); │ │ │ │ - return this.addVendorOptions(node, symbolizer) │ │ │ │ - }, │ │ │ │ - PolygonSymbolizer: function(symbolizer) { │ │ │ │ - var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ - var node = writers["sld"]["PolygonSymbolizer"].apply(this, arguments); │ │ │ │ - return this.addVendorOptions(node, symbolizer) │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.writers["sld"]) │ │ │ │ - }, OpenLayers.Format.SLD.v1_0_0.prototype.writers), │ │ │ │ - addVendorOptions: function(node, symbolizer) { │ │ │ │ - var options = symbolizer.vendorOptions; │ │ │ │ - if (options) { │ │ │ │ - for (var key in symbolizer.vendorOptions) { │ │ │ │ - this.writeNode("VendorOption", { │ │ │ │ - name: key, │ │ │ │ - value: symbolizer.vendorOptions[key] │ │ │ │ - }, node) │ │ │ │ + data.appendChild(value); │ │ │ │ + extendedData.appendChild(data) │ │ │ │ } │ │ │ │ } │ │ │ │ - return node │ │ │ │ + if (this.isSimpleContent(extendedData)) { │ │ │ │ + return null │ │ │ │ + } else { │ │ │ │ + return extendedData │ │ │ │ + } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0_GeoServer" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.KML" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.CSWGetDomain.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ - namespaces: { │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ - csw: "http://www.opengis.net/cat/csw/2.0.2" │ │ │ │ +OpenLayers.Format.WPSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { │ │ │ │ + defaultVersion: "1.0.0", │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WPSCapabilities" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WCSCapabilities.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + regExes: { │ │ │ │ + trimSpace: /^\s*|\s*$/g, │ │ │ │ + splitSpace: /\s+/ │ │ │ │ }, │ │ │ │ - defaultPrefix: "csw", │ │ │ │ - version: "2.0.2", │ │ │ │ - schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ - PropertyName: null, │ │ │ │ - ParameterName: null, │ │ │ │ + defaultPrefix: "wcs", │ │ │ │ read: function(data) { │ │ │ │ if (typeof data == "string") { │ │ │ │ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ } │ │ │ │ + var raw = data; │ │ │ │ if (data && data.nodeType == 9) { │ │ │ │ data = data.documentElement │ │ │ │ } │ │ │ │ - var obj = {}; │ │ │ │ - this.readNode(data, obj); │ │ │ │ - return obj │ │ │ │ + var capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + return capabilities │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ + namespaces: { │ │ │ │ + wcs: "http://www.opengis.net/wcs", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ + ows: "http://www.opengis.net/ows" │ │ │ │ }, │ │ │ │ + errorProperty: "service", │ │ │ │ readers: { │ │ │ │ - csw: { │ │ │ │ - GetDomainResponse: function(node, obj) { │ │ │ │ + wcs: { │ │ │ │ + WCS_Capabilities: function(node, obj) { │ │ │ │ this.readChildNodes(node, obj) │ │ │ │ }, │ │ │ │ - DomainValues: function(node, obj) { │ │ │ │ - if (!OpenLayers.Util.isArray(obj.DomainValues)) { │ │ │ │ - obj.DomainValues = [] │ │ │ │ - } │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var domainValue = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - domainValue[attrs[i].name] = attrs[i].nodeValue │ │ │ │ - } │ │ │ │ - this.readChildNodes(node, domainValue); │ │ │ │ - obj.DomainValues.push(domainValue) │ │ │ │ - }, │ │ │ │ - PropertyName: function(node, obj) { │ │ │ │ - obj.PropertyName = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - ParameterName: function(node, obj) { │ │ │ │ - obj.ParameterName = this.getChildValue(node) │ │ │ │ + Service: function(node, obj) { │ │ │ │ + obj.service = {}; │ │ │ │ + this.readChildNodes(node, obj.service) │ │ │ │ }, │ │ │ │ - ListOfValues: function(node, obj) { │ │ │ │ - if (!OpenLayers.Util.isArray(obj.ListOfValues)) { │ │ │ │ - obj.ListOfValues = [] │ │ │ │ - } │ │ │ │ - this.readChildNodes(node, obj.ListOfValues) │ │ │ │ + name: function(node, service) { │ │ │ │ + service.name = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - Value: function(node, obj) { │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var value = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - value[attrs[i].name] = attrs[i].nodeValue │ │ │ │ - } │ │ │ │ - value.value = this.getChildValue(node); │ │ │ │ - obj.push({ │ │ │ │ - Value: value │ │ │ │ - }) │ │ │ │ + label: function(node, service) { │ │ │ │ + service.label = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - ConceptualScheme: function(node, obj) { │ │ │ │ - obj.ConceptualScheme = {}; │ │ │ │ - this.readChildNodes(node, obj.ConceptualScheme) │ │ │ │ + keywords: function(node, service) { │ │ │ │ + service.keywords = []; │ │ │ │ + this.readChildNodes(node, service.keywords) │ │ │ │ }, │ │ │ │ - Name: function(node, obj) { │ │ │ │ - obj.Name = this.getChildValue(node) │ │ │ │ + keyword: function(node, keywords) { │ │ │ │ + keywords.push(this.getChildValue(node)) │ │ │ │ }, │ │ │ │ - Document: function(node, obj) { │ │ │ │ - obj.Document = this.getChildValue(node) │ │ │ │ + responsibleParty: function(node, service) { │ │ │ │ + service.responsibleParty = {}; │ │ │ │ + this.readChildNodes(node, service.responsibleParty) │ │ │ │ }, │ │ │ │ - Authority: function(node, obj) { │ │ │ │ - obj.Authority = this.getChildValue(node) │ │ │ │ + individualName: function(node, responsibleParty) { │ │ │ │ + responsibleParty.individualName = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - RangeOfValues: function(node, obj) { │ │ │ │ - obj.RangeOfValues = {}; │ │ │ │ - this.readChildNodes(node, obj.RangeOfValues) │ │ │ │ + organisationName: function(node, responsibleParty) { │ │ │ │ + responsibleParty.organisationName = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - MinValue: function(node, obj) { │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var value = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - value[attrs[i].name] = attrs[i].nodeValue │ │ │ │ - } │ │ │ │ - value.value = this.getChildValue(node); │ │ │ │ - obj.MinValue = value │ │ │ │ + positionName: function(node, responsibleParty) { │ │ │ │ + responsibleParty.positionName = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - MaxValue: function(node, obj) { │ │ │ │ - var attrs = node.attributes; │ │ │ │ - var value = {}; │ │ │ │ - for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ - value[attrs[i].name] = attrs[i].nodeValue │ │ │ │ - } │ │ │ │ - value.value = this.getChildValue(node); │ │ │ │ - obj.MaxValue = value │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - write: function(options) { │ │ │ │ - var node = this.writeNode("csw:GetDomain", options); │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [node]) │ │ │ │ - }, │ │ │ │ - writers: { │ │ │ │ - csw: { │ │ │ │ - GetDomain: function(options) { │ │ │ │ - var node = this.createElementNSPlus("csw:GetDomain", { │ │ │ │ - attributes: { │ │ │ │ - service: "CSW", │ │ │ │ - version: this.version │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (options.PropertyName || this.PropertyName) { │ │ │ │ - this.writeNode("csw:PropertyName", options.PropertyName || this.PropertyName, node) │ │ │ │ - } else if (options.ParameterName || this.ParameterName) { │ │ │ │ - this.writeNode("csw:ParameterName", options.ParameterName || this.ParameterName, node) │ │ │ │ - } │ │ │ │ - this.readChildNodes(node, options); │ │ │ │ - return node │ │ │ │ + contactInfo: function(node, responsibleParty) { │ │ │ │ + responsibleParty.contactInfo = {}; │ │ │ │ + this.readChildNodes(node, responsibleParty.contactInfo) │ │ │ │ }, │ │ │ │ - PropertyName: function(value) { │ │ │ │ - var node = this.createElementNSPlus("csw:PropertyName", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ + phone: function(node, contactInfo) { │ │ │ │ + contactInfo.phone = {}; │ │ │ │ + this.readChildNodes(node, contactInfo.phone) │ │ │ │ }, │ │ │ │ - ParameterName: function(value) { │ │ │ │ - var node = this.createElementNSPlus("csw:ParameterName", { │ │ │ │ - value: value │ │ │ │ - }); │ │ │ │ - return node │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.CSWGetDomain.v2_0_2" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WMTSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.OWSCommon.v1_1_0, { │ │ │ │ - version: "1.0.0", │ │ │ │ - namespaces: { │ │ │ │ - ows: "http://www.opengis.net/ows/1.1", │ │ │ │ - wmts: "http://www.opengis.net/wmts/1.0", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink" │ │ │ │ - }, │ │ │ │ - yx: null, │ │ │ │ - defaultPrefix: "wmts", │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ - this.options = options; │ │ │ │ - var yx = OpenLayers.Util.extend({}, OpenLayers.Format.WMTSCapabilities.prototype.yx); │ │ │ │ - this.yx = OpenLayers.Util.extend(yx, this.yx) │ │ │ │ - }, │ │ │ │ - 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 capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - capabilities.version = this.version; │ │ │ │ - return capabilities │ │ │ │ - }, │ │ │ │ - readers: { │ │ │ │ - wmts: { │ │ │ │ - Capabilities: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ + voice: function(node, phone) { │ │ │ │ + phone.voice = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - Contents: function(node, obj) { │ │ │ │ - obj.contents = {}; │ │ │ │ - obj.contents.layers = []; │ │ │ │ - obj.contents.tileMatrixSets = {}; │ │ │ │ - this.readChildNodes(node, obj.contents) │ │ │ │ + facsimile: function(node, phone) { │ │ │ │ + phone.facsimile = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - Layer: function(node, obj) { │ │ │ │ - var layer = { │ │ │ │ - styles: [], │ │ │ │ - formats: [], │ │ │ │ - dimensions: [], │ │ │ │ - tileMatrixSetLinks: [] │ │ │ │ - }; │ │ │ │ - layer.layers = []; │ │ │ │ - this.readChildNodes(node, layer); │ │ │ │ - obj.layers.push(layer) │ │ │ │ + address: function(node, contactInfo) { │ │ │ │ + contactInfo.address = {}; │ │ │ │ + this.readChildNodes(node, contactInfo.address) │ │ │ │ }, │ │ │ │ - Style: function(node, obj) { │ │ │ │ - var style = {}; │ │ │ │ - style.isDefault = node.getAttribute("isDefault") === "true"; │ │ │ │ - this.readChildNodes(node, style); │ │ │ │ - obj.styles.push(style) │ │ │ │ + deliveryPoint: function(node, address) { │ │ │ │ + address.deliveryPoint = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - Format: function(node, obj) { │ │ │ │ - obj.formats.push(this.getChildValue(node)) │ │ │ │ + city: function(node, address) { │ │ │ │ + address.city = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - TileMatrixSetLink: function(node, obj) { │ │ │ │ - var tileMatrixSetLink = {}; │ │ │ │ - this.readChildNodes(node, tileMatrixSetLink); │ │ │ │ - obj.tileMatrixSetLinks.push(tileMatrixSetLink) │ │ │ │ + postalCode: function(node, address) { │ │ │ │ + address.postalCode = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - TileMatrixSet: function(node, obj) { │ │ │ │ - if (obj.layers) { │ │ │ │ - var tileMatrixSet = { │ │ │ │ - matrixIds: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, tileMatrixSet); │ │ │ │ - obj.tileMatrixSets[tileMatrixSet.identifier] = tileMatrixSet │ │ │ │ - } else { │ │ │ │ - obj.tileMatrixSet = this.getChildValue(node) │ │ │ │ - } │ │ │ │ + country: function(node, address) { │ │ │ │ + address.country = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - TileMatrix: function(node, obj) { │ │ │ │ - var tileMatrix = { │ │ │ │ - supportedCRS: obj.supportedCRS │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, tileMatrix); │ │ │ │ - obj.matrixIds.push(tileMatrix) │ │ │ │ + electronicMailAddress: function(node, address) { │ │ │ │ + address.electronicMailAddress = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - ScaleDenominator: function(node, obj) { │ │ │ │ - obj.scaleDenominator = parseFloat(this.getChildValue(node)) │ │ │ │ + fees: function(node, service) { │ │ │ │ + service.fees = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - TopLeftCorner: function(node, obj) { │ │ │ │ - var topLeftCorner = this.getChildValue(node); │ │ │ │ - var coords = topLeftCorner.split(" "); │ │ │ │ - var yx; │ │ │ │ - if (obj.supportedCRS) { │ │ │ │ - var crs = obj.supportedCRS.replace(/urn:ogc:def:crs:(\w+):.+:(\w+)$/, "urn:ogc:def:crs:$1::$2"); │ │ │ │ - yx = !!this.yx[crs] │ │ │ │ - } │ │ │ │ - if (yx) { │ │ │ │ - obj.topLeftCorner = new OpenLayers.LonLat(coords[1], coords[0]) │ │ │ │ - } else { │ │ │ │ - obj.topLeftCorner = new OpenLayers.LonLat(coords[0], coords[1]) │ │ │ │ - } │ │ │ │ + accessConstraints: function(node, service) { │ │ │ │ + service.accessConstraints = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - TileWidth: function(node, obj) { │ │ │ │ - obj.tileWidth = parseInt(this.getChildValue(node)) │ │ │ │ + ContentMetadata: function(node, obj) { │ │ │ │ + obj.contentMetadata = []; │ │ │ │ + this.readChildNodes(node, obj.contentMetadata) │ │ │ │ }, │ │ │ │ - TileHeight: function(node, obj) { │ │ │ │ - obj.tileHeight = parseInt(this.getChildValue(node)) │ │ │ │ + CoverageOfferingBrief: function(node, contentMetadata) { │ │ │ │ + var coverageOfferingBrief = {}; │ │ │ │ + this.readChildNodes(node, coverageOfferingBrief); │ │ │ │ + contentMetadata.push(coverageOfferingBrief) │ │ │ │ }, │ │ │ │ - MatrixWidth: function(node, obj) { │ │ │ │ - obj.matrixWidth = parseInt(this.getChildValue(node)) │ │ │ │ + name: function(node, coverageOfferingBrief) { │ │ │ │ + coverageOfferingBrief.name = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - MatrixHeight: function(node, obj) { │ │ │ │ - obj.matrixHeight = parseInt(this.getChildValue(node)) │ │ │ │ + label: function(node, coverageOfferingBrief) { │ │ │ │ + coverageOfferingBrief.label = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - ResourceURL: function(node, obj) { │ │ │ │ - obj.resourceUrl = obj.resourceUrl || {}; │ │ │ │ - var resourceType = node.getAttribute("resourceType"); │ │ │ │ - if (!obj.resourceUrls) { │ │ │ │ - obj.resourceUrls = [] │ │ │ │ + lonLatEnvelope: function(node, coverageOfferingBrief) { │ │ │ │ + var nodeList = this.getElementsByTagNameNS(node, "http://www.opengis.net/gml", "pos"); │ │ │ │ + if (nodeList.length == 2) { │ │ │ │ + var min = {}; │ │ │ │ + var max = {}; │ │ │ │ + OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[0], min]); │ │ │ │ + OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[1], max]); │ │ │ │ + coverageOfferingBrief.lonLatEnvelope = {}; │ │ │ │ + coverageOfferingBrief.lonLatEnvelope.srsName = node.getAttribute("srsName"); │ │ │ │ + coverageOfferingBrief.lonLatEnvelope.min = min.points[0]; │ │ │ │ + coverageOfferingBrief.lonLatEnvelope.max = max.points[0] │ │ │ │ } │ │ │ │ - var resourceUrl = obj.resourceUrl[resourceType] = { │ │ │ │ - format: node.getAttribute("format"), │ │ │ │ - template: node.getAttribute("template"), │ │ │ │ - resourceType: resourceType │ │ │ │ - }; │ │ │ │ - obj.resourceUrls.push(resourceUrl) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_0_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WCSCapabilities.v1_1_0 = OpenLayers.Class(OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ + namespaces: { │ │ │ │ + wcs: "http://www.opengis.net/wcs/1.1", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ + ows: "http://www.opengis.net/ows/1.1" │ │ │ │ + }, │ │ │ │ + errorProperty: "operationsMetadata", │ │ │ │ + readers: { │ │ │ │ + wcs: OpenLayers.Util.applyDefaults({ │ │ │ │ + Capabilities: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ }, │ │ │ │ - WSDL: function(node, obj) { │ │ │ │ - obj.wsdl = {}; │ │ │ │ - obj.wsdl.href = node.getAttribute("xlink:href") │ │ │ │ + Contents: function(node, request) { │ │ │ │ + request.contentMetadata = []; │ │ │ │ + this.readChildNodes(node, request.contentMetadata) │ │ │ │ }, │ │ │ │ - ServiceMetadataURL: function(node, obj) { │ │ │ │ - obj.serviceMetadataUrl = {}; │ │ │ │ - obj.serviceMetadataUrl.href = node.getAttribute("xlink:href") │ │ │ │ + CoverageSummary: function(node, contentMetadata) { │ │ │ │ + var coverageSummary = {}; │ │ │ │ + this.readChildNodes(node, coverageSummary); │ │ │ │ + contentMetadata.push(coverageSummary) │ │ │ │ }, │ │ │ │ - LegendURL: function(node, obj) { │ │ │ │ - obj.legend = {}; │ │ │ │ - obj.legend.href = node.getAttribute("xlink:href"); │ │ │ │ - obj.legend.format = node.getAttribute("format") │ │ │ │ + Identifier: function(node, coverageSummary) { │ │ │ │ + coverageSummary.identifier = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - Dimension: function(node, obj) { │ │ │ │ - var dimension = { │ │ │ │ - values: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, dimension); │ │ │ │ - obj.dimensions.push(dimension) │ │ │ │ + Title: function(node, coverageSummary) { │ │ │ │ + coverageSummary.title = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - Default: function(node, obj) { │ │ │ │ - obj["default"] = this.getChildValue(node) │ │ │ │ + Abstract: function(node, coverageSummary) { │ │ │ │ + coverageSummary["abstract"] = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - Value: function(node, obj) { │ │ │ │ - obj.values.push(this.getChildValue(node)) │ │ │ │ + SupportedCRS: function(node, coverageSummary) { │ │ │ │ + var crs = this.getChildValue(node); │ │ │ │ + if (crs) { │ │ │ │ + if (!coverageSummary.supportedCRS) { │ │ │ │ + coverageSummary.supportedCRS = [] │ │ │ │ + } │ │ │ │ + coverageSummary.supportedCRS.push(crs) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + SupportedFormat: function(node, coverageSummary) { │ │ │ │ + var format = this.getChildValue(node); │ │ │ │ + if (format) { │ │ │ │ + if (!coverageSummary.supportedFormat) { │ │ │ │ + coverageSummary.supportedFormat = [] │ │ │ │ + } │ │ │ │ + coverageSummary.supportedFormat.push(format) │ │ │ │ + } │ │ │ │ } │ │ │ │ - }, │ │ │ │ + }, OpenLayers.Format.WCSCapabilities.v1.prototype.readers["wcs"]), │ │ │ │ ows: OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMTSCapabilities.v1_0_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_1_0" │ │ │ │ }); │ │ │ │ OpenLayers.Format.WMC.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ namespaces: { │ │ │ │ ol: "http://openlayers.org/context", │ │ │ │ wmc: "http://www.opengis.net/context", │ │ │ │ sld: "http://www.opengis.net/sld", │ │ │ │ xlink: "http://www.w3.org/1999/xlink", │ │ │ │ @@ -38258,14 +38925,48 @@ │ │ │ │ if (links.length > 0) { │ │ │ │ this.read_wmc_OnlineResource(object, links[0]) │ │ │ │ } │ │ │ │ return object.href │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.WMC.v1" │ │ │ │ }); │ │ │ │ +OpenLayers.Format.WMC.v1_0_0 = OpenLayers.Class(OpenLayers.Format.WMC.v1, { │ │ │ │ + VERSION: "1.0.0", │ │ │ │ + schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.0.0/context.xsd", │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.WMC.v1.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + read_wmc_SRS: function(layerContext, node) { │ │ │ │ + var srs = this.getChildValue(node); │ │ │ │ + if (typeof layerContext.projections != "object") { │ │ │ │ + layerContext.projections = {} │ │ │ │ + } │ │ │ │ + var values = srs.split(/ +/); │ │ │ │ + for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ + layerContext.projections[values[i]] = true │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + write_wmc_Layer: function(context) { │ │ │ │ + var node = OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply(this, [context]); │ │ │ │ + if (context.srs) { │ │ │ │ + var projections = []; │ │ │ │ + for (var name in context.srs) { │ │ │ │ + projections.push(name) │ │ │ │ + } │ │ │ │ + node.appendChild(this.createElementDefaultNS("SRS", projections.join(" "))) │ │ │ │ + } │ │ │ │ + node.appendChild(this.write_wmc_FormatList(context)); │ │ │ │ + node.appendChild(this.write_wmc_StyleList(context)); │ │ │ │ + if (context.dimensions) { │ │ │ │ + node.appendChild(this.write_wmc_DimensionList(context)) │ │ │ │ + } │ │ │ │ + node.appendChild(this.write_wmc_LayerExtension(context)) │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMC.v1_0_0" │ │ │ │ +}); │ │ │ │ OpenLayers.Format.WMC.v1_1_0 = OpenLayers.Class(OpenLayers.Format.WMC.v1, { │ │ │ │ VERSION: "1.1.0", │ │ │ │ schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.1.0/context.xsd", │ │ │ │ initialize: function(options) { │ │ │ │ OpenLayers.Format.WMC.v1.prototype.initialize.apply(this, [options]) │ │ │ │ }, │ │ │ │ read_sld_MinScaleDenominator: function(layerContext, node) { │ │ │ │ @@ -38306,491 +39007,458 @@ │ │ │ │ node.appendChild(this.write_wmc_DimensionList(context)) │ │ │ │ } │ │ │ │ node.appendChild(this.write_wmc_LayerExtension(context)); │ │ │ │ return node │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.WMC.v1_1_0" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.WMC.v1_0_0 = OpenLayers.Class(OpenLayers.Format.WMC.v1, { │ │ │ │ - VERSION: "1.0.0", │ │ │ │ - schemaLocation: "http://www.opengis.net/context http://schemas.opengis.net/context/1.0.0/context.xsd", │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.WMC.v1.prototype.initialize.apply(this, [options]) │ │ │ │ - }, │ │ │ │ - read_wmc_SRS: function(layerContext, node) { │ │ │ │ - var srs = this.getChildValue(node); │ │ │ │ - if (typeof layerContext.projections != "object") { │ │ │ │ - layerContext.projections = {} │ │ │ │ - } │ │ │ │ - var values = srs.split(/ +/); │ │ │ │ - for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ - layerContext.projections[values[i]] = true │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - write_wmc_Layer: function(context) { │ │ │ │ - var node = OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply(this, [context]); │ │ │ │ - if (context.srs) { │ │ │ │ - var projections = []; │ │ │ │ - for (var name in context.srs) { │ │ │ │ - projections.push(name) │ │ │ │ - } │ │ │ │ - node.appendChild(this.createElementDefaultNS("SRS", projections.join(" "))) │ │ │ │ - } │ │ │ │ - node.appendChild(this.write_wmc_FormatList(context)); │ │ │ │ - node.appendChild(this.write_wmc_StyleList(context)); │ │ │ │ - if (context.dimensions) { │ │ │ │ - node.appendChild(this.write_wmc_DimensionList(context)) │ │ │ │ - } │ │ │ │ - node.appendChild(this.write_wmc_LayerExtension(context)) │ │ │ │ +OpenLayers.Format.SOSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.SOSCapabilities, { │ │ │ │ + namespaces: { │ │ │ │ + ows: "http://www.opengis.net/ows/1.1", │ │ │ │ + sos: "http://www.opengis.net/sos/1.0", │ │ │ │ + gml: "http://www.opengis.net/gml", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink" │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WMC.v1_0_0" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WCSCapabilities.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ regExes: { │ │ │ │ trimSpace: /^\s*|\s*$/g, │ │ │ │ - splitSpace: /\s+/ │ │ │ │ + removeSpace: /\s*/g, │ │ │ │ + splitSpace: /\s+/, │ │ │ │ + trimComma: /\s*,\s*/g │ │ │ │ + }, │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ + this.options = options │ │ │ │ }, │ │ │ │ - defaultPrefix: "wcs", │ │ │ │ read: function(data) { │ │ │ │ if (typeof data == "string") { │ │ │ │ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ } │ │ │ │ - var raw = data; │ │ │ │ if (data && data.nodeType == 9) { │ │ │ │ data = data.documentElement │ │ │ │ } │ │ │ │ var capabilities = {}; │ │ │ │ this.readNode(data, capabilities); │ │ │ │ return capabilities │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WCSCapabilities.v1_1_0 = OpenLayers.Class(OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ - namespaces: { │ │ │ │ - wcs: "http://www.opengis.net/wcs/1.1", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ - ows: "http://www.opengis.net/ows/1.1" │ │ │ │ - }, │ │ │ │ - errorProperty: "operationsMetadata", │ │ │ │ readers: { │ │ │ │ - wcs: OpenLayers.Util.applyDefaults({ │ │ │ │ + gml: OpenLayers.Util.applyDefaults({ │ │ │ │ + name: function(node, obj) { │ │ │ │ + obj.name = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + TimePeriod: function(node, obj) { │ │ │ │ + obj.timePeriod = {}; │ │ │ │ + this.readChildNodes(node, obj.timePeriod) │ │ │ │ + }, │ │ │ │ + beginPosition: function(node, timePeriod) { │ │ │ │ + timePeriod.beginPosition = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + endPosition: function(node, timePeriod) { │ │ │ │ + timePeriod.endPosition = this.getChildValue(node) │ │ │ │ + } │ │ │ │ + }, OpenLayers.Format.GML.v3.prototype.readers["gml"]), │ │ │ │ + sos: { │ │ │ │ Capabilities: function(node, obj) { │ │ │ │ this.readChildNodes(node, obj) │ │ │ │ }, │ │ │ │ - Contents: function(node, request) { │ │ │ │ - request.contentMetadata = []; │ │ │ │ - this.readChildNodes(node, request.contentMetadata) │ │ │ │ + Contents: function(node, obj) { │ │ │ │ + obj.contents = {}; │ │ │ │ + this.readChildNodes(node, obj.contents) │ │ │ │ }, │ │ │ │ - CoverageSummary: function(node, contentMetadata) { │ │ │ │ - var coverageSummary = {}; │ │ │ │ - this.readChildNodes(node, coverageSummary); │ │ │ │ - contentMetadata.push(coverageSummary) │ │ │ │ + ObservationOfferingList: function(node, contents) { │ │ │ │ + contents.offeringList = {}; │ │ │ │ + this.readChildNodes(node, contents.offeringList) │ │ │ │ }, │ │ │ │ - Identifier: function(node, coverageSummary) { │ │ │ │ - coverageSummary.identifier = this.getChildValue(node) │ │ │ │ + ObservationOffering: function(node, offeringList) { │ │ │ │ + var id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ + offeringList[id] = { │ │ │ │ + procedures: [], │ │ │ │ + observedProperties: [], │ │ │ │ + featureOfInterestIds: [], │ │ │ │ + responseFormats: [], │ │ │ │ + resultModels: [], │ │ │ │ + responseModes: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, offeringList[id]) │ │ │ │ }, │ │ │ │ - Title: function(node, coverageSummary) { │ │ │ │ - coverageSummary.title = this.getChildValue(node) │ │ │ │ + time: function(node, offering) { │ │ │ │ + offering.time = {}; │ │ │ │ + this.readChildNodes(node, offering.time) │ │ │ │ }, │ │ │ │ - Abstract: function(node, coverageSummary) { │ │ │ │ - coverageSummary["abstract"] = this.getChildValue(node) │ │ │ │ + procedure: function(node, offering) { │ │ │ │ + offering.procedures.push(this.getAttributeNS(node, this.namespaces.xlink, "href")) │ │ │ │ }, │ │ │ │ - SupportedCRS: function(node, coverageSummary) { │ │ │ │ - var crs = this.getChildValue(node); │ │ │ │ - if (crs) { │ │ │ │ - if (!coverageSummary.supportedCRS) { │ │ │ │ - coverageSummary.supportedCRS = [] │ │ │ │ - } │ │ │ │ - coverageSummary.supportedCRS.push(crs) │ │ │ │ - } │ │ │ │ + observedProperty: function(node, offering) { │ │ │ │ + offering.observedProperties.push(this.getAttributeNS(node, this.namespaces.xlink, "href")) │ │ │ │ }, │ │ │ │ - SupportedFormat: function(node, coverageSummary) { │ │ │ │ - var format = this.getChildValue(node); │ │ │ │ - if (format) { │ │ │ │ - if (!coverageSummary.supportedFormat) { │ │ │ │ - coverageSummary.supportedFormat = [] │ │ │ │ - } │ │ │ │ - coverageSummary.supportedFormat.push(format) │ │ │ │ - } │ │ │ │ + featureOfInterest: function(node, offering) { │ │ │ │ + offering.featureOfInterestIds.push(this.getAttributeNS(node, this.namespaces.xlink, "href")) │ │ │ │ + }, │ │ │ │ + responseFormat: function(node, offering) { │ │ │ │ + offering.responseFormats.push(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + resultModel: function(node, offering) { │ │ │ │ + offering.resultModels.push(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + responseMode: function(node, offering) { │ │ │ │ + offering.responseModes.push(this.getChildValue(node)) │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.WCSCapabilities.v1.prototype.readers["wcs"]), │ │ │ │ + }, │ │ │ │ ows: OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_1_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SOSCapabilities.v1_0_0" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.WCSCapabilities.v1, { │ │ │ │ +OpenLayers.Format.XLS.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ namespaces: { │ │ │ │ - wcs: "http://www.opengis.net/wcs", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ - ows: "http://www.opengis.net/ows" │ │ │ │ + xls: "http://www.opengis.net/xls", │ │ │ │ + gml: "http://www.opengis.net/gml", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + }, │ │ │ │ + regExes: { │ │ │ │ + trimSpace: /^\s*|\s*$/g, │ │ │ │ + removeSpace: /\s*/g, │ │ │ │ + splitSpace: /\s+/, │ │ │ │ + trimComma: /\s*,\s*/g │ │ │ │ + }, │ │ │ │ + xy: true, │ │ │ │ + defaultPrefix: "xls", │ │ │ │ + schemaLocation: null, │ │ │ │ + read: function(data, options) { │ │ │ │ + options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ + var xls = {}; │ │ │ │ + this.readChildNodes(data, xls); │ │ │ │ + return xls │ │ │ │ }, │ │ │ │ - errorProperty: "service", │ │ │ │ readers: { │ │ │ │ - wcs: { │ │ │ │ - WCS_Capabilities: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - Service: function(node, obj) { │ │ │ │ - obj.service = {}; │ │ │ │ - this.readChildNodes(node, obj.service) │ │ │ │ - }, │ │ │ │ - name: function(node, service) { │ │ │ │ - service.name = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - label: function(node, service) { │ │ │ │ - service.label = this.getChildValue(node) │ │ │ │ + xls: { │ │ │ │ + XLS: function(node, xls) { │ │ │ │ + xls.version = node.getAttribute("version"); │ │ │ │ + this.readChildNodes(node, xls) │ │ │ │ }, │ │ │ │ - keywords: function(node, service) { │ │ │ │ - service.keywords = []; │ │ │ │ - this.readChildNodes(node, service.keywords) │ │ │ │ + Response: function(node, xls) { │ │ │ │ + this.readChildNodes(node, xls) │ │ │ │ }, │ │ │ │ - keyword: function(node, keywords) { │ │ │ │ - keywords.push(this.getChildValue(node)) │ │ │ │ + GeocodeResponse: function(node, xls) { │ │ │ │ + xls.responseLists = []; │ │ │ │ + this.readChildNodes(node, xls) │ │ │ │ }, │ │ │ │ - responsibleParty: function(node, service) { │ │ │ │ - service.responsibleParty = {}; │ │ │ │ - this.readChildNodes(node, service.responsibleParty) │ │ │ │ + GeocodeResponseList: function(node, xls) { │ │ │ │ + var responseList = { │ │ │ │ + features: [], │ │ │ │ + numberOfGeocodedAddresses: parseInt(node.getAttribute("numberOfGeocodedAddresses")) │ │ │ │ + }; │ │ │ │ + xls.responseLists.push(responseList); │ │ │ │ + this.readChildNodes(node, responseList) │ │ │ │ }, │ │ │ │ - individualName: function(node, responsibleParty) { │ │ │ │ - responsibleParty.individualName = this.getChildValue(node) │ │ │ │ + GeocodedAddress: function(node, responseList) { │ │ │ │ + var feature = new OpenLayers.Feature.Vector; │ │ │ │ + responseList.features.push(feature); │ │ │ │ + this.readChildNodes(node, feature); │ │ │ │ + feature.geometry = feature.components[0] │ │ │ │ }, │ │ │ │ - organisationName: function(node, responsibleParty) { │ │ │ │ - responsibleParty.organisationName = this.getChildValue(node) │ │ │ │ + GeocodeMatchCode: function(node, feature) { │ │ │ │ + feature.attributes.matchCode = { │ │ │ │ + accuracy: parseFloat(node.getAttribute("accuracy")), │ │ │ │ + matchType: node.getAttribute("matchType") │ │ │ │ + } │ │ │ │ }, │ │ │ │ - positionName: function(node, responsibleParty) { │ │ │ │ - responsibleParty.positionName = this.getChildValue(node) │ │ │ │ + Address: function(node, feature) { │ │ │ │ + var address = { │ │ │ │ + countryCode: node.getAttribute("countryCode"), │ │ │ │ + addressee: node.getAttribute("addressee"), │ │ │ │ + street: [], │ │ │ │ + place: [] │ │ │ │ + }; │ │ │ │ + feature.attributes.address = address; │ │ │ │ + this.readChildNodes(node, address) │ │ │ │ }, │ │ │ │ - contactInfo: function(node, responsibleParty) { │ │ │ │ - responsibleParty.contactInfo = {}; │ │ │ │ - this.readChildNodes(node, responsibleParty.contactInfo) │ │ │ │ + freeFormAddress: function(node, address) { │ │ │ │ + address.freeFormAddress = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - phone: function(node, contactInfo) { │ │ │ │ - contactInfo.phone = {}; │ │ │ │ - this.readChildNodes(node, contactInfo.phone) │ │ │ │ + StreetAddress: function(node, address) { │ │ │ │ + this.readChildNodes(node, address) │ │ │ │ }, │ │ │ │ - voice: function(node, phone) { │ │ │ │ - phone.voice = this.getChildValue(node) │ │ │ │ + Building: function(node, address) { │ │ │ │ + address.building = { │ │ │ │ + number: node.getAttribute("number"), │ │ │ │ + subdivision: node.getAttribute("subdivision"), │ │ │ │ + buildingName: node.getAttribute("buildingName") │ │ │ │ + } │ │ │ │ }, │ │ │ │ - facsimile: function(node, phone) { │ │ │ │ - phone.facsimile = this.getChildValue(node) │ │ │ │ + Street: function(node, address) { │ │ │ │ + address.street.push(this.getChildValue(node)) │ │ │ │ }, │ │ │ │ - address: function(node, contactInfo) { │ │ │ │ - contactInfo.address = {}; │ │ │ │ - this.readChildNodes(node, contactInfo.address) │ │ │ │ + Place: function(node, address) { │ │ │ │ + address.place[node.getAttribute("type")] = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - deliveryPoint: function(node, address) { │ │ │ │ - address.deliveryPoint = this.getChildValue(node) │ │ │ │ + PostalCode: function(node, address) { │ │ │ │ + address.postalCode = this.getChildValue(node) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + gml: OpenLayers.Format.GML.v3.prototype.readers.gml │ │ │ │ + }, │ │ │ │ + write: function(request) { │ │ │ │ + return this.writers.xls.XLS.apply(this, [request]) │ │ │ │ + }, │ │ │ │ + writers: { │ │ │ │ + xls: { │ │ │ │ + XLS: function(request) { │ │ │ │ + var root = this.createElementNSPlus("xls:XLS", { │ │ │ │ + attributes: { │ │ │ │ + version: this.VERSION, │ │ │ │ + "xsi:schemaLocation": this.schemaLocation │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.writeNode("RequestHeader", request.header, root); │ │ │ │ + this.writeNode("Request", request, root); │ │ │ │ + return root │ │ │ │ }, │ │ │ │ - city: function(node, address) { │ │ │ │ - address.city = this.getChildValue(node) │ │ │ │ + RequestHeader: function(header) { │ │ │ │ + return this.createElementNSPlus("xls:RequestHeader") │ │ │ │ }, │ │ │ │ - postalCode: function(node, address) { │ │ │ │ - address.postalCode = this.getChildValue(node) │ │ │ │ + Request: function(request) { │ │ │ │ + var node = this.createElementNSPlus("xls:Request", { │ │ │ │ + attributes: { │ │ │ │ + methodName: "GeocodeRequest", │ │ │ │ + requestID: request.requestID || "", │ │ │ │ + version: this.VERSION │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + this.writeNode("GeocodeRequest", request.addresses, node); │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - country: function(node, address) { │ │ │ │ - address.country = this.getChildValue(node) │ │ │ │ + GeocodeRequest: function(addresses) { │ │ │ │ + var node = this.createElementNSPlus("xls:GeocodeRequest"); │ │ │ │ + for (var i = 0, len = addresses.length; i < len; i++) { │ │ │ │ + this.writeNode("Address", addresses[i], node) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - electronicMailAddress: function(node, address) { │ │ │ │ - address.electronicMailAddress = this.getChildValue(node) │ │ │ │ + Address: function(address) { │ │ │ │ + var node = this.createElementNSPlus("xls:Address", { │ │ │ │ + attributes: { │ │ │ │ + countryCode: address.countryCode │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (address.freeFormAddress) { │ │ │ │ + this.writeNode("freeFormAddress", address.freeFormAddress, node) │ │ │ │ + } else { │ │ │ │ + if (address.street) { │ │ │ │ + this.writeNode("StreetAddress", address, node) │ │ │ │ + } │ │ │ │ + if (address.municipality) { │ │ │ │ + this.writeNode("Municipality", address.municipality, node) │ │ │ │ + } │ │ │ │ + if (address.countrySubdivision) { │ │ │ │ + this.writeNode("CountrySubdivision", address.countrySubdivision, node) │ │ │ │ + } │ │ │ │ + if (address.postalCode) { │ │ │ │ + this.writeNode("PostalCode", address.postalCode, node) │ │ │ │ + } │ │ │ │ + } │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - fees: function(node, service) { │ │ │ │ - service.fees = this.getChildValue(node) │ │ │ │ + freeFormAddress: function(freeFormAddress) { │ │ │ │ + return this.createElementNSPlus("freeFormAddress", { │ │ │ │ + value: freeFormAddress │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - accessConstraints: function(node, service) { │ │ │ │ - service.accessConstraints = this.getChildValue(node) │ │ │ │ + StreetAddress: function(address) { │ │ │ │ + var node = this.createElementNSPlus("xls:StreetAddress"); │ │ │ │ + if (address.building) { │ │ │ │ + this.writeNode(node, "Building", address.building) │ │ │ │ + } │ │ │ │ + var street = address.street; │ │ │ │ + if (!OpenLayers.Util.isArray(street)) { │ │ │ │ + street = [street] │ │ │ │ + } │ │ │ │ + for (var i = 0, len = street.length; i < len; i++) { │ │ │ │ + this.writeNode("Street", street[i], node) │ │ │ │ + } │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - ContentMetadata: function(node, obj) { │ │ │ │ - obj.contentMetadata = []; │ │ │ │ - this.readChildNodes(node, obj.contentMetadata) │ │ │ │ + Building: function(building) { │ │ │ │ + return this.createElementNSPlus("xls:Building", { │ │ │ │ + attributes: { │ │ │ │ + number: building["number"], │ │ │ │ + subdivision: building.subdivision, │ │ │ │ + buildingName: building.buildingName │ │ │ │ + } │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - CoverageOfferingBrief: function(node, contentMetadata) { │ │ │ │ - var coverageOfferingBrief = {}; │ │ │ │ - this.readChildNodes(node, coverageOfferingBrief); │ │ │ │ - contentMetadata.push(coverageOfferingBrief) │ │ │ │ + Street: function(street) { │ │ │ │ + return this.createElementNSPlus("xls:Street", { │ │ │ │ + value: street │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - name: function(node, coverageOfferingBrief) { │ │ │ │ - coverageOfferingBrief.name = this.getChildValue(node) │ │ │ │ + Municipality: function(municipality) { │ │ │ │ + return this.createElementNSPlus("xls:Place", { │ │ │ │ + attributes: { │ │ │ │ + type: "Municipality" │ │ │ │ + }, │ │ │ │ + value: municipality │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - label: function(node, coverageOfferingBrief) { │ │ │ │ - coverageOfferingBrief.label = this.getChildValue(node) │ │ │ │ + CountrySubdivision: function(countrySubdivision) { │ │ │ │ + return this.createElementNSPlus("xls:Place", { │ │ │ │ + attributes: { │ │ │ │ + type: "CountrySubdivision" │ │ │ │ + }, │ │ │ │ + value: countrySubdivision │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - lonLatEnvelope: function(node, coverageOfferingBrief) { │ │ │ │ - var nodeList = this.getElementsByTagNameNS(node, "http://www.opengis.net/gml", "pos"); │ │ │ │ - if (nodeList.length == 2) { │ │ │ │ - var min = {}; │ │ │ │ - var max = {}; │ │ │ │ - OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[0], min]); │ │ │ │ - OpenLayers.Format.GML.v3.prototype.readers["gml"].pos.apply(this, [nodeList[1], max]); │ │ │ │ - coverageOfferingBrief.lonLatEnvelope = {}; │ │ │ │ - coverageOfferingBrief.lonLatEnvelope.srsName = node.getAttribute("srsName"); │ │ │ │ - coverageOfferingBrief.lonLatEnvelope.min = min.points[0]; │ │ │ │ - coverageOfferingBrief.lonLatEnvelope.max = max.points[0] │ │ │ │ - } │ │ │ │ + PostalCode: function(postalCode) { │ │ │ │ + return this.createElementNSPlus("xls:PostalCode", { │ │ │ │ + value: postalCode │ │ │ │ + }) │ │ │ │ } │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_0_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.XLS.v1" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.WFSCapabilities.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ +OpenLayers.Format.XLS.v1_1_0 = OpenLayers.Class(OpenLayers.Format.XLS.v1, { │ │ │ │ + VERSION: "1.1", │ │ │ │ + schemaLocation: "http://www.opengis.net/xls http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd", │ │ │ │ + CLASS_NAME: "OpenLayers.Format.XLS.v1_1_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.XLS.v1_1 = OpenLayers.Format.XLS.v1_1_0; │ │ │ │ +OpenLayers.Format.CSWGetDomain.v2_0_2 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ namespaces: { │ │ │ │ - wfs: "http://www.opengis.net/wfs", │ │ │ │ xlink: "http://www.w3.org/1999/xlink", │ │ │ │ xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ - ows: "http://www.opengis.net/ows" │ │ │ │ + csw: "http://www.opengis.net/cat/csw/2.0.2" │ │ │ │ }, │ │ │ │ - errorProperty: "featureTypeList", │ │ │ │ - defaultPrefix: "wfs", │ │ │ │ + defaultPrefix: "csw", │ │ │ │ + version: "2.0.2", │ │ │ │ + schemaLocation: "http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd", │ │ │ │ + PropertyName: null, │ │ │ │ + ParameterName: null, │ │ │ │ read: function(data) { │ │ │ │ if (typeof data == "string") { │ │ │ │ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ } │ │ │ │ - var raw = data; │ │ │ │ if (data && data.nodeType == 9) { │ │ │ │ data = data.documentElement │ │ │ │ } │ │ │ │ - var capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - return capabilities │ │ │ │ + var obj = {}; │ │ │ │ + this.readNode(data, obj); │ │ │ │ + return obj │ │ │ │ }, │ │ │ │ readers: { │ │ │ │ - wfs: { │ │ │ │ - WFS_Capabilities: function(node, obj) { │ │ │ │ + csw: { │ │ │ │ + GetDomainResponse: function(node, obj) { │ │ │ │ this.readChildNodes(node, obj) │ │ │ │ }, │ │ │ │ - FeatureTypeList: function(node, request) { │ │ │ │ - request.featureTypeList = { │ │ │ │ - featureTypes: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, request.featureTypeList) │ │ │ │ - }, │ │ │ │ - FeatureType: function(node, featureTypeList) { │ │ │ │ - var featureType = {}; │ │ │ │ - this.readChildNodes(node, featureType); │ │ │ │ - featureTypeList.featureTypes.push(featureType) │ │ │ │ - }, │ │ │ │ - Name: function(node, obj) { │ │ │ │ - var name = this.getChildValue(node); │ │ │ │ - if (name) { │ │ │ │ - var parts = name.split(":"); │ │ │ │ - obj.name = parts.pop(); │ │ │ │ - if (parts.length > 0) { │ │ │ │ - obj.featureNS = this.lookupNamespaceURI(node, parts[0]) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - Title: function(node, obj) { │ │ │ │ - var title = this.getChildValue(node); │ │ │ │ - if (title) { │ │ │ │ - obj.title = title │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - Abstract: function(node, obj) { │ │ │ │ - var abst = this.getChildValue(node); │ │ │ │ - if (abst) { │ │ │ │ - obj["abstract"] = abst │ │ │ │ + DomainValues: function(node, obj) { │ │ │ │ + if (!OpenLayers.Util.isArray(obj.DomainValues)) { │ │ │ │ + obj.DomainValues = [] │ │ │ │ } │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WFSCapabilities.v1_1_0 = OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ - regExes: { │ │ │ │ - trimSpace: /^\s*|\s*$/g, │ │ │ │ - removeSpace: /\s*/g, │ │ │ │ - splitSpace: /\s+/, │ │ │ │ - trimComma: /\s*,\s*/g │ │ │ │ - }, │ │ │ │ - readers: { │ │ │ │ - wfs: OpenLayers.Util.applyDefaults({ │ │ │ │ - DefaultSRS: function(node, obj) { │ │ │ │ - var defaultSRS = this.getChildValue(node); │ │ │ │ - if (defaultSRS) { │ │ │ │ - obj.srs = defaultSRS │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var domainValue = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + domainValue[attrs[i].name] = attrs[i].nodeValue │ │ │ │ } │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]), │ │ │ │ - ows: OpenLayers.Format.OWSCommon.v1.prototype.readers.ows │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_1_0" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.WFSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ - readers: { │ │ │ │ - wfs: OpenLayers.Util.applyDefaults({ │ │ │ │ - Service: function(node, capabilities) { │ │ │ │ - capabilities.service = {}; │ │ │ │ - this.readChildNodes(node, capabilities.service) │ │ │ │ + this.readChildNodes(node, domainValue); │ │ │ │ + obj.DomainValues.push(domainValue) │ │ │ │ }, │ │ │ │ - Fees: function(node, service) { │ │ │ │ - var fees = this.getChildValue(node); │ │ │ │ - if (fees && fees.toLowerCase() != "none") { │ │ │ │ - service.fees = fees │ │ │ │ - } │ │ │ │ + PropertyName: function(node, obj) { │ │ │ │ + obj.PropertyName = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - AccessConstraints: function(node, service) { │ │ │ │ - var constraints = this.getChildValue(node); │ │ │ │ - if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ - service.accessConstraints = constraints │ │ │ │ - } │ │ │ │ + ParameterName: function(node, obj) { │ │ │ │ + obj.ParameterName = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - OnlineResource: function(node, service) { │ │ │ │ - var onlineResource = this.getChildValue(node); │ │ │ │ - if (onlineResource && onlineResource.toLowerCase() != "none") { │ │ │ │ - service.onlineResource = onlineResource │ │ │ │ + ListOfValues: function(node, obj) { │ │ │ │ + if (!OpenLayers.Util.isArray(obj.ListOfValues)) { │ │ │ │ + obj.ListOfValues = [] │ │ │ │ } │ │ │ │ + this.readChildNodes(node, obj.ListOfValues) │ │ │ │ }, │ │ │ │ - Keywords: function(node, service) { │ │ │ │ - var keywords = this.getChildValue(node); │ │ │ │ - if (keywords && keywords.toLowerCase() != "none") { │ │ │ │ - service.keywords = keywords.split(", ") │ │ │ │ + Value: function(node, obj) { │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var value = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + value[attrs[i].name] = attrs[i].nodeValue │ │ │ │ } │ │ │ │ + value.value = this.getChildValue(node); │ │ │ │ + obj.push({ │ │ │ │ + Value: value │ │ │ │ + }) │ │ │ │ }, │ │ │ │ - Capability: function(node, capabilities) { │ │ │ │ - capabilities.capability = {}; │ │ │ │ - this.readChildNodes(node, capabilities.capability) │ │ │ │ - }, │ │ │ │ - Request: function(node, obj) { │ │ │ │ - obj.request = {}; │ │ │ │ - this.readChildNodes(node, obj.request) │ │ │ │ - }, │ │ │ │ - GetFeature: function(node, request) { │ │ │ │ - request.getfeature = { │ │ │ │ - href: {}, │ │ │ │ - formats: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, request.getfeature) │ │ │ │ + ConceptualScheme: function(node, obj) { │ │ │ │ + obj.ConceptualScheme = {}; │ │ │ │ + this.readChildNodes(node, obj.ConceptualScheme) │ │ │ │ }, │ │ │ │ - ResultFormat: function(node, obj) { │ │ │ │ - var children = node.childNodes; │ │ │ │ - var childNode; │ │ │ │ - for (var i = 0; i < children.length; i++) { │ │ │ │ - childNode = children[i]; │ │ │ │ - if (childNode.nodeType == 1) { │ │ │ │ - obj.formats.push(childNode.nodeName) │ │ │ │ - } │ │ │ │ - } │ │ │ │ + Name: function(node, obj) { │ │ │ │ + obj.Name = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - DCPType: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ + Document: function(node, obj) { │ │ │ │ + obj.Document = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - HTTP: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj.href) │ │ │ │ + Authority: function(node, obj) { │ │ │ │ + obj.Authority = this.getChildValue(node) │ │ │ │ }, │ │ │ │ - Get: function(node, obj) { │ │ │ │ - obj.get = node.getAttribute("onlineResource") │ │ │ │ + RangeOfValues: function(node, obj) { │ │ │ │ + obj.RangeOfValues = {}; │ │ │ │ + this.readChildNodes(node, obj.RangeOfValues) │ │ │ │ }, │ │ │ │ - Post: function(node, obj) { │ │ │ │ - obj.post = node.getAttribute("onlineResource") │ │ │ │ + MinValue: function(node, obj) { │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var value = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + value[attrs[i].name] = attrs[i].nodeValue │ │ │ │ + } │ │ │ │ + value.value = this.getChildValue(node); │ │ │ │ + obj.MinValue = value │ │ │ │ }, │ │ │ │ - SRS: function(node, obj) { │ │ │ │ - var srs = this.getChildValue(node); │ │ │ │ - if (srs) { │ │ │ │ - obj.srs = srs │ │ │ │ + MaxValue: function(node, obj) { │ │ │ │ + var attrs = node.attributes; │ │ │ │ + var value = {}; │ │ │ │ + for (var i = 0, len = attrs.length; i < len; ++i) { │ │ │ │ + value[attrs[i].name] = attrs[i].nodeValue │ │ │ │ } │ │ │ │ + value.value = this.getChildValue(node); │ │ │ │ + obj.MaxValue = value │ │ │ │ } │ │ │ │ - }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]) │ │ │ │ - }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_0_0" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.SOSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.SOSCapabilities, { │ │ │ │ - namespaces: { │ │ │ │ - ows: "http://www.opengis.net/ows/1.1", │ │ │ │ - sos: "http://www.opengis.net/sos/1.0", │ │ │ │ - gml: "http://www.opengis.net/gml", │ │ │ │ - xlink: "http://www.w3.org/1999/xlink" │ │ │ │ - }, │ │ │ │ - regExes: { │ │ │ │ - trimSpace: /^\s*|\s*$/g, │ │ │ │ - removeSpace: /\s*/g, │ │ │ │ - splitSpace: /\s+/, │ │ │ │ - trimComma: /\s*,\s*/g │ │ │ │ - }, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ - this.options = options │ │ │ │ - }, │ │ │ │ - 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 capabilities = {}; │ │ │ │ - this.readNode(data, capabilities); │ │ │ │ - return capabilities │ │ │ │ }, │ │ │ │ - readers: { │ │ │ │ - gml: OpenLayers.Util.applyDefaults({ │ │ │ │ - name: function(node, obj) { │ │ │ │ - obj.name = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - TimePeriod: function(node, obj) { │ │ │ │ - obj.timePeriod = {}; │ │ │ │ - this.readChildNodes(node, obj.timePeriod) │ │ │ │ - }, │ │ │ │ - beginPosition: function(node, timePeriod) { │ │ │ │ - timePeriod.beginPosition = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - endPosition: function(node, timePeriod) { │ │ │ │ - timePeriod.endPosition = this.getChildValue(node) │ │ │ │ - } │ │ │ │ - }, OpenLayers.Format.GML.v3.prototype.readers["gml"]), │ │ │ │ - sos: { │ │ │ │ - Capabilities: function(node, obj) { │ │ │ │ - this.readChildNodes(node, obj) │ │ │ │ - }, │ │ │ │ - Contents: function(node, obj) { │ │ │ │ - obj.contents = {}; │ │ │ │ - this.readChildNodes(node, obj.contents) │ │ │ │ - }, │ │ │ │ - ObservationOfferingList: function(node, contents) { │ │ │ │ - contents.offeringList = {}; │ │ │ │ - this.readChildNodes(node, contents.offeringList) │ │ │ │ - }, │ │ │ │ - ObservationOffering: function(node, offeringList) { │ │ │ │ - var id = this.getAttributeNS(node, this.namespaces.gml, "id"); │ │ │ │ - offeringList[id] = { │ │ │ │ - procedures: [], │ │ │ │ - observedProperties: [], │ │ │ │ - featureOfInterestIds: [], │ │ │ │ - responseFormats: [], │ │ │ │ - resultModels: [], │ │ │ │ - responseModes: [] │ │ │ │ - }; │ │ │ │ - this.readChildNodes(node, offeringList[id]) │ │ │ │ - }, │ │ │ │ - time: function(node, offering) { │ │ │ │ - offering.time = {}; │ │ │ │ - this.readChildNodes(node, offering.time) │ │ │ │ - }, │ │ │ │ - procedure: function(node, offering) { │ │ │ │ - offering.procedures.push(this.getAttributeNS(node, this.namespaces.xlink, "href")) │ │ │ │ - }, │ │ │ │ - observedProperty: function(node, offering) { │ │ │ │ - offering.observedProperties.push(this.getAttributeNS(node, this.namespaces.xlink, "href")) │ │ │ │ - }, │ │ │ │ - featureOfInterest: function(node, offering) { │ │ │ │ - offering.featureOfInterestIds.push(this.getAttributeNS(node, this.namespaces.xlink, "href")) │ │ │ │ - }, │ │ │ │ - responseFormat: function(node, offering) { │ │ │ │ - offering.responseFormats.push(this.getChildValue(node)) │ │ │ │ + write: function(options) { │ │ │ │ + var node = this.writeNode("csw:GetDomain", options); │ │ │ │ + return OpenLayers.Format.XML.prototype.write.apply(this, [node]) │ │ │ │ + }, │ │ │ │ + writers: { │ │ │ │ + csw: { │ │ │ │ + GetDomain: function(options) { │ │ │ │ + var node = this.createElementNSPlus("csw:GetDomain", { │ │ │ │ + attributes: { │ │ │ │ + service: "CSW", │ │ │ │ + version: this.version │ │ │ │ + } │ │ │ │ + }); │ │ │ │ + if (options.PropertyName || this.PropertyName) { │ │ │ │ + this.writeNode("csw:PropertyName", options.PropertyName || this.PropertyName, node) │ │ │ │ + } else if (options.ParameterName || this.ParameterName) { │ │ │ │ + this.writeNode("csw:ParameterName", options.ParameterName || this.ParameterName, node) │ │ │ │ + } │ │ │ │ + this.readChildNodes(node, options); │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - resultModel: function(node, offering) { │ │ │ │ - offering.resultModels.push(this.getChildValue(node)) │ │ │ │ + PropertyName: function(value) { │ │ │ │ + var node = this.createElementNSPlus("csw:PropertyName", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - responseMode: function(node, offering) { │ │ │ │ - offering.responseModes.push(this.getChildValue(node)) │ │ │ │ + ParameterName: function(value) { │ │ │ │ + var node = this.createElementNSPlus("csw:ParameterName", { │ │ │ │ + value: value │ │ │ │ + }); │ │ │ │ + return node │ │ │ │ } │ │ │ │ - }, │ │ │ │ - ows: OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ + } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.SOSCapabilities.v1_0_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.CSWGetDomain.v2_0_2" │ │ │ │ }); │ │ │ │ OpenLayers.Format.OWSContext.v0_3_1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ namespaces: { │ │ │ │ owc: "http://www.opengis.net/ows-context", │ │ │ │ gml: "http://www.opengis.net/gml", │ │ │ │ kml: "http://www.opengis.net/kml/2.2", │ │ │ │ ogc: "http://www.opengis.net/ogc", │ │ │ │ @@ -39194,1044 +39862,1084 @@ │ │ │ │ }, OpenLayers.Format.GML.v2.prototype.writers.gml), │ │ │ │ ows: OpenLayers.Format.OWSCommon.v1_0_0.prototype.writers.ows, │ │ │ │ sld: OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld, │ │ │ │ feature: OpenLayers.Format.GML.v2.prototype.writers.feature │ │ │ │ }, │ │ │ │ CLASS_NAME: "OpenLayers.Format.OWSContext.v0_3_1" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.XLS.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ +OpenLayers.Format.WPSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ namespaces: { │ │ │ │ - xls: "http://www.opengis.net/xls", │ │ │ │ - gml: "http://www.opengis.net/gml", │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ + ows: "http://www.opengis.net/ows/1.1", │ │ │ │ + wps: "http://www.opengis.net/wps/1.0.0", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink" │ │ │ │ }, │ │ │ │ regExes: { │ │ │ │ trimSpace: /^\s*|\s*$/g, │ │ │ │ removeSpace: /\s*/g, │ │ │ │ splitSpace: /\s+/, │ │ │ │ trimComma: /\s*,\s*/g │ │ │ │ }, │ │ │ │ - xy: true, │ │ │ │ - defaultPrefix: "xls", │ │ │ │ - schemaLocation: null, │ │ │ │ - read: function(data, options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ - var xls = {}; │ │ │ │ - this.readChildNodes(data, xls); │ │ │ │ - return xls │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + 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 capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + return capabilities │ │ │ │ }, │ │ │ │ readers: { │ │ │ │ - xls: { │ │ │ │ - XLS: function(node, xls) { │ │ │ │ - xls.version = node.getAttribute("version"); │ │ │ │ - this.readChildNodes(node, xls) │ │ │ │ - }, │ │ │ │ - Response: function(node, xls) { │ │ │ │ - this.readChildNodes(node, xls) │ │ │ │ + wps: { │ │ │ │ + Capabilities: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ }, │ │ │ │ - GeocodeResponse: function(node, xls) { │ │ │ │ - xls.responseLists = []; │ │ │ │ - this.readChildNodes(node, xls) │ │ │ │ + ProcessOfferings: function(node, obj) { │ │ │ │ + obj.processOfferings = {}; │ │ │ │ + this.readChildNodes(node, obj.processOfferings) │ │ │ │ }, │ │ │ │ - GeocodeResponseList: function(node, xls) { │ │ │ │ - var responseList = { │ │ │ │ - features: [], │ │ │ │ - numberOfGeocodedAddresses: parseInt(node.getAttribute("numberOfGeocodedAddresses")) │ │ │ │ + Process: function(node, processOfferings) { │ │ │ │ + var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); │ │ │ │ + var process = { │ │ │ │ + processVersion: processVersion │ │ │ │ }; │ │ │ │ - xls.responseLists.push(responseList); │ │ │ │ - this.readChildNodes(node, responseList) │ │ │ │ - }, │ │ │ │ - GeocodedAddress: function(node, responseList) { │ │ │ │ - var feature = new OpenLayers.Feature.Vector; │ │ │ │ - responseList.features.push(feature); │ │ │ │ - this.readChildNodes(node, feature); │ │ │ │ - feature.geometry = feature.components[0] │ │ │ │ + this.readChildNodes(node, process); │ │ │ │ + processOfferings[process.identifier] = process │ │ │ │ }, │ │ │ │ - GeocodeMatchCode: function(node, feature) { │ │ │ │ - feature.attributes.matchCode = { │ │ │ │ - accuracy: parseFloat(node.getAttribute("accuracy")), │ │ │ │ - matchType: node.getAttribute("matchType") │ │ │ │ - } │ │ │ │ + Languages: function(node, obj) { │ │ │ │ + obj.languages = []; │ │ │ │ + this.readChildNodes(node, obj.languages) │ │ │ │ }, │ │ │ │ - Address: function(node, feature) { │ │ │ │ - var address = { │ │ │ │ - countryCode: node.getAttribute("countryCode"), │ │ │ │ - addressee: node.getAttribute("addressee"), │ │ │ │ - street: [], │ │ │ │ - place: [] │ │ │ │ + Default: function(node, languages) { │ │ │ │ + var language = { │ │ │ │ + isDefault: true │ │ │ │ }; │ │ │ │ - feature.attributes.address = address; │ │ │ │ - this.readChildNodes(node, address) │ │ │ │ - }, │ │ │ │ - freeFormAddress: function(node, address) { │ │ │ │ - address.freeFormAddress = this.getChildValue(node) │ │ │ │ - }, │ │ │ │ - StreetAddress: function(node, address) { │ │ │ │ - this.readChildNodes(node, address) │ │ │ │ - }, │ │ │ │ - Building: function(node, address) { │ │ │ │ - address.building = { │ │ │ │ - number: node.getAttribute("number"), │ │ │ │ - subdivision: node.getAttribute("subdivision"), │ │ │ │ - buildingName: node.getAttribute("buildingName") │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - Street: function(node, address) { │ │ │ │ - address.street.push(this.getChildValue(node)) │ │ │ │ - }, │ │ │ │ - Place: function(node, address) { │ │ │ │ - address.place[node.getAttribute("type")] = this.getChildValue(node) │ │ │ │ + this.readChildNodes(node, language); │ │ │ │ + languages.push(language) │ │ │ │ }, │ │ │ │ - PostalCode: function(node, address) { │ │ │ │ - address.postalCode = this.getChildValue(node) │ │ │ │ + Supported: function(node, languages) { │ │ │ │ + var language = {}; │ │ │ │ + this.readChildNodes(node, language); │ │ │ │ + languages.push(language) │ │ │ │ } │ │ │ │ }, │ │ │ │ - gml: OpenLayers.Format.GML.v3.prototype.readers.gml │ │ │ │ + ows: OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ }, │ │ │ │ - write: function(request) { │ │ │ │ - return this.writers.xls.XLS.apply(this, [request]) │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WPSCapabilities.v1_0_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WFSCapabilities.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + namespaces: { │ │ │ │ + wfs: "http://www.opengis.net/wfs", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance", │ │ │ │ + ows: "http://www.opengis.net/ows" │ │ │ │ }, │ │ │ │ - writers: { │ │ │ │ - xls: { │ │ │ │ - XLS: function(request) { │ │ │ │ - var root = this.createElementNSPlus("xls:XLS", { │ │ │ │ - attributes: { │ │ │ │ - version: this.VERSION, │ │ │ │ - "xsi:schemaLocation": this.schemaLocation │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - this.writeNode("RequestHeader", request.header, root); │ │ │ │ - this.writeNode("Request", request, root); │ │ │ │ - return root │ │ │ │ + errorProperty: "featureTypeList", │ │ │ │ + defaultPrefix: "wfs", │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ + } │ │ │ │ + var raw = data; │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement │ │ │ │ + } │ │ │ │ + var capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + return capabilities │ │ │ │ + }, │ │ │ │ + readers: { │ │ │ │ + wfs: { │ │ │ │ + WFS_Capabilities: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ }, │ │ │ │ - RequestHeader: function(header) { │ │ │ │ - return this.createElementNSPlus("xls:RequestHeader") │ │ │ │ + FeatureTypeList: function(node, request) { │ │ │ │ + request.featureTypeList = { │ │ │ │ + featureTypes: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, request.featureTypeList) │ │ │ │ }, │ │ │ │ - Request: function(request) { │ │ │ │ - var node = this.createElementNSPlus("xls:Request", { │ │ │ │ - attributes: { │ │ │ │ - methodName: "GeocodeRequest", │ │ │ │ - requestID: request.requestID || "", │ │ │ │ - version: this.VERSION │ │ │ │ + FeatureType: function(node, featureTypeList) { │ │ │ │ + var featureType = {}; │ │ │ │ + this.readChildNodes(node, featureType); │ │ │ │ + featureTypeList.featureTypes.push(featureType) │ │ │ │ + }, │ │ │ │ + Name: function(node, obj) { │ │ │ │ + var name = this.getChildValue(node); │ │ │ │ + if (name) { │ │ │ │ + var parts = name.split(":"); │ │ │ │ + obj.name = parts.pop(); │ │ │ │ + if (parts.length > 0) { │ │ │ │ + obj.featureNS = this.lookupNamespaceURI(node, parts[0]) │ │ │ │ } │ │ │ │ - }); │ │ │ │ - this.writeNode("GeocodeRequest", request.addresses, node); │ │ │ │ - return node │ │ │ │ + } │ │ │ │ }, │ │ │ │ - GeocodeRequest: function(addresses) { │ │ │ │ - var node = this.createElementNSPlus("xls:GeocodeRequest"); │ │ │ │ - for (var i = 0, len = addresses.length; i < len; i++) { │ │ │ │ - this.writeNode("Address", addresses[i], node) │ │ │ │ + Title: function(node, obj) { │ │ │ │ + var title = this.getChildValue(node); │ │ │ │ + if (title) { │ │ │ │ + obj.title = title │ │ │ │ } │ │ │ │ - return node │ │ │ │ }, │ │ │ │ - Address: function(address) { │ │ │ │ - var node = this.createElementNSPlus("xls:Address", { │ │ │ │ - attributes: { │ │ │ │ - countryCode: address.countryCode │ │ │ │ - } │ │ │ │ - }); │ │ │ │ - if (address.freeFormAddress) { │ │ │ │ - this.writeNode("freeFormAddress", address.freeFormAddress, node) │ │ │ │ - } else { │ │ │ │ - if (address.street) { │ │ │ │ - this.writeNode("StreetAddress", address, node) │ │ │ │ - } │ │ │ │ - if (address.municipality) { │ │ │ │ - this.writeNode("Municipality", address.municipality, node) │ │ │ │ - } │ │ │ │ - if (address.countrySubdivision) { │ │ │ │ - this.writeNode("CountrySubdivision", address.countrySubdivision, node) │ │ │ │ - } │ │ │ │ - if (address.postalCode) { │ │ │ │ - this.writeNode("PostalCode", address.postalCode, node) │ │ │ │ - } │ │ │ │ + Abstract: function(node, obj) { │ │ │ │ + var abst = this.getChildValue(node); │ │ │ │ + if (abst) { │ │ │ │ + obj["abstract"] = abst │ │ │ │ } │ │ │ │ - return node │ │ │ │ + } │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WFSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ + readers: { │ │ │ │ + wfs: OpenLayers.Util.applyDefaults({ │ │ │ │ + Service: function(node, capabilities) { │ │ │ │ + capabilities.service = {}; │ │ │ │ + this.readChildNodes(node, capabilities.service) │ │ │ │ }, │ │ │ │ - freeFormAddress: function(freeFormAddress) { │ │ │ │ - return this.createElementNSPlus("freeFormAddress", { │ │ │ │ - value: freeFormAddress │ │ │ │ - }) │ │ │ │ + Fees: function(node, service) { │ │ │ │ + var fees = this.getChildValue(node); │ │ │ │ + if (fees && fees.toLowerCase() != "none") { │ │ │ │ + service.fees = fees │ │ │ │ + } │ │ │ │ }, │ │ │ │ - StreetAddress: function(address) { │ │ │ │ - var node = this.createElementNSPlus("xls:StreetAddress"); │ │ │ │ - if (address.building) { │ │ │ │ - this.writeNode(node, "Building", address.building) │ │ │ │ + AccessConstraints: function(node, service) { │ │ │ │ + var constraints = this.getChildValue(node); │ │ │ │ + if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ + service.accessConstraints = constraints │ │ │ │ } │ │ │ │ - var street = address.street; │ │ │ │ - if (!OpenLayers.Util.isArray(street)) { │ │ │ │ - street = [street] │ │ │ │ + }, │ │ │ │ + OnlineResource: function(node, service) { │ │ │ │ + var onlineResource = this.getChildValue(node); │ │ │ │ + if (onlineResource && onlineResource.toLowerCase() != "none") { │ │ │ │ + service.onlineResource = onlineResource │ │ │ │ } │ │ │ │ - for (var i = 0, len = street.length; i < len; i++) { │ │ │ │ - this.writeNode("Street", street[i], node) │ │ │ │ + }, │ │ │ │ + Keywords: function(node, service) { │ │ │ │ + var keywords = this.getChildValue(node); │ │ │ │ + if (keywords && keywords.toLowerCase() != "none") { │ │ │ │ + service.keywords = keywords.split(", ") │ │ │ │ } │ │ │ │ - return node │ │ │ │ }, │ │ │ │ - Building: function(building) { │ │ │ │ - return this.createElementNSPlus("xls:Building", { │ │ │ │ - attributes: { │ │ │ │ - number: building["number"], │ │ │ │ - subdivision: building.subdivision, │ │ │ │ - buildingName: building.buildingName │ │ │ │ + Capability: function(node, capabilities) { │ │ │ │ + capabilities.capability = {}; │ │ │ │ + this.readChildNodes(node, capabilities.capability) │ │ │ │ + }, │ │ │ │ + Request: function(node, obj) { │ │ │ │ + obj.request = {}; │ │ │ │ + this.readChildNodes(node, obj.request) │ │ │ │ + }, │ │ │ │ + GetFeature: function(node, request) { │ │ │ │ + request.getfeature = { │ │ │ │ + href: {}, │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, request.getfeature) │ │ │ │ + }, │ │ │ │ + ResultFormat: function(node, obj) { │ │ │ │ + var children = node.childNodes; │ │ │ │ + var childNode; │ │ │ │ + for (var i = 0; i < children.length; i++) { │ │ │ │ + childNode = children[i]; │ │ │ │ + if (childNode.nodeType == 1) { │ │ │ │ + obj.formats.push(childNode.nodeName) │ │ │ │ } │ │ │ │ - }) │ │ │ │ + } │ │ │ │ }, │ │ │ │ - Street: function(street) { │ │ │ │ - return this.createElementNSPlus("xls:Street", { │ │ │ │ - value: street │ │ │ │ - }) │ │ │ │ + DCPType: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ }, │ │ │ │ - Municipality: function(municipality) { │ │ │ │ - return this.createElementNSPlus("xls:Place", { │ │ │ │ - attributes: { │ │ │ │ - type: "Municipality" │ │ │ │ - }, │ │ │ │ - value: municipality │ │ │ │ - }) │ │ │ │ + HTTP: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj.href) │ │ │ │ }, │ │ │ │ - CountrySubdivision: function(countrySubdivision) { │ │ │ │ - return this.createElementNSPlus("xls:Place", { │ │ │ │ - attributes: { │ │ │ │ - type: "CountrySubdivision" │ │ │ │ - }, │ │ │ │ - value: countrySubdivision │ │ │ │ - }) │ │ │ │ + Get: function(node, obj) { │ │ │ │ + obj.get = node.getAttribute("onlineResource") │ │ │ │ }, │ │ │ │ - PostalCode: function(postalCode) { │ │ │ │ - return this.createElementNSPlus("xls:PostalCode", { │ │ │ │ - value: postalCode │ │ │ │ - }) │ │ │ │ + Post: function(node, obj) { │ │ │ │ + obj.post = node.getAttribute("onlineResource") │ │ │ │ + }, │ │ │ │ + SRS: function(node, obj) { │ │ │ │ + var srs = this.getChildValue(node); │ │ │ │ + if (srs) { │ │ │ │ + obj.srs = srs │ │ │ │ + } │ │ │ │ } │ │ │ │ - } │ │ │ │ + }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Format.XLS.v1" │ │ │ │ -}); │ │ │ │ -OpenLayers.Format.XLS.v1_1_0 = OpenLayers.Class(OpenLayers.Format.XLS.v1, { │ │ │ │ - VERSION: "1.1", │ │ │ │ - schemaLocation: "http://www.opengis.net/xls http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd", │ │ │ │ - CLASS_NAME: "OpenLayers.Format.XLS.v1_1_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_0_0" │ │ │ │ }); │ │ │ │ -OpenLayers.Format.XLS.v1_1 = OpenLayers.Format.XLS.v1_1_0; │ │ │ │ -OpenLayers.Tile.Image.IFrame = { │ │ │ │ - useIFrame: null, │ │ │ │ - blankImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7", │ │ │ │ - draw: function() { │ │ │ │ - var draw = OpenLayers.Tile.Image.prototype.shouldDraw.call(this); │ │ │ │ - if (draw) { │ │ │ │ - var url = this.layer.getURL(this.bounds); │ │ │ │ - var usedIFrame = this.useIFrame; │ │ │ │ - this.useIFrame = this.maxGetUrlLength !== null && !this.layer.async && url.length > this.maxGetUrlLength; │ │ │ │ - var fromIFrame = usedIFrame && !this.useIFrame; │ │ │ │ - var toIFrame = !usedIFrame && this.useIFrame; │ │ │ │ - if (fromIFrame || toIFrame) { │ │ │ │ - if (this.imgDiv && this.imgDiv.parentNode === this.frame) { │ │ │ │ - this.frame.removeChild(this.imgDiv) │ │ │ │ - } │ │ │ │ - this.imgDiv = null; │ │ │ │ - if (fromIFrame) { │ │ │ │ - this.frame.removeChild(this.frame.firstChild) │ │ │ │ +OpenLayers.Format.WFSCapabilities.v1_1_0 = OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1, { │ │ │ │ + regExes: { │ │ │ │ + trimSpace: /^\s*|\s*$/g, │ │ │ │ + removeSpace: /\s*/g, │ │ │ │ + splitSpace: /\s+/, │ │ │ │ + trimComma: /\s*,\s*/g │ │ │ │ + }, │ │ │ │ + readers: { │ │ │ │ + wfs: OpenLayers.Util.applyDefaults({ │ │ │ │ + DefaultSRS: function(node, obj) { │ │ │ │ + var defaultSRS = this.getChildValue(node); │ │ │ │ + if (defaultSRS) { │ │ │ │ + obj.srs = defaultSRS │ │ │ │ } │ │ │ │ } │ │ │ │ - } │ │ │ │ - return OpenLayers.Tile.Image.prototype.draw.apply(this, arguments) │ │ │ │ + }, OpenLayers.Format.WFSCapabilities.v1.prototype.readers["wfs"]), │ │ │ │ + ows: OpenLayers.Format.OWSCommon.v1.prototype.readers.ows │ │ │ │ }, │ │ │ │ - getImage: function() { │ │ │ │ - if (this.useIFrame === true) { │ │ │ │ - if (!this.frame.childNodes.length) { │ │ │ │ - var eventPane = document.createElement("div"), │ │ │ │ - style = eventPane.style; │ │ │ │ - style.position = "absolute"; │ │ │ │ - style.width = "100%"; │ │ │ │ - style.height = "100%"; │ │ │ │ - style.zIndex = 1; │ │ │ │ - style.backgroundImage = "url(" + this.blankImageUrl + ")"; │ │ │ │ - this.frame.appendChild(eventPane) │ │ │ │ - } │ │ │ │ - var id = this.id + "_iFrame", │ │ │ │ - iframe; │ │ │ │ - if (parseFloat(navigator.appVersion.split("MSIE")[1]) < 9) { │ │ │ │ - iframe = document.createElement('<iframe name="' + id + '">'); │ │ │ │ - iframe.style.backgroundColor = "#FFFFFF"; │ │ │ │ - iframe.style.filter = "chroma(color=#FFFFFF)" │ │ │ │ - } else { │ │ │ │ - iframe = document.createElement("iframe"); │ │ │ │ - iframe.style.backgroundColor = "transparent"; │ │ │ │ - iframe.name = id │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_1_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.SLD.v1_0_0_GeoServer = OpenLayers.Class(OpenLayers.Format.SLD.v1_0_0, { │ │ │ │ + version: "1.0.0", │ │ │ │ + profile: "GeoServer", │ │ │ │ + readers: OpenLayers.Util.applyDefaults({ │ │ │ │ + sld: OpenLayers.Util.applyDefaults({ │ │ │ │ + Priority: function(node, obj) { │ │ │ │ + var value = this.readers.ogc._expression.call(this, node); │ │ │ │ + if (value) { │ │ │ │ + obj.priority = value │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + VendorOption: function(node, obj) { │ │ │ │ + if (!obj.vendorOptions) { │ │ │ │ + obj.vendorOptions = {} │ │ │ │ + } │ │ │ │ + obj.vendorOptions[node.getAttribute("name")] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + TextSymbolizer: function(node, rule) { │ │ │ │ + OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld.TextSymbolizer.apply(this, arguments); │ │ │ │ + var symbolizer = this.multipleSymbolizers ? rule.symbolizers[rule.symbolizers.length - 1] : rule.symbolizer["Text"]; │ │ │ │ + if (symbolizer.graphic === undefined) { │ │ │ │ + symbolizer.graphic = false │ │ │ │ + } │ │ │ │ } │ │ │ │ - iframe.scrolling = "no"; │ │ │ │ - iframe.marginWidth = "0px"; │ │ │ │ - iframe.marginHeight = "0px"; │ │ │ │ - iframe.frameBorder = "0"; │ │ │ │ - iframe.style.position = "absolute"; │ │ │ │ - iframe.style.width = "100%"; │ │ │ │ - iframe.style.height = "100%"; │ │ │ │ - if (this.layer.opacity < 1) { │ │ │ │ - OpenLayers.Util.modifyDOMElement(iframe, null, null, null, null, null, null, this.layer.opacity) │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.readers["sld"]) │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.readers), │ │ │ │ + writers: OpenLayers.Util.applyDefaults({ │ │ │ │ + sld: OpenLayers.Util.applyDefaults({ │ │ │ │ + Priority: function(priority) { │ │ │ │ + return this.writers.sld._OGCExpression.call(this, "sld:Priority", priority) │ │ │ │ + }, │ │ │ │ + VendorOption: function(option) { │ │ │ │ + return this.createElementNSPlus("sld:VendorOption", { │ │ │ │ + attributes: { │ │ │ │ + name: option.name │ │ │ │ + }, │ │ │ │ + value: option.value │ │ │ │ + }) │ │ │ │ + }, │ │ │ │ + TextSymbolizer: function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["TextSymbolizer"].apply(this, arguments); │ │ │ │ + if (symbolizer.graphic !== false && (symbolizer.externalGraphic || symbolizer.graphicName)) { │ │ │ │ + this.writeNode("Graphic", symbolizer, node) │ │ │ │ + } │ │ │ │ + if ("priority" in symbolizer) { │ │ │ │ + this.writeNode("Priority", symbolizer.priority, node) │ │ │ │ + } │ │ │ │ + return this.addVendorOptions(node, symbolizer) │ │ │ │ + }, │ │ │ │ + PointSymbolizer: function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["PointSymbolizer"].apply(this, arguments); │ │ │ │ + return this.addVendorOptions(node, symbolizer) │ │ │ │ + }, │ │ │ │ + LineSymbolizer: function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["LineSymbolizer"].apply(this, arguments); │ │ │ │ + return this.addVendorOptions(node, symbolizer) │ │ │ │ + }, │ │ │ │ + PolygonSymbolizer: function(symbolizer) { │ │ │ │ + var writers = OpenLayers.Format.SLD.v1_0_0.prototype.writers; │ │ │ │ + var node = writers["sld"]["PolygonSymbolizer"].apply(this, arguments); │ │ │ │ + return this.addVendorOptions(node, symbolizer) │ │ │ │ } │ │ │ │ - this.frame.appendChild(iframe); │ │ │ │ - this.imgDiv = iframe; │ │ │ │ - return iframe │ │ │ │ - } else { │ │ │ │ - return OpenLayers.Tile.Image.prototype.getImage.apply(this, arguments) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - createRequestForm: function() { │ │ │ │ - var form = document.createElement("form"); │ │ │ │ - form.method = "POST"; │ │ │ │ - var cacheId = this.layer.params["_OLSALT"]; │ │ │ │ - cacheId = (cacheId ? cacheId + "_" : "") + this.bounds.toBBOX(); │ │ │ │ - form.action = OpenLayers.Util.urlAppend(this.layer.url, cacheId); │ │ │ │ - form.target = this.id + "_iFrame"; │ │ │ │ - var imageSize = this.layer.getImageSize(), │ │ │ │ - params = OpenLayers.Util.getParameters(this.url), │ │ │ │ - field; │ │ │ │ - for (var par in params) { │ │ │ │ - field = document.createElement("input"); │ │ │ │ - field.type = "hidden"; │ │ │ │ - field.name = par; │ │ │ │ - field.value = params[par]; │ │ │ │ - form.appendChild(field) │ │ │ │ - } │ │ │ │ - return form │ │ │ │ - }, │ │ │ │ - setImgSrc: function(url) { │ │ │ │ - if (this.useIFrame === true) { │ │ │ │ - if (url) { │ │ │ │ - var form = this.createRequestForm(); │ │ │ │ - this.frame.appendChild(form); │ │ │ │ - form.submit(); │ │ │ │ - this.frame.removeChild(form) │ │ │ │ - } else if (this.imgDiv.parentNode === this.frame) { │ │ │ │ - this.frame.removeChild(this.imgDiv); │ │ │ │ - this.imgDiv = null │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.writers["sld"]) │ │ │ │ + }, OpenLayers.Format.SLD.v1_0_0.prototype.writers), │ │ │ │ + addVendorOptions: function(node, symbolizer) { │ │ │ │ + var options = symbolizer.vendorOptions; │ │ │ │ + if (options) { │ │ │ │ + for (var key in symbolizer.vendorOptions) { │ │ │ │ + this.writeNode("VendorOption", { │ │ │ │ + name: key, │ │ │ │ + value: symbolizer.vendorOptions[key] │ │ │ │ + }, node) │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - OpenLayers.Tile.Image.prototype.setImgSrc.apply(this, arguments) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - onImageLoad: function() { │ │ │ │ - OpenLayers.Tile.Image.prototype.onImageLoad.apply(this, arguments); │ │ │ │ - if (this.useIFrame === true) { │ │ │ │ - this.imgDiv.style.opacity = 1; │ │ │ │ - this.frame.style.opacity = this.layer.opacity │ │ │ │ } │ │ │ │ + return node │ │ │ │ }, │ │ │ │ - createBackBuffer: function() { │ │ │ │ - var backBuffer; │ │ │ │ - if (this.useIFrame === false) { │ │ │ │ - backBuffer = OpenLayers.Tile.Image.prototype.createBackBuffer.call(this) │ │ │ │ - } │ │ │ │ - return backBuffer │ │ │ │ - } │ │ │ │ -}; │ │ │ │ -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) │ │ │ │ -}; │ │ │ │ -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)) │ │ │ │ -}; │ │ │ │ -OpenLayers.Protocol.WFS.DEFAULTS = { │ │ │ │ - version: "1.0.0" │ │ │ │ -}; │ │ │ │ -OpenLayers.Protocol.Script = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - url: null, │ │ │ │ - params: null, │ │ │ │ - callback: null, │ │ │ │ - callbackTemplate: "OpenLayers.Protocol.Script.registry.${id}", │ │ │ │ - callbackKey: "callback", │ │ │ │ - callbackPrefix: "", │ │ │ │ - scope: null, │ │ │ │ - format: null, │ │ │ │ - pendingRequests: null, │ │ │ │ - srsInBBOX: false, │ │ │ │ + CLASS_NAME: "OpenLayers.Format.SLD.v1_0_0_GeoServer" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WMSDescribeLayer.v1_1_1 = OpenLayers.Class(OpenLayers.Format.WMSDescribeLayer, { │ │ │ │ initialize: function(options) { │ │ │ │ - options = options || {}; │ │ │ │ - this.params = {}; │ │ │ │ - this.pendingRequests = {}; │ │ │ │ - OpenLayers.Protocol.prototype.initialize.apply(this, arguments); │ │ │ │ - if (!this.format) { │ │ │ │ - this.format = new OpenLayers.Format.GeoJSON │ │ │ │ + OpenLayers.Format.WMSDescribeLayer.prototype.initialize.apply(this, [options]) │ │ │ │ + }, │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ } │ │ │ │ - if (!this.filterToParams && OpenLayers.Format.QueryStringFilter) { │ │ │ │ - var format = new OpenLayers.Format.QueryStringFilter({ │ │ │ │ - srsInBBOX: this.srsInBBOX │ │ │ │ - }); │ │ │ │ - this.filterToParams = function(filter, params) { │ │ │ │ - return format.write(filter, params) │ │ │ │ + var root = data.documentElement; │ │ │ │ + var children = root.childNodes; │ │ │ │ + var describelayer = { │ │ │ │ + layerDescriptions: [] │ │ │ │ + }; │ │ │ │ + var childNode, nodeName; │ │ │ │ + for (var i = 0; i < children.length; ++i) { │ │ │ │ + childNode = children[i]; │ │ │ │ + nodeName = childNode.nodeName; │ │ │ │ + if (nodeName == "LayerDescription") { │ │ │ │ + var layerName = childNode.getAttribute("name"); │ │ │ │ + var owsType = ""; │ │ │ │ + var owsURL = ""; │ │ │ │ + var typeName = ""; │ │ │ │ + if (childNode.getAttribute("owsType")) { │ │ │ │ + owsType = childNode.getAttribute("owsType"); │ │ │ │ + owsURL = childNode.getAttribute("owsURL") │ │ │ │ + } else { │ │ │ │ + if (childNode.getAttribute("wfs") != "") { │ │ │ │ + owsType = "WFS"; │ │ │ │ + owsURL = childNode.getAttribute("wfs") │ │ │ │ + } else if (childNode.getAttribute("wcs") != "") { │ │ │ │ + owsType = "WCS"; │ │ │ │ + owsURL = childNode.getAttribute("wcs") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var query = childNode.getElementsByTagName("Query"); │ │ │ │ + if (query.length > 0) { │ │ │ │ + typeName = query[0].getAttribute("typeName"); │ │ │ │ + if (!typeName) { │ │ │ │ + typeName = query[0].getAttribute("typename") │ │ │ │ + } │ │ │ │ + } │ │ │ │ + var layerDescription = { │ │ │ │ + layerName: layerName, │ │ │ │ + owsType: owsType, │ │ │ │ + owsURL: owsURL, │ │ │ │ + typeName: typeName │ │ │ │ + }; │ │ │ │ + describelayer.layerDescriptions.push(layerDescription); │ │ │ │ + describelayer.length = describelayer.layerDescriptions.length; │ │ │ │ + describelayer[describelayer.length - 1] = layerDescription │ │ │ │ + } else if (nodeName == "ServiceException") { │ │ │ │ + var parser = new OpenLayers.Format.OGCExceptionReport; │ │ │ │ + return { │ │ │ │ + error: parser.read(data) │ │ │ │ + } │ │ │ │ } │ │ │ │ } │ │ │ │ + return describelayer │ │ │ │ }, │ │ │ │ - read: function(options) { │ │ │ │ - OpenLayers.Protocol.prototype.read.apply(this, arguments); │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ - options.params = OpenLayers.Util.applyDefaults(options.params, this.options.params); │ │ │ │ - if (options.filter && this.filterToParams) { │ │ │ │ - options.params = this.filterToParams(options.filter, options.params) │ │ │ │ - } │ │ │ │ - var response = new OpenLayers.Protocol.Response({ │ │ │ │ - requestType: "read" │ │ │ │ - }); │ │ │ │ - var request = this.createRequest(options.url, options.params, OpenLayers.Function.bind(function(data) { │ │ │ │ - response.data = data; │ │ │ │ - this.handleRead(response, options) │ │ │ │ - }, this)); │ │ │ │ - response.priv = request; │ │ │ │ - return response │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSDescribeLayer.v1_1_1" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WMSDescribeLayer.v1_1_0 = OpenLayers.Format.WMSDescribeLayer.v1_1_1; │ │ │ │ +OpenLayers.Format.WMTSCapabilities.v1_0_0 = OpenLayers.Class(OpenLayers.Format.OWSCommon.v1_1_0, { │ │ │ │ + version: "1.0.0", │ │ │ │ + namespaces: { │ │ │ │ + ows: "http://www.opengis.net/ows/1.1", │ │ │ │ + wmts: "http://www.opengis.net/wmts/1.0", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink" │ │ │ │ }, │ │ │ │ - createRequest: function(url, params, callback) { │ │ │ │ - var id = OpenLayers.Protocol.Script.register(callback); │ │ │ │ - var name = OpenLayers.String.format(this.callbackTemplate, { │ │ │ │ - id: id │ │ │ │ - }); │ │ │ │ - params = OpenLayers.Util.extend({}, params); │ │ │ │ - params[this.callbackKey] = this.callbackPrefix + name; │ │ │ │ - url = OpenLayers.Util.urlAppend(url, OpenLayers.Util.getParameterString(params)); │ │ │ │ - var script = document.createElement("script"); │ │ │ │ - script.type = "text/javascript"; │ │ │ │ - script.src = url; │ │ │ │ - script.id = "OpenLayers_Protocol_Script_" + id; │ │ │ │ - this.pendingRequests[script.id] = script; │ │ │ │ - var head = document.getElementsByTagName("head")[0]; │ │ │ │ - head.appendChild(script); │ │ │ │ - return script │ │ │ │ + yx: null, │ │ │ │ + defaultPrefix: "wmts", │ │ │ │ + initialize: function(options) { │ │ │ │ + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ + this.options = options; │ │ │ │ + var yx = OpenLayers.Util.extend({}, OpenLayers.Format.WMTSCapabilities.prototype.yx); │ │ │ │ + this.yx = OpenLayers.Util.extend(yx, this.yx) │ │ │ │ }, │ │ │ │ - destroyRequest: function(script) { │ │ │ │ - OpenLayers.Protocol.Script.unregister(script.id.split("_").pop()); │ │ │ │ - delete this.pendingRequests[script.id]; │ │ │ │ - if (script.parentNode) { │ │ │ │ - script.parentNode.removeChild(script) │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ } │ │ │ │ - }, │ │ │ │ - handleRead: function(response, options) { │ │ │ │ - this.handleResponse(response, options) │ │ │ │ - }, │ │ │ │ - handleResponse: function(response, options) { │ │ │ │ - if (options.callback) { │ │ │ │ - if (response.data) { │ │ │ │ - response.features = this.parseFeatures(response.data); │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ - } else { │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ - } │ │ │ │ - this.destroyRequest(response.priv); │ │ │ │ - options.callback.call(options.scope, response) │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement │ │ │ │ } │ │ │ │ + var capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + capabilities.version = this.version; │ │ │ │ + return capabilities │ │ │ │ }, │ │ │ │ - parseFeatures: function(data) { │ │ │ │ - return this.format.read(data) │ │ │ │ - }, │ │ │ │ - abort: function(response) { │ │ │ │ - if (response) { │ │ │ │ - this.destroyRequest(response.priv) │ │ │ │ - } else { │ │ │ │ - for (var key in this.pendingRequests) { │ │ │ │ - this.destroyRequest(this.pendingRequests[key]) │ │ │ │ + readers: { │ │ │ │ + wmts: { │ │ │ │ + Capabilities: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + Contents: function(node, obj) { │ │ │ │ + obj.contents = {}; │ │ │ │ + obj.contents.layers = []; │ │ │ │ + obj.contents.tileMatrixSets = {}; │ │ │ │ + this.readChildNodes(node, obj.contents) │ │ │ │ + }, │ │ │ │ + Layer: function(node, obj) { │ │ │ │ + var layer = { │ │ │ │ + styles: [], │ │ │ │ + formats: [], │ │ │ │ + dimensions: [], │ │ │ │ + tileMatrixSetLinks: [] │ │ │ │ + }; │ │ │ │ + layer.layers = []; │ │ │ │ + this.readChildNodes(node, layer); │ │ │ │ + obj.layers.push(layer) │ │ │ │ + }, │ │ │ │ + Style: function(node, obj) { │ │ │ │ + var style = {}; │ │ │ │ + style.isDefault = node.getAttribute("isDefault") === "true"; │ │ │ │ + this.readChildNodes(node, style); │ │ │ │ + obj.styles.push(style) │ │ │ │ + }, │ │ │ │ + Format: function(node, obj) { │ │ │ │ + obj.formats.push(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + TileMatrixSetLink: function(node, obj) { │ │ │ │ + var tileMatrixSetLink = {}; │ │ │ │ + this.readChildNodes(node, tileMatrixSetLink); │ │ │ │ + obj.tileMatrixSetLinks.push(tileMatrixSetLink) │ │ │ │ + }, │ │ │ │ + TileMatrixSet: function(node, obj) { │ │ │ │ + if (obj.layers) { │ │ │ │ + var tileMatrixSet = { │ │ │ │ + matrixIds: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, tileMatrixSet); │ │ │ │ + obj.tileMatrixSets[tileMatrixSet.identifier] = tileMatrixSet │ │ │ │ + } else { │ │ │ │ + obj.tileMatrixSet = this.getChildValue(node) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + TileMatrix: function(node, obj) { │ │ │ │ + var tileMatrix = { │ │ │ │ + supportedCRS: obj.supportedCRS │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, tileMatrix); │ │ │ │ + obj.matrixIds.push(tileMatrix) │ │ │ │ + }, │ │ │ │ + ScaleDenominator: function(node, obj) { │ │ │ │ + obj.scaleDenominator = parseFloat(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + TopLeftCorner: function(node, obj) { │ │ │ │ + var topLeftCorner = this.getChildValue(node); │ │ │ │ + var coords = topLeftCorner.split(" "); │ │ │ │ + var yx; │ │ │ │ + if (obj.supportedCRS) { │ │ │ │ + var crs = obj.supportedCRS.replace(/urn:ogc:def:crs:(\w+):.+:(\w+)$/, "urn:ogc:def:crs:$1::$2"); │ │ │ │ + yx = !!this.yx[crs] │ │ │ │ + } │ │ │ │ + if (yx) { │ │ │ │ + obj.topLeftCorner = new OpenLayers.LonLat(coords[1], coords[0]) │ │ │ │ + } else { │ │ │ │ + obj.topLeftCorner = new OpenLayers.LonLat(coords[0], coords[1]) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + TileWidth: function(node, obj) { │ │ │ │ + obj.tileWidth = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + TileHeight: function(node, obj) { │ │ │ │ + obj.tileHeight = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + MatrixWidth: function(node, obj) { │ │ │ │ + obj.matrixWidth = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + MatrixHeight: function(node, obj) { │ │ │ │ + obj.matrixHeight = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + ResourceURL: function(node, obj) { │ │ │ │ + obj.resourceUrl = obj.resourceUrl || {}; │ │ │ │ + var resourceType = node.getAttribute("resourceType"); │ │ │ │ + if (!obj.resourceUrls) { │ │ │ │ + obj.resourceUrls = [] │ │ │ │ + } │ │ │ │ + var resourceUrl = obj.resourceUrl[resourceType] = { │ │ │ │ + format: node.getAttribute("format"), │ │ │ │ + template: node.getAttribute("template"), │ │ │ │ + resourceType: resourceType │ │ │ │ + }; │ │ │ │ + obj.resourceUrls.push(resourceUrl) │ │ │ │ + }, │ │ │ │ + WSDL: function(node, obj) { │ │ │ │ + obj.wsdl = {}; │ │ │ │ + obj.wsdl.href = node.getAttribute("xlink:href") │ │ │ │ + }, │ │ │ │ + ServiceMetadataURL: function(node, obj) { │ │ │ │ + obj.serviceMetadataUrl = {}; │ │ │ │ + obj.serviceMetadataUrl.href = node.getAttribute("xlink:href") │ │ │ │ + }, │ │ │ │ + LegendURL: function(node, obj) { │ │ │ │ + obj.legend = {}; │ │ │ │ + obj.legend.href = node.getAttribute("xlink:href"); │ │ │ │ + obj.legend.format = node.getAttribute("format") │ │ │ │ + }, │ │ │ │ + Dimension: function(node, obj) { │ │ │ │ + var dimension = { │ │ │ │ + values: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, dimension); │ │ │ │ + obj.dimensions.push(dimension) │ │ │ │ + }, │ │ │ │ + Default: function(node, obj) { │ │ │ │ + obj["default"] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + Value: function(node, obj) { │ │ │ │ + obj.values.push(this.getChildValue(node)) │ │ │ │ } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.abort(); │ │ │ │ - delete this.params; │ │ │ │ - delete this.format; │ │ │ │ - OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ + }, │ │ │ │ + ows: OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.Script" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMTSCapabilities.v1_0_0" │ │ │ │ }); │ │ │ │ -(function() { │ │ │ │ - var o = OpenLayers.Protocol.Script; │ │ │ │ - var counter = 0; │ │ │ │ - o.registry = {}; │ │ │ │ - o.register = function(callback) { │ │ │ │ - var id = "c" + ++counter; │ │ │ │ - o.registry[id] = function() { │ │ │ │ - callback.apply(this, arguments) │ │ │ │ - }; │ │ │ │ - return id │ │ │ │ - }; │ │ │ │ - o.unregister = function(id) { │ │ │ │ - delete o.registry[id] │ │ │ │ - } │ │ │ │ -})(); │ │ │ │ -OpenLayers.Protocol.CSW = function(options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, OpenLayers.Protocol.CSW.DEFAULTS); │ │ │ │ - var cls = OpenLayers.Protocol.CSW["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (!cls) { │ │ │ │ - throw "Unsupported CSW version: " + options.version │ │ │ │ - } │ │ │ │ - return new cls(options) │ │ │ │ -}; │ │ │ │ -OpenLayers.Protocol.CSW.DEFAULTS = { │ │ │ │ - version: "2.0.2" │ │ │ │ -}; │ │ │ │ -OpenLayers.Protocol.SOS = function(options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, OpenLayers.Protocol.SOS.DEFAULTS); │ │ │ │ - var cls = OpenLayers.Protocol.SOS["v" + options.version.replace(/\./g, "_")]; │ │ │ │ - if (!cls) { │ │ │ │ - throw "Unsupported SOS version: " + options.version │ │ │ │ - } │ │ │ │ - return new cls(options) │ │ │ │ -}; │ │ │ │ -OpenLayers.Protocol.SOS.DEFAULTS = { │ │ │ │ - version: "1.0.0" │ │ │ │ -}; │ │ │ │ -OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - url: null, │ │ │ │ - headers: null, │ │ │ │ - params: null, │ │ │ │ - callback: null, │ │ │ │ - scope: null, │ │ │ │ - readWithPOST: false, │ │ │ │ - updateWithPOST: false, │ │ │ │ - deleteWithPOST: false, │ │ │ │ - wildcarded: false, │ │ │ │ - srsInBBOX: false, │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - this.params = null; │ │ │ │ - this.headers = null; │ │ │ │ - OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1 = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + namespaces: { │ │ │ │ + wms: "http://www.opengis.net/wms", │ │ │ │ + xlink: "http://www.w3.org/1999/xlink", │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ }, │ │ │ │ - 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) │ │ │ │ + defaultPrefix: "wms", │ │ │ │ + read: function(data) { │ │ │ │ + if (typeof data == "string") { │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]) │ │ │ │ } │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ + var raw = data; │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ + data = data.documentElement │ │ │ │ } │ │ │ │ - return resp │ │ │ │ - }, │ │ │ │ - handleRead: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - handleCreate: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - handleUpdate: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options) │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ + var capabilities = {}; │ │ │ │ + this.readNode(data, capabilities); │ │ │ │ + if (capabilities.service === undefined) { │ │ │ │ + var parser = new OpenLayers.Format.OGCExceptionReport; │ │ │ │ + capabilities.error = parser.read(raw) │ │ │ │ } │ │ │ │ - resp.priv = OpenLayers.Request[method](requestOptions); │ │ │ │ - return resp │ │ │ │ - }, │ │ │ │ - handleDelete: function(resp, options) { │ │ │ │ - this.handleResponse(resp, options) │ │ │ │ + return capabilities │ │ │ │ }, │ │ │ │ - handleResponse: function(resp, options) { │ │ │ │ - var request = resp.priv; │ │ │ │ - if (options.callback) { │ │ │ │ - if (request.status >= 200 && request.status < 300) { │ │ │ │ - if (resp.requestType != "delete") { │ │ │ │ - resp.features = this.parseFeatures(request) │ │ │ │ + readers: { │ │ │ │ + wms: { │ │ │ │ + Service: function(node, obj) { │ │ │ │ + obj.service = {}; │ │ │ │ + this.readChildNodes(node, obj.service) │ │ │ │ + }, │ │ │ │ + Name: function(node, obj) { │ │ │ │ + obj.name = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + Title: function(node, obj) { │ │ │ │ + obj.title = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + Abstract: function(node, obj) { │ │ │ │ + obj["abstract"] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + BoundingBox: function(node, obj) { │ │ │ │ + var bbox = {}; │ │ │ │ + bbox.bbox = [parseFloat(node.getAttribute("minx")), parseFloat(node.getAttribute("miny")), parseFloat(node.getAttribute("maxx")), parseFloat(node.getAttribute("maxy"))]; │ │ │ │ + var res = { │ │ │ │ + x: parseFloat(node.getAttribute("resx")), │ │ │ │ + y: parseFloat(node.getAttribute("resy")) │ │ │ │ + }; │ │ │ │ + if (!(isNaN(res.x) && isNaN(res.y))) { │ │ │ │ + bbox.res = res │ │ │ │ } │ │ │ │ - resp.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ - } else { │ │ │ │ - resp.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ - } │ │ │ │ - options.callback.call(options.scope, resp) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ - }, │ │ │ │ - commit: function(features, options) { │ │ │ │ - options = OpenLayers.Util.applyDefaults(options, this.options); │ │ │ │ - var resp = [], │ │ │ │ - nResponses = 0; │ │ │ │ - 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) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - var nRequests = (types[OpenLayers.State.INSERT].length > 0 ? 1 : 0) + types[OpenLayers.State.UPDATE].length + types[OpenLayers.State.DELETE].length; │ │ │ │ - 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]) │ │ │ │ + return bbox │ │ │ │ + }, │ │ │ │ + OnlineResource: function(node, obj) { │ │ │ │ + obj.href = this.getAttributeNS(node, this.namespaces.xlink, "href") │ │ │ │ + }, │ │ │ │ + ContactInformation: function(node, obj) { │ │ │ │ + obj.contactInformation = {}; │ │ │ │ + this.readChildNodes(node, obj.contactInformation) │ │ │ │ + }, │ │ │ │ + ContactPersonPrimary: function(node, obj) { │ │ │ │ + obj.personPrimary = {}; │ │ │ │ + this.readChildNodes(node, obj.personPrimary) │ │ │ │ + }, │ │ │ │ + ContactPerson: function(node, obj) { │ │ │ │ + obj.person = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + ContactOrganization: function(node, obj) { │ │ │ │ + obj.organization = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + ContactPosition: function(node, obj) { │ │ │ │ + obj.position = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + ContactAddress: function(node, obj) { │ │ │ │ + obj.contactAddress = {}; │ │ │ │ + this.readChildNodes(node, obj.contactAddress) │ │ │ │ + }, │ │ │ │ + AddressType: function(node, obj) { │ │ │ │ + obj.type = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + Address: function(node, obj) { │ │ │ │ + obj.address = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + City: function(node, obj) { │ │ │ │ + obj.city = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + StateOrProvince: function(node, obj) { │ │ │ │ + obj.stateOrProvince = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + PostCode: function(node, obj) { │ │ │ │ + obj.postcode = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + Country: function(node, obj) { │ │ │ │ + obj.country = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + ContactVoiceTelephone: function(node, obj) { │ │ │ │ + obj.phone = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + ContactFacsimileTelephone: function(node, obj) { │ │ │ │ + obj.fax = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + ContactElectronicMailAddress: function(node, obj) { │ │ │ │ + obj.email = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + Fees: function(node, obj) { │ │ │ │ + var fees = this.getChildValue(node); │ │ │ │ + if (fees && fees.toLowerCase() != "none") { │ │ │ │ + obj.fees = fees │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + AccessConstraints: function(node, obj) { │ │ │ │ + var constraints = this.getChildValue(node); │ │ │ │ + if (constraints && constraints.toLowerCase() != "none") { │ │ │ │ + obj.accessConstraints = constraints │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + Capability: function(node, obj) { │ │ │ │ + obj.capability = { │ │ │ │ + nestedLayers: [], │ │ │ │ + layers: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.capability) │ │ │ │ + }, │ │ │ │ + Request: function(node, obj) { │ │ │ │ + obj.request = {}; │ │ │ │ + this.readChildNodes(node, obj.request) │ │ │ │ + }, │ │ │ │ + GetCapabilities: function(node, obj) { │ │ │ │ + obj.getcapabilities = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getcapabilities) │ │ │ │ + }, │ │ │ │ + Format: function(node, obj) { │ │ │ │ + if (OpenLayers.Util.isArray(obj.formats)) { │ │ │ │ + obj.formats.push(this.getChildValue(node)) │ │ │ │ + } else { │ │ │ │ + obj.format = this.getChildValue(node) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + DCPType: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + HTTP: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + Get: function(node, obj) { │ │ │ │ + obj.get = {}; │ │ │ │ + this.readChildNodes(node, obj.get); │ │ │ │ + if (!obj.href) { │ │ │ │ + obj.href = obj.get.href │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + Post: function(node, obj) { │ │ │ │ + obj.post = {}; │ │ │ │ + this.readChildNodes(node, obj.post); │ │ │ │ + if (!obj.href) { │ │ │ │ + obj.href = obj.get.href │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + GetMap: function(node, obj) { │ │ │ │ + obj.getmap = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getmap) │ │ │ │ + }, │ │ │ │ + GetFeatureInfo: function(node, obj) { │ │ │ │ + obj.getfeatureinfo = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getfeatureinfo) │ │ │ │ + }, │ │ │ │ + Exception: function(node, obj) { │ │ │ │ + obj.exception = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.exception) │ │ │ │ + }, │ │ │ │ + Layer: function(node, obj) { │ │ │ │ + var parentLayer, capability; │ │ │ │ + if (obj.capability) { │ │ │ │ + capability = obj.capability; │ │ │ │ + parentLayer = obj │ │ │ │ + } else { │ │ │ │ + capability = obj │ │ │ │ + } │ │ │ │ + var attrNode = node.getAttributeNode("queryable"); │ │ │ │ + var queryable = attrNode && attrNode.specified ? node.getAttribute("queryable") : null; │ │ │ │ + attrNode = node.getAttributeNode("cascaded"); │ │ │ │ + var cascaded = attrNode && attrNode.specified ? node.getAttribute("cascaded") : null; │ │ │ │ + attrNode = node.getAttributeNode("opaque"); │ │ │ │ + var opaque = attrNode && attrNode.specified ? node.getAttribute("opaque") : null; │ │ │ │ + var noSubsets = node.getAttribute("noSubsets"); │ │ │ │ + var fixedWidth = node.getAttribute("fixedWidth"); │ │ │ │ + var fixedHeight = node.getAttribute("fixedHeight"); │ │ │ │ + var parent = parentLayer || {}, │ │ │ │ + extend = OpenLayers.Util.extend; │ │ │ │ + var layer = { │ │ │ │ + nestedLayers: [], │ │ │ │ + styles: parentLayer ? [].concat(parentLayer.styles) : [], │ │ │ │ + srs: parentLayer ? extend({}, parent.srs) : {}, │ │ │ │ + metadataURLs: [], │ │ │ │ + bbox: parentLayer ? extend({}, parent.bbox) : {}, │ │ │ │ + llbbox: parent.llbbox, │ │ │ │ + dimensions: parentLayer ? extend({}, parent.dimensions) : {}, │ │ │ │ + authorityURLs: parentLayer ? extend({}, parent.authorityURLs) : {}, │ │ │ │ + identifiers: {}, │ │ │ │ + keywords: [], │ │ │ │ + queryable: queryable && queryable !== "" ? queryable === "1" || queryable === "true" : parent.queryable || false, │ │ │ │ + cascaded: cascaded !== null ? parseInt(cascaded) : parent.cascaded || 0, │ │ │ │ + opaque: opaque ? opaque === "1" || opaque === "true" : parent.opaque || false, │ │ │ │ + noSubsets: noSubsets !== null ? noSubsets === "1" || noSubsets === "true" : parent.noSubsets || false, │ │ │ │ + fixedWidth: fixedWidth != null ? parseInt(fixedWidth) : parent.fixedWidth || 0, │ │ │ │ + fixedHeight: fixedHeight != null ? parseInt(fixedHeight) : parent.fixedHeight || 0, │ │ │ │ + minScale: parent.minScale, │ │ │ │ + maxScale: parent.maxScale, │ │ │ │ + attribution: parent.attribution │ │ │ │ + }; │ │ │ │ + obj.nestedLayers.push(layer); │ │ │ │ + layer.capability = capability; │ │ │ │ + this.readChildNodes(node, layer); │ │ │ │ + delete layer.capability; │ │ │ │ + if (layer.name) { │ │ │ │ + var parts = layer.name.split(":"), │ │ │ │ + request = capability.request, │ │ │ │ + gfi = request.getfeatureinfo; │ │ │ │ + if (parts.length > 0) { │ │ │ │ + layer.prefix = parts[0] │ │ │ │ + } │ │ │ │ + capability.layers.push(layer); │ │ │ │ + if (layer.formats === undefined) { │ │ │ │ + layer.formats = request.getmap.formats │ │ │ │ + } │ │ │ │ + if (layer.infoFormats === undefined && gfi) { │ │ │ │ + layer.infoFormats = gfi.formats │ │ │ │ + } │ │ │ │ } │ │ │ │ + }, │ │ │ │ + Attribution: function(node, obj) { │ │ │ │ + obj.attribution = {}; │ │ │ │ + this.readChildNodes(node, obj.attribution) │ │ │ │ + }, │ │ │ │ + LogoURL: function(node, obj) { │ │ │ │ + obj.logo = { │ │ │ │ + width: node.getAttribute("width"), │ │ │ │ + height: node.getAttribute("height") │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.logo) │ │ │ │ + }, │ │ │ │ + Style: function(node, obj) { │ │ │ │ + var style = {}; │ │ │ │ + obj.styles.push(style); │ │ │ │ + this.readChildNodes(node, style) │ │ │ │ + }, │ │ │ │ + LegendURL: function(node, obj) { │ │ │ │ + var legend = { │ │ │ │ + width: node.getAttribute("width"), │ │ │ │ + height: node.getAttribute("height") │ │ │ │ + }; │ │ │ │ + obj.legend = legend; │ │ │ │ + this.readChildNodes(node, legend) │ │ │ │ + }, │ │ │ │ + MetadataURL: function(node, obj) { │ │ │ │ + var metadataURL = { │ │ │ │ + type: node.getAttribute("type") │ │ │ │ + }; │ │ │ │ + obj.metadataURLs.push(metadataURL); │ │ │ │ + this.readChildNodes(node, metadataURL) │ │ │ │ + }, │ │ │ │ + DataURL: function(node, obj) { │ │ │ │ + obj.dataURL = {}; │ │ │ │ + this.readChildNodes(node, obj.dataURL) │ │ │ │ + }, │ │ │ │ + FeatureListURL: function(node, obj) { │ │ │ │ + obj.featureListURL = {}; │ │ │ │ + this.readChildNodes(node, obj.featureListURL) │ │ │ │ + }, │ │ │ │ + AuthorityURL: function(node, obj) { │ │ │ │ + var name = node.getAttribute("name"); │ │ │ │ + var authority = {}; │ │ │ │ + this.readChildNodes(node, authority); │ │ │ │ + obj.authorityURLs[name] = authority.href │ │ │ │ + }, │ │ │ │ + Identifier: function(node, obj) { │ │ │ │ + var authority = node.getAttribute("authority"); │ │ │ │ + obj.identifiers[authority] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + KeywordList: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + SRS: function(node, obj) { │ │ │ │ + obj.srs[this.getChildValue(node)] = true │ │ │ │ } │ │ │ │ } │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - abort: function(response) { │ │ │ │ - if (response) { │ │ │ │ - response.priv.abort() │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - callUserCallback: function(resp, options) { │ │ │ │ - var opt = options[resp.requestType]; │ │ │ │ - if (opt && opt.callback) { │ │ │ │ - opt.callback.call(opt.scope, resp) │ │ │ │ - } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.HTTP" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1" │ │ │ │ }); │ │ │ │ -OpenLayers.Protocol.CSW.v2_0_2 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - formatOptions: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ - if (!options.format) { │ │ │ │ - this.format = new OpenLayers.Format.CSWGetRecords.v2_0_2(OpenLayers.Util.extend({}, this.formatOptions)) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.options && !this.options.format) { │ │ │ │ - this.format.destroy() │ │ │ │ - } │ │ │ │ - this.format = null; │ │ │ │ - OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ - }, │ │ │ │ - read: function(options) { │ │ │ │ - options = OpenLayers.Util.extend({}, options); │ │ │ │ - OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ - var response = new OpenLayers.Protocol.Response({ │ │ │ │ - requestType: "read" │ │ │ │ - }); │ │ │ │ - var data = this.format.write(options.params || 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 │ │ │ │ - }, │ │ │ │ - handleRead: function(response, options) { │ │ │ │ - if (options.callback) { │ │ │ │ - var request = response.priv; │ │ │ │ - if (request.status >= 200 && request.status < 300) { │ │ │ │ - response.data = this.parseData(request); │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ - } else { │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ + readers: { │ │ │ │ + wms: OpenLayers.Util.applyDefaults({ │ │ │ │ + WMT_MS_Capabilities: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + Keyword: function(node, obj) { │ │ │ │ + if (obj.keywords) { │ │ │ │ + obj.keywords.push(this.getChildValue(node)) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + DescribeLayer: function(node, obj) { │ │ │ │ + obj.describelayer = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.describelayer) │ │ │ │ + }, │ │ │ │ + GetLegendGraphic: function(node, obj) { │ │ │ │ + obj.getlegendgraphic = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getlegendgraphic) │ │ │ │ + }, │ │ │ │ + GetStyles: function(node, obj) { │ │ │ │ + obj.getstyles = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.getstyles) │ │ │ │ + }, │ │ │ │ + PutStyles: function(node, obj) { │ │ │ │ + obj.putstyles = { │ │ │ │ + formats: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.putstyles) │ │ │ │ + }, │ │ │ │ + UserDefinedSymbolization: function(node, obj) { │ │ │ │ + var userSymbols = { │ │ │ │ + supportSLD: parseInt(node.getAttribute("SupportSLD")) == 1, │ │ │ │ + userLayer: parseInt(node.getAttribute("UserLayer")) == 1, │ │ │ │ + userStyle: parseInt(node.getAttribute("UserStyle")) == 1, │ │ │ │ + remoteWFS: parseInt(node.getAttribute("RemoteWFS")) == 1 │ │ │ │ + }; │ │ │ │ + obj.userSymbols = userSymbols │ │ │ │ + }, │ │ │ │ + LatLonBoundingBox: function(node, obj) { │ │ │ │ + obj.llbbox = [parseFloat(node.getAttribute("minx")), parseFloat(node.getAttribute("miny")), parseFloat(node.getAttribute("maxx")), parseFloat(node.getAttribute("maxy"))] │ │ │ │ + }, │ │ │ │ + BoundingBox: function(node, obj) { │ │ │ │ + var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ + bbox.srs = node.getAttribute("SRS"); │ │ │ │ + obj.bbox[bbox.srs] = bbox │ │ │ │ + }, │ │ │ │ + ScaleHint: function(node, obj) { │ │ │ │ + var min = node.getAttribute("min"); │ │ │ │ + var max = node.getAttribute("max"); │ │ │ │ + var rad2 = Math.pow(2, .5); │ │ │ │ + var ipm = OpenLayers.INCHES_PER_UNIT["m"]; │ │ │ │ + if (min != 0) { │ │ │ │ + obj.maxScale = parseFloat((min / rad2 * ipm * OpenLayers.DOTS_PER_INCH).toPrecision(13)) │ │ │ │ + } │ │ │ │ + if (max != Number.POSITIVE_INFINITY) { │ │ │ │ + obj.minScale = parseFloat((max / rad2 * ipm * OpenLayers.DOTS_PER_INCH).toPrecision(13)) │ │ │ │ + } │ │ │ │ + }, │ │ │ │ + Dimension: function(node, obj) { │ │ │ │ + var name = node.getAttribute("name").toLowerCase(); │ │ │ │ + var dim = { │ │ │ │ + name: name, │ │ │ │ + units: node.getAttribute("units"), │ │ │ │ + unitsymbol: node.getAttribute("unitSymbol") │ │ │ │ + }; │ │ │ │ + obj.dimensions[dim.name] = dim │ │ │ │ + }, │ │ │ │ + Extent: function(node, obj) { │ │ │ │ + var name = node.getAttribute("name").toLowerCase(); │ │ │ │ + if (name in obj["dimensions"]) { │ │ │ │ + var extent = obj.dimensions[name]; │ │ │ │ + extent.nearestVal = node.getAttribute("nearestValue") === "1"; │ │ │ │ + extent.multipleVal = node.getAttribute("multipleValues") === "1"; │ │ │ │ + extent.current = node.getAttribute("current") === "1"; │ │ │ │ + extent["default"] = node.getAttribute("default") || ""; │ │ │ │ + var values = this.getChildValue(node); │ │ │ │ + extent.values = values.split(",") │ │ │ │ + } │ │ │ │ } │ │ │ │ - options.callback.call(options.scope, response) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - parseData: 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) │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.CSW.v2_0_2" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1" │ │ │ │ }); │ │ │ │ -OpenLayers.Protocol.SOS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - fois: null, │ │ │ │ - formatOptions: null, │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Protocol.prototype.initialize.apply(this, [options]); │ │ │ │ - if (!options.format) { │ │ │ │ - this.format = new OpenLayers.Format.SOSGetFeatureOfInterest(this.formatOptions) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.options && !this.options.format) { │ │ │ │ - this.format.destroy() │ │ │ │ - } │ │ │ │ - this.format = null; │ │ │ │ - OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ - }, │ │ │ │ - read: function(options) { │ │ │ │ - options = OpenLayers.Util.extend({}, options); │ │ │ │ - OpenLayers.Util.applyDefaults(options, this.options || {}); │ │ │ │ - var response = new OpenLayers.Protocol.Response({ │ │ │ │ - requestType: "read" │ │ │ │ - }); │ │ │ │ - var format = this.format; │ │ │ │ - var data = OpenLayers.Format.XML.prototype.write.apply(format, [format.writeNode("sos:GetFeatureOfInterest", { │ │ │ │ - fois: this.fois │ │ │ │ - })]); │ │ │ │ - response.priv = OpenLayers.Request.POST({ │ │ │ │ - url: options.url, │ │ │ │ - callback: this.createCallback(this.handleRead, response, options), │ │ │ │ - data: data │ │ │ │ - }); │ │ │ │ - return response │ │ │ │ - }, │ │ │ │ - handleRead: function(response, options) { │ │ │ │ - if (options.callback) { │ │ │ │ - var request = response.priv; │ │ │ │ - if (request.status >= 200 && request.status < 300) { │ │ │ │ - response.features = this.parseFeatures(request); │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ - } else { │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1_1 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ + version: "1.1.1", │ │ │ │ + readers: { │ │ │ │ + wms: OpenLayers.Util.applyDefaults({ │ │ │ │ + SRS: function(node, obj) { │ │ │ │ + obj.srs[this.getChildValue(node)] = true │ │ │ │ } │ │ │ │ - options.callback.call(options.scope, response) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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) │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.SOS.v1_0_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1" │ │ │ │ }); │ │ │ │ -OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, { │ │ │ │ - version: null, │ │ │ │ - srsName: "EPSG:4326", │ │ │ │ - featureType: null, │ │ │ │ - featureNS: null, │ │ │ │ - geometryName: "the_geom", │ │ │ │ - schema: null, │ │ │ │ - featurePrefix: "feature", │ │ │ │ - formatOptions: null, │ │ │ │ - readFormat: null, │ │ │ │ - readOptions: null, │ │ │ │ - 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) { │ │ │ │ - this.setGeometryName(null) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - destroy: function() { │ │ │ │ - if (this.options && !this.options.format) { │ │ │ │ - this.format.destroy() │ │ │ │ - } │ │ │ │ - this.format = null; │ │ │ │ - OpenLayers.Protocol.prototype.destroy.apply(this) │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - setFeatureType: function(featureType) { │ │ │ │ - this.featureType = featureType; │ │ │ │ - this.format.featureType = featureType │ │ │ │ - }, │ │ │ │ - setGeometryName: function(geometryName) { │ │ │ │ - this.geometryName = geometryName; │ │ │ │ - this.format.geometryName = geometryName │ │ │ │ - }, │ │ │ │ - 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) { │ │ │ │ - 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 │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1_1, { │ │ │ │ + version: "1.1.1", │ │ │ │ + profile: "WMSC", │ │ │ │ + readers: { │ │ │ │ + wms: OpenLayers.Util.applyDefaults({ │ │ │ │ + VendorSpecificCapabilities: function(node, obj) { │ │ │ │ + obj.vendorSpecific = { │ │ │ │ + tileSets: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, obj.vendorSpecific) │ │ │ │ + }, │ │ │ │ + TileSet: function(node, vendorSpecific) { │ │ │ │ + var tileset = { │ │ │ │ + srs: {}, │ │ │ │ + bbox: {}, │ │ │ │ + resolutions: [] │ │ │ │ + }; │ │ │ │ + this.readChildNodes(node, tileset); │ │ │ │ + vendorSpecific.tileSets.push(tileset) │ │ │ │ + }, │ │ │ │ + Resolutions: function(node, tileset) { │ │ │ │ + var res = this.getChildValue(node).split(" "); │ │ │ │ + for (var i = 0, len = res.length; i < len; i++) { │ │ │ │ + if (res[i] != "") { │ │ │ │ + tileset.resolutions.push(parseFloat(res[i])) │ │ │ │ } │ │ │ │ - response.code = OpenLayers.Protocol.Response.SUCCESS │ │ │ │ - } else { │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE; │ │ │ │ - response.error = result │ │ │ │ } │ │ │ │ - } else { │ │ │ │ - response.code = OpenLayers.Protocol.Response.FAILURE │ │ │ │ - } │ │ │ │ - options.callback.call(options.scope, response) │ │ │ │ - } │ │ │ │ - }, │ │ │ │ - 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; │ │ │ │ - format.autoConfig = false; │ │ │ │ - if (!this.geometryName) { │ │ │ │ - this.setGeometryName(format.geometryName) │ │ │ │ - } │ │ │ │ - } │ │ │ │ - return result │ │ │ │ - }, │ │ │ │ - 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 │ │ │ │ - }, │ │ │ │ - handleCommit: function(response, options) { │ │ │ │ - if (options.callback) { │ │ │ │ - var request = response.priv; │ │ │ │ - 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 │ │ │ │ + }, │ │ │ │ + Width: function(node, tileset) { │ │ │ │ + tileset.width = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + Height: function(node, tileset) { │ │ │ │ + tileset.height = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + Layers: function(node, tileset) { │ │ │ │ + tileset.layers = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + Styles: function(node, tileset) { │ │ │ │ + tileset.styles = this.getChildValue(node) │ │ │ │ } │ │ │ │ - options.callback.call(options.scope, response) │ │ │ │ - } │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1_1_1.prototype.readers["wms"]) │ │ │ │ }, │ │ │ │ - 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 │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_3 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1, { │ │ │ │ + readers: { │ │ │ │ + wms: OpenLayers.Util.applyDefaults({ │ │ │ │ + WMS_Capabilities: function(node, obj) { │ │ │ │ + this.readChildNodes(node, obj) │ │ │ │ + }, │ │ │ │ + LayerLimit: function(node, obj) { │ │ │ │ + obj.layerLimit = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + MaxWidth: function(node, obj) { │ │ │ │ + obj.maxWidth = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + MaxHeight: function(node, obj) { │ │ │ │ + obj.maxHeight = parseInt(this.getChildValue(node)) │ │ │ │ + }, │ │ │ │ + BoundingBox: function(node, obj) { │ │ │ │ + var bbox = OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]); │ │ │ │ + bbox.srs = node.getAttribute("CRS"); │ │ │ │ + obj.bbox[bbox.srs] = bbox │ │ │ │ + }, │ │ │ │ + CRS: function(node, obj) { │ │ │ │ + this.readers.wms.SRS.apply(this, [node, obj]) │ │ │ │ + }, │ │ │ │ + EX_GeographicBoundingBox: function(node, obj) { │ │ │ │ + obj.llbbox = []; │ │ │ │ + this.readChildNodes(node, obj.llbbox) │ │ │ │ + }, │ │ │ │ + westBoundLongitude: function(node, obj) { │ │ │ │ + obj[0] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + eastBoundLongitude: function(node, obj) { │ │ │ │ + obj[2] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + southBoundLatitude: function(node, obj) { │ │ │ │ + obj[1] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + northBoundLatitude: function(node, obj) { │ │ │ │ + obj[3] = this.getChildValue(node) │ │ │ │ + }, │ │ │ │ + MinScaleDenominator: function(node, obj) { │ │ │ │ + obj.maxScale = parseFloat(this.getChildValue(node)).toPrecision(16) │ │ │ │ + }, │ │ │ │ + MaxScaleDenominator: function(node, obj) { │ │ │ │ + obj.minScale = parseFloat(this.getChildValue(node)).toPrecision(16) │ │ │ │ + }, │ │ │ │ + Dimension: function(node, obj) { │ │ │ │ + var name = node.getAttribute("name").toLowerCase(); │ │ │ │ + var dim = { │ │ │ │ + name: name, │ │ │ │ + units: node.getAttribute("units"), │ │ │ │ + unitsymbol: node.getAttribute("unitSymbol"), │ │ │ │ + nearestVal: node.getAttribute("nearestValue") === "1", │ │ │ │ + multipleVal: node.getAttribute("multipleValues") === "1", │ │ │ │ + default: node.getAttribute("default") || "", │ │ │ │ + current: node.getAttribute("current") === "1", │ │ │ │ + values: this.getChildValue(node).split(",") │ │ │ │ + }; │ │ │ │ + obj.dimensions[dim.name] = dim │ │ │ │ + }, │ │ │ │ + Keyword: function(node, obj) { │ │ │ │ + var keyword = { │ │ │ │ + value: this.getChildValue(node), │ │ │ │ + vocabulary: node.getAttribute("vocabulary") │ │ │ │ + }; │ │ │ │ + if (obj.keywords) { │ │ │ │ + obj.keywords.push(keyword) │ │ │ │ + } │ │ │ │ } │ │ │ │ - }); │ │ │ │ - var deleteNode = this.format.createElementNSPlus("wfs:Delete", { │ │ │ │ - attributes: { │ │ │ │ - typeName: (options.featureNS ? this.featurePrefix + ":" : "") + options.featureType │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"]), │ │ │ │ + sld: { │ │ │ │ + UserDefinedSymbolization: function(node, obj) { │ │ │ │ + this.readers.wms.UserDefinedSymbolization.apply(this, [node, obj]); │ │ │ │ + obj.userSymbols.inlineFeature = parseInt(node.getAttribute("InlineFeature")) == 1; │ │ │ │ + obj.userSymbols.remoteWCS = parseInt(node.getAttribute("RemoteWCS")) == 1 │ │ │ │ + }, │ │ │ │ + DescribeLayer: function(node, obj) { │ │ │ │ + this.readers.wms.DescribeLayer.apply(this, [node, obj]) │ │ │ │ + }, │ │ │ │ + GetLegendGraphic: function(node, obj) { │ │ │ │ + this.readers.wms.GetLegendGraphic.apply(this, [node, obj]) │ │ │ │ } │ │ │ │ - }); │ │ │ │ - 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 │ │ │ │ - }) │ │ │ │ - }, │ │ │ │ - abort: function(response) { │ │ │ │ - if (response) { │ │ │ │ - response.priv.abort() │ │ │ │ } │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.WFS.v1" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3" │ │ │ │ }); │ │ │ │ -OpenLayers.Protocol.WFS.v1_1_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_3_0 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_3, { │ │ │ │ + version: "1.3.0", │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_3_0" │ │ │ │ +}); │ │ │ │ +OpenLayers.Format.WMSCapabilities.v1_1_0 = OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1, { │ │ │ │ version: "1.1.0", │ │ │ │ - initialize: function(options) { │ │ │ │ - OpenLayers.Protocol.WFS.v1.prototype.initialize.apply(this, arguments); │ │ │ │ - if (this.outputFormat && !this.readFormat) { │ │ │ │ - if (this.outputFormat.toLowerCase() == "gml2") { │ │ │ │ - this.readFormat = new OpenLayers.Format.GML.v2({ │ │ │ │ - featureType: this.featureType, │ │ │ │ - featureNS: this.featureNS, │ │ │ │ - geometryName: this.geometryName │ │ │ │ - }) │ │ │ │ - } else if (this.outputFormat.toLowerCase() == "json") { │ │ │ │ - this.readFormat = new OpenLayers.Format.GeoJSON │ │ │ │ + readers: { │ │ │ │ + wms: OpenLayers.Util.applyDefaults({ │ │ │ │ + SRS: function(node, obj) { │ │ │ │ + var srs = this.getChildValue(node); │ │ │ │ + var values = srs.split(/ +/); │ │ │ │ + for (var i = 0, len = values.length; i < len; i++) { │ │ │ │ + obj.srs[values[i]] = true │ │ │ │ + } │ │ │ │ } │ │ │ │ - } │ │ │ │ + }, OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"]) │ │ │ │ }, │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.WFS.v1_1_0" │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_0" │ │ │ │ }); │ │ │ │ -OpenLayers.Protocol.WFS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, { │ │ │ │ - version: "1.0.0", │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.WFS.v1_0_0" │ │ │ │ +OpenLayers.Format.ArcXML.Features = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ + read: function(data) { │ │ │ │ + var axl = new OpenLayers.Format.ArcXML; │ │ │ │ + var parsed = axl.read(data); │ │ │ │ + return parsed.features.feature │ │ │ │ + } │ │ │ │ }); │ │ │ │ OpenLayers.Events.featureclick = OpenLayers.Class({ │ │ │ │ cache: null, │ │ │ │ map: null, │ │ │ │ provides: ["featureclick", "nofeatureclick", "featureover", "featureout"], │ │ │ │ initialize: function(target) { │ │ │ │ this.target = target; │ │ │ │ @@ -40421,722 +41129,14 @@ │ │ │ │ delete this.map; │ │ │ │ delete this.target │ │ │ │ } │ │ │ │ }); │ │ │ │ OpenLayers.Events.nofeatureclick = OpenLayers.Events.featureclick; │ │ │ │ OpenLayers.Events.featureover = OpenLayers.Events.featureclick; │ │ │ │ OpenLayers.Events.featureout = OpenLayers.Events.featureclick; │ │ │ │ -OpenLayers.Lang.en = { │ │ │ │ - unhandledRequest: "Unhandled request return ${statusText}", │ │ │ │ - Permalink: "Permalink", │ │ │ │ - Overlays: "Overlays", │ │ │ │ - "Base Layer": "Base Layer", │ │ │ │ - noFID: "Can't update a feature for which there is no FID.", │ │ │ │ - browserNotSupported: "Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}", │ │ │ │ - minZoomLevelError: "The minZoomLevel property is only intended for use " + "with the FixedZoomLevels-descendent layers. That this " + "wfs layer checks for minZoomLevel is a relic of the" + "past. We cannot, however, remove it without possibly " + "breaking OL based applications that may depend on it." + " Therefore we are deprecating it -- the minZoomLevel " + "check below will be removed at 3.0. Please instead " + "use min/max resolution setting as described here: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "WFS Transaction: SUCCESS ${response}", │ │ │ │ - commitFailed: "WFS Transaction: FAILED ${response}", │ │ │ │ - googleWarning: "The Google Layer was unable to load correctly.<br><br>" + "To get rid of this message, select a new BaseLayer " + "in the layer switcher in the upper-right corner.<br><br>" + "Most likely, this is because the Google Maps library " + "script was either not included, or does not contain the " + "correct API key for your site.<br><br>" + "Developers: For help getting this working correctly, " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>click here</a>", │ │ │ │ - getLayerWarning: "The ${layerType} Layer was unable to load correctly.<br><br>" + "To get rid of this message, select a new BaseLayer " + "in the layer switcher in the upper-right corner.<br><br>" + "Most likely, this is because the ${layerLib} library " + "script was not correctly included.<br><br>" + "Developers: For help getting this working correctly, " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>click here</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Scale = 1 : ${scaleDenom}", │ │ │ │ - W: "W", │ │ │ │ - E: "E", │ │ │ │ - N: "N", │ │ │ │ - S: "S", │ │ │ │ - Graticule: "Graticule", │ │ │ │ - reprojectDeprecated: "You are using the 'reproject' option " + "on the ${layerName} layer. This option is deprecated: " + "its use was designed to support displaying data over commercial " + "basemaps, but that functionality should now be achieved by using " + "Spherical Mercator support. More information is available from " + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "This method has been deprecated and will be removed in 3.0. " + "Please use ${newMethod} instead.", │ │ │ │ - end: "" │ │ │ │ -}; │ │ │ │ -OpenLayers.Lang["oc"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Requèsta pas gerida, retorna ${statusText}", │ │ │ │ - Permalink: "Permaligam", │ │ │ │ - Overlays: "Calques", │ │ │ │ - "Base Layer": "Calc de basa", │ │ │ │ - noFID: "Impossible de metre a jorn un objècte sens identificant (fid).", │ │ │ │ - browserNotSupported: "Vòstre navegidor supòrta pas lo rendut vectorial. Los renderers actualament suportats son : \n${renderers}", │ │ │ │ - minZoomLevelError: "La proprietat minZoomLevel deu èsser utilizada solament per de jaces FixedZoomLevels-descendent. Lo fach qu'aqueste jaç WFS verifique la preséncia de minZoomLevel es una relica del passat. Çaquelà, la podèm suprimir sens copar d'aplicacions que ne poirián dependre. Es per aquò que la depreciam -- la verificacion del minZoomLevel serà suprimida en version 3.0. A la plaça, mercés d'utilizar los paramètres de resolucions min/max tal coma descrich sus : http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "Transaccion WFS : SUCCES ${response}", │ │ │ │ - commitFailed: "Transaccion WFS : FRACAS ${response}", │ │ │ │ - googleWarning: "Lo jaç Google es pas estat en mesura de se cargar corrèctament.<br><br>Per suprimir aqueste messatge, causissètz una BaseLayer novèla dins lo selector de jaç en naut a drecha.<br><br>Aquò es possiblament causat par la non-inclusion de la librariá Google Maps, o alara perque que la clau de l'API correspond pas a vòstre site.<br><br>Desvolopaires : per saber cossí corregir aquò, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>clicatz aicí</a>", │ │ │ │ - getLayerWarning: "Lo jaç ${layerType} es pas en mesura de se cargar corrèctament.<br><br>Per suprimir aqueste messatge, causissètz una BaseLayer novèla dins lo selector de jaç en naut a drecha.<br><br>Aquò es possiblament causat per la non-inclusion de la librariá ${layerLib}.<br><br>Desvolopaires : per saber cossí corregir aquí, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>clicatz aicí</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Escala ~ 1 : ${scaleDenom}", │ │ │ │ - W: "O", │ │ │ │ - E: "È", │ │ │ │ - N: "N", │ │ │ │ - S: "S", │ │ │ │ - reprojectDeprecated: "Utilizatz l'opcion 'reproject' sul jaç ${layerName}. Aquesta opcion es despreciada : Son usatge permetiá d'afichar de donadas al dessús de jaces raster comercials. Aquesta foncionalitat ara es suportada en utilizant lo supòrt de la projeccion Mercator Esferica. Mai d'informacion es disponibla sus http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Aqueste metòde es despreciada, e serà suprimida a la version 3.0. Mercés d'utilizar ${newMethod} a la plaça." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["zh-TW"] = { │ │ │ │ - unhandledRequest: "未處理的請求,傳回值為 ${statusText}。", │ │ │ │ - Permalink: "永久連結", │ │ │ │ - Overlays: "額外圖層", │ │ │ │ - "Base Layer": "基礎圖層", │ │ │ │ - noFID: "因為沒有 FID 所以無法更新 feature。", │ │ │ │ - browserNotSupported: "您的瀏覽器未支援向量渲染. 目前支援的渲染方式是:\n${renderers}", │ │ │ │ - minZoomLevelError: "minZoomLevel 屬性僅適合用在 " + "FixedZoomLevels-descendent 類型的圖層. 這個" + "wfs layer 的 minZoomLevel 是過去所遺留下來的," + "然而我們不能移除它而不讓它將" + "過去的程式相容性給破壞掉。" + "因此我們將會迴避使用它 -- minZoomLevel " + "會在3.0被移除,請改" + "用在這邊描述的 min/max resolution 設定: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "WFS Transaction: 成功 ${response}", │ │ │ │ - commitFailed: "WFS Transaction: 失敗 ${response}", │ │ │ │ - googleWarning: "The Google Layer 圖層無法被正確的載入。<br><br>" + "要迴避這個訊息, 請在右上角的圖層改變器裡," + "選一個新的基礎圖層。<br><br>" + "很有可能是因為 Google Maps 的函式庫" + "腳本沒有被正確的置入,或沒有包含 " + "您網站上正確的 API key <br><br>" + "開發者: 要幫助這個行為正確完成," + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>請按這裡</a>", │ │ │ │ - getLayerWarning: "${layerType} 圖層無法被正確的載入。<br><br>" + "要迴避這個訊息, 請在右上角的圖層改變器裡," + "選一個新的基礎圖層。<br><br>" + "很有可能是因為 ${layerLib} 的函式庫" + "腳本沒有被正確的置入。<br><br>" + "開發者: 要幫助這個行為正確完成," + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>請按這裡</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Scale = 1 : ${scaleDenom}", │ │ │ │ - reprojectDeprecated: "你正使用 'reproject' 這個選項 " + "在 ${layerName} 層。這個選項已經不再使用:" + "它的使用原本是設計用來支援在商業地圖上秀出資料," + "但這個功能已經被" + "Spherical Mercator所取代。更多的資訊可以在 " + "http://trac.openlayers.org/wiki/SphericalMercator 找到。", │ │ │ │ - methodDeprecated: "這個方法已經不再使用且在3.0將會被移除," + "請使用 ${newMethod} 來代替。", │ │ │ │ - end: "" │ │ │ │ -}; │ │ │ │ -OpenLayers.Lang["sk"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Neobslúžené požiadavky vracajú ${statusText}", │ │ │ │ - Permalink: "Trvalý odkaz", │ │ │ │ - Overlays: "Prekrytia", │ │ │ │ - "Base Layer": "Základná vrstva", │ │ │ │ - noFID: "Nie je možné aktualizovať vlastnosť, pre ktorú neexistuje FID.", │ │ │ │ - browserNotSupported: "Váš prehliadač nepodporuje vykresľovanie vektorov. Momentálne podporované vykresľovače sú:\n${renderers}", │ │ │ │ - minZoomLevelError: "Vlastnosť minZoomLevel je určený iba na použitie s vrstvami odvodenými od FixedZoomLevels. To, že táto wfs vrstva kontroluje minZoomLevel je pozostatok z minulosti. Nemôžeme ho však odstrániť, aby sme sa vyhli možnému porušeniu aplikácií založených na Open Layers, ktoré na tomto môže závisieť. Preto ho označujeme ako zavrhovaný - dolu uvedená kontrola minZoomLevel bude odstránená vo verzii 3.0. Použite prosím namiesto toho kontrolu min./max. rozlíšenia podľa tu uvedeného popisu: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "Transakcia WFS: ÚSPEŠNÁ ${response}", │ │ │ │ - commitFailed: "Transakcia WFS: ZLYHALA ${response}", │ │ │ │ - googleWarning: "Vrstvu Google nebolo možné správne načítať.<br><br>Aby ste sa tejto správy zbavili vyberte novú BaseLayer v prepínači vrstiev v pravom hornom rohu.<br><br>Toto sa stalo pravdepodobne preto, že skript knižnice Google Maps buď nebol načítaný alebo neobsahuje správny kľúč API pre vašu lokalitu.<br><br>Vývojári: Tu môžete získať <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>pomoc so sfunkčnením</a>", │ │ │ │ - getLayerWarning: "Vrstvu ${layerType} nebolo možné správne načítať.<br><br>Aby ste sa tejto správy zbavili vyberte novú BaseLayer v prepínači vrstiev v pravom hornom rohu.<br><br>Toto sa stalo pravdepodobne preto, že skript knižnice ${layerType} buď nebol načítaný alebo neobsahuje správny kľúč API pre vašu lokalitu.<br><br>Vývojári: Tu môžete získať <a href='http://trac.openlayers.org/wiki/${layerType}' target='_blank'>pomoc so sfunkčnením</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Mierka = 1 : ${scaleDenom}", │ │ │ │ - reprojectDeprecated: "Používate voľby „reproject“ vrstvy ${layerType}. Táto voľba je zzavrhovaná: jej použitie bolo navrhnuté na podporu zobrazovania údajov nad komerčnými základovými mapami, ale túto funkcionalitu je teraz možné dosiahnuť pomocou Spherical Mercator. Ďalšie informácie získate na stránke http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Táto metóda je zavrhovaná a bude odstránená vo verzii 3.0. Použite prosím namiesto nej metódu ${newMethod}." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["gl"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Solicitude non xerada; a resposta foi: ${statusText}", │ │ │ │ - Permalink: "Ligazón permanente", │ │ │ │ - Overlays: "Capas superpostas", │ │ │ │ - "Base Layer": "Capa base", │ │ │ │ - noFID: "Non se pode actualizar a funcionalidade para a que non hai FID.", │ │ │ │ - browserNotSupported: "O seu navegador non soporta a renderización de vectores. Os renderizadores soportados actualmente son:\n${renderers}", │ │ │ │ - minZoomLevelError: "A propiedade minZoomLevel é só para uso conxuntamente coas capas FixedZoomLevels-descendent. O feito de que esa capa wfs verifique o minZoomLevel é unha reliquia do pasado. Non podemos, con todo, eliminala sen a posibilidade de non romper as aplicacións baseadas en OL que poidan depender dela. Por iso a estamos deixando obsoleta (a comprobación minZoomLevel de embaixo será eliminada na versión 3.0). Por favor, no canto diso use o axuste de resolución mín/máx tal e como está descrito aquí: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "Transacción WFS: ÉXITO ${response}", │ │ │ │ - commitFailed: "Transacción WFS: FALLIDA ${response}", │ │ │ │ - googleWarning: "A capa do Google non puido cargarse correctamente.<br><br>Para evitar esta mensaxe, escolla unha nova capa base no seleccionador de capas na marxe superior dereita.<br><br>Probablemente, isto acontece porque a escritura da libraría do Google Maps ou ben non foi incluída ou ben non contén a clave API correcta para o seu sitio.<br><br>Desenvolvedores: para axudar a facer funcionar isto correctamente, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>premede aquí</a>", │ │ │ │ - getLayerWarning: "A capa ${layerType} foi incapaz de cargarse correctamente.<br><br>Para evitar esta mensaxe, escolla unha nova capa base no seleccionador de capas na marxe superior dereita.<br><br>Probablemente, isto acontece porque a escritura da libraría ${layerLib} non foi ben incluída.<br><br>Desenvolvedores: para axudar a facer funcionar isto correctamente, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>premede aquí</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Escala = 1 : ${scaleDenom}", │ │ │ │ - W: "O", │ │ │ │ - E: "L", │ │ │ │ - N: "N", │ │ │ │ - S: "S", │ │ │ │ - reprojectDeprecated: 'Está usando a opción "reproject" na capa ${layerName}. Esta opción está obsoleta: o seu uso foi deseñado para a visualización de datos sobre mapas base comerciais, pero esta funcionalidade debera agora ser obtida utilizando a proxección Spherical Mercator. Hai dispoñible máis información en http://trac.openlayers.org/wiki/SphericalMercator.', │ │ │ │ - methodDeprecated: "Este método está obsoleto e será eliminado na versión 3.0. Por favor, no canto deste use ${newMethod}." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["nb"] = { │ │ │ │ - unhandledRequest: "Ubehandlet forespørsel returnerte ${statusText}", │ │ │ │ - Permalink: "Kobling til denne siden", │ │ │ │ - Overlays: "Kartlag", │ │ │ │ - "Base Layer": "Bakgrunnskart", │ │ │ │ - noFID: "Kan ikke oppdatere et feature (et objekt) som ikke har FID.", │ │ │ │ - browserNotSupported: "Din nettleser støtter ikke vektortegning. Tegnemetodene som støttes er:\n${renderers}", │ │ │ │ - minZoomLevelError: "Egenskapen minZoomLevel er kun ment til bruk på lag " + "basert på FixedZoomLevels. At dette wfs-laget sjekker " + "minZoomLevel er en etterlevning fra tidligere versjoner. Det kan dog ikke " + "tas bort uten å risikere at OL-baserte applikasjoner " + "slutter å virke, så det er merket som foreldet: " + "minZoomLevel i sjekken nedenfor vil fjernes i 3.0. " + "Vennligst bruk innstillingene for min/maks oppløsning " + "som er beskrevet her: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "WFS-transaksjon: LYKTES ${response}", │ │ │ │ - commitFailed: "WFS-transaksjon: MISLYKTES ${response}", │ │ │ │ - googleWarning: "Google-laget kunne ikke lastes.<br><br>" + "Bytt til et annet bakgrunnslag i lagvelgeren i " + "øvre høyre hjørne for å slippe denne meldingen.<br><br>" + "Sannsynligvis forårsakes feilen av at Google Maps-biblioteket " + "ikke er riktig inkludert på nettsiden, eller at det ikke er " + "angitt riktig API-nøkkel for nettstedet.<br><br>" + "Utviklere: For hjelp til å få dette til å virke se " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>her</a>.", │ │ │ │ - getLayerWarning: "${layerType}-laget kunne ikke lastes.<br><br>" + "Bytt til et annet bakgrunnslag i lagvelgeren i " + "øvre høyre hjørne for å slippe denne meldingen.<br><br>" + "Sannsynligvis forårsakes feilen av at " + "${layerLib}-biblioteket ikke var riktig inkludert " + "på nettsiden.<br><br>" + "Utviklere: For hjelp til å få dette til å virke se " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>her</a>.", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "<strong>Skala</strong> 1 : ${scaleDenom}", │ │ │ │ - reprojectDeprecated: "Du bruker innstillingen 'reproject' på laget ${layerName}. " + "Denne innstillingen er foreldet, den var ment for å støtte " + "visning av kartdata over kommersielle bakgrunnskart, men det " + "bør nå gjøres med støtten for Spherical Mercator. Mer informasjon " + "finnes på http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Denne metoden er markert som foreldet og vil bli fjernet i 3.0. " + "Vennligst bruk ${newMethod} i stedet.", │ │ │ │ - end: "" │ │ │ │ -}; │ │ │ │ -OpenLayers.Lang["no"] = OpenLayers.Lang["nb"]; │ │ │ │ -OpenLayers.Lang["cs-CZ"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Nezpracovaná návratová hodnota ${statusText}", │ │ │ │ - Permalink: "Trvalý odkaz", │ │ │ │ - Overlays: "Překryvné vrstvy", │ │ │ │ - "Base Layer": "Podkladové vrstvy", │ │ │ │ - noFID: "Nelze aktualizovat prvek, pro který neexistuje FID.", │ │ │ │ - browserNotSupported: "Váš prohlížeč nepodporuje vykreslování vektorů. Momentálně podporované nástroje jsou::\n${renderers}", │ │ │ │ - minZoomLevelError: "Vlastnost minZoomLevel by se měla používat pouze s potomky FixedZoomLevels vrstvami. To znamená, že vrstva wfs kontroluje, zda-li minZoomLevel není zbytek z minulosti.Nelze to ovšem vyjmout bez možnosti, že bychom rozbili aplikace postavené na OL, které by na tom mohly záviset. Proto tuto vlastnost nedoporučujeme používat -- kontrola minZoomLevel bude odstraněna ve verzi 3.0. Použijte prosím raději nastavení min/max podle příkaldu popsaného na: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "WFS Transaction: ÚSPĚCH ${response}", │ │ │ │ - commitFailed: "WFS Transaction: CHYBA ${response}", │ │ │ │ - googleWarning: "Nepodařilo se správně načíst vrstvu Google.<br><br>Abyste se zbavili této zprávy, zvolte jinou základní vrstvu v přepínači vrstev.<br><br>To se většinou stává, pokud nebyl načten skript, nebo neobsahuje správný klíč pro API pro tuto stránku.<br><br>Vývojáři: Pro pomoc, aby tohle fungovalo , <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>klikněte sem</a>", │ │ │ │ - getLayerWarning: "The ${layerType} Layer was unable to load correctly.<br><br>To get rid of this message, select a new BaseLayer in the layer switcher in the upper-right corner.<br><br>Most likely, this is because the ${layerLib} library script was either not correctly included.<br><br>Developers: For help getting this working correctly, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>click here</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Měřítko = 1 : ${scaleDenom}", │ │ │ │ - reprojectDeprecated: "Použil jste volbu 'reproject' ve vrstvě ${layerName}. Tato volba není doporučená: byla zde proto, aby bylo možno zobrazovat data z okomerčních serverů, ale tato funkce je nyní zajištěna pomocí podpory Spherical Mercator. Více informací naleznete na http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Tato metoda je zavržená a bude ve verzi 3.0 odstraněna. Prosím, použijte raději ${newMethod}." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["nl"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Het verzoek is niet afgehandeld met de volgende melding: ${statusText}", │ │ │ │ - Permalink: "Permanente verwijzing", │ │ │ │ - Overlays: "Overlays", │ │ │ │ - "Base Layer": "Achtergrondkaart", │ │ │ │ - noFID: "Een optie die geen FID heeft kan niet bijgewerkt worden.", │ │ │ │ - browserNotSupported: "Uw browser ondersteunt het weergeven van vectoren niet.\nMomenteel ondersteunde weergavemogelijkheden:\n${renderers}", │ │ │ │ - minZoomLevelError: "De eigenschap minZoomLevel is alleen bedoeld voor gebruik lagen met die afstammen van FixedZoomLevels-lagen.\nDat deze WFS-laag minZoomLevel controleert, is een overblijfsel uit het verleden.\nWe kunnen deze controle echter niet verwijderen zonder op OL gebaseerde applicaties die hervan afhankelijk zijn stuk te maken.\nDaarom heeft deze functionaliteit de eigenschap 'deprecated' gekregen - de minZoomLevel wordt verwijderd in versie 3.0.\nGebruik in plaats van deze functie de mogelijkheid om min/max voor resolutie in te stellen zoals op de volgende pagina wordt beschreven:\nhttp://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "WFS-transactie: succesvol ${response}", │ │ │ │ - commitFailed: "WFS-transactie: mislukt ${response}", │ │ │ │ - googleWarning: "De Google-Layer kon niet correct geladen worden.<br /><br />\nOm deze melding niet meer te krijgen, moet u een andere achtergrondkaart kiezen in de laagwisselaar in de rechterbovenhoek.<br /><br />\nDit komt waarschijnlijk doordat de bibliotheek ${layerLib} niet correct ingevoegd is.<br /><br />\nOntwikkelaars: <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>klik hier</a> om dit werkend te krijgen.", │ │ │ │ - getLayerWarning: "De laag ${layerType} kon niet goed geladen worden.<br /><br />\nOm deze melding niet meer te krijgen, moet u een andere achtergrondkaart kiezen in de laagwisselaar in de rechterbovenhoek.<br /><br />\nDit komt waarschijnlijk doordat de bibliotheek ${layerLib} niet correct is ingevoegd.<br /><br />\nOntwikkelaars: <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>klik hier</a> om dit werkend te krijgen.", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Schaal = 1 : ${scaleDenom}", │ │ │ │ - W: "W", │ │ │ │ - E: "O", │ │ │ │ - N: "N", │ │ │ │ - S: "Z", │ │ │ │ - reprojectDeprecated: "U gebruikt de optie 'reproject' op de laag ${layerName}.\nDeze optie is vervallen: deze optie was ontwikkeld om gegevens over commerciële basiskaarten weer te geven, maar deze functionaliteit wordt nu bereikt door ondersteuning van Spherical Mercator.\nMeer informatie is beschikbaar op http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Deze methode is verouderd en wordt verwijderd in versie 3.0.\nGebruik ${newMethod}." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["br"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Distro evel reked anveret ${statusText}", │ │ │ │ - Permalink: "Peurliamm", │ │ │ │ - Overlays: "Gwiskadoù", │ │ │ │ - "Base Layer": "Gwiskad diazez", │ │ │ │ - noFID: "N'haller ket hizivaat un elfenn ma n'eus ket a niverenn-anaout (FID) eviti.", │ │ │ │ - browserNotSupported: "N'eo ket skoret an daskor vektorel gant ho merdeer. Setu aze an daskorerioù skoret evit ar poent :\n${renderers}", │ │ │ │ - minZoomLevelError: "Ne zleer implijout ar perzh minZoomLevel nemet evit gwiskadoù FixedZoomLevels-descendent. Ar fed ma wiria ar gwiskad WHS-se hag-eñ ez eus eus minZoomLevel zo un aspadenn gozh. Koulskoude n'omp ket evit e ziverkañ kuit da derriñ arloadoù diazezet war OL a c'hallfe bezañ stag outañ. Setu perak eo dispredet -- Lamet kuit e vo ar gwiriañ minZoomLevel a-is er stumm 3.0. Ober gant an arventennoù bihanañ/brasañ evel deskrivet amañ e plas : http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "Treuzgread WFS : MAT EO ${response}", │ │ │ │ - commitFailed: "Treuzgread WFS Transaction: C'HWITET ${response}", │ │ │ │ - googleWarning: "N'eus ket bet gallet kargañ ar gwiskad Google ent reizh.<br><br>Evit en em zizober eus ar c'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c'horn dehoù el laez.<br><br>Sur a-walc'h eo peogwir n'eo ket bet ensoc'het levraoueg Google Maps pe neuze ne glot ket an alc'hwez API gant ho lec'hienn.<br><br>Diorroerien : Evit reizhañ an dra-se, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>click here</a>", │ │ │ │ - getLayerWarning: "N'haller ket kargañ ar gwiskad ${layerType} ent reizh.<br><br>Evit en em zizober eus ar c'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c'horn dehoù el laez.<br><br>Sur a-walc'h eo peogwir n'eo ket bet ensoc'het mat al levraoueg ${layerLib}.<br><br>Diorroerien : Evit gouzout penaos reizhañ an dra-se, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>click here</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Skeul = 1 : ${scaleDenom}", │ │ │ │ - W: "K", │ │ │ │ - E: "R", │ │ │ │ - N: "N", │ │ │ │ - S: "S", │ │ │ │ - reprojectDeprecated: "Emaoc'h oc'h implijout an dibarzh 'reproject' war ar gwiskad ${layerName}. Dispredet eo an dibarzh-mañ : bet eo hag e talveze da ziskwel roadennoù war-c'horre kartennoù diazez kenwerzhel, un dra hag a c'haller ober bremañ gant an arc'hwel dre skor banndres boullek Mercator. Muioc'h a ditouroù a c'haller da gaout war http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Dispredet eo an daore-se ha tennet e vo kuit eus ar stumm 3.0. Grit gant ${newMethod} e plas." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["nds"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Unbehannelt Trüchmellels för de Anfraag ${statusText}", │ │ │ │ - Permalink: "Permalink", │ │ │ │ - Overlays: "Overlays", │ │ │ │ - "Base Layer": "Achtergrundkoort", │ │ │ │ - noFID: "En Feature, dat keen FID hett, kann nich aktuell maakt warrn.", │ │ │ │ - browserNotSupported: "Dien Browser ünnerstütt keen Vektorbiller. Ünnerstütt Renderers:\n${renderers}", │ │ │ │ - commitSuccess: "WFS-Transakschoon: hett klappt ${response}", │ │ │ │ - commitFailed: "WFS-Transakschoon: hett nich klappt ${response}", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Skaal = 1 : ${scaleDenom}", │ │ │ │ - methodDeprecated: "Disse Methood is oold un schall dat in 3.0 nich mehr geven. Bruuk dor man beter ${newMethod} för." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["is"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - Permalink: "Varanlegur tengill", │ │ │ │ - Overlays: "Þekjur", │ │ │ │ - "Base Layer": "Grunnlag", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Skali = 1 : ${scaleDenom}", │ │ │ │ - methodDeprecated: "Þetta fall hefur verið úrelt og verður fjarlægt í 3.0. Notaðu ${newMethod} í staðin." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang.ca = { │ │ │ │ - unhandledRequest: "Resposta a petició no gestionada ${statusText}", │ │ │ │ - Permalink: "Enllaç permanent", │ │ │ │ - Overlays: "Capes addicionals", │ │ │ │ - "Base Layer": "Capa Base", │ │ │ │ - noFID: "No es pot actualitzar un element per al que no existeix FID.", │ │ │ │ - browserNotSupported: "El seu navegador no suporta renderització vectorial. Els renderitzadors suportats actualment són:\n${renderers}", │ │ │ │ - minZoomLevelError: "La propietat minZoomLevel s'ha d'utilitzar només " + "amb les capes que tenen FixedZoomLevels. El fet que " + "una capa wfs comprovi minZoomLevel és una relíquia del " + "passat. No podem, però, eliminar-la sense trencar " + "les aplicacions d'OpenLayers que en puguin dependre. " + "Així doncs estem fent-la obsoleta -- la comprovació " + "minZoomLevel s'eliminarà a la versió 3.0. Feu servir " + "els paràmetres min/max resolution en substitució, tal com es descriu aquí: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "Transacció WFS: CORRECTA ${response}", │ │ │ │ - commitFailed: "Transacció WFS: HA FALLAT ${response}", │ │ │ │ - googleWarning: "La capa Google no s'ha pogut carregar correctament.<br><br>" + "Per evitar aquest missatge, seleccioneu una nova Capa Base " + "al gestor de capes de la cantonada superior dreta.<br><br>" + "Probablement això és degut a que l'script de la biblioteca de " + "Google Maps no ha estat inclòs a la vostra pàgina, o no " + "conté la clau de l'API correcta per a la vostra adreça.<br><br>" + "Desenvolupadors: Per obtenir consells sobre com fer anar això, " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>féu clic aquí</a>", │ │ │ │ - getLayerWarning: "Per evitar aquest missatge, seleccioneu una nova Capa Base " + "al gestor de capes de la cantonada superior dreta.<br><br>" + "Probablement això és degut a que l'script de la biblioteca " + "${layerLib} " + "no ha estat inclòs a la vostra pàgina.<br><br>" + "Desenvolupadors: Per obtenir consells sobre com fer anar això, " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>féu clic aquí</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Escala = 1 : ${scaleDenom}", │ │ │ │ - W: "O", │ │ │ │ - E: "E", │ │ │ │ - N: "N", │ │ │ │ - S: "S", │ │ │ │ - Graticule: "Retícula", │ │ │ │ - reprojectDeprecated: "Esteu fent servir l'opció 'reproject' a la capa " + "${layerName}. Aquesta opció és obsoleta: el seu ús fou concebut " + "per suportar la visualització de dades sobre mapes base comercials, " + "però ara aquesta funcionalitat s'hauria d'assolir mitjançant el suport " + "de la projecció Spherical Mercator. Més informació disponible a " + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Aquest mètode és obsolet i s'eliminarà a la versió 3.0. " + "Si us plau feu servir em mètode alternatiu ${newMethod}.", │ │ │ │ - end: "" │ │ │ │ -}; │ │ │ │ -OpenLayers.Lang["ar"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - Permalink: "وصلة دائمة", │ │ │ │ - "Base Layer": "الطبقة الاساسية", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "النسبة = 1 : ${scaleDenom}", │ │ │ │ - W: "غ", │ │ │ │ - E: "شر", │ │ │ │ - N: "شم", │ │ │ │ - S: "ج" │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["ru"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Необработанный запрос вернул ${statusText}", │ │ │ │ - Permalink: "Постоянная ссылка", │ │ │ │ - Overlays: "Слои", │ │ │ │ - "Base Layer": "Основной слой", │ │ │ │ - noFID: "Невозможно обновить объект, для которого нет FID.", │ │ │ │ - browserNotSupported: "Ваш браузер не поддерживает векторную графику. На данный момент поддерживаются:\n${renderers}", │ │ │ │ - minZoomLevelError: "Свойство minZoomLevel предназначено только для использования со слоями, являющимися потомками FixedZoomLevels. То, что этот WFS-слой проверяется на minZoomLevel — реликт прошлого. Однако мы не можем удалить эту функцию, так как, возможно, от неё зависят некоторые основанные на OpenLayers приложения. Функция объявлена устаревшей — проверка minZoomLevel будет удалена в 3.0. Пожалуйста, используйте вместо неё настройку мин/макс разрешения, описанную здесь: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "Транзакция WFS: УСПЕШНО ${response}", │ │ │ │ - commitFailed: "Транзакция WFS: ОШИБКА ${response}", │ │ │ │ - googleWarning: "Слой Google не удалось нормально загрузить.<br><br>Чтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.<br><br>Скорее всего, причина в том, что библиотека Google Maps не была включена или не содержит корректного API-ключа для вашего сайта.<br><br>Разработчикам: чтобы узнать, как сделать, чтобы всё заработало, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>щёлкните тут</a>", │ │ │ │ - getLayerWarning: "Слой ${layerType} не удалось нормально загрузить. <br><br>Чтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.<br><br>Скорее всего, причина в том, что библиотека ${layerLib} не была включена или была включена некорректно.<br><br>Разработчикам: чтобы узнать, как сделать, чтобы всё заработало, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>щёлкните тут</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Масштаб = 1 : ${scaleDenom}", │ │ │ │ - W: "З", │ │ │ │ - E: "В", │ │ │ │ - N: "С", │ │ │ │ - S: "Ю", │ │ │ │ - reprojectDeprecated: "Вы используете опцию 'reproject' для слоя ${layerName}. Эта опция является устаревшей: ее использование предполагалось для поддержки показа данных поверх коммерческих базовых карт, но теперь этот функционал несёт встроенная поддержка сферической проекции Меркатора. Больше сведений доступно на http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Этот метод считается устаревшим и будет удалён в версии 3.0. Пожалуйста, пользуйтесь ${newMethod}." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["zh-CN"] = { │ │ │ │ - unhandledRequest: "未处理的请求,返回值为 ${statusText}", │ │ │ │ - Permalink: "永久链接", │ │ │ │ - Overlays: "叠加层", │ │ │ │ - "Base Layer": "基础图层", │ │ │ │ - noFID: "无法更新feature,缺少FID。", │ │ │ │ - browserNotSupported: "你使用的浏览器不支持矢量渲染。当前支持的渲染方式包括:\n${renderers}", │ │ │ │ - minZoomLevelError: "minZoomLevel属性仅适合用于" + "使用了固定缩放级别的图层。这个 " + "wfs 图层检查 minZoomLevel 是过去遗留下来的。" + "然而,我们不能移除它," + "而破坏依赖于它的基于OL的应用程序。" + "因此,我们废除了它 -- minZoomLevel " + "将会在3.0中被移除。请改用 " + "min/max resolution 设置,参考:" + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "WFS Transaction: 成功。 ${response}", │ │ │ │ - commitFailed: "WFS Transaction: 失败。 ${response}", │ │ │ │ - googleWarning: "Google图层不能正确加载。<br><br>" + "要消除这个信息,请在右上角的" + "图层控制面板中选择其他的基础图层。<br><br>" + "这种情况很可能是没有正确的包含Google地图脚本库," + "或者是没有包含在你的站点上" + "使用的正确的Google Maps API密匙。<br><br>" + "开发者:获取使其正确工作的帮助信息," + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>点击这里</a>", │ │ │ │ - getLayerWarning: "${layerType} 图层不能正确加载。<br><br>" + "要消除这个信息,请在右上角的" + "图层控制面板中选择其他的基础图层。<br><br>" + "这种情况很可能是没有正确的包含" + "${layerLib} 脚本库。<br><br>" + "开发者:获取使其正确工作的帮助信息," + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>点击这里</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "比例尺 = 1 : ${scaleDenom}", │ │ │ │ - reprojectDeprecated: "你正在使用 ${layerName} 图层上的'reproject'选项。" + "这个选项已经不再使用:" + "它是被设计用来支持显示商业的地图数据," + "不过现在该功能可以通过使用Spherical Mercator来实现。" + "更多信息可以参阅" + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "该方法已经不再被支持,并且将在3.0中被移除。" + "请使用 ${newMethod} 方法来替代。", │ │ │ │ - end: "" │ │ │ │ -}; │ │ │ │ -OpenLayers.Lang["vi"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Không xử lý được phản hồi ${statusText} cho yêu cầu", │ │ │ │ - Permalink: "Liên kết thường trực", │ │ │ │ - Overlays: "Lấp bản đồ", │ │ │ │ - "Base Layer": "Lớp nền", │ │ │ │ - noFID: "Không thể cập nhật tính năng thiếu FID.", │ │ │ │ - browserNotSupported: "Trình duyệt của bạn không hỗ trợ chức năng vẽ bằng vectơ. Hiện hỗ trợ các bộ kết xuất:\n${renderers}", │ │ │ │ - minZoomLevelError: "Chỉ nên sử dụng thuộc tính minZoomLevel với các lớp FixedZoomLevels-descendent. Việc lớp wfs này tìm cho minZoomLevel là di tích còn lại từ xưa. Tuy nhiên, nếu chúng tôi dời nó thì sẽ vỡ các chương trình OpenLayers mà dựa trên nó. Bởi vậy chúng tôi phản đối sử dụng nó – bước tìm cho minZoomLevel sẽ được dời vào phiên bản 3.0. Xin sử dụng thiết lập độ phân tích tối thiểu / tối đa thay thế, theo hướng dẫn này: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "Giao dịch WFS: THÀNH CÔNG ${response}", │ │ │ │ - commitFailed: "Giao dịch WFS: THẤT BẠI ${response}", │ │ │ │ - googleWarning: "Không thể tải lớp Google đúng đắn.<br><br>Để tránh thông báo này lần sau, hãy chọn BaseLayer mới dùng điều khiển chọn lớp ở góc trên phải.<br><br>Chắc script thư viện Google Maps hoặc không được bao gồm hoặc không chứa khóa API hợp với website của bạn.<br><br><a href='http://trac.openlayers.org/wiki/Google' target='_blank'>Trợ giúp về tính năng này</a> cho người phát triển.", │ │ │ │ - getLayerWarning: "Không thể tải lớp ${layerType} đúng đắn.<br><br>Để tránh thông báo này lần sau, hãy chọn BaseLayer mới dùng điều khiển chọn lớp ở góc trên phải.<br><br>Chắc script thư viện ${layerLib} không được bao gồm đúng kiểu.<br><br><a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>Trợ giúp về tính năng này</a> cho người phát triển.", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Tỷ lệ = 1 : ${scaleDenom}", │ │ │ │ - W: "T", │ │ │ │ - E: "Đ", │ │ │ │ - N: "B", │ │ │ │ - S: "N", │ │ │ │ - reprojectDeprecated: "Bạn đang áp dụng chế độ “reproject” vào lớp ${layerName}. Chế độ này đã bị phản đối: nó có mục đích hỗ trợ lấp dữ liệu trên các nền bản đồ thương mại; nên thực hiện hiệu ứng đó dùng tính năng Mercator Hình cầu. Có sẵn thêm chi tiết tại http://trac.openlayers.org/wiki/SphericalMercator .", │ │ │ │ - methodDeprecated: "Phương thức này đã bị phản đối và sẽ bị dời vào phiên bản 3.0. Xin hãy sử dụng ${newMethod} thay thế." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["io"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Skalo = 1 : ${scaleDenom}" │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["ia"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Le responsa a un requesta non esseva maneate: ${statusText}", │ │ │ │ - Permalink: "Permaligamine", │ │ │ │ - Overlays: "Superpositiones", │ │ │ │ - "Base Layer": "Strato de base", │ │ │ │ - noFID: "Non pote actualisar un elemento sin FID.", │ │ │ │ - browserNotSupported: "Tu navigator non supporta le rendition de vectores. Le renditores actualmente supportate es:\n${renderers}", │ │ │ │ - minZoomLevelError: "Le proprietate minZoomLevel es solmente pro uso con le stratos descendente de FixedZoomLevels. Le facto que iste strato WFS verifica minZoomLevel es un reliquia del passato. Nonobstante, si nos lo remove immediatemente, nos pote rumper applicationes a base de OL que depende de illo. Ergo nos lo declara obsolete; le verification de minZoomLevel in basso essera removite in version 3.0. Per favor usa in su loco le configuration de resolutiones min/max como describite a: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "Transaction WFS: SUCCESSO ${response}", │ │ │ │ - commitFailed: "Transaction WFS: FALLEVA ${response}", │ │ │ │ - googleWarning: "Le strato Google non poteva esser cargate correctemente.<br><br>Pro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.<br><br>Multo probabilemente, isto es proque le script del libreria de Google Maps non esseva includite o non contine le clave API correcte pro tu sito.<br><br>Disveloppatores: Pro adjuta de corriger isto, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>clicca hic</a", │ │ │ │ - getLayerWarning: "Le strato ${layerType} non poteva esser cargate correctemente.<br><br>Pro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.<br><br>Multo probabilemente, isto es proque le script del libreria de ${layerLib} non esseva correctemente includite.<br><br>Disveloppatores: Pro adjuta de corriger isto, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>clicca hic</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Scala = 1 : ${scaleDenom}", │ │ │ │ - W: "W", │ │ │ │ - E: "E", │ │ │ │ - N: "N", │ │ │ │ - S: "S", │ │ │ │ - reprojectDeprecated: "Tu usa le option 'reproject' in le strato ${layerName} layer. Iste option es obsolescente: illo esseva pro poter monstrar datos super cartas de base commercial, ma iste functionalitate pote ora esser attingite con le uso de Spherical Mercator. Ulterior information es disponibile a http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Iste methodo ha essite declarate obsolescente e essera removite in version 3.0. Per favor usa ${newMethod} in su loco." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["be-tarask"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Неапрацаваны вынік запыту ${statusText}", │ │ │ │ - Permalink: "Сталая спасылка", │ │ │ │ - Overlays: "Слаі", │ │ │ │ - "Base Layer": "Базавы слой", │ │ │ │ - noFID: "Немагчыма абнавіць магчымасьць, для якога не існуе FID.", │ │ │ │ - browserNotSupported: "Ваш браўзэр не падтрымлівае вэктарную графіку. У цяперашні момант падтрымліваюцца: ${renderers}", │ │ │ │ - minZoomLevelError: "Уласьцівасьць minZoomLevel прызначана толькі для выкарыстаньня са слаямі вытворнымі ад FixedZoomLevels. Тое, што гэты wfs-слой правяраецца на minZoomLevel — рэха прошлага. Але мы ня можам выдаліць гэтую магчымасьць, таму што ад яе залежаць некаторыя заснаваныя на OL дастасаваньні. Тым ня менш, праверка minZoomLevel будзе выдаленая ў вэрсіі 3.0. Калі ласка, выкарыстоўваеце замест яе ўстаноўкі мінімальнага/максымальнага памераў, як апісана тут: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "WFS-транзакцыя: ПОСЬПЕХ ${response}", │ │ │ │ - commitFailed: "WFS-транзакцыя: ПАМЫЛКА ${response}", │ │ │ │ - googleWarning: "Не атрымалася загрузіць слой Google. <br><br>Каб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.<br><br> Хутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі Google Maps ня быў уключаныя альбо не ўтрымлівае слушны API-ключ для Вашага сайта.<br><br>Распрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>націсьніце тут</a>", │ │ │ │ - getLayerWarning: "Немагчыма загрузіць слой ${layerType}.<br><br>Каб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.<br><br>Хутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі ${layerLib} ня быў слушна ўключаны.<br><br>Распрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>націсьніце тут</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Маштаб = 1 : ${scaleDenom}", │ │ │ │ - W: "З", │ │ │ │ - E: "У", │ │ │ │ - N: "Пн", │ │ │ │ - S: "Пд", │ │ │ │ - reprojectDeprecated: "Вы выкарыстоўваеце ўстаноўку 'reproject' для слоя ${layerName}. Гэтая ўстаноўка зьяўляецца састарэлай: яна выкарыстоўвалася для падтрымкі паказу зьвестак на камэрцыйных базавых мапах, але гэта функцыя цяпер рэалізаваная ў убудаванай падтрымцы сфэрычнай праекцыі Мэркатара. Дадатковая інфармацыя ёсьць на http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Гэты мэтад састарэлы і будзе выдалены ў вэрсіі 3.0. Калі ласка, замест яго выкарыстоўвайце ${newMethod}." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["hu"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Nem kezelt kérés visszatérése ${statusText}", │ │ │ │ - Permalink: "Permalink", │ │ │ │ - Overlays: "Rávetítések", │ │ │ │ - "Base Layer": "Alapréteg", │ │ │ │ - noFID: "Nem frissíthető olyan jellemző, amely nem rendelkezik FID-del.", │ │ │ │ - browserNotSupported: "A böngészője nem támogatja a vektoros renderelést. A jelenleg támogatott renderelők:\n${renderers}", │ │ │ │ - minZoomLevelError: "A minZoomLevel tulajdonságot csak a következővel való használatra szánták: FixedZoomLevels-leszármazott fóliák. Ez azt jelenti, hogy a minZoomLevel wfs fólia jelölőnégyzetei már a múlté. Mi azonban nem távolíthatjuk el annak a veszélye nélkül, hogy az esetlegesen ettől függő OL alapú alkalmazásokat tönkretennénk. Ezért ezt érvénytelenítjük -- a minZoomLevel az alul levő jelölőnégyzet a 3.0-s verzióból el lesz távolítva. Kérjük, helyette használja a min/max felbontás beállítást, amelyről az alábbi helyen talál leírást: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "WFS tranzakció: SIKERES ${response}", │ │ │ │ - commitFailed: "WFS tranzakció: SIKERTELEN ${response}", │ │ │ │ - googleWarning: "A Google fólia betöltése sikertelen.<br><br>Ahhoz, hogy ez az üzenet eltűnjön, válasszon egy új BaseLayer fóliát a jobb felső sarokban található fóliakapcsoló segítségével.<br><br>Nagy valószínűséggel ez azért van, mert a Google Maps könyvtár parancsfájlja nem található, vagy nem tartalmazza az Ön oldalához tartozó megfelelő API-kulcsot.<br><br>Fejlesztőknek: A helyes működtetésre vonatkozó segítség az alábbi helyen érhető el, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>kattintson ide</a>", │ │ │ │ - getLayerWarning: "A(z) ${layerType} fólia nem töltődött be helyesen.<br><br>Ahhoz, hogy ez az üzenet eltűnjön, válasszon egy új BaseLayer fóliát a jobb felső sarokban található fóliakapcsoló segítségével.<br><br>Nagy valószínűséggel ez azért van, mert a(z) ${layerLib} könyvtár parancsfájlja helytelen.<br><br>Fejlesztőknek: A helyes működtetésre vonatkozó segítség az alábbi helyen érhető el, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>kattintson ide</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Lépték = 1 : ${scaleDenom}", │ │ │ │ - W: "Ny", │ │ │ │ - E: "K", │ │ │ │ - N: "É", │ │ │ │ - S: "D", │ │ │ │ - reprojectDeprecated: "Ön a 'reproject' beállítást használja a(z) ${layerName} fólián. Ez a beállítás érvénytelen: használata az üzleti alaptérképek fölötti adatok megjelenítésének támogatására szolgált, de ezt a funkció ezentúl a Gömbi Mercator használatával érhető el. További információ az alábbi helyen érhető el: http://trac.openlayers.org/wiki/SphericalMercator", │ │ │ │ - methodDeprecated: "Ez a módszer érvénytelenítve lett és a 3.0-s verzióból el lesz távolítva. Használja a(z) ${newMethod} módszert helyette." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["bg"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - Permalink: "Постоянна препратка", │ │ │ │ - "Base Layer": "Основен слой", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Мащаб = 1 : ${scaleDenom}", │ │ │ │ - methodDeprecated: "Този метод е остарял и ще бъде премахват в 3.0. Вместо него използвайте ${newMethod}." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang.ro = { │ │ │ │ - unhandledRequest: "Cerere nesoluționată return ${statusText}", │ │ │ │ - Permalink: "Legatură permanentă", │ │ │ │ - Overlays: "Straturi vector", │ │ │ │ - "Base Layer": "Straturi de bază", │ │ │ │ - noFID: "Nu pot actualiza un feature pentru care nu există FID.", │ │ │ │ - browserNotSupported: "Browserul tău nu suportă afișarea vectorilor. Supoetul curent pentru randare:\n${renderers}", │ │ │ │ - minZoomLevelError: "Proprietatea minZoomLevel este doar pentru a fi folosită " + "cu straturile FixedZoomLevels-descendent. De aceea acest " + "strat wfs verifică dacă minZoomLevel este o relicvă" + ". Nu îl putem , oricum, înlătura fără " + "a afecta aplicațiile Openlayers care depind de ea." + " De aceea considerăm depreciat -- minZoomLevel " + "și îl vom înlătura în 3.0. Folosește " + "min/max resolution cum este descrisă aici: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "Tranzacție WFS: SUCCES ${response}", │ │ │ │ - commitFailed: "Tranzacție WFS : EȘEC ${response}", │ │ │ │ - googleWarning: "Stratul Google nu a putut fi încărcat corect.<br><br>" + "Pentru a elimina acest mesaj, selectează un nou strat de bază " + "în Layerswitcher din colțul dreata-sus.<br><br>" + "Asta datorită, faptului că Google Maps library " + "script nu este inclus, sau nu conține " + "cheia API corectă pentru situl tău.<br><br>" + "Developeri: Pentru ajutor, " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>apăsați aici</a>", │ │ │ │ - getLayerWarning: "Stratul ${layerType} nu a putut fi încărcat corect.<br><br>" + "pentru a înlătura acest mesaj, selectează un nou strat de bază " + "Acesta eroare apare de obicei când ${layerLib} library " + "script nu a fost încărcat corect.<br><br>" + "Developeri: Pentru ajutor privind utilizarea corectă, " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>apasă aici</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Scara = 1 : ${scaleDenom}", │ │ │ │ - W: "V", │ │ │ │ - E: "E", │ │ │ │ - N: "N", │ │ │ │ - S: "S", │ │ │ │ - Graticule: "Graticule", │ │ │ │ - reprojectDeprecated: "folosești opțiunea 'reproject' " + "pentru stratul ${layerName} . Această opțiune este depreciată: " + "a fost utilizată pentru afișarea straturilor de bază comerciale " + "Mai multe informații despre proiecția Mercator sunt disponibile aici " + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Această metodă este depreciată și va fi înlăturată in versiunea 3.0. " + "folosește metoda ${newMethod}.", │ │ │ │ - end: "" │ │ │ │ -}; │ │ │ │ -OpenLayers.Lang["da-DK"] = { │ │ │ │ - unhandledRequest: "En ikke håndteret forespørgsel returnerede ${statusText}", │ │ │ │ - Permalink: "Permalink", │ │ │ │ - Overlays: "Kortlag", │ │ │ │ - "Base Layer": "Baggrundslag", │ │ │ │ - noFID: "Kan ikke opdateret en feature (et objekt) der ikke har et FID.", │ │ │ │ - browserNotSupported: "Din browser understøtter ikke vektor visning. Følgende vektor visninger understøttes:\n${renderers}", │ │ │ │ - minZoomLevelError: "Egenskaben minZoomLevel er kun beregnet til brug " + "med FixedZoomLevels. At dette WFS lag kontrollerer " + "minZoomLevel egenskaben, er et levn fra en tidligere " + "version. Vi kan desværre ikke fjerne dette uden at risikere " + "at ødelægge eksisterende OL baserede programmer der " + " benytter denne funktionalitet. " + "Egenskaben bør derfor ikke anvendes, og minZoomLevel " + "kontrollen herunder vil blive fjernet i version 3.0. " + "Benyt istedet min/max opløsnings indstillingerne, som " + "er beskrevet her: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "WFS transaktion: LYKKEDES ${response}", │ │ │ │ - commitFailed: "WFS transaktion: MISLYKKEDES ${response}", │ │ │ │ - googleWarning: "Google laget kunne ikke indlæses.<br><br>" + "For at fjerne denne besked, vælg et nyt bagrundskort i " + "lagskifteren i øverste højre hjørne.<br><br>" + "Fejlen skyldes formentlig at Google Maps bibliotekts " + "scriptet ikke er inkluderet, eller ikke indeholder den " + "korrkte API nøgle for dit site.<br><br>" + "Udviklere: For hjælp til at få dette til at fungere, " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>klik her</a>", │ │ │ │ - getLayerWarning: "${layerType}-laget kunne ikke indlæses.<br><br>" + "For at fjerne denne besked, vælg et nyt bagrundskort i " + "lagskifteren i øverste højre hjørne.<br><br>" + "Fejlen skyldes formentlig at ${layerLib} bibliotekts " + "scriptet ikke er inkluderet.<br><br>" + "Udviklere: For hjælp til at få dette til at fungere, " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>klik her</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Målforhold = 1 : ${scaleDenom}", │ │ │ │ - reprojectDeprecated: "Du anvender indstillingen 'reproject' på laget ${layerName}." + "Denne indstilling bør ikke længere anvendes. Den var beregnet " + "til at vise data ovenpå kommercielle grundkort, men den funktionalitet " + "bør nu opnås ved at anvende Spherical Mercator understøttelsen. " + "Mere information er tilgængelig her: " + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Denne funktion bør ikke længere anvendes, og vil blive fjernet i version 3.0. " + "Anvend venligst funktionen ${newMethod} istedet." │ │ │ │ -}; │ │ │ │ -OpenLayers.Lang["fr"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Requête non gérée, retournant ${statusText}", │ │ │ │ - Permalink: "Permalien", │ │ │ │ - Overlays: "Calques", │ │ │ │ - "Base Layer": "Calque de base", │ │ │ │ - noFID: "Impossible de mettre à jour un objet sans identifiant (fid).", │ │ │ │ - browserNotSupported: "Votre navigateur ne supporte pas le rendu vectoriel. Les renderers actuellement supportés sont : \n${renderers}", │ │ │ │ - minZoomLevelError: "La propriété minZoomLevel doit seulement être utilisée pour des couches FixedZoomLevels-descendent. Le fait que cette couche WFS vérifie la présence de minZoomLevel est une relique du passé. Nous ne pouvons toutefois la supprimer sans casser des applications qui pourraient en dépendre. C'est pourquoi nous la déprécions -- la vérification du minZoomLevel sera supprimée en version 3.0. A la place, merci d'utiliser les paramètres de résolutions min/max tel que décrit sur : http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "Transaction WFS : SUCCES ${response}", │ │ │ │ - commitFailed: "Transaction WFS : ECHEC ${response}", │ │ │ │ - googleWarning: "La couche Google n'a pas été en mesure de se charger correctement.<br><br>Pour supprimer ce message, choisissez une nouvelle BaseLayer dans le sélecteur de couche en haut à droite.<br><br>Cela est possiblement causé par la non-inclusion de la librairie Google Maps, ou alors parce que la clé de l'API ne correspond pas à votre site.<br><br>Développeurs : pour savoir comment corriger ceci, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>cliquez ici</a>", │ │ │ │ - getLayerWarning: "La couche ${layerType} n'est pas en mesure de se charger correctement.<br><br>Pour supprimer ce message, choisissez une nouvelle BaseLayer dans le sélecteur de couche en haut à droite.<br><br>Cela est possiblement causé par la non-inclusion de la librairie ${layerLib}.<br><br>Développeurs : pour savoir comment corriger ceci, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>cliquez ici</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Echelle ~ 1 : ${scaleDenom}", │ │ │ │ - W: "O", │ │ │ │ - E: "E", │ │ │ │ - N: "N", │ │ │ │ - S: "S", │ │ │ │ - reprojectDeprecated: "Vous utilisez l'option 'reproject' sur la couche ${layerName}. Cette option est dépréciée : Son usage permettait d'afficher des données au dessus de couches raster commerciales.Cette fonctionalité est maintenant supportée en utilisant le support de la projection Mercator Sphérique. Plus d'information est disponible sur http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Cette méthode est dépréciée, et sera supprimée à la version 3.0. Merci d'utiliser ${newMethod} à la place." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["sv"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Ej hanterad fråga retur ${statusText}", │ │ │ │ - Permalink: "Permalänk", │ │ │ │ - Overlays: "Kartlager", │ │ │ │ - "Base Layer": "Bakgrundskarta", │ │ │ │ - noFID: "Kan ej uppdatera feature (objekt) för vilket FID saknas.", │ │ │ │ - browserNotSupported: "Din webbläsare stöder inte vektorvisning. För närvarande stöds följande visning:\n${renderers}", │ │ │ │ - minZoomLevelError: "Egenskapen minZoomLevel är endast avsedd att användas med lager med FixedZoomLevels. Att detta WFS-lager kontrollerar minZoomLevel är en relik från äldre versioner. Vi kan dock inte ta bort det utan att riskera att OL-baserade tillämpningar som använder detta slutar fungera. Därför är det satt som deprecated, minZoomLevel kommer att tas bort i version 3.0. Använd i stället inställning av min/max resolution som beskrivs här: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "WFS-transaktion: LYCKADES ${response}", │ │ │ │ - commitFailed: "WFS-transaktion: MISSLYCKADES ${response}", │ │ │ │ - googleWarning: "Google-lagret kunde inte laddas korrekt.<br><br>För att slippa detta meddelande, välj en annan bakgrundskarta i lagerväljaren i övre högra hörnet.<br><br>Sannolikt beror felet på att Google Maps-biblioteket inte är inkluderat på webbsidan eller på att sidan inte anger korrekt API-nyckel för webbplatsen.<br><br>Utvecklare: hjälp för att åtgärda detta, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>klicka här</a>.", │ │ │ │ - getLayerWarning: "${layerType}-lagret kunde inte laddas korrekt.<br><br>För att slippa detta meddelande, välj en annan bakgrundskarta i lagerväljaren i övre högra hörnet.<br><br>Sannolikt beror felet på att ${layerLib}-biblioteket inte är inkluderat på webbsidan.<br><br>Utvecklare: hjälp för att åtgärda detta, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>klicka här</a>.", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "<strong>Skala</strong> 1 : ${scaleDenom}", │ │ │ │ - reprojectDeprecated: "Du använder inställningen 'reproject' på lagret ${layerName}. Denna inställning markerad som deprecated: den var avsedd att användas för att stödja visning av kartdata på kommersiella bakgrundskartor, men nu bör man i stället använda Spherical Mercator-stöd för den funktionaliteten. Mer information finns på http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Denna metod är markerad som deprecated och kommer att tas bort i 3.0. Använd ${newMethod} i stället." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["gsw"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Nit behandleti Aafrogsruckmäldig ${statusText}", │ │ │ │ - Permalink: "Permalink", │ │ │ │ - Overlays: "Iberlagerige", │ │ │ │ - "Base Layer": "Grundcharte", │ │ │ │ - noFID: "E Feature, wu s kei FID derfir git, cha nit aktualisiert wäre.", │ │ │ │ - browserNotSupported: "Dyy Browser unterstitzt kei Vektordarstellig. Aktuäll unterstitzti Renderer:\n${renderers}", │ │ │ │ - minZoomLevelError: "D minZoomLevel-Eigeschaft isch nume dänk fir d Layer, wu vu dr FixedZoomLevels abstamme. Ass dää wfs-Layer minZoomLevel prieft, scih e Relikt us dr Vergangeheit. Mir chenne s aber nit ändere ohni OL_basierti Aawändige villicht kaputt gehn, wu dervu abhänge. Us däm Grund het die Funktion d Eigeschaft 'deprecated' iberchuu. D minZoomLevel-Priefig unte wird in dr Version 3.0 usegnuu. Bitte verwänd statt däm e min/max-Uflesig wie s do bschriben isch: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "WFS-Transaktion: ERFOLGRYCH ${response}", │ │ │ │ - commitFailed: "WFS-Transaktion: FÄHLGSCHLAA ${response}", │ │ │ │ - googleWarning: "Dr Google-Layer het nit korräkt chenne glade wäre.<br><br>Go die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.<br><br>Dää Fähler git s seli hyfig, wel s Skript vu dr Google-Maps-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.<br><br>Entwickler: Fir Hilf zum korräkte Yybinde vum Google-Layer <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>doo drucke</a>", │ │ │ │ - getLayerWarning: "Dr ${layerType}-Layer het nit korräkt chenne glade wäre.<br><br>Go die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.<br><br>Dää Fähler git s seli hyfig, wel s Skript vu dr '${layerLib}'-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.<br><br>Entwickler: Fir Hilf zum korräkte Yybinde vu Layer <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>doo drucke</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Maßstab = 1 : ${scaleDenom}", │ │ │ │ - W: "W", │ │ │ │ - E: "O", │ │ │ │ - N: "N", │ │ │ │ - S: "S", │ │ │ │ - reprojectDeprecated: "Du bruchsch d 'reproject'-Option bim ${layerName}-Layer. Die Option isch nimi giltig: si isch aagleit wore go Date iber kommerziälli Grundcharte lege, aber des sott mer jetz mache mit dr Unterstitzig vu Spherical Mercator. Meh Informatione git s uf http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Die Methode isch veraltet un wird us dr Version 3.0 usegnuu. Bitte verwäbnd statt däm ${newMethod}." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["hsb"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Wotmołwa njewobdźěłaneho naprašowanja ${statusText}", │ │ │ │ - Permalink: "Trajny wotkaz", │ │ │ │ - Overlays: "Naworštowanja", │ │ │ │ - "Base Layer": "Zakładna runina", │ │ │ │ - noFID: "Funkcija, za kotruž FID njeje, njeda so aktualizować.", │ │ │ │ - browserNotSupported: "Twój wobhladowak wektorowe rysowanje njepodpěruje. Tuchwilu podpěrowane rysowaki su:\n${renderers}", │ │ │ │ - minZoomLevelError: "Kajkosć minZoomLevel je jenož za wužiwanje z worštami myslena, kotrež wot FixedZoomLevels pochadźeja. Zo tuta woršta wfs za minZoomLevel přepruwuje, je relikt zańdźenosće. Njemóžemy wšak ju wotstronić, bjeztoho zo aplikacije, kotrež na OpenLayers bazěruja a snano tutu kajkosć wužiwaja, hižo njefunguja. Tohodla smy ju jako zestarjenu woznamjenili -- přepruwowanje za minZoomLevel budu so we wersiji 3.0 wotstronjeć. Prošu wužij město toho nastajenje min/max, kaž je tu wopisane: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "WFS-Transakcija: WUSPĚŠNA ${response}", │ │ │ │ - commitFailed: "WFS-Transakcija: NJEPORADŹENA ${response}", │ │ │ │ - googleWarning: "Woršta Google njemóžeše so korektnje začitać.<br><br>Zo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.<br><br>Najskerje so to stawa, dokelž skript biblioteki Google Maps pak njebu zapřijaty pak njewobsahuje korektny kluč API za twoje sydło.<br><br>Wuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n<a href='http://trac.openlayers.org/wiki/Google' target='_blank'>tu kliknyć</a>", │ │ │ │ - getLayerWarning: "Woršta ${layerType} njemóžeše so korektnje začitać.<br><br>Zo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.<br><br>Najskerje so to stawa, dokelž skript biblioteki ${layerLib} njebu korektnje zapřijaty.<br><br>Wuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n<a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>tu kliknyć</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Měritko = 1 : ${scaleDenom}", │ │ │ │ - W: "Z", │ │ │ │ - E: "W", │ │ │ │ - N: "S", │ │ │ │ - S: "J", │ │ │ │ - reprojectDeprecated: 'Wužiwaš opciju "reproject" wořšty ${layerName}. Tuta opcija je zestarjena: jeje wužiwanje bě myslene, zo by zwobraznjenje datow nad komercielnymi bazowymi kartami podpěrało, ale funkcionalnosć měła so nětko z pomocu Sperical Mercator docpěć. Dalše informacije steja na http://trac.openlayers.org/wiki/SphericalMercator k dispoziciji.', │ │ │ │ - methodDeprecated: "Tuta metoda je so njeschwaliła a budźe so w 3.0 wotstronjeć. Prošu wužij ${newMethod} město toho." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["te"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - Permalink: "స్థిరలింకు", │ │ │ │ - W: "ప", │ │ │ │ - E: "తూ", │ │ │ │ - N: "ఉ", │ │ │ │ - S: "ద" │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["el"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Κλίμακα ~ 1 : ${scaleDenom}" │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["de"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Unbehandelte Anfragerückmeldung ${statusText}", │ │ │ │ - Permalink: "Permalink", │ │ │ │ - Overlays: "Overlays", │ │ │ │ - "Base Layer": "Grundkarte", │ │ │ │ - noFID: "Ein Feature, für das keine FID existiert, kann nicht aktualisiert werden.", │ │ │ │ - browserNotSupported: "Ihr Browser unterstützt keine Vektordarstellung. Aktuell unterstützte Renderer:\n${renderers}", │ │ │ │ - minZoomLevelError: "Die <code>minZoomLevel</code>-Eigenschaft ist nur für die Verwendung mit <code>FixedZoomLevels</code>-untergeordneten Layers vorgesehen. Das dieser <tt>wfs</tt>-Layer die <code>minZoomLevel</code>-Eigenschaft überprüft ist ein Relikt der Vergangenheit. Wir können diese Überprüfung nicht entfernen, ohne das OL basierende Applikationen nicht mehr funktionieren. Daher markieren wir es als veraltet - die <code>minZoomLevel</code>-Überprüfung wird in Version 3.0 entfernt werden. Bitte verwenden Sie stattdessen die Min-/Max-Lösung, wie sie unter http://trac.openlayers.org/wiki/SettingZoomLevels beschrieben ist.", │ │ │ │ - commitSuccess: "WFS-Transaktion: Erfolgreich ${response}", │ │ │ │ - commitFailed: "WFS-Transaktion: Fehlgeschlagen ${response}", │ │ │ │ - googleWarning: "Der Google-Layer konnte nicht korrekt geladen werden.<br><br>Um diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.<br><br>Sehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der Google-Maps-Bibliothek nicht eingebunden wurde oder keinen gültigen API-Schlüssel für Ihre URL enthält.<br><br>Entwickler: Besuche <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>das Wiki</a> für Hilfe zum korrekten Einbinden des Google-Layers", │ │ │ │ - getLayerWarning: "Der ${layerType}-Layer konnte nicht korrekt geladen werden.<br><br>Um diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.<br><br>Sehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der '${layerLib}'-Bibliothek nicht eingebunden wurde.<br><br>Entwickler: Besuche <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>das Wiki</a> für Hilfe zum korrekten Einbinden von Layern", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Maßstab = 1 : ${scaleDenom}", │ │ │ │ - W: "W", │ │ │ │ - E: "O", │ │ │ │ - N: "N", │ │ │ │ - S: "S", │ │ │ │ - reprojectDeprecated: "Sie verwenden die „Reproject“-Option des Layers ${layerName}. Diese Option ist veraltet: Sie wurde entwickelt um die Anzeige von Daten auf kommerziellen Basiskarten zu unterstützen, aber diese Funktion sollte jetzt durch Unterstützung der „Spherical Mercator“ erreicht werden. Weitere Informationen sind unter http://trac.openlayers.org/wiki/SphericalMercator verfügbar.", │ │ │ │ - methodDeprecated: "Die Methode ist veraltet und wird in 3.0 entfernt. Bitte verwende stattdessen ${newMethod}." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["pt"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Servidor devolveu erro não contemplado ${statusText}", │ │ │ │ - Permalink: "Ligação permanente", │ │ │ │ - Overlays: "Sobreposições", │ │ │ │ - "Base Layer": "Camada Base", │ │ │ │ - noFID: "Não é possível atualizar um elemento para a qual não há FID.", │ │ │ │ - browserNotSupported: "O seu navegador não suporta renderização vetorial. Actualmente os renderizadores suportados são:\n${renderers}", │ │ │ │ - minZoomLevelError: "A propriedade minZoomLevel só deve ser usada com as camadas descendentes da FixedZoomLevels. A verificação da propriedade por esta camada wfs é uma relíquia do passado. No entanto, não podemos removê-la sem correr o risco de afectar aplicações OL que dependam dela. Portanto, estamos a torná-la obsoleta -- a verificação minZoomLevel será removida na versão 3.0. Em vez dela, por favor, use as opções de resolução min/max descritas aqui: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "Transacção WFS: SUCESSO ${response}", │ │ │ │ - commitFailed: "Transacção WFS: FALHOU ${response}", │ │ │ │ - googleWarning: "A Camada Google não foi correctamente carregada.<br><br>Para deixar de receber esta mensagem, seleccione uma nova Camada-Base no ''switcher'' de camadas no canto superior direito.<br><br>Provavelmente, isto acontece porque o ''script'' da biblioteca do Google Maps não foi incluído ou não contém a chave API correcta para o seu sítio.<br><br>Programadores: Para ajuda sobre como solucionar o problema <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>clique aqui</a> .", │ │ │ │ - getLayerWarning: "A camada ${layerType} não foi correctamente carregada.<br><br>Para desactivar esta mensagem, seleccione uma nova Camada-Base no ''switcher'' de camadas no canto superior direito.<br><br>Provavelmente, isto acontece porque o ''script'' da biblioteca ${layerLib} não foi incluído correctamente.<br><br>Programadores: Para ajuda sobre como solucionar o problema <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>clique aqui</a> .", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Escala = 1 : ${scaleDenom}", │ │ │ │ - W: "O", │ │ │ │ - E: "E", │ │ │ │ - N: "N", │ │ │ │ - S: "S", │ │ │ │ - reprojectDeprecated: "Está usando a opção 'reproject' na camada ${layerName}. Esta opção é obsoleta: foi concebida para permitir a apresentação de dados sobre mapas-base comerciais, mas esta funcionalidade é agora suportada pelo Mercator Esférico. Mais informação está disponível em http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Este método foi declarado obsoleto e será removido na versão 3.0. Por favor, use ${newMethod} em vez disso." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["pt-BR"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "A requisição retornou um erro não tratado: ${statusText}", │ │ │ │ - Permalink: "Link para essa página", │ │ │ │ - Overlays: "Camadas de Sobreposição", │ │ │ │ - "Base Layer": "Camada Base", │ │ │ │ - noFID: "Não é possível atualizar uma feição que não tenha um FID.", │ │ │ │ - browserNotSupported: "Seu navegador não suporta renderização de vetores. Os renderizadores suportados atualmente são:\n${renderers}", │ │ │ │ - minZoomLevelError: "A propriedade minZoomLevel é de uso restrito das camadas descendentes de FixedZoomLevels. A verificação dessa propriedade pelas camadas wfs é um resíduo do passado. Não podemos, entretanto não é possível removê-la sem possívelmente quebrar o funcionamento de aplicações OL que possuem depência com ela. Portanto estamos tornando seu uso obsoleto -- a verificação desse atributo será removida na versão 3.0. Ao invés, use as opções de resolução min/max como descrito em: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "Transação WFS : SUCESSO ${response}", │ │ │ │ - commitFailed: "Transação WFS : ERRO ${response}", │ │ │ │ - googleWarning: "Não foi possível carregar a camada Google corretamente.<br><br>Para se livrar dessa mensagem, selecione uma nova Camada Base, na ferramenta de alternação de camadas localização do canto superior direito.<br><br>Muito provavelmente, isso foi causado porque o script da biblioteca do Google Maps não foi incluído, ou porque ele não contém a chave correta da API para o seu site.<br><br>Desenvolvedores: Para obter ajuda em solucionar esse problema <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>cliquem aqui</a>", │ │ │ │ - getLayerWarning: "Não foi possível carregar a camada ${layerType} corretamente.<br><br>Para se livrar dessa mensagem, selecione uma nova Camada Base, na ferramenta de alternação de camadas localização do canto superior direito.<br><br>Muito provavelmente, isso foi causado porque o script da biblioteca ${layerLib} não foi incluído corretamente.<br><br>Desenvolvedores: Para obter ajuda em solucionar esse problema <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>cliquem aqui</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Escala = 1 : ${scaleDenom}", │ │ │ │ - W: "O", │ │ │ │ - E: "L", │ │ │ │ - N: "N", │ │ │ │ - S: "S", │ │ │ │ - reprojectDeprecated: "Você está usando a opção 'reproject' na camada ${layerName}. Essa opção está obsoleta: seu uso foi projetado para suportar a visualização de dados sobre bases de mapas comerciais, entretanto essa funcionalidade deve agora ser alcançada usando o suporte à projeção Mercator. Mais informação está disponível em: http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Esse método está obsoleto e será removido na versão 3.0. Ao invés, por favor use ${newMethod}." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["nn"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Skala = 1 : ${scaleDenom}" │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["hr"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Nepodržani zahtjev ${statusText}", │ │ │ │ - Permalink: "Permalink", │ │ │ │ - Overlays: "Overlays", │ │ │ │ - "Base Layer": "Osnovna karta", │ │ │ │ - noFID: "Ne mogu ažurirati značajku za koju ne postoji FID.", │ │ │ │ - browserNotSupported: "Vaš preglednik ne podržava vektorsko renderiranje. Trenutno podržani rendereri su: ${renderers}", │ │ │ │ - commitSuccess: "WFS Transakcija: USPJEŠNA ${response}", │ │ │ │ - commitFailed: "WFS Transakcija: NEUSPJEŠNA ${response}", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Mjerilo = 1 : ${scaleDenom}", │ │ │ │ - methodDeprecated: "Ova metoda nije odobrena i biti će maknuta u 3.0. Koristite ${newMethod}." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["km"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - Permalink: "តំណភ្ជាប់អចិន្ត្រៃយ៍", │ │ │ │ - "Base Layer": "ស្រទាប់បាត​", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "មាត្រដ្ឋាន = ១ ៖ ${scaleDenom}" │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["pl"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Nieobsługiwane żądanie zwróciło ${statusText}", │ │ │ │ - Permalink: "Permalink", │ │ │ │ - Overlays: "Nakładki", │ │ │ │ - "Base Layer": "Warstwa podstawowa", │ │ │ │ - noFID: "Nie można zaktualizować funkcji, dla których nie ma FID.", │ │ │ │ - browserNotSupported: "Twoja przeglądarka nie obsługuje renderowania wektorów. Obecnie obsługiwane renderowanie to:\n${renderers}", │ │ │ │ - minZoomLevelError: "Właściwość minZoomLevel jest przeznaczona tylko do użytku " + "z warstwami FixedZoomLevels-descendent." + "Warstwa wfs, która sprawdza minZoomLevel jest reliktem przeszłości." + "Nie możemy jej jednak usunąc bez mozliwości łamania OL aplikacji, " + "które mogą być od niej zależne. " + "Dlatego jesteśmy za deprecjację -- minZoomLevel " + "zostanie usunięta w wersji 3.0. W zamian prosze użyj " + "min/max rozdzielczości w sposób opisany tutaj: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "Transakcja WFS: SUKCES ${response}", │ │ │ │ - commitFailed: "Transakcja WFS: FAILED ${response}", │ │ │ │ - googleWarning: "Warstwa Google nie był w stanie załadować się poprawnie.<br><br>" + "Aby pozbyć się tej wiadomości, wybierz nową Warstwe podstawową " + "w przełączniku warstw w górnym prawym rogu mapy.<br><br>" + "Najprawdopodobniej jest to spowodowane tym, że biblioteka Google Maps " + "nie jest załadowana, lub nie zawiera poprawnego klucza do API dla twojej strony<br><br>" + "Programisto: Aby uzyskać pomoc , " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>kliknij tutaj</a>", │ │ │ │ - getLayerWarning: "Warstwa ${layerType} nie mogła zostać załadowana poprawnie.<br><br>" + "Aby pozbyć się tej wiadomości, wybierz nową Warstwe podstawową " + "w przełączniku warstw w górnym prawym rogu mapy.<br><br>" + "Najprawdopodobniej jest to spowodowane tym, że biblioteka ${layerLib} " + "nie jest załadowana, lub może(o ile biblioteka tego wymaga) " + "byc potrzebny klucza do API dla twojej strony<br><br>" + "Programisto: Aby uzyskać pomoc , " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>kliknij tutaj</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Skala = 1 : ${scaleDenom}", │ │ │ │ - W: "ZACH", │ │ │ │ - E: "WSCH", │ │ │ │ - N: "PN", │ │ │ │ - S: "PD", │ │ │ │ - Graticule: "Siatka", │ │ │ │ - reprojectDeprecated: "w warstwie ${layerName} używasz opcji 'reproject'. " + "Ta opcja jest przestarzała: " + "jej zastosowanie został zaprojektowany, aby wspierać wyświetlania danych przez komercyjne mapy, " + "jednak obecnie ta funkcjonalność powinien zostać osiągnięty za pomocą Spherical Mercator " + "its use was designed to support displaying data over commercial. Więcje informacji na ten temat możesz znaleźć na stronie " + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Ta metoda jest przestarzała i będzie usunięta od wersji 3.0. " + "W zamian użyj ${newMethod}." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["fur"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - Permalink: "Leam Permanent", │ │ │ │ - Overlays: "Livei parsore", │ │ │ │ - "Base Layer": "Livel di base", │ │ │ │ - browserNotSupported: "Il to sgarfadôr nol supuarte la renderizazion vetoriâl. Al moment a son supuartâts:\n${renderers}", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Scjale = 1 : ${scaleDenom}", │ │ │ │ - W: "O", │ │ │ │ - E: "E", │ │ │ │ - N: "N", │ │ │ │ - S: "S" │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang.es = { │ │ │ │ - unhandledRequest: "Respuesta a petición no gestionada ${statusText}", │ │ │ │ - Permalink: "Enlace permanente", │ │ │ │ - Overlays: "Capas superpuestas", │ │ │ │ - "Base Layer": "Capa Base", │ │ │ │ - noFID: "No se puede actualizar un elemento para el que no existe FID.", │ │ │ │ - browserNotSupported: "Su navegador no soporta renderización vectorial. Los renderizadores soportados actualmente son:\n${renderers}", │ │ │ │ - minZoomLevelError: "La propiedad minZoomLevel debe sólo utilizarse " + "con las capas que tienen FixedZoomLevels. El hecho de que " + "una capa wfs compruebe minZoomLevel es una reliquia del " + "pasado. Sin embargo, no podemos eliminarla sin discontinuar " + "probablemente las aplicaciones OL que puedan depender de ello. " + "Así pues estamos haciéndolo obsoleto --la comprobación " + "minZoomLevel se eliminará en la versión 3.0. Utilice el ajuste " + "de resolution min/max en su lugar, tal como se describe aquí: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "Transacción WFS: ÉXITO ${response}", │ │ │ │ - commitFailed: "Transacción WFS: FALLÓ ${response}", │ │ │ │ - googleWarning: "La capa Google no pudo ser cargada correctamente.<br><br>" + "Para evitar este mensaje, seleccione una nueva Capa Base " + "en el selector de capas en la esquina superior derecha.<br><br>" + "Probablemente, esto se debe a que el script de la biblioteca de " + "Google Maps no fue correctamente incluido en su página, o no " + "contiene la clave del API correcta para su sitio.<br><br>" + "Desarrolladores: Para ayudar a hacer funcionar esto correctamente, " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>haga clic aquí</a>", │ │ │ │ - getLayerWarning: "La capa ${layerType} no pudo ser cargada correctamente.<br><br>" + "Para evitar este mensaje, seleccione una nueva Capa Base " + "en el selector de capas en la esquina superior derecha.<br><br>" + "Probablemente, esto se debe a que el script de " + "la biblioteca ${layerLib} " + "no fue correctamente incluido en su página.<br><br>" + "Desarrolladores: Para ayudar a hacer funcionar esto correctamente, " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>haga clic aquí</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Escala = 1 : ${scaleDenom}", │ │ │ │ - W: "O", │ │ │ │ - E: "E", │ │ │ │ - N: "N", │ │ │ │ - S: "S", │ │ │ │ - Graticule: "Retícula", │ │ │ │ - reprojectDeprecated: "Está usando la opción 'reproject' en la capa " + "${layerName}. Esta opción es obsoleta: su uso fue diseñado " + "para soportar la visualización de datos sobre mapas base comerciales, " + "pero ahora esa funcionalidad debería conseguirse mediante el soporte " + "de la proyección Spherical Mercator. Más información disponible en " + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Este método es obsoleto y se eliminará en la versión 3.0. " + "Por favor utilice el método ${newMethod} en su lugar.", │ │ │ │ - end: "" │ │ │ │ -}; │ │ │ │ -OpenLayers.Lang["en-CA"] = OpenLayers.Util.applyDefaults({}, OpenLayers.Lang["en"]); │ │ │ │ -OpenLayers.Lang["ja"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "未処理の要求は ${statusText} を返します", │ │ │ │ - Permalink: "パーマリンク", │ │ │ │ - Overlays: "オーバーレイ", │ │ │ │ - "Base Layer": "基底レイヤー", │ │ │ │ - noFID: "FID のない地物は更新できません。", │ │ │ │ - browserNotSupported: "あなたのブラウザはベクターグラフィックスの描写に対応していません。現時点で対応しているソフトウェアは以下のものです。\n${renderers}", │ │ │ │ - minZoomLevelError: "minZoomLevel プロパティは FixedZoomLevels を継承するレイヤーでの使用のみを想定しています。この minZoomLevel に対する WFS レイヤーの検査は歴史的なものです。しかしながら、この検査を除去するとそれに依存する OpenLayers ベースのアプリケーションを破壊してしまう可能性があります。よって廃止が予定されており、この minZoomLevel 検査はバージョン3.0で除去されます。代わりに、http://trac.openlayers.org/wiki/SettingZoomLevels で解説されている、最小および最大解像度設定を使用してください。", │ │ │ │ - commitSuccess: "WFS トランザクション: 成功 ${response}", │ │ │ │ - commitFailed: "WFS トランザクション: 失敗 ${response}", │ │ │ │ - googleWarning: "Google レイヤーが正しく読み込みを行えませんでした。<br><br>このメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。<br><br>おそらく、これは Google マップ用ライブラリのスクリプトが組み込まれていないか、あなたのサイトに対応する正しい API キーが設定されていないためです。<br><br>開発者の方へ: 正しい動作をさせるために<a href='http://trac.openlayers.org/wiki/Google' target='_blank'>こちらのウィキ</a>を参照してください。", │ │ │ │ - getLayerWarning: "${layerType} レイヤーが正しく読み込みを行えませんでした。<br><br>このメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。<br><br>おそらく、これは ${layerLib} ライブラリのスクリプトが正しく組み込まれていないためです。<br><br>開発者の方へ: 正しい動作をさせるために<a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>こちらのウィキ</a>を参照してください。", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "縮尺 = 1 : ${scaleDenom}", │ │ │ │ - W: "西", │ │ │ │ - E: "東", │ │ │ │ - N: "北", │ │ │ │ - S: "南", │ │ │ │ - reprojectDeprecated: "あなたは「${layerName}」レイヤーで reproject オプションを使っています。このオプションは商用の基底地図上に情報を表示する目的で設計されましたが、現在ではその機能は Spherical Mercator サポートを利用して実現されており、このオプションの使用は非推奨です。追加の情報は http://trac.openlayers.org/wiki/SphericalMercator で入手できます。", │ │ │ │ - methodDeprecated: "このメソッドは廃止が予定されており、バージョン3.0で除去されます。代わりに ${newMethod} を使用してください。" │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["fi"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - Permalink: "Ikilinkki", │ │ │ │ - Overlays: "Kerrokset", │ │ │ │ - "Base Layer": "Peruskerros", │ │ │ │ - W: "L", │ │ │ │ - E: "I", │ │ │ │ - N: "P", │ │ │ │ - S: "E" │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang.it = { │ │ │ │ - unhandledRequest: "Codice di ritorno della richiesta ${statusText}", │ │ │ │ - Permalink: "Permalink", │ │ │ │ - Overlays: "Overlays", │ │ │ │ - "Base Layer": "Livello base", │ │ │ │ - noFID: "Impossibile aggiornare un elemento grafico che non abbia il FID.", │ │ │ │ - browserNotSupported: "Il tuo browser non supporta il rendering vettoriale. I renderizzatore attualemnte supportati sono:\n${renderers}", │ │ │ │ - minZoomLevelError: "La proprietà minZoomLevel è da utilizzare solamente " + "con livelli che abbiano FixedZoomLevels. Il fatto che " + "questo livello wfs controlli la proprietà minZoomLevel è " + "un retaggio del passato. Non possiamo comunque rimuoverla " + "senza rompere le vecchie applicazioni che dipendono su di essa." + "Quindi siamo costretti a deprecarla -- minZoomLevel " + "e sarà rimossa dalla vesione 3.0. Si prega di utilizzare i " + "settaggi di risoluzione min/max come descritto qui: " + "http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "Transazione WFS: SUCCESS ${response}", │ │ │ │ - commitFailed: "Transazione WFS: FAILED ${response}", │ │ │ │ - googleWarning: "Il livello Google non è riuscito a caricare correttamente.<br><br>" + "Per evitare questo messaggio, seleziona un nuovo BaseLayer " + "nel selettore di livelli nell'angolo in alto a destra.<br><br>" + "Più precisamente, ciò accade perchè la libreria Google Maps " + "non è stata inclusa nella pagina, oppure non contiene la " + "corretta API key per il tuo sito.<br><br>" + "Sviluppatori: Per aiuto su come farlo funzionare correttamente, " + "<a href='http://trac.openlayers.org/wiki/Google' " + "target='_blank'>clicca qui</a>", │ │ │ │ - getLayerWarning: "Il livello ${layerType} non è riuscito a caricare correttamente.<br><br>" + "Per evitare questo messaggio, seleziona un nuovo BaseLayer " + "nel selettore di livelli nell'angolo in alto a destra.<br><br>" + "Più precisamente, ciò accade perchè la libreria ${layerLib} " + "non è stata inclusa nella pagina.<br><br>" + "Sviluppatori: Per aiuto su come farlo funzionare correttamente, " + "<a href='http://trac.openlayers.org/wiki/${layerLib}' " + "target='_blank'>clicca qui</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Scala = 1 : ${scaleDenom}", │ │ │ │ - reprojectDeprecated: "Stai utilizzando l'opzione 'reproject' sul livello ${layerName}. " + "Questa opzione è deprecata: il suo utilizzo è stato introdotto per" + "supportare il disegno dei dati sopra mappe commerciali, ma tale " + "funzionalità dovrebbe essere ottenuta tramite l'utilizzo della proiezione " + "Spherical Mercator. Per maggiori informazioni consultare qui " + "http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Questo metodo è stato deprecato e sarà rimosso dalla versione 3.0. " + "Si prega di utilizzare il metodo ${newMethod} in alternativa.", │ │ │ │ - end: "" │ │ │ │ -}; │ │ │ │ -OpenLayers.Lang["lt"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Neapdorota užklausa gražino ${statusText}", │ │ │ │ - Permalink: "Pastovi nuoroda", │ │ │ │ - Overlays: "Papildomi sluoksniai", │ │ │ │ - "Base Layer": "Pagrindinis sluoksnis", │ │ │ │ - noFID: "Negaliu atnaujinti objekto, kuris neturi FID.", │ │ │ │ - browserNotSupported: "Jūsų naršyklė nemoka parodyti vektorių. Šiuo metu galima naudotis tokiais rodymo varikliais:\n{renderers}", │ │ │ │ - commitSuccess: "WFS Tranzakcija: PAVYKO ${response}", │ │ │ │ - commitFailed: "WFS Tranzakcija: ŽLUGO ${response}", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Mastelis = 1 : ${scaleDenom}", │ │ │ │ - W: "V", │ │ │ │ - E: "R", │ │ │ │ - N: "Š", │ │ │ │ - S: "P", │ │ │ │ - Graticule: "Tinklelis", │ │ │ │ - methodDeprecated: "Šis metodas yra pasenęs ir 3.0 versijoje bus pašalintas. " + "Prašome naudoti ${newMethod}.", │ │ │ │ - end: "" │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["ksh"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Met dä Antwoot op en Aanfrooch ham_mer nix aanjefange: ${statusText}", │ │ │ │ - Permalink: "Lengk op Duuer", │ │ │ │ - Overlays: "Drövver jelaat", │ │ │ │ - "Base Layer": "Jrund-Nivoh", │ │ │ │ - noFID: 'En Saach, woh kein <i lang="en">FID</i> för doh es, löht sesch nit ändere.', │ │ │ │ - browserNotSupported: "Dinge Brauser kann kein Väktore ußjävve. De Zoote Ußjaabe, di em Momang jon, sen:\n${renderers}", │ │ │ │ - minZoomLevelError: 'De Eijeschaff „<code lang="en">minZoomLevel</code>“ es bloß doför jedaach, dat mer se met dä Nivvohß bruch, di vun <code lang="en">FixedZoomLevels</code> affhange don. Dat dat <i lang="en">WFS</i>-Nivvoh övverhoup de Eijeschaff „<code lang="en">minZoomLevel</code>“ pröhfe deiht, es noch övveresch vun fröhjer. Mer künne dat ävver jez nit fott lohße, oohne dat mer Jevaa loufe, dat Aanwendunge vun OpenLayers nit mieh loufe, di sesch doh velleijsch noch drop am verlohße sin. Dröm sare mer, dat mer et nit mieh han welle, un de „<code lang="en">minZoomLevel</code>“-Eijeschaff weed hee vun de Version 3.0 af nit mieh jeprööf wäde. Nemm doför de Enstellung för de hühßte un de kleinßte Oplöhsung, esu wi et en http://trac.openlayers.org/wiki/SettingZoomLevels opjeschrevve es.', │ │ │ │ - commitSuccess: 'Dä <i lang="en">WFS</i>-Vörjang es joot jeloufe: ${response}', │ │ │ │ - commitFailed: 'Dä <i lang="en">WFS</i>-Vörjang es scheif jejange: ${response}', │ │ │ │ - googleWarning: 'Dat Nivvoh <code lang="en">Google</code> kunnt nit reschtesch jelaade wääde.<br /><br />Öm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhke, rähß bovve en de Äk.<br /><br />Wascheinlesch es dat wiel dat <i lang="en">Google-Maps</i>-Skrepp entweeder nit reschtesch enjebonge wood, udder nit dä reschtejje <i lang="en">API</i>-Schlößel för Ding Web-ßait scheke deiht.<br /><br />För Projrammierer jidd_et Hölp do_drövver, <a href="http://trac.openlayers.org/wiki/Google" target="_blank">wi mer dat aan et Loufe brengk</a>.', │ │ │ │ - getLayerWarning: 'Dat Nivvoh <code>${layerType}</code> kunnt nit reschtesch jelaade wääde.<br /><br />Öm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhkre, rähß bovve en de Äk.<br /><br />Wascheinlesch es dat, wiel dat Skrepp <code>${layerLib}</code> nit reschtesch enjebonge wood.<br /><br />För Projrammierer jidd_Et Hölp do_drövver, <a href="http://trac.openlayers.org/wiki/${layerLib}" target="_blank">wi mer dat aan et Loufe brengk</a>.', │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Mohßshtaab = 1 : ${scaleDenom}", │ │ │ │ - W: "W", │ │ │ │ - E: "O", │ │ │ │ - N: "N", │ │ │ │ - S: "S", │ │ │ │ - reprojectDeprecated: "Do bruchs de Ußwahl <code>reproject</code> op däm Nivvoh <code>${layerName}</code>. Di Ußwahl es nit mieh jähn jesinn. Se wohr doför jedaach, öm Date op jeschääfsmäßesch eruß jejovve Kaate bovve drop ze moole, wat ävver enzwesche besser met dä Öngershtözung för de ßfääresche Mäkaator Beldscher jeiht. Doh kanns De mieh drövver fenge op dä Sigg: http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Hee di Metood es nim_mih aktoäll un et weed se en dä Version 3.0 nit mieh jävve. Nemm <code>${newMethod}</code> doföör." │ │ │ │ -}); │ │ │ │ -OpenLayers.Lang["id"] = OpenLayers.Util.applyDefaults({ │ │ │ │ - unhandledRequest: "Permintaan yang tak tertangani menghasilkan ${statusText}", │ │ │ │ - Permalink: "Pranala permanen", │ │ │ │ - Overlays: "Hamparan", │ │ │ │ - "Base Layer": "Lapisan Dasar", │ │ │ │ - noFID: "Tidak dapat memperbarui fitur yang tidak memiliki FID.", │ │ │ │ - browserNotSupported: "Peramban Anda tidak mendukung penggambaran vektor. Penggambar yang didukung saat ini adalah:\n${renderers}", │ │ │ │ - minZoomLevelError: "Properti minZoomLevel hanya ditujukan bekerja dengan lapisan FixedZoomLevels-descendent. Pengecekan minZoomLevel oleh lapisan wfs adalah peninggalan masa lalu. Kami tidak dapat menghapusnya tanpa kemungkinan merusak aplikasi berbasis OL yang mungkin bergantung padanya. Karenanya, kami menganggapnya tidak berlaku -- Cek minZoomLevel di bawah ini akan dihapus pada 3.0. Silakan gunakan penyetelan resolusi min/maks seperti dijabarkan di sini: http://trac.openlayers.org/wiki/SettingZoomLevels", │ │ │ │ - commitSuccess: "WFS Transaksi: BERHASIL ${respon}", │ │ │ │ - commitFailed: "WFS Transaksi: GAGAL ${respon}", │ │ │ │ - googleWarning: "Lapisan Google tidak dapat dimuat dengan benar.<br><br>Untuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.<br><br>Kemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan atau tidak mengandung kunci API yang tepat untuk situs Anda.<br><br>Pengembang: Untuk bantuan mengatasi masalah ini, <a href='http://trac.openlayers.org/wiki/Google' target='_blank'>klik di sini</a>", │ │ │ │ - getLayerWarning: "Lapisan ${layerType} tidak dapat dimuat dengan benar.<br><br>Untuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.<br><br>Kemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan dengan benar.<br><br>Pengembang: Untuk bantuan mengatasi masalah ini, <a href='http://trac.openlayers.org/wiki/${layerLib}' target='_blank'>klik di sini</a>", │ │ │ │ - "Scale = 1 : ${scaleDenom}": "Sekala = 1 : ${scaleDenom}", │ │ │ │ - W: "B", │ │ │ │ - E: "T", │ │ │ │ - N: "U", │ │ │ │ - S: "S", │ │ │ │ - reprojectDeprecated: "Anda menggunakan opsi 'reproject' pada lapisan ${layerName}. Opsi ini telah ditinggalkan: penggunaannya dirancang untuk mendukung tampilan data melalui peta dasar komersial, tapi fungsionalitas tersebut saat ini harus dilakukan dengan menggunakan dukungan Spherical Mercator. Informasi lebih lanjut tersedia di http://trac.openlayers.org/wiki/SphericalMercator.", │ │ │ │ - methodDeprecated: "Metode ini telah usang dan akan dihapus di 3.0. Sebaliknya, harap gunakan ${newMethod}." │ │ │ │ -}); │ │ │ │ OpenLayers.Popup.Framed = OpenLayers.Class(OpenLayers.Popup.Anchored, { │ │ │ │ imageSrc: null, │ │ │ │ imageSize: null, │ │ │ │ isAlphaImage: false, │ │ │ │ positionBlocks: null, │ │ │ │ blocks: null, │ │ │ │ fixedRelativePosition: false,